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:
@@ -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;
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user