]> granicus.if.org Git - postgresql/blob - src/backend/catalog/pg_constraint.c
Change the rules for inherited CHECK constraints to be essentially the same
[postgresql] / src / backend / catalog / pg_constraint.c
1 /*-------------------------------------------------------------------------
2  *
3  * pg_constraint.c
4  *        routines to support manipulation of the pg_constraint relation
5  *
6  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        $PostgreSQL: pgsql/src/backend/catalog/pg_constraint.c,v 1.41 2008/05/09 23:32:04 tgl Exp $
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_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/syscache.h"
30 #include "utils/tqual.h"
31
32
33 /*
34  * CreateConstraintEntry
35  *      Create a constraint table entry.
36  *
37  * Subsidiary records (such as triggers or indexes to implement the
38  * constraint) are *not* created here.  But we do make dependency links
39  * from the constraint to the things it depends on.
40  */
41 Oid
42 CreateConstraintEntry(const char *constraintName,
43                                           Oid constraintNamespace,
44                                           char constraintType,
45                                           bool isDeferrable,
46                                           bool isDeferred,
47                                           Oid relId,
48                                           const int16 *constraintKey,
49                                           int constraintNKeys,
50                                           Oid domainId,
51                                           Oid foreignRelId,
52                                           const int16 *foreignKey,
53                                           const Oid *pfEqOp,
54                                           const Oid *ppEqOp,
55                                           const Oid *ffEqOp,
56                                           int foreignNKeys,
57                                           char foreignUpdateType,
58                                           char foreignDeleteType,
59                                           char foreignMatchType,
60                                           Oid indexRelId,
61                                           Node *conExpr,
62                                           const char *conBin,
63                                           const char *conSrc,
64                                           bool conIsLocal,
65                                           int conInhCount)
66 {
67         Relation        conDesc;
68         Oid                     conOid;
69         HeapTuple       tup;
70         char            nulls[Natts_pg_constraint];
71         Datum           values[Natts_pg_constraint];
72         ArrayType  *conkeyArray;
73         ArrayType  *confkeyArray;
74         ArrayType  *conpfeqopArray;
75         ArrayType  *conppeqopArray;
76         ArrayType  *conffeqopArray;
77         NameData        cname;
78         int                     i;
79         ObjectAddress conobject;
80
81         conDesc = heap_open(ConstraintRelationId, RowExclusiveLock);
82
83         Assert(constraintName);
84         namestrcpy(&cname, constraintName);
85
86         /*
87          * Convert C arrays into Postgres arrays.
88          */
89         if (constraintNKeys > 0)
90         {
91                 Datum      *conkey;
92
93                 conkey = (Datum *) palloc(constraintNKeys * sizeof(Datum));
94                 for (i = 0; i < constraintNKeys; i++)
95                         conkey[i] = Int16GetDatum(constraintKey[i]);
96                 conkeyArray = construct_array(conkey, constraintNKeys,
97                                                                           INT2OID, 2, true, 's');
98         }
99         else
100                 conkeyArray = NULL;
101
102         if (foreignNKeys > 0)
103         {
104                 Datum      *fkdatums;
105
106                 fkdatums = (Datum *) palloc(foreignNKeys * sizeof(Datum));
107                 for (i = 0; i < foreignNKeys; i++)
108                         fkdatums[i] = Int16GetDatum(foreignKey[i]);
109                 confkeyArray = construct_array(fkdatums, foreignNKeys,
110                                                                            INT2OID, 2, true, 's');
111                 for (i = 0; i < foreignNKeys; i++)
112                         fkdatums[i] = ObjectIdGetDatum(pfEqOp[i]);
113                 conpfeqopArray = construct_array(fkdatums, foreignNKeys,
114                                                                                  OIDOID, sizeof(Oid), true, 'i');
115                 for (i = 0; i < foreignNKeys; i++)
116                         fkdatums[i] = ObjectIdGetDatum(ppEqOp[i]);
117                 conppeqopArray = construct_array(fkdatums, foreignNKeys,
118                                                                                  OIDOID, sizeof(Oid), true, 'i');
119                 for (i = 0; i < foreignNKeys; i++)
120                         fkdatums[i] = ObjectIdGetDatum(ffEqOp[i]);
121                 conffeqopArray = construct_array(fkdatums, foreignNKeys,
122                                                                                  OIDOID, sizeof(Oid), true, 'i');
123         }
124         else
125         {
126                 confkeyArray = NULL;
127                 conpfeqopArray = NULL;
128                 conppeqopArray = NULL;
129                 conffeqopArray = NULL;
130         }
131
132         /* initialize nulls and values */
133         for (i = 0; i < Natts_pg_constraint; i++)
134         {
135                 nulls[i] = ' ';
136                 values[i] = (Datum) NULL;
137         }
138
139         values[Anum_pg_constraint_conname - 1] = NameGetDatum(&cname);
140         values[Anum_pg_constraint_connamespace - 1] = ObjectIdGetDatum(constraintNamespace);
141         values[Anum_pg_constraint_contype - 1] = CharGetDatum(constraintType);
142         values[Anum_pg_constraint_condeferrable - 1] = BoolGetDatum(isDeferrable);
143         values[Anum_pg_constraint_condeferred - 1] = BoolGetDatum(isDeferred);
144         values[Anum_pg_constraint_conrelid - 1] = ObjectIdGetDatum(relId);
145         values[Anum_pg_constraint_contypid - 1] = ObjectIdGetDatum(domainId);
146         values[Anum_pg_constraint_confrelid - 1] = ObjectIdGetDatum(foreignRelId);
147         values[Anum_pg_constraint_confupdtype - 1] = CharGetDatum(foreignUpdateType);
148         values[Anum_pg_constraint_confdeltype - 1] = CharGetDatum(foreignDeleteType);
149         values[Anum_pg_constraint_confmatchtype - 1] = CharGetDatum(foreignMatchType);
150         values[Anum_pg_constraint_conislocal - 1] = BoolGetDatum(conIsLocal);
151         values[Anum_pg_constraint_coninhcount - 1] = Int32GetDatum(conInhCount);
152
153         if (conkeyArray)
154                 values[Anum_pg_constraint_conkey - 1] = PointerGetDatum(conkeyArray);
155         else
156                 nulls[Anum_pg_constraint_conkey - 1] = 'n';
157
158         if (confkeyArray)
159                 values[Anum_pg_constraint_confkey - 1] = PointerGetDatum(confkeyArray);
160         else
161                 nulls[Anum_pg_constraint_confkey - 1] = 'n';
162
163         if (conpfeqopArray)
164                 values[Anum_pg_constraint_conpfeqop - 1] = PointerGetDatum(conpfeqopArray);
165         else
166                 nulls[Anum_pg_constraint_conpfeqop - 1] = 'n';
167
168         if (conppeqopArray)
169                 values[Anum_pg_constraint_conppeqop - 1] = PointerGetDatum(conppeqopArray);
170         else
171                 nulls[Anum_pg_constraint_conppeqop - 1] = 'n';
172
173         if (conffeqopArray)
174                 values[Anum_pg_constraint_conffeqop - 1] = PointerGetDatum(conffeqopArray);
175         else
176                 nulls[Anum_pg_constraint_conffeqop - 1] = 'n';
177
178         /*
179          * initialize the binary form of the check constraint.
180          */
181         if (conBin)
182                 values[Anum_pg_constraint_conbin - 1] = CStringGetTextDatum(conBin);
183         else
184                 nulls[Anum_pg_constraint_conbin - 1] = 'n';
185
186         /*
187          * initialize the text form of the check constraint
188          */
189         if (conSrc)
190                 values[Anum_pg_constraint_consrc - 1] = CStringGetTextDatum(conSrc);
191         else
192                 nulls[Anum_pg_constraint_consrc - 1] = 'n';
193
194         tup = heap_formtuple(RelationGetDescr(conDesc), values, nulls);
195
196         conOid = simple_heap_insert(conDesc, tup);
197
198         /* update catalog indexes */
199         CatalogUpdateIndexes(conDesc, tup);
200
201         conobject.classId = ConstraintRelationId;
202         conobject.objectId = conOid;
203         conobject.objectSubId = 0;
204
205         heap_close(conDesc, RowExclusiveLock);
206
207         if (OidIsValid(relId))
208         {
209                 /*
210                  * Register auto dependency from constraint to owning relation, or to
211                  * specific column(s) if any are mentioned.
212                  */
213                 ObjectAddress relobject;
214
215                 relobject.classId = RelationRelationId;
216                 relobject.objectId = relId;
217                 if (constraintNKeys > 0)
218                 {
219                         for (i = 0; i < constraintNKeys; i++)
220                         {
221                                 relobject.objectSubId = constraintKey[i];
222
223                                 recordDependencyOn(&conobject, &relobject, DEPENDENCY_AUTO);
224                         }
225                 }
226                 else
227                 {
228                         relobject.objectSubId = 0;
229
230                         recordDependencyOn(&conobject, &relobject, DEPENDENCY_AUTO);
231                 }
232         }
233
234         if (OidIsValid(domainId))
235         {
236                 /*
237                  * Register auto dependency from constraint to owning domain
238                  */
239                 ObjectAddress domobject;
240
241                 domobject.classId = TypeRelationId;
242                 domobject.objectId = domainId;
243                 domobject.objectSubId = 0;
244
245                 recordDependencyOn(&conobject, &domobject, DEPENDENCY_AUTO);
246         }
247
248         if (OidIsValid(foreignRelId))
249         {
250                 /*
251                  * Register normal dependency from constraint to foreign relation, or
252                  * to specific column(s) if any are mentioned.
253                  */
254                 ObjectAddress relobject;
255
256                 relobject.classId = RelationRelationId;
257                 relobject.objectId = foreignRelId;
258                 if (foreignNKeys > 0)
259                 {
260                         for (i = 0; i < foreignNKeys; i++)
261                         {
262                                 relobject.objectSubId = foreignKey[i];
263
264                                 recordDependencyOn(&conobject, &relobject, DEPENDENCY_NORMAL);
265                         }
266                 }
267                 else
268                 {
269                         relobject.objectSubId = 0;
270
271                         recordDependencyOn(&conobject, &relobject, DEPENDENCY_NORMAL);
272                 }
273         }
274
275         if (OidIsValid(indexRelId))
276         {
277                 /*
278                  * Register normal dependency on the unique index that supports a
279                  * foreign-key constraint.
280                  */
281                 ObjectAddress relobject;
282
283                 relobject.classId = RelationRelationId;
284                 relobject.objectId = indexRelId;
285                 relobject.objectSubId = 0;
286
287                 recordDependencyOn(&conobject, &relobject, DEPENDENCY_NORMAL);
288         }
289
290         if (foreignNKeys > 0)
291         {
292                 /*
293                  * Register normal dependencies on the equality operators that support
294                  * a foreign-key constraint.  If the PK and FK types are the same then
295                  * all three operators for a column are the same; otherwise they are
296                  * different.
297                  */
298                 ObjectAddress oprobject;
299
300                 oprobject.classId = OperatorRelationId;
301                 oprobject.objectSubId = 0;
302
303                 for (i = 0; i < foreignNKeys; i++)
304                 {
305                         oprobject.objectId = pfEqOp[i];
306                         recordDependencyOn(&conobject, &oprobject, DEPENDENCY_NORMAL);
307                         if (ppEqOp[i] != pfEqOp[i])
308                         {
309                                 oprobject.objectId = ppEqOp[i];
310                                 recordDependencyOn(&conobject, &oprobject, DEPENDENCY_NORMAL);
311                         }
312                         if (ffEqOp[i] != pfEqOp[i])
313                         {
314                                 oprobject.objectId = ffEqOp[i];
315                                 recordDependencyOn(&conobject, &oprobject, DEPENDENCY_NORMAL);
316                         }
317                 }
318         }
319
320         if (conExpr != NULL)
321         {
322                 /*
323                  * Register dependencies from constraint to objects mentioned in CHECK
324                  * expression.
325                  */
326                 recordDependencyOnSingleRelExpr(&conobject, conExpr, relId,
327                                                                                 DEPENDENCY_NORMAL,
328                                                                                 DEPENDENCY_NORMAL);
329         }
330
331         return conOid;
332 }
333
334
335 /*
336  * Test whether given name is currently used as a constraint name
337  * for the given object (relation or domain).
338  *
339  * This is used to decide whether to accept a user-specified constraint name.
340  * It is deliberately not the same test as ChooseConstraintName uses to decide
341  * whether an auto-generated name is OK: here, we will allow it unless there
342  * is an identical constraint name in use *on the same object*.
343  *
344  * NB: Caller should hold exclusive lock on the given object, else
345  * this test can be fooled by concurrent additions.
346  */
347 bool
348 ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId,
349                                          Oid objNamespace, const char *conname)
350 {
351         bool            found;
352         Relation        conDesc;
353         SysScanDesc conscan;
354         ScanKeyData skey[2];
355         HeapTuple       tup;
356
357         conDesc = heap_open(ConstraintRelationId, AccessShareLock);
358
359         found = false;
360
361         ScanKeyInit(&skey[0],
362                                 Anum_pg_constraint_conname,
363                                 BTEqualStrategyNumber, F_NAMEEQ,
364                                 CStringGetDatum(conname));
365
366         ScanKeyInit(&skey[1],
367                                 Anum_pg_constraint_connamespace,
368                                 BTEqualStrategyNumber, F_OIDEQ,
369                                 ObjectIdGetDatum(objNamespace));
370
371         conscan = systable_beginscan(conDesc, ConstraintNameNspIndexId, true,
372                                                                  SnapshotNow, 2, skey);
373
374         while (HeapTupleIsValid(tup = systable_getnext(conscan)))
375         {
376                 Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tup);
377
378                 if (conCat == CONSTRAINT_RELATION && con->conrelid == objId)
379                 {
380                         found = true;
381                         break;
382                 }
383                 else if (conCat == CONSTRAINT_DOMAIN && con->contypid == objId)
384                 {
385                         found = true;
386                         break;
387                 }
388         }
389
390         systable_endscan(conscan);
391         heap_close(conDesc, AccessShareLock);
392
393         return found;
394 }
395
396 /*
397  * Select a nonconflicting name for a new constraint.
398  *
399  * The objective here is to choose a name that is unique within the
400  * specified namespace.  Postgres does not require this, but the SQL
401  * spec does, and some apps depend on it.  Therefore we avoid choosing
402  * default names that so conflict.
403  *
404  * name1, name2, and label are used the same way as for makeObjectName(),
405  * except that the label can't be NULL; digits will be appended to the label
406  * if needed to create a name that is unique within the specified namespace.
407  *
408  * 'others' can be a list of string names already chosen within the current
409  * command (but not yet reflected into the catalogs); we will not choose
410  * a duplicate of one of these either.
411  *
412  * Note: it is theoretically possible to get a collision anyway, if someone
413  * else chooses the same name concurrently.  This is fairly unlikely to be
414  * a problem in practice, especially if one is holding an exclusive lock on
415  * the relation identified by name1.
416  *
417  * Returns a palloc'd string.
418  */
419 char *
420 ChooseConstraintName(const char *name1, const char *name2,
421                                          const char *label, Oid namespace,
422                                          List *others)
423 {
424         int                     pass = 0;
425         char       *conname = NULL;
426         char            modlabel[NAMEDATALEN];
427         Relation        conDesc;
428         SysScanDesc conscan;
429         ScanKeyData skey[2];
430         bool            found;
431         ListCell   *l;
432
433         conDesc = heap_open(ConstraintRelationId, AccessShareLock);
434
435         /* try the unmodified label first */
436         StrNCpy(modlabel, label, sizeof(modlabel));
437
438         for (;;)
439         {
440                 conname = makeObjectName(name1, name2, modlabel);
441
442                 found = false;
443
444                 foreach(l, others)
445                 {
446                         if (strcmp((char *) lfirst(l), conname) == 0)
447                         {
448                                 found = true;
449                                 break;
450                         }
451                 }
452
453                 if (!found)
454                 {
455                         ScanKeyInit(&skey[0],
456                                                 Anum_pg_constraint_conname,
457                                                 BTEqualStrategyNumber, F_NAMEEQ,
458                                                 CStringGetDatum(conname));
459
460                         ScanKeyInit(&skey[1],
461                                                 Anum_pg_constraint_connamespace,
462                                                 BTEqualStrategyNumber, F_OIDEQ,
463                                                 ObjectIdGetDatum(namespace));
464
465                         conscan = systable_beginscan(conDesc, ConstraintNameNspIndexId, true,
466                                                                                  SnapshotNow, 2, skey);
467
468                         found = (HeapTupleIsValid(systable_getnext(conscan)));
469
470                         systable_endscan(conscan);
471                 }
472
473                 if (!found)
474                         break;
475
476                 /* found a conflict, so try a new name component */
477                 pfree(conname);
478                 snprintf(modlabel, sizeof(modlabel), "%s%d", label, ++pass);
479         }
480
481         heap_close(conDesc, AccessShareLock);
482
483         return conname;
484 }
485
486 /*
487  * Delete a single constraint record.
488  */
489 void
490 RemoveConstraintById(Oid conId)
491 {
492         Relation        conDesc;
493         HeapTuple       tup;
494         Form_pg_constraint con;
495
496         conDesc = heap_open(ConstraintRelationId, RowExclusiveLock);
497
498         tup = SearchSysCache(CONSTROID,
499                                                  ObjectIdGetDatum(conId),
500                                                  0, 0, 0);
501         if (!HeapTupleIsValid(tup)) /* should not happen */
502                 elog(ERROR, "cache lookup failed for constraint %u", conId);
503         con = (Form_pg_constraint) GETSTRUCT(tup);
504
505         /*
506          * Special processing depending on what the constraint is for.
507          */
508         if (OidIsValid(con->conrelid))
509         {
510                 Relation        rel;
511
512                 /*
513                  * If the constraint is for a relation, open and exclusive-lock the
514                  * relation it's for.
515                  */
516                 rel = heap_open(con->conrelid, AccessExclusiveLock);
517
518                 /*
519                  * We need to update the relcheck count if it is a check constraint
520                  * being dropped.  This update will force backends to rebuild relcache
521                  * entries when we commit.
522                  */
523                 if (con->contype == CONSTRAINT_CHECK)
524                 {
525                         Relation        pgrel;
526                         HeapTuple       relTup;
527                         Form_pg_class classForm;
528
529                         pgrel = heap_open(RelationRelationId, RowExclusiveLock);
530                         relTup = SearchSysCacheCopy(RELOID,
531                                                                                 ObjectIdGetDatum(con->conrelid),
532                                                                                 0, 0, 0);
533                         if (!HeapTupleIsValid(relTup))
534                                 elog(ERROR, "cache lookup failed for relation %u",
535                                          con->conrelid);
536                         classForm = (Form_pg_class) GETSTRUCT(relTup);
537
538                         if (classForm->relchecks == 0)          /* should not happen */
539                                 elog(ERROR, "relation \"%s\" has relchecks = 0",
540                                          RelationGetRelationName(rel));
541                         classForm->relchecks--;
542
543                         simple_heap_update(pgrel, &relTup->t_self, relTup);
544
545                         CatalogUpdateIndexes(pgrel, relTup);
546
547                         heap_freetuple(relTup);
548
549                         heap_close(pgrel, RowExclusiveLock);
550                 }
551
552                 /* Keep lock on constraint's rel until end of xact */
553                 heap_close(rel, NoLock);
554         }
555         else if (OidIsValid(con->contypid))
556         {
557                 /*
558                  * XXX for now, do nothing special when dropping a domain constraint
559                  *
560                  * Probably there should be some form of locking on the domain type,
561                  * but we have no such concept at the moment.
562                  */
563         }
564         else
565                 elog(ERROR, "constraint %u is not of a known type", conId);
566
567         /* Fry the constraint itself */
568         simple_heap_delete(conDesc, &tup->t_self);
569
570         /* Clean up */
571         ReleaseSysCache(tup);
572         heap_close(conDesc, RowExclusiveLock);
573 }
574
575 /*
576  * RenameConstraintById
577  *              Rename a constraint.
578  *
579  * Note: this isn't intended to be a user-exposed function; it doesn't check
580  * permissions etc.  Currently this is only invoked when renaming an index
581  * that is associated with a constraint, but it's made a little more general
582  * than that with the expectation of someday having ALTER TABLE RENAME
583  * CONSTRAINT.
584  */
585 void
586 RenameConstraintById(Oid conId, const char *newname)
587 {
588         Relation        conDesc;
589         HeapTuple       tuple;
590         Form_pg_constraint con;
591
592         conDesc = heap_open(ConstraintRelationId, RowExclusiveLock);
593
594         tuple = SearchSysCacheCopy(CONSTROID,
595                                                            ObjectIdGetDatum(conId),
596                                                            0, 0, 0);
597         if (!HeapTupleIsValid(tuple))
598                 elog(ERROR, "cache lookup failed for constraint %u", conId);
599         con = (Form_pg_constraint) GETSTRUCT(tuple);
600
601         /*
602          * We need to check whether the name is already in use --- note that
603          * there currently is not a unique index that would catch this.
604          */
605         if (OidIsValid(con->conrelid) &&
606                 ConstraintNameIsUsed(CONSTRAINT_RELATION,
607                                                          con->conrelid,
608                                                          con->connamespace,
609                                                          newname))
610                 ereport(ERROR,
611                                 (errcode(ERRCODE_DUPLICATE_OBJECT),
612                                  errmsg("constraint \"%s\" for relation \"%s\" already exists",
613                                                 newname, get_rel_name(con->conrelid))));
614         if (OidIsValid(con->contypid) &&
615                 ConstraintNameIsUsed(CONSTRAINT_DOMAIN,
616                                                          con->contypid,
617                                                          con->connamespace,
618                                                          newname))
619                 ereport(ERROR,
620                                 (errcode(ERRCODE_DUPLICATE_OBJECT),
621                                  errmsg("constraint \"%s\" for domain \"%s\" already exists",
622                                                 newname, format_type_be(con->contypid))));
623
624         /* OK, do the rename --- tuple is a copy, so OK to scribble on it */
625         namestrcpy(&(con->conname), newname);
626
627         simple_heap_update(conDesc, &tuple->t_self, tuple);
628
629         /* update the system catalog indexes */
630         CatalogUpdateIndexes(conDesc, tuple);
631
632         heap_freetuple(tuple);
633         heap_close(conDesc, RowExclusiveLock);
634 }
635
636 /*
637  * AlterConstraintNamespaces
638  *              Find any constraints belonging to the specified object,
639  *              and move them to the specified new namespace.
640  *
641  * isType indicates whether the owning object is a type or a relation.
642  */
643 void
644 AlterConstraintNamespaces(Oid ownerId, Oid oldNspId,
645                                                   Oid newNspId, bool isType)
646 {
647         Relation        conRel;
648         ScanKeyData key[1];
649         SysScanDesc scan;
650         HeapTuple       tup;
651
652         conRel = heap_open(ConstraintRelationId, RowExclusiveLock);
653
654         if (isType)
655         {
656                 ScanKeyInit(&key[0],
657                                         Anum_pg_constraint_contypid,
658                                         BTEqualStrategyNumber, F_OIDEQ,
659                                         ObjectIdGetDatum(ownerId));
660
661                 scan = systable_beginscan(conRel, ConstraintTypidIndexId, true,
662                                                                   SnapshotNow, 1, key);
663         }
664         else
665         {
666                 ScanKeyInit(&key[0],
667                                         Anum_pg_constraint_conrelid,
668                                         BTEqualStrategyNumber, F_OIDEQ,
669                                         ObjectIdGetDatum(ownerId));
670
671                 scan = systable_beginscan(conRel, ConstraintRelidIndexId, true,
672                                                                   SnapshotNow, 1, key);
673         }
674
675         while (HeapTupleIsValid((tup = systable_getnext(scan))))
676         {
677                 Form_pg_constraint conform = (Form_pg_constraint) GETSTRUCT(tup);
678
679                 if (conform->connamespace == oldNspId)
680                 {
681                         tup = heap_copytuple(tup);
682                         conform = (Form_pg_constraint) GETSTRUCT(tup);
683
684                         conform->connamespace = newNspId;
685
686                         simple_heap_update(conRel, &tup->t_self, tup);
687                         CatalogUpdateIndexes(conRel, tup);
688
689                         /*
690                          * Note: currently, the constraint will not have its own
691                          * dependency on the namespace, so we don't need to do
692                          * changeDependencyFor().
693                          */
694                 }
695         }
696
697         systable_endscan(scan);
698
699         heap_close(conRel, RowExclusiveLock);
700 }