]> granicus.if.org Git - postgresql/blobdiff - src/backend/catalog/pg_largeobject.c
Update copyright for 2016
[postgresql] / src / backend / catalog / pg_largeobject.c
index 819099329ced41ab90f722b69b30b53c17872434..d08b94e28f443275de63cde5e0dfc7d257b0bda2 100644 (file)
@@ -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
  *
  *-------------------------------------------------------------------------
  */
 
 #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;
 }