From 5e0377ae7e8e1882ddfdc1a1a66984bab9889f54 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Sun, 4 Nov 2007 21:25:55 +0000 Subject: [PATCH] Minor improvements to code for converting legacy CREATE CONSTRAINT TRIGGER commands into proper foreign-key constraints. Believe the constraint name given in the trigger arguments in preference to the trigger name --- to judge from Olivier Prenant's example, pg_dump must at some time have used the autogenerated trigger name there, though AFAICT no current release branch tip does. Improve the emitted NOTICEs to provide more detail (PK table's name and column names). Handle the case where pg_dump forgot to provide the FROM table (a bug that never did get fixed in 7.0.x apparently). This commit doesn't do anything about the question of what to do with incomplete trigger groups. --- src/backend/commands/trigger.c | 117 +++++++++++++++++++++++++++++------------ 1 file changed, 82 insertions(+), 35 deletions(-) diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c index 98fbe4595e..8798992ecf 100644 --- a/src/backend/commands/trigger.c +++ b/src/backend/commands/trigger.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/trigger.c,v 1.220 2007/11/04 01:16:19 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/trigger.c,v 1.221 2007/11/04 21:25:55 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -218,7 +218,6 @@ CreateTrigger(CreateTrigStmt *stmt, Oid constraintOid) * constraint. Ugly, but necessary for loading old dump files. */ if (stmt->isconstraint && !OidIsValid(constraintOid) && - stmt->constrrel != NULL && list_length(stmt->args) >= 6 && (list_length(stmt->args) % 2) == 0 && RI_FKey_trigger_type(funcoid) != RI_TRIGGER_NONE) @@ -482,9 +481,69 @@ ConvertTriggerToFK(CreateTrigStmt *stmt, Oid funcoid) { static List *info_list = NIL; + char *constr_name; + char *fk_table_name; + char *pk_table_name; + char fk_matchtype = FKCONSTR_MATCH_UNSPECIFIED; + List *fk_attrs = NIL; + List *pk_attrs = NIL; + StringInfoData buf; bool isupd; 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_UNSPECIFIED; + 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) @@ -508,8 +567,8 @@ ConvertTriggerToFK(CreateTrigStmt *stmt, Oid funcoid) default: /* Ignore triggers on referencing table */ ereport(NOTICE, - (errmsg("ignoring incomplete foreign-key trigger group for constraint \"%s\" on table \"%s\"", - stmt->trigname, stmt->relation->relname))); + (errmsg("ignoring incomplete trigger group for constraint \"%s\" %s", + constr_name, buf.data))); return; } @@ -527,8 +586,8 @@ ConvertTriggerToFK(CreateTrigStmt *stmt, Oid funcoid) MemoryContext oldContext; ereport(NOTICE, - (errmsg("ignoring incomplete foreign-key trigger group for constraint \"%s\" on table \"%s\"", - stmt->trigname, stmt->constrrel->relname))); + (errmsg("ignoring incomplete trigger group for constraint \"%s\" %s", + constr_name, buf.data))); oldContext = MemoryContextSwitchTo(TopMemoryContext); info = (OldTriggerInfo *) palloc(sizeof(OldTriggerInfo)); info->args = copyObject(stmt->args); @@ -539,49 +598,36 @@ ConvertTriggerToFK(CreateTrigStmt *stmt, Oid funcoid) } else { - /* OK, we have a pair, so make the FK constraint */ + /* OK, we have a pair, so make the FK constraint ALTER TABLE cmd */ AlterTableStmt *atstmt = makeNode(AlterTableStmt); AlterTableCmd *atcmd = makeNode(AlterTableCmd); FkConstraint *fkcon = makeNode(FkConstraint); - int i; Oid updfunc, delfunc; ereport(NOTICE, - (errmsg("converting foreign-key trigger group into constraint \"%s\" on table \"%s\"", - stmt->trigname, stmt->constrrel->relname))); - atstmt->relation = stmt->constrrel; + (errmsg("converting trigger group into constraint \"%s\" %s", + constr_name, buf.data))); + + if (stmt->constrrel) + atstmt->relation = stmt->constrrel; + else + { + /* Work around ancient pg_dump bug that omitted constrrel */ + atstmt->relation = makeRangeVar(NULL, fk_table_name); + } atstmt->cmds = list_make1(atcmd); atstmt->relkind = OBJECT_TABLE; atcmd->subtype = AT_AddConstraint; atcmd->def = (Node *) fkcon; - if (strcmp(stmt->trigname, "") == 0) + if (strcmp(constr_name, "") == 0) fkcon->constr_name = NULL; else - fkcon->constr_name = stmt->trigname; + fkcon->constr_name = constr_name; fkcon->pktable = stmt->relation; - - i = 0; - foreach(l, stmt->args) - { - Value *arg = (Value *) lfirst(l); - - i++; - if (i < 4) /* ignore constraint and table names */ - continue; - if (i == 4) /* handle match type */ - { - if (strcmp(strVal(arg), "FULL") == 0) - fkcon->fk_matchtype = FKCONSTR_MATCH_FULL; - else - fkcon->fk_matchtype = FKCONSTR_MATCH_UNSPECIFIED; - continue; - } - if (i % 2) - fkcon->fk_attrs = lappend(fkcon->fk_attrs, arg); - else - fkcon->pk_attrs = lappend(fkcon->pk_attrs, arg); - } + fkcon->fk_attrs = fk_attrs; + fkcon->pk_attrs = pk_attrs; + fkcon->fk_matchtype = fk_matchtype; if (isupd) { @@ -638,6 +684,7 @@ ConvertTriggerToFK(CreateTrigStmt *stmt, Oid funcoid) fkcon->deferrable = stmt->deferrable; fkcon->initdeferred = stmt->initdeferred; + /* ... and execute it */ ProcessUtility((Node *) atstmt, NULL, NULL, false, None_Receiver, NULL); -- 2.11.0