Commit ddd596d3 authored by Jan Wieck's avatar Jan Wieck

Added ALTER TABLE ... ADD CONSTRAINT (provided by Stephan Szabo).

Added constraint dumping capability to pg_dump (also from Stephan)

Fixed DROP TABLE -> RelationBuildTriggers: 2 record(s) not found for rel
error.

Fixed little error in gram.y I made the last days.

Jan
parent 74d53d78
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.67 2000/01/29 16:58:34 petere Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.68 2000/02/04 18:49:31 wieck Exp $
* *
* NOTES * NOTES
* The PortalExecutorHeapMemory crap needs to be eliminated * The PortalExecutorHeapMemory crap needs to be eliminated
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include "commands/rename.h" #include "commands/rename.h"
#include "executor/execdefs.h" #include "executor/execdefs.h"
#include "executor/executor.h" #include "executor/executor.h"
#include "executor/spi.h"
#include "catalog/heap.h" #include "catalog/heap.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "optimizer/prep.h" #include "optimizer/prep.h"
...@@ -41,7 +42,7 @@ ...@@ -41,7 +42,7 @@
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/syscache.h" #include "utils/syscache.h"
#include "utils/temprel.h" #include "utils/temprel.h"
#include "commands/trigger.h"
/* ---------------- /* ----------------
* PortalExecutorHeapMemory stuff * PortalExecutorHeapMemory stuff
...@@ -688,7 +689,95 @@ void ...@@ -688,7 +689,95 @@ void
AlterTableAddConstraint(const char *relationName, AlterTableAddConstraint(const char *relationName,
bool inh, Node *newConstraint) bool inh, Node *newConstraint)
{ {
if (newConstraint == NULL)
elog(ERROR, "ALTER TABLE / ADD CONSTRAINT passed invalid constraint.");
switch (nodeTag(newConstraint))
{
case T_Constraint:
elog(ERROR, "ALTER TABLE / ADD CONSTRAINT is not implemented"); elog(ERROR, "ALTER TABLE / ADD CONSTRAINT is not implemented");
case T_FkConstraint:
{
FkConstraint *fkconstraint=(FkConstraint *)newConstraint;
Relation rel, classrel;
HeapScanDesc scan;
HeapTuple tuple;
Trigger trig;
List *list;
int count;
/*
* Grab an exclusive lock on the pk table, so that someone
* doesn't delete rows out from under us.
*/
rel = heap_openr(fkconstraint->pktable_name, AccessExclusiveLock);
heap_close(rel, NoLock);
/*
* Grab an exclusive lock on the fk table, and then scan through
* each tuple, calling the RI_FKey_Match_Ins (insert trigger)
* as if that tuple had just been inserted. If any of those
* fail, it should elog(ERROR) and that's that.
*/
rel = heap_openr(relationName, AccessExclusiveLock);
trig.tgoid = 0;
trig.tgname = "<unknown>";
trig.tgfoid = 0;
trig.tgtype = 0;
trig.tgenabled = TRUE;
trig.tgisconstraint = TRUE;
trig.tginitdeferred = FALSE;
trig.tgdeferrable = FALSE;
trig.tgargs = (char **)palloc(
sizeof(char *) * (4 + length(fkconstraint->fk_attrs)
+ length(fkconstraint->pk_attrs)));
trig.tgargs[0] = "<unnamed>";
trig.tgargs[1] = (char *)relationName;
trig.tgargs[2] = fkconstraint->pktable_name;
trig.tgargs[3] = fkconstraint->match_type;
count = 4;
foreach (list, fkconstraint->fk_attrs)
{
Ident *fk_at = lfirst(list);
trig.tgargs[count++] = fk_at->name;
}
foreach (list, fkconstraint->pk_attrs)
{
Ident *pk_at = lfirst(list);
trig.tgargs[count++] = pk_at->name;
}
trig.tgnargs = count;
scan = heap_beginscan(rel, false, SnapshotNow, 0, NULL);
AssertState(scan!=NULL);
while (HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
{
TriggerData newtrigdata;
newtrigdata.tg_event = TRIGGER_EVENT_INSERT | TRIGGER_EVENT_ROW;
newtrigdata.tg_relation = rel;
newtrigdata.tg_trigtuple = tuple;
newtrigdata.tg_newtuple = NULL;
newtrigdata.tg_trigger = &trig;
CurrentTriggerData = &newtrigdata;
RI_FKey_check_ins(NULL);
/* Make a call to the check function */
}
heap_endscan(scan);
heap_close(rel, NoLock); /* close rel but keep lock! */
pfree(trig.tgargs);
}
break;
default:
elog(ERROR, "ALTER TABLE / ADD CONSTRAINT unable to determine type of constraint passed");
}
} }
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.56 2000/01/31 04:35:49 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.57 2000/02/04 18:49:31 wieck Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -399,6 +399,15 @@ RelationRemoveTriggers(Relation rel) ...@@ -399,6 +399,15 @@ RelationRemoveTriggers(Relation rel)
DropTrigger(&stmt); DropTrigger(&stmt);
/* ----------
* Need to do a command counter increment here to show up
* new pg_class.reltriggers in the next loop invocation already
* (there are multiple referential integrity action
* triggers for the same FK table defined on the PK table).
* ----------
*/
CommandCounterIncrement();
pfree(stmt.relname); pfree(stmt.relname);
pfree(stmt.trigname); pfree(stmt.trigname);
} }
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: analyze.c,v 1.134 2000/01/27 18:11:35 tgl Exp $ * $Id: analyze.c,v 1.135 2000/02/04 18:49:32 wieck Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -40,6 +40,7 @@ static Query *transformSelectStmt(ParseState *pstate, SelectStmt *stmt); ...@@ -40,6 +40,7 @@ static Query *transformSelectStmt(ParseState *pstate, SelectStmt *stmt);
static Query *transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt); static Query *transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt);
static Query *transformCursorStmt(ParseState *pstate, SelectStmt *stmt); static Query *transformCursorStmt(ParseState *pstate, SelectStmt *stmt);
static Query *transformCreateStmt(ParseState *pstate, CreateStmt *stmt); static Query *transformCreateStmt(ParseState *pstate, CreateStmt *stmt);
static Query *transformAlterTableStmt(ParseState *pstate, AlterTableStmt *stmt);
static void transformForUpdate(Query *qry, List *forUpdate); static void transformForUpdate(Query *qry, List *forUpdate);
static void transformFkeyGetPrimaryKey(FkConstraint *fkconstraint); static void transformFkeyGetPrimaryKey(FkConstraint *fkconstraint);
...@@ -181,13 +182,7 @@ transformStmt(ParseState *pstate, Node *parseTree) ...@@ -181,13 +182,7 @@ transformStmt(ParseState *pstate, Node *parseTree)
case T_AlterTableStmt: case T_AlterTableStmt:
{ {
AlterTableStmt *n = (AlterTableStmt *) parseTree; result = transformAlterTableStmt(pstate, (AlterTableStmt *) parseTree);
result = makeNode(Query);
result->commandType = CMD_UTILITY;
if (n->subtype == 'A') /* ADD COLUMN */
transformColumnType(pstate, (ColumnDef *) n->def);
result->utilityStmt = (Node *) parseTree;
} }
break; break;
...@@ -1459,6 +1454,254 @@ transformCursorStmt(ParseState *pstate, SelectStmt *stmt) ...@@ -1459,6 +1454,254 @@ transformCursorStmt(ParseState *pstate, SelectStmt *stmt)
return qry; return qry;
} }
/*
* tranformAlterTableStmt -
* transform an Alter Table Statement
*
*/
static Query *
transformAlterTableStmt(ParseState *pstate, AlterTableStmt *stmt)
{
Query *qry;
qry = makeNode(Query);
qry->commandType = CMD_UTILITY;
/*
* The only subtypes that currently have special handling are
* 'A'dd column and Add 'C'onstraint. In addition, right now
* only Foreign Key 'C'onstraints have a special transformation.
*
*/
switch (stmt->subtype) {
case 'A':
transformColumnType(pstate, (ColumnDef *) stmt->def);
break;
case 'C':
if (stmt->def && nodeTag(stmt->def) == T_FkConstraint )
{
CreateTrigStmt *fk_trigger;
List *fk_attr;
List *pk_attr;
Ident *id;
FkConstraint *fkconstraint;
extras_after = NIL;
elog(NOTICE, "ALTER TABLE ... ADD CONSTRAINT will create implicit trigger(s) for FOREIGN KEY check(s)");
fkconstraint = (FkConstraint *) stmt->def;
/*
* If the constraint has no name, set it to <unnamed>
*
*/
if (fkconstraint->constr_name == NULL)
fkconstraint->constr_name = "<unnamed>";
/*
* If the attribute list for the referenced table was
* omitted, lookup for the definition of the primary key
*
*/
if (fkconstraint->fk_attrs != NIL && fkconstraint->pk_attrs == NIL)
transformFkeyGetPrimaryKey(fkconstraint);
/*
* Build a CREATE CONSTRAINT TRIGGER statement for the CHECK
* action.
*
*/
fk_trigger = (CreateTrigStmt *)makeNode(CreateTrigStmt);
fk_trigger->trigname = fkconstraint->constr_name;
fk_trigger->relname = stmt->relname;
fk_trigger->funcname = "RI_FKey_check_ins";
fk_trigger->before = false;
fk_trigger->row = true;
fk_trigger->actions[0] = 'i';
fk_trigger->actions[1] = 'u';
fk_trigger->actions[2] = '\0';
fk_trigger->lang = NULL;
fk_trigger->text = NULL;
fk_trigger->attr = NIL;
fk_trigger->when = NULL;
fk_trigger->isconstraint = true;
fk_trigger->deferrable = fkconstraint->deferrable;
fk_trigger->initdeferred = fkconstraint->initdeferred;
fk_trigger->constrrelname = fkconstraint->pktable_name;
fk_trigger->args = NIL;
fk_trigger->args = lappend(fk_trigger->args,
fkconstraint->constr_name);
fk_trigger->args = lappend(fk_trigger->args,
stmt->relname);
fk_trigger->args = lappend(fk_trigger->args,
fkconstraint->pktable_name);
fk_trigger->args = lappend(fk_trigger->args,
fkconstraint->match_type);
fk_attr = fkconstraint->fk_attrs;
pk_attr = fkconstraint->pk_attrs;
if (length(fk_attr) != length(pk_attr))
{
elog(NOTICE, "Illegal FOREIGN KEY definition REFERENCES \"%s\"",
fkconstraint->pktable_name);
elog(ERROR, "number of key attributes in referenced table must be equal to foreign key");
}
while (fk_attr != NIL)
{
id = (Ident *)lfirst(fk_attr);
fk_trigger->args = lappend(fk_trigger->args, id->name);
id = (Ident *)lfirst(pk_attr);
fk_trigger->args = lappend(fk_trigger->args, id->name);
fk_attr = lnext(fk_attr);
pk_attr = lnext(pk_attr);
}
extras_after = lappend(extras_after, (Node *)fk_trigger);
/*
* Build a CREATE CONSTRAINT TRIGGER statement for the
* ON DELETE action fired on the PK table !!!
*
*/
fk_trigger = (CreateTrigStmt *)makeNode(CreateTrigStmt);
fk_trigger->trigname = fkconstraint->constr_name;
fk_trigger->relname = fkconstraint->pktable_name;
switch ((fkconstraint->actions & FKCONSTR_ON_DELETE_MASK)
>> FKCONSTR_ON_DELETE_SHIFT)
{
case FKCONSTR_ON_KEY_NOACTION:
fk_trigger->funcname = "RI_FKey_noaction_del";
break;
case FKCONSTR_ON_KEY_RESTRICT:
fk_trigger->funcname = "RI_FKey_restrict_del";
break;
case FKCONSTR_ON_KEY_CASCADE:
fk_trigger->funcname = "RI_FKey_cascade_del";
break;
case FKCONSTR_ON_KEY_SETNULL:
fk_trigger->funcname = "RI_FKey_setnull_del";
break;
case FKCONSTR_ON_KEY_SETDEFAULT:
fk_trigger->funcname = "RI_FKey_setdefault_del";
break;
default:
elog(ERROR, "Only one ON DELETE action can be specified for FOREIGN KEY constraint");
break;
}
fk_trigger->before = false;
fk_trigger->row = true;
fk_trigger->actions[0] = 'd';
fk_trigger->actions[1] = '\0';
fk_trigger->lang = NULL;
fk_trigger->text = NULL;
fk_trigger->attr = NIL;
fk_trigger->when = NULL;
fk_trigger->isconstraint = true;
fk_trigger->deferrable = fkconstraint->deferrable;
fk_trigger->initdeferred = fkconstraint->initdeferred;
fk_trigger->constrrelname = stmt->relname;
fk_trigger->args = NIL;
fk_trigger->args = lappend(fk_trigger->args,
fkconstraint->constr_name);
fk_trigger->args = lappend(fk_trigger->args,
stmt->relname);
fk_trigger->args = lappend(fk_trigger->args,
fkconstraint->pktable_name);
fk_trigger->args = lappend(fk_trigger->args,
fkconstraint->match_type);
fk_attr = fkconstraint->fk_attrs;
pk_attr = fkconstraint->pk_attrs;
while (fk_attr != NIL)
{
id = (Ident *)lfirst(fk_attr);
fk_trigger->args = lappend(fk_trigger->args, id->name);
id = (Ident *)lfirst(pk_attr);
fk_trigger->args = lappend(fk_trigger->args, id->name);
fk_attr = lnext(fk_attr);
pk_attr = lnext(pk_attr);
}
extras_after = lappend(extras_after, (Node *)fk_trigger);
/*
* Build a CREATE CONSTRAINT TRIGGER statement for the
* ON UPDATE action fired on the PK table !!!
*
*/
fk_trigger = (CreateTrigStmt *)makeNode(CreateTrigStmt);
fk_trigger->trigname = fkconstraint->constr_name;
fk_trigger->relname = fkconstraint->pktable_name;
switch ((fkconstraint->actions & FKCONSTR_ON_UPDATE_MASK)
>> FKCONSTR_ON_UPDATE_SHIFT)
{
case FKCONSTR_ON_KEY_NOACTION:
fk_trigger->funcname = "RI_FKey_noaction_upd";
break;
case FKCONSTR_ON_KEY_RESTRICT:
fk_trigger->funcname = "RI_FKey_restrict_upd";
break;
case FKCONSTR_ON_KEY_CASCADE:
fk_trigger->funcname = "RI_FKey_cascade_upd";
break;
case FKCONSTR_ON_KEY_SETNULL:
fk_trigger->funcname = "RI_FKey_setnull_upd";
break;
case FKCONSTR_ON_KEY_SETDEFAULT:
fk_trigger->funcname = "RI_FKey_setdefault_upd";
break;
default:
elog(ERROR, "Only one ON UPDATE action can be specified for FOREIGN KEY constraint");
break;
}
fk_trigger->before = false;
fk_trigger->row = true;
fk_trigger->actions[0] = 'u';
fk_trigger->actions[1] = '\0';
fk_trigger->lang = NULL;
fk_trigger->text = NULL;
fk_trigger->attr = NIL;
fk_trigger->when = NULL;
fk_trigger->isconstraint = true;
fk_trigger->deferrable = fkconstraint->deferrable;
fk_trigger->initdeferred = fkconstraint->initdeferred;
fk_trigger->constrrelname = stmt->relname;
fk_trigger->args = NIL;
fk_trigger->args = lappend(fk_trigger->args,
fkconstraint->constr_name);
fk_trigger->args = lappend(fk_trigger->args,
stmt->relname);
fk_trigger->args = lappend(fk_trigger->args,
fkconstraint->pktable_name);
fk_trigger->args = lappend(fk_trigger->args,
fkconstraint->match_type);
fk_attr = fkconstraint->fk_attrs;
pk_attr = fkconstraint->pk_attrs;
while (fk_attr != NIL)
{
id = (Ident *)lfirst(fk_attr);
fk_trigger->args = lappend(fk_trigger->args, id->name);
id = (Ident *)lfirst(pk_attr);
fk_trigger->args = lappend(fk_trigger->args, id->name);
fk_attr = lnext(fk_attr);
pk_attr = lnext(pk_attr);
}
extras_after = lappend(extras_after, (Node *)fk_trigger);
}
break;
default:
break;
}
qry->utilityStmt = (Node *) stmt;
return qry;
}
/* This function steps through the tree /* This function steps through the tree
* built up by the select_w_o_sort rule * built up by the select_w_o_sort rule
* and builds a list of all SelectStmt Nodes found * and builds a list of all SelectStmt Nodes found
...@@ -1748,3 +1991,4 @@ transformColumnType(ParseState *pstate, ColumnDef *column) ...@@ -1748,3 +1991,4 @@ transformColumnType(ParseState *pstate, ColumnDef *column)
} }
} }
} }
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.138 2000/02/02 20:54:17 wieck Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.139 2000/02/04 18:49:33 wieck Exp $
* *
* HISTORY * HISTORY
* AUTHOR DATE MAJOR EVENT * AUTHOR DATE MAJOR EVENT
...@@ -1489,7 +1489,7 @@ CreateTrigStmt: CREATE TRIGGER name TriggerActionTime TriggerEvents ON ...@@ -1489,7 +1489,7 @@ CreateTrigStmt: CREATE TRIGGER name TriggerActionTime TriggerEvents ON
n->constrrelname = NULL; n->constrrelname = NULL;
$$ = (Node *)n; $$ = (Node *)n;
} }
| CREATE CONSTRAINT TRIGGER name AFTER TriggerOneEvent ON | CREATE CONSTRAINT TRIGGER name AFTER TriggerEvents ON
relation_name OptConstrFromTable relation_name OptConstrFromTable
ConstraintAttributeSpec ConstraintAttributeSpec
FOR EACH ROW EXECUTE PROCEDURE name '(' TriggerFuncArgs ')' FOR EACH ROW EXECUTE PROCEDURE name '(' TriggerFuncArgs ')'
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.142 2000/02/02 13:20:15 petere Exp $ * $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.143 2000/02/04 18:49:34 wieck Exp $
* *
* Modifications - 6/10/96 - dave@bensoft.com - version 1.13.dhb * Modifications - 6/10/96 - dave@bensoft.com - version 1.13.dhb
* *
...@@ -1699,7 +1699,11 @@ getTables(int *numTables, FuncInfo *finfo, int numFuncs) ...@@ -1699,7 +1699,11 @@ getTables(int *numTables, FuncInfo *finfo, int numFuncs)
i_tgfoid, i_tgfoid,
i_tgtype, i_tgtype,
i_tgnargs, i_tgnargs,
i_tgargs; i_tgargs,
i_tgisconstraint,
i_tgconstrname,
i_tgdeferrable,
i_tginitdeferred;
int ntups2; int ntups2;
int i2; int i2;
...@@ -1710,7 +1714,7 @@ getTables(int *numTables, FuncInfo *finfo, int numFuncs) ...@@ -1710,7 +1714,7 @@ getTables(int *numTables, FuncInfo *finfo, int numFuncs)
g_comment_end); g_comment_end);
resetPQExpBuffer(query); resetPQExpBuffer(query);
appendPQExpBuffer(query, "SELECT tgname, tgfoid, tgtype, tgnargs, tgargs, oid " appendPQExpBuffer(query, "SELECT tgname, tgfoid, tgtype, tgnargs, tgargs, tgisconstraint, tgconstrname, tgdeferrable, tginitdeferred, oid "
"from pg_trigger " "from pg_trigger "
"where tgrelid = '%s'::oid ", "where tgrelid = '%s'::oid ",
tblinfo[i].oid); tblinfo[i].oid);
...@@ -1734,34 +1738,79 @@ getTables(int *numTables, FuncInfo *finfo, int numFuncs) ...@@ -1734,34 +1738,79 @@ getTables(int *numTables, FuncInfo *finfo, int numFuncs)
i_tgnargs = PQfnumber(res2, "tgnargs"); i_tgnargs = PQfnumber(res2, "tgnargs");
i_tgargs = PQfnumber(res2, "tgargs"); i_tgargs = PQfnumber(res2, "tgargs");
i_tgoid = PQfnumber(res2, "oid"); i_tgoid = PQfnumber(res2, "oid");
i_tgisconstraint = PQfnumber(res2, "tgisconstraint");
i_tgconstrname = PQfnumber(res2, "tgconstrname");
i_tgdeferrable = PQfnumber(res2, "tgdeferrable");
i_tginitdeferred = PQfnumber(res2, "tginitdeferred");
tblinfo[i].triggers = (char **) malloc(ntups2 * sizeof(char *)); tblinfo[i].triggers = (char **) malloc(ntups2 * sizeof(char *));
tblinfo[i].trcomments = (char **) malloc(ntups2 * sizeof(char *)); tblinfo[i].trcomments = (char **) malloc(ntups2 * sizeof(char *));
tblinfo[i].troids = (char **) malloc(ntups2 * sizeof(char *)); tblinfo[i].troids = (char **) malloc(ntups2 * sizeof(char *));
resetPQExpBuffer(query); resetPQExpBuffer(query);
for (i2 = 0; i2 < ntups2; i2++) for (i2 = 0; i2 < ntups2; i2++)
{ {
const char *tgfunc = PQgetvalue(res2, i2, i_tgfoid); const char *tgfuncoid = PQgetvalue(res2, i2, i_tgfoid);
char *tgfunc = NULL;
int2 tgtype = atoi(PQgetvalue(res2, i2, i_tgtype)); int2 tgtype = atoi(PQgetvalue(res2, i2, i_tgtype));
int tgnargs = atoi(PQgetvalue(res2, i2, i_tgnargs)); int tgnargs = atoi(PQgetvalue(res2, i2, i_tgnargs));
const char *tgargs = PQgetvalue(res2, i2, i_tgargs); const char *tgargs = PQgetvalue(res2, i2, i_tgargs);
int tgisconstraint;
int tgdeferrable;
int tginitdeferred;
const char *p; const char *p;
int findx; int findx;
if (strcmp(PQgetvalue(res2, i2, i_tgisconstraint), "f") == 0)
tgisconstraint=0;
else
tgisconstraint=1;
if (strcmp(PQgetvalue(res2, i2, i_tgdeferrable), "f") == 0)
tgdeferrable=0;
else
tgdeferrable=1;
if (strcmp(PQgetvalue(res2, i2, i_tginitdeferred), "f") == 0)
tginitdeferred=0;
else
tginitdeferred=1;
for (findx = 0; findx < numFuncs; findx++) for (findx = 0; findx < numFuncs; findx++)
{ {
if (strcmp(finfo[findx].oid, tgfunc) == 0 && if (strcmp(finfo[findx].oid, tgfuncoid) == 0 &&
finfo[findx].nargs == 0 && finfo[findx].nargs == 0 &&
strcmp(finfo[findx].prorettype, "0") == 0) strcmp(finfo[findx].prorettype, "0") == 0)
break; break;
} }
if (findx == numFuncs) if (findx == numFuncs)
{ {
fprintf(stderr, "getTables(): relation '%s': cannot find function with oid %s for trigger %s\n", PGresult *r;
tblinfo[i].relname, tgfunc, PQgetvalue(res2, i2, i_tgname));
/*
* the funcname is an oid which we use to find the name of the
* pg_proc. We need to do this because getFuncs() only reads
* in the user-defined funcs not all the funcs. We might not
* find what we want by looking in FuncInfo*
*/
resetPQExpBuffer(query);
appendPQExpBuffer(query,
"SELECT proname from pg_proc "
"where pg_proc.oid = '%s'::oid",
tgfuncoid);
r = PQexec(g_conn, query->data);
if (!r || PQresultStatus(r) != PGRES_TUPLES_OK)
{
fprintf(stderr, "getTables(): SELECT (funcname) failed. Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
exit_nicely(g_conn); exit_nicely(g_conn);
} }
tgfunc = finfo[findx].proname; tgfunc = strdup(PQgetvalue(r, 0, PQfnumber(r, "proname")));
PQclear(r);
}
else {
tgfunc = strdup(finfo[findx].proname);
}
#if 0 #if 0
/* XXX - how to emit this DROP TRIGGER? */ /* XXX - how to emit this DROP TRIGGER? */
if (dropSchema) if (dropSchema)
...@@ -1777,8 +1826,15 @@ getTables(int *numTables, FuncInfo *finfo, int numFuncs) ...@@ -1777,8 +1826,15 @@ getTables(int *numTables, FuncInfo *finfo, int numFuncs)
#endif #endif
resetPQExpBuffer(query); resetPQExpBuffer(query);
if (tgisconstraint)
{
appendPQExpBuffer(query, "CREATE CONSTRAINT TRIGGER ");
appendPQExpBuffer(query, fmtId(PQgetvalue(res2, i2, i_tgconstrname), force_quotes));
}
else {
appendPQExpBuffer(query, "CREATE TRIGGER "); appendPQExpBuffer(query, "CREATE TRIGGER ");
appendPQExpBuffer(query, fmtId(PQgetvalue(res2, i2, i_tgname), force_quotes)); appendPQExpBuffer(query, fmtId(PQgetvalue(res2, i2, i_tgname), force_quotes));
}
appendPQExpBufferChar(query, ' '); appendPQExpBufferChar(query, ' ');
/* Trigger type */ /* Trigger type */
findx = 0; findx = 0;
...@@ -1806,8 +1862,27 @@ getTables(int *numTables, FuncInfo *finfo, int numFuncs) ...@@ -1806,8 +1862,27 @@ getTables(int *numTables, FuncInfo *finfo, int numFuncs)
else else
appendPQExpBuffer(query, " UPDATE"); appendPQExpBuffer(query, " UPDATE");
} }
appendPQExpBuffer(query, " ON %s FOR EACH ROW", appendPQExpBuffer(query, " ON %s ", fmtId(tblinfo[i].relname, force_quotes));
fmtId(tblinfo[i].relname, force_quotes));
if (tgisconstraint)
{
if (!tgdeferrable)
{
appendPQExpBuffer(query, " NOT");
}
appendPQExpBuffer(query, " DEFERRABLE INITIALLY ");
if (tginitdeferred)
{
appendPQExpBuffer(query, "DEFERRED");
}
else
{
appendPQExpBuffer(query, "IMMEDIATE");
}
}
appendPQExpBuffer(query, " FOR EACH ROW");
appendPQExpBuffer(query, " EXECUTE PROCEDURE %s (", appendPQExpBuffer(query, " EXECUTE PROCEDURE %s (",
fmtId(tgfunc, force_quotes)); fmtId(tgfunc, force_quotes));
for (findx = 0; findx < tgnargs; findx++) for (findx = 0; findx < tgnargs; findx++)
...@@ -1847,6 +1922,7 @@ getTables(int *numTables, FuncInfo *finfo, int numFuncs) ...@@ -1847,6 +1922,7 @@ getTables(int *numTables, FuncInfo *finfo, int numFuncs)
tgargs = p + 4; tgargs = p + 4;
} }
appendPQExpBuffer(query, ");\n"); appendPQExpBuffer(query, ");\n");
tblinfo[i].triggers[i2] = strdup(query->data); tblinfo[i].triggers[i2] = strdup(query->data);
/*** Initialize trcomments and troids ***/ /*** Initialize trcomments and troids ***/
...@@ -1859,6 +1935,10 @@ getTables(int *numTables, FuncInfo *finfo, int numFuncs) ...@@ -1859,6 +1935,10 @@ getTables(int *numTables, FuncInfo *finfo, int numFuncs)
tblinfo[i].trcomments[i2] = strdup(query->data); tblinfo[i].trcomments[i2] = strdup(query->data);
tblinfo[i].troids[i2] = strdup(PQgetvalue(res2, i2, i_tgoid)); tblinfo[i].troids[i2] = strdup(PQgetvalue(res2, i2, i_tgoid));
if (tgfunc)
{
free(tgfunc);
}
} }
PQclear(res2); PQclear(res2);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment