OSDN Git Service

Add notion of a "transform function" that can simplify function calls.
[pg-rex/syncrep.git] / src / backend / catalog / pg_depend.c
index 99cdf5e..67aad86 100644 (file)
@@ -3,12 +3,12 @@
  * pg_depend.c
  *       routines to support manipulation of the pg_depend relation
  *
- * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/catalog/pg_depend.c,v 1.22 2006/08/21 00:57:24 tgl Exp $
+ *       src/backend/catalog/pg_depend.c
  *
  *-------------------------------------------------------------------------
  */
 #include "access/heapam.h"
 #include "catalog/dependency.h"
 #include "catalog/indexing.h"
+#include "catalog/pg_constraint.h"
 #include "catalog/pg_depend.h"
+#include "catalog/pg_extension.h"
+#include "commands/extension.h"
 #include "miscadmin.h"
 #include "utils/fmgroids.h"
+#include "utils/lsyscache.h"
+#include "utils/rel.h"
+#include "utils/tqual.h"
 
 
 static bool isObjectPinned(const ObjectAddress *object, Relation rel);
@@ -55,7 +61,7 @@ recordMultipleDependencies(const ObjectAddress *depender,
        CatalogIndexState indstate;
        HeapTuple       tup;
        int                     i;
-       char            nulls[Natts_pg_depend];
+       bool            nulls[Natts_pg_depend];
        Datum           values[Natts_pg_depend];
 
        if (nreferenced <= 0)
@@ -73,7 +79,7 @@ recordMultipleDependencies(const ObjectAddress *depender,
        /* Don't open indexes unless we need to make an update */
        indstate = NULL;
 
-       memset(nulls, ' ', sizeof(nulls));
+       memset(nulls, false, sizeof(nulls));
 
        for (i = 0; i < nreferenced; i++, referenced++)
        {
@@ -98,7 +104,7 @@ recordMultipleDependencies(const ObjectAddress *depender,
 
                        values[Anum_pg_depend_deptype - 1] = CharGetDatum((char) behavior);
 
-                       tup = heap_formtuple(dependDesc->rd_att, values, nulls);
+                       tup = heap_form_tuple(dependDesc->rd_att, values, nulls);
 
                        simple_heap_insert(dependDesc, tup);
 
@@ -119,15 +125,42 @@ recordMultipleDependencies(const ObjectAddress *depender,
 }
 
 /*
+ * If we are executing a CREATE EXTENSION operation, mark the given object
+ * as being a member of the extension. Otherwise, do nothing.
+ *
+ * This must be called during creation of any user-definable object type
+ * that could be a member of an extension.
+ */
+void
+recordDependencyOnCurrentExtension(const ObjectAddress *object)
+{
+       if (creating_extension)
+       {
+               ObjectAddress extension;
+
+               extension.classId = ExtensionRelationId;
+               extension.objectId = CurrentExtensionObject;
+               extension.objectSubId = 0;
+
+               recordDependencyOn(object, &extension, DEPENDENCY_EXTENSION);
+       }
+}
+
+/*
  * deleteDependencyRecordsFor -- delete all records with given depender
  * classId/objectId.  Returns the number of records deleted.
  *
  * This is used when redefining an existing object.  Links leading to the
  * object do not change, and links leading from it will be recreated
  * (possibly with some differences from before).
+ *
+ * If skipExtensionDeps is true, we do not delete any dependencies that
+ * show that the given object is a member of an extension.     This avoids
+ * needing a lot of extra logic to fetch and recreate that dependency.
  */
 long
-deleteDependencyRecordsFor(Oid classId, Oid objectId)
+deleteDependencyRecordsFor(Oid classId, Oid objectId,
+                                                  bool skipExtensionDeps)
 {
        long            count = 0;
        Relation        depRel;
@@ -151,6 +184,10 @@ deleteDependencyRecordsFor(Oid classId, Oid objectId)
 
        while (HeapTupleIsValid(tup = systable_getnext(scan)))
        {
+               if (skipExtensionDeps &&
+                 ((Form_pg_depend) GETSTRUCT(tup))->deptype == DEPENDENCY_EXTENSION)
+                       continue;
+
                simple_heap_delete(depRel, &tup->t_self);
                count++;
        }
@@ -163,6 +200,57 @@ deleteDependencyRecordsFor(Oid classId, Oid objectId)
 }
 
 /*
+ * deleteDependencyRecordsForClass -- delete all records with given depender
+ * classId/objectId, dependee classId, and deptype.
+ * Returns the number of records deleted.
+ *
+ * This is a variant of deleteDependencyRecordsFor, useful when revoking
+ * an object property that is expressed by a dependency record (such as
+ * extension membership).
+ */
+long
+deleteDependencyRecordsForClass(Oid classId, Oid objectId,
+                                                               Oid refclassId, char deptype)
+{
+       long            count = 0;
+       Relation        depRel;
+       ScanKeyData key[2];
+       SysScanDesc scan;
+       HeapTuple       tup;
+
+       depRel = heap_open(DependRelationId, RowExclusiveLock);
+
+       ScanKeyInit(&key[0],
+                               Anum_pg_depend_classid,
+                               BTEqualStrategyNumber, F_OIDEQ,
+                               ObjectIdGetDatum(classId));
+       ScanKeyInit(&key[1],
+                               Anum_pg_depend_objid,
+                               BTEqualStrategyNumber, F_OIDEQ,
+                               ObjectIdGetDatum(objectId));
+
+       scan = systable_beginscan(depRel, DependDependerIndexId, true,
+                                                         SnapshotNow, 2, key);
+
+       while (HeapTupleIsValid(tup = systable_getnext(scan)))
+       {
+               Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
+
+               if (depform->refclassid == refclassId && depform->deptype == deptype)
+               {
+                       simple_heap_delete(depRel, &tup->t_self);
+                       count++;
+               }
+       }
+
+       systable_endscan(scan);
+
+       heap_close(depRel, RowExclusiveLock);
+
+       return count;
+}
+
+/*
  * Adjust dependency record(s) to point to a different object of the same type
  *
  * classId/objectId specify the referencing object.
@@ -261,10 +349,119 @@ changeDependencyFor(Oid classId, Oid objectId,
 }
 
 /*
+ * isObjectPinned()
+ *
+ * Test if an object is required for basic database functionality.
+ * Caller must already have opened pg_depend.
+ *
+ * The passed subId, if any, is ignored; we assume that only whole objects
+ * are pinned (and that this implies pinning their components).
+ */
+static bool
+isObjectPinned(const ObjectAddress *object, Relation rel)
+{
+       bool            ret = false;
+       SysScanDesc scan;
+       HeapTuple       tup;
+       ScanKeyData key[2];
+
+       ScanKeyInit(&key[0],
+                               Anum_pg_depend_refclassid,
+                               BTEqualStrategyNumber, F_OIDEQ,
+                               ObjectIdGetDatum(object->classId));
+
+       ScanKeyInit(&key[1],
+                               Anum_pg_depend_refobjid,
+                               BTEqualStrategyNumber, F_OIDEQ,
+                               ObjectIdGetDatum(object->objectId));
+
+       scan = systable_beginscan(rel, DependReferenceIndexId, true,
+                                                         SnapshotNow, 2, key);
+
+       /*
+        * Since we won't generate additional pg_depend entries for pinned
+        * objects, there can be at most one entry referencing a pinned object.
+        * Hence, it's sufficient to look at the first returned tuple; we don't
+        * need to loop.
+        */
+       tup = systable_getnext(scan);
+       if (HeapTupleIsValid(tup))
+       {
+               Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(tup);
+
+               if (foundDep->deptype == DEPENDENCY_PIN)
+                       ret = true;
+       }
+
+       systable_endscan(scan);
+
+       return ret;
+}
+
+
+/*
+ * Various special-purpose lookups and manipulations of pg_depend.
+ */
+
+
+/*
+ * Find the extension containing the specified object, if any
+ *
+ * Returns the OID of the extension, or InvalidOid if the object does not
+ * belong to any extension.
+ *
+ * Extension membership is marked by an EXTENSION dependency from the object
+ * to the extension.  Note that the result will be indeterminate if pg_depend
+ * contains links from this object to more than one extension ... but that
+ * should never happen.
+ */
+Oid
+getExtensionOfObject(Oid classId, Oid objectId)
+{
+       Oid                     result = InvalidOid;
+       Relation        depRel;
+       ScanKeyData key[2];
+       SysScanDesc scan;
+       HeapTuple       tup;
+
+       depRel = heap_open(DependRelationId, AccessShareLock);
+
+       ScanKeyInit(&key[0],
+                               Anum_pg_depend_classid,
+                               BTEqualStrategyNumber, F_OIDEQ,
+                               ObjectIdGetDatum(classId));
+       ScanKeyInit(&key[1],
+                               Anum_pg_depend_objid,
+                               BTEqualStrategyNumber, F_OIDEQ,
+                               ObjectIdGetDatum(objectId));
+
+       scan = systable_beginscan(depRel, DependDependerIndexId, true,
+                                                         SnapshotNow, 2, key);
+
+       while (HeapTupleIsValid((tup = systable_getnext(scan))))
+       {
+               Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
+
+               if (depform->refclassid == ExtensionRelationId &&
+                       depform->deptype == DEPENDENCY_EXTENSION)
+               {
+                       result = depform->refobjid;
+                       break;                          /* no need to keep scanning */
+               }
+       }
+
+       systable_endscan(scan);
+
+       heap_close(depRel, AccessShareLock);
+
+       return result;
+}
+
+/*
  * Detect whether a sequence is marked as "owned" by a column
  *
  * An ownership marker is an AUTO dependency from the sequence to the
- * column.  If we find one, store the identity of the owning column
+ * column.     If we find one, store the identity of the owning column
  * into *tableId and *colId and return TRUE; else return FALSE.
  *
  * Note: if there's more than one such pg_depend entry then you get
@@ -324,87 +521,176 @@ sequenceIsOwned(Oid seqId, Oid *tableId, int32 *colId)
 void
 markSequenceUnowned(Oid seqId)
 {
+       deleteDependencyRecordsForClass(RelationRelationId, seqId,
+                                                                       RelationRelationId, DEPENDENCY_AUTO);
+}
+
+/*
+ * Collect a list of OIDs of all sequences owned by the specified relation.
+ */
+List *
+getOwnedSequences(Oid relid)
+{
+       List       *result = NIL;
        Relation        depRel;
        ScanKeyData key[2];
        SysScanDesc scan;
        HeapTuple       tup;
 
-       depRel = heap_open(DependRelationId, RowExclusiveLock);
+       depRel = heap_open(DependRelationId, AccessShareLock);
 
        ScanKeyInit(&key[0],
-                               Anum_pg_depend_classid,
+                               Anum_pg_depend_refclassid,
                                BTEqualStrategyNumber, F_OIDEQ,
                                ObjectIdGetDatum(RelationRelationId));
        ScanKeyInit(&key[1],
-                               Anum_pg_depend_objid,
+                               Anum_pg_depend_refobjid,
                                BTEqualStrategyNumber, F_OIDEQ,
-                               ObjectIdGetDatum(seqId));
+                               ObjectIdGetDatum(relid));
 
-       scan = systable_beginscan(depRel, DependDependerIndexId, true,
+       scan = systable_beginscan(depRel, DependReferenceIndexId, true,
                                                          SnapshotNow, 2, key);
 
-       while (HeapTupleIsValid((tup = systable_getnext(scan))))
+       while (HeapTupleIsValid(tup = systable_getnext(scan)))
        {
-               Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
+               Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
 
-               if (depform->refclassid == RelationRelationId &&
-                       depform->deptype == DEPENDENCY_AUTO)
+               /*
+                * We assume any auto dependency of a sequence on a column must be
+                * what we are looking for.  (We need the relkind test because indexes
+                * can also have auto dependencies on columns.)
+                */
+               if (deprec->classid == RelationRelationId &&
+                       deprec->objsubid == 0 &&
+                       deprec->refobjsubid != 0 &&
+                       deprec->deptype == DEPENDENCY_AUTO &&
+                       get_rel_relkind(deprec->objid) == RELKIND_SEQUENCE)
                {
-                       simple_heap_delete(depRel, &tup->t_self);
+                       result = lappend_oid(result, deprec->objid);
                }
        }
 
        systable_endscan(scan);
 
-       heap_close(depRel, RowExclusiveLock);
+       heap_close(depRel, AccessShareLock);
+
+       return result;
 }
 
+
 /*
- * isObjectPinned()
+ * get_constraint_index
+ *             Given the OID of a unique or primary-key constraint, return the
+ *             OID of the underlying unique index.
  *
- * Test if an object is required for basic database functionality.
- * Caller must already have opened pg_depend.
- *
- * The passed subId, if any, is ignored; we assume that only whole objects
- * are pinned (and that this implies pinning their components).
+ * Return InvalidOid if the index couldn't be found; this suggests the
+ * given OID is bogus, but we leave it to caller to decide what to do.
  */
-static bool
-isObjectPinned(const ObjectAddress *object, Relation rel)
+Oid
+get_constraint_index(Oid constraintId)
 {
-       bool            ret = false;
+       Oid                     indexId = InvalidOid;
+       Relation        depRel;
+       ScanKeyData key[3];
        SysScanDesc scan;
        HeapTuple       tup;
-       ScanKeyData key[2];
+
+       /* Search the dependency table for the dependent index */
+       depRel = heap_open(DependRelationId, AccessShareLock);
 
        ScanKeyInit(&key[0],
                                Anum_pg_depend_refclassid,
                                BTEqualStrategyNumber, F_OIDEQ,
-                               ObjectIdGetDatum(object->classId));
-
+                               ObjectIdGetDatum(ConstraintRelationId));
        ScanKeyInit(&key[1],
                                Anum_pg_depend_refobjid,
                                BTEqualStrategyNumber, F_OIDEQ,
-                               ObjectIdGetDatum(object->objectId));
+                               ObjectIdGetDatum(constraintId));
+       ScanKeyInit(&key[2],
+                               Anum_pg_depend_refobjsubid,
+                               BTEqualStrategyNumber, F_INT4EQ,
+                               Int32GetDatum(0));
 
-       scan = systable_beginscan(rel, DependReferenceIndexId, true,
-                                                         SnapshotNow, 2, key);
+       scan = systable_beginscan(depRel, DependReferenceIndexId, true,
+                                                         SnapshotNow, 3, key);
 
-       /*
-        * Since we won't generate additional pg_depend entries for pinned
-        * objects, there can be at most one entry referencing a pinned object.
-        * Hence, it's sufficient to look at the first returned tuple; we don't
-        * need to loop.
-        */
-       tup = systable_getnext(scan);
-       if (HeapTupleIsValid(tup))
+       while (HeapTupleIsValid(tup = systable_getnext(scan)))
        {
-               Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(tup);
+               Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
 
-               if (foundDep->deptype == DEPENDENCY_PIN)
-                       ret = true;
+               /*
+                * We assume any internal dependency of an index on the constraint
+                * must be what we are looking for.  (The relkind test is just
+                * paranoia; there shouldn't be any such dependencies otherwise.)
+                */
+               if (deprec->classid == RelationRelationId &&
+                       deprec->objsubid == 0 &&
+                       deprec->deptype == DEPENDENCY_INTERNAL &&
+                       get_rel_relkind(deprec->objid) == RELKIND_INDEX)
+               {
+                       indexId = deprec->objid;
+                       break;
+               }
        }
 
        systable_endscan(scan);
+       heap_close(depRel, AccessShareLock);
 
-       return ret;
+       return indexId;
+}
+
+/*
+ * get_index_constraint
+ *             Given the OID of an index, return the OID of the owning unique or
+ *             primary-key constraint, or InvalidOid if no such constraint.
+ */
+Oid
+get_index_constraint(Oid indexId)
+{
+       Oid                     constraintId = InvalidOid;
+       Relation        depRel;
+       ScanKeyData key[3];
+       SysScanDesc scan;
+       HeapTuple       tup;
+
+       /* Search the dependency table for the index */
+       depRel = heap_open(DependRelationId, AccessShareLock);
+
+       ScanKeyInit(&key[0],
+                               Anum_pg_depend_classid,
+                               BTEqualStrategyNumber, F_OIDEQ,
+                               ObjectIdGetDatum(RelationRelationId));
+       ScanKeyInit(&key[1],
+                               Anum_pg_depend_objid,
+                               BTEqualStrategyNumber, F_OIDEQ,
+                               ObjectIdGetDatum(indexId));
+       ScanKeyInit(&key[2],
+                               Anum_pg_depend_objsubid,
+                               BTEqualStrategyNumber, F_INT4EQ,
+                               Int32GetDatum(0));
+
+       scan = systable_beginscan(depRel, DependDependerIndexId, true,
+                                                         SnapshotNow, 3, key);
+
+       while (HeapTupleIsValid(tup = systable_getnext(scan)))
+       {
+               Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
+
+               /*
+                * We assume any internal dependency on a constraint must be what we
+                * are looking for.
+                */
+               if (deprec->refclassid == ConstraintRelationId &&
+                       deprec->refobjsubid == 0 &&
+                       deprec->deptype == DEPENDENCY_INTERNAL)
+               {
+                       constraintId = deprec->refobjid;
+                       break;
+               }
+       }
+
+       systable_endscan(scan);
+       heap_close(depRel, AccessShareLock);
+
+       return constraintId;
 }