Commit eabc714a authored by Tom Lane's avatar Tom Lane

Reimplement parsing and storage of default expressions and constraint

expressions in CREATE TABLE.  There is no longer an emasculated expression
syntax for these things; it's full a_expr for constraints, and b_expr
for defaults (unfortunately the fact that NOT NULL is a part of the
column constraint syntax causes a shift/reduce conflict if you try a_expr.
Oh well --- at least parenthesized boolean expressions work now).  Also,
stored expression for a column default is not pre-coerced to the column
type; we rely on transformInsertStatement to do that when the default is
actually used.  This means "f1 datetime default 'now'" behaves the way
people usually expect it to.
BTW, all the support code is now there to implement ALTER TABLE ADD
CONSTRAINT and ALTER TABLE ADD COLUMN with a default value.  I didn't
actually teach ALTER TABLE to call it, but it wouldn't be much work.
parent f29ccc82
......@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/common/tupdesc.c,v 1.54 1999/07/17 20:16:36 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/access/common/tupdesc.c,v 1.55 1999/10/03 23:55:25 tgl Exp $
*
* NOTES
* some of the executor utility code such as "ExecTypeFromTL" should be
......@@ -160,8 +160,6 @@ CreateTupleDescCopyConstr(TupleDesc tupdesc)
{
if (constr->defval[i].adbin)
cpy->defval[i].adbin = pstrdup(constr->defval[i].adbin);
if (constr->defval[i].adsrc)
cpy->defval[i].adsrc = pstrdup(constr->defval[i].adsrc);
}
}
......@@ -175,8 +173,6 @@ CreateTupleDescCopyConstr(TupleDesc tupdesc)
cpy->check[i].ccname = pstrdup(constr->check[i].ccname);
if (constr->check[i].ccbin)
cpy->check[i].ccbin = pstrdup(constr->check[i].ccbin);
if (constr->check[i].ccsrc)
cpy->check[i].ccsrc = pstrdup(constr->check[i].ccsrc);
}
}
......@@ -206,8 +202,6 @@ FreeTupleDesc(TupleDesc tupdesc)
{
if (attrdef[i].adbin)
pfree(attrdef[i].adbin);
if (attrdef[i].adsrc)
pfree(attrdef[i].adsrc);
}
pfree(attrdef);
}
......@@ -221,8 +215,6 @@ FreeTupleDesc(TupleDesc tupdesc)
pfree(check[i].ccname);
if (check[i].ccbin)
pfree(check[i].ccbin);
if (check[i].ccsrc)
pfree(check[i].ccsrc);
}
pfree(check);
}
......@@ -438,7 +430,7 @@ BuildDescForRelation(List *schema, char *relname)
AttrDefault *attrdef = NULL;
TupleConstr *constr = (TupleConstr *) palloc(sizeof(TupleConstr));
char *attname;
char *typename;
char typename[NAMEDATALEN];
int32 atttypmod;
int attdim;
int ndef = 0;
......@@ -454,11 +446,9 @@ BuildDescForRelation(List *schema, char *relname)
attnum = 0;
typename = palloc(NAMEDATALEN);
foreach(p, schema)
{
ColumnDef *entry;
ColumnDef *entry = lfirst(p);
List *arry;
/* ----------------
......@@ -469,7 +459,6 @@ BuildDescForRelation(List *schema, char *relname)
*/
attnum++;
entry = lfirst(p);
attname = entry->colname;
arry = entry->typename->arrayBounds;
attisset = entry->typename->setof;
......@@ -513,13 +502,15 @@ BuildDescForRelation(List *schema, char *relname)
constr->has_not_null = true;
desc->attrs[attnum - 1]->attnotnull = entry->is_not_null;
if (entry->defval != NULL)
/* Note we copy only pre-cooked default expressions.
* Digestion of raw ones is someone else's problem.
*/
if (entry->cooked_default != NULL)
{
if (attrdef == NULL)
attrdef = (AttrDefault *) palloc(natts * sizeof(AttrDefault));
attrdef[ndef].adnum = attnum;
attrdef[ndef].adbin = NULL;
attrdef[ndef].adsrc = entry->defval;
attrdef[ndef].adbin = pstrdup(entry->cooked_default);
ndef++;
desc->attrs[attnum - 1]->atthasdef = true;
}
......@@ -539,7 +530,11 @@ BuildDescForRelation(List *schema, char *relname)
constr->num_defval = ndef;
}
else
{
constr->defval = NULL;
constr->num_defval = 0;
}
constr->check = NULL;
constr->num_check = 0;
}
else
......
This diff is collapsed.
......@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.54 1999/09/18 19:06:40 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.55 1999/10/03 23:55:27 tgl Exp $
*
* NOTES
* The PortalExecutorHeapMemory crap needs to be eliminated
......@@ -324,7 +324,7 @@ PerformAddAttribute(char *relationName,
*/
if (colDef->is_not_null)
elog(ERROR, "Can't add a NOT NULL attribute to an existing relation");
if (colDef->defval)
if (colDef->raw_default || colDef->cooked_default)
elog(ERROR, "ADD ATTRIBUTE: DEFAULT not yet implemented");
/*
......@@ -457,7 +457,8 @@ PerformAddAttribute(char *relationName,
attribute->attisset = (bool) (tform->typtype == 'c');
attribute->attalign = tform->typalign;
attribute->attnotnull = false;
attribute->atthasdef = (colDef->defval != NULL);
attribute->atthasdef = (colDef->raw_default != NULL ||
colDef->cooked_default != NULL);
heap_insert(attrdesc, attributeTuple);
if (hasindex)
......
......@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/creatinh.c,v 1.47 1999/09/23 17:02:40 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/creatinh.c,v 1.48 1999/10/03 23:55:27 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -45,15 +45,19 @@ DefineRelation(CreateStmt *stmt, char relkind)
List *schema = stmt->tableElts;
int numberOfAttributes;
Oid relationId;
List *inheritList = NULL;
Relation rel;
List *inheritList;
TupleDesc descriptor;
List *constraints;
List *old_constraints;
List *rawDefaults;
List *listptr;
int i;
AttrNumber attnum;
if (strlen(stmt->relname) >= NAMEDATALEN)
elog(ERROR, "the relation name %s is >= %d characters long", stmt->relname,
NAMEDATALEN);
StrNCpy(relname, stmt->relname, NAMEDATALEN); /* make full length for
* copy */
elog(ERROR, "the relation name %s is >= %d characters long",
stmt->relname, NAMEDATALEN);
StrNCpy(relname, stmt->relname, NAMEDATALEN);
/* ----------------
* Handle parameters
......@@ -66,8 +70,7 @@ DefineRelation(CreateStmt *stmt, char relkind)
* generate relation schema, including inherited attributes.
* ----------------
*/
schema = MergeAttributes(schema, inheritList, &constraints);
constraints = nconc(constraints, stmt->constraints);
schema = MergeAttributes(schema, inheritList, &old_constraints);
numberOfAttributes = length(schema);
if (numberOfAttributes <= 0)
......@@ -78,53 +81,53 @@ DefineRelation(CreateStmt *stmt, char relkind)
/* ----------------
* create a relation descriptor from the relation schema
* and create the relation.
* and create the relation. Note that in this stage only
* inherited (pre-cooked) defaults and constraints will be
* included into the new relation. (BuildDescForRelation
* takes care of the inherited defaults, but we have to copy
* inherited constraints here.)
* ----------------
*/
descriptor = BuildDescForRelation(schema, relname);
if (constraints != NIL)
if (old_constraints != NIL)
{
List *entry;
int nconstr = length(constraints),
ncheck = 0,
i;
ConstrCheck *check = (ConstrCheck *) palloc(nconstr * sizeof(ConstrCheck));
ConstrCheck *check = (ConstrCheck *) palloc(length(old_constraints) *
sizeof(ConstrCheck));
int ncheck = 0;
foreach(entry, constraints)
foreach(listptr, old_constraints)
{
Constraint *cdef = (Constraint *) lfirst(entry);
Constraint *cdef = (Constraint *) lfirst(listptr);
if (cdef->contype == CONSTR_CHECK)
if (cdef->contype != CONSTR_CHECK)
continue;
if (cdef->name != NULL)
{
if (cdef->name != NULL)
{
for (i = 0; i < ncheck; i++)
{
if (strcmp(check[i].ccname, cdef->name) == 0)
elog(ERROR,
"DefineRelation: name (%s) of CHECK constraint duplicated",
cdef->name);
}
check[ncheck].ccname = cdef->name;
}
else
for (i = 0; i < ncheck; i++)
{
check[ncheck].ccname = (char *) palloc(NAMEDATALEN);
snprintf(check[ncheck].ccname, NAMEDATALEN, "$%d", ncheck + 1);
if (strcmp(check[i].ccname, cdef->name) == 0)
elog(ERROR, "Duplicate CHECK constraint name: '%s'",
cdef->name);
}
check[ncheck].ccbin = NULL;
check[ncheck].ccsrc = (char *) cdef->def;
ncheck++;
check[ncheck].ccname = cdef->name;
}
else
{
check[ncheck].ccname = (char *) palloc(NAMEDATALEN);
snprintf(check[ncheck].ccname, NAMEDATALEN, "$%d", ncheck + 1);
}
Assert(cdef->raw_expr == NULL && cdef->cooked_expr != NULL);
check[ncheck].ccbin = pstrdup(cdef->cooked_expr);
ncheck++;
}
if (ncheck > 0)
{
if (ncheck < nconstr)
check = (ConstrCheck *) repalloc(check, ncheck * sizeof(ConstrCheck));
if (descriptor->constr == NULL)
{
descriptor->constr = (TupleConstr *) palloc(sizeof(TupleConstr));
descriptor->constr->defval = NULL;
descriptor->constr->num_defval = 0;
descriptor->constr->has_not_null = false;
}
......@@ -137,6 +140,61 @@ DefineRelation(CreateStmt *stmt, char relkind)
relkind, stmt->istemp);
StoreCatalogInheritance(relationId, inheritList);
/*
* Now add any newly specified column default values
* and CHECK constraints to the new relation. These are passed
* to us in the form of raw parsetrees; we need to transform
* them to executable expression trees before they can be added.
* The most convenient way to do that is to apply the parser's
* transformExpr routine, but transformExpr doesn't work unless
* we have a pre-existing relation. So, the transformation has
* to be postponed to this final step of CREATE TABLE.
*
* First, scan schema to find new column defaults.
*/
rawDefaults = NIL;
attnum = 0;
foreach(listptr, schema)
{
ColumnDef *colDef = lfirst(listptr);
RawColumnDefault *rawEnt;
attnum++;
if (colDef->raw_default == NULL)
continue;
Assert(colDef->cooked_default == NULL);
rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
rawEnt->attnum = attnum;
rawEnt->raw_default = colDef->raw_default;
rawDefaults = lappend(rawDefaults, rawEnt);
}
/* If no raw defaults and no constraints, nothing to do. */
if (rawDefaults == NIL && stmt->constraints == NIL)
return;
/*
* We must bump the command counter to make the newly-created
* relation tuple visible for opening.
*/
CommandCounterIncrement();
/*
* Open the new relation.
*/
rel = heap_openr(relname, AccessExclusiveLock);
/*
* Parse and add the defaults/constraints.
*/
AddRelationRawConstraints(rel, rawDefaults, stmt->constraints);
/*
* Clean up. We keep lock on new relation (although it shouldn't
* be visible to anyone else anyway, until commit).
*/
heap_close(rel, NoLock);
}
/*
......@@ -164,18 +222,14 @@ RemoveRelation(char *name)
* Exceptions:
* BadArg if name is invalid
*
*
* Note:
* Rows are removed, indices are truncated and reconstructed.
*/
void
TruncateRelation(char *name)
{
AssertArg(name);
heap_truncate(name);
AssertArg(name);
heap_truncate(name);
}
/*
......@@ -316,22 +370,25 @@ MergeAttributes(List *schema, List *supers, List **supconstr)
typename->typmod = attribute->atttypmod;
def->typename = typename;
def->is_not_null = attribute->attnotnull;
def->defval = NULL;
def->raw_default = NULL;
def->cooked_default = NULL;
if (attribute->atthasdef)
{
AttrDefault *attrdef = constr->defval;
AttrDefault *attrdef;
int i;
Assert(constr != NULL && constr->num_defval > 0);
Assert(constr != NULL);
attrdef = constr->defval;
for (i = 0; i < constr->num_defval; i++)
{
if (attrdef[i].adnum != attrno + 1)
continue;
def->defval = pstrdup(attrdef[i].adsrc);
break;
if (attrdef[i].adnum == attrno + 1)
{
def->cooked_default = pstrdup(attrdef[i].adbin);
break;
}
}
Assert(def->defval != NULL);
Assert(def->cooked_default != NULL);
}
partialResult = lcons(def, partialResult);
}
......@@ -343,14 +400,15 @@ MergeAttributes(List *schema, List *supers, List **supconstr)
for (i = 0; i < constr->num_check; i++)
{
Constraint *cdef = (Constraint *) makeNode(Constraint);
Constraint *cdef = makeNode(Constraint);
cdef->contype = CONSTR_CHECK;
if (check[i].ccname[0] == '$')
cdef->name = NULL;
else
cdef->name = pstrdup(check[i].ccname);
cdef->def = (void *) pstrdup(check[i].ccsrc);
cdef->raw_expr = NULL;
cdef->cooked_expr = pstrdup(check[i].ccbin);
constraints = lappend(constraints, cdef);
}
}
......
......@@ -96,7 +96,8 @@ DefineSequence(CreateSeqStmt *seq)
typnam->typmod = -1;
coldef = makeNode(ColumnDef);
coldef->typename = typnam;
coldef->defval = NULL;
coldef->raw_default = NULL;
coldef->cooked_default = NULL;
coldef->is_not_null = false;
null[i - 1] = ' ';
......
......@@ -5,7 +5,7 @@
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: view.c,v 1.37 1999/07/17 20:16:54 momjian Exp $
* $Id: view.c,v 1.38 1999/10/03 23:55:27 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -76,7 +76,8 @@ DefineVirtualRelation(char *relname, List *tlist)
def->typename = typename;
def->is_not_null = false;
def->defval = (char *) NULL;
def->raw_default = NULL;
def->cooked_default = NULL;
attrList = lappend(attrList, def);
}
......
......@@ -5,7 +5,7 @@
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: outfuncs.c,v 1.95 1999/08/31 01:28:32 tgl Exp $
* $Id: outfuncs.c,v 1.96 1999/10/03 23:55:29 tgl Exp $
*
* NOTES
* Every (plan) node in POSTGRES has an associated "out" routine which
......@@ -124,10 +124,12 @@ _outColumnDef(StringInfo str, ColumnDef *node)
appendStringInfo(str, " COLUMNDEF :colname %s :typename ",
stringStringInfo(node->colname));
_outNode(str, node->typename);
appendStringInfo(str, " :is_not_null %s :defval %s :constraints ",
appendStringInfo(str, " :is_not_null %s :is_sequence %s :raw_default ",
node->is_not_null ? "true" : "false",
stringStringInfo(node->defval));
node->is_sequence ? "true" : "false");
_outNode(str, node->raw_default);
appendStringInfo(str, " :cooked_default %s :constraints ",
stringStringInfo(node->cooked_default));
_outNode(str, node->constraints);
}
......@@ -1216,11 +1218,17 @@ _outConstraint(StringInfo str, Constraint *node)
break;
case CONSTR_CHECK:
appendStringInfo(str, " CHECK %s", stringStringInfo(node->def));
appendStringInfo(str, " CHECK :raw ");
_outNode(str, node->raw_expr);
appendStringInfo(str, " :cooked %s ",
stringStringInfo(node->cooked_expr));
break;
case CONSTR_DEFAULT:
appendStringInfo(str, " DEFAULT %s", stringStringInfo(node->def));
appendStringInfo(str, " DEFAULT :raw ");
_outNode(str, node->raw_expr);
appendStringInfo(str, " :cooked %s ",
stringStringInfo(node->cooked_expr));
break;
case CONSTR_NOTNULL:
......@@ -1236,7 +1244,6 @@ _outConstraint(StringInfo str, Constraint *node)
appendStringInfo(str, "<unrecognized constraint>");
break;
}
return;
}
static void
......
......@@ -5,7 +5,7 @@
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: analyze.c,v 1.119 1999/09/18 19:07:12 tgl Exp $
* $Id: analyze.c,v 1.120 1999/10/03 23:55:30 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -396,7 +396,7 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
if (namestrcmp(&(thisatt->attname), resnode->resname) == 0)
break;
}
if (tl != NIL) /* something given for this attr */
if (tl != NIL) /* found TLE for this attr */
continue;
/*
* No user-supplied value, so add a targetentry with DEFAULT expr
......@@ -573,7 +573,6 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
q = makeNode(Query);
q->commandType = CMD_UTILITY;
elements = stmt->tableElts;
constraints = stmt->constraints;
columns = NIL;
dlist = NIL;
......@@ -581,7 +580,7 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
/*
* Run through each primary element in the table creation clause
*/
while (elements != NIL)
foreach(elements, stmt->tableElts)
{
element = lfirst(elements);
switch (nodeTag(element))
......@@ -594,19 +593,31 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
if (column->is_sequence)
{
char *sname;
char *cstring;
char *qstring;
A_Const *snamenode;
FuncCall *funccallnode;
CreateSeqStmt *sequence;
sname = makeObjectName(stmt->relname, column->colname,
"seq");
/*
* Create an expression tree representing the function
* call nextval('"sequencename"')
*/
qstring = palloc(strlen(sname) + 2 + 1);
sprintf(qstring, "\"%s\"", sname);
snamenode = makeNode(A_Const);
snamenode->val.type = T_String;
snamenode->val.val.str = qstring;
funccallnode = makeNode(FuncCall);
funccallnode->funcname = "nextval";
funccallnode->args = lcons(snamenode, NIL);
constraint = makeNode(Constraint);
constraint->contype = CONSTR_DEFAULT;
constraint->name = sname;
cstring = palloc(10 + strlen(constraint->name) + 3 + 1);
strcpy(cstring, "nextval('\"");
strcat(cstring, constraint->name);
strcat(cstring, "\"')");
constraint->def = cstring;
constraint->raw_expr = (Node *) funccallnode;
constraint->cooked_expr = NULL;
constraint->keys = NULL;
column->constraints = lappend(column->constraints, constraint);
......@@ -628,69 +639,65 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
blist = lcons(sequence, NIL);
}
/* Check for column constraints, if any... */
if (column->constraints != NIL)
/* Process column constraints, if any... */
foreach(clist, column->constraints)
{
clist = column->constraints;
while (clist != NIL)
constraint = lfirst(clist);
switch (constraint->contype)
{
constraint = lfirst(clist);
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)
elog(ERROR, "CREATE TABLE/(NOT) NULL conflicting declaration"
" for '%s.%s'", stmt->relname, column->colname);
column->is_not_null = FALSE;
break;
case CONSTR_NOTNULL:
if (column->is_not_null)
elog(ERROR, "CREATE TABLE/NOT NULL already specified"
" for '%s.%s'", stmt->relname, column->colname);
column->is_not_null = TRUE;
break;
case CONSTR_DEFAULT:
if (column->defval != NULL)
elog(ERROR, "CREATE TABLE/DEFAULT multiple values specified"
" for '%s.%s'", stmt->relname, column->colname);
column->defval = constraint->def;
break;
case CONSTR_PRIMARY:
if (constraint->name == NULL)
constraint->name = makeObjectName(stmt->relname, NULL, "pkey");
if (constraint->keys == NIL)
constraint->keys = lappend(constraint->keys, column);
dlist = lappend(dlist, constraint);
break;
case CONSTR_UNIQUE:
if (constraint->name == NULL)
constraint->name = makeObjectName(stmt->relname, column->colname, "key");
if (constraint->keys == NIL)
constraint->keys = lappend(constraint->keys, column);
dlist = lappend(dlist, constraint);
break;
case CONSTR_CHECK:
constraints = lappend(constraints, constraint);
if (constraint->name == NULL)
constraint->name = makeObjectName(stmt->relname, column->colname, NULL);
break;
default:
elog(ERROR, "parser: unrecognized constraint (internal error)", NULL);
break;
}
clist = lnext(clist);
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)
elog(ERROR, "CREATE TABLE/(NOT) NULL conflicting declaration"
" for '%s.%s'", stmt->relname, column->colname);
column->is_not_null = FALSE;
break;
case CONSTR_NOTNULL:
if (column->is_not_null)
elog(ERROR, "CREATE TABLE/NOT NULL already specified"
" for '%s.%s'", stmt->relname, column->colname);
column->is_not_null = TRUE;
break;
case CONSTR_DEFAULT:
if (column->raw_default != NULL)
elog(ERROR, "CREATE TABLE/DEFAULT multiple values specified"
" for '%s.%s'", stmt->relname, column->colname);
column->raw_default = constraint->raw_expr;
Assert(constraint->cooked_expr == NULL);
break;
case CONSTR_PRIMARY:
if (constraint->name == NULL)
constraint->name = makeObjectName(stmt->relname, NULL, "pkey");
if (constraint->keys == NIL)
constraint->keys = lappend(constraint->keys, column);
dlist = lappend(dlist, constraint);
break;
case CONSTR_UNIQUE:
if (constraint->name == NULL)
constraint->name = makeObjectName(stmt->relname, column->colname, "key");
if (constraint->keys == NIL)
constraint->keys = lappend(constraint->keys, column);
dlist = lappend(dlist, constraint);
break;
case CONSTR_CHECK:
if (constraint->name == NULL)
constraint->name = makeObjectName(stmt->relname, column->colname, NULL);
constraints = lappend(constraints, constraint);
break;
default:
elog(ERROR, "parser: unrecognized constraint (internal error)", NULL);
break;
}
}
break;
......@@ -715,19 +722,17 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
case CONSTR_NOTNULL:
case CONSTR_DEFAULT:
elog(ERROR, "parser: illegal context for constraint (internal error)", NULL);
elog(ERROR, "parser: illegal context for constraint (internal error)");
break;
default:
elog(ERROR, "parser: unrecognized constraint (internal error)", NULL);
elog(ERROR, "parser: unrecognized constraint (internal error)");
break;
}
break;
default:
elog(ERROR, "parser: unrecognized node (internal error)", NULL);
elog(ERROR, "parser: unrecognized node (internal error)");
}
elements = lnext(elements);
}
stmt->tableElts = columns;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -6,7 +6,7 @@
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: tupdesc.h,v 1.24 1999/07/16 17:07:28 momjian Exp $
* $Id: tupdesc.h,v 1.25 1999/10/03 23:55:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -21,22 +21,20 @@
typedef struct attrDefault
{
AttrNumber adnum;
char *adbin;
char *adsrc;
char *adbin; /* nodeToString representation of expr */
} AttrDefault;
typedef struct constrCheck
{
char *ccname;
char *ccbin;
char *ccsrc;
char *ccbin; /* nodeToString representation of expr */
} ConstrCheck;
/* This structure contains constraints of a tuple */
typedef struct tupleConstr
{
AttrDefault *defval;
ConstrCheck *check;
AttrDefault *defval; /* array */
ConstrCheck *check; /* array */
uint16 num_defval;
uint16 num_check;
bool has_not_null;
......
......@@ -6,7 +6,7 @@
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: heap.h,v 1.21 1999/09/23 17:03:10 momjian Exp $
* $Id: heap.h,v 1.22 1999/10/03 23:55:35 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -15,6 +15,12 @@
#include "utils/rel.h"
typedef struct RawColumnDefault
{
AttrNumber attnum; /* attribute to attach default to */
Node *raw_default; /* default value (untransformed parse tree) */
} RawColumnDefault;
extern Oid RelnameFindRelid(char *relname);
extern Relation heap_create(char *relname, TupleDesc att,
bool isnoname, bool istemp);
......@@ -26,6 +32,10 @@ extern void heap_destroy_with_catalog(char *relname);
extern void heap_truncate(char *relname);
extern void heap_destroy(Relation rel);
extern void AddRelationRawConstraints(Relation rel,
List *rawColDefaults,
List *rawConstraints);
extern void InitNoNameRelList(void);
extern void DestroyNoNameRels(void);
......
......@@ -6,7 +6,7 @@
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: parsenodes.h,v 1.82 1999/10/02 21:33:33 tgl Exp $
* $Id: parsenodes.h,v 1.83 1999/10/03 23:55:36 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -140,25 +140,36 @@ typedef struct CreateStmt
{
NodeTag type;
bool istemp; /* is this a temp table? */
char *relname; /* the relation to create */
List *tableElts; /* column definitions list of Column */
List *inhRelnames; /* relations to inherit from list of Value
* (string) */
List *constraints; /* list of constraints (ConstaintDef) */
char *relname; /* name of relation to create */
List *tableElts; /* column definitions (list of ColumnDef) */
List *inhRelnames; /* relations to inherit from (list of
* T_String Values) */
List *constraints; /* list of constraints (Constraint nodes) */
} CreateStmt;
typedef enum ConstrType /* type of constaints */
typedef enum ConstrType /* types of constraints */
{
CONSTR_NULL, CONSTR_NOTNULL, CONSTR_DEFAULT, CONSTR_CHECK, CONSTR_PRIMARY, CONSTR_UNIQUE
CONSTR_NULL, CONSTR_NOTNULL, CONSTR_DEFAULT, CONSTR_CHECK,
CONSTR_PRIMARY, CONSTR_UNIQUE
} ConstrType;
/*
* For constraints that use expressions (CONSTR_DEFAULT, CONSTR_CHECK)
* 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!
*/
typedef struct Constraint
{
NodeTag type;
ConstrType contype;
char *name; /* name */
void *def; /* definition */
void *keys; /* list of primary keys */
Node *raw_expr; /* untransformed parse tree */
char *cooked_expr; /* nodeToString representation */
List *keys; /* list of primary keys */
} Constraint;
/* ----------------------
......@@ -790,6 +801,18 @@ typedef struct CaseWhen
/*
* ColumnDef - column definition (used in various creates)
*
* If the column has a default value, we may have the value expression
* in either "raw" form (an untransformed parse tree) or "cooked" form
* (the nodeToString representation of an executable expression tree),
* depending on how this ColumnDef node was created (by parsing, or by
* inheritance from an existing relation). We should never have both
* in the same node!
*
* The constraints list may contain a CONSTR_DEFAULT item in a raw
* parsetree produced by gram.y, but transformCreateStmt will remove
* the item and set raw_default instead. CONSTR_DEFAULT items
* should not appear in any subsequent processing.
*/
typedef struct ColumnDef
{
......@@ -798,8 +821,9 @@ typedef struct ColumnDef
TypeName *typename; /* type of column */
bool is_not_null; /* flag to NOT NULL constraint */
bool is_sequence; /* is a sequence? */
char *defval; /* default value of column */
List *constraints; /* constraints on column */
Node *raw_default; /* default value (untransformed parse tree) */
char *cooked_default; /* nodeToString representation */
List *constraints; /* other constraints on column */
} ColumnDef;
/*
......
......@@ -6,7 +6,7 @@
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: builtins.h,v 1.87 1999/09/30 14:54:24 wieck Exp $
* $Id: builtins.h,v 1.88 1999/10/03 23:55:37 tgl Exp $
*
* NOTES
* This should normally only be included by fmgr.h.
......@@ -372,6 +372,14 @@ extern Oid regproctooid(RegProcedure rp);
/* define macro to replace mixed-case function call - tgl 97/04/27 */
#define RegprocToOid(rp) regproctooid(rp)
/* ruleutils.c */
extern text *pg_get_ruledef(NameData *rname);
extern text *pg_get_viewdef(NameData *rname);
extern text *pg_get_indexdef(Oid indexrelid);
extern NameData *pg_get_userbyid(int32 uid);
extern char *deparse_expression(Node *expr, List *rangetables,
bool forceprefix);
/* selfuncs.c */
extern float64 eqsel(Oid opid, Oid relid, AttrNumber attno, Datum value, int32 flag);
extern float64 neqsel(Oid opid, Oid relid, AttrNumber attno, Datum value, int32 flag);
......
......@@ -6,7 +6,7 @@
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: relcache.h,v 1.14 1999/09/04 18:42:11 tgl Exp $
* $Id: relcache.h,v 1.15 1999/10/03 23:55:38 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -24,6 +24,12 @@ extern Relation RelationNameGetRelation(char *relationName);
extern void RelationClose(Relation relation);
extern void RelationForgetRelation(Oid rid);
/*
* Routines for flushing/rebuilding relcache entries in various scenarios
*/
extern void RelationRebuildRelation(Relation relation);
extern void RelationIdInvalidateRelationCacheByRelationId(Oid relationId);
extern void RelationIdInvalidateRelationCacheByAccessMethodId(Oid accessMethodId);
......
......@@ -34,12 +34,17 @@ INSERT INTO DEFAULTEXPR_TBL (i2) VALUES (NULL);
SELECT '' AS four, * FROM DEFAULTEXPR_TBL;
-- errors
-- test for:
-- extraneous comma
-- booleans not allowed
-- syntax errors
-- test for extraneous comma
CREATE TABLE error_tbl (i int DEFAULT (100, ));
-- this will fail because gram.y uses b_expr not a_expr for defaults,
-- to avoid a shift/reduce conflict that arises from NOT NULL being
-- part of the column definition syntax:
CREATE TABLE error_tbl (b1 bool DEFAULT 1 < 2);
-- this should work, however:
CREATE TABLE error_tbl (b1 bool DEFAULT (1 < 2));
DROP TABLE error_tbl;
--
-- CHECK syntax
......
......@@ -34,7 +34,9 @@ four| i1|i2
QUERY: CREATE TABLE error_tbl (i int DEFAULT (100, ));
ERROR: parser: parse error at or near ","
QUERY: CREATE TABLE error_tbl (b1 bool DEFAULT 1 < 2);
ERROR: boolean expressions not supported in DEFAULT
ERROR: parser: parse error at or near "<"
QUERY: CREATE TABLE error_tbl (b1 bool DEFAULT (1 < 2));
QUERY: DROP TABLE error_tbl;
QUERY: CREATE TABLE CHECK_TBL (x int,
CONSTRAINT CHECK_CON CHECK (x > 3));
QUERY: INSERT INTO CHECK_TBL VALUES (5);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment