I have reviewed your patch
referential-actions-on-delete-only-set-cols-v3.patch. Attached are two
patches that go on top of yours that contain my recommended changes.
Basically, this all looks pretty good to me. My changes are mostly
stylistic.
Some notes of substance:
- The omission of the referential actions details from the CREATE TABLE
reference page surprised me. I have committed that separately (without
the column support, of course). So you should rebase your patch on top
of that. Note that ALTER TABLE would now also need to be updated by
your patch.
- I recommend setting pg_constraint.confdelsetcols to null for the
default behavior of setting all columns, instead of an empty array the
way you have done it. I have noted the places in the code that need to
be changed for that.
- The outfuncs.c support shouldn't be included in the final patch.
There is nothing wrong it, but I don't think it should be part of this
patch to add piecemeal support like that. I have included a few changes
there anyway for completeness.
- In gram.y, I moved the error check around to avoid duplication.
- In ri_triggers.c, I follow your renaming of the constants, but
RI_PLAN_ONTRIGGER_RESTRICT seems a little weird. Maybe do _ONBOTH_, or
else reverse the order, like RI_PLAN_SETNULL_ONDELETE, which would then
allow RI_PLAN_RESTRICT.
Please look through this and provide an updated patch, and then it
should be good to go.From cacfc7737bc62e28b8ada7bd6230034050e76946 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <pe...@eisentraut.org>
Date: Thu, 11 Nov 2021 08:06:27 +0100
Subject: [PATCH 1/2] Fix whitespace
---
src/backend/commands/tablecmds.c | 4 +-
src/backend/parser/gram.y | 86 ++++++++++++++++----------------
2 files changed, 45 insertions(+), 45 deletions(-)
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 38b49694b3..3ef5d6d285 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -9403,8 +9403,8 @@ void validateFkOnDeleteSetColumns(
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)));
+
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
+ errmsg("column \"%s\" referenced in ON
DELETE SET action must be part of foreign key", col)));
}
}
}
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index b39c15cfeb..7ee0414e0b 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -4011,39 +4011,39 @@ OptWhereClause:
key_actions:
key_update
- {
+ {
KeyActions *n = (KeyActions *)
palloc(sizeof(KeyActions));
- n->updateAction = $1;
- n->deleteAction = (KeyAction *) palloc(sizeof(KeyAction));
- n->deleteAction->action = FKCONSTR_ACTION_NOACTION;
- n->deleteAction->cols = NIL;
+ n->updateAction = $1;
+ n->deleteAction = (KeyAction *)
palloc(sizeof(KeyAction));
+ n->deleteAction->action =
FKCONSTR_ACTION_NOACTION;
+ n->deleteAction->cols = NIL;
$$ = n;
- }
+ }
| key_delete
- {
+ {
KeyActions *n = (KeyActions *)
palloc(sizeof(KeyActions));
- n->updateAction = (KeyAction *) palloc(sizeof(KeyAction));
- n->updateAction->action = FKCONSTR_ACTION_NOACTION;
- n->updateAction->cols = NIL;
- n->deleteAction = $1;
+ n->updateAction = (KeyAction *)
palloc(sizeof(KeyAction));
+ n->updateAction->action =
FKCONSTR_ACTION_NOACTION;
+ n->updateAction->cols = NIL;
+ n->deleteAction = $1;
$$ = n;
- }
+ }
| key_update key_delete
- {
+ {
KeyActions *n = (KeyActions *)
palloc(sizeof(KeyActions));
- n->updateAction = $1;
- n->deleteAction = $2;
+ n->updateAction = $1;
+ n->deleteAction = $2;
$$ = n;
- }
+ }
| key_delete key_update
- {
+ {
KeyActions *n = (KeyActions *)
palloc(sizeof(KeyActions));
- n->updateAction = $2;
- n->deleteAction = $1;
+ n->updateAction = $2;
+ n->deleteAction = $1;
$$ = n;
- }
- | /*EMPTY*/
- {
+ }
+ | /*EMPTY*/
+ {
KeyActions *n = (KeyActions *)
palloc(sizeof(KeyActions));
n->updateAction = (KeyAction *)
palloc(sizeof(KeyAction));
n->updateAction->action =
FKCONSTR_ACTION_NOACTION;
@@ -4052,7 +4052,7 @@ key_actions:
n->deleteAction->action =
FKCONSTR_ACTION_NOACTION;
n->deleteAction->cols = NIL;
$$ = n;
- }
+ }
;
key_update: ON UPDATE key_action { $$ = $3; }
@@ -4065,38 +4065,38 @@ key_action:
NO ACTION
{
KeyAction *n = (KeyAction *)
palloc(sizeof(KeyAction));
- n->action = FKCONSTR_ACTION_NOACTION;
- n->cols = NIL;
- $$ = n;
- }
+ n->action = FKCONSTR_ACTION_NOACTION;
+ n->cols = NIL;
+ $$ = n;
+ }
| RESTRICT
{
KeyAction *n = (KeyAction *)
palloc(sizeof(KeyAction));
- n->action = FKCONSTR_ACTION_RESTRICT;
- n->cols = NIL;
- $$ = n;
- }
+ n->action = FKCONSTR_ACTION_RESTRICT;
+ n->cols = NIL;
+ $$ = n;
+ }
| CASCADE
{
KeyAction *n = (KeyAction *)
palloc(sizeof(KeyAction));
- n->action = FKCONSTR_ACTION_CASCADE;
- n->cols = NIL;
- $$ = n;
- }
+ n->action = FKCONSTR_ACTION_CASCADE;
+ n->cols = NIL;
+ $$ = n;
+ }
| SET NULL_P opt_column_list
{
KeyAction *n = (KeyAction *)
palloc(sizeof(KeyAction));
- n->action = FKCONSTR_ACTION_SETNULL;
- n->cols = $3;
- $$ = n;
- }
+ n->action = FKCONSTR_ACTION_SETNULL;
+ n->cols = $3;
+ $$ = n;
+ }
| SET DEFAULT opt_column_list
{
KeyAction *n = (KeyAction *)
palloc(sizeof(KeyAction));
- n->action = FKCONSTR_ACTION_SETDEFAULT;
- n->cols = $3;
- $$ = n;
- }
+ n->action = FKCONSTR_ACTION_SETDEFAULT;
+ n->cols = $3;
+ $$ = n;
+ }
;
OptInherit: INHERITS '(' qualified_name_list ')' { $$ = $3; }
--
2.33.1
From 98a3fc16f49dea24d34d1af257c5017281bfe27a Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <pe...@eisentraut.org>
Date: Thu, 11 Nov 2021 11:07:02 +0100
Subject: [PATCH 2/2] Review changes
---
doc/src/sgml/ref/create_table.sgml | 6 +--
src/backend/catalog/pg_constraint.c | 10 +++--
src/backend/commands/tablecmds.c | 29 +++++++-----
src/backend/nodes/outfuncs.c | 12 +++--
src/backend/parser/gram.y | 54 ++++++++++++-----------
src/backend/utils/adt/ri_triggers.c | 32 ++++++++------
src/backend/utils/adt/ruleutils.c | 13 +++---
src/include/catalog/pg_constraint.h | 2 +-
src/include/nodes/parsenodes.h | 1 -
src/test/regress/expected/foreign_key.out | 2 +-
10 files changed, 90 insertions(+), 71 deletions(-)
diff --git a/doc/src/sgml/ref/create_table.sgml
b/doc/src/sgml/ref/create_table.sgml
index c6a9072ca0..eee837d86e 100644
--- a/doc/src/sgml/ref/create_table.sgml
+++ b/doc/src/sgml/ref/create_table.sgml
@@ -106,7 +106,7 @@
{ <replaceable class="parameter">column_name</replaceable> | ( <replaceable
class="parameter">expression</replaceable> ) } [ <replaceable
class="parameter">opclass</replaceable> ] [ ASC | DESC ] [ NULLS { FIRST | LAST
} ]
-<phrase><replaceable class="parameter">referential_action</replaceable> in an
<literal>EXCLUDE</literal> constraint is:</phrase>
+<phrase><replaceable class="parameter">referential_action</replaceable> in a
<literal>FOREIGN KEY</literal>/<literal>REFERENCES</literal> constraint
is:</phrase>
{ NO ACTION | RESTRICT | CASCADE | SET NULL [ ( <replaceable
class="parameter">column_name</replaceable> [, ... ] ) ] | SET DEFAULT [ (
<replaceable class="parameter">column_name</replaceable> [, ... ] ) ] }
@@ -1175,7 +1175,7 @@ <title>Parameters</title>
<para>
Set all of the referencing columns, or a specified subset of the
referencing columns, to null. A subset of columns can only be
- specified for <literal>ON DELETE</literal> triggers.
+ specified for <literal>ON DELETE</literal> actions.
</para>
</listitem>
</varlistentry>
@@ -1186,7 +1186,7 @@ <title>Parameters</title>
<para>
Set all of the referencing columns, or a specified subset of the
referencing columns, to their default values. A subset of columns
- can only be specified for <literal>ON DELETE</literal> triggers.
+ can only be specified for <literal>ON DELETE</literal> actions.
(There must be a row in the referenced table matching the default
values, if they are not null, or the operation will fail.)
</para>
diff --git a/src/backend/catalog/pg_constraint.c
b/src/backend/catalog/pg_constraint.c
index 00af9930f4..35496984b9 100644
--- a/src/backend/catalog/pg_constraint.c
+++ b/src/backend/catalog/pg_constraint.c
@@ -139,6 +139,7 @@ CreateConstraintEntry(const char *constraintName,
fkdatums[i] = ObjectIdGetDatum(ffEqOp[i]);
conffeqopArray = construct_array(fkdatums, foreignNKeys,
OIDOID, sizeof(Oid), true, TYPALIGN_INT);
+ // FIXME: use null instead of empty array for standard behavior
for (i = 0; i < numFkDeleteSetCols; i++)
fkdatums[i] = Int16GetDatum(fkDeleteSetCols[i]);
confdelsetcolsArray = construct_array(fkdatums,
numFkDeleteSetCols,
@@ -1170,8 +1171,9 @@ get_primary_key_attnos(Oid relid, bool deferrableOk, Oid
*constraintOid)
/*
* Extract data from the pg_constraint tuple of a foreign-key constraint.
*
- * All arguments save the first are output arguments; fields other than
- * numfks, conkey and confkey can be passed as NULL if caller doesn't need
them.
+ * All arguments save the first are output arguments. All output arguments
+ * other than numfks, conkey and confkey can be passed as NULL if caller
+ * doesn't need them.
*/
void
DeconstructFkConstraintRow(HeapTuple tuple, int *numfks,
@@ -1277,10 +1279,12 @@ DeconstructFkConstraintRow(HeapTuple tuple, int *numfks,
if (fk_del_set_cols)
{
int num_delete_cols = 0;
+
+ // FIXME: use null instead of empty array for standard behavior
adatum = SysCacheGetAttr(CONSTROID, tuple,
Anum_pg_constraint_confdelsetcols, &isNull);
if (isNull)
- elog(ERROR, "null confdelsetcols for foreign-key
constraint %u", constrId);
+ elog(ERROR, "null confdelsetcols for constraint %u",
constrId);
arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
if (ARR_NDIM(arr) != 0)
{
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 3ef5d6d285..d158fef975 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -484,8 +484,8 @@ static ObjectAddress addFkRecurseReferenced(List **wqueue,
Constraint *fkconstra
Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators,
int numfkdelsetcols, int16 *fkdelsetcols,
bool old_check_ok);
-static void validateFkOnDeleteSetColumns(int numfks, int16 *fkattnums,
- int
numfksetcols, int16 *fksetcolsattnums,
+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,
@@ -9385,22 +9385,27 @@ ATAddForeignKeyConstraint(List **wqueue,
AlteredTableInfo *tab, Relation rel,
* Verifies that columns used in ON DELETE SET NULL/DEFAULT (...)
* column lists are valid.
*/
-void validateFkOnDeleteSetColumns(
- int numfks, int16 *fkattnums,
- int numfksetcols, int16 *fksetcolsattnums,
- List *fksetcols)
+void
+validateFkOnDeleteSetColumns(int numfks, const int16 *fkattnums,
+ int numfksetcols,
const int16 *fksetcolsattnums,
+ List *fksetcols)
{
- for (int i = 0; i < numfksetcols; i++) {
- int setcol_attnum = fksetcolsattnums[i];
+ 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) {
+
+ for (int j = 0; j < numfks; j++)
+ {
+ if (fkattnums[j] == setcol_attnum)
+ {
seen = true;
break;
}
}
- if (!seen) {
+ if (!seen)
+ {
char *col = strVal(list_nth(fksetcols, i));
ereport(ERROR,
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
@@ -10871,7 +10876,7 @@ ATExecValidateConstraint(List **wqueue, Relation rel,
char *constrName,
/*
* transformColumnNameList - transform list of column names
*
- * Lookup each name and return its attnum and, if needed, type OID
+ * Lookup each name and return its attnum and, optionally, type OID
*/
static int
transformColumnNameList(Oid relId, List *colList,
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 7225434494..58bebbaa2d 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -2871,10 +2871,11 @@ _outPLAssignStmt(StringInfo str, const PLAssignStmt
*node)
WRITE_LOCATION_FIELD(location);
}
+#if 0
static void
_outAlterTableStmt(StringInfo str, const AlterTableStmt *node)
{
- WRITE_NODE_TYPE("ALTERTABLE");
+ WRITE_NODE_TYPE("ALTERTABLESTMT");
WRITE_NODE_FIELD(relation);
WRITE_NODE_FIELD(cmds);
@@ -2885,7 +2886,7 @@ _outAlterTableStmt(StringInfo str, const AlterTableStmt
*node)
static void
_outAlterTableCmd(StringInfo str, const AlterTableCmd *node)
{
- WRITE_NODE_TYPE("ALTERTABLE_CMD");
+ WRITE_NODE_TYPE("ALTERTABLECMD");
WRITE_ENUM_FIELD(subtype, AlterTableType);
WRITE_STRING_FIELD(name);
@@ -2899,12 +2900,13 @@ _outAlterTableCmd(StringInfo str, const AlterTableCmd
*node)
static void
_outRoleSpec(StringInfo str, const RoleSpec *node)
{
- WRITE_NODE_TYPE("ROLE_SPEC");
+ WRITE_NODE_TYPE("ROLESPEC");
WRITE_ENUM_FIELD(roletype, RoleSpecType);
WRITE_STRING_FIELD(rolename);
- WRITE_INT_FIELD(location);
+ WRITE_LOCATION_FIELD(location);
}
+#endif
static void
_outFuncCall(StringInfo str, const FuncCall *node)
@@ -4408,6 +4410,7 @@ outNode(StringInfo str, const void *obj)
case T_PLAssignStmt:
_outPLAssignStmt(str, obj);
break;
+#if 0
case T_AlterTableStmt:
_outAlterTableStmt(str, obj);
break;
@@ -4417,6 +4420,7 @@ outNode(StringInfo str, const void *obj)
case T_RoleSpec:
_outRoleSpec(str, obj);
break;
+#endif
case T_ColumnDef:
_outColumnDef(str, obj);
break;
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 7ee0414e0b..2a319eecda 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -3708,11 +3708,6 @@ ColConstraintElem:
n->pk_attrs = $3;
n->fk_matchtype = $4;
n->fk_upd_action =
($5)->updateAction->action;
- if (($5)->updateAction->cols != NIL)
- ereport(ERROR,
-
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("SET
NULL/DEFAULT <column_list> only supported for ON DELETE triggers"),
-
parser_errposition(@5)));
n->fk_del_action =
($5)->deleteAction->action;
n->fk_del_set_cols =
($5)->deleteAction->cols;
n->skip_validation = false;
@@ -3925,11 +3920,6 @@ ConstraintElem:
n->pk_attrs = $8;
n->fk_matchtype = $9;
n->fk_upd_action =
($10)->updateAction->action;
- if (($10)->updateAction->cols != NIL)
- ereport(ERROR,
-
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("SET
NULL/DEFAULT <column_list> only supported for ON DELETE triggers"),
-
parser_errposition(@10)));
n->fk_del_action =
($10)->deleteAction->action;
n->fk_del_set_cols =
($10)->deleteAction->cols;
processCASbits($11, @11, "FOREIGN KEY",
@@ -4012,17 +4002,17 @@ OptWhereClause:
key_actions:
key_update
{
- KeyActions *n = (KeyActions *)
palloc(sizeof(KeyActions));
+ KeyActions *n =
palloc(sizeof(KeyActions));
n->updateAction = $1;
- n->deleteAction = (KeyAction *)
palloc(sizeof(KeyAction));
+ n->deleteAction =
palloc(sizeof(KeyAction));
n->deleteAction->action =
FKCONSTR_ACTION_NOACTION;
n->deleteAction->cols = NIL;
$$ = n;
}
| key_delete
{
- KeyActions *n = (KeyActions *)
palloc(sizeof(KeyActions));
- n->updateAction = (KeyAction *)
palloc(sizeof(KeyAction));
+ KeyActions *n =
palloc(sizeof(KeyActions));
+ n->updateAction =
palloc(sizeof(KeyAction));
n->updateAction->action =
FKCONSTR_ACTION_NOACTION;
n->updateAction->cols = NIL;
n->deleteAction = $1;
@@ -4030,69 +4020,81 @@ key_actions:
}
| key_update key_delete
{
- KeyActions *n = (KeyActions *)
palloc(sizeof(KeyActions));
+ KeyActions *n =
palloc(sizeof(KeyActions));
n->updateAction = $1;
n->deleteAction = $2;
$$ = n;
}
| key_delete key_update
{
- KeyActions *n = (KeyActions *)
palloc(sizeof(KeyActions));
+ KeyActions *n =
palloc(sizeof(KeyActions));
n->updateAction = $2;
n->deleteAction = $1;
$$ = n;
}
| /*EMPTY*/
{
- KeyActions *n = (KeyActions *)
palloc(sizeof(KeyActions));
- n->updateAction = (KeyAction *)
palloc(sizeof(KeyAction));
+ KeyActions *n =
palloc(sizeof(KeyActions));
+ n->updateAction =
palloc(sizeof(KeyAction));
n->updateAction->action =
FKCONSTR_ACTION_NOACTION;
n->updateAction->cols = NIL;
- n->deleteAction = (KeyAction *)
palloc(sizeof(KeyAction));
+ n->deleteAction =
palloc(sizeof(KeyAction));
n->deleteAction->action =
FKCONSTR_ACTION_NOACTION;
n->deleteAction->cols = NIL;
$$ = n;
}
;
-key_update: ON UPDATE key_action { $$ = $3; }
+key_update: ON UPDATE key_action
+ {
+ if (($3)->cols)
+ ereport(ERROR,
+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("a
column list with %s is only supported for ON DELETE actions",
+
($3)->action == FKCONSTR_ACTION_SETNULL ? "SET NULL" : "SET DEFAULT"),
+
parser_errposition(@1)));
+ $$ = $3;
+ }
;
-key_delete: ON DELETE_P key_action { $$ = $3; }
+key_delete: ON DELETE_P key_action
+ {
+ $$ = $3;
+ }
;
key_action:
NO ACTION
{
- KeyAction *n = (KeyAction *)
palloc(sizeof(KeyAction));
+ KeyAction *n =
palloc(sizeof(KeyAction));
n->action = FKCONSTR_ACTION_NOACTION;
n->cols = NIL;
$$ = n;
}
| RESTRICT
{
- KeyAction *n = (KeyAction *)
palloc(sizeof(KeyAction));
+ KeyAction *n =
palloc(sizeof(KeyAction));
n->action = FKCONSTR_ACTION_RESTRICT;
n->cols = NIL;
$$ = n;
}
| CASCADE
{
- KeyAction *n = (KeyAction *)
palloc(sizeof(KeyAction));
+ KeyAction *n =
palloc(sizeof(KeyAction));
n->action = FKCONSTR_ACTION_CASCADE;
n->cols = NIL;
$$ = n;
}
| SET NULL_P opt_column_list
{
- KeyAction *n = (KeyAction *)
palloc(sizeof(KeyAction));
+ KeyAction *n =
palloc(sizeof(KeyAction));
n->action = FKCONSTR_ACTION_SETNULL;
n->cols = $3;
$$ = n;
}
| SET DEFAULT opt_column_list
{
- KeyAction *n = (KeyAction *)
palloc(sizeof(KeyAction));
+ KeyAction *n =
palloc(sizeof(KeyAction));
n->action = FKCONSTR_ACTION_SETDEFAULT;
n->cols = $3;
$$ = n;
diff --git a/src/backend/utils/adt/ri_triggers.c
b/src/backend/utils/adt/ri_triggers.c
index a088622b8b..dc53ce6cad 100644
--- a/src/backend/utils/adt/ri_triggers.c
+++ b/src/backend/utils/adt/ri_triggers.c
@@ -72,15 +72,15 @@
#define RI_PLAN_CHECK_LOOKUPPK 1
#define RI_PLAN_CHECK_LOOKUPPK_FROM_PK 2
#define RI_PLAN_LAST_ON_PK
RI_PLAN_CHECK_LOOKUPPK_FROM_PK
-/* these queries are executed against the FK (referencing) table. */
-#define RI_PLAN_ONDELETE_CASCADE 3
-#define RI_PLAN_ONUPDATE_CASCADE 4
+/* these queries are executed against the FK (referencing) table: */
+#define RI_PLAN_ONDELETE_CASCADE 3
+#define RI_PLAN_ONUPDATE_CASCADE 4
/* the same plan can be used for both ON DELETE and ON UPDATE triggers. */
-#define RI_PLAN_ONTRIGGER_RESTRICT 5
-#define RI_PLAN_ONDELETE_SETNULL 6
-#define RI_PLAN_ONUPDATE_SETNULL 7
-#define RI_PLAN_ONDELETE_SETDEFAULT 8
-#define RI_PLAN_ONUPDATE_SETDEFAULT 9
+#define RI_PLAN_ONTRIGGER_RESTRICT 5 // XXX confusing name
+#define RI_PLAN_ONDELETE_SETNULL 6
+#define RI_PLAN_ONUPDATE_SETNULL 7
+#define RI_PLAN_ONDELETE_SETDEFAULT 8
+#define RI_PLAN_ONUPDATE_SETDEFAULT 9
#define MAX_QUOTED_NAME_LEN (NAMEDATALEN*2+3)
#define MAX_QUOTED_REL_NAME_LEN (MAX_QUOTED_NAME_LEN*2)
@@ -1128,7 +1128,9 @@ ri_set(TriggerData *trigdata, bool is_set_null, int
tgkind)
appendStringInfo(&querybuf, "UPDATE %s%s SET",
fk_only, fkrelname);
- // Add assignment clauses
+ /*
+ * Add assignment clauses
+ */
querysep = "";
for (int i = 0; i < num_cols_to_set; i++)
{
@@ -1140,14 +1142,16 @@ ri_set(TriggerData *trigdata, bool is_set_null, int
tgkind)
querysep = ",";
}
- // Add WHERE clause
+ /*
+ * Add WHERE clause
+ */
qualsep = "WHERE";
for (int i = 0; i < riinfo->nkeys; i++)
{
- Oid pk_type = RIAttType(pk_rel,
riinfo->pk_attnums[i]);
- Oid fk_type = RIAttType(fk_rel,
riinfo->fk_attnums[i]);
- Oid pk_coll = RIAttCollation(pk_rel,
riinfo->pk_attnums[i]);
- Oid fk_coll = RIAttCollation(fk_rel,
riinfo->fk_attnums[i]);
+ Oid pk_type = RIAttType(pk_rel,
riinfo->pk_attnums[i]);
+ Oid fk_type = RIAttType(fk_rel,
riinfo->fk_attnums[i]);
+ Oid pk_coll =
RIAttCollation(pk_rel, riinfo->pk_attnums[i]);
+ Oid fk_coll =
RIAttCollation(fk_rel, riinfo->fk_attnums[i]);
quoteOneName(attname,
RIAttName(fk_rel,
riinfo->fk_attnums[i]));
diff --git a/src/backend/utils/adt/ruleutils.c
b/src/backend/utils/adt/ruleutils.c
index d5d5320c10..062a5b7051 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -2262,12 +2262,6 @@ pg_get_constraintdef_worker(Oid constraintId, bool
fullCommand,
if (string)
appendStringInfo(&buf, " ON UPDATE %s",
string);
- val = SysCacheGetAttr(CONSTROID, tup,
-
Anum_pg_constraint_confdelsetcols, &isnull);
- if (isnull)
- elog(ERROR, "null confdelsetcols for
foreign key constraint %u",
- constraintId);
-
switch (conForm->confdeltype)
{
case FKCONSTR_ACTION_NOACTION:
@@ -2295,6 +2289,13 @@ pg_get_constraintdef_worker(Oid constraintId, bool
fullCommand,
appendStringInfo(&buf, " ON DELETE %s",
string);
/* Add columns specified to SET NULL or SET
DEFAULT if provided. */
+ // FIXME: use null instead of empty array for
standard behavior
+ val = SysCacheGetAttr(CONSTROID, tup,
+
Anum_pg_constraint_confdelsetcols, &isnull);
+ if (isnull)
+ elog(ERROR, "null confdelsetcols for
constraint %u",
+ constraintId);
+
if (ARR_NDIM(DatumGetArrayTypeP(val)) > 0)
{
appendStringInfo(&buf, " (");
diff --git a/src/include/catalog/pg_constraint.h
b/src/include/catalog/pg_constraint.h
index 4e256d4d89..dd0d975468 100644
--- a/src/include/catalog/pg_constraint.h
+++ b/src/include/catalog/pg_constraint.h
@@ -142,7 +142,7 @@ CATALOG(pg_constraint,2606,ConstraintRelationId)
* If a foreign key with an ON DELETE SET NULL/DEFAULT action, the
subset
* of conkey to updated. If empty, all columns should be updated.
*/
- Oid confdelsetcols[1];
+ int16 confdelsetcols[1];
/*
* If an exclusion constraint, the OIDs of the exclusion operators for
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index b682e9abb1..4c5a8a39bf 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -2302,7 +2302,6 @@ typedef struct Constraint
char fk_upd_action; /* ON UPDATE action */
char fk_del_action; /* ON DELETE action */
List *fk_del_set_cols; /* ON DELETE SET NULL/DEFAULT (col1,
col2) */
-
List *old_conpfeqop; /* pg_constraint.conpfeqop of my former
self */
Oid old_pktable_oid; /*
pg_constraint.confrelid of my former
* self
*/
diff --git a/src/test/regress/expected/foreign_key.out
b/src/test/regress/expected/foreign_key.out
index a2680dbc9d..4c5274983d 100644
--- a/src/test/regress/expected/foreign_key.out
+++ b/src/test/regress/expected/foreign_key.out
@@ -764,7 +764,7 @@ ERROR: column "bar" referenced in foreign key constraint
does not exist
CREATE TABLE FKTABLE (tid int, id int, foo int, FOREIGN KEY (tid, id)
REFERENCES PKTABLE ON DELETE SET NULL (foo));
ERROR: column "foo" referenced in ON DELETE SET action must be part of
foreign key
CREATE TABLE FKTABLE (tid int, id int, foo int, FOREIGN KEY (tid, foo)
REFERENCES PKTABLE ON UPDATE SET NULL (foo));
-ERROR: SET NULL/DEFAULT <column_list> only supported for ON DELETE triggers
+ERROR: a column list with SET NULL is only supported for ON DELETE actions
LINE 1: ...oo int, FOREIGN KEY (tid, foo) REFERENCES PKTABLE ON UPDATE ...
^
CREATE TABLE FKTABLE (
--
2.33.1