* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: analyze.c,v 1.138 2000/02/29 12:28:25 wieck Exp $
+ * $Id: analyze.c,v 1.139 2000/03/01 05:18:20 tgl Exp $
*
*-------------------------------------------------------------------------
*/
static void transformForUpdate(Query *qry, List *forUpdate);
static void transformFkeyGetPrimaryKey(FkConstraint *fkconstraint);
+static void transformConstraintAttrs(List *constraintList);
static void transformColumnType(ParseState *pstate, ColumnDef *column);
/* kluge to return extra info from transformCreateStmt() */
IndexStmt *index,
*pkey = NULL;
IndexElem *iparam;
+ bool saw_nullable;
q = makeNode(Query);
q->commandType = CMD_UTILITY;
FuncCall *funccallnode;
CreateSeqStmt *sequence;
+ /*
+ * Create appropriate constraints for SERIAL. We do this
+ * in full, rather than shortcutting, so that we will
+ * detect any conflicting constraints the user wrote
+ * (like a different DEFAULT).
+ */
sname = makeObjectName(stmt->relname, column->colname,
"seq");
/*
constraint->raw_expr = (Node *) funccallnode;
constraint->cooked_expr = NULL;
constraint->keys = NULL;
-
- column->constraints = lappend(column->constraints, constraint);
+ column->constraints = lappend(column->constraints,
+ constraint);
constraint = makeNode(Constraint);
constraint->contype = CONSTR_UNIQUE;
constraint->name = makeObjectName(stmt->relname,
column->colname,
"key");
- column->constraints = lappend(column->constraints, constraint);
+ column->constraints = lappend(column->constraints,
+ constraint);
+
+ constraint = makeNode(Constraint);
+ constraint->contype = CONSTR_NOTNULL;
+ column->constraints = lappend(column->constraints,
+ constraint);
sequence = makeNode(CreateSeqStmt);
sequence->seqname = pstrdup(sname);
sequence->options = NIL;
elog(NOTICE, "CREATE TABLE will create implicit sequence '%s' for SERIAL column '%s.%s'",
- sequence->seqname, stmt->relname, column->colname);
+ sequence->seqname, stmt->relname, column->colname);
blist = lcons(sequence, NIL);
}
/* Process column constraints, if any... */
+ transformConstraintAttrs(column->constraints);
+
+ saw_nullable = false;
+
foreach(clist, column->constraints)
{
constraint = lfirst(clist);
* to be processed later.
* ----------
*/
- if (nodeTag(constraint) == T_FkConstraint)
+ if (IsA(constraint, FkConstraint))
{
Ident *id = makeNode(Ident);
id->name = column->colname;
switch (constraint->contype)
{
case CONSTR_NULL:
-
- /*
- * We should mark this explicitly, so we
- * can tell if NULL and NOT NULL are both
- * specified
- */
- if (column->is_not_null)
+ if (saw_nullable && column->is_not_null)
elog(ERROR, "CREATE TABLE/(NOT) NULL conflicting declaration"
" for '%s.%s'", stmt->relname, column->colname);
column->is_not_null = FALSE;
+ saw_nullable = true;
break;
case CONSTR_NOTNULL:
- if (column->is_not_null)
- elog(ERROR, "CREATE TABLE/NOT NULL already specified"
+ if (saw_nullable && ! column->is_not_null)
+ elog(ERROR, "CREATE TABLE/(NOT) NULL conflicting declaration"
" for '%s.%s'", stmt->relname, column->colname);
column->is_not_null = TRUE;
+ saw_nullable = true;
break;
case CONSTR_DEFAULT:
constraints = lappend(constraints, constraint);
break;
+ case CONSTR_ATTR_DEFERRABLE:
+ case CONSTR_ATTR_NOT_DEFERRABLE:
+ case CONSTR_ATTR_DEFERRED:
+ case CONSTR_ATTR_IMMEDIATE:
+ /* transformConstraintAttrs took care of these */
+ break;
+
default:
elog(ERROR, "parser: unrecognized constraint (internal error)");
break;
constraints = lappend(constraints, constraint);
break;
+ case CONSTR_NULL:
case CONSTR_NOTNULL:
case CONSTR_DEFAULT:
+ case CONSTR_ATTR_DEFERRABLE:
+ case CONSTR_ATTR_NOT_DEFERRABLE:
+ case CONSTR_ATTR_DEFERRED:
+ case CONSTR_ATTR_IMMEDIATE:
elog(ERROR, "parser: illegal context for constraint (internal error)");
break;
+
default:
elog(ERROR, "parser: unrecognized constraint (internal error)");
break;
heap_close(pkrel, AccessShareLock);
}
+/*
+ * Preprocess a list of column constraint clauses
+ * to attach constraint attributes to their primary constraint nodes
+ * and detect inconsistent/misplaced constraint attributes.
+ *
+ * NOTE: currently, attributes are only supported for FOREIGN KEY primary
+ * constraints, but someday they ought to be supported for other constraints.
+ */
+static void
+transformConstraintAttrs(List *constraintList)
+{
+ Node *lastprimarynode = NULL;
+ bool saw_deferrability = false;
+ bool saw_initially = false;
+ List *clist;
+
+ foreach(clist, constraintList)
+ {
+ Node *node = lfirst(clist);
+
+ if (! IsA(node, Constraint))
+ {
+ lastprimarynode = node;
+ /* reset flags for new primary node */
+ saw_deferrability = false;
+ saw_initially = false;
+ }
+ else
+ {
+ Constraint *con = (Constraint *) node;
+
+ switch (con->contype)
+ {
+ case CONSTR_ATTR_DEFERRABLE:
+ if (lastprimarynode == NULL ||
+ ! IsA(lastprimarynode, FkConstraint))
+ elog(ERROR, "Misplaced DEFERRABLE clause");
+ if (saw_deferrability)
+ elog(ERROR, "Multiple DEFERRABLE/NOT DEFERRABLE clauses not allowed");
+ saw_deferrability = true;
+ ((FkConstraint *) lastprimarynode)->deferrable = true;
+ break;
+ case CONSTR_ATTR_NOT_DEFERRABLE:
+ if (lastprimarynode == NULL ||
+ ! IsA(lastprimarynode, FkConstraint))
+ elog(ERROR, "Misplaced NOT DEFERRABLE clause");
+ if (saw_deferrability)
+ elog(ERROR, "Multiple DEFERRABLE/NOT DEFERRABLE clauses not allowed");
+ saw_deferrability = true;
+ ((FkConstraint *) lastprimarynode)->deferrable = false;
+ if (saw_initially &&
+ ((FkConstraint *) lastprimarynode)->initdeferred)
+ elog(ERROR, "INITIALLY DEFERRED constraint must be DEFERRABLE");
+ break;
+ case CONSTR_ATTR_DEFERRED:
+ if (lastprimarynode == NULL ||
+ ! IsA(lastprimarynode, FkConstraint))
+ elog(ERROR, "Misplaced INITIALLY DEFERRED clause");
+ if (saw_initially)
+ elog(ERROR, "Multiple INITIALLY IMMEDIATE/DEFERRED clauses not allowed");
+ saw_initially = true;
+ ((FkConstraint *) lastprimarynode)->initdeferred = true;
+ /* If only INITIALLY DEFERRED appears, assume DEFERRABLE */
+ if (! saw_deferrability)
+ ((FkConstraint *) lastprimarynode)->deferrable = true;
+ else if (! ((FkConstraint *) lastprimarynode)->deferrable)
+ elog(ERROR, "INITIALLY DEFERRED constraint must be DEFERRABLE");
+ break;
+ case CONSTR_ATTR_IMMEDIATE:
+ if (lastprimarynode == NULL ||
+ ! IsA(lastprimarynode, FkConstraint))
+ elog(ERROR, "Misplaced INITIALLY IMMEDIATE clause");
+ if (saw_initially)
+ elog(ERROR, "Multiple INITIALLY IMMEDIATE/DEFERRED clauses not allowed");
+ saw_initially = true;
+ ((FkConstraint *) 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;
+ }
+ }
+ }
+}
+
/*
* Special handling of type definition for a column
*/
}
}
}
-
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.152 2000/02/26 18:13:41 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.153 2000/03/01 05:18:19 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
%type <chr> operation, TriggerOneEvent
%type <list> stmtblock, stmtmulti,
- result, relation_name_list, OptTableElementList,
+ result, OptTempTableName, relation_name_list, OptTableElementList,
OptInherit, definition, opt_distinct,
opt_with, func_args, func_args_list, func_as,
oper_argtypes, RuleActionList, RuleActionMulti,
%type <node> func_return
%type <boolean> set_opt
-%type <boolean> TriggerForOpt, TriggerForType, OptTemp, OptTempType, OptTempScope
+%type <boolean> TriggerForOpt, TriggerForType, OptTemp
%type <list> for_update_clause, update_list
%type <boolean> opt_all
%type <str> TypeId
%type <node> TableConstraint
-%type <list> ColQualList, ColQualifier
-%type <list> ColQualListWithNull
-%type <node> ColConstraint, ColConstraintElem, PrimaryKey, NotNull
-%type <node> DefaultClause, DefaultExpr
-%type <node> ColConstraintWithNull, ColConstraintElemWithNull
+%type <list> ColQualList
+%type <node> ColConstraint, ColConstraintElem, ConstraintAttr
%type <ival> key_actions, key_delete, key_update, key_reference
%type <str> key_match
-%type <ival> ConstraintAttribute, DeferrabilityClause,
- TimeClause
+%type <ival> ConstraintAttributeSpec, ConstraintDeferrabilitySpec,
+ ConstraintTimeSpec
%type <list> constraints_set_list
%type <list> constraints_set_namelist
}
;
-OptTemp: OptTempType { $$ = $1; }
- | OptTempScope OptTempType { $$ = $2; }
- ;
-
-OptTempType: TEMP { $$ = TRUE; }
- | TEMPORARY { $$ = TRUE; }
- | /*EMPTY*/ { $$ = FALSE; }
- ;
-
-OptTempScope: GLOBAL
+/*
+ * Redundancy here is needed to avoid shift/reduce conflicts,
+ * since TEMP is not a reserved word. See also OptTempTableName.
+ */
+OptTemp: TEMPORARY { $$ = TRUE; }
+ | TEMP { $$ = TRUE; }
+ | LOCAL TEMPORARY { $$ = TRUE; }
+ | LOCAL TEMP { $$ = TRUE; }
+ | GLOBAL TEMPORARY
{
elog(ERROR, "GLOBAL TEMPORARY TABLE is not currently supported");
$$ = TRUE;
}
- | LOCAL
+ | GLOBAL TEMP
{
- $$ = FALSE;
+ elog(ERROR, "GLOBAL TEMPORARY TABLE is not currently supported");
+ $$ = TRUE;
}
+ | /*EMPTY*/ { $$ = FALSE; }
;
OptTableElementList: OptTableElementList ',' OptTableElement
| TableConstraint { $$ = $1; }
;
-columnDef: ColId Typename ColQualifier opt_collate
+columnDef: ColId Typename ColQualList opt_collate
{
ColumnDef *n = makeNode(ColumnDef);
n->colname = $1;
n->typename = $2;
-#if 0
- n->raw_default = NULL;
- n->cooked_default = NULL;
- n->is_not_null = FALSE;
-#endif
n->constraints = $3;
if ($4 != NULL)
$$ = (Node *)n;
}
- | ColId SERIAL ColQualifier opt_collate
+ | ColId SERIAL ColQualList opt_collate
{
ColumnDef *n = makeNode(ColumnDef);
n->colname = $1;
n->typename = makeNode(TypeName);
n->typename->name = xlateSqlType("integer");
n->typename->typmod = -1;
-#if 0
- n->raw_default = NULL;
- n->cooked_default = NULL;
-#endif
- n->is_not_null = TRUE;
n->is_sequence = TRUE;
n->constraints = $3;
}
;
-/*
- * ColQualifier encapsulates an entire column qualification,
- * including DEFAULT, constraints, and constraint attributes.
- * Note that the DefaultClause handles the empty case.
- */
-ColQualifier: DefaultClause ColQualList
- {
- if ($1 != NULL)
- $$ = lcons($1, $2);
- else
- $$ = $2;
- }
- | NotNull DefaultClause ColQualListWithNull
- {
- $$ = lcons($1, $3);
- if ($2 != NULL)
- $$ = lcons($2, $$);
- }
- | DefaultExpr NotNull ColQualListWithNull
- {
- $$ = lcons($2, $3);
- if ($1 != NULL)
- $$ = lcons($1, $$);
- }
- | DefaultExpr NotNull
- {
- $$ = lcons($2, NIL);
- if ($1 != NULL)
- $$ = lcons($1, $$);
- }
- | NotNull DefaultClause
- {
- $$ = lcons($1, NIL);
- if ($2 != NULL)
- $$ = lcons($2, $$);
- }
- | NULL_P DefaultClause ColQualListWithNull
- {
- $$ = $3;
- if ($2 != NULL)
- $$ = lcons($2, $$);
- }
- | NULL_P DefaultClause
- {
- if ($2 != NULL)
- $$ = lcons($2, NIL);
- else
- $$ = NIL;
- }
- | DefaultClause
- {
- if ($1 != NULL)
- $$ = lcons($1, NIL);
- else
- $$ = NIL;
- }
- ;
-
-/*
- * DEFAULT expression must be b_expr not a_expr to prevent shift/reduce
- * conflict on NOT (since NOT might start a subsequent NOT NULL constraint,
- * or be part of a_expr NOT LIKE or similar constructs).
- */
-DefaultClause: DefaultExpr { $$ = $1; }
- | /*EMPTY*/ { $$ = NULL; }
+ColQualList: ColQualList ColConstraint { $$ = lappend($1, $2); }
+ | /*EMPTY*/ { $$ = NIL; }
;
-DefaultExpr: DEFAULT NULL_P
- {
- Constraint *n = makeNode(Constraint);
- n->contype = CONSTR_DEFAULT;
- n->name = NULL;
- n->raw_expr = NULL;
- n->cooked_expr = NULL;
- n->keys = NULL;
- $$ = (Node *)n;
- }
- | DEFAULT b_expr
- {
- Constraint *n = makeNode(Constraint);
- n->contype = CONSTR_DEFAULT;
- n->name = NULL;
- n->raw_expr = $2;
- n->cooked_expr = NULL;
- n->keys = NULL;
- $$ = (Node *)n;
- }
- ;
-
-ColQualList: ColQualList ColConstraint
- {
- if ($2 != NULL)
- $$ = lappend($1, $2);
- else
- $$ = $1;
- }
- | ColConstraint
- {
- if ($1 != NULL)
- $$ = lcons($1, NIL);
- else
- $$ = NULL;
- }
- ;
-
-ColQualListWithNull: ColConstraintWithNull ColQualListWithNull
- {
- if ($1 != NULL)
- $$ = lcons($1, $2);
- else
- $$ = $2;
- }
- | ColConstraintWithNull
- {
- if ($1 != NULL)
- $$ = lcons($1, NIL);
- else
- $$ = NULL;
- }
- ;
-
-ColConstraint: CONSTRAINT name ColConstraintElem
+ColConstraint:
+ CONSTRAINT name ColConstraintElem
{
switch (nodeTag($3))
{
case T_Constraint:
{
Constraint *n = (Constraint *)$3;
- if (n != NULL) n->name = $2;
+ n->name = $2;
}
break;
case T_FkConstraint:
{
FkConstraint *n = (FkConstraint *)$3;
- if (n != NULL) n->constr_name = $2;
+ n->constr_name = $2;
}
break;
default:
}
| ColConstraintElem
{ $$ = $1; }
- ;
-
-ColConstraintWithNull: CONSTRAINT name ColConstraintElemWithNull
- {
- switch (nodeTag($3))
- {
- case T_Constraint:
- {
- Constraint *n = (Constraint *)$3;
- if (n != NULL) n->name = $2;
- }
- break;
- case T_FkConstraint:
- {
- FkConstraint *n = (FkConstraint *)$3;
- if (n != NULL) n->constr_name = $2;
- }
- break;
- default:
- break;
- }
- $$ = $3;
- }
- | ColConstraintElemWithNull
+ | ConstraintAttr
{ $$ = $1; }
;
* that a column may have that value. WITH NULL leads to
* shift/reduce conflicts with WITH TIME ZONE anyway.
* - thomas 1999-01-08
+ *
+ * DEFAULT expression must be b_expr not a_expr to prevent shift/reduce
+ * conflict on NOT (since NOT might start a subsequent NOT NULL constraint,
+ * or be part of a_expr NOT LIKE or similar constructs).
*/
-ColConstraintElem: ColConstraintElemWithNull
+ColConstraintElem:
+ NOT NULL_P
{
- $$ = $1;
+ Constraint *n = makeNode(Constraint);
+ n->contype = CONSTR_NOTNULL;
+ n->name = NULL;
+ n->raw_expr = NULL;
+ n->cooked_expr = NULL;
+ n->keys = NULL;
+ $$ = (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;
+ $$ = (Node *)n;
}
| UNIQUE
{
n->keys = NULL;
$$ = (Node *)n;
}
- | PrimaryKey
+ | PRIMARY KEY
{
- $$ = $1;
+ Constraint *n = makeNode(Constraint);
+ n->contype = CONSTR_PRIMARY;
+ n->name = NULL;
+ n->raw_expr = NULL;
+ n->cooked_expr = NULL;
+ n->keys = NULL;
+ $$ = (Node *)n;
}
- ;
-
-ColConstraintElemWithNull: CHECK '(' a_expr ')'
+ | CHECK '(' a_expr ')'
{
Constraint *n = makeNode(Constraint);
n->contype = CONSTR_CHECK;
n->keys = NULL;
$$ = (Node *)n;
}
- | REFERENCES ColId opt_column_list
- key_match key_actions ConstraintAttribute
+ | DEFAULT NULL_P
{
- FkConstraint *n = makeNode(FkConstraint);
- n->constr_name = NULL;
- n->pktable_name = $2;
- n->fk_attrs = NIL;
- n->pk_attrs = $3;
- n->match_type = $4;
- n->actions = $5;
- n->deferrable = (($6 & 1) != 0);
- n->initdeferred = (($6 & 2) != 0);
+ Constraint *n = makeNode(Constraint);
+ n->contype = CONSTR_DEFAULT;
+ n->name = NULL;
+ n->raw_expr = NULL;
+ n->cooked_expr = NULL;
+ n->keys = NULL;
$$ = (Node *)n;
}
- | REFERENCES ColId opt_column_list
- key_match key_actions
+ | DEFAULT b_expr
+ {
+ Constraint *n = makeNode(Constraint);
+ n->contype = CONSTR_DEFAULT;
+ n->name = NULL;
+ n->raw_expr = $2;
+ n->cooked_expr = NULL;
+ n->keys = NULL;
+ $$ = (Node *)n;
+ }
+ | REFERENCES ColId opt_column_list key_match key_actions
{
FkConstraint *n = makeNode(FkConstraint);
n->constr_name = NULL;
n->pk_attrs = $3;
n->match_type = $4;
n->actions = $5;
- n->deferrable = true;
+ n->deferrable = false;
n->initdeferred = false;
$$ = (Node *)n;
}
;
-PrimaryKey: PRIMARY KEY
+/*
+ * ConstraintAttr represents constraint attributes, which we parse as if
+ * they were independent constraint clauses, in order to avoid shift/reduce
+ * conflicts (since NOT might start either an independent NOT NULL clause
+ * or an attribute). analyze.c is responsible for attaching the attribute
+ * information to the preceding "real" constraint node, and for complaining
+ * if attribute clauses appear in the wrong place or wrong combinations.
+ *
+ * See also ConstraintAttributeSpec, which can be used in places where
+ * there is no parsing conflict.
+ */
+ConstraintAttr: DEFERRABLE
{
Constraint *n = makeNode(Constraint);
- n->contype = CONSTR_PRIMARY;
- n->name = NULL;
- n->raw_expr = NULL;
- n->cooked_expr = NULL;
- n->keys = NULL;
+ n->contype = CONSTR_ATTR_DEFERRABLE;
$$ = (Node *)n;
}
- ;
-
-NotNull: NOT NULL_P
+ | NOT DEFERRABLE
{
Constraint *n = makeNode(Constraint);
- n->contype = CONSTR_NOTNULL;
- n->name = NULL;
- n->raw_expr = NULL;
- n->cooked_expr = NULL;
- n->keys = NULL;
+ n->contype = CONSTR_ATTR_NOT_DEFERRABLE;
+ $$ = (Node *)n;
+ }
+ | INITIALLY DEFERRED
+ {
+ Constraint *n = makeNode(Constraint);
+ n->contype = CONSTR_ATTR_DEFERRED;
+ $$ = (Node *)n;
+ }
+ | INITIALLY IMMEDIATE
+ {
+ Constraint *n = makeNode(Constraint);
+ n->contype = CONSTR_ATTR_IMMEDIATE;
$$ = (Node *)n;
}
+ ;
+
/* ConstraintElem specifies constraint syntax which is not embedded into
* a column definition. ColConstraintElem specifies the embedded form.
case T_Constraint:
{
Constraint *n = (Constraint *)$3;
- if (n != NULL) n->name = $2;
+ n->name = $2;
}
break;
case T_FkConstraint:
{
FkConstraint *n = (FkConstraint *)$3;
- if (n != NULL) n->constr_name = $2;
+ n->constr_name = $2;
}
break;
default:
n->keys = $3;
$$ = (Node *)n;
}
- | PrimaryKey '(' columnList ')'
+ | PRIMARY KEY '(' columnList ')'
{
- Constraint *n = (Constraint *)$1;
- n->keys = $3;
+ Constraint *n = makeNode(Constraint);
+ n->contype = CONSTR_PRIMARY;
+ n->name = NULL;
+ n->raw_expr = NULL;
+ n->cooked_expr = NULL;
+ n->keys = $4;
$$ = (Node *)n;
}
| FOREIGN KEY '(' columnList ')' REFERENCES ColId opt_column_list
- key_match key_actions ConstraintAttribute
+ key_match key_actions ConstraintAttributeSpec
{
FkConstraint *n = makeNode(FkConstraint);
n->constr_name = NULL;
n->initdeferred = ($11 & 2) != 0;
$$ = (Node *)n;
}
- | FOREIGN KEY '(' columnList ')' REFERENCES ColId opt_column_list
- key_match key_actions
- {
- FkConstraint *n = makeNode(FkConstraint);
- n->constr_name = NULL;
- n->pktable_name = $7;
- n->fk_attrs = $4;
- n->pk_attrs = $8;
- n->match_type = $9;
- n->actions = $10;
- n->deferrable = false;
- n->initdeferred = false;
- $$ = (Node *)n;
- }
;
key_match: MATCH FULL
}
| CREATE CONSTRAINT TRIGGER name AFTER TriggerEvents ON
relation_name OptConstrFromTable
- ConstraintAttribute
+ ConstraintAttributeSpec
FOR EACH ROW EXECUTE PROCEDURE name '(' TriggerFuncArgs ')'
{
CreateTrigStmt *n = makeNode(CreateTrigStmt);
}
;
-ConstraintAttribute: DeferrabilityClause
+ConstraintAttributeSpec: ConstraintDeferrabilitySpec
+ { $$ = $1; }
+ | ConstraintDeferrabilitySpec ConstraintTimeSpec
{
- $$ = $1;
+ if ($1 == 0 && $2 != 0)
+ elog(ERROR, "INITIALLY DEFERRED constraint must be DEFERRABLE");
+ $$ = $1 | $2;
}
- | TimeClause
+ | ConstraintTimeSpec
{
if ($1 != 0)
$$ = 3;
else
$$ = 0;
}
- | DeferrabilityClause TimeClause
- {
- if ($1 == 0 && $2 != 0)
- elog(ERROR, "INITIALLY DEFERRED constraint must be DEFERRABLE");
- $$ = $1 | $2;
- }
- | TimeClause DeferrabilityClause
+ | ConstraintTimeSpec ConstraintDeferrabilitySpec
{
if ($2 == 0 && $1 != 0)
elog(ERROR, "INITIALLY DEFERRED constraint must be DEFERRABLE");
$$ = $1 | $2;
}
+ | /* Empty */
+ { $$ = 0; }
;
-DeferrabilityClause: DEFERRABLE { $$ = 1; }
- | NOT DEFERRABLE { $$ = 0; }
+ConstraintDeferrabilitySpec: NOT DEFERRABLE
+ { $$ = 0; }
+ | DEFERRABLE
+ { $$ = 1; }
;
-TimeClause: INITIALLY IMMEDIATE { $$ = 0; }
- | INITIALLY DEFERRED { $$ = 2; }
+ConstraintTimeSpec: INITIALLY IMMEDIATE
+ { $$ = 0; }
+ | INITIALLY DEFERRED
+ { $$ = 2; }
;
;
/* easy way to return two values. Can someone improve this? bjm */
-result: INTO OptTemp opt_table relation_name { $$ = lcons(makeInteger($2), (List *)$4); }
- | /*EMPTY*/ { $$ = lcons(makeInteger(false), NIL); }
+result: INTO OptTempTableName { $$ = $2; }
+ | /*EMPTY*/ { $$ = lcons(makeInteger(false), NIL); }
+ ;
+
+/*
+ * Redundancy here is needed to avoid shift/reduce conflicts,
+ * since TEMP is not a reserved word. See also OptTemp.
+ *
+ * The result is a cons cell (not a true list!) containing
+ * a boolean and a table name.
+ */
+OptTempTableName: TEMPORARY opt_table relation_name
+ { $$ = lcons(makeInteger(TRUE), (List *) $3); }
+ | TEMP opt_table relation_name
+ { $$ = lcons(makeInteger(TRUE), (List *) $3); }
+ | LOCAL TEMPORARY opt_table relation_name
+ { $$ = lcons(makeInteger(TRUE), (List *) $4); }
+ | LOCAL TEMP opt_table relation_name
+ { $$ = lcons(makeInteger(TRUE), (List *) $4); }
+ | GLOBAL TEMPORARY opt_table relation_name
+ {
+ elog(ERROR, "GLOBAL TEMPORARY TABLE is not currently supported");
+ $$ = lcons(makeInteger(TRUE), (List *) $4);
+ }
+ | GLOBAL TEMP opt_table relation_name
+ {
+ elog(ERROR, "GLOBAL TEMPORARY TABLE is not currently supported");
+ $$ = lcons(makeInteger(TRUE), (List *) $4);
+ }
+ | TABLE relation_name
+ { $$ = lcons(makeInteger(FALSE), (List *) $2); }
+ | relation_name
+ { $$ = lcons(makeInteger(FALSE), (List *) $1); }
;
opt_table: TABLE { $$ = TRUE; }
| CREATEUSER { $$ = "createuser"; }
| CYCLE { $$ = "cycle"; }
| DATABASE { $$ = "database"; }
- | DEFERRABLE { $$ = "deferrable"; }
| DEFERRED { $$ = "deferred"; }
| DELIMITERS { $$ = "delimiters"; }
| DOUBLE { $$ = "double"; }
| INCREMENT { $$ = "increment"; }
| INDEX { $$ = "index"; }
| INHERITS { $$ = "inherits"; }
- | INITIALLY { $$ = "initially"; }
| INSENSITIVE { $$ = "insensitive"; }
| INSTEAD { $$ = "instead"; }
| INTERVAL { $$ = "interval"; }
| STDIN { $$ = "stdin"; }
| STDOUT { $$ = "stdout"; }
| SYSID { $$ = "sysid"; }
+ | TEMP { $$ = "temp"; }
+ | TEMPORARY { $$ = "temporary"; }
| TIME { $$ = "time"; }
| TIMESTAMP { $$ = "timestamp"; }
| TIMEZONE_HOUR { $$ = "timezone_hour"; }
| CURRENT_USER { $$ = "current_user"; }
| DEC { $$ = "dec"; }
| DECIMAL { $$ = "decimal"; }
+ | DEFERRABLE { $$ = "deferrable"; }
| DO { $$ = "do"; }
| ELSE { $$ = "else"; }
| END_TRANS { $$ = "end"; }
| FOREIGN { $$ = "foreign"; }
| GLOBAL { $$ = "global"; }
| GROUP { $$ = "group"; }
+ | INITIALLY { $$ = "initially"; }
| LISTEN { $$ = "listen"; }
| LOAD { $$ = "load"; }
| LOCAL { $$ = "local"; }