Remove ancient support for upgrading pre-7.3 foreign key constraints.

Before 7.3, foreign key constraints had no explicit catalog
representation, so that what pg_dump produced for them was (usually)
a set of three CREATE CONSTRAINT TRIGGER commands.  Commit a2899ebdc
and some follow-on fixes added an ugly hack in CreateTrigger() to
recognize that pattern and reconstruct the foreign key definition.
However, we've never had any test coverage for that code, so that it's
legitimate to wonder if it still works; and having to maintain it in
the face of upcoming trigger-related patches seems rather pointless.
Let's decree that its time has passed, and drop it.

This is part of a group of patches removing various server-side kluges
for transparently upgrading pre-8.0 dump files.  Since we've had few
complaints about dropping pg_dump's support for dumping from pre-8.0
servers (commit 64f3524e2), it seems okay to now remove these kluges.

Daniel Gustafsson

Discussion: https://postgr.es/m/805874E2-999C-4CDA-856F-1AFBD9DFE933@yesql.se
This commit is contained in:
Tom Lane 2020-03-05 15:25:45 -05:00
parent a77315fdf2
commit e58a599752
1 changed files with 0 additions and 304 deletions

View File

@ -80,7 +80,6 @@ static int MyTriggerDepth = 0;
exec_rt_fetch((relinfo)->ri_RangeTableIndex, estate)->extraUpdatedCols))
/* Local function prototypes */
static void ConvertTriggerToFK(CreateTrigStmt *stmt, Oid funcoid);
static void SetTriggerFlags(TriggerDesc *trigdesc, Trigger *trigger);
static bool GetTupleForTrigger(EState *estate,
EPQState *epqstate,
@ -153,10 +152,6 @@ static bool before_stmt_triggers_fired(Oid relid, CmdType cmdType);
* When called on partitioned tables, this function recurses to create the
* trigger on all the partitions, except if isInternal is true, in which
* case caller is expected to execute recursion on its own.
*
* Note: can return InvalidObjectAddress if we decided to not create a trigger
* at all, but a foreign-key constraint. This is a kluge for backwards
* compatibility.
*/
ObjectAddress
CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
@ -719,26 +714,6 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
NameListToString(stmt->funcname), "trigger")));
}
/*
* If the command is a user-entered CREATE CONSTRAINT TRIGGER command that
* references one of the built-in RI_FKey trigger functions, assume it is
* from a dump of a pre-7.3 foreign key constraint, and take steps to
* convert this legacy representation into a regular foreign key
* constraint. Ugly, but necessary for loading old dump files.
*/
if (stmt->isconstraint && !isInternal &&
list_length(stmt->args) >= 6 &&
(list_length(stmt->args) % 2) == 0 &&
RI_FKey_trigger_type(funcoid) != RI_TRIGGER_NONE)
{
/* Keep lock on target rel until end of xact */
table_close(rel, NoLock);
ConvertTriggerToFK(stmt, funcoid);
return InvalidObjectAddress;
}
/*
* If it's a user-entered CREATE CONSTRAINT TRIGGER command, make a
* corresponding pg_constraint entry.
@ -1206,285 +1181,6 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
}
/*
* Convert legacy (pre-7.3) CREATE CONSTRAINT TRIGGER commands into
* full-fledged foreign key constraints.
*
* The conversion is complex because a pre-7.3 foreign key involved three
* separate triggers, which were reported separately in dumps. While the
* single trigger on the referencing table adds no new information, we need
* to know the trigger functions of both of the triggers on the referenced
* table to build the constraint declaration. Also, due to lack of proper
* dependency checking pre-7.3, it is possible that the source database had
* an incomplete set of triggers resulting in an only partially enforced
* FK constraint. (This would happen if one of the tables had been dropped
* and re-created, but only if the DB had been affected by a 7.0 pg_dump bug
* that caused loss of tgconstrrelid information.) We choose to translate to
* an FK constraint only when we've seen all three triggers of a set. This is
* implemented by storing unmatched items in a list in TopMemoryContext.
* We match triggers together by comparing the trigger arguments (which
* include constraint name, table and column names, so should be good enough).
*/
typedef struct
{
List *args; /* list of (T_String) Values or NIL */
Oid funcoids[3]; /* OIDs of trigger functions */
/* The three function OIDs are stored in the order update, delete, child */
} OldTriggerInfo;
static void
ConvertTriggerToFK(CreateTrigStmt *stmt, Oid funcoid)
{
static List *info_list = NIL;
static const char *const funcdescr[3] = {
gettext_noop("Found referenced table's UPDATE trigger."),
gettext_noop("Found referenced table's DELETE trigger."),
gettext_noop("Found referencing table's trigger.")
};
char *constr_name;
char *fk_table_name;
char *pk_table_name;
char fk_matchtype = FKCONSTR_MATCH_SIMPLE;
List *fk_attrs = NIL;
List *pk_attrs = NIL;
StringInfoData buf;
int funcnum;
OldTriggerInfo *info = NULL;
ListCell *l;
int i;
/* Parse out the trigger arguments */
constr_name = strVal(linitial(stmt->args));
fk_table_name = strVal(lsecond(stmt->args));
pk_table_name = strVal(lthird(stmt->args));
i = 0;
foreach(l, stmt->args)
{
Value *arg = (Value *) lfirst(l);
i++;
if (i < 4) /* skip constraint and table names */
continue;
if (i == 4) /* handle match type */
{
if (strcmp(strVal(arg), "FULL") == 0)
fk_matchtype = FKCONSTR_MATCH_FULL;
else
fk_matchtype = FKCONSTR_MATCH_SIMPLE;
continue;
}
if (i % 2)
fk_attrs = lappend(fk_attrs, arg);
else
pk_attrs = lappend(pk_attrs, arg);
}
/* Prepare description of constraint for use in messages */
initStringInfo(&buf);
appendStringInfo(&buf, "FOREIGN KEY %s(",
quote_identifier(fk_table_name));
i = 0;
foreach(l, fk_attrs)
{
Value *arg = (Value *) lfirst(l);
if (i++ > 0)
appendStringInfoChar(&buf, ',');
appendStringInfoString(&buf, quote_identifier(strVal(arg)));
}
appendStringInfo(&buf, ") REFERENCES %s(",
quote_identifier(pk_table_name));
i = 0;
foreach(l, pk_attrs)
{
Value *arg = (Value *) lfirst(l);
if (i++ > 0)
appendStringInfoChar(&buf, ',');
appendStringInfoString(&buf, quote_identifier(strVal(arg)));
}
appendStringInfoChar(&buf, ')');
/* Identify class of trigger --- update, delete, or referencing-table */
switch (funcoid)
{
case F_RI_FKEY_CASCADE_UPD:
case F_RI_FKEY_RESTRICT_UPD:
case F_RI_FKEY_SETNULL_UPD:
case F_RI_FKEY_SETDEFAULT_UPD:
case F_RI_FKEY_NOACTION_UPD:
funcnum = 0;
break;
case F_RI_FKEY_CASCADE_DEL:
case F_RI_FKEY_RESTRICT_DEL:
case F_RI_FKEY_SETNULL_DEL:
case F_RI_FKEY_SETDEFAULT_DEL:
case F_RI_FKEY_NOACTION_DEL:
funcnum = 1;
break;
default:
funcnum = 2;
break;
}
/* See if we have a match to this trigger */
foreach(l, info_list)
{
info = (OldTriggerInfo *) lfirst(l);
if (info->funcoids[funcnum] == InvalidOid &&
equal(info->args, stmt->args))
{
info->funcoids[funcnum] = funcoid;
break;
}
}
if (l == NULL)
{
/* First trigger of set, so create a new list entry */
MemoryContext oldContext;
ereport(NOTICE,
(errmsg("ignoring incomplete trigger group for constraint \"%s\" %s",
constr_name, buf.data),
errdetail_internal("%s", _(funcdescr[funcnum]))));
oldContext = MemoryContextSwitchTo(TopMemoryContext);
info = (OldTriggerInfo *) palloc0(sizeof(OldTriggerInfo));
info->args = copyObject(stmt->args);
info->funcoids[funcnum] = funcoid;
info_list = lappend(info_list, info);
MemoryContextSwitchTo(oldContext);
}
else if (info->funcoids[0] == InvalidOid ||
info->funcoids[1] == InvalidOid ||
info->funcoids[2] == InvalidOid)
{
/* Second trigger of set */
ereport(NOTICE,
(errmsg("ignoring incomplete trigger group for constraint \"%s\" %s",
constr_name, buf.data),
errdetail_internal("%s", _(funcdescr[funcnum]))));
}
else
{
/* OK, we have a set, so make the FK constraint ALTER TABLE cmd */
AlterTableStmt *atstmt = makeNode(AlterTableStmt);
AlterTableCmd *atcmd = makeNode(AlterTableCmd);
Constraint *fkcon = makeNode(Constraint);
PlannedStmt *wrapper = makeNode(PlannedStmt);
ereport(NOTICE,
(errmsg("converting trigger group into constraint \"%s\" %s",
constr_name, buf.data),
errdetail_internal("%s", _(funcdescr[funcnum]))));
fkcon->contype = CONSTR_FOREIGN;
fkcon->location = -1;
if (funcnum == 2)
{
/* This trigger is on the FK table */
atstmt->relation = stmt->relation;
if (stmt->constrrel)
fkcon->pktable = stmt->constrrel;
else
{
/* Work around ancient pg_dump bug that omitted constrrel */
fkcon->pktable = makeRangeVar(NULL, pk_table_name, -1);
}
}
else
{
/* This trigger is on the PK table */
fkcon->pktable = stmt->relation;
if (stmt->constrrel)
atstmt->relation = stmt->constrrel;
else
{
/* Work around ancient pg_dump bug that omitted constrrel */
atstmt->relation = makeRangeVar(NULL, fk_table_name, -1);
}
}
atstmt->cmds = list_make1(atcmd);
atstmt->relkind = OBJECT_TABLE;
atcmd->subtype = AT_AddConstraint;
atcmd->def = (Node *) fkcon;
if (strcmp(constr_name, "<unnamed>") == 0)
fkcon->conname = NULL;
else
fkcon->conname = constr_name;
fkcon->fk_attrs = fk_attrs;
fkcon->pk_attrs = pk_attrs;
fkcon->fk_matchtype = fk_matchtype;
switch (info->funcoids[0])
{
case F_RI_FKEY_NOACTION_UPD:
fkcon->fk_upd_action = FKCONSTR_ACTION_NOACTION;
break;
case F_RI_FKEY_CASCADE_UPD:
fkcon->fk_upd_action = FKCONSTR_ACTION_CASCADE;
break;
case F_RI_FKEY_RESTRICT_UPD:
fkcon->fk_upd_action = FKCONSTR_ACTION_RESTRICT;
break;
case F_RI_FKEY_SETNULL_UPD:
fkcon->fk_upd_action = FKCONSTR_ACTION_SETNULL;
break;
case F_RI_FKEY_SETDEFAULT_UPD:
fkcon->fk_upd_action = FKCONSTR_ACTION_SETDEFAULT;
break;
default:
/* can't get here because of earlier checks */
elog(ERROR, "confused about RI update function");
}
switch (info->funcoids[1])
{
case F_RI_FKEY_NOACTION_DEL:
fkcon->fk_del_action = FKCONSTR_ACTION_NOACTION;
break;
case F_RI_FKEY_CASCADE_DEL:
fkcon->fk_del_action = FKCONSTR_ACTION_CASCADE;
break;
case F_RI_FKEY_RESTRICT_DEL:
fkcon->fk_del_action = FKCONSTR_ACTION_RESTRICT;
break;
case F_RI_FKEY_SETNULL_DEL:
fkcon->fk_del_action = FKCONSTR_ACTION_SETNULL;
break;
case F_RI_FKEY_SETDEFAULT_DEL:
fkcon->fk_del_action = FKCONSTR_ACTION_SETDEFAULT;
break;
default:
/* can't get here because of earlier checks */
elog(ERROR, "confused about RI delete function");
}
fkcon->deferrable = stmt->deferrable;
fkcon->initdeferred = stmt->initdeferred;
fkcon->skip_validation = false;
fkcon->initially_valid = true;
/* finally, wrap it in a dummy PlannedStmt */
wrapper->commandType = CMD_UTILITY;
wrapper->canSetTag = false;
wrapper->utilityStmt = (Node *) atstmt;
wrapper->stmt_location = -1;
wrapper->stmt_len = -1;
/* ... and execute it */
ProcessUtility(wrapper,
"(generated ALTER TABLE ADD FOREIGN KEY command)",
PROCESS_UTILITY_SUBCOMMAND, NULL, NULL,
None_Receiver, NULL);
/* Remove the matched item from the list */
info_list = list_delete_ptr(info_list, info);
pfree(info);
/* We leak the copied args ... not worth worrying about */
}
}
/*
* Guts of trigger deletion.
*/