00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "postgres.h"
00016
00017 #include "access/genam.h"
00018 #include "access/heapam.h"
00019 #include "access/htup_details.h"
00020 #include "catalog/dependency.h"
00021 #include "catalog/indexing.h"
00022 #include "catalog/objectaccess.h"
00023 #include "catalog/pg_constraint.h"
00024 #include "catalog/pg_operator.h"
00025 #include "catalog/pg_type.h"
00026 #include "commands/defrem.h"
00027 #include "utils/array.h"
00028 #include "utils/builtins.h"
00029 #include "utils/fmgroids.h"
00030 #include "utils/lsyscache.h"
00031 #include "utils/rel.h"
00032 #include "utils/syscache.h"
00033 #include "utils/tqual.h"
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044 Oid
00045 CreateConstraintEntry(const char *constraintName,
00046 Oid constraintNamespace,
00047 char constraintType,
00048 bool isDeferrable,
00049 bool isDeferred,
00050 bool isValidated,
00051 Oid relId,
00052 const int16 *constraintKey,
00053 int constraintNKeys,
00054 Oid domainId,
00055 Oid indexRelId,
00056 Oid foreignRelId,
00057 const int16 *foreignKey,
00058 const Oid *pfEqOp,
00059 const Oid *ppEqOp,
00060 const Oid *ffEqOp,
00061 int foreignNKeys,
00062 char foreignUpdateType,
00063 char foreignDeleteType,
00064 char foreignMatchType,
00065 const Oid *exclOp,
00066 Node *conExpr,
00067 const char *conBin,
00068 const char *conSrc,
00069 bool conIsLocal,
00070 int conInhCount,
00071 bool conNoInherit,
00072 bool is_internal)
00073 {
00074 Relation conDesc;
00075 Oid conOid;
00076 HeapTuple tup;
00077 bool nulls[Natts_pg_constraint];
00078 Datum values[Natts_pg_constraint];
00079 ArrayType *conkeyArray;
00080 ArrayType *confkeyArray;
00081 ArrayType *conpfeqopArray;
00082 ArrayType *conppeqopArray;
00083 ArrayType *conffeqopArray;
00084 ArrayType *conexclopArray;
00085 NameData cname;
00086 int i;
00087 ObjectAddress conobject;
00088
00089 conDesc = heap_open(ConstraintRelationId, RowExclusiveLock);
00090
00091 Assert(constraintName);
00092 namestrcpy(&cname, constraintName);
00093
00094
00095
00096
00097 if (constraintNKeys > 0)
00098 {
00099 Datum *conkey;
00100
00101 conkey = (Datum *) palloc(constraintNKeys * sizeof(Datum));
00102 for (i = 0; i < constraintNKeys; i++)
00103 conkey[i] = Int16GetDatum(constraintKey[i]);
00104 conkeyArray = construct_array(conkey, constraintNKeys,
00105 INT2OID, 2, true, 's');
00106 }
00107 else
00108 conkeyArray = NULL;
00109
00110 if (foreignNKeys > 0)
00111 {
00112 Datum *fkdatums;
00113
00114 fkdatums = (Datum *) palloc(foreignNKeys * sizeof(Datum));
00115 for (i = 0; i < foreignNKeys; i++)
00116 fkdatums[i] = Int16GetDatum(foreignKey[i]);
00117 confkeyArray = construct_array(fkdatums, foreignNKeys,
00118 INT2OID, 2, true, 's');
00119 for (i = 0; i < foreignNKeys; i++)
00120 fkdatums[i] = ObjectIdGetDatum(pfEqOp[i]);
00121 conpfeqopArray = construct_array(fkdatums, foreignNKeys,
00122 OIDOID, sizeof(Oid), true, 'i');
00123 for (i = 0; i < foreignNKeys; i++)
00124 fkdatums[i] = ObjectIdGetDatum(ppEqOp[i]);
00125 conppeqopArray = construct_array(fkdatums, foreignNKeys,
00126 OIDOID, sizeof(Oid), true, 'i');
00127 for (i = 0; i < foreignNKeys; i++)
00128 fkdatums[i] = ObjectIdGetDatum(ffEqOp[i]);
00129 conffeqopArray = construct_array(fkdatums, foreignNKeys,
00130 OIDOID, sizeof(Oid), true, 'i');
00131 }
00132 else
00133 {
00134 confkeyArray = NULL;
00135 conpfeqopArray = NULL;
00136 conppeqopArray = NULL;
00137 conffeqopArray = NULL;
00138 }
00139
00140 if (exclOp != NULL)
00141 {
00142 Datum *opdatums;
00143
00144 opdatums = (Datum *) palloc(constraintNKeys * sizeof(Datum));
00145 for (i = 0; i < constraintNKeys; i++)
00146 opdatums[i] = ObjectIdGetDatum(exclOp[i]);
00147 conexclopArray = construct_array(opdatums, constraintNKeys,
00148 OIDOID, sizeof(Oid), true, 'i');
00149 }
00150 else
00151 conexclopArray = NULL;
00152
00153
00154 for (i = 0; i < Natts_pg_constraint; i++)
00155 {
00156 nulls[i] = false;
00157 values[i] = (Datum) NULL;
00158 }
00159
00160 values[Anum_pg_constraint_conname - 1] = NameGetDatum(&cname);
00161 values[Anum_pg_constraint_connamespace - 1] = ObjectIdGetDatum(constraintNamespace);
00162 values[Anum_pg_constraint_contype - 1] = CharGetDatum(constraintType);
00163 values[Anum_pg_constraint_condeferrable - 1] = BoolGetDatum(isDeferrable);
00164 values[Anum_pg_constraint_condeferred - 1] = BoolGetDatum(isDeferred);
00165 values[Anum_pg_constraint_convalidated - 1] = BoolGetDatum(isValidated);
00166 values[Anum_pg_constraint_conrelid - 1] = ObjectIdGetDatum(relId);
00167 values[Anum_pg_constraint_contypid - 1] = ObjectIdGetDatum(domainId);
00168 values[Anum_pg_constraint_conindid - 1] = ObjectIdGetDatum(indexRelId);
00169 values[Anum_pg_constraint_confrelid - 1] = ObjectIdGetDatum(foreignRelId);
00170 values[Anum_pg_constraint_confupdtype - 1] = CharGetDatum(foreignUpdateType);
00171 values[Anum_pg_constraint_confdeltype - 1] = CharGetDatum(foreignDeleteType);
00172 values[Anum_pg_constraint_confmatchtype - 1] = CharGetDatum(foreignMatchType);
00173 values[Anum_pg_constraint_conislocal - 1] = BoolGetDatum(conIsLocal);
00174 values[Anum_pg_constraint_coninhcount - 1] = Int32GetDatum(conInhCount);
00175 values[Anum_pg_constraint_connoinherit - 1] = BoolGetDatum(conNoInherit);
00176
00177 if (conkeyArray)
00178 values[Anum_pg_constraint_conkey - 1] = PointerGetDatum(conkeyArray);
00179 else
00180 nulls[Anum_pg_constraint_conkey - 1] = true;
00181
00182 if (confkeyArray)
00183 values[Anum_pg_constraint_confkey - 1] = PointerGetDatum(confkeyArray);
00184 else
00185 nulls[Anum_pg_constraint_confkey - 1] = true;
00186
00187 if (conpfeqopArray)
00188 values[Anum_pg_constraint_conpfeqop - 1] = PointerGetDatum(conpfeqopArray);
00189 else
00190 nulls[Anum_pg_constraint_conpfeqop - 1] = true;
00191
00192 if (conppeqopArray)
00193 values[Anum_pg_constraint_conppeqop - 1] = PointerGetDatum(conppeqopArray);
00194 else
00195 nulls[Anum_pg_constraint_conppeqop - 1] = true;
00196
00197 if (conffeqopArray)
00198 values[Anum_pg_constraint_conffeqop - 1] = PointerGetDatum(conffeqopArray);
00199 else
00200 nulls[Anum_pg_constraint_conffeqop - 1] = true;
00201
00202 if (conexclopArray)
00203 values[Anum_pg_constraint_conexclop - 1] = PointerGetDatum(conexclopArray);
00204 else
00205 nulls[Anum_pg_constraint_conexclop - 1] = true;
00206
00207
00208
00209
00210 if (conBin)
00211 values[Anum_pg_constraint_conbin - 1] = CStringGetTextDatum(conBin);
00212 else
00213 nulls[Anum_pg_constraint_conbin - 1] = true;
00214
00215
00216
00217
00218 if (conSrc)
00219 values[Anum_pg_constraint_consrc - 1] = CStringGetTextDatum(conSrc);
00220 else
00221 nulls[Anum_pg_constraint_consrc - 1] = true;
00222
00223 tup = heap_form_tuple(RelationGetDescr(conDesc), values, nulls);
00224
00225 conOid = simple_heap_insert(conDesc, tup);
00226
00227
00228 CatalogUpdateIndexes(conDesc, tup);
00229
00230 conobject.classId = ConstraintRelationId;
00231 conobject.objectId = conOid;
00232 conobject.objectSubId = 0;
00233
00234 heap_close(conDesc, RowExclusiveLock);
00235
00236 if (OidIsValid(relId))
00237 {
00238
00239
00240
00241
00242 ObjectAddress relobject;
00243
00244 relobject.classId = RelationRelationId;
00245 relobject.objectId = relId;
00246 if (constraintNKeys > 0)
00247 {
00248 for (i = 0; i < constraintNKeys; i++)
00249 {
00250 relobject.objectSubId = constraintKey[i];
00251
00252 recordDependencyOn(&conobject, &relobject, DEPENDENCY_AUTO);
00253 }
00254 }
00255 else
00256 {
00257 relobject.objectSubId = 0;
00258
00259 recordDependencyOn(&conobject, &relobject, DEPENDENCY_AUTO);
00260 }
00261 }
00262
00263 if (OidIsValid(domainId))
00264 {
00265
00266
00267
00268 ObjectAddress domobject;
00269
00270 domobject.classId = TypeRelationId;
00271 domobject.objectId = domainId;
00272 domobject.objectSubId = 0;
00273
00274 recordDependencyOn(&conobject, &domobject, DEPENDENCY_AUTO);
00275 }
00276
00277 if (OidIsValid(foreignRelId))
00278 {
00279
00280
00281
00282
00283 ObjectAddress relobject;
00284
00285 relobject.classId = RelationRelationId;
00286 relobject.objectId = foreignRelId;
00287 if (foreignNKeys > 0)
00288 {
00289 for (i = 0; i < foreignNKeys; i++)
00290 {
00291 relobject.objectSubId = foreignKey[i];
00292
00293 recordDependencyOn(&conobject, &relobject, DEPENDENCY_NORMAL);
00294 }
00295 }
00296 else
00297 {
00298 relobject.objectSubId = 0;
00299
00300 recordDependencyOn(&conobject, &relobject, DEPENDENCY_NORMAL);
00301 }
00302 }
00303
00304 if (OidIsValid(indexRelId) && constraintType == CONSTRAINT_FOREIGN)
00305 {
00306
00307
00308
00309
00310
00311
00312 ObjectAddress relobject;
00313
00314 relobject.classId = RelationRelationId;
00315 relobject.objectId = indexRelId;
00316 relobject.objectSubId = 0;
00317
00318 recordDependencyOn(&conobject, &relobject, DEPENDENCY_NORMAL);
00319 }
00320
00321 if (foreignNKeys > 0)
00322 {
00323
00324
00325
00326
00327
00328
00329 ObjectAddress oprobject;
00330
00331 oprobject.classId = OperatorRelationId;
00332 oprobject.objectSubId = 0;
00333
00334 for (i = 0; i < foreignNKeys; i++)
00335 {
00336 oprobject.objectId = pfEqOp[i];
00337 recordDependencyOn(&conobject, &oprobject, DEPENDENCY_NORMAL);
00338 if (ppEqOp[i] != pfEqOp[i])
00339 {
00340 oprobject.objectId = ppEqOp[i];
00341 recordDependencyOn(&conobject, &oprobject, DEPENDENCY_NORMAL);
00342 }
00343 if (ffEqOp[i] != pfEqOp[i])
00344 {
00345 oprobject.objectId = ffEqOp[i];
00346 recordDependencyOn(&conobject, &oprobject, DEPENDENCY_NORMAL);
00347 }
00348 }
00349 }
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359 if (conExpr != NULL)
00360 {
00361
00362
00363
00364
00365 recordDependencyOnSingleRelExpr(&conobject, conExpr, relId,
00366 DEPENDENCY_NORMAL,
00367 DEPENDENCY_NORMAL);
00368 }
00369
00370
00371 InvokeObjectPostCreateHookArg(ConstraintRelationId, conOid, 0,
00372 is_internal);
00373
00374 return conOid;
00375 }
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390 bool
00391 ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId,
00392 Oid objNamespace, const char *conname)
00393 {
00394 bool found;
00395 Relation conDesc;
00396 SysScanDesc conscan;
00397 ScanKeyData skey[2];
00398 HeapTuple tup;
00399
00400 conDesc = heap_open(ConstraintRelationId, AccessShareLock);
00401
00402 found = false;
00403
00404 ScanKeyInit(&skey[0],
00405 Anum_pg_constraint_conname,
00406 BTEqualStrategyNumber, F_NAMEEQ,
00407 CStringGetDatum(conname));
00408
00409 ScanKeyInit(&skey[1],
00410 Anum_pg_constraint_connamespace,
00411 BTEqualStrategyNumber, F_OIDEQ,
00412 ObjectIdGetDatum(objNamespace));
00413
00414 conscan = systable_beginscan(conDesc, ConstraintNameNspIndexId, true,
00415 SnapshotNow, 2, skey);
00416
00417 while (HeapTupleIsValid(tup = systable_getnext(conscan)))
00418 {
00419 Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tup);
00420
00421 if (conCat == CONSTRAINT_RELATION && con->conrelid == objId)
00422 {
00423 found = true;
00424 break;
00425 }
00426 else if (conCat == CONSTRAINT_DOMAIN && con->contypid == objId)
00427 {
00428 found = true;
00429 break;
00430 }
00431 }
00432
00433 systable_endscan(conscan);
00434 heap_close(conDesc, AccessShareLock);
00435
00436 return found;
00437 }
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462 char *
00463 ChooseConstraintName(const char *name1, const char *name2,
00464 const char *label, Oid namespaceid,
00465 List *others)
00466 {
00467 int pass = 0;
00468 char *conname = NULL;
00469 char modlabel[NAMEDATALEN];
00470 Relation conDesc;
00471 SysScanDesc conscan;
00472 ScanKeyData skey[2];
00473 bool found;
00474 ListCell *l;
00475
00476 conDesc = heap_open(ConstraintRelationId, AccessShareLock);
00477
00478
00479 StrNCpy(modlabel, label, sizeof(modlabel));
00480
00481 for (;;)
00482 {
00483 conname = makeObjectName(name1, name2, modlabel);
00484
00485 found = false;
00486
00487 foreach(l, others)
00488 {
00489 if (strcmp((char *) lfirst(l), conname) == 0)
00490 {
00491 found = true;
00492 break;
00493 }
00494 }
00495
00496 if (!found)
00497 {
00498 ScanKeyInit(&skey[0],
00499 Anum_pg_constraint_conname,
00500 BTEqualStrategyNumber, F_NAMEEQ,
00501 CStringGetDatum(conname));
00502
00503 ScanKeyInit(&skey[1],
00504 Anum_pg_constraint_connamespace,
00505 BTEqualStrategyNumber, F_OIDEQ,
00506 ObjectIdGetDatum(namespaceid));
00507
00508 conscan = systable_beginscan(conDesc, ConstraintNameNspIndexId, true,
00509 SnapshotNow, 2, skey);
00510
00511 found = (HeapTupleIsValid(systable_getnext(conscan)));
00512
00513 systable_endscan(conscan);
00514 }
00515
00516 if (!found)
00517 break;
00518
00519
00520 pfree(conname);
00521 snprintf(modlabel, sizeof(modlabel), "%s%d", label, ++pass);
00522 }
00523
00524 heap_close(conDesc, AccessShareLock);
00525
00526 return conname;
00527 }
00528
00529
00530
00531
00532 void
00533 RemoveConstraintById(Oid conId)
00534 {
00535 Relation conDesc;
00536 HeapTuple tup;
00537 Form_pg_constraint con;
00538
00539 conDesc = heap_open(ConstraintRelationId, RowExclusiveLock);
00540
00541 tup = SearchSysCache1(CONSTROID, ObjectIdGetDatum(conId));
00542 if (!HeapTupleIsValid(tup))
00543 elog(ERROR, "cache lookup failed for constraint %u", conId);
00544 con = (Form_pg_constraint) GETSTRUCT(tup);
00545
00546
00547
00548
00549 if (OidIsValid(con->conrelid))
00550 {
00551 Relation rel;
00552
00553
00554
00555
00556
00557 rel = heap_open(con->conrelid, AccessExclusiveLock);
00558
00559
00560
00561
00562
00563
00564 if (con->contype == CONSTRAINT_CHECK)
00565 {
00566 Relation pgrel;
00567 HeapTuple relTup;
00568 Form_pg_class classForm;
00569
00570 pgrel = heap_open(RelationRelationId, RowExclusiveLock);
00571 relTup = SearchSysCacheCopy1(RELOID,
00572 ObjectIdGetDatum(con->conrelid));
00573 if (!HeapTupleIsValid(relTup))
00574 elog(ERROR, "cache lookup failed for relation %u",
00575 con->conrelid);
00576 classForm = (Form_pg_class) GETSTRUCT(relTup);
00577
00578 if (classForm->relchecks == 0)
00579 elog(ERROR, "relation \"%s\" has relchecks = 0",
00580 RelationGetRelationName(rel));
00581 classForm->relchecks--;
00582
00583 simple_heap_update(pgrel, &relTup->t_self, relTup);
00584
00585 CatalogUpdateIndexes(pgrel, relTup);
00586
00587 heap_freetuple(relTup);
00588
00589 heap_close(pgrel, RowExclusiveLock);
00590 }
00591
00592
00593 heap_close(rel, NoLock);
00594 }
00595 else if (OidIsValid(con->contypid))
00596 {
00597
00598
00599
00600
00601
00602
00603 }
00604 else
00605 elog(ERROR, "constraint %u is not of a known type", conId);
00606
00607
00608 simple_heap_delete(conDesc, &tup->t_self);
00609
00610
00611 ReleaseSysCache(tup);
00612 heap_close(conDesc, RowExclusiveLock);
00613 }
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625 void
00626 RenameConstraintById(Oid conId, const char *newname)
00627 {
00628 Relation conDesc;
00629 HeapTuple tuple;
00630 Form_pg_constraint con;
00631
00632 conDesc = heap_open(ConstraintRelationId, RowExclusiveLock);
00633
00634 tuple = SearchSysCacheCopy1(CONSTROID, ObjectIdGetDatum(conId));
00635 if (!HeapTupleIsValid(tuple))
00636 elog(ERROR, "cache lookup failed for constraint %u", conId);
00637 con = (Form_pg_constraint) GETSTRUCT(tuple);
00638
00639
00640
00641
00642
00643 if (OidIsValid(con->conrelid) &&
00644 ConstraintNameIsUsed(CONSTRAINT_RELATION,
00645 con->conrelid,
00646 con->connamespace,
00647 newname))
00648 ereport(ERROR,
00649 (errcode(ERRCODE_DUPLICATE_OBJECT),
00650 errmsg("constraint \"%s\" for relation \"%s\" already exists",
00651 newname, get_rel_name(con->conrelid))));
00652 if (OidIsValid(con->contypid) &&
00653 ConstraintNameIsUsed(CONSTRAINT_DOMAIN,
00654 con->contypid,
00655 con->connamespace,
00656 newname))
00657 ereport(ERROR,
00658 (errcode(ERRCODE_DUPLICATE_OBJECT),
00659 errmsg("constraint \"%s\" for domain %s already exists",
00660 newname, format_type_be(con->contypid))));
00661
00662
00663 namestrcpy(&(con->conname), newname);
00664
00665 simple_heap_update(conDesc, &tuple->t_self, tuple);
00666
00667
00668 CatalogUpdateIndexes(conDesc, tuple);
00669
00670 InvokeObjectPostAlterHook(ConstraintRelationId, conId, 0);
00671
00672 heap_freetuple(tuple);
00673 heap_close(conDesc, RowExclusiveLock);
00674 }
00675
00676
00677
00678
00679
00680
00681
00682
00683 void
00684 AlterConstraintNamespaces(Oid ownerId, Oid oldNspId,
00685 Oid newNspId, bool isType, ObjectAddresses *objsMoved)
00686 {
00687 Relation conRel;
00688 ScanKeyData key[1];
00689 SysScanDesc scan;
00690 HeapTuple tup;
00691
00692 conRel = heap_open(ConstraintRelationId, RowExclusiveLock);
00693
00694 if (isType)
00695 {
00696 ScanKeyInit(&key[0],
00697 Anum_pg_constraint_contypid,
00698 BTEqualStrategyNumber, F_OIDEQ,
00699 ObjectIdGetDatum(ownerId));
00700
00701 scan = systable_beginscan(conRel, ConstraintTypidIndexId, true,
00702 SnapshotNow, 1, key);
00703 }
00704 else
00705 {
00706 ScanKeyInit(&key[0],
00707 Anum_pg_constraint_conrelid,
00708 BTEqualStrategyNumber, F_OIDEQ,
00709 ObjectIdGetDatum(ownerId));
00710
00711 scan = systable_beginscan(conRel, ConstraintRelidIndexId, true,
00712 SnapshotNow, 1, key);
00713 }
00714
00715 while (HeapTupleIsValid((tup = systable_getnext(scan))))
00716 {
00717 Form_pg_constraint conform = (Form_pg_constraint) GETSTRUCT(tup);
00718 ObjectAddress thisobj;
00719
00720 thisobj.classId = ConstraintRelationId;
00721 thisobj.objectId = HeapTupleGetOid(tup);
00722 thisobj.objectSubId = 0;
00723
00724 if (object_address_present(&thisobj, objsMoved))
00725 continue;
00726
00727 if (conform->connamespace == oldNspId)
00728 {
00729 tup = heap_copytuple(tup);
00730 conform = (Form_pg_constraint) GETSTRUCT(tup);
00731
00732 conform->connamespace = newNspId;
00733
00734 simple_heap_update(conRel, &tup->t_self, tup);
00735 CatalogUpdateIndexes(conRel, tup);
00736
00737
00738
00739
00740
00741
00742 }
00743
00744 InvokeObjectPostAlterHook(ConstraintRelationId, thisobj.objectId, 0);
00745
00746 add_exact_object_address(&thisobj, objsMoved);
00747 }
00748
00749 systable_endscan(scan);
00750
00751 heap_close(conRel, RowExclusiveLock);
00752 }
00753
00754
00755
00756
00757
00758
00759 Oid
00760 get_relation_constraint_oid(Oid relid, const char *conname, bool missing_ok)
00761 {
00762 Relation pg_constraint;
00763 HeapTuple tuple;
00764 SysScanDesc scan;
00765 ScanKeyData skey[1];
00766 Oid conOid = InvalidOid;
00767
00768
00769
00770
00771
00772
00773 pg_constraint = heap_open(ConstraintRelationId, AccessShareLock);
00774
00775 ScanKeyInit(&skey[0],
00776 Anum_pg_constraint_conrelid,
00777 BTEqualStrategyNumber, F_OIDEQ,
00778 ObjectIdGetDatum(relid));
00779
00780 scan = systable_beginscan(pg_constraint, ConstraintRelidIndexId, true,
00781 SnapshotNow, 1, skey);
00782
00783 while (HeapTupleIsValid(tuple = systable_getnext(scan)))
00784 {
00785 Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tuple);
00786
00787 if (strcmp(NameStr(con->conname), conname) == 0)
00788 {
00789 if (OidIsValid(conOid))
00790 ereport(ERROR,
00791 (errcode(ERRCODE_DUPLICATE_OBJECT),
00792 errmsg("table \"%s\" has multiple constraints named \"%s\"",
00793 get_rel_name(relid), conname)));
00794 conOid = HeapTupleGetOid(tuple);
00795 }
00796 }
00797
00798 systable_endscan(scan);
00799
00800
00801 if (!OidIsValid(conOid) && !missing_ok)
00802 ereport(ERROR,
00803 (errcode(ERRCODE_UNDEFINED_OBJECT),
00804 errmsg("constraint \"%s\" for table \"%s\" does not exist",
00805 conname, get_rel_name(relid))));
00806
00807 heap_close(pg_constraint, AccessShareLock);
00808
00809 return conOid;
00810 }
00811
00812
00813
00814
00815
00816
00817 Oid
00818 get_domain_constraint_oid(Oid typid, const char *conname, bool missing_ok)
00819 {
00820 Relation pg_constraint;
00821 HeapTuple tuple;
00822 SysScanDesc scan;
00823 ScanKeyData skey[1];
00824 Oid conOid = InvalidOid;
00825
00826
00827
00828
00829
00830
00831 pg_constraint = heap_open(ConstraintRelationId, AccessShareLock);
00832
00833 ScanKeyInit(&skey[0],
00834 Anum_pg_constraint_contypid,
00835 BTEqualStrategyNumber, F_OIDEQ,
00836 ObjectIdGetDatum(typid));
00837
00838 scan = systable_beginscan(pg_constraint, ConstraintTypidIndexId, true,
00839 SnapshotNow, 1, skey);
00840
00841 while (HeapTupleIsValid(tuple = systable_getnext(scan)))
00842 {
00843 Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tuple);
00844
00845 if (strcmp(NameStr(con->conname), conname) == 0)
00846 {
00847 if (OidIsValid(conOid))
00848 ereport(ERROR,
00849 (errcode(ERRCODE_DUPLICATE_OBJECT),
00850 errmsg("domain \"%s\" has multiple constraints named \"%s\"",
00851 format_type_be(typid), conname)));
00852 conOid = HeapTupleGetOid(tuple);
00853 }
00854 }
00855
00856 systable_endscan(scan);
00857
00858
00859 if (!OidIsValid(conOid) && !missing_ok)
00860 ereport(ERROR,
00861 (errcode(ERRCODE_UNDEFINED_OBJECT),
00862 errmsg("constraint \"%s\" for domain \"%s\" does not exist",
00863 conname, format_type_be(typid))));
00864
00865 heap_close(pg_constraint, AccessShareLock);
00866
00867 return conOid;
00868 }
00869
00870
00871
00872
00873
00874
00875
00876
00877
00878
00879
00880
00881
00882
00883
00884
00885 bool
00886 check_functional_grouping(Oid relid,
00887 Index varno, Index varlevelsup,
00888 List *grouping_columns,
00889 List **constraintDeps)
00890 {
00891 bool result = false;
00892 Relation pg_constraint;
00893 HeapTuple tuple;
00894 SysScanDesc scan;
00895 ScanKeyData skey[1];
00896
00897
00898 pg_constraint = heap_open(ConstraintRelationId, AccessShareLock);
00899
00900 ScanKeyInit(&skey[0],
00901 Anum_pg_constraint_conrelid,
00902 BTEqualStrategyNumber, F_OIDEQ,
00903 ObjectIdGetDatum(relid));
00904
00905 scan = systable_beginscan(pg_constraint, ConstraintRelidIndexId, true,
00906 SnapshotNow, 1, skey);
00907
00908 while (HeapTupleIsValid(tuple = systable_getnext(scan)))
00909 {
00910 Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tuple);
00911 Datum adatum;
00912 bool isNull;
00913 ArrayType *arr;
00914 int16 *attnums;
00915 int numkeys;
00916 int i;
00917 bool found_col;
00918
00919
00920 if (con->contype != CONSTRAINT_PRIMARY)
00921 continue;
00922
00923 if (con->condeferrable)
00924 continue;
00925
00926
00927 adatum = heap_getattr(tuple, Anum_pg_constraint_conkey,
00928 RelationGetDescr(pg_constraint), &isNull);
00929 if (isNull)
00930 elog(ERROR, "null conkey for constraint %u",
00931 HeapTupleGetOid(tuple));
00932 arr = DatumGetArrayTypeP(adatum);
00933 numkeys = ARR_DIMS(arr)[0];
00934 if (ARR_NDIM(arr) != 1 ||
00935 numkeys < 0 ||
00936 ARR_HASNULL(arr) ||
00937 ARR_ELEMTYPE(arr) != INT2OID)
00938 elog(ERROR, "conkey is not a 1-D smallint array");
00939 attnums = (int16 *) ARR_DATA_PTR(arr);
00940
00941 found_col = false;
00942 for (i = 0; i < numkeys; i++)
00943 {
00944 AttrNumber attnum = attnums[i];
00945 ListCell *gl;
00946
00947 found_col = false;
00948 foreach(gl, grouping_columns)
00949 {
00950 Var *gvar = (Var *) lfirst(gl);
00951
00952 if (IsA(gvar, Var) &&
00953 gvar->varno == varno &&
00954 gvar->varlevelsup == varlevelsup &&
00955 gvar->varattno == attnum)
00956 {
00957 found_col = true;
00958 break;
00959 }
00960 }
00961 if (!found_col)
00962 break;
00963 }
00964
00965 if (found_col)
00966 {
00967
00968 *constraintDeps = lappend_oid(*constraintDeps,
00969 HeapTupleGetOid(tuple));
00970 result = true;
00971 break;
00972 }
00973 }
00974
00975 systable_endscan(scan);
00976
00977 heap_close(pg_constraint, AccessShareLock);
00978
00979 return result;
00980 }