Update obsolete comment in index_drop(). When the comment was written,
[PostgreSQL.git] / src / backend / catalog / pg_depend.c
blob36215bff33fd00473c87b9b8c07db3d7c9b08001
1 /*-------------------------------------------------------------------------
3 * pg_depend.c
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
10 * IDENTIFICATION
11 * $PostgreSQL$
13 *-------------------------------------------------------------------------
15 #include "postgres.h"
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
36 * references.
38 * This simply creates an entry in pg_depend, without any other processing.
40 void
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.
52 void
53 recordMultipleDependencies(const ObjectAddress *depender,
54 const ObjectAddress *referenced,
55 int nreferenced,
56 DependencyType behavior)
58 Relation dependDesc;
59 CatalogIndexState indstate;
60 HeapTuple tup;
61 int i;
62 bool nulls[Natts_pg_depend];
63 Datum values[Natts_pg_depend];
65 if (nreferenced <= 0)
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())
73 return;
75 dependDesc = heap_open(DependRelationId, RowExclusiveLock);
77 /* Don't open indexes unless we need to make an update */
78 indstate = NULL;
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);
115 heap_freetuple(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).
133 long
134 deleteDependencyRecordsFor(Oid classId, Oid objectId)
136 long count = 0;
137 Relation depRel;
138 ScanKeyData key[2];
139 SysScanDesc scan;
140 HeapTuple tup;
142 depRel = heap_open(DependRelationId, RowExclusiveLock);
144 ScanKeyInit(&key[0],
145 Anum_pg_depend_classid,
146 BTEqualStrategyNumber, F_OIDEQ,
147 ObjectIdGetDatum(classId));
148 ScanKeyInit(&key[1],
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);
159 count++;
162 systable_endscan(scan);
164 heap_close(depRel, RowExclusiveLock);
166 return count;
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.
181 long
182 changeDependencyFor(Oid classId, Oid objectId,
183 Oid refClassId, Oid oldRefObjectId,
184 Oid newRefObjectId)
186 long count = 0;
187 Relation depRel;
188 ScanKeyData key[2];
189 SysScanDesc scan;
190 HeapTuple tup;
191 ObjectAddress objAddr;
192 bool newIsPinned;
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))
207 ereport(ERROR,
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 */
221 ScanKeyInit(&key[0],
222 Anum_pg_depend_classid,
223 BTEqualStrategyNumber, F_OIDEQ,
224 ObjectIdGetDatum(classId));
225 ScanKeyInit(&key[1],
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)
240 if (newIsPinned)
241 simple_heap_delete(depRel, &tup->t_self);
242 else
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);
253 heap_freetuple(tup);
256 count++;
260 systable_endscan(scan);
262 heap_close(depRel, RowExclusiveLock);
264 return count;
268 * isObjectPinned()
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).
276 static bool
277 isObjectPinned(const ObjectAddress *object, Relation rel)
279 bool ret = false;
280 SysScanDesc scan;
281 HeapTuple tup;
282 ScanKeyData key[2];
284 ScanKeyInit(&key[0],
285 Anum_pg_depend_refclassid,
286 BTEqualStrategyNumber, F_OIDEQ,
287 ObjectIdGetDatum(object->classId));
289 ScanKeyInit(&key[1],
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
301 * need to loop.
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)
309 ret = true;
312 systable_endscan(scan);
314 return ret;
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.
334 bool
335 sequenceIsOwned(Oid seqId, Oid *tableId, int32 *colId)
337 bool ret = false;
338 Relation depRel;
339 ScanKeyData key[2];
340 SysScanDesc scan;
341 HeapTuple tup;
343 depRel = heap_open(DependRelationId, AccessShareLock);
345 ScanKeyInit(&key[0],
346 Anum_pg_depend_classid,
347 BTEqualStrategyNumber, F_OIDEQ,
348 ObjectIdGetDatum(RelationRelationId));
349 ScanKeyInit(&key[1],
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;
366 ret = true;
367 break; /* no need to keep scanning */
371 systable_endscan(scan);
373 heap_close(depRel, AccessShareLock);
375 return ret;
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().
384 void
385 markSequenceUnowned(Oid seqId)
387 Relation depRel;
388 ScanKeyData key[2];
389 SysScanDesc scan;
390 HeapTuple tup;
392 depRel = heap_open(DependRelationId, RowExclusiveLock);
394 ScanKeyInit(&key[0],
395 Anum_pg_depend_classid,
396 BTEqualStrategyNumber, F_OIDEQ,
397 ObjectIdGetDatum(RelationRelationId));
398 ScanKeyInit(&key[1],
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.
425 List *
426 getOwnedSequences(Oid relid)
428 List *result = NIL;
429 Relation depRel;
430 ScanKeyData key[2];
431 SysScanDesc scan;
432 HeapTuple tup;
434 depRel = heap_open(DependRelationId, AccessShareLock);
436 ScanKeyInit(&key[0],
437 Anum_pg_depend_refclassid,
438 BTEqualStrategyNumber, F_OIDEQ,
439 ObjectIdGetDatum(RelationRelationId));
440 ScanKeyInit(&key[1],
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);
471 return result;
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;
487 Relation depRel;
488 ScanKeyData key[3];
489 SysScanDesc scan;
490 HeapTuple tup;
492 /* Search the dependency table for the dependent index */
493 depRel = heap_open(DependRelationId, AccessShareLock);
495 ScanKeyInit(&key[0],
496 Anum_pg_depend_refclassid,
497 BTEqualStrategyNumber, F_OIDEQ,
498 ObjectIdGetDatum(ConstraintRelationId));
499 ScanKeyInit(&key[1],
500 Anum_pg_depend_refobjid,
501 BTEqualStrategyNumber, F_OIDEQ,
502 ObjectIdGetDatum(constraintId));
503 ScanKeyInit(&key[2],
504 Anum_pg_depend_refobjsubid,
505 BTEqualStrategyNumber, F_INT4EQ,
506 Int32GetDatum(0));
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;
526 break;
530 systable_endscan(scan);
531 heap_close(depRel, AccessShareLock);
533 return indexId;
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;
545 Relation depRel;
546 ScanKeyData key[3];
547 SysScanDesc scan;
548 HeapTuple tup;
550 /* Search the dependency table for the index */
551 depRel = heap_open(DependRelationId, AccessShareLock);
553 ScanKeyInit(&key[0],
554 Anum_pg_depend_classid,
555 BTEqualStrategyNumber, F_OIDEQ,
556 ObjectIdGetDatum(RelationRelationId));
557 ScanKeyInit(&key[1],
558 Anum_pg_depend_objid,
559 BTEqualStrategyNumber, F_OIDEQ,
560 ObjectIdGetDatum(indexId));
561 ScanKeyInit(&key[2],
562 Anum_pg_depend_objsubid,
563 BTEqualStrategyNumber, F_INT4EQ,
564 Int32GetDatum(0));
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;
582 break;
586 systable_endscan(scan);
587 heap_close(depRel, AccessShareLock);
589 return constraintId;