1 /*-------------------------------------------------------------------------
4 * routines to support manipulation of the pg_depend relation
6 * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
13 *-------------------------------------------------------------------------
17 #include "access/genam.h"
18 #include "access/heapam.h"
19 #include "catalog/dependency.h"
20 #include "catalog/indexing.h"
21 #include "catalog/pg_constraint.h"
22 #include "catalog/pg_depend.h"
23 #include "miscadmin.h"
24 #include "utils/fmgroids.h"
25 #include "utils/lsyscache.h"
26 #include "utils/rel.h"
27 #include "utils/tqual.h"
30 static bool isObjectPinned(const ObjectAddress
*object
, Relation rel
);
34 * Record a dependency between 2 objects via their respective objectAddress.
35 * The first argument is the dependent object, the second the one it
38 * This simply creates an entry in pg_depend, without any other processing.
41 recordDependencyOn(const ObjectAddress
*depender
,
42 const ObjectAddress
*referenced
,
43 DependencyType behavior
)
45 recordMultipleDependencies(depender
, referenced
, 1, behavior
);
49 * Record multiple dependencies (of the same kind) for a single dependent
50 * object. This has a little less overhead than recording each separately.
53 recordMultipleDependencies(const ObjectAddress
*depender
,
54 const ObjectAddress
*referenced
,
56 DependencyType behavior
)
59 CatalogIndexState indstate
;
62 bool nulls
[Natts_pg_depend
];
63 Datum values
[Natts_pg_depend
];
66 return; /* nothing to do */
69 * During bootstrap, do nothing since pg_depend may not exist yet. initdb
70 * will fill in appropriate pg_depend entries after bootstrap.
72 if (IsBootstrapProcessingMode())
75 dependDesc
= heap_open(DependRelationId
, RowExclusiveLock
);
77 /* Don't open indexes unless we need to make an update */
80 memset(nulls
, false, sizeof(nulls
));
82 for (i
= 0; i
< nreferenced
; i
++, referenced
++)
85 * If the referenced object is pinned by the system, there's no real
86 * need to record dependencies on it. This saves lots of space in
87 * pg_depend, so it's worth the time taken to check.
89 if (!isObjectPinned(referenced
, dependDesc
))
92 * Record the Dependency. Note we don't bother to check for
93 * duplicate dependencies; there's no harm in them.
95 values
[Anum_pg_depend_classid
- 1] = ObjectIdGetDatum(depender
->classId
);
96 values
[Anum_pg_depend_objid
- 1] = ObjectIdGetDatum(depender
->objectId
);
97 values
[Anum_pg_depend_objsubid
- 1] = Int32GetDatum(depender
->objectSubId
);
99 values
[Anum_pg_depend_refclassid
- 1] = ObjectIdGetDatum(referenced
->classId
);
100 values
[Anum_pg_depend_refobjid
- 1] = ObjectIdGetDatum(referenced
->objectId
);
101 values
[Anum_pg_depend_refobjsubid
- 1] = Int32GetDatum(referenced
->objectSubId
);
103 values
[Anum_pg_depend_deptype
- 1] = CharGetDatum((char) behavior
);
105 tup
= heap_form_tuple(dependDesc
->rd_att
, values
, nulls
);
107 simple_heap_insert(dependDesc
, tup
);
109 /* keep indexes current */
110 if (indstate
== NULL
)
111 indstate
= CatalogOpenIndexes(dependDesc
);
113 CatalogIndexInsert(indstate
, tup
);
119 if (indstate
!= NULL
)
120 CatalogCloseIndexes(indstate
);
122 heap_close(dependDesc
, RowExclusiveLock
);
126 * deleteDependencyRecordsFor -- delete all records with given depender
127 * classId/objectId. Returns the number of records deleted.
129 * This is used when redefining an existing object. Links leading to the
130 * object do not change, and links leading from it will be recreated
131 * (possibly with some differences from before).
134 deleteDependencyRecordsFor(Oid classId
, Oid objectId
)
142 depRel
= heap_open(DependRelationId
, RowExclusiveLock
);
145 Anum_pg_depend_classid
,
146 BTEqualStrategyNumber
, F_OIDEQ
,
147 ObjectIdGetDatum(classId
));
149 Anum_pg_depend_objid
,
150 BTEqualStrategyNumber
, F_OIDEQ
,
151 ObjectIdGetDatum(objectId
));
153 scan
= systable_beginscan(depRel
, DependDependerIndexId
, true,
154 SnapshotNow
, 2, key
);
156 while (HeapTupleIsValid(tup
= systable_getnext(scan
)))
158 simple_heap_delete(depRel
, &tup
->t_self
);
162 systable_endscan(scan
);
164 heap_close(depRel
, RowExclusiveLock
);
170 * Adjust dependency record(s) to point to a different object of the same type
172 * classId/objectId specify the referencing object.
173 * refClassId/oldRefObjectId specify the old referenced object.
174 * newRefObjectId is the new referenced object (must be of class refClassId).
176 * Note the lack of objsubid parameters. If there are subobject references
177 * they will all be readjusted.
179 * Returns the number of records updated.
182 changeDependencyFor(Oid classId
, Oid objectId
,
183 Oid refClassId
, Oid oldRefObjectId
,
191 ObjectAddress objAddr
;
194 depRel
= heap_open(DependRelationId
, RowExclusiveLock
);
197 * If oldRefObjectId is pinned, there won't be any dependency entries on
198 * it --- we can't cope in that case. (This isn't really worth expending
199 * code to fix, in current usage; it just means you can't rename stuff out
200 * of pg_catalog, which would likely be a bad move anyway.)
202 objAddr
.classId
= refClassId
;
203 objAddr
.objectId
= oldRefObjectId
;
204 objAddr
.objectSubId
= 0;
206 if (isObjectPinned(&objAddr
, depRel
))
208 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED
),
209 errmsg("cannot remove dependency on %s because it is a system object",
210 getObjectDescription(&objAddr
))));
213 * We can handle adding a dependency on something pinned, though, since
214 * that just means deleting the dependency entry.
216 objAddr
.objectId
= newRefObjectId
;
218 newIsPinned
= isObjectPinned(&objAddr
, depRel
);
220 /* Now search for dependency records */
222 Anum_pg_depend_classid
,
223 BTEqualStrategyNumber
, F_OIDEQ
,
224 ObjectIdGetDatum(classId
));
226 Anum_pg_depend_objid
,
227 BTEqualStrategyNumber
, F_OIDEQ
,
228 ObjectIdGetDatum(objectId
));
230 scan
= systable_beginscan(depRel
, DependDependerIndexId
, true,
231 SnapshotNow
, 2, key
);
233 while (HeapTupleIsValid((tup
= systable_getnext(scan
))))
235 Form_pg_depend depform
= (Form_pg_depend
) GETSTRUCT(tup
);
237 if (depform
->refclassid
== refClassId
&&
238 depform
->refobjid
== oldRefObjectId
)
241 simple_heap_delete(depRel
, &tup
->t_self
);
244 /* make a modifiable copy */
245 tup
= heap_copytuple(tup
);
246 depform
= (Form_pg_depend
) GETSTRUCT(tup
);
248 depform
->refobjid
= newRefObjectId
;
250 simple_heap_update(depRel
, &tup
->t_self
, tup
);
251 CatalogUpdateIndexes(depRel
, tup
);
260 systable_endscan(scan
);
262 heap_close(depRel
, RowExclusiveLock
);
270 * Test if an object is required for basic database functionality.
271 * Caller must already have opened pg_depend.
273 * The passed subId, if any, is ignored; we assume that only whole objects
274 * are pinned (and that this implies pinning their components).
277 isObjectPinned(const ObjectAddress
*object
, Relation rel
)
285 Anum_pg_depend_refclassid
,
286 BTEqualStrategyNumber
, F_OIDEQ
,
287 ObjectIdGetDatum(object
->classId
));
290 Anum_pg_depend_refobjid
,
291 BTEqualStrategyNumber
, F_OIDEQ
,
292 ObjectIdGetDatum(object
->objectId
));
294 scan
= systable_beginscan(rel
, DependReferenceIndexId
, true,
295 SnapshotNow
, 2, key
);
298 * Since we won't generate additional pg_depend entries for pinned
299 * objects, there can be at most one entry referencing a pinned object.
300 * Hence, it's sufficient to look at the first returned tuple; we don't
303 tup
= systable_getnext(scan
);
304 if (HeapTupleIsValid(tup
))
306 Form_pg_depend foundDep
= (Form_pg_depend
) GETSTRUCT(tup
);
308 if (foundDep
->deptype
== DEPENDENCY_PIN
)
312 systable_endscan(scan
);
319 * Various special-purpose lookups and manipulations of pg_depend.
324 * Detect whether a sequence is marked as "owned" by a column
326 * An ownership marker is an AUTO dependency from the sequence to the
327 * column. If we find one, store the identity of the owning column
328 * into *tableId and *colId and return TRUE; else return FALSE.
330 * Note: if there's more than one such pg_depend entry then you get
331 * a random one of them returned into the out parameters. This should
332 * not happen, though.
335 sequenceIsOwned(Oid seqId
, Oid
*tableId
, int32
*colId
)
343 depRel
= heap_open(DependRelationId
, AccessShareLock
);
346 Anum_pg_depend_classid
,
347 BTEqualStrategyNumber
, F_OIDEQ
,
348 ObjectIdGetDatum(RelationRelationId
));
350 Anum_pg_depend_objid
,
351 BTEqualStrategyNumber
, F_OIDEQ
,
352 ObjectIdGetDatum(seqId
));
354 scan
= systable_beginscan(depRel
, DependDependerIndexId
, true,
355 SnapshotNow
, 2, key
);
357 while (HeapTupleIsValid((tup
= systable_getnext(scan
))))
359 Form_pg_depend depform
= (Form_pg_depend
) GETSTRUCT(tup
);
361 if (depform
->refclassid
== RelationRelationId
&&
362 depform
->deptype
== DEPENDENCY_AUTO
)
364 *tableId
= depform
->refobjid
;
365 *colId
= depform
->refobjsubid
;
367 break; /* no need to keep scanning */
371 systable_endscan(scan
);
373 heap_close(depRel
, AccessShareLock
);
379 * Remove any existing "owned" markers for the specified sequence.
381 * Note: we don't provide a special function to install an "owned"
382 * marker; just use recordDependencyOn().
385 markSequenceUnowned(Oid seqId
)
392 depRel
= heap_open(DependRelationId
, RowExclusiveLock
);
395 Anum_pg_depend_classid
,
396 BTEqualStrategyNumber
, F_OIDEQ
,
397 ObjectIdGetDatum(RelationRelationId
));
399 Anum_pg_depend_objid
,
400 BTEqualStrategyNumber
, F_OIDEQ
,
401 ObjectIdGetDatum(seqId
));
403 scan
= systable_beginscan(depRel
, DependDependerIndexId
, true,
404 SnapshotNow
, 2, key
);
406 while (HeapTupleIsValid((tup
= systable_getnext(scan
))))
408 Form_pg_depend depform
= (Form_pg_depend
) GETSTRUCT(tup
);
410 if (depform
->refclassid
== RelationRelationId
&&
411 depform
->deptype
== DEPENDENCY_AUTO
)
413 simple_heap_delete(depRel
, &tup
->t_self
);
417 systable_endscan(scan
);
419 heap_close(depRel
, RowExclusiveLock
);
423 * Collect a list of OIDs of all sequences owned by the specified relation.
426 getOwnedSequences(Oid relid
)
434 depRel
= heap_open(DependRelationId
, AccessShareLock
);
437 Anum_pg_depend_refclassid
,
438 BTEqualStrategyNumber
, F_OIDEQ
,
439 ObjectIdGetDatum(RelationRelationId
));
441 Anum_pg_depend_refobjid
,
442 BTEqualStrategyNumber
, F_OIDEQ
,
443 ObjectIdGetDatum(relid
));
445 scan
= systable_beginscan(depRel
, DependReferenceIndexId
, true,
446 SnapshotNow
, 2, key
);
448 while (HeapTupleIsValid(tup
= systable_getnext(scan
)))
450 Form_pg_depend deprec
= (Form_pg_depend
) GETSTRUCT(tup
);
453 * We assume any auto dependency of a sequence on a column must be
454 * what we are looking for. (We need the relkind test because indexes
455 * can also have auto dependencies on columns.)
457 if (deprec
->classid
== RelationRelationId
&&
458 deprec
->objsubid
== 0 &&
459 deprec
->refobjsubid
!= 0 &&
460 deprec
->deptype
== DEPENDENCY_AUTO
&&
461 get_rel_relkind(deprec
->objid
) == RELKIND_SEQUENCE
)
463 result
= lappend_oid(result
, deprec
->objid
);
467 systable_endscan(scan
);
469 heap_close(depRel
, AccessShareLock
);
476 * get_constraint_index
477 * Given the OID of a unique or primary-key constraint, return the
478 * OID of the underlying unique index.
480 * Return InvalidOid if the index couldn't be found; this suggests the
481 * given OID is bogus, but we leave it to caller to decide what to do.
484 get_constraint_index(Oid constraintId
)
486 Oid indexId
= InvalidOid
;
492 /* Search the dependency table for the dependent index */
493 depRel
= heap_open(DependRelationId
, AccessShareLock
);
496 Anum_pg_depend_refclassid
,
497 BTEqualStrategyNumber
, F_OIDEQ
,
498 ObjectIdGetDatum(ConstraintRelationId
));
500 Anum_pg_depend_refobjid
,
501 BTEqualStrategyNumber
, F_OIDEQ
,
502 ObjectIdGetDatum(constraintId
));
504 Anum_pg_depend_refobjsubid
,
505 BTEqualStrategyNumber
, F_INT4EQ
,
508 scan
= systable_beginscan(depRel
, DependReferenceIndexId
, true,
509 SnapshotNow
, 3, key
);
511 while (HeapTupleIsValid(tup
= systable_getnext(scan
)))
513 Form_pg_depend deprec
= (Form_pg_depend
) GETSTRUCT(tup
);
516 * We assume any internal dependency of an index on the constraint
517 * must be what we are looking for. (The relkind test is just
518 * paranoia; there shouldn't be any such dependencies otherwise.)
520 if (deprec
->classid
== RelationRelationId
&&
521 deprec
->objsubid
== 0 &&
522 deprec
->deptype
== DEPENDENCY_INTERNAL
&&
523 get_rel_relkind(deprec
->objid
) == RELKIND_INDEX
)
525 indexId
= deprec
->objid
;
530 systable_endscan(scan
);
531 heap_close(depRel
, AccessShareLock
);
537 * get_index_constraint
538 * Given the OID of an index, return the OID of the owning unique or
539 * primary-key constraint, or InvalidOid if no such constraint.
542 get_index_constraint(Oid indexId
)
544 Oid constraintId
= InvalidOid
;
550 /* Search the dependency table for the index */
551 depRel
= heap_open(DependRelationId
, AccessShareLock
);
554 Anum_pg_depend_classid
,
555 BTEqualStrategyNumber
, F_OIDEQ
,
556 ObjectIdGetDatum(RelationRelationId
));
558 Anum_pg_depend_objid
,
559 BTEqualStrategyNumber
, F_OIDEQ
,
560 ObjectIdGetDatum(indexId
));
562 Anum_pg_depend_objsubid
,
563 BTEqualStrategyNumber
, F_INT4EQ
,
566 scan
= systable_beginscan(depRel
, DependDependerIndexId
, true,
567 SnapshotNow
, 3, key
);
569 while (HeapTupleIsValid(tup
= systable_getnext(scan
)))
571 Form_pg_depend deprec
= (Form_pg_depend
) GETSTRUCT(tup
);
574 * We assume any internal dependency on a constraint
575 * must be what we are looking for.
577 if (deprec
->refclassid
== ConstraintRelationId
&&
578 deprec
->refobjsubid
== 0 &&
579 deprec
->deptype
== DEPENDENCY_INTERNAL
)
581 constraintId
= deprec
->refobjid
;
586 systable_endscan(scan
);
587 heap_close(depRel
, AccessShareLock
);