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 405510c..67aad86 100644 (file)
@@ -3,12 +3,12 @@
  * pg_depend.c
  *       routines to support manipulation of the pg_depend relation
  *
- * Portions Copyright (c) 1996-2008, 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.29 2008/06/19 00:46:04 alvherre Exp $
+ *       src/backend/catalog/pg_depend.c
  *
  *-------------------------------------------------------------------------
  */
@@ -20,6 +20,8 @@
 #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"
@@ -59,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)
@@ -77,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++)
        {
@@ -102,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);
 
@@ -123,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;
@@ -155,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++;
        }
@@ -167,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.
@@ -321,20 +405,20 @@ isObjectPinned(const ObjectAddress *object, Relation rel)
 
 
 /*
- * Detect whether a sequence is marked as "owned" by a column
+ * Find the extension containing the specified object, if any
  *
- * An ownership marker is an AUTO dependency from the sequence to the
- * column.     If we find one, store the identity of the owning column
- * into *tableId and *colId and return TRUE; else return FALSE.
+ * Returns the OID of the extension, or InvalidOid if the object does not
+ * belong to any extension.
  *
- * Note: if there's more than one such pg_depend entry then you get
- * a random one of them returned into the out parameters.  This should
- * not happen, though.
+ * 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.
  */
-bool
-sequenceIsOwned(Oid seqId, Oid *tableId, int32 *colId)
+Oid
+getExtensionOfObject(Oid classId, Oid objectId)
 {
-       bool            ret = false;
+       Oid                     result = InvalidOid;
        Relation        depRel;
        ScanKeyData key[2];
        SysScanDesc scan;
@@ -345,11 +429,11 @@ sequenceIsOwned(Oid seqId, Oid *tableId, int32 *colId)
        ScanKeyInit(&key[0],
                                Anum_pg_depend_classid,
                                BTEqualStrategyNumber, F_OIDEQ,
-                               ObjectIdGetDatum(RelationRelationId));
+                               ObjectIdGetDatum(classId));
        ScanKeyInit(&key[1],
                                Anum_pg_depend_objid,
                                BTEqualStrategyNumber, F_OIDEQ,
-                               ObjectIdGetDatum(seqId));
+                               ObjectIdGetDatum(objectId));
 
        scan = systable_beginscan(depRel, DependDependerIndexId, true,
                                                          SnapshotNow, 2, key);
@@ -358,12 +442,10 @@ sequenceIsOwned(Oid seqId, Oid *tableId, int32 *colId)
        {
                Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
 
-               if (depform->refclassid == RelationRelationId &&
-                       depform->deptype == DEPENDENCY_AUTO)
+               if (depform->refclassid == ExtensionRelationId &&
+                       depform->deptype == DEPENDENCY_EXTENSION)
                {
-                       *tableId = depform->refobjid;
-                       *colId = depform->refobjsubid;
-                       ret = true;
+                       result = depform->refobjid;
                        break;                          /* no need to keep scanning */
                }
        }
@@ -372,24 +454,30 @@ sequenceIsOwned(Oid seqId, Oid *tableId, int32 *colId)
 
        heap_close(depRel, AccessShareLock);
 
-       return ret;
+       return result;
 }
 
 /*
- * Remove any existing "owned" markers for the specified sequence.
+ * Detect whether a sequence is marked as "owned" by a column
  *
- * Note: we don't provide a special function to install an "owned"
- * marker; just use recordDependencyOn().
+ * An ownership marker is an AUTO dependency from the sequence to the
+ * 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
+ * a random one of them returned into the out parameters.  This should
+ * not happen, though.
  */
-void
-markSequenceUnowned(Oid seqId)
+bool
+sequenceIsOwned(Oid seqId, Oid *tableId, int32 *colId)
 {
+       bool            ret = false;
        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,
@@ -410,13 +498,31 @@ markSequenceUnowned(Oid seqId)
                if (depform->refclassid == RelationRelationId &&
                        depform->deptype == DEPENDENCY_AUTO)
                {
-                       simple_heap_delete(depRel, &tup->t_self);
+                       *tableId = depform->refobjid;
+                       *colId = depform->refobjsubid;
+                       ret = true;
+                       break;                          /* no need to keep scanning */
                }
        }
 
        systable_endscan(scan);
 
-       heap_close(depRel, RowExclusiveLock);
+       heap_close(depRel, AccessShareLock);
+
+       return ret;
+}
+
+/*
+ * Remove any existing "owned" markers for the specified sequence.
+ *
+ * Note: we don't provide a special function to install an "owned"
+ * marker; just use recordDependencyOn().
+ */
+void
+markSequenceUnowned(Oid seqId)
+{
+       deleteDependencyRecordsForClass(RelationRelationId, seqId,
+                                                                       RelationRelationId, DEPENDENCY_AUTO);
 }
 
 /*
@@ -427,8 +533,8 @@ getOwnedSequences(Oid relid)
 {
        List       *result = NIL;
        Relation        depRel;
-       ScanKeyData     key[2];
-       SysScanDesc     scan;
+       ScanKeyData key[2];
+       SysScanDesc scan;
        HeapTuple       tup;
 
        depRel = heap_open(DependRelationId, AccessShareLock);
@@ -571,8 +677,8 @@ get_index_constraint(Oid indexId)
                Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
 
                /*
-                * We assume any internal dependency on a constraint
-                * must be what we are looking for.
+                * We assume any internal dependency on a constraint must be what we
+                * are looking for.
                 */
                if (deprec->refclassid == ConstraintRelationId &&
                        deprec->refobjsubid == 0 &&