summaryrefslogtreecommitdiff
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 3baf9231ed0..b6fd46b019f 100644
--- a/src/backend/catalog/pg_constraint.c
+++ b/src/backend/catalog/pg_constraint.c
@@ -118,8 +118,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 535c74feb03..e6d5dcc252e 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -512,8 +512,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,
@@ -9716,9 +9716,10 @@ ATAddForeignKeyConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
numfkdelsetcols = transformColumnNameList(RelationGetRelid(rel),
fkconstraint->fk_del_set_cols,
fkdelsetcols, 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
@@ -10039,17 +10040,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)
@@ -10067,7 +10074,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 a7fe9407d25..eac9af9a858 100644
--- a/src/test/regress/expected/foreign_key.out
+++ b/src/test/regress/expected/foreign_key.out
@@ -772,7 +772,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 6aa675c7286..2d7584b49fe 100644
--- a/src/test/regress/sql/foreign_key.sql
+++ b/src/test/regress/sql/foreign_key.sql
@@ -473,7 +473,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;