1 /*-------------------------------------------------------------------------
4 * routines to support manipulation of the pg_constraint relation
6 * Portions Copyright (c) 1996-2008, 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_operator.h"
23 #include "catalog/pg_type.h"
24 #include "commands/defrem.h"
25 #include "utils/array.h"
26 #include "utils/builtins.h"
27 #include "utils/fmgroids.h"
28 #include "utils/lsyscache.h"
29 #include "utils/rel.h"
30 #include "utils/syscache.h"
31 #include "utils/tqual.h"
35 * CreateConstraintEntry
36 * Create a constraint table entry.
38 * Subsidiary records (such as triggers or indexes to implement the
39 * constraint) are *not* created here. But we do make dependency links
40 * from the constraint to the things it depends on.
43 CreateConstraintEntry(const char *constraintName
,
44 Oid constraintNamespace
,
49 const int16
*constraintKey
,
53 const int16
*foreignKey
,
58 char foreignUpdateType
,
59 char foreignDeleteType
,
60 char foreignMatchType
,
71 char nulls
[Natts_pg_constraint
];
72 Datum values
[Natts_pg_constraint
];
73 ArrayType
*conkeyArray
;
74 ArrayType
*confkeyArray
;
75 ArrayType
*conpfeqopArray
;
76 ArrayType
*conppeqopArray
;
77 ArrayType
*conffeqopArray
;
80 ObjectAddress conobject
;
82 conDesc
= heap_open(ConstraintRelationId
, RowExclusiveLock
);
84 Assert(constraintName
);
85 namestrcpy(&cname
, constraintName
);
88 * Convert C arrays into Postgres arrays.
90 if (constraintNKeys
> 0)
94 conkey
= (Datum
*) palloc(constraintNKeys
* sizeof(Datum
));
95 for (i
= 0; i
< constraintNKeys
; i
++)
96 conkey
[i
] = Int16GetDatum(constraintKey
[i
]);
97 conkeyArray
= construct_array(conkey
, constraintNKeys
,
98 INT2OID
, 2, true, 's');
103 if (foreignNKeys
> 0)
107 fkdatums
= (Datum
*) palloc(foreignNKeys
* sizeof(Datum
));
108 for (i
= 0; i
< foreignNKeys
; i
++)
109 fkdatums
[i
] = Int16GetDatum(foreignKey
[i
]);
110 confkeyArray
= construct_array(fkdatums
, foreignNKeys
,
111 INT2OID
, 2, true, 's');
112 for (i
= 0; i
< foreignNKeys
; i
++)
113 fkdatums
[i
] = ObjectIdGetDatum(pfEqOp
[i
]);
114 conpfeqopArray
= construct_array(fkdatums
, foreignNKeys
,
115 OIDOID
, sizeof(Oid
), true, 'i');
116 for (i
= 0; i
< foreignNKeys
; i
++)
117 fkdatums
[i
] = ObjectIdGetDatum(ppEqOp
[i
]);
118 conppeqopArray
= construct_array(fkdatums
, foreignNKeys
,
119 OIDOID
, sizeof(Oid
), true, 'i');
120 for (i
= 0; i
< foreignNKeys
; i
++)
121 fkdatums
[i
] = ObjectIdGetDatum(ffEqOp
[i
]);
122 conffeqopArray
= construct_array(fkdatums
, foreignNKeys
,
123 OIDOID
, sizeof(Oid
), true, 'i');
128 conpfeqopArray
= NULL
;
129 conppeqopArray
= NULL
;
130 conffeqopArray
= NULL
;
133 /* initialize nulls and values */
134 for (i
= 0; i
< Natts_pg_constraint
; i
++)
137 values
[i
] = (Datum
) NULL
;
140 values
[Anum_pg_constraint_conname
- 1] = NameGetDatum(&cname
);
141 values
[Anum_pg_constraint_connamespace
- 1] = ObjectIdGetDatum(constraintNamespace
);
142 values
[Anum_pg_constraint_contype
- 1] = CharGetDatum(constraintType
);
143 values
[Anum_pg_constraint_condeferrable
- 1] = BoolGetDatum(isDeferrable
);
144 values
[Anum_pg_constraint_condeferred
- 1] = BoolGetDatum(isDeferred
);
145 values
[Anum_pg_constraint_conrelid
- 1] = ObjectIdGetDatum(relId
);
146 values
[Anum_pg_constraint_contypid
- 1] = ObjectIdGetDatum(domainId
);
147 values
[Anum_pg_constraint_confrelid
- 1] = ObjectIdGetDatum(foreignRelId
);
148 values
[Anum_pg_constraint_confupdtype
- 1] = CharGetDatum(foreignUpdateType
);
149 values
[Anum_pg_constraint_confdeltype
- 1] = CharGetDatum(foreignDeleteType
);
150 values
[Anum_pg_constraint_confmatchtype
- 1] = CharGetDatum(foreignMatchType
);
151 values
[Anum_pg_constraint_conislocal
- 1] = BoolGetDatum(conIsLocal
);
152 values
[Anum_pg_constraint_coninhcount
- 1] = Int32GetDatum(conInhCount
);
155 values
[Anum_pg_constraint_conkey
- 1] = PointerGetDatum(conkeyArray
);
157 nulls
[Anum_pg_constraint_conkey
- 1] = 'n';
160 values
[Anum_pg_constraint_confkey
- 1] = PointerGetDatum(confkeyArray
);
162 nulls
[Anum_pg_constraint_confkey
- 1] = 'n';
165 values
[Anum_pg_constraint_conpfeqop
- 1] = PointerGetDatum(conpfeqopArray
);
167 nulls
[Anum_pg_constraint_conpfeqop
- 1] = 'n';
170 values
[Anum_pg_constraint_conppeqop
- 1] = PointerGetDatum(conppeqopArray
);
172 nulls
[Anum_pg_constraint_conppeqop
- 1] = 'n';
175 values
[Anum_pg_constraint_conffeqop
- 1] = PointerGetDatum(conffeqopArray
);
177 nulls
[Anum_pg_constraint_conffeqop
- 1] = 'n';
180 * initialize the binary form of the check constraint.
183 values
[Anum_pg_constraint_conbin
- 1] = CStringGetTextDatum(conBin
);
185 nulls
[Anum_pg_constraint_conbin
- 1] = 'n';
188 * initialize the text form of the check constraint
191 values
[Anum_pg_constraint_consrc
- 1] = CStringGetTextDatum(conSrc
);
193 nulls
[Anum_pg_constraint_consrc
- 1] = 'n';
195 tup
= heap_formtuple(RelationGetDescr(conDesc
), values
, nulls
);
197 conOid
= simple_heap_insert(conDesc
, tup
);
199 /* update catalog indexes */
200 CatalogUpdateIndexes(conDesc
, tup
);
202 conobject
.classId
= ConstraintRelationId
;
203 conobject
.objectId
= conOid
;
204 conobject
.objectSubId
= 0;
206 heap_close(conDesc
, RowExclusiveLock
);
208 if (OidIsValid(relId
))
211 * Register auto dependency from constraint to owning relation, or to
212 * specific column(s) if any are mentioned.
214 ObjectAddress relobject
;
216 relobject
.classId
= RelationRelationId
;
217 relobject
.objectId
= relId
;
218 if (constraintNKeys
> 0)
220 for (i
= 0; i
< constraintNKeys
; i
++)
222 relobject
.objectSubId
= constraintKey
[i
];
224 recordDependencyOn(&conobject
, &relobject
, DEPENDENCY_AUTO
);
229 relobject
.objectSubId
= 0;
231 recordDependencyOn(&conobject
, &relobject
, DEPENDENCY_AUTO
);
235 if (OidIsValid(domainId
))
238 * Register auto dependency from constraint to owning domain
240 ObjectAddress domobject
;
242 domobject
.classId
= TypeRelationId
;
243 domobject
.objectId
= domainId
;
244 domobject
.objectSubId
= 0;
246 recordDependencyOn(&conobject
, &domobject
, DEPENDENCY_AUTO
);
249 if (OidIsValid(foreignRelId
))
252 * Register normal dependency from constraint to foreign relation, or
253 * to specific column(s) if any are mentioned.
255 ObjectAddress relobject
;
257 relobject
.classId
= RelationRelationId
;
258 relobject
.objectId
= foreignRelId
;
259 if (foreignNKeys
> 0)
261 for (i
= 0; i
< foreignNKeys
; i
++)
263 relobject
.objectSubId
= foreignKey
[i
];
265 recordDependencyOn(&conobject
, &relobject
, DEPENDENCY_NORMAL
);
270 relobject
.objectSubId
= 0;
272 recordDependencyOn(&conobject
, &relobject
, DEPENDENCY_NORMAL
);
276 if (OidIsValid(indexRelId
))
279 * Register normal dependency on the unique index that supports a
280 * foreign-key constraint.
282 ObjectAddress relobject
;
284 relobject
.classId
= RelationRelationId
;
285 relobject
.objectId
= indexRelId
;
286 relobject
.objectSubId
= 0;
288 recordDependencyOn(&conobject
, &relobject
, DEPENDENCY_NORMAL
);
291 if (foreignNKeys
> 0)
294 * Register normal dependencies on the equality operators that support
295 * a foreign-key constraint. If the PK and FK types are the same then
296 * all three operators for a column are the same; otherwise they are
299 ObjectAddress oprobject
;
301 oprobject
.classId
= OperatorRelationId
;
302 oprobject
.objectSubId
= 0;
304 for (i
= 0; i
< foreignNKeys
; i
++)
306 oprobject
.objectId
= pfEqOp
[i
];
307 recordDependencyOn(&conobject
, &oprobject
, DEPENDENCY_NORMAL
);
308 if (ppEqOp
[i
] != pfEqOp
[i
])
310 oprobject
.objectId
= ppEqOp
[i
];
311 recordDependencyOn(&conobject
, &oprobject
, DEPENDENCY_NORMAL
);
313 if (ffEqOp
[i
] != pfEqOp
[i
])
315 oprobject
.objectId
= ffEqOp
[i
];
316 recordDependencyOn(&conobject
, &oprobject
, DEPENDENCY_NORMAL
);
324 * Register dependencies from constraint to objects mentioned in CHECK
327 recordDependencyOnSingleRelExpr(&conobject
, conExpr
, relId
,
337 * Test whether given name is currently used as a constraint name
338 * for the given object (relation or domain).
340 * This is used to decide whether to accept a user-specified constraint name.
341 * It is deliberately not the same test as ChooseConstraintName uses to decide
342 * whether an auto-generated name is OK: here, we will allow it unless there
343 * is an identical constraint name in use *on the same object*.
345 * NB: Caller should hold exclusive lock on the given object, else
346 * this test can be fooled by concurrent additions.
349 ConstraintNameIsUsed(ConstraintCategory conCat
, Oid objId
,
350 Oid objNamespace
, const char *conname
)
358 conDesc
= heap_open(ConstraintRelationId
, AccessShareLock
);
362 ScanKeyInit(&skey
[0],
363 Anum_pg_constraint_conname
,
364 BTEqualStrategyNumber
, F_NAMEEQ
,
365 CStringGetDatum(conname
));
367 ScanKeyInit(&skey
[1],
368 Anum_pg_constraint_connamespace
,
369 BTEqualStrategyNumber
, F_OIDEQ
,
370 ObjectIdGetDatum(objNamespace
));
372 conscan
= systable_beginscan(conDesc
, ConstraintNameNspIndexId
, true,
373 SnapshotNow
, 2, skey
);
375 while (HeapTupleIsValid(tup
= systable_getnext(conscan
)))
377 Form_pg_constraint con
= (Form_pg_constraint
) GETSTRUCT(tup
);
379 if (conCat
== CONSTRAINT_RELATION
&& con
->conrelid
== objId
)
384 else if (conCat
== CONSTRAINT_DOMAIN
&& con
->contypid
== objId
)
391 systable_endscan(conscan
);
392 heap_close(conDesc
, AccessShareLock
);
398 * Select a nonconflicting name for a new constraint.
400 * The objective here is to choose a name that is unique within the
401 * specified namespace. Postgres does not require this, but the SQL
402 * spec does, and some apps depend on it. Therefore we avoid choosing
403 * default names that so conflict.
405 * name1, name2, and label are used the same way as for makeObjectName(),
406 * except that the label can't be NULL; digits will be appended to the label
407 * if needed to create a name that is unique within the specified namespace.
409 * 'others' can be a list of string names already chosen within the current
410 * command (but not yet reflected into the catalogs); we will not choose
411 * a duplicate of one of these either.
413 * Note: it is theoretically possible to get a collision anyway, if someone
414 * else chooses the same name concurrently. This is fairly unlikely to be
415 * a problem in practice, especially if one is holding an exclusive lock on
416 * the relation identified by name1.
418 * Returns a palloc'd string.
421 ChooseConstraintName(const char *name1
, const char *name2
,
422 const char *label
, Oid
namespace,
426 char *conname
= NULL
;
427 char modlabel
[NAMEDATALEN
];
434 conDesc
= heap_open(ConstraintRelationId
, AccessShareLock
);
436 /* try the unmodified label first */
437 StrNCpy(modlabel
, label
, sizeof(modlabel
));
441 conname
= makeObjectName(name1
, name2
, modlabel
);
447 if (strcmp((char *) lfirst(l
), conname
) == 0)
456 ScanKeyInit(&skey
[0],
457 Anum_pg_constraint_conname
,
458 BTEqualStrategyNumber
, F_NAMEEQ
,
459 CStringGetDatum(conname
));
461 ScanKeyInit(&skey
[1],
462 Anum_pg_constraint_connamespace
,
463 BTEqualStrategyNumber
, F_OIDEQ
,
464 ObjectIdGetDatum(namespace));
466 conscan
= systable_beginscan(conDesc
, ConstraintNameNspIndexId
, true,
467 SnapshotNow
, 2, skey
);
469 found
= (HeapTupleIsValid(systable_getnext(conscan
)));
471 systable_endscan(conscan
);
477 /* found a conflict, so try a new name component */
479 snprintf(modlabel
, sizeof(modlabel
), "%s%d", label
, ++pass
);
482 heap_close(conDesc
, AccessShareLock
);
488 * Delete a single constraint record.
491 RemoveConstraintById(Oid conId
)
495 Form_pg_constraint con
;
497 conDesc
= heap_open(ConstraintRelationId
, RowExclusiveLock
);
499 tup
= SearchSysCache(CONSTROID
,
500 ObjectIdGetDatum(conId
),
502 if (!HeapTupleIsValid(tup
)) /* should not happen */
503 elog(ERROR
, "cache lookup failed for constraint %u", conId
);
504 con
= (Form_pg_constraint
) GETSTRUCT(tup
);
507 * Special processing depending on what the constraint is for.
509 if (OidIsValid(con
->conrelid
))
514 * If the constraint is for a relation, open and exclusive-lock the
517 rel
= heap_open(con
->conrelid
, AccessExclusiveLock
);
520 * We need to update the relcheck count if it is a check constraint
521 * being dropped. This update will force backends to rebuild relcache
522 * entries when we commit.
524 if (con
->contype
== CONSTRAINT_CHECK
)
528 Form_pg_class classForm
;
530 pgrel
= heap_open(RelationRelationId
, RowExclusiveLock
);
531 relTup
= SearchSysCacheCopy(RELOID
,
532 ObjectIdGetDatum(con
->conrelid
),
534 if (!HeapTupleIsValid(relTup
))
535 elog(ERROR
, "cache lookup failed for relation %u",
537 classForm
= (Form_pg_class
) GETSTRUCT(relTup
);
539 if (classForm
->relchecks
== 0) /* should not happen */
540 elog(ERROR
, "relation \"%s\" has relchecks = 0",
541 RelationGetRelationName(rel
));
542 classForm
->relchecks
--;
544 simple_heap_update(pgrel
, &relTup
->t_self
, relTup
);
546 CatalogUpdateIndexes(pgrel
, relTup
);
548 heap_freetuple(relTup
);
550 heap_close(pgrel
, RowExclusiveLock
);
553 /* Keep lock on constraint's rel until end of xact */
554 heap_close(rel
, NoLock
);
556 else if (OidIsValid(con
->contypid
))
559 * XXX for now, do nothing special when dropping a domain constraint
561 * Probably there should be some form of locking on the domain type,
562 * but we have no such concept at the moment.
566 elog(ERROR
, "constraint %u is not of a known type", conId
);
568 /* Fry the constraint itself */
569 simple_heap_delete(conDesc
, &tup
->t_self
);
572 ReleaseSysCache(tup
);
573 heap_close(conDesc
, RowExclusiveLock
);
577 * RenameConstraintById
578 * Rename a constraint.
580 * Note: this isn't intended to be a user-exposed function; it doesn't check
581 * permissions etc. Currently this is only invoked when renaming an index
582 * that is associated with a constraint, but it's made a little more general
583 * than that with the expectation of someday having ALTER TABLE RENAME
587 RenameConstraintById(Oid conId
, const char *newname
)
591 Form_pg_constraint con
;
593 conDesc
= heap_open(ConstraintRelationId
, RowExclusiveLock
);
595 tuple
= SearchSysCacheCopy(CONSTROID
,
596 ObjectIdGetDatum(conId
),
598 if (!HeapTupleIsValid(tuple
))
599 elog(ERROR
, "cache lookup failed for constraint %u", conId
);
600 con
= (Form_pg_constraint
) GETSTRUCT(tuple
);
603 * We need to check whether the name is already in use --- note that
604 * there currently is not a unique index that would catch this.
606 if (OidIsValid(con
->conrelid
) &&
607 ConstraintNameIsUsed(CONSTRAINT_RELATION
,
612 (errcode(ERRCODE_DUPLICATE_OBJECT
),
613 errmsg("constraint \"%s\" for relation \"%s\" already exists",
614 newname
, get_rel_name(con
->conrelid
))));
615 if (OidIsValid(con
->contypid
) &&
616 ConstraintNameIsUsed(CONSTRAINT_DOMAIN
,
621 (errcode(ERRCODE_DUPLICATE_OBJECT
),
622 errmsg("constraint \"%s\" for domain \"%s\" already exists",
623 newname
, format_type_be(con
->contypid
))));
625 /* OK, do the rename --- tuple is a copy, so OK to scribble on it */
626 namestrcpy(&(con
->conname
), newname
);
628 simple_heap_update(conDesc
, &tuple
->t_self
, tuple
);
630 /* update the system catalog indexes */
631 CatalogUpdateIndexes(conDesc
, tuple
);
633 heap_freetuple(tuple
);
634 heap_close(conDesc
, RowExclusiveLock
);
638 * AlterConstraintNamespaces
639 * Find any constraints belonging to the specified object,
640 * and move them to the specified new namespace.
642 * isType indicates whether the owning object is a type or a relation.
645 AlterConstraintNamespaces(Oid ownerId
, Oid oldNspId
,
646 Oid newNspId
, bool isType
)
653 conRel
= heap_open(ConstraintRelationId
, RowExclusiveLock
);
658 Anum_pg_constraint_contypid
,
659 BTEqualStrategyNumber
, F_OIDEQ
,
660 ObjectIdGetDatum(ownerId
));
662 scan
= systable_beginscan(conRel
, ConstraintTypidIndexId
, true,
663 SnapshotNow
, 1, key
);
668 Anum_pg_constraint_conrelid
,
669 BTEqualStrategyNumber
, F_OIDEQ
,
670 ObjectIdGetDatum(ownerId
));
672 scan
= systable_beginscan(conRel
, ConstraintRelidIndexId
, true,
673 SnapshotNow
, 1, key
);
676 while (HeapTupleIsValid((tup
= systable_getnext(scan
))))
678 Form_pg_constraint conform
= (Form_pg_constraint
) GETSTRUCT(tup
);
680 if (conform
->connamespace
== oldNspId
)
682 tup
= heap_copytuple(tup
);
683 conform
= (Form_pg_constraint
) GETSTRUCT(tup
);
685 conform
->connamespace
= newNspId
;
687 simple_heap_update(conRel
, &tup
->t_self
, tup
);
688 CatalogUpdateIndexes(conRel
, tup
);
691 * Note: currently, the constraint will not have its own
692 * dependency on the namespace, so we don't need to do
693 * changeDependencyFor().
698 systable_endscan(scan
);
700 heap_close(conRel
, RowExclusiveLock
);