]> granicus.if.org Git - postgresql/blob - src/backend/catalog/pg_constraint.c
Make backend header files C++ safe
[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-2009, 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.46 2009/07/16 06:33:42 petere 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/rel.h"
30 #include "utils/syscache.h"
31 #include "utils/tqual.h"
32
33
34 /*
35  * CreateConstraintEntry
36  *      Create a constraint table entry.
37  *
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.
41  */
42 Oid
43 CreateConstraintEntry(const char *constraintName,
44                                           Oid constraintNamespace,
45                                           char constraintType,
46                                           bool isDeferrable,
47                                           bool isDeferred,
48                                           Oid relId,
49                                           const int16 *constraintKey,
50                                           int constraintNKeys,
51                                           Oid domainId,
52                                           Oid foreignRelId,
53                                           const int16 *foreignKey,
54                                           const Oid *pfEqOp,
55                                           const Oid *ppEqOp,
56                                           const Oid *ffEqOp,
57                                           int foreignNKeys,
58                                           char foreignUpdateType,
59                                           char foreignDeleteType,
60                                           char foreignMatchType,
61                                           Oid indexRelId,
62                                           Node *conExpr,
63                                           const char *conBin,
64                                           const char *conSrc,
65                                           bool conIsLocal,
66                                           int conInhCount)
67 {
68         Relation        conDesc;
69         Oid                     conOid;
70         HeapTuple       tup;
71         bool            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;
78         NameData        cname;
79         int                     i;
80         ObjectAddress conobject;
81
82         conDesc = heap_open(ConstraintRelationId, RowExclusiveLock);
83
84         Assert(constraintName);
85         namestrcpy(&cname, constraintName);
86
87         /*
88          * Convert C arrays into Postgres arrays.
89          */
90         if (constraintNKeys > 0)
91         {
92                 Datum      *conkey;
93
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');
99         }
100         else
101                 conkeyArray = NULL;
102
103         if (foreignNKeys > 0)
104         {
105                 Datum      *fkdatums;
106
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');
124         }
125         else
126         {
127                 confkeyArray = NULL;
128                 conpfeqopArray = NULL;
129                 conppeqopArray = NULL;
130                 conffeqopArray = NULL;
131         }
132
133         /* initialize nulls and values */
134         for (i = 0; i < Natts_pg_constraint; i++)
135         {
136                 nulls[i] = false;
137                 values[i] = (Datum) NULL;
138         }
139
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);
153
154         if (conkeyArray)
155                 values[Anum_pg_constraint_conkey - 1] = PointerGetDatum(conkeyArray);
156         else
157                 nulls[Anum_pg_constraint_conkey - 1] = true;
158
159         if (confkeyArray)
160                 values[Anum_pg_constraint_confkey - 1] = PointerGetDatum(confkeyArray);
161         else
162                 nulls[Anum_pg_constraint_confkey - 1] = true;
163
164         if (conpfeqopArray)
165                 values[Anum_pg_constraint_conpfeqop - 1] = PointerGetDatum(conpfeqopArray);
166         else
167                 nulls[Anum_pg_constraint_conpfeqop - 1] = true;
168
169         if (conppeqopArray)
170                 values[Anum_pg_constraint_conppeqop - 1] = PointerGetDatum(conppeqopArray);
171         else
172                 nulls[Anum_pg_constraint_conppeqop - 1] = true;
173
174         if (conffeqopArray)
175                 values[Anum_pg_constraint_conffeqop - 1] = PointerGetDatum(conffeqopArray);
176         else
177                 nulls[Anum_pg_constraint_conffeqop - 1] = true;
178
179         /*
180          * initialize the binary form of the check constraint.
181          */
182         if (conBin)
183                 values[Anum_pg_constraint_conbin - 1] = CStringGetTextDatum(conBin);
184         else
185                 nulls[Anum_pg_constraint_conbin - 1] = true;
186
187         /*
188          * initialize the text form of the check constraint
189          */
190         if (conSrc)
191                 values[Anum_pg_constraint_consrc - 1] = CStringGetTextDatum(conSrc);
192         else
193                 nulls[Anum_pg_constraint_consrc - 1] = true;
194
195         tup = heap_form_tuple(RelationGetDescr(conDesc), values, nulls);
196
197         conOid = simple_heap_insert(conDesc, tup);
198
199         /* update catalog indexes */
200         CatalogUpdateIndexes(conDesc, tup);
201
202         conobject.classId = ConstraintRelationId;
203         conobject.objectId = conOid;
204         conobject.objectSubId = 0;
205
206         heap_close(conDesc, RowExclusiveLock);
207
208         if (OidIsValid(relId))
209         {
210                 /*
211                  * Register auto dependency from constraint to owning relation, or to
212                  * specific column(s) if any are mentioned.
213                  */
214                 ObjectAddress relobject;
215
216                 relobject.classId = RelationRelationId;
217                 relobject.objectId = relId;
218                 if (constraintNKeys > 0)
219                 {
220                         for (i = 0; i < constraintNKeys; i++)
221                         {
222                                 relobject.objectSubId = constraintKey[i];
223
224                                 recordDependencyOn(&conobject, &relobject, DEPENDENCY_AUTO);
225                         }
226                 }
227                 else
228                 {
229                         relobject.objectSubId = 0;
230
231                         recordDependencyOn(&conobject, &relobject, DEPENDENCY_AUTO);
232                 }
233         }
234
235         if (OidIsValid(domainId))
236         {
237                 /*
238                  * Register auto dependency from constraint to owning domain
239                  */
240                 ObjectAddress domobject;
241
242                 domobject.classId = TypeRelationId;
243                 domobject.objectId = domainId;
244                 domobject.objectSubId = 0;
245
246                 recordDependencyOn(&conobject, &domobject, DEPENDENCY_AUTO);
247         }
248
249         if (OidIsValid(foreignRelId))
250         {
251                 /*
252                  * Register normal dependency from constraint to foreign relation, or
253                  * to specific column(s) if any are mentioned.
254                  */
255                 ObjectAddress relobject;
256
257                 relobject.classId = RelationRelationId;
258                 relobject.objectId = foreignRelId;
259                 if (foreignNKeys > 0)
260                 {
261                         for (i = 0; i < foreignNKeys; i++)
262                         {
263                                 relobject.objectSubId = foreignKey[i];
264
265                                 recordDependencyOn(&conobject, &relobject, DEPENDENCY_NORMAL);
266                         }
267                 }
268                 else
269                 {
270                         relobject.objectSubId = 0;
271
272                         recordDependencyOn(&conobject, &relobject, DEPENDENCY_NORMAL);
273                 }
274         }
275
276         if (OidIsValid(indexRelId))
277         {
278                 /*
279                  * Register normal dependency on the unique index that supports a
280                  * foreign-key constraint.
281                  */
282                 ObjectAddress relobject;
283
284                 relobject.classId = RelationRelationId;
285                 relobject.objectId = indexRelId;
286                 relobject.objectSubId = 0;
287
288                 recordDependencyOn(&conobject, &relobject, DEPENDENCY_NORMAL);
289         }
290
291         if (foreignNKeys > 0)
292         {
293                 /*
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
297                  * different.
298                  */
299                 ObjectAddress oprobject;
300
301                 oprobject.classId = OperatorRelationId;
302                 oprobject.objectSubId = 0;
303
304                 for (i = 0; i < foreignNKeys; i++)
305                 {
306                         oprobject.objectId = pfEqOp[i];
307                         recordDependencyOn(&conobject, &oprobject, DEPENDENCY_NORMAL);
308                         if (ppEqOp[i] != pfEqOp[i])
309                         {
310                                 oprobject.objectId = ppEqOp[i];
311                                 recordDependencyOn(&conobject, &oprobject, DEPENDENCY_NORMAL);
312                         }
313                         if (ffEqOp[i] != pfEqOp[i])
314                         {
315                                 oprobject.objectId = ffEqOp[i];
316                                 recordDependencyOn(&conobject, &oprobject, DEPENDENCY_NORMAL);
317                         }
318                 }
319         }
320
321         if (conExpr != NULL)
322         {
323                 /*
324                  * Register dependencies from constraint to objects mentioned in CHECK
325                  * expression.
326                  */
327                 recordDependencyOnSingleRelExpr(&conobject, conExpr, relId,
328                                                                                 DEPENDENCY_NORMAL,
329                                                                                 DEPENDENCY_NORMAL);
330         }
331
332         return conOid;
333 }
334
335
336 /*
337  * Test whether given name is currently used as a constraint name
338  * for the given object (relation or domain).
339  *
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*.
344  *
345  * NB: Caller should hold exclusive lock on the given object, else
346  * this test can be fooled by concurrent additions.
347  */
348 bool
349 ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId,
350                                          Oid objNamespace, const char *conname)
351 {
352         bool            found;
353         Relation        conDesc;
354         SysScanDesc conscan;
355         ScanKeyData skey[2];
356         HeapTuple       tup;
357
358         conDesc = heap_open(ConstraintRelationId, AccessShareLock);
359
360         found = false;
361
362         ScanKeyInit(&skey[0],
363                                 Anum_pg_constraint_conname,
364                                 BTEqualStrategyNumber, F_NAMEEQ,
365                                 CStringGetDatum(conname));
366
367         ScanKeyInit(&skey[1],
368                                 Anum_pg_constraint_connamespace,
369                                 BTEqualStrategyNumber, F_OIDEQ,
370                                 ObjectIdGetDatum(objNamespace));
371
372         conscan = systable_beginscan(conDesc, ConstraintNameNspIndexId, true,
373                                                                  SnapshotNow, 2, skey);
374
375         while (HeapTupleIsValid(tup = systable_getnext(conscan)))
376         {
377                 Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tup);
378
379                 if (conCat == CONSTRAINT_RELATION && con->conrelid == objId)
380                 {
381                         found = true;
382                         break;
383                 }
384                 else if (conCat == CONSTRAINT_DOMAIN && con->contypid == objId)
385                 {
386                         found = true;
387                         break;
388                 }
389         }
390
391         systable_endscan(conscan);
392         heap_close(conDesc, AccessShareLock);
393
394         return found;
395 }
396
397 /*
398  * Select a nonconflicting name for a new constraint.
399  *
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.
404  *
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.
408  *
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.
412  *
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.
417  *
418  * Returns a palloc'd string.
419  */
420 char *
421 ChooseConstraintName(const char *name1, const char *name2,
422                                          const char *label, Oid namespaceid,
423                                          List *others)
424 {
425         int                     pass = 0;
426         char       *conname = NULL;
427         char            modlabel[NAMEDATALEN];
428         Relation        conDesc;
429         SysScanDesc conscan;
430         ScanKeyData skey[2];
431         bool            found;
432         ListCell   *l;
433
434         conDesc = heap_open(ConstraintRelationId, AccessShareLock);
435
436         /* try the unmodified label first */
437         StrNCpy(modlabel, label, sizeof(modlabel));
438
439         for (;;)
440         {
441                 conname = makeObjectName(name1, name2, modlabel);
442
443                 found = false;
444
445                 foreach(l, others)
446                 {
447                         if (strcmp((char *) lfirst(l), conname) == 0)
448                         {
449                                 found = true;
450                                 break;
451                         }
452                 }
453
454                 if (!found)
455                 {
456                         ScanKeyInit(&skey[0],
457                                                 Anum_pg_constraint_conname,
458                                                 BTEqualStrategyNumber, F_NAMEEQ,
459                                                 CStringGetDatum(conname));
460
461                         ScanKeyInit(&skey[1],
462                                                 Anum_pg_constraint_connamespace,
463                                                 BTEqualStrategyNumber, F_OIDEQ,
464                                                 ObjectIdGetDatum(namespaceid));
465
466                         conscan = systable_beginscan(conDesc, ConstraintNameNspIndexId, true,
467                                                                                  SnapshotNow, 2, skey);
468
469                         found = (HeapTupleIsValid(systable_getnext(conscan)));
470
471                         systable_endscan(conscan);
472                 }
473
474                 if (!found)
475                         break;
476
477                 /* found a conflict, so try a new name component */
478                 pfree(conname);
479                 snprintf(modlabel, sizeof(modlabel), "%s%d", label, ++pass);
480         }
481
482         heap_close(conDesc, AccessShareLock);
483
484         return conname;
485 }
486
487 /*
488  * Delete a single constraint record.
489  */
490 void
491 RemoveConstraintById(Oid conId)
492 {
493         Relation        conDesc;
494         HeapTuple       tup;
495         Form_pg_constraint con;
496
497         conDesc = heap_open(ConstraintRelationId, RowExclusiveLock);
498
499         tup = SearchSysCache(CONSTROID,
500                                                  ObjectIdGetDatum(conId),
501                                                  0, 0, 0);
502         if (!HeapTupleIsValid(tup)) /* should not happen */
503                 elog(ERROR, "cache lookup failed for constraint %u", conId);
504         con = (Form_pg_constraint) GETSTRUCT(tup);
505
506         /*
507          * Special processing depending on what the constraint is for.
508          */
509         if (OidIsValid(con->conrelid))
510         {
511                 Relation        rel;
512
513                 /*
514                  * If the constraint is for a relation, open and exclusive-lock the
515                  * relation it's for.
516                  */
517                 rel = heap_open(con->conrelid, AccessExclusiveLock);
518
519                 /*
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.
523                  */
524                 if (con->contype == CONSTRAINT_CHECK)
525                 {
526                         Relation        pgrel;
527                         HeapTuple       relTup;
528                         Form_pg_class classForm;
529
530                         pgrel = heap_open(RelationRelationId, RowExclusiveLock);
531                         relTup = SearchSysCacheCopy(RELOID,
532                                                                                 ObjectIdGetDatum(con->conrelid),
533                                                                                 0, 0, 0);
534                         if (!HeapTupleIsValid(relTup))
535                                 elog(ERROR, "cache lookup failed for relation %u",
536                                          con->conrelid);
537                         classForm = (Form_pg_class) GETSTRUCT(relTup);
538
539                         if (classForm->relchecks == 0)          /* should not happen */
540                                 elog(ERROR, "relation \"%s\" has relchecks = 0",
541                                          RelationGetRelationName(rel));
542                         classForm->relchecks--;
543
544                         simple_heap_update(pgrel, &relTup->t_self, relTup);
545
546                         CatalogUpdateIndexes(pgrel, relTup);
547
548                         heap_freetuple(relTup);
549
550                         heap_close(pgrel, RowExclusiveLock);
551                 }
552
553                 /* Keep lock on constraint's rel until end of xact */
554                 heap_close(rel, NoLock);
555         }
556         else if (OidIsValid(con->contypid))
557         {
558                 /*
559                  * XXX for now, do nothing special when dropping a domain constraint
560                  *
561                  * Probably there should be some form of locking on the domain type,
562                  * but we have no such concept at the moment.
563                  */
564         }
565         else
566                 elog(ERROR, "constraint %u is not of a known type", conId);
567
568         /* Fry the constraint itself */
569         simple_heap_delete(conDesc, &tup->t_self);
570
571         /* Clean up */
572         ReleaseSysCache(tup);
573         heap_close(conDesc, RowExclusiveLock);
574 }
575
576 /*
577  * RenameConstraintById
578  *              Rename a constraint.
579  *
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
584  * CONSTRAINT.
585  */
586 void
587 RenameConstraintById(Oid conId, const char *newname)
588 {
589         Relation        conDesc;
590         HeapTuple       tuple;
591         Form_pg_constraint con;
592
593         conDesc = heap_open(ConstraintRelationId, RowExclusiveLock);
594
595         tuple = SearchSysCacheCopy(CONSTROID,
596                                                            ObjectIdGetDatum(conId),
597                                                            0, 0, 0);
598         if (!HeapTupleIsValid(tuple))
599                 elog(ERROR, "cache lookup failed for constraint %u", conId);
600         con = (Form_pg_constraint) GETSTRUCT(tuple);
601
602         /*
603          * We need to check whether the name is already in use --- note that there
604          * currently is not a unique index that would catch this.
605          */
606         if (OidIsValid(con->conrelid) &&
607                 ConstraintNameIsUsed(CONSTRAINT_RELATION,
608                                                          con->conrelid,
609                                                          con->connamespace,
610                                                          newname))
611                 ereport(ERROR,
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,
617                                                          con->contypid,
618                                                          con->connamespace,
619                                                          newname))
620                 ereport(ERROR,
621                                 (errcode(ERRCODE_DUPLICATE_OBJECT),
622                                  errmsg("constraint \"%s\" for domain \"%s\" already exists",
623                                                 newname, format_type_be(con->contypid))));
624
625         /* OK, do the rename --- tuple is a copy, so OK to scribble on it */
626         namestrcpy(&(con->conname), newname);
627
628         simple_heap_update(conDesc, &tuple->t_self, tuple);
629
630         /* update the system catalog indexes */
631         CatalogUpdateIndexes(conDesc, tuple);
632
633         heap_freetuple(tuple);
634         heap_close(conDesc, RowExclusiveLock);
635 }
636
637 /*
638  * AlterConstraintNamespaces
639  *              Find any constraints belonging to the specified object,
640  *              and move them to the specified new namespace.
641  *
642  * isType indicates whether the owning object is a type or a relation.
643  */
644 void
645 AlterConstraintNamespaces(Oid ownerId, Oid oldNspId,
646                                                   Oid newNspId, bool isType)
647 {
648         Relation        conRel;
649         ScanKeyData key[1];
650         SysScanDesc scan;
651         HeapTuple       tup;
652
653         conRel = heap_open(ConstraintRelationId, RowExclusiveLock);
654
655         if (isType)
656         {
657                 ScanKeyInit(&key[0],
658                                         Anum_pg_constraint_contypid,
659                                         BTEqualStrategyNumber, F_OIDEQ,
660                                         ObjectIdGetDatum(ownerId));
661
662                 scan = systable_beginscan(conRel, ConstraintTypidIndexId, true,
663                                                                   SnapshotNow, 1, key);
664         }
665         else
666         {
667                 ScanKeyInit(&key[0],
668                                         Anum_pg_constraint_conrelid,
669                                         BTEqualStrategyNumber, F_OIDEQ,
670                                         ObjectIdGetDatum(ownerId));
671
672                 scan = systable_beginscan(conRel, ConstraintRelidIndexId, true,
673                                                                   SnapshotNow, 1, key);
674         }
675
676         while (HeapTupleIsValid((tup = systable_getnext(scan))))
677         {
678                 Form_pg_constraint conform = (Form_pg_constraint) GETSTRUCT(tup);
679
680                 if (conform->connamespace == oldNspId)
681                 {
682                         tup = heap_copytuple(tup);
683                         conform = (Form_pg_constraint) GETSTRUCT(tup);
684
685                         conform->connamespace = newNspId;
686
687                         simple_heap_update(conRel, &tup->t_self, tup);
688                         CatalogUpdateIndexes(conRel, tup);
689
690                         /*
691                          * Note: currently, the constraint will not have its own
692                          * dependency on the namespace, so we don't need to do
693                          * changeDependencyFor().
694                          */
695                 }
696         }
697
698         systable_endscan(scan);
699
700         heap_close(conRel, RowExclusiveLock);
701 }