diff options
Diffstat (limited to 'src/backend/commands/tablecmds.c')
-rw-r--r-- | src/backend/commands/tablecmds.c | 97 |
1 files changed, 91 insertions, 6 deletions
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index c8212713069..47b29001d5c 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -482,11 +482,16 @@ static ObjectAddress addFkRecurseReferenced(List **wqueue, Constraint *fkconstra Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr, int numfks, int16 *pkattnum, int16 *fkattnum, Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators, + int numfkdelsetcols, int16 *fkdelsetcols, bool old_check_ok); +static void validateFkOnDeleteSetColumns(int numfks, const int16 *fkattnums, + int numfksetcols, const int16 *fksetcolsattnums, + List *fksetcols); static void addFkRecurseReferencing(List **wqueue, Constraint *fkconstraint, Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr, int numfks, int16 *pkattnum, int16 *fkattnum, Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators, + int numfkdelsetcols, int16 *fkdelsetcols, bool old_check_ok, LOCKMODE lockmode); static void CloneForeignKeyConstraints(List **wqueue, Relation parentRel, Relation partitionRel); @@ -8973,9 +8978,11 @@ ATAddForeignKeyConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, Oid pfeqoperators[INDEX_MAX_KEYS]; Oid ppeqoperators[INDEX_MAX_KEYS]; Oid ffeqoperators[INDEX_MAX_KEYS]; + int16 fkdelsetcols[INDEX_MAX_KEYS]; int i; int numfks, - numpks; + numpks, + numfkdelsetcols; Oid indexOid; bool old_check_ok; ObjectAddress address; @@ -9071,11 +9078,19 @@ ATAddForeignKeyConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, MemSet(pfeqoperators, 0, sizeof(pfeqoperators)); MemSet(ppeqoperators, 0, sizeof(ppeqoperators)); MemSet(ffeqoperators, 0, sizeof(ffeqoperators)); + MemSet(fkdelsetcols, 0, sizeof(fkdelsetcols)); numfks = transformColumnNameList(RelationGetRelid(rel), fkconstraint->fk_attrs, fkattnum, fktypoid); + numfkdelsetcols = transformColumnNameList(RelationGetRelid(rel), + fkconstraint->fk_del_set_cols, + fkdelsetcols, NULL); + validateFkOnDeleteSetColumns(numfks, fkattnum, + numfkdelsetcols, fkdelsetcols, + fkconstraint->fk_del_set_cols); + /* * If the attribute list for the referenced table was omitted, lookup the * definition of the primary key and use it. Otherwise, validate the @@ -9350,6 +9365,8 @@ ATAddForeignKeyConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, pfeqoperators, ppeqoperators, ffeqoperators, + numfkdelsetcols, + fkdelsetcols, old_check_ok); /* Now handle the referencing side. */ @@ -9362,6 +9379,8 @@ ATAddForeignKeyConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, pfeqoperators, ppeqoperators, ffeqoperators, + numfkdelsetcols, + fkdelsetcols, old_check_ok, lockmode); @@ -9374,6 +9393,40 @@ ATAddForeignKeyConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, } /* + * validateFkActionSetColumns + * Verifies that columns used in ON DELETE SET NULL/DEFAULT (...) + * column lists are valid. + */ +void +validateFkOnDeleteSetColumns(int numfks, const int16 *fkattnums, + int numfksetcols, const int16 *fksetcolsattnums, + List *fksetcols) +{ + for (int i = 0; i < numfksetcols; i++) + { + int16 setcol_attnum = fksetcolsattnums[i]; + bool seen = false; + + for (int j = 0; j < numfks; j++) + { + if (fkattnums[j] == setcol_attnum) + { + seen = true; + break; + } + } + + if (!seen) + { + char *col = strVal(list_nth(fksetcols, i)); + ereport(ERROR, + (errcode(ERRCODE_INVALID_COLUMN_REFERENCE), + errmsg("column \"%s\" referenced in ON DELETE SET action must be part of foreign key", col))); + } + } +} + +/* * addFkRecurseReferenced * subroutine for ATAddForeignKeyConstraint; recurses on the referenced * side of the constraint @@ -9394,6 +9447,10 @@ ATAddForeignKeyConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, * numfks is the number of columns in the foreign key * pkattnum is the attnum array of referenced attributes. * fkattnum is the attnum array of referencing attributes. + * numfkdelsetcols is the number of columns in the ON DELETE SET NULL/DELETE + * (...) clause + * fkdelsetcols is the attnum array of the columns in the ON DELETE SET + * NULL/DELETE clause * pf/pp/ffeqoperators are OID array of operators between columns. * old_check_ok signals that this constraint replaces an existing one that * was already validated (thus this one doesn't need validation). @@ -9403,7 +9460,9 @@ addFkRecurseReferenced(List **wqueue, Constraint *fkconstraint, Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr, int numfks, int16 *pkattnum, int16 *fkattnum, Oid *pfeqoperators, - Oid *ppeqoperators, Oid *ffeqoperators, bool old_check_ok) + Oid *ppeqoperators, Oid *ffeqoperators, + int numfkdelsetcols, int16 *fkdelsetcols, + bool old_check_ok) { ObjectAddress address; Oid constrOid; @@ -9478,6 +9537,8 @@ addFkRecurseReferenced(List **wqueue, Constraint *fkconstraint, Relation rel, numfks, fkconstraint->fk_upd_action, fkconstraint->fk_del_action, + fkdelsetcols, + numfkdelsetcols, fkconstraint->fk_matchtype, NULL, /* no exclusion constraint */ NULL, /* no check constraint */ @@ -9559,6 +9620,7 @@ addFkRecurseReferenced(List **wqueue, Constraint *fkconstraint, Relation rel, partIndexId, constrOid, numfks, mapped_pkattnum, fkattnum, pfeqoperators, ppeqoperators, ffeqoperators, + numfkdelsetcols, fkdelsetcols, old_check_ok); /* Done -- clean up (but keep the lock) */ @@ -9599,6 +9661,10 @@ addFkRecurseReferenced(List **wqueue, Constraint *fkconstraint, Relation rel, * pkattnum is the attnum array of referenced attributes. * fkattnum is the attnum array of referencing attributes. * pf/pp/ffeqoperators are OID array of operators between columns. + * numfkdelsetcols is the number of columns in the ON DELETE SET NULL/DELETE + * (...) clause + * fkdelsetcols is the attnum array of the columns in the ON DELETE SET + * NULL/DELETE clause * old_check_ok signals that this constraint replaces an existing one that * was already validated (thus this one doesn't need validation). * lockmode is the lockmode to acquire on partitions when recursing. @@ -9608,6 +9674,7 @@ addFkRecurseReferencing(List **wqueue, Constraint *fkconstraint, Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr, int numfks, int16 *pkattnum, int16 *fkattnum, Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators, + int numfkdelsetcols, int16 *fkdelsetcols, bool old_check_ok, LOCKMODE lockmode) { AssertArg(OidIsValid(parentConstr)); @@ -9746,6 +9813,8 @@ addFkRecurseReferencing(List **wqueue, Constraint *fkconstraint, Relation rel, numfks, fkconstraint->fk_upd_action, fkconstraint->fk_del_action, + fkdelsetcols, + numfkdelsetcols, fkconstraint->fk_matchtype, NULL, NULL, @@ -9778,6 +9847,8 @@ addFkRecurseReferencing(List **wqueue, Constraint *fkconstraint, Relation rel, pfeqoperators, ppeqoperators, ffeqoperators, + numfkdelsetcols, + fkdelsetcols, old_check_ok, lockmode); @@ -9883,6 +9954,8 @@ CloneFkReferenced(Relation parentRel, Relation partitionRel) Oid conpfeqop[INDEX_MAX_KEYS]; Oid conppeqop[INDEX_MAX_KEYS]; Oid conffeqop[INDEX_MAX_KEYS]; + int numfkdelsetcols; + AttrNumber confdelsetcols[INDEX_MAX_KEYS]; Constraint *fkconstraint; tuple = SearchSysCache1(CONSTROID, constrOid); @@ -9915,7 +9988,9 @@ CloneFkReferenced(Relation parentRel, Relation partitionRel) confkey, conpfeqop, conppeqop, - conffeqop); + conffeqop, + &numfkdelsetcols, + confdelsetcols); for (int i = 0; i < numfks; i++) mapped_confkey[i] = attmap->attnums[confkey[i] - 1]; @@ -9962,6 +10037,8 @@ CloneFkReferenced(Relation parentRel, Relation partitionRel) conpfeqop, conppeqop, conffeqop, + numfkdelsetcols, + confdelsetcols, true); table_close(fkRel, NoLock); @@ -10032,6 +10109,8 @@ CloneFkReferencing(List **wqueue, Relation parentRel, Relation partRel) Oid conpfeqop[INDEX_MAX_KEYS]; Oid conppeqop[INDEX_MAX_KEYS]; Oid conffeqop[INDEX_MAX_KEYS]; + int numfkdelsetcols; + AttrNumber confdelsetcols[INDEX_MAX_KEYS]; Constraint *fkconstraint; bool attached; Oid indexOid; @@ -10063,7 +10142,8 @@ CloneFkReferencing(List **wqueue, Relation parentRel, Relation partRel) ShareRowExclusiveLock, NULL); DeconstructFkConstraintRow(tuple, &numfks, conkey, confkey, - conpfeqop, conppeqop, conffeqop); + conpfeqop, conppeqop, conffeqop, + &numfkdelsetcols, confdelsetcols); for (int i = 0; i < numfks; i++) mapped_conkey[i] = attmap->attnums[conkey[i] - 1]; @@ -10148,6 +10228,8 @@ CloneFkReferencing(List **wqueue, Relation parentRel, Relation partRel) numfks, fkconstraint->fk_upd_action, fkconstraint->fk_del_action, + confdelsetcols, + numfkdelsetcols, fkconstraint->fk_matchtype, NULL, NULL, @@ -10183,6 +10265,8 @@ CloneFkReferencing(List **wqueue, Relation parentRel, Relation partRel) conpfeqop, conppeqop, conffeqop, + numfkdelsetcols, + confdelsetcols, false, /* no old check exists */ AccessExclusiveLock); table_close(pkrel, NoLock); @@ -10804,7 +10888,7 @@ ATExecValidateConstraint(List **wqueue, Relation rel, char *constrName, /* * transformColumnNameList - transform list of column names * - * Lookup each name and return its attnum and type OID + * Lookup each name and return its attnum and, optionally, type OID */ static int transformColumnNameList(Oid relId, List *colList, @@ -10831,7 +10915,8 @@ transformColumnNameList(Oid relId, List *colList, errmsg("cannot have more than %d keys in a foreign key", INDEX_MAX_KEYS))); attnums[attnum] = ((Form_pg_attribute) GETSTRUCT(atttuple))->attnum; - atttypids[attnum] = ((Form_pg_attribute) GETSTRUCT(atttuple))->atttypid; + if (atttypids != NULL) + atttypids[attnum] = ((Form_pg_attribute) GETSTRUCT(atttuple))->atttypid; ReleaseSysCache(atttuple); attnum++; } |