diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index 588c26ad12..478583a742 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.355 2009/07/28 02:56:29 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.356 2009/07/30 02:45:36 tgl Exp $ * * * INTERFACE ROUTINES @@ -1870,11 +1870,11 @@ AddRelationNewConstraints(Relation rel, /* * Check name uniqueness, or generate a name if none was given. */ - if (cdef->name != NULL) + if (cdef->conname != NULL) { ListCell *cell2; - ccname = cdef->name; + ccname = cdef->conname; /* Check against other new constraints */ /* Needed because we don't do CommandCounterIncrement in loop */ foreach(cell2, checknames) diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 0d3e3bc167..53abfec697 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.293 2009/07/29 20:56:18 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.294 2009/07/30 02:45:36 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -154,7 +154,7 @@ typedef struct NewConstraint Oid refrelid; /* PK rel, if FOREIGN */ Oid refindid; /* OID of PK's index, if FOREIGN */ Oid conid; /* OID of pg_constraint entry, if FOREIGN */ - Node *qual; /* Check expr or FkConstraint struct */ + Node *qual; /* Check expr or CONSTR_FOREIGN Constraint */ List *qualstate; /* Execution state for CHECK */ } NewConstraint; @@ -247,10 +247,10 @@ static Oid transformFkeyCheckAttrs(Relation pkrel, int numattrs, int16 *attnums, Oid *opclasses); static void checkFkeyPermissions(Relation rel, int16 *attnums, int natts); -static void validateForeignKeyConstraint(FkConstraint *fkconstraint, +static void validateForeignKeyConstraint(Constraint *fkconstraint, Relation rel, Relation pkrel, Oid pkindOid, Oid constraintOid); -static void createForeignKeyTriggers(Relation rel, FkConstraint *fkconstraint, +static void createForeignKeyTriggers(Relation rel, Constraint *fkconstraint, Oid constraintOid, Oid indexOid); static void ATController(Relation rel, List *cmds, bool recurse); static void ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd, @@ -293,13 +293,13 @@ static void ATExecAddIndex(AlteredTableInfo *tab, Relation rel, IndexStmt *stmt, bool is_rebuild); static void ATExecAddConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, - Node *newConstraint, bool recurse); + Constraint *newConstraint, bool recurse); static void ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, Constraint *constr, bool recurse, bool recursing); static void ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel, - FkConstraint *fkconstraint); + Constraint *fkconstraint); static void ATExecDropConstraint(Relation rel, const char *constrName, DropBehavior behavior, bool recurse, bool recursing, @@ -2637,10 +2637,12 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel, ATExecAddIndex(tab, rel, (IndexStmt *) cmd->def, true); break; case AT_AddConstraint: /* ADD CONSTRAINT */ - ATExecAddConstraint(wqueue, tab, rel, cmd->def, false); + ATExecAddConstraint(wqueue, tab, rel, (Constraint *) cmd->def, + false); break; case AT_AddConstraintRecurse: /* ADD CONSTRAINT with recursion */ - ATExecAddConstraint(wqueue, tab, rel, cmd->def, true); + ATExecAddConstraint(wqueue, tab, rel, (Constraint *) cmd->def, + true); break; case AT_DropConstraint: /* DROP CONSTRAINT */ ATExecDropConstraint(rel, cmd->name, cmd->behavior, @@ -2905,7 +2907,7 @@ ATRewriteTables(List **wqueue) if (con->contype == CONSTR_FOREIGN) { - FkConstraint *fkconstraint = (FkConstraint *) con->qual; + Constraint *fkconstraint = (Constraint *) con->qual; Relation refrel; if (rel == NULL) @@ -4405,69 +4407,55 @@ ATExecAddIndex(AlteredTableInfo *tab, Relation rel, */ static void ATExecAddConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, - Node *newConstraint, bool recurse) + Constraint *newConstraint, bool recurse) { - switch (nodeTag(newConstraint)) + Assert(IsA(newConstraint, Constraint)); + + /* + * Currently, we only expect to see CONSTR_CHECK and CONSTR_FOREIGN nodes + * arriving here (see the preprocessing done in parse_utilcmd.c). Use a + * switch anyway to make it easier to add more code later. + */ + switch (newConstraint->contype) { - case T_Constraint: + case CONSTR_CHECK: + ATAddCheckConstraint(wqueue, tab, rel, + newConstraint, recurse, false); + break; + + case CONSTR_FOREIGN: + /* + * Note that we currently never recurse for FK constraints, so + * the "recurse" flag is silently ignored. + * + * Assign or validate constraint name + */ + if (newConstraint->conname) { - Constraint *constr = (Constraint *) newConstraint; - - /* - * Currently, we only expect to see CONSTR_CHECK nodes - * arriving here (see the preprocessing done in - * parse_utilcmd.c). Use a switch anyway to make it easier to - * add more code later. - */ - switch (constr->contype) - { - case CONSTR_CHECK: - ATAddCheckConstraint(wqueue, tab, rel, - constr, recurse, false); - break; - default: - elog(ERROR, "unrecognized constraint type: %d", - (int) constr->contype); - } - break; + if (ConstraintNameIsUsed(CONSTRAINT_RELATION, + RelationGetRelid(rel), + RelationGetNamespace(rel), + newConstraint->conname)) + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("constraint \"%s\" for relation \"%s\" already exists", + newConstraint->conname, + RelationGetRelationName(rel)))); } - case T_FkConstraint: - { - FkConstraint *fkconstraint = (FkConstraint *) newConstraint; + else + newConstraint->conname = + ChooseConstraintName(RelationGetRelationName(rel), + strVal(linitial(newConstraint->fk_attrs)), + "fkey", + RelationGetNamespace(rel), + NIL); - /* - * Note that we currently never recurse for FK constraints, so - * the "recurse" flag is silently ignored. - * - * Assign or validate constraint name - */ - if (fkconstraint->constr_name) - { - if (ConstraintNameIsUsed(CONSTRAINT_RELATION, - RelationGetRelid(rel), - RelationGetNamespace(rel), - fkconstraint->constr_name)) - ereport(ERROR, - (errcode(ERRCODE_DUPLICATE_OBJECT), - errmsg("constraint \"%s\" for relation \"%s\" already exists", - fkconstraint->constr_name, - RelationGetRelationName(rel)))); - } - else - fkconstraint->constr_name = - ChooseConstraintName(RelationGetRelationName(rel), - strVal(linitial(fkconstraint->fk_attrs)), - "fkey", - RelationGetNamespace(rel), - NIL); + ATAddForeignKeyConstraint(tab, rel, newConstraint); + break; - ATAddForeignKeyConstraint(tab, rel, fkconstraint); - - break; - } default: - elog(ERROR, "unrecognized node type: %d", - (int) nodeTag(newConstraint)); + elog(ERROR, "unrecognized constraint type: %d", + (int) newConstraint->contype); } } @@ -4526,12 +4514,12 @@ ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, tab->constraints = lappend(tab->constraints, newcon); /* Save the actually assigned name if it was defaulted */ - if (constr->name == NULL) - constr->name = ccon->name; + if (constr->conname == NULL) + constr->conname = ccon->name; } /* At this point we must have a locked-down name to use */ - Assert(constr->name != NULL); + Assert(constr->conname != NULL); /* Advance command counter in case same table is visited multiple times */ CommandCounterIncrement(); @@ -4583,7 +4571,7 @@ ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, */ static void ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel, - FkConstraint *fkconstraint) + Constraint *fkconstraint) { Relation pkrel; int16 pkattnum[INDEX_MAX_KEYS]; @@ -4798,7 +4786,7 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("foreign key constraint \"%s\" " "cannot be implemented", - fkconstraint->constr_name), + fkconstraint->conname), errdetail("Key columns \"%s\" and \"%s\" " "are of incompatible types: %s and %s.", strVal(list_nth(fkconstraint->fk_attrs, i)), @@ -4814,7 +4802,7 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel, /* * Record the FK constraint in pg_constraint. */ - constrOid = CreateConstraintEntry(fkconstraint->constr_name, + constrOid = CreateConstraintEntry(fkconstraint->conname, RelationGetNamespace(rel), CONSTRAINT_FOREIGN, fkconstraint->deferrable, @@ -4854,7 +4842,7 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel, NewConstraint *newcon; newcon = (NewConstraint *) palloc0(sizeof(NewConstraint)); - newcon->name = fkconstraint->constr_name; + newcon->name = fkconstraint->conname; newcon->contype = CONSTR_FOREIGN; newcon->refrelid = RelationGetRelid(pkrel); newcon->refindid = indexOid; @@ -5156,7 +5144,7 @@ checkFkeyPermissions(Relation rel, int16 *attnums, int natts) * Caller must have opened and locked both relations. */ static void -validateForeignKeyConstraint(FkConstraint *fkconstraint, +validateForeignKeyConstraint(Constraint *fkconstraint, Relation rel, Relation pkrel, Oid pkindOid, @@ -5171,7 +5159,7 @@ validateForeignKeyConstraint(FkConstraint *fkconstraint, */ MemSet(&trig, 0, sizeof(trig)); trig.tgoid = InvalidOid; - trig.tgname = fkconstraint->constr_name; + trig.tgname = fkconstraint->conname; trig.tgenabled = TRIGGER_FIRES_ON_ORIGIN; trig.tgisconstraint = TRUE; trig.tgconstrrelid = RelationGetRelid(pkrel); @@ -5228,13 +5216,13 @@ validateForeignKeyConstraint(FkConstraint *fkconstraint, } static void -CreateFKCheckTrigger(RangeVar *myRel, FkConstraint *fkconstraint, +CreateFKCheckTrigger(RangeVar *myRel, Constraint *fkconstraint, Oid constraintOid, Oid indexOid, bool on_insert) { CreateTrigStmt *fk_trigger; fk_trigger = makeNode(CreateTrigStmt); - fk_trigger->trigname = fkconstraint->constr_name; + fk_trigger->trigname = fkconstraint->conname; fk_trigger->relation = myRel; fk_trigger->before = false; fk_trigger->row = true; @@ -5268,7 +5256,7 @@ CreateFKCheckTrigger(RangeVar *myRel, FkConstraint *fkconstraint, * Create the triggers that implement an FK constraint. */ static void -createForeignKeyTriggers(Relation rel, FkConstraint *fkconstraint, +createForeignKeyTriggers(Relation rel, Constraint *fkconstraint, Oid constraintOid, Oid indexOid) { RangeVar *myRel; @@ -5296,7 +5284,7 @@ createForeignKeyTriggers(Relation rel, FkConstraint *fkconstraint, * DELETE action on the referenced table. */ fk_trigger = makeNode(CreateTrigStmt); - fk_trigger->trigname = fkconstraint->constr_name; + fk_trigger->trigname = fkconstraint->conname; fk_trigger->relation = fkconstraint->pktable; fk_trigger->before = false; fk_trigger->row = true; @@ -5348,7 +5336,7 @@ createForeignKeyTriggers(Relation rel, FkConstraint *fkconstraint, * UPDATE action on the referenced table. */ fk_trigger = makeNode(CreateTrigStmt); - fk_trigger->trigname = fkconstraint->constr_name; + fk_trigger->trigname = fkconstraint->conname; fk_trigger->relation = fkconstraint->pktable; fk_trigger->before = false; fk_trigger->row = true; diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c index b84731126a..7bc8212789 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.250 2009/07/29 20:56:18 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/trigger.c,v 1.251 2009/07/30 02:45:36 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -607,12 +607,14 @@ ConvertTriggerToFK(CreateTrigStmt *stmt, Oid funcoid) /* OK, we have a set, so make the FK constraint ALTER TABLE cmd */ AlterTableStmt *atstmt = makeNode(AlterTableStmt); AlterTableCmd *atcmd = makeNode(AlterTableCmd); - FkConstraint *fkcon = makeNode(FkConstraint); + Constraint *fkcon = makeNode(Constraint); ereport(NOTICE, (errmsg("converting trigger group into constraint \"%s\" %s", constr_name, buf.data), errdetail("%s", _(funcdescr[funcnum])))); + fkcon->contype = CONSTR_FOREIGN; + fkcon->location = -1; if (funcnum == 2) { /* This trigger is on the FK table */ @@ -642,9 +644,9 @@ ConvertTriggerToFK(CreateTrigStmt *stmt, Oid funcoid) atcmd->subtype = AT_AddConstraint; atcmd->def = (Node *) fkcon; if (strcmp(constr_name, "") == 0) - fkcon->constr_name = NULL; + fkcon->conname = NULL; else - fkcon->constr_name = constr_name; + fkcon->conname = constr_name; fkcon->fk_attrs = fk_attrs; fkcon->pk_attrs = pk_attrs; fkcon->fk_matchtype = fk_matchtype; diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c index 1d3077cc32..5fa2ac6bc9 100644 --- a/src/backend/commands/typecmds.c +++ b/src/backend/commands/typecmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.136 2009/07/28 02:56:30 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.137 2009/07/30 02:45:36 tgl Exp $ * * DESCRIPTION * The "DefineFoo" routines take the parse tree and pick out the @@ -867,22 +867,11 @@ DefineDomain(CreateDomainStmt *stmt) */ foreach(listptr, schema) { - Node *newConstraint = lfirst(listptr); - Constraint *constr; + Constraint *constr = lfirst(listptr); - /* Check for unsupported constraint types */ - if (IsA(newConstraint, FkConstraint)) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("foreign key constraints not possible for domains"))); - - /* otherwise it should be a plain Constraint */ - if (!IsA(newConstraint, Constraint)) + if (!IsA(constr, Constraint)) elog(ERROR, "unrecognized node type: %d", - (int) nodeTag(newConstraint)); - - constr = (Constraint *) newConstraint; - + (int) nodeTag(constr)); switch (constr->contype) { case CONSTR_DEFAULT: @@ -995,6 +984,12 @@ DefineDomain(CreateDomainStmt *stmt) errmsg("primary key constraints not possible for domains"))); break; + case CONSTR_FOREIGN: + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("foreign key constraints not possible for domains"))); + break; + case CONSTR_ATTR_DEFERRABLE: case CONSTR_ATTR_NOT_DEFERRABLE: case CONSTR_ATTR_DEFERRED: @@ -1849,13 +1844,6 @@ AlterDomainAddConstraint(List *names, Node *newConstraint) /* Check it's a domain and check user has permission for ALTER DOMAIN */ checkDomainOwner(tup, typename); - /* Check for unsupported constraint types */ - if (IsA(newConstraint, FkConstraint)) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("foreign key constraints not possible for domains"))); - - /* otherwise it should be a plain Constraint */ if (!IsA(newConstraint, Constraint)) elog(ERROR, "unrecognized node type: %d", (int) nodeTag(newConstraint)); @@ -1880,6 +1868,12 @@ AlterDomainAddConstraint(List *names, Node *newConstraint) errmsg("primary key constraints not possible for domains"))); break; + case CONSTR_FOREIGN: + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("foreign key constraints not possible for domains"))); + break; + case CONSTR_ATTR_DEFERRABLE: case CONSTR_ATTR_NOT_DEFERRABLE: case CONSTR_ATTR_DEFERRED: @@ -2188,23 +2182,23 @@ domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid, /* * Assign or validate constraint name */ - if (constr->name) + if (constr->conname) { if (ConstraintNameIsUsed(CONSTRAINT_DOMAIN, domainOid, domainNamespace, - constr->name)) + constr->conname)) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("constraint \"%s\" for domain \"%s\" already exists", - constr->name, domainName))); + constr->conname, domainName))); } else - constr->name = ChooseConstraintName(domainName, - NULL, - "check", - domainNamespace, - NIL); + constr->conname = ChooseConstraintName(domainName, + NULL, + "check", + domainNamespace, + NIL); /* * Convert the A_EXPR in raw_expr into an EXPR @@ -2284,7 +2278,7 @@ domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid, /* * Store the constraint in pg_constraint */ - CreateConstraintEntry(constr->name, /* Constraint Name */ + CreateConstraintEntry(constr->conname, /* Constraint Name */ domainNamespace, /* namespace */ CONSTRAINT_CHECK, /* Constraint Type */ false, /* Is Deferrable */ diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index d10a9eb6cc..48039b86cb 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -15,7 +15,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.436 2009/07/29 20:56:19 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.437 2009/07/30 02:45:37 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1738,25 +1738,6 @@ _copyRangeTblEntry(RangeTblEntry *from) return newnode; } -static FkConstraint * -_copyFkConstraint(FkConstraint *from) -{ - FkConstraint *newnode = makeNode(FkConstraint); - - COPY_STRING_FIELD(constr_name); - COPY_NODE_FIELD(pktable); - COPY_NODE_FIELD(fk_attrs); - COPY_NODE_FIELD(pk_attrs); - COPY_SCALAR_FIELD(fk_matchtype); - COPY_SCALAR_FIELD(fk_upd_action); - COPY_SCALAR_FIELD(fk_del_action); - COPY_SCALAR_FIELD(deferrable); - COPY_SCALAR_FIELD(initdeferred); - COPY_SCALAR_FIELD(skip_validation); - - return newnode; -} - static SortGroupClause * _copySortGroupClause(SortGroupClause *from) { @@ -2085,14 +2066,22 @@ _copyConstraint(Constraint *from) Constraint *newnode = makeNode(Constraint); COPY_SCALAR_FIELD(contype); - COPY_STRING_FIELD(name); + COPY_STRING_FIELD(conname); + COPY_SCALAR_FIELD(deferrable); + COPY_SCALAR_FIELD(initdeferred); + COPY_LOCATION_FIELD(location); COPY_NODE_FIELD(raw_expr); COPY_STRING_FIELD(cooked_expr); COPY_NODE_FIELD(keys); COPY_NODE_FIELD(options); COPY_STRING_FIELD(indexspace); - COPY_SCALAR_FIELD(deferrable); - COPY_SCALAR_FIELD(initdeferred); + COPY_NODE_FIELD(pktable); + COPY_NODE_FIELD(fk_attrs); + COPY_NODE_FIELD(pk_attrs); + COPY_SCALAR_FIELD(fk_matchtype); + COPY_SCALAR_FIELD(fk_upd_action); + COPY_SCALAR_FIELD(fk_del_action); + COPY_SCALAR_FIELD(skip_validation); return newnode; } @@ -4082,9 +4071,6 @@ copyObject(void *from) case T_CommonTableExpr: retval = _copyCommonTableExpr(from); break; - case T_FkConstraint: - retval = _copyFkConstraint(from); - break; case T_PrivGrantee: retval = _copyPrivGrantee(from); break; diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index 6fceab2785..6c75f2e274 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -22,7 +22,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.359 2009/07/29 20:56:19 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.360 2009/07/30 02:45:37 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -2064,14 +2064,22 @@ static bool _equalConstraint(Constraint *a, Constraint *b) { COMPARE_SCALAR_FIELD(contype); - COMPARE_STRING_FIELD(name); + COMPARE_STRING_FIELD(conname); + COMPARE_SCALAR_FIELD(deferrable); + COMPARE_SCALAR_FIELD(initdeferred); + COMPARE_LOCATION_FIELD(location); COMPARE_NODE_FIELD(raw_expr); COMPARE_STRING_FIELD(cooked_expr); COMPARE_NODE_FIELD(keys); COMPARE_NODE_FIELD(options); COMPARE_STRING_FIELD(indexspace); - COMPARE_SCALAR_FIELD(deferrable); - COMPARE_SCALAR_FIELD(initdeferred); + COMPARE_NODE_FIELD(pktable); + COMPARE_NODE_FIELD(fk_attrs); + COMPARE_NODE_FIELD(pk_attrs); + COMPARE_SCALAR_FIELD(fk_matchtype); + COMPARE_SCALAR_FIELD(fk_upd_action); + COMPARE_SCALAR_FIELD(fk_del_action); + COMPARE_SCALAR_FIELD(skip_validation); return true; } @@ -2189,23 +2197,6 @@ _equalCommonTableExpr(CommonTableExpr *a, CommonTableExpr *b) return true; } -static bool -_equalFkConstraint(FkConstraint *a, FkConstraint *b) -{ - COMPARE_STRING_FIELD(constr_name); - COMPARE_NODE_FIELD(pktable); - COMPARE_NODE_FIELD(fk_attrs); - COMPARE_NODE_FIELD(pk_attrs); - COMPARE_SCALAR_FIELD(fk_matchtype); - COMPARE_SCALAR_FIELD(fk_upd_action); - COMPARE_SCALAR_FIELD(fk_del_action); - COMPARE_SCALAR_FIELD(deferrable); - COMPARE_SCALAR_FIELD(initdeferred); - COMPARE_SCALAR_FIELD(skip_validation); - - return true; -} - static bool _equalXmlSerialize(XmlSerialize *a, XmlSerialize *b) { @@ -2859,9 +2850,6 @@ equal(void *a, void *b) case T_CommonTableExpr: retval = _equalCommonTableExpr(a, b); break; - case T_FkConstraint: - retval = _equalFkConstraint(a, b); - break; case T_PrivGrantee: retval = _equalPrivGrantee(a, b); break; diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c index 4dc9bd4bbf..61c0e21db0 100644 --- a/src/backend/nodes/nodeFuncs.c +++ b/src/backend/nodes/nodeFuncs.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/nodes/nodeFuncs.c,v 1.41 2009/07/16 06:33:42 petere Exp $ + * $PostgreSQL: pgsql/src/backend/nodes/nodeFuncs.c,v 1.42 2009/07/30 02:45:37 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -903,6 +903,9 @@ exprLocation(Node *expr) case T_TypeName: loc = ((TypeName *) expr)->location; break; + case T_Constraint: + loc = ((Constraint *) expr)->location; + break; case T_XmlSerialize: /* XMLSERIALIZE keyword should always be the first thing */ loc = ((XmlSerialize *) expr)->location; diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index e4de1c5aee..454a8d0886 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.362 2009/07/29 20:56:19 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.363 2009/07/30 02:45:37 tgl Exp $ * * NOTES * Every node type that can appear in stored rules' parsetrees *must* @@ -2277,33 +2277,20 @@ _outConstraint(StringInfo str, Constraint *node) { WRITE_NODE_TYPE("CONSTRAINT"); - WRITE_STRING_FIELD(name); + WRITE_STRING_FIELD(conname); + WRITE_BOOL_FIELD(deferrable); + WRITE_BOOL_FIELD(initdeferred); + WRITE_LOCATION_FIELD(location); appendStringInfo(str, " :contype "); switch (node->contype) { - case CONSTR_PRIMARY: - appendStringInfo(str, "PRIMARY_KEY"); - WRITE_NODE_FIELD(keys); - WRITE_NODE_FIELD(options); - WRITE_STRING_FIELD(indexspace); - WRITE_BOOL_FIELD(deferrable); - WRITE_BOOL_FIELD(initdeferred); + case CONSTR_NULL: + appendStringInfo(str, "NULL"); break; - case CONSTR_UNIQUE: - appendStringInfo(str, "UNIQUE"); - WRITE_NODE_FIELD(keys); - WRITE_NODE_FIELD(options); - WRITE_STRING_FIELD(indexspace); - WRITE_BOOL_FIELD(deferrable); - WRITE_BOOL_FIELD(initdeferred); - break; - - case CONSTR_CHECK: - appendStringInfo(str, "CHECK"); - WRITE_NODE_FIELD(raw_expr); - WRITE_STRING_FIELD(cooked_expr); + case CONSTR_NOTNULL: + appendStringInfo(str, "NOT_NULL"); break; case CONSTR_DEFAULT: @@ -2312,33 +2299,60 @@ _outConstraint(StringInfo str, Constraint *node) WRITE_STRING_FIELD(cooked_expr); break; - case CONSTR_NOTNULL: - appendStringInfo(str, "NOT_NULL"); + case CONSTR_CHECK: + appendStringInfo(str, "CHECK"); + WRITE_NODE_FIELD(raw_expr); + WRITE_STRING_FIELD(cooked_expr); + break; + + case CONSTR_PRIMARY: + appendStringInfo(str, "PRIMARY_KEY"); + WRITE_NODE_FIELD(keys); + WRITE_NODE_FIELD(options); + WRITE_STRING_FIELD(indexspace); + break; + + case CONSTR_UNIQUE: + appendStringInfo(str, "UNIQUE"); + WRITE_NODE_FIELD(keys); + WRITE_NODE_FIELD(options); + WRITE_STRING_FIELD(indexspace); + break; + + case CONSTR_FOREIGN: + appendStringInfo(str, "FOREIGN_KEY"); + WRITE_NODE_FIELD(pktable); + WRITE_NODE_FIELD(fk_attrs); + WRITE_NODE_FIELD(pk_attrs); + WRITE_CHAR_FIELD(fk_matchtype); + WRITE_CHAR_FIELD(fk_upd_action); + WRITE_CHAR_FIELD(fk_del_action); + WRITE_BOOL_FIELD(skip_validation); + break; + + case CONSTR_ATTR_DEFERRABLE: + appendStringInfo(str, "ATTR_DEFERRABLE"); + break; + + case CONSTR_ATTR_NOT_DEFERRABLE: + appendStringInfo(str, "ATTR_NOT_DEFERRABLE"); + break; + + case CONSTR_ATTR_DEFERRED: + appendStringInfo(str, "ATTR_DEFERRED"); + break; + + case CONSTR_ATTR_IMMEDIATE: + appendStringInfo(str, "ATTR_IMMEDIATE"); break; default: - appendStringInfo(str, ""); + appendStringInfo(str, "", + (int) node->contype); break; } } -static void -_outFkConstraint(StringInfo str, FkConstraint *node) -{ - WRITE_NODE_TYPE("FKCONSTRAINT"); - - WRITE_STRING_FIELD(constr_name); - WRITE_NODE_FIELD(pktable); - WRITE_NODE_FIELD(fk_attrs); - WRITE_NODE_FIELD(pk_attrs); - WRITE_CHAR_FIELD(fk_matchtype); - WRITE_CHAR_FIELD(fk_upd_action); - WRITE_CHAR_FIELD(fk_del_action); - WRITE_BOOL_FIELD(deferrable); - WRITE_BOOL_FIELD(initdeferred); - WRITE_BOOL_FIELD(skip_validation); -} - /* * _outNode - @@ -2765,9 +2779,6 @@ _outNode(StringInfo str, void *obj) case T_Constraint: _outConstraint(str, obj); break; - case T_FkConstraint: - _outFkConstraint(str, obj); - break; case T_FuncCall: _outFuncCall(str, obj); break; diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 0547b64a6e..543aea9928 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -11,7 +11,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.674 2009/07/29 20:56:19 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.675 2009/07/30 02:45:37 tgl Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -2172,24 +2172,11 @@ ColQualList: ColConstraint: CONSTRAINT name ColConstraintElem { - switch (nodeTag($3)) - { - case T_Constraint: - { - Constraint *n = (Constraint *)$3; - n->name = $2; - } - break; - case T_FkConstraint: - { - FkConstraint *n = (FkConstraint *)$3; - n->constr_name = $2; - } - break; - default: - break; - } - $$ = $3; + Constraint *n = (Constraint *) $3; + Assert(IsA(n, Constraint)); + n->conname = $2; + n->location = @1; + $$ = (Node *) n; } | ColConstraintElem { $$ = $1; } | ConstraintAttr { $$ = $1; } @@ -2215,94 +2202,66 @@ ColConstraintElem: { Constraint *n = makeNode(Constraint); n->contype = CONSTR_NOTNULL; - n->name = NULL; - n->raw_expr = NULL; - n->cooked_expr = NULL; - n->keys = NULL; - n->indexspace = NULL; - n->deferrable = FALSE; - n->initdeferred = FALSE; + n->location = @1; $$ = (Node *)n; } | NULL_P { Constraint *n = makeNode(Constraint); n->contype = CONSTR_NULL; - n->name = NULL; - n->raw_expr = NULL; - n->cooked_expr = NULL; - n->keys = NULL; - n->indexspace = NULL; - n->deferrable = FALSE; - n->initdeferred = FALSE; + n->location = @1; $$ = (Node *)n; } | UNIQUE opt_definition OptConsTableSpace { Constraint *n = makeNode(Constraint); n->contype = CONSTR_UNIQUE; - n->name = NULL; - n->raw_expr = NULL; - n->cooked_expr = NULL; + n->location = @1; n->keys = NULL; n->options = $2; n->indexspace = $3; - n->deferrable = FALSE; - n->initdeferred = FALSE; $$ = (Node *)n; } | PRIMARY KEY opt_definition OptConsTableSpace { Constraint *n = makeNode(Constraint); n->contype = CONSTR_PRIMARY; - n->name = NULL; - n->raw_expr = NULL; - n->cooked_expr = NULL; + n->location = @1; n->keys = NULL; n->options = $3; n->indexspace = $4; - n->deferrable = FALSE; - n->initdeferred = FALSE; $$ = (Node *)n; } | CHECK '(' a_expr ')' { Constraint *n = makeNode(Constraint); n->contype = CONSTR_CHECK; - n->name = NULL; + n->location = @1; n->raw_expr = $3; n->cooked_expr = NULL; - n->keys = NULL; - n->indexspace = NULL; - n->deferrable = FALSE; - n->initdeferred = FALSE; $$ = (Node *)n; } | DEFAULT b_expr { Constraint *n = makeNode(Constraint); n->contype = CONSTR_DEFAULT; - n->name = NULL; + n->location = @1; n->raw_expr = $2; n->cooked_expr = NULL; - n->keys = NULL; - n->indexspace = NULL; - n->deferrable = FALSE; - n->initdeferred = FALSE; $$ = (Node *)n; } | REFERENCES qualified_name opt_column_list key_match key_actions { - FkConstraint *n = makeNode(FkConstraint); - n->constr_name = NULL; + Constraint *n = makeNode(Constraint); + n->contype = CONSTR_FOREIGN; + n->location = @1; n->pktable = $2; n->fk_attrs = NIL; n->pk_attrs = $3; n->fk_matchtype = $4; n->fk_upd_action = (char) ($5 >> 8); n->fk_del_action = (char) ($5 & 0xFF); - n->deferrable = FALSE; - n->initdeferred = FALSE; + n->skip_validation = FALSE; $$ = (Node *)n; } ; @@ -2324,24 +2283,28 @@ ConstraintAttr: { Constraint *n = makeNode(Constraint); n->contype = CONSTR_ATTR_DEFERRABLE; + n->location = @1; $$ = (Node *)n; } | NOT DEFERRABLE { Constraint *n = makeNode(Constraint); n->contype = CONSTR_ATTR_NOT_DEFERRABLE; + n->location = @1; $$ = (Node *)n; } | INITIALLY DEFERRED { Constraint *n = makeNode(Constraint); n->contype = CONSTR_ATTR_DEFERRED; + n->location = @1; $$ = (Node *)n; } | INITIALLY IMMEDIATE { Constraint *n = makeNode(Constraint); n->contype = CONSTR_ATTR_IMMEDIATE; + n->location = @1; $$ = (Node *)n; } ; @@ -2387,24 +2350,11 @@ TableLikeOption: TableConstraint: CONSTRAINT name ConstraintElem { - switch (nodeTag($3)) - { - case T_Constraint: - { - Constraint *n = (Constraint *)$3; - n->name = $2; - } - break; - case T_FkConstraint: - { - FkConstraint *n = (FkConstraint *)$3; - n->constr_name = $2; - } - break; - default: - break; - } - $$ = $3; + Constraint *n = (Constraint *) $3; + Assert(IsA(n, Constraint)); + n->conname = $2; + n->location = @1; + $$ = (Node *) n; } | ConstraintElem { $$ = $1; } ; @@ -2414,17 +2364,14 @@ ConstraintElem: { Constraint *n = makeNode(Constraint); n->contype = CONSTR_CHECK; - n->name = NULL; + n->location = @1; n->raw_expr = $3; n->cooked_expr = NULL; - n->indexspace = NULL; if ($5 != 0) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("CHECK constraints cannot be deferred"), parser_errposition(@5))); - n->deferrable = FALSE; - n->initdeferred = FALSE; $$ = (Node *)n; } | UNIQUE '(' columnList ')' opt_definition OptConsTableSpace @@ -2432,9 +2379,7 @@ ConstraintElem: { Constraint *n = makeNode(Constraint); n->contype = CONSTR_UNIQUE; - n->name = NULL; - n->raw_expr = NULL; - n->cooked_expr = NULL; + n->location = @1; n->keys = $3; n->options = $5; n->indexspace = $6; @@ -2447,9 +2392,7 @@ ConstraintElem: { Constraint *n = makeNode(Constraint); n->contype = CONSTR_PRIMARY; - n->name = NULL; - n->raw_expr = NULL; - n->cooked_expr = NULL; + n->location = @1; n->keys = $4; n->options = $6; n->indexspace = $7; @@ -2460,14 +2403,16 @@ ConstraintElem: | FOREIGN KEY '(' columnList ')' REFERENCES qualified_name opt_column_list key_match key_actions ConstraintAttributeSpec { - FkConstraint *n = makeNode(FkConstraint); - n->constr_name = NULL; + Constraint *n = makeNode(Constraint); + n->contype = CONSTR_FOREIGN; + n->location = @1; n->pktable = $7; n->fk_attrs = $4; n->pk_attrs = $8; n->fk_matchtype = $9; n->fk_upd_action = (char) ($10 >> 8); n->fk_del_action = (char) ($10 & 0xFF); + n->skip_validation = FALSE; n->deferrable = ($11 & 1) != 0; n->initdeferred = ($11 & 2) != 0; $$ = (Node *)n; diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c index 94c8c5977b..7a11eb96ed 100644 --- a/src/backend/parser/parse_utilcmd.c +++ b/src/backend/parser/parse_utilcmd.c @@ -19,7 +19,7 @@ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/backend/parser/parse_utilcmd.c,v 2.24 2009/07/29 20:56:19 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_utilcmd.c,v 2.25 2009/07/30 02:45:37 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -112,7 +112,7 @@ static void transformFKConstraints(ParseState *pstate, CreateStmtContext *cxt, bool skipValidation, bool isAddConstraint); -static void transformConstraintAttrs(List *constraintList); +static void transformConstraintAttrs(ParseState *pstate, List *constraintList); static void transformColumnType(ParseState *pstate, ColumnDef *column); static void setSchemaName(char *context_schema, char **stmt_schema_name); @@ -199,11 +199,6 @@ transformCreateStmt(CreateStmt *stmt, const char *queryString) (Constraint *) element); break; - case T_FkConstraint: - /* No pre-transformation needed */ - cxt.fkconstraints = lappend(cxt.fkconstraints, element); - break; - case T_InhRelation: transformInhRelation(pstate, &cxt, (InhRelation *) element); @@ -295,7 +290,8 @@ transformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt, if (is_serial && column->typeName->arrayBounds != NIL) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("array of serial is not implemented"))); + errmsg("array of serial is not implemented"), + parser_errposition(pstate, column->typeName->location))); } /* Do necessary work on the column type declaration */ @@ -397,18 +393,19 @@ transformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt, constraint = makeNode(Constraint); constraint->contype = CONSTR_DEFAULT; + constraint->location = -1; constraint->raw_expr = (Node *) funccallnode; constraint->cooked_expr = NULL; - constraint->keys = NIL; column->constraints = lappend(column->constraints, constraint); constraint = makeNode(Constraint); constraint->contype = CONSTR_NOTNULL; + constraint->location = -1; column->constraints = lappend(column->constraints, constraint); } /* Process column constraints, if any... */ - transformConstraintAttrs(column->constraints); + transformConstraintAttrs(pstate, column->constraints); saw_nullable = false; saw_default = false; @@ -416,21 +413,6 @@ transformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt, foreach(clist, column->constraints) { constraint = lfirst(clist); - - /* - * If this column constraint is a FOREIGN KEY constraint, then we fill - * in the current attribute's name and throw it into the list of FK - * constraints to be processed later. - */ - if (IsA(constraint, FkConstraint)) - { - FkConstraint *fkconstraint = (FkConstraint *) constraint; - - fkconstraint->fk_attrs = list_make1(makeString(column->colname)); - cxt->fkconstraints = lappend(cxt->fkconstraints, fkconstraint); - continue; - } - Assert(IsA(constraint, Constraint)); switch (constraint->contype) @@ -440,7 +422,9 @@ transformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt, ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting NULL/NOT NULL declarations for column \"%s\" of table \"%s\"", - column->colname, cxt->relation->relname))); + column->colname, cxt->relation->relname), + parser_errposition(pstate, + constraint->location))); column->is_not_null = FALSE; saw_nullable = true; break; @@ -450,7 +434,9 @@ transformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt, ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting NULL/NOT NULL declarations for column \"%s\" of table \"%s\"", - column->colname, cxt->relation->relname))); + column->colname, cxt->relation->relname), + parser_errposition(pstate, + constraint->location))); column->is_not_null = TRUE; saw_nullable = true; break; @@ -460,7 +446,9 @@ transformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt, ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("multiple default values specified for column \"%s\" of table \"%s\"", - column->colname, cxt->relation->relname))); + column->colname, cxt->relation->relname), + parser_errposition(pstate, + constraint->location))); column->raw_default = constraint->raw_expr; Assert(constraint->cooked_expr == NULL); saw_default = true; @@ -477,6 +465,15 @@ transformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt, cxt->ckconstraints = lappend(cxt->ckconstraints, constraint); break; + case CONSTR_FOREIGN: + /* + * Fill in the current attribute's name and throw it into the + * list of FK constraints to be processed later. + */ + constraint->fk_attrs = list_make1(makeString(column->colname)); + cxt->fkconstraints = lappend(cxt->fkconstraints, constraint); + break; + case CONSTR_ATTR_DEFERRABLE: case CONSTR_ATTR_NOT_DEFERRABLE: case CONSTR_ATTR_DEFERRED: @@ -511,6 +508,10 @@ transformTableConstraint(ParseState *pstate, CreateStmtContext *cxt, cxt->ckconstraints = lappend(cxt->ckconstraints, constraint); break; + case CONSTR_FOREIGN: + cxt->fkconstraints = lappend(cxt->fkconstraints, constraint); + break; + case CONSTR_NULL: case CONSTR_NOTNULL: case CONSTR_DEFAULT: @@ -688,11 +689,11 @@ transformInhRelation(ParseState *pstate, CreateStmtContext *cxt, change_varattnos_of_a_node(ccbin_node, attmap); n->contype = CONSTR_CHECK; - n->name = pstrdup(ccname); + n->location = -1; + n->conname = pstrdup(ccname); n->raw_expr = NULL; n->cooked_expr = nodeToString(ccbin_node); - n->indexspace = NULL; - cxt->ckconstraints = lappend(cxt->ckconstraints, (Node *) n); + cxt->ckconstraints = lappend(cxt->ckconstraints, n); } } @@ -1121,8 +1122,8 @@ transformIndexConstraint(Constraint *constraint, CreateStmtContext *cxt) index->deferrable = constraint->deferrable; index->initdeferred = constraint->initdeferred; - if (constraint->name != NULL) - index->idxname = pstrdup(constraint->name); + if (constraint->conname != NULL) + index->idxname = pstrdup(constraint->conname); else index->idxname = NULL; /* DefineIndex will choose name */ @@ -1281,9 +1282,9 @@ transformFKConstraints(ParseState *pstate, CreateStmtContext *cxt, { foreach(fkclist, cxt->fkconstraints) { - FkConstraint *fkconstraint = (FkConstraint *) lfirst(fkclist); + Constraint *constraint = (Constraint *) lfirst(fkclist); - fkconstraint->skip_validation = true; + constraint->skip_validation = true; } } @@ -1308,12 +1309,12 @@ transformFKConstraints(ParseState *pstate, CreateStmtContext *cxt, foreach(fkclist, cxt->fkconstraints) { - FkConstraint *fkconstraint = (FkConstraint *) lfirst(fkclist); + Constraint *constraint = (Constraint *) lfirst(fkclist); AlterTableCmd *altercmd = makeNode(AlterTableCmd); altercmd->subtype = AT_ProcessedConstraint; altercmd->name = NULL; - altercmd->def = (Node *) fkconstraint; + altercmd->def = (Node *) constraint; alterstmt->cmds = lappend(alterstmt->cmds, altercmd); } @@ -1784,12 +1785,11 @@ transformAlterTableStmt(AlterTableStmt *stmt, const char *queryString) * The original AddConstraint cmd node doesn't go to newcmds */ if (IsA(cmd->def, Constraint)) + { transformTableConstraint(pstate, &cxt, (Constraint *) cmd->def); - else if (IsA(cmd->def, FkConstraint)) - { - cxt.fkconstraints = lappend(cxt.fkconstraints, cmd->def); - skipValidation = false; + if (((Constraint *) cmd->def)->contype == CONSTR_FOREIGN) + skipValidation = false; } else elog(ERROR, "unrecognized node type: %d", @@ -1886,145 +1886,112 @@ transformAlterTableStmt(AlterTableStmt *stmt, const char *queryString) * for other constraint types. */ static void -transformConstraintAttrs(List *constraintList) +transformConstraintAttrs(ParseState *pstate, List *constraintList) { - Node *lastprimarynode = NULL; + Constraint *lastprimarycon = NULL; bool saw_deferrability = false; bool saw_initially = false; ListCell *clist; -#define SUPPORTS_ATTRS(node) \ - ((node) != NULL && \ - (IsA((node), FkConstraint) || \ - (IsA((node), Constraint) && \ - (((Constraint *) (node))->contype == CONSTR_PRIMARY || \ - ((Constraint *) (node))->contype == CONSTR_UNIQUE)))) +#define SUPPORTS_ATTRS(node) \ + ((node) != NULL && \ + ((node)->contype == CONSTR_PRIMARY || \ + (node)->contype == CONSTR_UNIQUE || \ + (node)->contype == CONSTR_FOREIGN)) foreach(clist, constraintList) { - Node *node = lfirst(clist); + Constraint *con = (Constraint *) lfirst(clist); - if (!IsA(node, Constraint)) + if (!IsA(con, Constraint)) + elog(ERROR, "unrecognized node type: %d", + (int) nodeTag(con)); + switch (con->contype) { - lastprimarynode = node; - /* reset flags for new primary node */ - saw_deferrability = false; - saw_initially = false; - } - else - { - Constraint *con = (Constraint *) node; + case CONSTR_ATTR_DEFERRABLE: + if (!SUPPORTS_ATTRS(lastprimarycon)) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("misplaced DEFERRABLE clause"), + parser_errposition(pstate, con->location))); + if (saw_deferrability) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("multiple DEFERRABLE/NOT DEFERRABLE clauses not allowed"), + parser_errposition(pstate, con->location))); + saw_deferrability = true; + lastprimarycon->deferrable = true; + break; - switch (con->contype) - { - case CONSTR_ATTR_DEFERRABLE: - if (!SUPPORTS_ATTRS(lastprimarynode)) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("misplaced DEFERRABLE clause"))); - if (saw_deferrability) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("multiple DEFERRABLE/NOT DEFERRABLE clauses not allowed"))); - saw_deferrability = true; - if (IsA(lastprimarynode, FkConstraint)) - ((FkConstraint *) lastprimarynode)->deferrable = true; - else - ((Constraint *) lastprimarynode)->deferrable = true; - break; + case CONSTR_ATTR_NOT_DEFERRABLE: + if (!SUPPORTS_ATTRS(lastprimarycon)) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("misplaced NOT DEFERRABLE clause"), + parser_errposition(pstate, con->location))); + if (saw_deferrability) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("multiple DEFERRABLE/NOT DEFERRABLE clauses not allowed"), + parser_errposition(pstate, con->location))); + saw_deferrability = true; + lastprimarycon->deferrable = false; + if (saw_initially && + lastprimarycon->initdeferred) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("constraint declared INITIALLY DEFERRED must be DEFERRABLE"), + parser_errposition(pstate, con->location))); + break; - case CONSTR_ATTR_NOT_DEFERRABLE: - if (!SUPPORTS_ATTRS(lastprimarynode)) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("misplaced NOT DEFERRABLE clause"))); - if (saw_deferrability) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("multiple DEFERRABLE/NOT DEFERRABLE clauses not allowed"))); - saw_deferrability = true; - if (IsA(lastprimarynode, FkConstraint)) - { - ((FkConstraint *) lastprimarynode)->deferrable = false; - if (saw_initially && - ((FkConstraint *) lastprimarynode)->initdeferred) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("constraint declared INITIALLY DEFERRED must be DEFERRABLE"))); - } - else - { - ((Constraint *) lastprimarynode)->deferrable = false; - if (saw_initially && - ((Constraint *) lastprimarynode)->initdeferred) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("constraint declared INITIALLY DEFERRED must be DEFERRABLE"))); - } - break; + case CONSTR_ATTR_DEFERRED: + if (!SUPPORTS_ATTRS(lastprimarycon)) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("misplaced INITIALLY DEFERRED clause"), + parser_errposition(pstate, con->location))); + if (saw_initially) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("multiple INITIALLY IMMEDIATE/DEFERRED clauses not allowed"), + parser_errposition(pstate, con->location))); + saw_initially = true; + lastprimarycon->initdeferred = true; - case CONSTR_ATTR_DEFERRED: - if (!SUPPORTS_ATTRS(lastprimarynode)) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("misplaced INITIALLY DEFERRED clause"))); - if (saw_initially) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("multiple INITIALLY IMMEDIATE/DEFERRED clauses not allowed"))); - saw_initially = true; + /* + * If only INITIALLY DEFERRED appears, assume DEFERRABLE + */ + if (!saw_deferrability) + lastprimarycon->deferrable = true; + else if (!lastprimarycon->deferrable) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("constraint declared INITIALLY DEFERRED must be DEFERRABLE"), + parser_errposition(pstate, con->location))); + break; - /* - * If only INITIALLY DEFERRED appears, assume DEFERRABLE - */ - if (IsA(lastprimarynode, FkConstraint)) - { - ((FkConstraint *) lastprimarynode)->initdeferred = true; + case CONSTR_ATTR_IMMEDIATE: + if (!SUPPORTS_ATTRS(lastprimarycon)) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("misplaced INITIALLY IMMEDIATE clause"), + parser_errposition(pstate, con->location))); + if (saw_initially) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("multiple INITIALLY IMMEDIATE/DEFERRED clauses not allowed"), + parser_errposition(pstate, con->location))); + saw_initially = true; + lastprimarycon->initdeferred = false; + break; - if (!saw_deferrability) - ((FkConstraint *) lastprimarynode)->deferrable = true; - else if (!((FkConstraint *) lastprimarynode)->deferrable) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("constraint declared INITIALLY DEFERRED must be DEFERRABLE"))); - } - else - { - ((Constraint *) lastprimarynode)->initdeferred = true; - - if (!saw_deferrability) - ((Constraint *) lastprimarynode)->deferrable = true; - else if (!((Constraint *) lastprimarynode)->deferrable) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("constraint declared INITIALLY DEFERRED must be DEFERRABLE"))); - } - break; - - case CONSTR_ATTR_IMMEDIATE: - if (!SUPPORTS_ATTRS(lastprimarynode)) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("misplaced INITIALLY IMMEDIATE clause"))); - if (saw_initially) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("multiple INITIALLY IMMEDIATE/DEFERRED clauses not allowed"))); - saw_initially = true; - if (IsA(lastprimarynode, FkConstraint)) - ((FkConstraint *) lastprimarynode)->initdeferred = false; - else - ((Constraint *) lastprimarynode)->initdeferred = false; - break; - - default: - /* Otherwise it's not an attribute */ - lastprimarynode = node; - /* reset flags for new primary node */ - saw_deferrability = false; - saw_initially = false; - break; - } + default: + /* Otherwise it's not an attribute */ + lastprimarycon = con; + /* reset flags for new primary node */ + saw_deferrability = false; + saw_initially = false; + break; } } } diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h index f255c44d1c..b29f7203ca 100644 --- a/src/include/nodes/nodes.h +++ b/src/include/nodes/nodes.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.223 2009/06/11 14:49:11 momjian Exp $ + * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.224 2009/07/30 02:45:37 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -364,7 +364,6 @@ typedef enum NodeTag T_RangeTblEntry, T_SortGroupClause, T_WindowClause, - T_FkConstraint, T_PrivGrantee, T_FuncWithArgs, T_AccessPriv, diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index ae2f087360..d0573455a0 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -13,7 +13,7 @@ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.399 2009/07/29 20:56:21 tgl Exp $ + * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.400 2009/07/30 02:45:38 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1317,10 +1317,10 @@ typedef struct VariableShowStmt /* ---------------------- * Create Table Statement * - * NOTE: in the raw gram.y output, ColumnDef, Constraint, and FkConstraint - * nodes are intermixed in tableElts, and constraints is NIL. After parse - * analysis, tableElts contains just ColumnDefs, and constraints contains - * just Constraint nodes (in fact, only CONSTR_CHECK nodes, in the present + * NOTE: in the raw gram.y output, ColumnDef and Constraint nodes are + * intermixed in tableElts, and constraints is NIL. After parse analysis, + * tableElts contains just ColumnDefs, and constraints contains just + * Constraint nodes (in fact, only CONSTR_CHECK nodes, in the present * implementation). * ---------------------- */ @@ -1339,23 +1339,32 @@ typedef struct CreateStmt } CreateStmt; /* ---------- - * Definitions for plain (non-FOREIGN KEY) constraints in CreateStmt + * Definitions for constraints in CreateStmt * - * XXX probably these ought to be unified with FkConstraints at some point? - * To this end we include CONSTR_FOREIGN in the ConstrType enum, even though - * the parser does not generate it. + * Note that column defaults are treated as a type of constraint, + * even though that's a bit odd semantically. * - * For constraints that use expressions (CONSTR_DEFAULT, CONSTR_CHECK) + * For constraints that use expressions (CONSTR_CHECK, CONSTR_DEFAULT) * we may have the expression in either "raw" form (an untransformed * parse tree) or "cooked" form (the nodeToString representation of * an executable expression tree), depending on how this Constraint * node was created (by parsing, or by inheritance from an existing * relation). We should never have both in the same node! * + * FKCONSTR_ACTION_xxx values are stored into pg_constraint.confupdtype + * and pg_constraint.confdeltype columns; FKCONSTR_MATCH_xxx values are + * stored into pg_constraint.confmatchtype. Changing the code values may + * require an initdb! + * + * If skip_validation is true then we skip checking that the existing rows + * in the table satisfy the constraint, and just install the catalog entries + * for the constraint. This is currently used only during CREATE TABLE + * (when we know the table must be empty). + * * Constraint attributes (DEFERRABLE etc) are initially represented as * separate Constraint nodes for simplicity of parsing. parse_utilcmd.c makes - * a pass through the constraints list to attach the info to the appropriate - * Constraint and FkConstraint nodes. + * a pass through the constraints list to insert the info into the appropriate + * Constraint node. * ---------- */ @@ -1365,69 +1374,56 @@ typedef enum ConstrType /* types of constraints */ CONSTR_NOTNULL, CONSTR_DEFAULT, CONSTR_CHECK, - CONSTR_FOREIGN, CONSTR_PRIMARY, CONSTR_UNIQUE, + CONSTR_FOREIGN, CONSTR_ATTR_DEFERRABLE, /* attributes for previous constraint node */ CONSTR_ATTR_NOT_DEFERRABLE, CONSTR_ATTR_DEFERRED, CONSTR_ATTR_IMMEDIATE } ConstrType; -typedef struct Constraint -{ - NodeTag type; - ConstrType contype; - char *name; /* name, or NULL if unnamed */ - Node *raw_expr; /* expr, as untransformed parse tree */ - char *cooked_expr; /* expr, as nodeToString representation */ - List *keys; /* String nodes naming referenced column(s) */ - List *options; /* options from WITH clause */ - char *indexspace; /* index tablespace for PKEY/UNIQUE - * constraints; NULL for default */ - bool deferrable; /* DEFERRABLE */ - bool initdeferred; /* INITIALLY DEFERRED */ -} Constraint; - -/* ---------- - * Definitions for FOREIGN KEY constraints in CreateStmt - * - * Note: FKCONSTR_ACTION_xxx values are stored into pg_constraint.confupdtype - * and pg_constraint.confdeltype columns; FKCONSTR_MATCH_xxx values are - * stored into pg_constraint.confmatchtype. Changing the code values may - * require an initdb! - * - * If skip_validation is true then we skip checking that the existing rows - * in the table satisfy the constraint, and just install the catalog entries - * for the constraint. This is currently used only during CREATE TABLE - * (when we know the table must be empty). - * ---------- - */ +/* Foreign key action codes */ #define FKCONSTR_ACTION_NOACTION 'a' #define FKCONSTR_ACTION_RESTRICT 'r' #define FKCONSTR_ACTION_CASCADE 'c' #define FKCONSTR_ACTION_SETNULL 'n' #define FKCONSTR_ACTION_SETDEFAULT 'd' +/* Foreign key matchtype codes */ #define FKCONSTR_MATCH_FULL 'f' #define FKCONSTR_MATCH_PARTIAL 'p' #define FKCONSTR_MATCH_UNSPECIFIED 'u' -typedef struct FkConstraint +typedef struct Constraint { NodeTag type; - char *constr_name; /* Constraint name, or NULL if unnamed */ + ConstrType contype; /* see above */ + + /* Fields used for most/all constraint types: */ + char *conname; /* Constraint name, or NULL if unnamed */ + bool deferrable; /* DEFERRABLE? */ + bool initdeferred; /* INITIALLY DEFERRED? */ + int location; /* token location, or -1 if unknown */ + + /* Fields used for constraints with expressions (CHECK and DEFAULT): */ + Node *raw_expr; /* expr, as untransformed parse tree */ + char *cooked_expr; /* expr, as nodeToString representation */ + + /* Fields used for index constraints (UNIQUE and PRIMARY KEY): */ + List *keys; /* String nodes naming referenced column(s) */ + List *options; /* options from WITH clause */ + char *indexspace; /* index tablespace; NULL for default */ + + /* Fields used for FOREIGN KEY constraints: */ RangeVar *pktable; /* Primary key table */ List *fk_attrs; /* Attributes of foreign key */ List *pk_attrs; /* Corresponding attrs in PK table */ char fk_matchtype; /* FULL, PARTIAL, UNSPECIFIED */ char fk_upd_action; /* ON UPDATE action */ char fk_del_action; /* ON DELETE action */ - bool deferrable; /* DEFERRABLE */ - bool initdeferred; /* INITIALLY DEFERRED */ bool skip_validation; /* skip validation of existing rows? */ -} FkConstraint; - +} Constraint; /* ---------------------- * Create/Drop Table Space Statements