]> granicus.if.org Git - postgresql/blob - src/backend/catalog/pg_depend.c
Remove cvs keywords from all files.
[postgresql] / src / backend / catalog / pg_depend.c
1 /*-------------------------------------------------------------------------
2  *
3  * pg_depend.c
4  *        routines to support manipulation of the pg_depend relation
5  *
6  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        src/backend/catalog/pg_depend.c
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16
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"
28
29
30 static bool isObjectPinned(const ObjectAddress *object, Relation rel);
31
32
33 /*
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.
37  *
38  * This simply creates an entry in pg_depend, without any other processing.
39  */
40 void
41 recordDependencyOn(const ObjectAddress *depender,
42                                    const ObjectAddress *referenced,
43                                    DependencyType behavior)
44 {
45         recordMultipleDependencies(depender, referenced, 1, behavior);
46 }
47
48 /*
49  * Record multiple dependencies (of the same kind) for a single dependent
50  * object.      This has a little less overhead than recording each separately.
51  */
52 void
53 recordMultipleDependencies(const ObjectAddress *depender,
54                                                    const ObjectAddress *referenced,
55                                                    int nreferenced,
56                                                    DependencyType behavior)
57 {
58         Relation        dependDesc;
59         CatalogIndexState indstate;
60         HeapTuple       tup;
61         int                     i;
62         bool            nulls[Natts_pg_depend];
63         Datum           values[Natts_pg_depend];
64
65         if (nreferenced <= 0)
66                 return;                                 /* nothing to do */
67
68         /*
69          * During bootstrap, do nothing since pg_depend may not exist yet. initdb
70          * will fill in appropriate pg_depend entries after bootstrap.
71          */
72         if (IsBootstrapProcessingMode())
73                 return;
74
75         dependDesc = heap_open(DependRelationId, RowExclusiveLock);
76
77         /* Don't open indexes unless we need to make an update */
78         indstate = NULL;
79
80         memset(nulls, false, sizeof(nulls));
81
82         for (i = 0; i < nreferenced; i++, referenced++)
83         {
84                 /*
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.
88                  */
89                 if (!isObjectPinned(referenced, dependDesc))
90                 {
91                         /*
92                          * Record the Dependency.  Note we don't bother to check for
93                          * duplicate dependencies; there's no harm in them.
94                          */
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);
98
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);
102
103                         values[Anum_pg_depend_deptype - 1] = CharGetDatum((char) behavior);
104
105                         tup = heap_form_tuple(dependDesc->rd_att, values, nulls);
106
107                         simple_heap_insert(dependDesc, tup);
108
109                         /* keep indexes current */
110                         if (indstate == NULL)
111                                 indstate = CatalogOpenIndexes(dependDesc);
112
113                         CatalogIndexInsert(indstate, tup);
114
115                         heap_freetuple(tup);
116                 }
117         }
118
119         if (indstate != NULL)
120                 CatalogCloseIndexes(indstate);
121
122         heap_close(dependDesc, RowExclusiveLock);
123 }
124
125 /*
126  * deleteDependencyRecordsFor -- delete all records with given depender
127  * classId/objectId.  Returns the number of records deleted.
128  *
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).
132  */
133 long
134 deleteDependencyRecordsFor(Oid classId, Oid objectId)
135 {
136         long            count = 0;
137         Relation        depRel;
138         ScanKeyData key[2];
139         SysScanDesc scan;
140         HeapTuple       tup;
141
142         depRel = heap_open(DependRelationId, RowExclusiveLock);
143
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));
152
153         scan = systable_beginscan(depRel, DependDependerIndexId, true,
154                                                           SnapshotNow, 2, key);
155
156         while (HeapTupleIsValid(tup = systable_getnext(scan)))
157         {
158                 simple_heap_delete(depRel, &tup->t_self);
159                 count++;
160         }
161
162         systable_endscan(scan);
163
164         heap_close(depRel, RowExclusiveLock);
165
166         return count;
167 }
168
169 /*
170  * Adjust dependency record(s) to point to a different object of the same type
171  *
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).
175  *
176  * Note the lack of objsubid parameters.  If there are subobject references
177  * they will all be readjusted.
178  *
179  * Returns the number of records updated.
180  */
181 long
182 changeDependencyFor(Oid classId, Oid objectId,
183                                         Oid refClassId, Oid oldRefObjectId,
184                                         Oid newRefObjectId)
185 {
186         long            count = 0;
187         Relation        depRel;
188         ScanKeyData key[2];
189         SysScanDesc scan;
190         HeapTuple       tup;
191         ObjectAddress objAddr;
192         bool            newIsPinned;
193
194         depRel = heap_open(DependRelationId, RowExclusiveLock);
195
196         /*
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.)
201          */
202         objAddr.classId = refClassId;
203         objAddr.objectId = oldRefObjectId;
204         objAddr.objectSubId = 0;
205
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))));
211
212         /*
213          * We can handle adding a dependency on something pinned, though, since
214          * that just means deleting the dependency entry.
215          */
216         objAddr.objectId = newRefObjectId;
217
218         newIsPinned = isObjectPinned(&objAddr, depRel);
219
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));
229
230         scan = systable_beginscan(depRel, DependDependerIndexId, true,
231                                                           SnapshotNow, 2, key);
232
233         while (HeapTupleIsValid((tup = systable_getnext(scan))))
234         {
235                 Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
236
237                 if (depform->refclassid == refClassId &&
238                         depform->refobjid == oldRefObjectId)
239                 {
240                         if (newIsPinned)
241                                 simple_heap_delete(depRel, &tup->t_self);
242                         else
243                         {
244                                 /* make a modifiable copy */
245                                 tup = heap_copytuple(tup);
246                                 depform = (Form_pg_depend) GETSTRUCT(tup);
247
248                                 depform->refobjid = newRefObjectId;
249
250                                 simple_heap_update(depRel, &tup->t_self, tup);
251                                 CatalogUpdateIndexes(depRel, tup);
252
253                                 heap_freetuple(tup);
254                         }
255
256                         count++;
257                 }
258         }
259
260         systable_endscan(scan);
261
262         heap_close(depRel, RowExclusiveLock);
263
264         return count;
265 }
266
267 /*
268  * isObjectPinned()
269  *
270  * Test if an object is required for basic database functionality.
271  * Caller must already have opened pg_depend.
272  *
273  * The passed subId, if any, is ignored; we assume that only whole objects
274  * are pinned (and that this implies pinning their components).
275  */
276 static bool
277 isObjectPinned(const ObjectAddress *object, Relation rel)
278 {
279         bool            ret = false;
280         SysScanDesc scan;
281         HeapTuple       tup;
282         ScanKeyData key[2];
283
284         ScanKeyInit(&key[0],
285                                 Anum_pg_depend_refclassid,
286                                 BTEqualStrategyNumber, F_OIDEQ,
287                                 ObjectIdGetDatum(object->classId));
288
289         ScanKeyInit(&key[1],
290                                 Anum_pg_depend_refobjid,
291                                 BTEqualStrategyNumber, F_OIDEQ,
292                                 ObjectIdGetDatum(object->objectId));
293
294         scan = systable_beginscan(rel, DependReferenceIndexId, true,
295                                                           SnapshotNow, 2, key);
296
297         /*
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.
302          */
303         tup = systable_getnext(scan);
304         if (HeapTupleIsValid(tup))
305         {
306                 Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(tup);
307
308                 if (foundDep->deptype == DEPENDENCY_PIN)
309                         ret = true;
310         }
311
312         systable_endscan(scan);
313
314         return ret;
315 }
316
317
318 /*
319  * Various special-purpose lookups and manipulations of pg_depend.
320  */
321
322
323 /*
324  * Detect whether a sequence is marked as "owned" by a column
325  *
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.
329  *
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.
333  */
334 bool
335 sequenceIsOwned(Oid seqId, Oid *tableId, int32 *colId)
336 {
337         bool            ret = false;
338         Relation        depRel;
339         ScanKeyData key[2];
340         SysScanDesc scan;
341         HeapTuple       tup;
342
343         depRel = heap_open(DependRelationId, AccessShareLock);
344
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));
353
354         scan = systable_beginscan(depRel, DependDependerIndexId, true,
355                                                           SnapshotNow, 2, key);
356
357         while (HeapTupleIsValid((tup = systable_getnext(scan))))
358         {
359                 Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
360
361                 if (depform->refclassid == RelationRelationId &&
362                         depform->deptype == DEPENDENCY_AUTO)
363                 {
364                         *tableId = depform->refobjid;
365                         *colId = depform->refobjsubid;
366                         ret = true;
367                         break;                          /* no need to keep scanning */
368                 }
369         }
370
371         systable_endscan(scan);
372
373         heap_close(depRel, AccessShareLock);
374
375         return ret;
376 }
377
378 /*
379  * Remove any existing "owned" markers for the specified sequence.
380  *
381  * Note: we don't provide a special function to install an "owned"
382  * marker; just use recordDependencyOn().
383  */
384 void
385 markSequenceUnowned(Oid seqId)
386 {
387         Relation        depRel;
388         ScanKeyData key[2];
389         SysScanDesc scan;
390         HeapTuple       tup;
391
392         depRel = heap_open(DependRelationId, RowExclusiveLock);
393
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));
402
403         scan = systable_beginscan(depRel, DependDependerIndexId, true,
404                                                           SnapshotNow, 2, key);
405
406         while (HeapTupleIsValid((tup = systable_getnext(scan))))
407         {
408                 Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
409
410                 if (depform->refclassid == RelationRelationId &&
411                         depform->deptype == DEPENDENCY_AUTO)
412                 {
413                         simple_heap_delete(depRel, &tup->t_self);
414                 }
415         }
416
417         systable_endscan(scan);
418
419         heap_close(depRel, RowExclusiveLock);
420 }
421
422 /*
423  * Collect a list of OIDs of all sequences owned by the specified relation.
424  */
425 List *
426 getOwnedSequences(Oid relid)
427 {
428         List       *result = NIL;
429         Relation        depRel;
430         ScanKeyData key[2];
431         SysScanDesc scan;
432         HeapTuple       tup;
433
434         depRel = heap_open(DependRelationId, AccessShareLock);
435
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));
444
445         scan = systable_beginscan(depRel, DependReferenceIndexId, true,
446                                                           SnapshotNow, 2, key);
447
448         while (HeapTupleIsValid(tup = systable_getnext(scan)))
449         {
450                 Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
451
452                 /*
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.)
456                  */
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)
462                 {
463                         result = lappend_oid(result, deprec->objid);
464                 }
465         }
466
467         systable_endscan(scan);
468
469         heap_close(depRel, AccessShareLock);
470
471         return result;
472 }
473
474
475 /*
476  * get_constraint_index
477  *              Given the OID of a unique or primary-key constraint, return the
478  *              OID of the underlying unique index.
479  *
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.
482  */
483 Oid
484 get_constraint_index(Oid constraintId)
485 {
486         Oid                     indexId = InvalidOid;
487         Relation        depRel;
488         ScanKeyData key[3];
489         SysScanDesc scan;
490         HeapTuple       tup;
491
492         /* Search the dependency table for the dependent index */
493         depRel = heap_open(DependRelationId, AccessShareLock);
494
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));
507
508         scan = systable_beginscan(depRel, DependReferenceIndexId, true,
509                                                           SnapshotNow, 3, key);
510
511         while (HeapTupleIsValid(tup = systable_getnext(scan)))
512         {
513                 Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
514
515                 /*
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.)
519                  */
520                 if (deprec->classid == RelationRelationId &&
521                         deprec->objsubid == 0 &&
522                         deprec->deptype == DEPENDENCY_INTERNAL &&
523                         get_rel_relkind(deprec->objid) == RELKIND_INDEX)
524                 {
525                         indexId = deprec->objid;
526                         break;
527                 }
528         }
529
530         systable_endscan(scan);
531         heap_close(depRel, AccessShareLock);
532
533         return indexId;
534 }
535
536 /*
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.
540  */
541 Oid
542 get_index_constraint(Oid indexId)
543 {
544         Oid                     constraintId = InvalidOid;
545         Relation        depRel;
546         ScanKeyData key[3];
547         SysScanDesc scan;
548         HeapTuple       tup;
549
550         /* Search the dependency table for the index */
551         depRel = heap_open(DependRelationId, AccessShareLock);
552
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));
565
566         scan = systable_beginscan(depRel, DependDependerIndexId, true,
567                                                           SnapshotNow, 3, key);
568
569         while (HeapTupleIsValid(tup = systable_getnext(scan)))
570         {
571                 Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
572
573                 /*
574                  * We assume any internal dependency on a constraint must be what we
575                  * are looking for.
576                  */
577                 if (deprec->refclassid == ConstraintRelationId &&
578                         deprec->refobjsubid == 0 &&
579                         deprec->deptype == DEPENDENCY_INTERNAL)
580                 {
581                         constraintId = deprec->refobjid;
582                         break;
583                 }
584         }
585
586         systable_endscan(scan);
587         heap_close(depRel, AccessShareLock);
588
589         return constraintId;
590 }