1
0
mirror of https://github.com/postgres/postgres.git synced 2025-09-08 00:47:37 +03:00

Merge the Constraint and FkConstraint node types into a single type.

This was foreseen to be a good idea long ago, but nobody had got round
to doing it.  The recent patch for deferred unique constraints made
transformConstraintAttrs() ugly enough that I decided it was time.
This change will also greatly simplify parsing of deferred CHECK constraints,
if anyone ever gets around to implementing that.

While at it, add a location field to Constraint, and use that to provide
an error cursor for some of the constraint-related error messages.
This commit is contained in:
Tom Lane
2009-07-30 02:45:38 +00:00
parent 78aef14c59
commit 060baf2784
12 changed files with 394 additions and 515 deletions

View File

@@ -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;

View File

@@ -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;
}
}
}