diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 50a72c3..91299f9 100644 *** a/src/backend/commands/tablecmds.c --- /bsrc/backend/commands/tablecmds.c *************** ATExecDropConstraint(Relation rel, const *** 4999,5037 **** DropBehavior behavior, bool recurse, bool recursing) { ! HeapTuple tuple; ! List *children; ! Relation conrel; ! Form_pg_constraint con; ! conrel = heap_open(ConstraintRelationId, RowExclusiveLock); /* At top level, permission check was done in ATPrepCmd, else do it */ if (recursing) ATSimplePermissions(rel, false); ! tuple = SearchSysCache(CONSTRNAME, ! ObjectIdGetDatum(RelationGetRelid(rel)), ! CStringGetDatum(constrName), ! 0, 0); ! if (!HeapTupleIsValid(tuple)) ! ereport(ERROR, ! (errcode(ERRCODE_UNDEFINED_COLUMN), ! errmsg("constraint \"%s\" of relation \"%s\" does not exist", ! constrName, RelationGetRelationName(rel)))); ! con = (Form_pg_constraint) GETSTRUCT(tuple); ! /* Don't drop inherited constraints */ ! if (con->coninhcount > 0 && !recursing) ! ereport(ERROR, (errcode(ERRCODE_INVALID_TABLE_DEFINITION), errmsg("cannot drop inherited constraint \"%s\" of relation \"%s\"", constrName, RelationGetRelationName(rel)))); ! ReleaseSysCache(tuple); /* * Propagate to children as appropriate. Unlike most other ALTER --- 4999,5050 ---- DropBehavior behavior, bool recurse, bool recursing) { ! List *children; ! Relation conrel; ! Form_pg_constraint con; ! SysScanDesc scan; ! ScanKeyData key; ! HeapTuple tuple; ! bool found = false; ! conrel = heap_open(ConstraintRelationId, AccessExclusiveLock); /* At top level, permission check was done in ATPrepCmd, else do it */ if (recursing) ATSimplePermissions(rel, false); ! /* Find the constraint, make sure we don't drop it if its inherited */ ! ScanKeyInit(&key, ! Anum_pg_constraint_conrelid, ! BTEqualStrategyNumber, F_OIDEQ, ! ObjectIdGetDatum(RelationGetRelid(rel))); ! scan = systable_beginscan(conrel, ConstraintRelidIndexId, ! true, SnapshotNow, 1, &key); ! while (HeapTupleIsValid(tuple = systable_getnext(scan))) ! { ! con = (Form_pg_constraint) GETSTRUCT(tuple); ! if (strcmp(NameStr(con->conname), ! constrName) != 0) ! continue; ! /* Don't drop inherited constraints */ ! if (con->contype == CONSTRAINT_CHECK && con->coninhcount > 0 && !recursing) ! ereport(ERROR, (errcode(ERRCODE_INVALID_TABLE_DEFINITION), errmsg("cannot drop inherited constraint \"%s\" of relation \"%s\"", constrName, RelationGetRelationName(rel)))); ! found = true; ! } ! ! if(!found) ! elog(ERROR, "failed to find constraint \"%s\" of relation %u", ! constrName, RelationGetRelid(rel)); ! ! systable_endscan(scan); /* * Propagate to children as appropriate. Unlike most other ALTER *************** ATExecDropConstraint(Relation rel, const *** 5048,5109 **** { Oid childrelid = lfirst_oid(child); Relation childrel; - Form_pg_constraint childcon; childrel = heap_open(childrelid, AccessExclusiveLock); CheckTableNotInUse(childrel, "ALTER TABLE"); ! tuple = SearchSysCacheCopy(CONSTRNAME, ! ObjectIdGetDatum(childrelid), ! CStringGetDatum(constrName), ! 0, 0); ! if (!HeapTupleIsValid(tuple)) ! elog(ERROR, "cache lookup failed for constraint \"%s\" of relation %u", ! constrName, childrelid); ! ! childcon = (Form_pg_constraint) GETSTRUCT(tuple); ! ! if (childcon->coninhcount <= 0) ! elog(ERROR, "relation %u has non-inherited constraint \"%s\"", ! childrelid, constrName); ! if (recurse) { ! if (childcon->coninhcount == 1 && !childcon->conislocal) { ! ATExecDropConstraint(childrel, constrName, behavior, true, true); } else { ! childcon->coninhcount--; ! simple_heap_update(conrel, &tuple->t_self, tuple); ! CatalogUpdateIndexes(conrel, tuple); ! } ! } ! else ! { ! /* ! * If we were told to drop ONLY in this table (no recursion), ! * we need to mark the inheritors' attribute as locally ! * defined rather than inherited. ! */ ! childcon->coninhcount--; ! childcon->conislocal = true; ! simple_heap_update(conrel, &tuple->t_self, tuple); ! CatalogUpdateIndexes(conrel, tuple); } ! heap_freetuple(tuple); heap_close(childrel, AccessExclusiveLock); } } RemoveRelConstraints(rel, constrName, behavior); ! heap_close(conrel, RowExclusiveLock); } /* --- 5061,5144 ---- { Oid childrelid = lfirst_oid(child); Relation childrel; childrel = heap_open(childrelid, AccessExclusiveLock); CheckTableNotInUse(childrel, "ALTER TABLE"); ! ScanKeyInit(&key, ! Anum_pg_constraint_conrelid, ! BTEqualStrategyNumber, F_OIDEQ, ! ObjectIdGetDatum(childrelid)); ! scan = systable_beginscan(conrel, ConstraintRelidIndexId, ! true, SnapshotNow, 1, &key); ! ! found = false; ! while (HeapTupleIsValid(tuple = systable_getnext(scan))) { ! HeapTuple copy_tuple; ! ! con = (Form_pg_constraint) GETSTRUCT(tuple); ! ! if (con->contype != CONSTRAINT_CHECK) ! continue; ! ! if (strcmp(NameStr(con->conname), ! constrName) != 0) ! continue; ! else ! found = true; ! ! if (con->coninhcount <= 0) ! elog(ERROR, "relation %u has non-inherited constraint \"%s\"", ! childrelid, constrName); ! ! copy_tuple = heap_copytuple(tuple); ! con = (Form_pg_constraint) GETSTRUCT(copy_tuple); ! ! if (recurse) { ! if (con->coninhcount == 1 && !con->conislocal) ! { ! ATExecDropConstraint(childrel, constrName, behavior, true, true); ! } ! else ! { ! con->coninhcount--; ! simple_heap_update(conrel, ©_tuple->t_self, copy_tuple); ! CatalogUpdateIndexes(conrel, copy_tuple); ! } } else { ! /* ! * If we were told to drop ONLY in this table (no recursion), ! * we need to mark the inheritors' attribute as locally ! * defined rather than inherited. ! */ ! con->coninhcount--; ! con->conislocal = true; ! simple_heap_update(conrel, ©_tuple->t_self, copy_tuple); ! CatalogUpdateIndexes(conrel, copy_tuple); ! } ! heap_freetuple(copy_tuple); } ! if (!found) ! elog(ERROR, "failed to find constraint \"%s\" of relation %u", ! constrName, childrelid); ! ! systable_endscan(scan); heap_close(childrel, AccessExclusiveLock); } } RemoveRelConstraints(rel, constrName, behavior); ! heap_close(conrel, AccessExclusiveLock); } /* *************** MergeAttributesIntoExisting(Relation chi *** 6621,6683 **** * make it possible to ensure no records are mistakenly inserted into the * master in partitioned tables rather than the appropriate child. * */ static void MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel) { ! Relation catalogRelation; ! TupleDesc tupleDesc; ! SysScanDesc scan; ! ScanKeyData key; ! HeapTuple constraintTuple; ! catalogRelation = heap_open(ConstraintRelationId, RowExclusiveLock); ! tupleDesc = RelationGetDescr(catalogRelation); ! ScanKeyInit(&key, Anum_pg_constraint_conrelid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(RelationGetRelid(parent_rel))); ! scan = systable_beginscan(catalogRelation, ConstraintRelidIndexId, ! true, SnapshotNow, 1, &key); ! while (HeapTupleIsValid(constraintTuple = systable_getnext(scan))) { ! HeapTuple childTuple; ! Form_pg_constraint child_con; ! Form_pg_constraint parent_con = (Form_pg_constraint) GETSTRUCT(constraintTuple); if (parent_con->contype != CONSTRAINT_CHECK) continue; ! childTuple = SearchSysCacheCopy(CONSTRNAME, ! ObjectIdGetDatum(RelationGetRelid(child_rel)), ! CStringGetDatum(NameStr(parent_con->conname)), ! 0, 0); ! if (!HeapTupleIsValid(childTuple)) ! ereport(ERROR, ! (errcode(ERRCODE_DATATYPE_MISMATCH), ! errmsg("child table is missing constraint \"%s\"", ! NameStr(parent_con->conname)))); ! child_con = (Form_pg_constraint) GETSTRUCT(childTuple); ! if (!ConstraintIsEquiv(constraintTuple, childTuple, tupleDesc)) ! ereport(ERROR, ! (errcode(ERRCODE_DATATYPE_MISMATCH), ! errmsg("constraint definition for check constraint \"%s\" does not match", ! NameStr(parent_con->conname)))); ! /* increment coninhcount */ ! child_con->coninhcount++; ! simple_heap_update(catalogRelation, &childTuple->t_self, childTuple); ! CatalogUpdateIndexes(catalogRelation, childTuple); ! heap_freetuple(childTuple); } ! systable_endscan(scan); ! heap_close(catalogRelation, RowExclusiveLock); } /* --- 6656,6747 ---- * make it possible to ensure no records are mistakenly inserted into the * master in partitioned tables rather than the appropriate child. * + * XXX This is O(N^2) which may be an issue with tables with hundreds of + * constraints. As long as tables have more like 10 constraints it shouldn't be + * a problem though. Even 100 constraints ought not be the end of the world. */ static void MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel) { ! Relation catalog_relation; ! TupleDesc tuple_desc; ! SysScanDesc parent_scan; ! ScanKeyData parent_key; ! HeapTuple constraint_tuple; ! catalog_relation = heap_open(ConstraintRelationId, RowExclusiveLock); ! tuple_desc = RelationGetDescr(catalog_relation); ! /* First gather up the parents constraint definitions */ ! ScanKeyInit(&parent_key, Anum_pg_constraint_conrelid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(RelationGetRelid(parent_rel))); ! parent_scan = systable_beginscan(catalog_relation, ConstraintRelidIndexId, ! true, SnapshotNow, 1, &parent_key); ! while (HeapTupleIsValid(constraint_tuple = systable_getnext(parent_scan))) { ! Form_pg_constraint parent_con = (Form_pg_constraint) GETSTRUCT(constraint_tuple); ! HeapTuple child_tuple; ! Form_pg_constraint child_con; ! SysScanDesc child_scan; ! ScanKeyData child_key; ! bool found = false; if (parent_con->contype != CONSTRAINT_CHECK) continue; ! /* Now look for matching child matches */ ! ScanKeyInit(&child_key, ! Anum_pg_constraint_conrelid, ! BTEqualStrategyNumber, F_OIDEQ, ! ObjectIdGetDatum(RelationGetRelid(child_rel))); ! child_scan = systable_beginscan(catalog_relation, ConstraintRelidIndexId, ! true, SnapshotNow, 1, &child_key); ! ! while (HeapTupleIsValid(child_tuple = systable_getnext(child_scan))) ! { ! HeapTuple child_copy; ! child_con = (Form_pg_constraint) GETSTRUCT(child_tuple); ! if (child_con->contype != CONSTRAINT_CHECK) ! continue; ! child_copy = heap_copytuple(child_tuple); ! child_con = (Form_pg_constraint) GETSTRUCT(child_copy); ! ! if (strcmp(NameStr(parent_con->conname), ! NameStr(child_con->conname)) != 0) ! continue; ! ! if (!ConstraintIsEquiv(constraint_tuple, child_tuple, tuple_desc)) ! ereport(ERROR, ! (errcode(ERRCODE_DATATYPE_MISMATCH), ! errmsg("constraint definition for check constraint \"%s\" does not match", ! NameStr(parent_con->conname)))); ! found = true; ! ! /* increment coninhcount */ ! child_con->coninhcount++; ! simple_heap_update(catalog_relation, &child_copy->t_self, child_copy); ! CatalogUpdateIndexes(catalog_relation, child_copy); ! heap_freetuple(child_copy); ! } ! ! systable_endscan(child_scan); ! ! if (!found) ! ereport(ERROR, ! (errcode(ERRCODE_DATATYPE_MISMATCH), ! errmsg("child table is missing constraint \"%s\"", ! NameStr(parent_con->conname)))); } ! systable_endscan(parent_scan); ! heap_close(catalog_relation, RowExclusiveLock); } /* diff --git a/src/backend/utils/cache/syscache.c b/src/backend/utils/cache/syscache.c index 789c6a4..7ff0e8a 100644 *** a/src/backend/utils/cache/syscache.c --- /bsrc/backend/utils/cache/syscache.c *************** static const struct cachedesc cacheinfo[ *** 305,322 **** }, 128 }, - {ConstraintRelationId, // CONSTRNAME - ConstraintRelidNameIndexId, - Anum_pg_constraint_conrelid, - 2, - { - Anum_pg_constraint_conrelid, - Anum_pg_constraint_conname, - 0, - 0 - }, - 256, - }, {ConstraintRelationId, /* CONSTROID */ ConstraintOidIndexId, 0, --- 305,310 ---- diff --git a/src/include/catalog/indexing.h b/src/include/catalog/indexing.h index d962930..7dc5215 100644 *** a/src/include/catalog/indexing.h --- /bsrc/include/catalog/indexing.h *************** DECLARE_INDEX(pg_constraint_contypid_ind *** 121,128 **** #define ConstraintTypidIndexId 2666 DECLARE_UNIQUE_INDEX(pg_constraint_oid_index, 2667, on pg_constraint using btree(oid oid_ops)); #define ConstraintOidIndexId 2667 - DECLARE_UNIQUE_INDEX(pg_constraint_relid_coname_index, 2700, on pg_constraint using btree(conrelid oid_ops, conname name_ops)); - #define ConstraintRelidNameIndexId 2700 DECLARE_UNIQUE_INDEX(pg_conversion_default_index, 2668, on pg_conversion using btree(connamespace oid_ops, conforencoding int4_ops, contoencoding int4_ops, oid oid_ops)); #define ConversionDefaultIndexId 2668 --- 121,126 ---- diff --git a/src/include/utils/syscache.h b/src/include/utils/syscache.h index b99da72..c97a256 100644 *** a/src/include/utils/syscache.h --- /bsrc/include/utils/syscache.h *************** enum SysCacheIdent { *** 46,52 **** CLAOID, CONDEFAULT, CONNAMENSP, - CONSTRNAME, CONSTROID, CONVOID, DATABASEOID, --- 46,51 ----