* Add a foreign-key constraint to a single table; return the new constraint's * address. * * Subroutine for ATExecAddConstraint. Must already hold exclusive * lock on the rel, and have done appropriate validity checks for it. * We do permissions checks here, however. * * When the referenced or referencing tables (or both) are partitioned, * multiple pg_constraint rows are required -- one
| 10967 | * referencing side. |
| 10968 | */ |
| 10969 | static ObjectAddress |
| 10970 | ATAddForeignKeyConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, |
| 10971 | Constraint *fkconstraint, |
| 10972 | bool recurse, bool recursing, LOCKMODE lockmode) |
| 10973 | { |
| 10974 | Relation pkrel; |
| 10975 | int16 pkattnum[INDEX_MAX_KEYS]; |
| 10976 | int16 fkattnum[INDEX_MAX_KEYS]; |
| 10977 | Oid pktypoid[INDEX_MAX_KEYS]; |
| 10978 | Oid fktypoid[INDEX_MAX_KEYS]; |
| 10979 | Oid opclasses[INDEX_MAX_KEYS]; |
| 10980 | Oid pfeqoperators[INDEX_MAX_KEYS]; |
| 10981 | Oid ppeqoperators[INDEX_MAX_KEYS]; |
| 10982 | Oid ffeqoperators[INDEX_MAX_KEYS]; |
| 10983 | int i; |
| 10984 | int numfks, |
| 10985 | numpks; |
| 10986 | Oid indexOid; |
| 10987 | bool old_check_ok; |
| 10988 | ObjectAddress address; |
| 10989 | ListCell *old_pfeqop_item = list_head(fkconstraint->old_conpfeqop); |
| 10990 | |
| 10991 | /* |
| 10992 | * Grab ShareRowExclusiveLock on the pk table, so that someone doesn't |
| 10993 | * delete rows out from under us. |
| 10994 | */ |
| 10995 | if (OidIsValid(fkconstraint->old_pktable_oid)) |
| 10996 | pkrel = table_open(fkconstraint->old_pktable_oid, ShareRowExclusiveLock); |
| 10997 | else |
| 10998 | pkrel = table_openrv(fkconstraint->pktable, ShareRowExclusiveLock); |
| 10999 | |
| 11000 | /* |
| 11001 | * GPDB: Schema-qualify the primary key table for the statement dispatch |
| 11002 | * that will happen later. The QE nodes are not guaranteed to have the |
| 11003 | * same search_path as the QD (e.g. CREATE SCHEMA command with schema |
| 11004 | * elements creating relations). |
| 11005 | */ |
| 11006 | if (Gp_role == GP_ROLE_DISPATCH) |
| 11007 | fkconstraint->pktable->schemaname = |
| 11008 | get_namespace_name(pkrel->rd_rel->relnamespace); |
| 11009 | |
| 11010 | /* |
| 11011 | * Validity checks (permission checks wait till we have the column |
| 11012 | * numbers) |
| 11013 | */ |
| 11014 | if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) |
| 11015 | { |
| 11016 | if (!recurse) |
| 11017 | ereport(ERROR, |
| 11018 | (errcode(ERRCODE_WRONG_OBJECT_TYPE), |
| 11019 | errmsg("cannot use ONLY for foreign key on partitioned table \"%s\" referencing relation \"%s\"", |
| 11020 | RelationGetRelationName(rel), |
| 11021 | RelationGetRelationName(pkrel)))); |
| 11022 | if (fkconstraint->skip_validation && !fkconstraint->initially_valid) |
| 11023 | ereport(ERROR, |
| 11024 | (errcode(ERRCODE_WRONG_OBJECT_TYPE), |
| 11025 | errmsg("cannot add NOT VALID foreign key on partitioned table \"%s\" referencing relation \"%s\"", |
| 11026 | RelationGetRelationName(rel), |
no test coverage detected