diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c index 6e8b7223fe5..35b4bb35106 100644 --- a/src/backend/commands/trigger.c +++ b/src/backend/commands/trigger.c @@ -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, "") == 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. */