X-Git-Url: https://granicus.if.org/sourcecode?a=blobdiff_plain;f=src%2Fbackend%2Fcatalog%2Fpg_largeobject.c;h=d08b94e28f443275de63cde5e0dfc7d257b0bda2;hb=ee943004466418595363d567f18c053bae407792;hp=819099329ced41ab90f722b69b30b53c17872434;hpb=ef6ccb0bcc62150d49690a1d95d1de3562c8d9ce;p=postgresql diff --git a/src/backend/catalog/pg_largeobject.c b/src/backend/catalog/pg_largeobject.c index 819099329c..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-2001, PostgreSQL Global Development Group + * 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.10 2001/08/10 20:52:24 tgl Exp $ + * src/backend/catalog/pg_largeobject.c * *------------------------------------------------------------------------- */ @@ -16,164 +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. + * 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. */ -void +Oid LargeObjectCreate(Oid loid) { - 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("")); + values[Anum_pg_largeobject_metadata_lomowner - 1] + = ObjectIdGetDatum(GetUserId()); + nulls[Anum_pg_largeobject_metadata_lomacl - 1] = true; - ntup = heap_formtuple(pg_largeobject->rd_att, values, nulls); + ntup = heap_form_tuple(RelationGetDescr(pg_lo_meta), + values, nulls); + if (OidIsValid(loid)) + HeapTupleSetOid(ntup, loid); - /* - * Insert it - */ - heap_insert(pg_largeobject, ntup); - - /* - * 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); - } + loid_new = simple_heap_insert(pg_lo_meta, ntup); + Assert(!OidIsValid(loid) || loid == loid_new); - heap_close(pg_largeobject, RowExclusiveLock); + CatalogUpdateIndexes(pg_lo_meta, ntup); heap_freetuple(ntup); + + 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; + SysScanDesc scan; + HeapTuple tuple; + + pg_lo_meta = heap_open(LargeObjectMetadataRelationId, + RowExclusiveLock); + + pg_largeobject = heap_open(LargeObjectRelationId, + RowExclusiveLock); - ScanKeyEntryInitialize(&skey[0], - (bits16) 0x0, - (AttrNumber) 1, - (RegProcedure) F_OIDEQ, - ObjectIdGetDatum(loid)); + /* + * 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); - pg_largeobject = heap_openr(LargeObjectRelationName, RowShareLock); - pg_lo_idx = index_openr(LargeObjectLOidPNIndex); + tuple = systable_getnext(scan); + if (!HeapTupleIsValid(tuple)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("large object %u does not exist", loid))); - sd = index_beginscan(pg_lo_idx, false, 1, skey); + simple_heap_delete(pg_lo_meta, &tuple->t_self); - tuple.t_datamcxt = CurrentMemoryContext; - tuple.t_data = NULL; + systable_endscan(scan); - while ((indexRes = index_getnext(sd, ForwardScanDirection))) + /* + * 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, sd); - pfree(indexRes); - if (tuple.t_data != NULL) - { - simple_heap_delete(pg_largeobject, &tuple.t_self); - 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) { - bool retval = false; - Relation pg_largeobject; - Relation pg_lo_idx; + Relation pg_lo_meta; 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)); + SysScanDesc sd; + HeapTuple tuple; + bool retval = false; - 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, sd); - 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; }