aboutsummaryrefslogtreecommitdiff
path: root/src/backend/commands/creatinh.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>1999-10-03 23:55:40 +0000
committerTom Lane <tgl@sss.pgh.pa.us>1999-10-03 23:55:40 +0000
commiteabc714a916b772650c97b065ef27767dc5942e4 (patch)
tree9271817f0a846e303ae8d32338b1d58a5c2754d5 /src/backend/commands/creatinh.c
parentf29ccc827006d13be0f4bf0255b06f3c4e921709 (diff)
downloadpostgresql-eabc714a916b772650c97b065ef27767dc5942e4.tar.gz
postgresql-eabc714a916b772650c97b065ef27767dc5942e4.zip
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.
Diffstat (limited to 'src/backend/commands/creatinh.c')
-rw-r--r--src/backend/commands/creatinh.c166
1 files changed, 112 insertions, 54 deletions
diff --git a/src/backend/commands/creatinh.c b/src/backend/commands/creatinh.c
index c146afa1db4..0b2d2360b3c 100644
--- a/src/backend/commands/creatinh.c
+++ b/src/backend/commands/creatinh.c
@@ -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);
}
}