| /*------------------------------------------------------------------------- |
| * |
| * pg_largeobject.c |
| * routines to support manipulation of the pg_largeobject relation |
| * |
| * Portions Copyright (c) 1996-2021, 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; |
| } |