diff options
Diffstat (limited to 'src/backend/parser/analyze.c')
-rw-r--r-- | src/backend/parser/analyze.c | 260 |
1 files changed, 252 insertions, 8 deletions
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c index fd3dda8f17e..d44f0df091d 100644 --- a/src/backend/parser/analyze.c +++ b/src/backend/parser/analyze.c @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * 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); static Query *transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt); static Query *transformCursorStmt(ParseState *pstate, SelectStmt *stmt); static Query *transformCreateStmt(ParseState *pstate, CreateStmt *stmt); +static Query *transformAlterTableStmt(ParseState *pstate, AlterTableStmt *stmt); static void transformForUpdate(Query *qry, List *forUpdate); static void transformFkeyGetPrimaryKey(FkConstraint *fkconstraint); @@ -181,13 +182,7 @@ transformStmt(ParseState *pstate, Node *parseTree) case T_AlterTableStmt: { - AlterTableStmt *n = (AlterTableStmt *) parseTree; - - result = makeNode(Query); - result->commandType = CMD_UTILITY; - if (n->subtype == 'A') /* ADD COLUMN */ - transformColumnType(pstate, (ColumnDef *) n->def); - result->utilityStmt = (Node *) parseTree; + result = transformAlterTableStmt(pstate, (AlterTableStmt *) parseTree); } break; @@ -1459,6 +1454,254 @@ transformCursorStmt(ParseState *pstate, SelectStmt *stmt) 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 * built up by the select_w_o_sort rule * and builds a list of all SelectStmt Nodes found @@ -1748,3 +1991,4 @@ transformColumnType(ParseState *pstate, ColumnDef *column) } } } + |