* 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.26 2008/01/01 19:45:48 momjian Exp $
+ * src/backend/catalog/pg_depend.c
*
*-------------------------------------------------------------------------
*/
#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);
CatalogIndexState indstate;
HeapTuple tup;
int i;
- char nulls[Natts_pg_depend];
+ bool nulls[Natts_pg_depend];
Datum values[Natts_pg_depend];
if (nreferenced <= 0)
/* 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++)
{
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);
}
/*
+ * 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;
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++;
}
}
/*
+ * 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.
/*
+ * 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
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;
}
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 &&