X-Git-Url: https://granicus.if.org/sourcecode?a=blobdiff_plain;f=src%2Fbackend%2Fcatalog%2Fpg_largeobject.c;h=d08b94e28f443275de63cde5e0dfc7d257b0bda2;hb=ee943004466418595363d567f18c053bae407792;hp=c471a9ae139fc838e951267dfc1db2760b31eb2d;hpb=4f44aa04b53f26d3abbf64beb0c1b3d10be324a3;p=postgresql diff --git a/src/backend/catalog/pg_largeobject.c b/src/backend/catalog/pg_largeobject.c index c471a9ae13..d08b94e28f 100644 --- a/src/backend/catalog/pg_largeobject.c +++ b/src/backend/catalog/pg_largeobject.c @@ -3,12 +3,12 @@ * pg_largeobject.c * routines to support manipulation of the pg_largeobject relation * - * Portions Copyright (c) 1996-2000, PostgreSQL, Inc + * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/catalog/pg_largeobject.c,v 1.5 2000/10/24 01:38:23 tgl Exp $ + * src/backend/catalog/pg_largeobject.c * *------------------------------------------------------------------------- */ @@ -16,169 +16,169 @@ #include "access/genam.h" #include "access/heapam.h" -#include "catalog/catname.h" +#include "access/htup_details.h" +#include "access/sysattr.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/builtins.h" +#include "utils/acl.h" #include "utils/fmgroids.h" +#include "utils/rel.h" +#include "utils/tqual.h" /* * Create a large object having the given LO identifier. * - * We do this by inserting an empty first page, so that the object will - * appear to exist with size 0. Note that the unique index will reject - * an attempt to create a duplicate page. - * - * Return value is OID assigned to the page tuple (any use in it?) + * 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) { - Oid retval; - Relation pg_largeobject; + Relation pg_lo_meta; HeapTuple ntup; - Relation idescs[Num_pg_largeobject_indices]; - Datum values[Natts_pg_largeobject]; - char nulls[Natts_pg_largeobject]; - int i; + Oid loid_new; + Datum values[Natts_pg_largeobject_metadata]; + bool nulls[Natts_pg_largeobject_metadata]; - pg_largeobject = heap_openr(LargeObjectRelationName, RowExclusiveLock); + pg_lo_meta = heap_open(LargeObjectMetadataRelationId, + RowExclusiveLock); /* - * Form new tuple + * Insert metadata of the largeobject */ - for (i = 0; i < Natts_pg_largeobject; i++) - { - values[i] = (Datum)NULL; - nulls[i] = ' '; - } + memset(values, 0, sizeof(values)); + memset(nulls, false, sizeof(nulls)); - i = 0; - values[i++] = ObjectIdGetDatum(loid); - values[i++] = Int32GetDatum(0); - values[i++] = DirectFunctionCall1(byteain, - CStringGetDatum("")); - - ntup = heap_formtuple(pg_largeobject->rd_att, values, nulls); + values[Anum_pg_largeobject_metadata_lomowner - 1] + = ObjectIdGetDatum(GetUserId()); + nulls[Anum_pg_largeobject_metadata_lomacl - 1] = true; - /* - * Insert it - */ - retval = heap_insert(pg_largeobject, ntup); + ntup = heap_form_tuple(RelationGetDescr(pg_lo_meta), + values, nulls); + if (OidIsValid(loid)) + HeapTupleSetOid(ntup, loid); - /* - * Update indices - */ - if (!IsIgnoringSystemIndexes()) - { - CatalogOpenIndices(Num_pg_largeobject_indices, Name_pg_largeobject_indices, idescs); - CatalogIndexInsert(idescs, Num_pg_largeobject_indices, pg_largeobject, ntup); - CatalogCloseIndices(Num_pg_largeobject_indices, idescs); - } - - heap_close(pg_largeobject, RowExclusiveLock); + loid_new = simple_heap_insert(pg_lo_meta, ntup); + Assert(!OidIsValid(loid) || loid == loid_new); + + CatalogUpdateIndexes(pg_lo_meta, ntup); heap_freetuple(ntup); - return retval; + heap_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) { - bool found = false; + Relation pg_lo_meta; Relation pg_largeobject; - Relation pg_lo_idx; - ScanKeyData skey[1]; - IndexScanDesc sd; - RetrieveIndexResult indexRes; - HeapTupleData tuple; - Buffer buffer; + ScanKeyData skey[1]; + SysScanDesc scan; + HeapTuple tuple; + + pg_lo_meta = heap_open(LargeObjectMetadataRelationId, + RowExclusiveLock); - ScanKeyEntryInitialize(&skey[0], - (bits16) 0x0, - (AttrNumber) 1, - (RegProcedure) F_OIDEQ, - ObjectIdGetDatum(loid)); + pg_largeobject = heap_open(LargeObjectRelationId, + RowExclusiveLock); - pg_largeobject = heap_openr(LargeObjectRelationName, RowShareLock); - pg_lo_idx = index_openr(LargeObjectLOidPNIndex); + /* + * Delete an entry from pg_largeobject_metadata + */ + ScanKeyInit(&skey[0], + ObjectIdAttributeNumber, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(loid)); + + scan = systable_beginscan(pg_lo_meta, + LargeObjectMetadataOidIndexId, true, + NULL, 1, skey); - sd = index_beginscan(pg_lo_idx, false, 1, skey); + tuple = systable_getnext(scan); + if (!HeapTupleIsValid(tuple)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("large object %u does not exist", loid))); - tuple.t_datamcxt = CurrentMemoryContext; - tuple.t_data = NULL; + simple_heap_delete(pg_lo_meta, &tuple->t_self); - while ((indexRes = index_getnext(sd, ForwardScanDirection))) + 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))) { - tuple.t_self = indexRes->heap_iptr; - heap_fetch(pg_largeobject, SnapshotNow, &tuple, &buffer); - pfree(indexRes); - if (tuple.t_data != NULL) - { - heap_delete(pg_largeobject, &tuple.t_self, NULL); - ReleaseBuffer(buffer); - found = true; - } + simple_heap_delete(pg_largeobject, &tuple->t_self); } - index_endscan(sd); + systable_endscan(scan); - index_close(pg_lo_idx); - heap_close(pg_largeobject, RowShareLock); + heap_close(pg_largeobject, RowExclusiveLock); - if (!found) - elog(ERROR, "LargeObjectDrop: large object %u not found", loid); + heap_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; - Relation pg_largeobject; - Relation pg_lo_idx; - ScanKeyData skey[1]; - IndexScanDesc sd; - RetrieveIndexResult indexRes; - HeapTupleData tuple; - Buffer buffer; - - /* - * See if we can find any tuples belonging to the specified LO - */ - ScanKeyEntryInitialize(&skey[0], - (bits16) 0x0, - (AttrNumber) 1, - (RegProcedure) F_OIDEQ, - ObjectIdGetDatum(loid)); - pg_largeobject = heap_openr(LargeObjectRelationName, RowShareLock); - pg_lo_idx = index_openr(LargeObjectLOidPNIndex); + ScanKeyInit(&skey[0], + ObjectIdAttributeNumber, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(loid)); - sd = index_beginscan(pg_lo_idx, false, 1, skey); + pg_lo_meta = heap_open(LargeObjectMetadataRelationId, + AccessShareLock); - tuple.t_datamcxt = CurrentMemoryContext; - tuple.t_data = NULL; + sd = systable_beginscan(pg_lo_meta, + LargeObjectMetadataOidIndexId, true, + NULL, 1, skey); - while ((indexRes = index_getnext(sd, ForwardScanDirection))) - { - tuple.t_self = indexRes->heap_iptr; - heap_fetch(pg_largeobject, SnapshotNow, &tuple, &buffer); - pfree(indexRes); - if (tuple.t_data != NULL) - { - retval = true; - ReleaseBuffer(buffer); - break; - } - } + tuple = systable_getnext(sd); + if (HeapTupleIsValid(tuple)) + retval = true; - index_endscan(sd); + systable_endscan(sd); - index_close(pg_lo_idx); - heap_close(pg_largeobject, RowShareLock); + heap_close(pg_lo_meta, AccessShareLock); return retval; }