aboutsummaryrefslogtreecommitdiff
path: root/src/backend/commands/tablecmds.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/commands/tablecmds.c')
-rw-r--r--src/backend/commands/tablecmds.c97
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++;
}