diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2002-07-12 18:43:19 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2002-07-12 18:43:19 +0000 |
commit | 7c6df91dda27accab3097390ef0d21d93028c7a1 (patch) | |
tree | 5705b975e8de4edf82252e6df28e0bd57c83cb95 /src/backend/parser | |
parent | 791a40f943e2a9353c5823fb4f2bd446ec623d38 (diff) | |
download | postgresql-7c6df91dda27accab3097390ef0d21d93028c7a1.tar.gz postgresql-7c6df91dda27accab3097390ef0d21d93028c7a1.zip |
Second phase of committing Rod Taylor's pg_depend/pg_constraint patch.
pg_relcheck is gone; CHECK, UNIQUE, PRIMARY KEY, and FOREIGN KEY
constraints all have real live entries in pg_constraint. pg_depend
exists, and RESTRICT/CASCADE options work on most kinds of DROP;
however, pg_depend is not yet very well populated with dependencies.
(Most of the ones that are present at this point just replace formerly
hardwired associations, such as the implicit drop of a relation's pg_type
entry when the relation is dropped.) Need to add more logic to create
dependency entries, improve pg_dump to dump constraints in place of
indexes and triggers, and add some regression tests.
Diffstat (limited to 'src/backend/parser')
-rw-r--r-- | src/backend/parser/analyze.c | 232 | ||||
-rw-r--r-- | src/backend/parser/gram.y | 70 |
2 files changed, 66 insertions, 236 deletions
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c index b1b94dc6fda..2fbca505987 100644 --- a/src/backend/parser/analyze.c +++ b/src/backend/parser/analyze.c @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.237 2002/06/20 20:29:31 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.238 2002/07/12 18:43:17 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -47,7 +47,7 @@ /* State shared by transformCreateSchemaStmt and its subroutines */ typedef struct { - const char *stmtType; /* "CREATE TABLE" or "ALTER TABLE" */ + const char *stmtType; /* "CREATE SCHEMA" or "ALTER SCHEMA" */ char *schemaname; /* name of schema */ char *authid; /* owner of schema */ List *tables; /* CREATE TABLE items */ @@ -1066,6 +1066,7 @@ transformIndexConstraints(ParseState *pstate, CreateStmtContext *cxt) cxt->stmtType, (cxt->relation)->relname); cxt->pkey = index; } + index->isconstraint = true; if (constraint->name != NULL) index->idxname = pstrdup(constraint->name); @@ -1304,15 +1305,8 @@ transformIndexConstraints(ParseState *pstate, CreateStmtContext *cxt) static void transformFKConstraints(ParseState *pstate, CreateStmtContext *cxt) { - CreateTrigStmt *fk_trigger; List *fkactions = NIL; List *fkclist; - List *fk_attr; - List *pk_attr; - Ident *id; - Oid pktypoid[INDEX_MAX_KEYS]; - Oid fktypoid[INDEX_MAX_KEYS]; - int i; if (cxt->fkconstraints == NIL) return; @@ -1323,15 +1317,12 @@ transformFKConstraints(ParseState *pstate, CreateStmtContext *cxt) foreach(fkclist, cxt->fkconstraints) { FkConstraint *fkconstraint = (FkConstraint *) lfirst(fkclist); + Oid pktypoid[INDEX_MAX_KEYS]; + Oid fktypoid[INDEX_MAX_KEYS]; + int i; int attnum; List *fkattrs; - /* - * If the constraint has no name, set it to <unnamed> - */ - if (fkconstraint->constr_name == NULL) - fkconstraint->constr_name = "<unnamed>"; - for (attnum = 0; attnum < INDEX_MAX_KEYS; attnum++) pktypoid[attnum] = fktypoid[attnum] = InvalidOid; @@ -1473,203 +1464,24 @@ transformFKConstraints(ParseState *pstate, CreateStmtContext *cxt) } /* - * Build a CREATE CONSTRAINT TRIGGER statement for the CHECK - * action. + * For ALTER TABLE ADD CONSTRAINT, we're done. For CREATE TABLE, + * gin up an ALTER TABLE ADD CONSTRAINT command to execute after + * the basic CREATE TABLE is complete. */ - fk_trigger = (CreateTrigStmt *) makeNode(CreateTrigStmt); - fk_trigger->trigname = fkconstraint->constr_name; - fk_trigger->relation = cxt->relation; - fk_trigger->funcname = SystemFuncName("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->constrrel = fkconstraint->pktable; - - fk_trigger->args = NIL; - fk_trigger->args = lappend(fk_trigger->args, - makeString(fkconstraint->constr_name)); - fk_trigger->args = lappend(fk_trigger->args, - makeString((cxt->relation)->relname)); - fk_trigger->args = lappend(fk_trigger->args, - makeString(fkconstraint->pktable->relname)); - fk_trigger->args = lappend(fk_trigger->args, - makeString(fkconstraint->match_type)); - fk_attr = fkconstraint->fk_attrs; - pk_attr = fkconstraint->pk_attrs; - if (length(fk_attr) != length(pk_attr)) - elog(ERROR, "number of key attributes in referenced table must be equal to foreign key" - "\n\tIllegal FOREIGN KEY definition references \"%s\"", - fkconstraint->pktable->relname); - - while (fk_attr != NIL) + if (strcmp(cxt->stmtType, "CREATE TABLE") == 0) { - id = (Ident *) lfirst(fk_attr); - fk_trigger->args = lappend(fk_trigger->args, - makeString(id->name)); - - id = (Ident *) lfirst(pk_attr); - fk_trigger->args = lappend(fk_trigger->args, - makeString(id->name)); + AlterTableStmt *alterstmt = makeNode(AlterTableStmt); - fk_attr = lnext(fk_attr); - pk_attr = lnext(pk_attr); - } + alterstmt->subtype = 'c'; /* preprocessed add constraint */ + alterstmt->relation = cxt->relation; + alterstmt->name = NULL; + alterstmt->def = (Node *) makeList1(fkconstraint); - fkactions = lappend(fkactions, (Node *) fk_trigger); + /* Don't need to scan the table contents in this case */ + fkconstraint->skip_validation = true; - /* - * 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->relation = fkconstraint->pktable; - 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->constrrel = cxt->relation; - switch ((fkconstraint->actions & FKCONSTR_ON_DELETE_MASK) - >> FKCONSTR_ON_DELETE_SHIFT) - { - case FKCONSTR_ON_KEY_NOACTION: - fk_trigger->funcname = SystemFuncName("RI_FKey_noaction_del"); - break; - case FKCONSTR_ON_KEY_RESTRICT: - fk_trigger->deferrable = false; - fk_trigger->initdeferred = false; - fk_trigger->funcname = SystemFuncName("RI_FKey_restrict_del"); - break; - case FKCONSTR_ON_KEY_CASCADE: - fk_trigger->funcname = SystemFuncName("RI_FKey_cascade_del"); - break; - case FKCONSTR_ON_KEY_SETNULL: - fk_trigger->funcname = SystemFuncName("RI_FKey_setnull_del"); - break; - case FKCONSTR_ON_KEY_SETDEFAULT: - fk_trigger->funcname = SystemFuncName("RI_FKey_setdefault_del"); - break; - default: - elog(ERROR, "Only one ON DELETE action can be specified for FOREIGN KEY constraint"); - break; + fkactions = lappend(fkactions, (Node *) alterstmt); } - - fk_trigger->args = NIL; - fk_trigger->args = lappend(fk_trigger->args, - makeString(fkconstraint->constr_name)); - fk_trigger->args = lappend(fk_trigger->args, - makeString((cxt->relation)->relname)); - fk_trigger->args = lappend(fk_trigger->args, - makeString(fkconstraint->pktable->relname)); - fk_trigger->args = lappend(fk_trigger->args, - makeString(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, - makeString(id->name)); - - id = (Ident *) lfirst(pk_attr); - fk_trigger->args = lappend(fk_trigger->args, - makeString(id->name)); - - fk_attr = lnext(fk_attr); - pk_attr = lnext(pk_attr); - } - - fkactions = lappend(fkactions, (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->relation = fkconstraint->pktable; - 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->constrrel = cxt->relation; - switch ((fkconstraint->actions & FKCONSTR_ON_UPDATE_MASK) - >> FKCONSTR_ON_UPDATE_SHIFT) - { - case FKCONSTR_ON_KEY_NOACTION: - fk_trigger->funcname = SystemFuncName("RI_FKey_noaction_upd"); - break; - case FKCONSTR_ON_KEY_RESTRICT: - fk_trigger->deferrable = false; - fk_trigger->initdeferred = false; - fk_trigger->funcname = SystemFuncName("RI_FKey_restrict_upd"); - break; - case FKCONSTR_ON_KEY_CASCADE: - fk_trigger->funcname = SystemFuncName("RI_FKey_cascade_upd"); - break; - case FKCONSTR_ON_KEY_SETNULL: - fk_trigger->funcname = SystemFuncName("RI_FKey_setnull_upd"); - break; - case FKCONSTR_ON_KEY_SETDEFAULT: - fk_trigger->funcname = SystemFuncName("RI_FKey_setdefault_upd"); - break; - default: - elog(ERROR, "Only one ON UPDATE action can be specified for FOREIGN KEY constraint"); - break; - } - - fk_trigger->args = NIL; - fk_trigger->args = lappend(fk_trigger->args, - makeString(fkconstraint->constr_name)); - fk_trigger->args = lappend(fk_trigger->args, - makeString((cxt->relation)->relname)); - fk_trigger->args = lappend(fk_trigger->args, - makeString(fkconstraint->pktable->relname)); - fk_trigger->args = lappend(fk_trigger->args, - makeString(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, - makeString(id->name)); - - id = (Ident *) lfirst(pk_attr); - fk_trigger->args = lappend(fk_trigger->args, - makeString(id->name)); - - fk_attr = lnext(fk_attr); - pk_attr = lnext(pk_attr); - } - - fkactions = lappend(fkactions, (Node *) fk_trigger); } /* @@ -2642,6 +2454,14 @@ transformAlterTableStmt(ParseState *pstate, AlterTableStmt *stmt, *extras_after = nconc(cxt.alist, *extras_after); break; + case 'c': + /* + * Already-transformed ADD CONSTRAINT, so just make it look + * like the standard case. + */ + stmt->subtype = 'C'; + break; + default: break; } diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 18b349c4ee2..17128a814e5 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -11,7 +11,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.338 2002/07/11 07:39:25 ishii Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.339 2002/07/12 18:43:17 tgl Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -309,8 +309,7 @@ static void doNegateFloat(Value *v); %type <node> TableConstraint, TableLikeClause %type <list> ColQualList %type <node> ColConstraint, ColConstraintElem, ConstraintAttr -%type <ival> key_actions, key_delete, key_update, key_reference -%type <str> key_match +%type <ival> key_actions, key_delete, key_match, key_update, key_action %type <ival> ConstraintAttributeSpec, ConstraintDeferrabilitySpec, ConstraintTimeSpec @@ -1594,8 +1593,9 @@ ColConstraintElem: n->pktable = $2; n->fk_attrs = NIL; n->pk_attrs = $3; - n->match_type = $4; - n->actions = $5; + n->fk_matchtype = $4; + n->fk_upd_action = (char) ($5 >> 8); + n->fk_del_action = (char) ($5 & 0xFF); n->deferrable = FALSE; n->initdeferred = FALSE; $$ = (Node *)n; @@ -1714,16 +1714,16 @@ ConstraintElem: $$ = (Node *)n; } | FOREIGN KEY '(' columnList ')' REFERENCES qualified_name - opt_column_list - key_match key_actions ConstraintAttributeSpec + opt_column_list key_match key_actions ConstraintAttributeSpec { FkConstraint *n = makeNode(FkConstraint); n->constr_name = NULL; n->pktable = $7; n->fk_attrs = $4; n->pk_attrs = $8; - n->match_type = $9; - n->actions = $10; + n->fk_matchtype = $9; + n->fk_upd_action = (char) ($10 >> 8); + n->fk_del_action = (char) ($10 & 0xFF); n->deferrable = ($11 & 1) != 0; n->initdeferred = ($11 & 2) != 0; $$ = (Node *)n; @@ -1750,45 +1750,54 @@ columnElem: ColId key_match: MATCH FULL { - $$ = "FULL"; + $$ = FKCONSTR_MATCH_FULL; } | MATCH PARTIAL { elog(ERROR, "FOREIGN KEY/MATCH PARTIAL not yet implemented"); - $$ = "PARTIAL"; + $$ = FKCONSTR_MATCH_PARTIAL; } | MATCH SIMPLE { - $$ = "UNSPECIFIED"; + $$ = FKCONSTR_MATCH_UNSPECIFIED; } | /*EMPTY*/ { - $$ = "UNSPECIFIED"; + $$ = FKCONSTR_MATCH_UNSPECIFIED; } ; +/* + * We combine the update and delete actions into one value temporarily + * for simplicity of parsing, and then break them down again in the + * calling production. update is in the left 8 bits, delete in the right. + * Note that NOACTION is the default. + */ key_actions: - key_delete { $$ = $1; } - | key_update { $$ = $1; } - | key_delete key_update { $$ = $1 | $2; } - | key_update key_delete { $$ = $1 | $2; } - | /*EMPTY*/ { $$ = 0; } + key_update + { $$ = ($1 << 8) | (FKCONSTR_ACTION_NOACTION & 0xFF); } + | key_delete + { $$ = (FKCONSTR_ACTION_NOACTION << 8) | ($1 & 0xFF); } + | key_update key_delete + { $$ = ($1 << 8) | ($2 & 0xFF); } + | key_delete key_update + { $$ = ($2 << 8) | ($1 & 0xFF); } + | /*EMPTY*/ + { $$ = (FKCONSTR_ACTION_NOACTION << 8) | (FKCONSTR_ACTION_NOACTION & 0xFF); } ; -key_delete: ON DELETE_P key_reference - { $$ = $3 << FKCONSTR_ON_DELETE_SHIFT; } +key_update: ON UPDATE key_action { $$ = $3; } ; -key_update: ON UPDATE key_reference - { $$ = $3 << FKCONSTR_ON_UPDATE_SHIFT; } +key_delete: ON DELETE_P key_action { $$ = $3; } ; -key_reference: - NO ACTION { $$ = FKCONSTR_ON_KEY_NOACTION; } - | RESTRICT { $$ = FKCONSTR_ON_KEY_RESTRICT; } - | CASCADE { $$ = FKCONSTR_ON_KEY_CASCADE; } - | SET NULL_P { $$ = FKCONSTR_ON_KEY_SETNULL; } - | SET DEFAULT { $$ = FKCONSTR_ON_KEY_SETDEFAULT; } +key_action: + NO ACTION { $$ = FKCONSTR_ACTION_NOACTION; } + | RESTRICT { $$ = FKCONSTR_ACTION_RESTRICT; } + | CASCADE { $$ = FKCONSTR_ACTION_CASCADE; } + | SET NULL_P { $$ = FKCONSTR_ACTION_SETNULL; } + | SET DEFAULT { $$ = FKCONSTR_ACTION_SETDEFAULT; } ; OptInherit: INHERITS '(' qualified_name_list ')' { $$ = $3; } @@ -2300,7 +2309,7 @@ drop_type: TABLE { $$ = DROP_TABLE; } | INDEX { $$ = DROP_INDEX; } | TYPE_P { $$ = DROP_TYPE; } | DOMAIN_P { $$ = DROP_DOMAIN; } - | CONVERSION_P { $$ = DROP_CONVERSION; } + | CONVERSION_P { $$ = DROP_CONVERSION; } ; any_name_list: @@ -6673,6 +6682,7 @@ unreserved_keyword: | COMMIT | COMMITTED | CONSTRAINTS + | CONVERSION_P | COPY | CREATEDB | CREATEUSER @@ -6857,6 +6867,7 @@ col_name_keyword: | SUBSTRING | TIME | TIMESTAMP + | TREAT | TRIM | VARCHAR ; @@ -6963,7 +6974,6 @@ reserved_keyword: | THEN | TO | TRAILING - | TREAT | TRUE_P | UNION | UNIQUE |