summaryrefslogtreecommitdiffstats
path: root/src/backend/catalog/pg_largeobject.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/catalog/pg_largeobject.c')
-rw-r--r--src/backend/catalog/pg_largeobject.c187
1 files changed, 187 insertions, 0 deletions
diff --git a/src/backend/catalog/pg_largeobject.c b/src/backend/catalog/pg_largeobject.c
new file mode 100644
index 0000000..ae9365e
--- /dev/null
+++ b/src/backend/catalog/pg_largeobject.c
@@ -0,0 +1,187 @@
+/*-------------------------------------------------------------------------
+ *
+ * pg_largeobject.c
+ * routines to support manipulation of the pg_largeobject relation
+ *
+ * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * src/backend/catalog/pg_largeobject.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "access/genam.h"
+#include "access/htup_details.h"
+#include "access/sysattr.h"
+#include "access/table.h"
+#include "catalog/catalog.h"
+#include "catalog/dependency.h"
+#include "catalog/indexing.h"
+#include "catalog/pg_largeobject.h"
+#include "catalog/pg_largeobject_metadata.h"
+#include "miscadmin.h"
+#include "utils/acl.h"
+#include "utils/fmgroids.h"
+#include "utils/rel.h"
+
+
+/*
+ * Create a large object having the given LO identifier.
+ *
+ * We create a new large object by inserting an entry into
+ * pg_largeobject_metadata without any data pages, so that the object
+ * will appear to exist with size 0.
+ */
+Oid
+LargeObjectCreate(Oid loid)
+{
+ Relation pg_lo_meta;
+ HeapTuple ntup;
+ Oid loid_new;
+ Datum values[Natts_pg_largeobject_metadata];
+ bool nulls[Natts_pg_largeobject_metadata];
+
+ pg_lo_meta = table_open(LargeObjectMetadataRelationId,
+ RowExclusiveLock);
+
+ /*
+ * Insert metadata of the largeobject
+ */
+ memset(values, 0, sizeof(values));
+ memset(nulls, false, sizeof(nulls));
+
+ if (OidIsValid(loid))
+ loid_new = loid;
+ else
+ loid_new = GetNewOidWithIndex(pg_lo_meta,
+ LargeObjectMetadataOidIndexId,
+ Anum_pg_largeobject_metadata_oid);
+
+ values[Anum_pg_largeobject_metadata_oid - 1] = ObjectIdGetDatum(loid_new);
+ values[Anum_pg_largeobject_metadata_lomowner - 1]
+ = ObjectIdGetDatum(GetUserId());
+ nulls[Anum_pg_largeobject_metadata_lomacl - 1] = true;
+
+ ntup = heap_form_tuple(RelationGetDescr(pg_lo_meta),
+ values, nulls);
+
+ CatalogTupleInsert(pg_lo_meta, ntup);
+
+ heap_freetuple(ntup);
+
+ table_close(pg_lo_meta, RowExclusiveLock);
+
+ return loid_new;
+}
+
+/*
+ * Drop a large object having the given LO identifier. Both the data pages
+ * and metadata must be dropped.
+ */
+void
+LargeObjectDrop(Oid loid)
+{
+ Relation pg_lo_meta;
+ Relation pg_largeobject;
+ ScanKeyData skey[1];
+ SysScanDesc scan;
+ HeapTuple tuple;
+
+ pg_lo_meta = table_open(LargeObjectMetadataRelationId,
+ RowExclusiveLock);
+
+ pg_largeobject = table_open(LargeObjectRelationId,
+ RowExclusiveLock);
+
+ /*
+ * Delete an entry from pg_largeobject_metadata
+ */
+ ScanKeyInit(&skey[0],
+ Anum_pg_largeobject_metadata_oid,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(loid));
+
+ scan = systable_beginscan(pg_lo_meta,
+ LargeObjectMetadataOidIndexId, true,
+ NULL, 1, skey);
+
+ tuple = systable_getnext(scan);
+ if (!HeapTupleIsValid(tuple))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("large object %u does not exist", loid)));
+
+ CatalogTupleDelete(pg_lo_meta, &tuple->t_self);
+
+ systable_endscan(scan);
+
+ /*
+ * Delete all the associated entries from pg_largeobject
+ */
+ ScanKeyInit(&skey[0],
+ Anum_pg_largeobject_loid,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(loid));
+
+ scan = systable_beginscan(pg_largeobject,
+ LargeObjectLOidPNIndexId, true,
+ NULL, 1, skey);
+ while (HeapTupleIsValid(tuple = systable_getnext(scan)))
+ {
+ CatalogTupleDelete(pg_largeobject, &tuple->t_self);
+ }
+
+ systable_endscan(scan);
+
+ table_close(pg_largeobject, RowExclusiveLock);
+
+ table_close(pg_lo_meta, RowExclusiveLock);
+}
+
+/*
+ * LargeObjectExists
+ *
+ * We don't use the system cache for large object metadata, for fear of
+ * using too much local memory.
+ *
+ * This function always scans the system catalog using an up-to-date snapshot,
+ * so it should not be used when a large object is opened in read-only mode
+ * (because large objects opened in read only mode are supposed to be viewed
+ * relative to the caller's snapshot, whereas in read-write mode they are
+ * relative to a current snapshot).
+ */
+bool
+LargeObjectExists(Oid loid)
+{
+ Relation pg_lo_meta;
+ ScanKeyData skey[1];
+ SysScanDesc sd;
+ HeapTuple tuple;
+ bool retval = false;
+
+ ScanKeyInit(&skey[0],
+ Anum_pg_largeobject_metadata_oid,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(loid));
+
+ pg_lo_meta = table_open(LargeObjectMetadataRelationId,
+ AccessShareLock);
+
+ sd = systable_beginscan(pg_lo_meta,
+ LargeObjectMetadataOidIndexId, true,
+ NULL, 1, skey);
+
+ tuple = systable_getnext(sd);
+ if (HeapTupleIsValid(tuple))
+ retval = true;
+
+ systable_endscan(sd);
+
+ table_close(pg_lo_meta, AccessShareLock);
+
+ return retval;
+}