Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 0da03f6

Browse files
pjungwirCommitfest Bot
authored and
Commitfest Bot
committed
Add CASCADE/SET NULL/SET DEFAULT for temporal foreign keys
Previously we raised an error for these options, because their implementations require FOR PORTION OF. Now that we have temporal UPDATE/DELETE, we can implement foreign keys that use it. Author: Paul Jungwirth
1 parent daee80e commit 0da03f6

File tree

7 files changed

+3178
-50
lines changed

7 files changed

+3178
-50
lines changed

doc/src/sgml/ref/create_table.sgml

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1299,7 +1299,9 @@ WITH ( MODULUS <replaceable class="parameter">numeric_literal</replaceable>, REM
12991299
</para>
13001300

13011301
<para>
1302-
In a temporal foreign key, this option is not supported.
1302+
In a temporal foreign key, the delete/update will use
1303+
<literal>FOR PORTION OF</literal> semantics to constrain the
1304+
effect to the bounds being deleted/updated in the referenced row.
13031305
</para>
13041306
</listitem>
13051307
</varlistentry>
@@ -1314,7 +1316,10 @@ WITH ( MODULUS <replaceable class="parameter">numeric_literal</replaceable>, REM
13141316
</para>
13151317

13161318
<para>
1317-
In a temporal foreign key, this option is not supported.
1319+
In a temporal foreign key, the change will use <literal>FOR PORTION
1320+
OF</literal> semantics to constrain the effect to the bounds being
1321+
deleted/updated in the referenced row. The column maked with
1322+
<literal>PERIOD</literal> will not be set to null.
13181323
</para>
13191324
</listitem>
13201325
</varlistentry>
@@ -1331,7 +1336,10 @@ WITH ( MODULUS <replaceable class="parameter">numeric_literal</replaceable>, REM
13311336
</para>
13321337

13331338
<para>
1334-
In a temporal foreign key, this option is not supported.
1339+
In a temporal foreign key, the change will use <literal>FOR PORTION
1340+
OF</literal> semantics to constrain the effect to the bounds being
1341+
deleted/updated in the referenced row. The column marked with
1342+
<literal>PERIOD</literal> with not be set to a default value.
13351343
</para>
13361344
</listitem>
13371345
</varlistentry>

src/backend/commands/tablecmds.c

Lines changed: 45 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -532,7 +532,7 @@ static ObjectAddress ATAddForeignKeyConstraint(List **wqueue, AlteredTableInfo *
532532
Relation rel, Constraint *fkconstraint,
533533
bool recurse, bool recursing,
534534
LOCKMODE lockmode);
535-
static void validateFkOnDeleteSetColumns(int numfks, const int16 *fkattnums,
535+
static void validateFkOnDeleteSetColumns(int numfks, const int16 *fkattnums, const int16 fkperiodattnum,
536536
int numfksetcols, const int16 *fksetcolsattnums,
537537
List *fksetcols);
538538
static ObjectAddress addFkConstraint(addFkConstraintSides fkside,
@@ -9870,6 +9870,7 @@ ATAddForeignKeyConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
98709870
int16 fkdelsetcols[INDEX_MAX_KEYS] = {0};
98719871
bool with_period;
98729872
bool pk_has_without_overlaps;
9873+
int16 fkperiodattnum = InvalidAttrNumber;
98739874
int i;
98749875
int numfks,
98759876
numpks,
@@ -9955,15 +9956,19 @@ ATAddForeignKeyConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
99559956
fkconstraint->fk_attrs,
99569957
fkattnum, fktypoid, fkcolloid);
99579958
with_period = fkconstraint->fk_with_period || fkconstraint->pk_with_period;
9958-
if (with_period && !fkconstraint->fk_with_period)
9959-
ereport(ERROR,
9960-
errcode(ERRCODE_INVALID_FOREIGN_KEY),
9961-
errmsg("foreign key uses PERIOD on the referenced table but not the referencing table"));
9959+
if (with_period)
9960+
{
9961+
if (!fkconstraint->fk_with_period)
9962+
ereport(ERROR,
9963+
(errcode(ERRCODE_INVALID_FOREIGN_KEY),
9964+
errmsg("foreign key uses PERIOD on the referenced table but not the referencing table")));
9965+
fkperiodattnum = fkattnum[numfks - 1];
9966+
}
99629967

99639968
numfkdelsetcols = transformColumnNameList(RelationGetRelid(rel),
99649969
fkconstraint->fk_del_set_cols,
99659970
fkdelsetcols, NULL, NULL);
9966-
validateFkOnDeleteSetColumns(numfks, fkattnum,
9971+
validateFkOnDeleteSetColumns(numfks, fkattnum, fkperiodattnum,
99679972
numfkdelsetcols, fkdelsetcols,
99689973
fkconstraint->fk_del_set_cols);
99699974

@@ -10064,19 +10069,13 @@ ATAddForeignKeyConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
1006410069
*/
1006510070
if (fkconstraint->fk_with_period)
1006610071
{
10067-
if (fkconstraint->fk_upd_action == FKCONSTR_ACTION_RESTRICT ||
10068-
fkconstraint->fk_upd_action == FKCONSTR_ACTION_CASCADE ||
10069-
fkconstraint->fk_upd_action == FKCONSTR_ACTION_SETNULL ||
10070-
fkconstraint->fk_upd_action == FKCONSTR_ACTION_SETDEFAULT)
10072+
if (fkconstraint->fk_upd_action == FKCONSTR_ACTION_RESTRICT)
1007110073
ereport(ERROR,
1007210074
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1007310075
errmsg("unsupported %s action for foreign key constraint using PERIOD",
1007410076
"ON UPDATE"));
1007510077

10076-
if (fkconstraint->fk_del_action == FKCONSTR_ACTION_RESTRICT ||
10077-
fkconstraint->fk_del_action == FKCONSTR_ACTION_CASCADE ||
10078-
fkconstraint->fk_del_action == FKCONSTR_ACTION_SETNULL ||
10079-
fkconstraint->fk_del_action == FKCONSTR_ACTION_SETDEFAULT)
10078+
if (fkconstraint->fk_del_action == FKCONSTR_ACTION_RESTRICT)
1008010079
ereport(ERROR,
1008110080
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1008210081
errmsg("unsupported %s action for foreign key constraint using PERIOD",
@@ -10431,6 +10430,7 @@ ATAddForeignKeyConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
1043110430
*/
1043210431
void
1043310432
validateFkOnDeleteSetColumns(int numfks, const int16 *fkattnums,
10433+
const int16 fkperiodattnum,
1043410434
int numfksetcols, const int16 *fksetcolsattnums,
1043510435
List *fksetcols)
1043610436
{
@@ -10441,6 +10441,13 @@ validateFkOnDeleteSetColumns(int numfks, const int16 *fkattnums,
1044110441

1044210442
for (int j = 0; j < numfks; j++)
1044310443
{
10444+
if (fkperiodattnum == setcol_attnum)
10445+
{
10446+
char *col = strVal(list_nth(fksetcols, i));
10447+
ereport(ERROR,
10448+
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
10449+
errmsg("column \"%s\" referenced in ON DELETE SET action cannot be PERIOD", col)));
10450+
}
1044410451
if (fkattnums[j] == setcol_attnum)
1044510452
{
1044610453
seen = true;
@@ -13192,17 +13199,26 @@ createForeignKeyActionTriggers(Relation rel, Oid refRelOid, Constraint *fkconstr
1319213199
case FKCONSTR_ACTION_CASCADE:
1319313200
fk_trigger->deferrable = false;
1319413201
fk_trigger->initdeferred = false;
13195-
fk_trigger->funcname = SystemFuncName("RI_FKey_cascade_del");
13202+
if (fkconstraint->fk_with_period)
13203+
fk_trigger->funcname = SystemFuncName("RI_FKey_period_cascade_del");
13204+
else
13205+
fk_trigger->funcname = SystemFuncName("RI_FKey_cascade_del");
1319613206
break;
1319713207
case FKCONSTR_ACTION_SETNULL:
1319813208
fk_trigger->deferrable = false;
1319913209
fk_trigger->initdeferred = false;
13200-
fk_trigger->funcname = SystemFuncName("RI_FKey_setnull_del");
13210+
if (fkconstraint->fk_with_period)
13211+
fk_trigger->funcname = SystemFuncName("RI_FKey_period_setnull_del");
13212+
else
13213+
fk_trigger->funcname = SystemFuncName("RI_FKey_setnull_del");
1320113214
break;
1320213215
case FKCONSTR_ACTION_SETDEFAULT:
1320313216
fk_trigger->deferrable = false;
1320413217
fk_trigger->initdeferred = false;
13205-
fk_trigger->funcname = SystemFuncName("RI_FKey_setdefault_del");
13218+
if (fkconstraint->fk_with_period)
13219+
fk_trigger->funcname = SystemFuncName("RI_FKey_period_setdefault_del");
13220+
else
13221+
fk_trigger->funcname = SystemFuncName("RI_FKey_setdefault_del");
1320613222
break;
1320713223
default:
1320813224
elog(ERROR, "unrecognized FK action type: %d",
@@ -13253,17 +13269,26 @@ createForeignKeyActionTriggers(Relation rel, Oid refRelOid, Constraint *fkconstr
1325313269
case FKCONSTR_ACTION_CASCADE:
1325413270
fk_trigger->deferrable = false;
1325513271
fk_trigger->initdeferred = false;
13256-
fk_trigger->funcname = SystemFuncName("RI_FKey_cascade_upd");
13272+
if (fkconstraint->fk_with_period)
13273+
fk_trigger->funcname = SystemFuncName("RI_FKey_period_cascade_upd");
13274+
else
13275+
fk_trigger->funcname = SystemFuncName("RI_FKey_cascade_upd");
1325713276
break;
1325813277
case FKCONSTR_ACTION_SETNULL:
1325913278
fk_trigger->deferrable = false;
1326013279
fk_trigger->initdeferred = false;
13261-
fk_trigger->funcname = SystemFuncName("RI_FKey_setnull_upd");
13280+
if (fkconstraint->fk_with_period)
13281+
fk_trigger->funcname = SystemFuncName("RI_FKey_period_setnull_upd");
13282+
else
13283+
fk_trigger->funcname = SystemFuncName("RI_FKey_setnull_upd");
1326213284
break;
1326313285
case FKCONSTR_ACTION_SETDEFAULT:
1326413286
fk_trigger->deferrable = false;
1326513287
fk_trigger->initdeferred = false;
13266-
fk_trigger->funcname = SystemFuncName("RI_FKey_setdefault_upd");
13288+
if (fkconstraint->fk_with_period)
13289+
fk_trigger->funcname = SystemFuncName("RI_FKey_period_setdefault_upd");
13290+
else
13291+
fk_trigger->funcname = SystemFuncName("RI_FKey_setdefault_upd");
1326713292
break;
1326813293
default:
1326913294
elog(ERROR, "unrecognized FK action type: %d",

0 commit comments

Comments
 (0)