aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/catalog/pg_constraint.c3
-rw-r--r--src/backend/commands/tablecmds.c35
-rw-r--r--src/test/regress/expected/foreign_key.out3
-rw-r--r--src/test/regress/sql/foreign_key.sql3
4 files changed, 34 insertions, 10 deletions
diff --git a/src/backend/catalog/pg_constraint.c b/src/backend/catalog/pg_constraint.c
index 0467e7442ff..b97960d2766 100644
--- a/src/backend/catalog/pg_constraint.c
+++ b/src/backend/catalog/pg_constraint.c
@@ -129,8 +129,9 @@ CreateConstraintEntry(const char *constraintName,
if (foreignNKeys > 0)
{
Datum *fkdatums;
+ int nkeys = Max(foreignNKeys, numFkDeleteSetCols);
- fkdatums = (Datum *) palloc(foreignNKeys * sizeof(Datum));
+ fkdatums = (Datum *) palloc(nkeys * sizeof(Datum));
for (i = 0; i < foreignNKeys; i++)
fkdatums[i] = Int16GetDatum(foreignKey[i]);
confkeyArray = construct_array_builtin(fkdatums, foreignNKeys, INT2OID);
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 11fcb51a165..4397123398e 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -557,8 +557,8 @@ static ObjectAddress ATAddForeignKeyConstraint(List **wqueue, AlteredTableInfo *
Relation rel, Constraint *fkconstraint,
bool recurse, bool recursing,
LOCKMODE lockmode);
-static void validateFkOnDeleteSetColumns(int numfks, const int16 *fkattnums,
- int numfksetcols, const int16 *fksetcolsattnums,
+static int validateFkOnDeleteSetColumns(int numfks, const int16 *fkattnums,
+ int numfksetcols, int16 *fksetcolsattnums,
List *fksetcols);
static ObjectAddress addFkConstraint(addFkConstraintSides fkside,
char *constraintname,
@@ -10037,9 +10037,10 @@ ATAddForeignKeyConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
numfkdelsetcols = transformColumnNameList(RelationGetRelid(rel),
fkconstraint->fk_del_set_cols,
fkdelsetcols, NULL, NULL);
- validateFkOnDeleteSetColumns(numfks, fkattnum,
- numfkdelsetcols, fkdelsetcols,
- fkconstraint->fk_del_set_cols);
+ numfkdelsetcols = validateFkOnDeleteSetColumns(numfks, fkattnum,
+ numfkdelsetcols,
+ fkdelsetcols,
+ fkconstraint->fk_del_set_cols);
/*
* If the attribute list for the referenced table was omitted, lookup the
@@ -10499,17 +10500,23 @@ ATAddForeignKeyConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
* validateFkOnDeleteSetColumns
* Verifies that columns used in ON DELETE SET NULL/DEFAULT (...)
* column lists are valid.
+ *
+ * If there are duplicates in the fksetcolsattnums[] array, this silently
+ * removes the dups. The new count of numfksetcols is returned.
*/
-void
+static int
validateFkOnDeleteSetColumns(int numfks, const int16 *fkattnums,
- int numfksetcols, const int16 *fksetcolsattnums,
+ int numfksetcols, int16 *fksetcolsattnums,
List *fksetcols)
{
+ int numcolsout = 0;
+
for (int i = 0; i < numfksetcols; i++)
{
int16 setcol_attnum = fksetcolsattnums[i];
bool seen = false;
+ /* Make sure it's in fkattnums[] */
for (int j = 0; j < numfks; j++)
{
if (fkattnums[j] == setcol_attnum)
@@ -10527,7 +10534,21 @@ validateFkOnDeleteSetColumns(int numfks, const int16 *fkattnums,
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
errmsg("column \"%s\" referenced in ON DELETE SET action must be part of foreign key", col)));
}
+
+ /* Now check for dups */
+ seen = false;
+ for (int j = 0; j < numcolsout; j++)
+ {
+ if (fksetcolsattnums[j] == setcol_attnum)
+ {
+ seen = true;
+ break;
+ }
+ }
+ if (!seen)
+ fksetcolsattnums[numcolsout++] = setcol_attnum;
}
+ return numcolsout;
}
/*
diff --git a/src/test/regress/expected/foreign_key.out b/src/test/regress/expected/foreign_key.out
index 53810a0fde9..c49abc3f0f6 100644
--- a/src/test/regress/expected/foreign_key.out
+++ b/src/test/regress/expected/foreign_key.out
@@ -837,7 +837,8 @@ CREATE TABLE FKTABLE (
fk_id_del_set_null int,
fk_id_del_set_default int DEFAULT 0,
FOREIGN KEY (tid, fk_id_del_set_null) REFERENCES PKTABLE ON DELETE SET NULL (fk_id_del_set_null),
- FOREIGN KEY (tid, fk_id_del_set_default) REFERENCES PKTABLE ON DELETE SET DEFAULT (fk_id_del_set_default)
+ -- this tests handling of duplicate entries in SET DEFAULT column list
+ FOREIGN KEY (tid, fk_id_del_set_default) REFERENCES PKTABLE ON DELETE SET DEFAULT (fk_id_del_set_default, fk_id_del_set_default)
);
SELECT pg_get_constraintdef(oid) FROM pg_constraint WHERE conrelid = 'fktable'::regclass::oid ORDER BY oid;
pg_get_constraintdef
diff --git a/src/test/regress/sql/foreign_key.sql b/src/test/regress/sql/foreign_key.sql
index 77c0c615630..f478d17745a 100644
--- a/src/test/regress/sql/foreign_key.sql
+++ b/src/test/regress/sql/foreign_key.sql
@@ -517,7 +517,8 @@ CREATE TABLE FKTABLE (
fk_id_del_set_null int,
fk_id_del_set_default int DEFAULT 0,
FOREIGN KEY (tid, fk_id_del_set_null) REFERENCES PKTABLE ON DELETE SET NULL (fk_id_del_set_null),
- FOREIGN KEY (tid, fk_id_del_set_default) REFERENCES PKTABLE ON DELETE SET DEFAULT (fk_id_del_set_default)
+ -- this tests handling of duplicate entries in SET DEFAULT column list
+ FOREIGN KEY (tid, fk_id_del_set_default) REFERENCES PKTABLE ON DELETE SET DEFAULT (fk_id_del_set_default, fk_id_del_set_default)
);
SELECT pg_get_constraintdef(oid) FROM pg_constraint WHERE conrelid = 'fktable'::regclass::oid ORDER BY oid;