diff --git a/doc/src/sgml/ref/create_domain.sgml b/doc/src/sgml/ref/create_domain.sgml
index 488f86811c..0d44434b3e 100644
--- a/doc/src/sgml/ref/create_domain.sgml
+++ b/doc/src/sgml/ref/create_domain.sgml
@@ -1,5 +1,5 @@
@@ -30,7 +30,7 @@ CREATE DOMAIN domainname [AS] constraint is:
[ CONSTRAINT constraint_name ]
-{ NOT NULL | NULL }
+{ NOT NULL | NULL | CHECK (expression) }
@@ -128,6 +128,25 @@ where constraint is:
+
+ CHECK (expression)
+
+
+ CHECK> clauses specify integrity constraints or tests
+ which values of the domain must satisfy.
+ Each constraint must be an expression
+ producing a Boolean result. It should use the name VALUE>
+ to refer to the value being tested.
+
+
+
+ Currently, CHECK expressions cannot contain
+ subselects nor refer to variables other than VALUE>.
+
+
+
+
+
diff --git a/doc/src/sgml/release.sgml b/doc/src/sgml/release.sgml
index b43db923e2..ce54952e02 100644
--- a/doc/src/sgml/release.sgml
+++ b/doc/src/sgml/release.sgml
@@ -1,5 +1,5 @@
@@ -24,6 +24,7 @@ CDATA means the content is "SGML-free", so you can write without
worries about funny characters.
-->
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index bd068271ac..424684d74d 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.236 2002/12/12 15:49:23 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.237 2002/12/12 20:35:08 tgl Exp $
*
*
* INTERFACE ROUTINES
@@ -1567,7 +1567,7 @@ AddRelationRawConstraints(Relation rel,
/*
* Transform raw parsetree to executable expression.
*/
- expr = transformExpr(pstate, cdef->raw_expr, NULL);
+ expr = transformExpr(pstate, cdef->raw_expr);
/*
* Make sure it yields a boolean result.
@@ -1691,7 +1691,7 @@ cookDefault(ParseState *pstate,
/*
* Transform raw parsetree to executable expression.
*/
- expr = transformExpr(pstate, raw_default, NULL);
+ expr = transformExpr(pstate, raw_default);
/*
* Make sure default expr does not refer to any vars.
diff --git a/src/backend/catalog/pg_constraint.c b/src/backend/catalog/pg_constraint.c
index 8c274caf3b..e724034969 100644
--- a/src/backend/catalog/pg_constraint.c
+++ b/src/backend/catalog/pg_constraint.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/catalog/pg_constraint.c,v 1.11 2002/12/06 05:00:10 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/catalog/pg_constraint.c,v 1.12 2002/12/12 20:35:11 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -439,18 +439,16 @@ RemoveConstraintById(Oid conId)
con = (Form_pg_constraint) GETSTRUCT(tup);
/*
- * If the constraint is for a relation, open and exclusive-lock
- * the relation it's for.
- *
- * If the constraint is for a domain, open and lock the pg_type entry
- * tye constraint is used on.
- *
- * XXX not clear what we should lock, if anything, for assert constraints.
+ * Special processing depending on what the constraint is for.
*/
if (OidIsValid(con->conrelid))
{
Relation rel;
+ /*
+ * If the constraint is for a relation, open and exclusive-lock the
+ * relation it's for.
+ */
rel = heap_open(con->conrelid, AccessExclusiveLock);
/*
@@ -490,34 +488,14 @@ RemoveConstraintById(Oid conId)
/* Keep lock on constraint's rel until end of xact */
heap_close(rel, NoLock);
}
- /* Lock the domain row in pg_type */
else if (OidIsValid(con->contypid))
{
- Relation typRel;
- HeapTuple typTup;
- ScanKeyData typKey[1];
- SysScanDesc typScan;
- int nkeys = 0;
-
- typRel = heap_openr(TypeRelationName, RowExclusiveLock);
-
- ScanKeyEntryInitialize(&typKey[nkeys++], 0x0,
- ObjectIdAttributeNumber, F_OIDEQ,
- ObjectIdGetDatum(con->contypid));
-
- typScan = systable_beginscan(typRel, TypeOidIndex, true,
- SnapshotNow, nkeys, typKey);
-
- typTup = systable_getnext(typScan);
-
- if (!HeapTupleIsValid(typTup))
- elog(ERROR, "RemoveConstraintById: Type %d does not exist",
- con->contypid);
-
- systable_endscan(typScan);
-
- /* Keep lock on domain type until end of xact */
- heap_close(typRel, NoLock);
+ /*
+ * XXX for now, do nothing special when dropping a domain constraint
+ *
+ * Probably there should be some form of locking on the domain type,
+ * but we have no such concept at the moment.
+ */
}
else
{
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 1968773733..9f5d89a87f 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.58 2002/12/12 15:49:24 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.59 2002/12/12 20:35:12 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -2737,7 +2737,7 @@ AlterTableAddCheckConstraint(Relation rel, Constraint *constr)
/*
* Convert the A_EXPR in raw_expr into an EXPR
*/
- expr = transformExpr(pstate, constr->raw_expr, NULL);
+ expr = transformExpr(pstate, constr->raw_expr);
/*
* Make sure it yields a boolean result.
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index e16942acd7..989bc36ee8 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/typecmds.c,v 1.22 2002/12/12 15:49:24 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/typecmds.c,v 1.23 2002/12/12 20:35:12 tgl Exp $
*
* DESCRIPTION
* The "DefineFoo" routines take the parse tree and pick out the
@@ -562,14 +562,14 @@ DefineDomain(CreateDomainStmt *stmt)
break;
case CONSTR_NOTNULL:
- if (nullDefined)
+ if (nullDefined && !typNotNull)
elog(ERROR, "CREATE DOMAIN has conflicting NULL / NOT NULL constraint");
typNotNull = true;
nullDefined = true;
break;
case CONSTR_NULL:
- if (nullDefined)
+ if (nullDefined && typNotNull)
elog(ERROR, "CREATE DOMAIN has conflicting NULL / NOT NULL constraint");
typNotNull = false;
nullDefined = true;
@@ -644,14 +644,9 @@ DefineDomain(CreateDomainStmt *stmt)
switch (constr->contype)
{
case CONSTR_CHECK:
- {
- char *junk;
-
- /* Returns the cooked constraint which is not needed during creation */
- junk = domainAddConstraint(domainoid, domainNamespace,
- basetypeoid, stmt->typename->typmod,
- constr, &counter, domainName);
- }
+ domainAddConstraint(domainoid, domainNamespace,
+ basetypeoid, stmt->typename->typmod,
+ constr, &counter, domainName);
break;
/* Other constraint types were fully processed above */
@@ -1247,6 +1242,7 @@ AlterDomainAddConstraint(List *names, Node *newConstraint)
List *rels;
List *rt;
Form_pg_type typTup;
+ ExprContext *econtext;
char *ccbin;
Node *expr;
int counter = 0;
@@ -1261,7 +1257,7 @@ AlterDomainAddConstraint(List *names, Node *newConstraint)
/* Lock the type table */
rel = heap_openr(TypeRelationName, RowExclusiveLock);
- /* Use LookupTypeName here so that shell types can be removed. */
+ /* Use LookupTypeName here so that shell types can be found. */
domainoid = LookupTypeName(typename);
if (!OidIsValid(domainoid))
elog(ERROR, "Type \"%s\" does not exist",
@@ -1328,10 +1324,10 @@ AlterDomainAddConstraint(List *names, Node *newConstraint)
/*
* Since all other constraint types throw errors, this must be
- * a check constraint.
+ * a check constraint. First, process the constraint expression
+ * and add an entry to pg_constraint.
*/
- /* Returns the cooked constraint which is not needed during creation */
ccbin = domainAddConstraint(HeapTupleGetOid(tup), typTup->typnamespace,
typTup->typbasetype, typTup->typtypmod,
constr, &counter, NameStr(typTup->typname));
@@ -1342,61 +1338,46 @@ AlterDomainAddConstraint(List *names, Node *newConstraint)
*/
expr = stringToNode(ccbin);
fix_opfuncids(expr);
+
+ /* Make an expression context for ExecQual */
+ econtext = MakeExprContext(NULL, CurrentMemoryContext);
+
rels = get_rels_with_domain(domainoid);
foreach (rt, rels)
{
- Relation typrel;
+ relToCheck *rtc = (relToCheck *) lfirst(rt);
+ Relation testrel;
+ TupleDesc tupdesc;
HeapTuple tuple;
HeapScanDesc scan;
- TupleDesc tupdesc;
- ExprContext *econtext;
- TupleTableSlot *slot;
- relToCheck *rtc = (relToCheck *) lfirst(rt);
- /* Lock relation */
- typrel = heap_open(rtc->relOid, ExclusiveLock);
+ /* Lock relation against changes */
+ testrel = heap_open(rtc->relOid, ShareLock);
- /* Test attributes */
- tupdesc = RelationGetDescr(typrel);
-
- /* Make tuple slot to hold tuples */
- slot = MakeTupleTableSlot();
- ExecSetSlotDescriptor(slot, RelationGetDescr(typrel), false);
-
- /* Make an expression context for ExecQual */
- econtext = MakeExprContext(slot, CurrentMemoryContext);
+ tupdesc = RelationGetDescr(testrel);
/* Scan through table */
- scan = heap_beginscan(typrel, SnapshotNow, 0, NULL);
+ scan = heap_beginscan(testrel, SnapshotNow, 0, NULL);
while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
{
int i;
- ExecStoreTuple(tuple, slot, InvalidBuffer, false);
-
/* Loop through each attribute of the tuple with a domain */
for (i = 0; i < rtc->natts; i++)
{
Datum d;
bool isNull;
Datum conResult;
- ExprDoneCond isDone;
d = heap_getattr(tuple, rtc->atts[i], tupdesc, &isNull);
- if (isNull)
- elog(ERROR, "ALTER DOMAIN: Relation \"%s\" Attribute \"%s\" "
- "contains NULL values",
- RelationGetRelationName(typrel),
- NameStr(*attnumAttName(typrel, rtc->atts[i])));
-
econtext->domainValue_datum = d;
econtext->domainValue_isNull = isNull;
- conResult = ExecEvalExpr(expr, econtext, &isNull, &isDone);
+ conResult = ExecEvalExpr(expr, econtext, &isNull, NULL);
- if (!DatumGetBool(conResult))
+ if (!isNull && !DatumGetBool(conResult))
elog(ERROR, "AlterDomainAddConstraint: Domain %s constraint %s failed",
NameStr(typTup->typname), constr->name);
}
@@ -1406,13 +1387,12 @@ AlterDomainAddConstraint(List *names, Node *newConstraint)
heap_endscan(scan);
- FreeExprContext(econtext);
- pfree(slot);
-
- /* Hold type lock */
- heap_close(typrel, NoLock);
+ /* Hold relation lock till commit (XXX bad for concurrency) */
+ heap_close(testrel, NoLock);
}
+ FreeExprContext(econtext);
+
/* Clean up */
heap_close(rel, NoLock);
}
@@ -1524,11 +1504,12 @@ domainPermissionCheck(HeapTuple tup, TypeName *typename)
/*
- * domainAddConstraint
+ * domainAddConstraint - code shared between CREATE and ALTER DOMAIN
*/
-char *
+static char *
domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
- int typMod, Constraint *constr, int *counter, char *domainName)
+ int typMod, Constraint *constr,
+ int *counter, char *domainName)
{
Node *expr;
char *ccsrc;
@@ -1556,26 +1537,24 @@ domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
counter);
/*
- * Convert the A_EXPR in raw_expr into an
- * EXPR
+ * Convert the A_EXPR in raw_expr into an EXPR
*/
pstate = make_parsestate(NULL);
/*
- * We want to have the domain VALUE node type filled in so
- * that proper casting can occur.
+ * Set up a ConstraintTestValue to represent the occurrence of VALUE
+ * in the expression. Note that it will appear to have the type of the
+ * base type, not the domain. This seems correct since within the
+ * check expression, we should not assume the input value can be considered
+ * a member of the domain.
*/
domVal = makeNode(ConstraintTestValue);
domVal->typeId = baseTypeOid;
domVal->typeMod = typMod;
- expr = transformExpr(pstate, constr->raw_expr, domVal);
+ pstate->p_value_substitute = (Node *) domVal;
- /*
- * Domains don't allow var clauses
- */
- if (contain_var_clause(expr))
- elog(ERROR, "cannot use column references in domain CHECK clause");
+ expr = transformExpr(pstate, constr->raw_expr);
/*
* Make sure it yields a boolean result.
@@ -1589,6 +1568,13 @@ domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
if (length(pstate->p_rtable) != 0)
elog(ERROR, "Relations cannot be referenced in domain CHECK constraint");
+ /*
+ * Domains don't allow var clauses (this should be redundant with the
+ * above check, but make it anyway)
+ */
+ if (contain_var_clause(expr))
+ elog(ERROR, "cannot use column references in domain CHECK clause");
+
/*
* No subplans or aggregates, either...
*/
@@ -1618,7 +1604,9 @@ domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
InvalidOid),
false, false);
- /* Write the constraint */
+ /*
+ * Store the constraint in pg_constraint
+ */
CreateConstraintEntry(constr->name, /* Constraint Name */
domainNamespace, /* namespace */
CONSTRAINT_CHECK, /* Constraint Type */
@@ -1640,8 +1628,8 @@ domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
ccsrc); /* Source form check constraint */
/*
- * Return the constraint so the calling routine can perform any additional
- * required tests.
+ * Return the compiled constraint expression so the calling routine can
+ * perform any additional required tests.
*/
return ccbin;
}
diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c
index d96e983fa3..79796f1c0b 100644
--- a/src/backend/executor/execQual.c
+++ b/src/backend/executor/execQual.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.117 2002/12/12 15:49:28 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.118 2002/12/12 20:35:12 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -77,8 +77,7 @@ static Datum ExecEvalConstraintTest(ConstraintTest *constraint,
ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone);
static Datum ExecEvalConstraintTestValue(ConstraintTestValue *conVal,
- ExprContext *econtext,
- bool *isNull, ExprDoneCond *isDone);
+ ExprContext *econtext, bool *isNull);
/*----------
@@ -1553,23 +1552,6 @@ ExecEvalBooleanTest(BooleanTest *btest,
}
}
-/*
- * ExecEvalConstraintTestValue
- *
- * Return the value stored by constraintTest.
- */
-static Datum
-ExecEvalConstraintTestValue(ConstraintTestValue *conVal, ExprContext *econtext,
- bool *isNull, ExprDoneCond *isDone)
-{
- /*
- * If the Datum hasn't been set, then it's ExecEvalConstraintTest
- * hasn't been called.
- */
- *isNull = econtext->domainValue_isNull;
- return econtext->domainValue_datum;
-}
-
/*
* ExecEvalConstraintTest
*
@@ -1585,6 +1567,9 @@ ExecEvalConstraintTest(ConstraintTest *constraint, ExprContext *econtext,
result = ExecEvalExpr((Node *) constraint->arg, econtext, isNull, isDone);
+ if (isDone && *isDone == ExprEndResult)
+ return result; /* nothing to check */
+
switch (constraint->testtype)
{
case CONSTR_TEST_NOTNULL:
@@ -1595,16 +1580,32 @@ ExecEvalConstraintTest(ConstraintTest *constraint, ExprContext *econtext,
case CONSTR_TEST_CHECK:
{
Datum conResult;
+ bool conIsNull;
+ Datum save_datum;
+ bool save_isNull;
+
+ /*
+ * Set up value to be returned by ConstraintTestValue nodes.
+ * We must save and restore prior setting of econtext's
+ * domainValue fields, in case this node is itself within
+ * a check expression for another domain.
+ */
+ save_datum = econtext->domainValue_datum;
+ save_isNull = econtext->domainValue_isNull;
- /* Var with attnum == UnassignedAttrNum uses the result */
econtext->domainValue_datum = result;
econtext->domainValue_isNull = *isNull;
- conResult = ExecEvalExpr((Node *) constraint->check_expr, econtext, isNull, isDone);
+ conResult = ExecEvalExpr((Node *) constraint->check_expr,
+ econtext, &conIsNull, NULL);
- if (!DatumGetBool(conResult))
+ if (!conIsNull &&
+ !DatumGetBool(conResult))
elog(ERROR, "ExecEvalConstraintTest: Domain %s constraint %s failed",
constraint->domname, constraint->name);
+
+ econtext->domainValue_datum = save_datum;
+ econtext->domainValue_isNull = save_isNull;
}
break;
default:
@@ -1616,6 +1617,19 @@ ExecEvalConstraintTest(ConstraintTest *constraint, ExprContext *econtext,
return result;
}
+/*
+ * ExecEvalConstraintTestValue
+ *
+ * Return the value stored by constraintTest.
+ */
+static Datum
+ExecEvalConstraintTestValue(ConstraintTestValue *conVal, ExprContext *econtext,
+ bool *isNull)
+{
+ *isNull = econtext->domainValue_isNull;
+ return econtext->domainValue_datum;
+}
+
/* ----------------------------------------------------------------
* ExecEvalFieldSelect
*
@@ -1811,9 +1825,8 @@ ExecEvalExpr(Node *expression,
break;
case T_ConstraintTestValue:
retDatum = ExecEvalConstraintTestValue((ConstraintTestValue *) expression,
- econtext,
- isNull,
- isDone);
+ econtext,
+ isNull);
break;
default:
elog(ERROR, "ExecEvalExpr: unknown expression type %d",
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index f7aa8fcb7e..258e1a1188 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.230 2002/12/12 15:49:28 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.231 2002/12/12 20:35:12 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1297,14 +1297,6 @@ _copyTypeName(TypeName *from)
return newnode;
}
-static DomainConstraintValue *
-_copyDomainConstraintValue(DomainConstraintValue *from)
-{
- DomainConstraintValue *newnode = makeNode(DomainConstraintValue);
-
- return newnode;
-}
-
static SortGroupBy *
_copySortGroupBy(SortGroupBy *from)
{
@@ -2763,9 +2755,6 @@ copyObject(void *from)
case T_TypeCast:
retval = _copyTypeCast(from);
break;
- case T_DomainConstraintValue:
- retval = _copyDomainConstraintValue(from);
- break;
case T_SortGroupBy:
retval = _copySortGroupBy(from);
break;
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 3b51038206..3fc924024e 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -18,7 +18,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.175 2002/12/12 15:49:28 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.176 2002/12/12 20:35:12 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -648,12 +648,6 @@ _equalInsertDefault(InsertDefault *a, InsertDefault *b)
return true;
}
-static bool
-_equalDomainConstraintValue(DomainConstraintValue *a, DomainConstraintValue *b)
-{
- return true;
-}
-
static bool
_equalClosePortalStmt(ClosePortalStmt *a, ClosePortalStmt *b)
{
@@ -1931,9 +1925,6 @@ equal(void *a, void *b)
case T_InsertDefault:
retval = _equalInsertDefault(a, b);
break;
- case T_DomainConstraintValue:
- retval = _equalDomainConstraintValue(a, b);
- break;
default:
elog(WARNING, "equal: don't know whether nodes of type %d are equal",
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index bd44816e6f..9ae7155509 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.187 2002/12/12 15:49:28 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.188 2002/12/12 20:35:12 tgl Exp $
*
* NOTES
* Every node type that can appear in stored rules' parsetrees *must*
@@ -1299,12 +1299,6 @@ _outExprFieldSelect(StringInfo str, ExprFieldSelect *node)
WRITE_NODE_FIELD(indirection);
}
-static void
-_outDomainConstraintValue(StringInfo str, DomainConstraintValue *node)
-{
- WRITE_NODE_TYPE("DOMAINCONSTRAINTVALUE");
-}
-
static void
_outConstraint(StringInfo str, Constraint *node)
{
@@ -1637,9 +1631,6 @@ _outNode(StringInfo str, void *obj)
case T_ExprFieldSelect:
_outExprFieldSelect(str, obj);
break;
- case T_DomainConstraintValue:
- _outDomainConstraintValue(str, obj);
- break;
case T_Constraint:
_outConstraint(str, obj);
break;
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index bb4a565a8b..ba46a4f088 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.141 2002/12/12 15:49:28 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.142 2002/12/12 20:35:12 tgl Exp $
*
* NOTES
* Path and Plan nodes do not have any readfuncs support, because we
@@ -792,17 +792,6 @@ _readExprFieldSelect(void)
READ_DONE();
}
-/*
- * _readDomainConstraintValue
- */
-static DomainConstraintValue *
-_readDomainConstraintValue(void)
-{
- READ_LOCALS_NO_FIELDS(DomainConstraintValue);
-
- READ_DONE();
-}
-
/*
* _readRangeTblEntry
*/
@@ -935,8 +924,6 @@ parseNodeString(void)
return_value = _readTypeName();
else if (MATCH("EXPRFIELDSELECT", 15))
return_value = _readExprFieldSelect();
- else if (MATCH("DOMAINCONSTRAINTVALUE", 21))
- return_value = _readDomainConstraintValue();
else if (MATCH("RTE", 3))
return_value = _readRangeTblEntry();
else
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index ef317c5b22..83c05a5d5f 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.116 2002/12/12 15:49:32 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.117 2002/12/12 20:35:12 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -2129,6 +2129,7 @@ expression_tree_walker(Node *node,
case T_Var:
case T_Const:
case T_Param:
+ case T_ConstraintTestValue:
case T_RangeTblRef:
/* primitive node types with no subnodes */
break;
@@ -2265,8 +2266,6 @@ expression_tree_walker(Node *node,
if (walker(((ConstraintTest *) node)->arg, context))
return true;
return walker(((ConstraintTest *) node)->check_expr, context);
- case T_ConstraintTestValue:
- break;
case T_TargetEntry:
return walker(((TargetEntry *) node)->expr, context);
case T_Query:
@@ -2474,6 +2473,7 @@ expression_tree_mutator(Node *node,
case T_Var:
case T_Const:
case T_Param:
+ case T_ConstraintTestValue:
case T_RangeTblRef:
/* primitive node types with no subnodes */
return (Node *) copyObject(node);
@@ -2651,15 +2651,6 @@ expression_tree_mutator(Node *node,
return (Node *) newnode;
}
break;
- case T_ConstraintTestValue:
- {
- ConstraintTestValue *ctest = (ConstraintTestValue *) node;
- ConstraintTestValue *newnode;
-
- FLATCOPY(newnode, ctest, ConstraintTestValue);
- return (Node *) newnode;
- }
- break;
case T_TargetEntry:
{
/*
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index 56f0fdd955..a7ead10318 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.255 2002/12/12 15:49:33 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.256 2002/12/12 20:35:12 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -2401,7 +2401,7 @@ transformExecuteStmt(ParseState *pstate, ExecuteStmt *stmt)
Oid expected_type_id,
given_type_id;
- expr = transformExpr(pstate, expr, NULL);
+ expr = transformExpr(pstate, expr);
/* Cannot contain subselects or aggregates */
if (contain_subplans(expr))
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 53e1a5999f..bb94d1f8e8 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.387 2002/12/12 15:49:36 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.388 2002/12/12 20:35:13 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -393,7 +393,7 @@ static void doNegateFloat(Value *v);
UNENCRYPTED UNION UNIQUE UNKNOWN UNLISTEN UNTIL
UPDATE USAGE USER USING
- VACUUM VALID VALIDATOR VALUE VALUES VARCHAR VARYING
+ VACUUM VALID VALIDATOR VALUES VARCHAR VARYING
VERBOSE VERSION VIEW VOLATILE
WHEN WHERE WITH WITHOUT WORK WRITE
@@ -6464,11 +6464,6 @@ c_expr: columnref { $$ = (Node *) $1; }
n->subselect = $2;
$$ = (Node *)n;
}
- | VALUE
- {
- DomainConstraintValue *n = makeNode(DomainConstraintValue);
- $$ = (Node *)n;
- }
;
/*
@@ -7378,7 +7373,6 @@ reserved_keyword:
| UNIQUE
| USER
| USING
- | VALUE
| WHEN
| WHERE
;
diff --git a/src/backend/parser/keywords.c b/src/backend/parser/keywords.c
index de8a6e09b1..5373b974cb 100644
--- a/src/backend/parser/keywords.c
+++ b/src/backend/parser/keywords.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.131 2002/11/15 02:50:08 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.132 2002/12/12 20:35:13 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -314,7 +314,6 @@ static const ScanKeyword ScanKeywords[] = {
{"vacuum", VACUUM},
{"valid", VALID},
{"validator", VALIDATOR},
- {"value", VALUE},
{"values", VALUES},
{"varchar", VARCHAR},
{"varying", VARYING},
diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c
index 6f05ee329c..71375f62c9 100644
--- a/src/backend/parser/parse_clause.c
+++ b/src/backend/parser/parse_clause.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.101 2002/12/12 15:49:38 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.102 2002/12/12 20:35:13 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -283,7 +283,7 @@ transformJoinUsingClause(ParseState *pstate, List *leftVars, List *rightVars)
* transformJoinOnClause() does. Just invoke transformExpr() to fix
* up the operators, and we're done.
*/
- result = transformExpr(pstate, result, NULL);
+ result = transformExpr(pstate, result);
result = coerce_to_boolean(result, "JOIN/USING");
@@ -317,7 +317,7 @@ transformJoinOnClause(ParseState *pstate, JoinExpr *j,
pstate->p_namespace = makeList2(j->larg, j->rarg);
/* This part is just like transformWhereClause() */
- result = transformExpr(pstate, j->quals, NULL);
+ result = transformExpr(pstate, j->quals);
result = coerce_to_boolean(result, "JOIN/ON");
@@ -478,7 +478,7 @@ transformRangeFunction(ParseState *pstate, RangeFunction *r)
save_namespace = pstate->p_namespace;
pstate->p_namespace = NIL;
- funcexpr = transformExpr(pstate, r->funccallnode, NULL);
+ funcexpr = transformExpr(pstate, r->funccallnode);
pstate->p_namespace = save_namespace;
@@ -950,7 +950,7 @@ transformWhereClause(ParseState *pstate, Node *clause)
if (clause == NULL)
return NULL;
- qual = transformExpr(pstate, clause, NULL);
+ qual = transformExpr(pstate, clause);
qual = coerce_to_boolean(qual, "WHERE");
@@ -1093,7 +1093,7 @@ findTargetlistEntry(ParseState *pstate, Node *node, List *tlist, int clause)
* willing to match a resjunk target here, though the above cases must
* ignore resjunk targets.
*/
- expr = transformExpr(pstate, node, NULL);
+ expr = transformExpr(pstate, node);
foreach(tl, tlist)
{
diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c
index 3856939d40..af184eca6d 100644
--- a/src/backend/parser/parse_coerce.c
+++ b/src/backend/parser/parse_coerce.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.90 2002/12/12 15:49:38 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.91 2002/12/12 20:35:13 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -458,9 +458,8 @@ coerce_type_constraints(Node *arg, Oid typeId, CoercionForm cformat)
r->testtype = CONSTR_TEST_CHECK;
r->name = NameStr(c->conname);
r->domname = NameStr(typTup->typname);
- r->check_expr = stringToNode(MemoryContextStrdup(CacheMemoryContext,
- DatumGetCString(DirectFunctionCall1(textout,
- val))));
+ r->check_expr = stringToNode(DatumGetCString(DirectFunctionCall1(textout,
+ val)));
arg = (Node *) r;
}
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index 7dcbf59a4e..db0667ef16 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.136 2002/12/12 15:49:39 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.137 2002/12/12 20:35:13 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -20,7 +20,6 @@
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/params.h"
-#include "optimizer/clauses.h"
#include "parser/analyze.h"
#include "parser/gramparse.h"
#include "parser/parse.h"
@@ -84,7 +83,7 @@ parse_expr_init(void)
* input and output of transformExpr; see SubLink for example.
*/
Node *
-transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
+transformExpr(ParseState *pstate, Node *expr)
{
Node *result = NULL;
@@ -152,7 +151,7 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
ExprFieldSelect *efs = (ExprFieldSelect *) expr;
List *fields;
- result = transformExpr(pstate, efs->arg, domVal);
+ result = transformExpr(pstate, efs->arg);
/* handle qualification, if any */
foreach(fields, efs->fields)
{
@@ -169,7 +168,7 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
case T_TypeCast:
{
TypeCast *tc = (TypeCast *) expr;
- Node *arg = transformExpr(pstate, tc->arg, domVal);
+ Node *arg = transformExpr(pstate, tc->arg);
result = typecast_expression(arg, tc->typename);
break;
@@ -204,14 +203,14 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
n->arg = (Expr *) a->lexpr;
result = transformExpr(pstate,
- (Node *) n, domVal);
+ (Node *) n);
}
else
{
Node *lexpr = transformExpr(pstate,
- a->lexpr, domVal);
+ a->lexpr);
Node *rexpr = transformExpr(pstate,
- a->rexpr, domVal);
+ a->rexpr);
result = (Node *) make_op(a->name,
lexpr,
@@ -222,9 +221,9 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
case AND:
{
Node *lexpr = transformExpr(pstate,
- a->lexpr, domVal);
+ a->lexpr);
Node *rexpr = transformExpr(pstate,
- a->rexpr, domVal);
+ a->rexpr);
lexpr = coerce_to_boolean(lexpr, "AND");
rexpr = coerce_to_boolean(rexpr, "AND");
@@ -237,9 +236,9 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
case OR:
{
Node *lexpr = transformExpr(pstate,
- a->lexpr, domVal);
+ a->lexpr);
Node *rexpr = transformExpr(pstate,
- a->rexpr, domVal);
+ a->rexpr);
lexpr = coerce_to_boolean(lexpr, "OR");
rexpr = coerce_to_boolean(rexpr, "OR");
@@ -252,7 +251,7 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
case NOT:
{
Node *rexpr = transformExpr(pstate,
- a->rexpr, domVal);
+ a->rexpr);
rexpr = coerce_to_boolean(rexpr, "NOT");
@@ -263,9 +262,9 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
case DISTINCT:
{
Node *lexpr = transformExpr(pstate,
- a->lexpr, domVal);
+ a->lexpr);
Node *rexpr = transformExpr(pstate,
- a->rexpr, domVal);
+ a->rexpr);
result = (Node *) make_op(a->name,
lexpr,
@@ -291,7 +290,7 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
* Will result in a boolean constant node.
*/
Node *lexpr = transformExpr(pstate,
- a->lexpr, domVal);
+ a->lexpr);
ltype = exprType(lexpr);
foreach(telem, (List *) a->rexpr)
@@ -315,7 +314,7 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
n->val.val.str = (matched ? "t" : "f");
n->typename = SystemTypeName("bool");
- result = transformExpr(pstate, (Node *) n, domVal);
+ result = transformExpr(pstate, (Node *) n);
}
break;
}
@@ -329,7 +328,7 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
/* transform the list of arguments */
foreach(args, fn->args)
lfirst(args) = transformExpr(pstate,
- (Node *) lfirst(args), domVal);
+ (Node *) lfirst(args));
result = ParseFuncOrColumn(pstate,
fn->funcname,
fn->args,
@@ -403,7 +402,7 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
List *elist;
foreach(elist, left_list)
- lfirst(elist) = transformExpr(pstate, lfirst(elist), domVal);
+ lfirst(elist) = transformExpr(pstate, lfirst(elist));
Assert(IsA(sublink->oper, A_Expr));
op = ((A_Expr *) sublink->oper)->name;
@@ -507,7 +506,7 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
(Node *) c->arg,
warg);
}
- neww->expr = (Expr *) transformExpr(pstate, warg, domVal);
+ neww->expr = (Expr *) transformExpr(pstate, warg);
neww->expr = (Expr *) coerce_to_boolean((Node *) neww->expr,
"CASE/WHEN");
@@ -524,7 +523,7 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
n->val.type = T_Null;
warg = (Node *) n;
}
- neww->result = (Expr *) transformExpr(pstate, warg, domVal);
+ neww->result = (Expr *) transformExpr(pstate, warg);
newargs = lappend(newargs, neww);
typeids = lappendi(typeids, exprType((Node *) neww->result));
@@ -548,7 +547,7 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
n->val.type = T_Null;
defresult = (Node *) n;
}
- newc->defresult = (Expr *) transformExpr(pstate, defresult, domVal);
+ newc->defresult = (Expr *) transformExpr(pstate, defresult);
/*
* Note: default result is considered the most significant
@@ -586,7 +585,7 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
{
NullTest *n = (NullTest *) expr;
- n->arg = (Expr *) transformExpr(pstate, (Node *) n->arg, domVal);
+ n->arg = (Expr *) transformExpr(pstate, (Node *) n->arg);
/* the argument can be any type, so don't coerce it */
result = expr;
break;
@@ -623,7 +622,7 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
clausename = NULL; /* keep compiler quiet */
}
- b->arg = (Expr *) transformExpr(pstate, (Node *) b->arg, domVal);
+ b->arg = (Expr *) transformExpr(pstate, (Node *) b->arg);
b->arg = (Expr *) coerce_to_boolean((Node *) b->arg, clausename);
@@ -631,21 +630,6 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
break;
}
- case T_DomainConstraintValue:
- {
- /*
- * If domVal is NULL, we are not translating an expression that
- * can use it
- */
- if (domVal == NULL)
- elog(ERROR, "VALUE is not allowed in expression for node %d",
- nodeTag(expr));
-
- result = (Node *) copyObject(domVal);
-
- break;
- }
-
/*********************************************
* Quietly accept node types that may be presented when we are
* called on an already-transformed tree.
@@ -663,6 +647,7 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
case T_FieldSelect:
case T_RelabelType:
case T_ConstraintTest:
+ case T_ConstraintTestValue:
{
result = (Node *) expr;
break;
@@ -700,6 +685,7 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
int numnames = length(cref->fields);
Node *node;
RangeVar *rv;
+ int levels_up;
/*----------
* The allowed syntaxes are:
@@ -740,18 +726,30 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
if (node == NULL)
{
/*
- * Not known as a column of any range-table entry, so
- * try to find the name as a relation ... but not if
+ * Not known as a column of any range-table entry.
+ *
+ * Consider the possibility that it's VALUE in a domain
+ * check expression. (We handle VALUE as a name, not a
+ * keyword, to avoid breaking a lot of applications that
+ * have used VALUE as a column name in the past.)
+ */
+ if (pstate->p_value_substitute != NULL &&
+ strcmp(name, "value") == 0)
+ {
+ node = (Node *) copyObject(pstate->p_value_substitute);
+ break;
+ }
+
+ /*
+ * Try to find the name as a relation ... but not if
* subscripts appear. Note also that only relations
* already entered into the rangetable will be
* recognized.
*
* This is a hack for backwards compatibility with
- * PostQUEL- inspired syntax. The preferred form now
+ * PostQUEL-inspired syntax. The preferred form now
* is "rel.*".
*/
- int levels_up;
-
if (cref->indirection == NIL &&
refnameRangeTblEntry(pstate, NULL, name,
&levels_up) != NULL)
@@ -1055,7 +1053,8 @@ exprTypmod(Node *expr)
break;
case T_ConstraintTest:
return exprTypmod((Node *) ((ConstraintTest *) expr)->arg);
-
+ case T_ConstraintTestValue:
+ return ((ConstraintTestValue *) expr)->typeMod;
default:
break;
}
diff --git a/src/backend/parser/parse_node.c b/src/backend/parser/parse_node.c
index a246344c7b..9de23d0cb8 100644
--- a/src/backend/parser/parse_node.c
+++ b/src/backend/parser/parse_node.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.75 2002/12/12 15:49:39 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.76 2002/12/12 20:35:13 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -272,7 +272,7 @@ transformArraySubscripts(ParseState *pstate,
{
if (ai->lidx)
{
- subexpr = transformExpr(pstate, ai->lidx, NULL);
+ subexpr = transformExpr(pstate, ai->lidx);
/* If it's not int4 already, try to coerce */
subexpr = coerce_to_target_type(subexpr, exprType(subexpr),
INT4OID, -1,
@@ -292,7 +292,7 @@ transformArraySubscripts(ParseState *pstate,
}
lowerIndexpr = lappend(lowerIndexpr, subexpr);
}
- subexpr = transformExpr(pstate, ai->uidx, NULL);
+ subexpr = transformExpr(pstate, ai->uidx);
/* If it's not int4 already, try to coerce */
subexpr = coerce_to_target_type(subexpr, exprType(subexpr),
INT4OID, -1,
diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c
index 5e4e23db92..7e73b1b7b0 100644
--- a/src/backend/parser/parse_target.c
+++ b/src/backend/parser/parse_target.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.93 2002/12/12 15:49:39 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.94 2002/12/12 20:35:13 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -56,7 +56,7 @@ transformTargetEntry(ParseState *pstate,
/* Transform the node if caller didn't do it already */
if (expr == NULL)
- expr = transformExpr(pstate, node, NULL);
+ expr = transformExpr(pstate, node);
if (IsA(expr, RangeVar))
elog(ERROR, "You can't use relation names alone in the target list, try relation.*.");
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index a4f10ef4c0..db8e431c76 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: execnodes.h,v 1.82 2002/12/05 15:50:38 tgl Exp $
+ * $Id: execnodes.h,v 1.83 2002/12/12 20:35:13 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -82,7 +82,7 @@ typedef struct ExprContext_CB
* * ecxt_per_query_memory is a relatively long-lived context (such as
* TransactionCommandContext); typically it's the same context the
* ExprContext node itself is allocated in. This context can be
- * used for purposes such as storing operator/function fcache nodes.
+ * used for purposes such as storing function call cache info.
* * ecxt_per_tuple_memory is a short-term context for expression results.
* As the name suggests, it will typically be reset once per tuple,
* before we begin to evaluate expressions for that tuple. Each
@@ -112,10 +112,7 @@ typedef struct ExprContext
Datum *ecxt_aggvalues; /* precomputed values for Aggref nodes */
bool *ecxt_aggnulls; /* null flags for Aggref nodes */
- /*
- * Carry the domain value through the executor for application
- * in a domain constraint
- */
+ /* Value to substitute for ConstraintTestValue nodes in expression */
Datum domainValue_datum;
bool domainValue_isNull;
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index aacdf60dd9..0c031b830e 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: nodes.h,v 1.130 2002/12/12 15:49:40 tgl Exp $
+ * $Id: nodes.h,v 1.131 2002/12/12 20:35:14 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -252,7 +252,6 @@ typedef enum NodeTag
T_FuncWithArgs,
T_PrivTarget,
T_InsertDefault,
- T_DomainConstraintValue,
T_CreateOpClassItem,
T_CompositeTypeStmt,
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index f2d92431b7..c409ec7ea8 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: parsenodes.h,v 1.222 2002/12/12 15:49:40 tgl Exp $
+ * $Id: parsenodes.h,v 1.223 2002/12/12 20:35:16 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -275,15 +275,6 @@ typedef struct InsertDefault
NodeTag type;
} InsertDefault;
-/*
- * Empty node used as raw-parse-tree representation of VALUE keyword
- * for domain check constraints.
- */
-typedef struct DomainConstraintValue
-{
- NodeTag type;
-} DomainConstraintValue;
-
/*
* SortGroupBy - for ORDER BY clause
*/
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index ec0ad4235c..ae0df7e441 100644
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -10,7 +10,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: primnodes.h,v 1.72 2002/12/12 15:49:40 tgl Exp $
+ * $Id: primnodes.h,v 1.73 2002/12/12 20:35:16 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -599,15 +599,19 @@ typedef struct ConstraintTest
} ConstraintTest;
/*
- * Placeholder node for the value to be processed by a domains
- * check constraint. This is effectively like a Param; could we use
- * a Param node instead?
+ * Placeholder node for the value to be processed by a domain's check
+ * constraint. This is effectively like a Param, but can be implemented more
+ * simply since we need only one replacement value at a time.
+ *
+ * Note: the typeId/typeMod will be set from the domain's base type, not
+ * the domain itself. This is because we shouldn't consider the value to
+ * be a member of the domain if we haven't yet checked its constraints.
*/
typedef struct ConstraintTestValue
{
Expr xpr;
- Oid typeId;
- int32 typeMod;
+ Oid typeId; /* type for substituted value */
+ int32 typeMod; /* typemod for substituted value */
} ConstraintTestValue;
diff --git a/src/include/optimizer/var.h b/src/include/optimizer/var.h
index 68ffc8e373..102e928a54 100644
--- a/src/include/optimizer/var.h
+++ b/src/include/optimizer/var.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: var.h,v 1.22 2002/11/15 02:50:21 momjian Exp $
+ * $Id: var.h,v 1.23 2002/12/12 20:35:16 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -22,7 +22,6 @@ extern bool contain_var_reference(Node *node, int varno, int varattno,
int levelsup);
extern bool contain_whole_tuple_var(Node *node, int varno, int levelsup);
extern bool contain_var_clause(Node *node);
-extern bool contain_var_tuple_clause(Node *node);
extern List *pull_var_clause(Node *node, bool includeUpperVars);
extern Node *flatten_join_alias_vars(Node *node, List *rtable, bool force);
diff --git a/src/include/parser/parse_expr.h b/src/include/parser/parse_expr.h
index bcf84912ac..6606d3913e 100644
--- a/src/include/parser/parse_expr.h
+++ b/src/include/parser/parse_expr.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: parse_expr.h,v 1.29 2002/11/15 02:50:21 momjian Exp $
+ * $Id: parse_expr.h,v 1.30 2002/12/12 20:35:16 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -22,7 +22,7 @@ extern int max_expr_depth;
extern bool Transform_null_equals;
-extern Node *transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal);
+extern Node *transformExpr(ParseState *pstate, Node *expr);
extern Oid exprType(Node *expr);
extern int32 exprTypmod(Node *expr);
extern bool exprIsLengthCoercion(Node *expr, int32 *coercedTypmod);
diff --git a/src/include/parser/parse_node.h b/src/include/parser/parse_node.h
index beb16e2cc8..46c86e1f79 100644
--- a/src/include/parser/parse_node.h
+++ b/src/include/parser/parse_node.h
@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: parse_node.h,v 1.32 2002/09/18 21:35:24 tgl Exp $
+ * $Id: parse_node.h,v 1.33 2002/12/12 20:35:16 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -42,6 +42,7 @@ typedef struct ParseState
List *p_namespace; /* current lookup namespace (join items) */
int p_last_resno; /* last targetlist resno assigned */
List *p_forUpdate; /* FOR UPDATE clause, if any (see gram.y) */
+ Node *p_value_substitute; /* what to replace VALUE with, if any */
bool p_hasAggs;
bool p_hasSubLinks;
bool p_is_insert;
diff --git a/src/test/regress/expected/domain.out b/src/test/regress/expected/domain.out
index f91191bddb..cbbb902379 100644
--- a/src/test/regress/expected/domain.out
+++ b/src/test/regress/expected/domain.out
@@ -115,7 +115,7 @@ INSERT INTO nulltest DEFAULT VALUES;
ERROR: Domain dnotnull does not allow NULL values
INSERT INTO nulltest values ('a', 'b', 'c', 'd', 'c'); -- Good
insert into nulltest values ('a', 'b', 'c', 'd', NULL);
-ERROR: ExecEvalConstraintTest: Domain dcheck constraint $1 failed
+ERROR: Domain dcheck does not allow NULL values
insert into nulltest values ('a', 'b', 'c', 'd', 'a');
ERROR: ExecInsert: rejected due to CHECK constraint "nulltest_col5" on "nulltest"
INSERT INTO nulltest values (NULL, 'b', 'c', 'd', 'd');
@@ -127,7 +127,7 @@ ERROR: ExecInsert: Fail to add null value in not null attribute col3
INSERT INTO nulltest values ('a', 'b', 'c', NULL, 'd'); -- Good
-- Test copy
COPY nulltest FROM stdin; --fail
-ERROR: copy: line 1, ExecEvalConstraintTest: Domain dcheck constraint $1 failed
+ERROR: copy: line 1, Domain dcheck does not allow NULL values
lost synchronization with server, resetting connection
SET autocommit TO 'on';
-- Last row is bad