Preliminary code review for domain CHECK constraints patch: add documentation,

make VALUE a non-reserved word again, use less invasive method of passing
ConstraintTestValue into transformExpr, fix problems with nested constraint
testing, do correct thing with NULL result from a constraint expression,
remove memory leak.  Domain checks still need much more work if we are going
to allow ALTER DOMAIN, however.
This commit is contained in:
Tom Lane 2002-12-12 20:35:16 +00:00
parent ff7349694f
commit b0422b215c
28 changed files with 222 additions and 292 deletions

View File

@ -1,5 +1,5 @@
<!-- <!--
$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_domain.sgml,v 1.8 2002/11/21 23:34:43 petere Exp $ $Header: /cvsroot/pgsql/doc/src/sgml/ref/create_domain.sgml,v 1.9 2002/12/12 20:35:07 tgl Exp $
PostgreSQL documentation PostgreSQL documentation
--> -->
@ -30,7 +30,7 @@ CREATE DOMAIN <replaceable class="parameter">domainname</replaceable> [AS] <repl
where <replaceable class="PARAMETER">constraint</replaceable> is: where <replaceable class="PARAMETER">constraint</replaceable> is:
[ CONSTRAINT <replaceable class="PARAMETER">constraint_name</replaceable> ] [ CONSTRAINT <replaceable class="PARAMETER">constraint_name</replaceable> ]
{ NOT NULL | NULL } { NOT NULL | NULL | CHECK (<replaceable class="PARAMETER">expression</replaceable>) }
</synopsis> </synopsis>
<refsect2 id="R2-SQL-CREATEDOMAIN-1"> <refsect2 id="R2-SQL-CREATEDOMAIN-1">
@ -128,6 +128,25 @@ where <replaceable class="PARAMETER">constraint</replaceable> is:
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><literal>CHECK (<replaceable class="PARAMETER">expression</replaceable>)</literal></term>
<listitem>
<para>
<literal>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 <literal>VALUE</>
to refer to the value being tested.
</para>
<para>
Currently, <literal>CHECK</literal> expressions cannot contain
subselects nor refer to variables other than <literal>VALUE</>.
</para>
</listitem>
</varlistentry>
</variablelist> </variablelist>
</para> </para>
</refsect2> </refsect2>

View File

@ -1,5 +1,5 @@
<!-- <!--
$Header: /cvsroot/pgsql/doc/src/sgml/release.sgml,v 1.168 2002/11/26 22:04:03 momjian Exp $ $Header: /cvsroot/pgsql/doc/src/sgml/release.sgml,v 1.169 2002/12/12 20:35:07 tgl Exp $
--> -->
<appendix id="release"> <appendix id="release">
@ -24,6 +24,7 @@ CDATA means the content is "SGML-free", so you can write without
worries about funny characters. worries about funny characters.
--> -->
<literallayout><![CDATA[ <literallayout><![CDATA[
Domains now support CHECK constraints
]]></literallayout> ]]></literallayout>
</sect1> </sect1>

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * INTERFACE ROUTINES
@ -1567,7 +1567,7 @@ AddRelationRawConstraints(Relation rel,
/* /*
* Transform raw parsetree to executable expression. * 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. * Make sure it yields a boolean result.
@ -1691,7 +1691,7 @@ cookDefault(ParseState *pstate,
/* /*
* Transform raw parsetree to executable expression. * 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. * Make sure default expr does not refer to any vars.

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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); con = (Form_pg_constraint) GETSTRUCT(tup);
/* /*
* If the constraint is for a relation, open and exclusive-lock * Special processing depending on what the constraint is for.
* 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.
*/ */
if (OidIsValid(con->conrelid)) if (OidIsValid(con->conrelid))
{ {
Relation rel; Relation rel;
/*
* If the constraint is for a relation, open and exclusive-lock the
* relation it's for.
*/
rel = heap_open(con->conrelid, AccessExclusiveLock); rel = heap_open(con->conrelid, AccessExclusiveLock);
/* /*
@ -490,34 +488,14 @@ RemoveConstraintById(Oid conId)
/* Keep lock on constraint's rel until end of xact */ /* Keep lock on constraint's rel until end of xact */
heap_close(rel, NoLock); heap_close(rel, NoLock);
} }
/* Lock the domain row in pg_type */
else if (OidIsValid(con->contypid)) else if (OidIsValid(con->contypid))
{ {
Relation typRel; /*
HeapTuple typTup; * XXX for now, do nothing special when dropping a domain constraint
ScanKeyData typKey[1]; *
SysScanDesc typScan; * Probably there should be some form of locking on the domain type,
int nkeys = 0; * but we have no such concept at the moment.
*/
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);
} }
else else
{ {

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * 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. * Make sure it yields a boolean result.

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * DESCRIPTION
* The "DefineFoo" routines take the parse tree and pick out the * The "DefineFoo" routines take the parse tree and pick out the
@ -562,14 +562,14 @@ DefineDomain(CreateDomainStmt *stmt)
break; break;
case CONSTR_NOTNULL: case CONSTR_NOTNULL:
if (nullDefined) if (nullDefined && !typNotNull)
elog(ERROR, "CREATE DOMAIN has conflicting NULL / NOT NULL constraint"); elog(ERROR, "CREATE DOMAIN has conflicting NULL / NOT NULL constraint");
typNotNull = true; typNotNull = true;
nullDefined = true; nullDefined = true;
break; break;
case CONSTR_NULL: case CONSTR_NULL:
if (nullDefined) if (nullDefined && typNotNull)
elog(ERROR, "CREATE DOMAIN has conflicting NULL / NOT NULL constraint"); elog(ERROR, "CREATE DOMAIN has conflicting NULL / NOT NULL constraint");
typNotNull = false; typNotNull = false;
nullDefined = true; nullDefined = true;
@ -644,14 +644,9 @@ DefineDomain(CreateDomainStmt *stmt)
switch (constr->contype) switch (constr->contype)
{ {
case CONSTR_CHECK: case CONSTR_CHECK:
{ domainAddConstraint(domainoid, domainNamespace,
char *junk;
/* Returns the cooked constraint which is not needed during creation */
junk = domainAddConstraint(domainoid, domainNamespace,
basetypeoid, stmt->typename->typmod, basetypeoid, stmt->typename->typmod,
constr, &counter, domainName); constr, &counter, domainName);
}
break; break;
/* Other constraint types were fully processed above */ /* Other constraint types were fully processed above */
@ -1247,6 +1242,7 @@ AlterDomainAddConstraint(List *names, Node *newConstraint)
List *rels; List *rels;
List *rt; List *rt;
Form_pg_type typTup; Form_pg_type typTup;
ExprContext *econtext;
char *ccbin; char *ccbin;
Node *expr; Node *expr;
int counter = 0; int counter = 0;
@ -1261,7 +1257,7 @@ AlterDomainAddConstraint(List *names, Node *newConstraint)
/* Lock the type table */ /* Lock the type table */
rel = heap_openr(TypeRelationName, RowExclusiveLock); 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); domainoid = LookupTypeName(typename);
if (!OidIsValid(domainoid)) if (!OidIsValid(domainoid))
elog(ERROR, "Type \"%s\" does not exist", 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 * 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, ccbin = domainAddConstraint(HeapTupleGetOid(tup), typTup->typnamespace,
typTup->typbasetype, typTup->typtypmod, typTup->typbasetype, typTup->typtypmod,
constr, &counter, NameStr(typTup->typname)); constr, &counter, NameStr(typTup->typname));
@ -1342,61 +1338,46 @@ AlterDomainAddConstraint(List *names, Node *newConstraint)
*/ */
expr = stringToNode(ccbin); expr = stringToNode(ccbin);
fix_opfuncids(expr); fix_opfuncids(expr);
/* Make an expression context for ExecQual */
econtext = MakeExprContext(NULL, CurrentMemoryContext);
rels = get_rels_with_domain(domainoid); rels = get_rels_with_domain(domainoid);
foreach (rt, rels) foreach (rt, rels)
{ {
Relation typrel; relToCheck *rtc = (relToCheck *) lfirst(rt);
Relation testrel;
TupleDesc tupdesc;
HeapTuple tuple; HeapTuple tuple;
HeapScanDesc scan; HeapScanDesc scan;
TupleDesc tupdesc;
ExprContext *econtext;
TupleTableSlot *slot;
relToCheck *rtc = (relToCheck *) lfirst(rt);
/* Lock relation */ /* Lock relation against changes */
typrel = heap_open(rtc->relOid, ExclusiveLock); testrel = heap_open(rtc->relOid, ShareLock);
/* Test attributes */ tupdesc = RelationGetDescr(testrel);
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);
/* Scan through table */ /* Scan through table */
scan = heap_beginscan(typrel, SnapshotNow, 0, NULL); scan = heap_beginscan(testrel, SnapshotNow, 0, NULL);
while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL) while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
{ {
int i; int i;
ExecStoreTuple(tuple, slot, InvalidBuffer, false);
/* Loop through each attribute of the tuple with a domain */ /* Loop through each attribute of the tuple with a domain */
for (i = 0; i < rtc->natts; i++) for (i = 0; i < rtc->natts; i++)
{ {
Datum d; Datum d;
bool isNull; bool isNull;
Datum conResult; Datum conResult;
ExprDoneCond isDone;
d = heap_getattr(tuple, rtc->atts[i], tupdesc, &isNull); 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_datum = d;
econtext->domainValue_isNull = isNull; 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", elog(ERROR, "AlterDomainAddConstraint: Domain %s constraint %s failed",
NameStr(typTup->typname), constr->name); NameStr(typTup->typname), constr->name);
} }
@ -1406,13 +1387,12 @@ AlterDomainAddConstraint(List *names, Node *newConstraint)
heap_endscan(scan); heap_endscan(scan);
FreeExprContext(econtext); /* Hold relation lock till commit (XXX bad for concurrency) */
pfree(slot); heap_close(testrel, NoLock);
/* Hold type lock */
heap_close(typrel, NoLock);
} }
FreeExprContext(econtext);
/* Clean up */ /* Clean up */
heap_close(rel, NoLock); 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, 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; Node *expr;
char *ccsrc; char *ccsrc;
@ -1556,26 +1537,24 @@ domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
counter); counter);
/* /*
* Convert the A_EXPR in raw_expr into an * Convert the A_EXPR in raw_expr into an EXPR
* EXPR
*/ */
pstate = make_parsestate(NULL); pstate = make_parsestate(NULL);
/* /*
* We want to have the domain VALUE node type filled in so * Set up a ConstraintTestValue to represent the occurrence of VALUE
* that proper casting can occur. * 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 = makeNode(ConstraintTestValue);
domVal->typeId = baseTypeOid; domVal->typeId = baseTypeOid;
domVal->typeMod = typMod; domVal->typeMod = typMod;
expr = transformExpr(pstate, constr->raw_expr, domVal); pstate->p_value_substitute = (Node *) domVal;
/* expr = transformExpr(pstate, constr->raw_expr);
* Domains don't allow var clauses
*/
if (contain_var_clause(expr))
elog(ERROR, "cannot use column references in domain CHECK clause");
/* /*
* Make sure it yields a boolean result. * Make sure it yields a boolean result.
@ -1589,6 +1568,13 @@ domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
if (length(pstate->p_rtable) != 0) if (length(pstate->p_rtable) != 0)
elog(ERROR, "Relations cannot be referenced in domain CHECK constraint"); 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... * No subplans or aggregates, either...
*/ */
@ -1618,7 +1604,9 @@ domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
InvalidOid), InvalidOid),
false, false); false, false);
/* Write the constraint */ /*
* Store the constraint in pg_constraint
*/
CreateConstraintEntry(constr->name, /* Constraint Name */ CreateConstraintEntry(constr->name, /* Constraint Name */
domainNamespace, /* namespace */ domainNamespace, /* namespace */
CONSTRAINT_CHECK, /* Constraint Type */ CONSTRAINT_CHECK, /* Constraint Type */
@ -1640,8 +1628,8 @@ domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
ccsrc); /* Source form check constraint */ ccsrc); /* Source form check constraint */
/* /*
* Return the constraint so the calling routine can perform any additional * Return the compiled constraint expression so the calling routine can
* required tests. * perform any additional required tests.
*/ */
return ccbin; return ccbin;
} }

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone); bool *isNull, ExprDoneCond *isDone);
static Datum ExecEvalConstraintTestValue(ConstraintTestValue *conVal, static Datum ExecEvalConstraintTestValue(ConstraintTestValue *conVal,
ExprContext *econtext, ExprContext *econtext, bool *isNull);
bool *isNull, ExprDoneCond *isDone);
/*---------- /*----------
@ -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 * ExecEvalConstraintTest
* *
@ -1585,6 +1567,9 @@ ExecEvalConstraintTest(ConstraintTest *constraint, ExprContext *econtext,
result = ExecEvalExpr((Node *) constraint->arg, econtext, isNull, isDone); result = ExecEvalExpr((Node *) constraint->arg, econtext, isNull, isDone);
if (isDone && *isDone == ExprEndResult)
return result; /* nothing to check */
switch (constraint->testtype) switch (constraint->testtype)
{ {
case CONSTR_TEST_NOTNULL: case CONSTR_TEST_NOTNULL:
@ -1595,16 +1580,32 @@ ExecEvalConstraintTest(ConstraintTest *constraint, ExprContext *econtext,
case CONSTR_TEST_CHECK: case CONSTR_TEST_CHECK:
{ {
Datum conResult; 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_datum = result;
econtext->domainValue_isNull = *isNull; 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", elog(ERROR, "ExecEvalConstraintTest: Domain %s constraint %s failed",
constraint->domname, constraint->name); constraint->domname, constraint->name);
econtext->domainValue_datum = save_datum;
econtext->domainValue_isNull = save_isNull;
} }
break; break;
default: default:
@ -1616,6 +1617,19 @@ ExecEvalConstraintTest(ConstraintTest *constraint, ExprContext *econtext,
return result; 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 * ExecEvalFieldSelect
* *
@ -1812,8 +1826,7 @@ ExecEvalExpr(Node *expression,
case T_ConstraintTestValue: case T_ConstraintTestValue:
retDatum = ExecEvalConstraintTestValue((ConstraintTestValue *) expression, retDatum = ExecEvalConstraintTestValue((ConstraintTestValue *) expression,
econtext, econtext,
isNull, isNull);
isDone);
break; break;
default: default:
elog(ERROR, "ExecEvalExpr: unknown expression type %d", elog(ERROR, "ExecEvalExpr: unknown expression type %d",

View File

@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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; return newnode;
} }
static DomainConstraintValue *
_copyDomainConstraintValue(DomainConstraintValue *from)
{
DomainConstraintValue *newnode = makeNode(DomainConstraintValue);
return newnode;
}
static SortGroupBy * static SortGroupBy *
_copySortGroupBy(SortGroupBy *from) _copySortGroupBy(SortGroupBy *from)
{ {
@ -2763,9 +2755,6 @@ copyObject(void *from)
case T_TypeCast: case T_TypeCast:
retval = _copyTypeCast(from); retval = _copyTypeCast(from);
break; break;
case T_DomainConstraintValue:
retval = _copyDomainConstraintValue(from);
break;
case T_SortGroupBy: case T_SortGroupBy:
retval = _copySortGroupBy(from); retval = _copySortGroupBy(from);
break; break;

View File

@ -18,7 +18,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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; return true;
} }
static bool
_equalDomainConstraintValue(DomainConstraintValue *a, DomainConstraintValue *b)
{
return true;
}
static bool static bool
_equalClosePortalStmt(ClosePortalStmt *a, ClosePortalStmt *b) _equalClosePortalStmt(ClosePortalStmt *a, ClosePortalStmt *b)
{ {
@ -1931,9 +1925,6 @@ equal(void *a, void *b)
case T_InsertDefault: case T_InsertDefault:
retval = _equalInsertDefault(a, b); retval = _equalInsertDefault(a, b);
break; break;
case T_DomainConstraintValue:
retval = _equalDomainConstraintValue(a, b);
break;
default: default:
elog(WARNING, "equal: don't know whether nodes of type %d are equal", elog(WARNING, "equal: don't know whether nodes of type %d are equal",

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* Every node type that can appear in stored rules' parsetrees *must* * Every node type that can appear in stored rules' parsetrees *must*
@ -1299,12 +1299,6 @@ _outExprFieldSelect(StringInfo str, ExprFieldSelect *node)
WRITE_NODE_FIELD(indirection); WRITE_NODE_FIELD(indirection);
} }
static void
_outDomainConstraintValue(StringInfo str, DomainConstraintValue *node)
{
WRITE_NODE_TYPE("DOMAINCONSTRAINTVALUE");
}
static void static void
_outConstraint(StringInfo str, Constraint *node) _outConstraint(StringInfo str, Constraint *node)
{ {
@ -1637,9 +1631,6 @@ _outNode(StringInfo str, void *obj)
case T_ExprFieldSelect: case T_ExprFieldSelect:
_outExprFieldSelect(str, obj); _outExprFieldSelect(str, obj);
break; break;
case T_DomainConstraintValue:
_outDomainConstraintValue(str, obj);
break;
case T_Constraint: case T_Constraint:
_outConstraint(str, obj); _outConstraint(str, obj);
break; break;

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* Path and Plan nodes do not have any readfuncs support, because we * Path and Plan nodes do not have any readfuncs support, because we
@ -792,17 +792,6 @@ _readExprFieldSelect(void)
READ_DONE(); READ_DONE();
} }
/*
* _readDomainConstraintValue
*/
static DomainConstraintValue *
_readDomainConstraintValue(void)
{
READ_LOCALS_NO_FIELDS(DomainConstraintValue);
READ_DONE();
}
/* /*
* _readRangeTblEntry * _readRangeTblEntry
*/ */
@ -935,8 +924,6 @@ parseNodeString(void)
return_value = _readTypeName(); return_value = _readTypeName();
else if (MATCH("EXPRFIELDSELECT", 15)) else if (MATCH("EXPRFIELDSELECT", 15))
return_value = _readExprFieldSelect(); return_value = _readExprFieldSelect();
else if (MATCH("DOMAINCONSTRAINTVALUE", 21))
return_value = _readDomainConstraintValue();
else if (MATCH("RTE", 3)) else if (MATCH("RTE", 3))
return_value = _readRangeTblEntry(); return_value = _readRangeTblEntry();
else else

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * HISTORY
* AUTHOR DATE MAJOR EVENT * AUTHOR DATE MAJOR EVENT
@ -2129,6 +2129,7 @@ expression_tree_walker(Node *node,
case T_Var: case T_Var:
case T_Const: case T_Const:
case T_Param: case T_Param:
case T_ConstraintTestValue:
case T_RangeTblRef: case T_RangeTblRef:
/* primitive node types with no subnodes */ /* primitive node types with no subnodes */
break; break;
@ -2265,8 +2266,6 @@ expression_tree_walker(Node *node,
if (walker(((ConstraintTest *) node)->arg, context)) if (walker(((ConstraintTest *) node)->arg, context))
return true; return true;
return walker(((ConstraintTest *) node)->check_expr, context); return walker(((ConstraintTest *) node)->check_expr, context);
case T_ConstraintTestValue:
break;
case T_TargetEntry: case T_TargetEntry:
return walker(((TargetEntry *) node)->expr, context); return walker(((TargetEntry *) node)->expr, context);
case T_Query: case T_Query:
@ -2474,6 +2473,7 @@ expression_tree_mutator(Node *node,
case T_Var: case T_Var:
case T_Const: case T_Const:
case T_Param: case T_Param:
case T_ConstraintTestValue:
case T_RangeTblRef: case T_RangeTblRef:
/* primitive node types with no subnodes */ /* primitive node types with no subnodes */
return (Node *) copyObject(node); return (Node *) copyObject(node);
@ -2651,15 +2651,6 @@ expression_tree_mutator(Node *node,
return (Node *) newnode; return (Node *) newnode;
} }
break; break;
case T_ConstraintTestValue:
{
ConstraintTestValue *ctest = (ConstraintTestValue *) node;
ConstraintTestValue *newnode;
FLATCOPY(newnode, ctest, ConstraintTestValue);
return (Node *) newnode;
}
break;
case T_TargetEntry: case T_TargetEntry:
{ {
/* /*

View File

@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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, Oid expected_type_id,
given_type_id; given_type_id;
expr = transformExpr(pstate, expr, NULL); expr = transformExpr(pstate, expr);
/* Cannot contain subselects or aggregates */ /* Cannot contain subselects or aggregates */
if (contain_subplans(expr)) if (contain_subplans(expr))

View File

@ -11,7 +11,7 @@
* *
* *
* IDENTIFICATION * 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 * HISTORY
* AUTHOR DATE MAJOR EVENT * AUTHOR DATE MAJOR EVENT
@ -393,7 +393,7 @@ static void doNegateFloat(Value *v);
UNENCRYPTED UNION UNIQUE UNKNOWN UNLISTEN UNTIL UNENCRYPTED UNION UNIQUE UNKNOWN UNLISTEN UNTIL
UPDATE USAGE USER USING UPDATE USAGE USER USING
VACUUM VALID VALIDATOR VALUE VALUES VARCHAR VARYING VACUUM VALID VALIDATOR VALUES VARCHAR VARYING
VERBOSE VERSION VIEW VOLATILE VERBOSE VERSION VIEW VOLATILE
WHEN WHERE WITH WITHOUT WORK WRITE WHEN WHERE WITH WITHOUT WORK WRITE
@ -6464,11 +6464,6 @@ c_expr: columnref { $$ = (Node *) $1; }
n->subselect = $2; n->subselect = $2;
$$ = (Node *)n; $$ = (Node *)n;
} }
| VALUE
{
DomainConstraintValue *n = makeNode(DomainConstraintValue);
$$ = (Node *)n;
}
; ;
/* /*
@ -7378,7 +7373,6 @@ reserved_keyword:
| UNIQUE | UNIQUE
| USER | USER
| USING | USING
| VALUE
| WHEN | WHEN
| WHERE | WHERE
; ;

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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}, {"vacuum", VACUUM},
{"valid", VALID}, {"valid", VALID},
{"validator", VALIDATOR}, {"validator", VALIDATOR},
{"value", VALUE},
{"values", VALUES}, {"values", VALUES},
{"varchar", VARCHAR}, {"varchar", VARCHAR},
{"varying", VARYING}, {"varying", VARYING},

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * transformJoinOnClause() does. Just invoke transformExpr() to fix
* up the operators, and we're done. * up the operators, and we're done.
*/ */
result = transformExpr(pstate, result, NULL); result = transformExpr(pstate, result);
result = coerce_to_boolean(result, "JOIN/USING"); result = coerce_to_boolean(result, "JOIN/USING");
@ -317,7 +317,7 @@ transformJoinOnClause(ParseState *pstate, JoinExpr *j,
pstate->p_namespace = makeList2(j->larg, j->rarg); pstate->p_namespace = makeList2(j->larg, j->rarg);
/* This part is just like transformWhereClause() */ /* This part is just like transformWhereClause() */
result = transformExpr(pstate, j->quals, NULL); result = transformExpr(pstate, j->quals);
result = coerce_to_boolean(result, "JOIN/ON"); result = coerce_to_boolean(result, "JOIN/ON");
@ -478,7 +478,7 @@ transformRangeFunction(ParseState *pstate, RangeFunction *r)
save_namespace = pstate->p_namespace; save_namespace = pstate->p_namespace;
pstate->p_namespace = NIL; pstate->p_namespace = NIL;
funcexpr = transformExpr(pstate, r->funccallnode, NULL); funcexpr = transformExpr(pstate, r->funccallnode);
pstate->p_namespace = save_namespace; pstate->p_namespace = save_namespace;
@ -950,7 +950,7 @@ transformWhereClause(ParseState *pstate, Node *clause)
if (clause == NULL) if (clause == NULL)
return NULL; return NULL;
qual = transformExpr(pstate, clause, NULL); qual = transformExpr(pstate, clause);
qual = coerce_to_boolean(qual, "WHERE"); 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 * willing to match a resjunk target here, though the above cases must
* ignore resjunk targets. * ignore resjunk targets.
*/ */
expr = transformExpr(pstate, node, NULL); expr = transformExpr(pstate, node);
foreach(tl, tlist) foreach(tl, tlist)
{ {

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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->testtype = CONSTR_TEST_CHECK;
r->name = NameStr(c->conname); r->name = NameStr(c->conname);
r->domname = NameStr(typTup->typname); r->domname = NameStr(typTup->typname);
r->check_expr = stringToNode(MemoryContextStrdup(CacheMemoryContext, r->check_expr = stringToNode(DatumGetCString(DirectFunctionCall1(textout,
DatumGetCString(DirectFunctionCall1(textout, val)));
val))));
arg = (Node *) r; arg = (Node *) r;
} }

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 "miscadmin.h"
#include "nodes/makefuncs.h" #include "nodes/makefuncs.h"
#include "nodes/params.h" #include "nodes/params.h"
#include "optimizer/clauses.h"
#include "parser/analyze.h" #include "parser/analyze.h"
#include "parser/gramparse.h" #include "parser/gramparse.h"
#include "parser/parse.h" #include "parser/parse.h"
@ -84,7 +83,7 @@ parse_expr_init(void)
* input and output of transformExpr; see SubLink for example. * input and output of transformExpr; see SubLink for example.
*/ */
Node * Node *
transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal) transformExpr(ParseState *pstate, Node *expr)
{ {
Node *result = NULL; Node *result = NULL;
@ -152,7 +151,7 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
ExprFieldSelect *efs = (ExprFieldSelect *) expr; ExprFieldSelect *efs = (ExprFieldSelect *) expr;
List *fields; List *fields;
result = transformExpr(pstate, efs->arg, domVal); result = transformExpr(pstate, efs->arg);
/* handle qualification, if any */ /* handle qualification, if any */
foreach(fields, efs->fields) foreach(fields, efs->fields)
{ {
@ -169,7 +168,7 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
case T_TypeCast: case T_TypeCast:
{ {
TypeCast *tc = (TypeCast *) expr; TypeCast *tc = (TypeCast *) expr;
Node *arg = transformExpr(pstate, tc->arg, domVal); Node *arg = transformExpr(pstate, tc->arg);
result = typecast_expression(arg, tc->typename); result = typecast_expression(arg, tc->typename);
break; break;
@ -204,14 +203,14 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
n->arg = (Expr *) a->lexpr; n->arg = (Expr *) a->lexpr;
result = transformExpr(pstate, result = transformExpr(pstate,
(Node *) n, domVal); (Node *) n);
} }
else else
{ {
Node *lexpr = transformExpr(pstate, Node *lexpr = transformExpr(pstate,
a->lexpr, domVal); a->lexpr);
Node *rexpr = transformExpr(pstate, Node *rexpr = transformExpr(pstate,
a->rexpr, domVal); a->rexpr);
result = (Node *) make_op(a->name, result = (Node *) make_op(a->name,
lexpr, lexpr,
@ -222,9 +221,9 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
case AND: case AND:
{ {
Node *lexpr = transformExpr(pstate, Node *lexpr = transformExpr(pstate,
a->lexpr, domVal); a->lexpr);
Node *rexpr = transformExpr(pstate, Node *rexpr = transformExpr(pstate,
a->rexpr, domVal); a->rexpr);
lexpr = coerce_to_boolean(lexpr, "AND"); lexpr = coerce_to_boolean(lexpr, "AND");
rexpr = coerce_to_boolean(rexpr, "AND"); rexpr = coerce_to_boolean(rexpr, "AND");
@ -237,9 +236,9 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
case OR: case OR:
{ {
Node *lexpr = transformExpr(pstate, Node *lexpr = transformExpr(pstate,
a->lexpr, domVal); a->lexpr);
Node *rexpr = transformExpr(pstate, Node *rexpr = transformExpr(pstate,
a->rexpr, domVal); a->rexpr);
lexpr = coerce_to_boolean(lexpr, "OR"); lexpr = coerce_to_boolean(lexpr, "OR");
rexpr = coerce_to_boolean(rexpr, "OR"); rexpr = coerce_to_boolean(rexpr, "OR");
@ -252,7 +251,7 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
case NOT: case NOT:
{ {
Node *rexpr = transformExpr(pstate, Node *rexpr = transformExpr(pstate,
a->rexpr, domVal); a->rexpr);
rexpr = coerce_to_boolean(rexpr, "NOT"); rexpr = coerce_to_boolean(rexpr, "NOT");
@ -263,9 +262,9 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
case DISTINCT: case DISTINCT:
{ {
Node *lexpr = transformExpr(pstate, Node *lexpr = transformExpr(pstate,
a->lexpr, domVal); a->lexpr);
Node *rexpr = transformExpr(pstate, Node *rexpr = transformExpr(pstate,
a->rexpr, domVal); a->rexpr);
result = (Node *) make_op(a->name, result = (Node *) make_op(a->name,
lexpr, lexpr,
@ -291,7 +290,7 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
* Will result in a boolean constant node. * Will result in a boolean constant node.
*/ */
Node *lexpr = transformExpr(pstate, Node *lexpr = transformExpr(pstate,
a->lexpr, domVal); a->lexpr);
ltype = exprType(lexpr); ltype = exprType(lexpr);
foreach(telem, (List *) a->rexpr) foreach(telem, (List *) a->rexpr)
@ -315,7 +314,7 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
n->val.val.str = (matched ? "t" : "f"); n->val.val.str = (matched ? "t" : "f");
n->typename = SystemTypeName("bool"); n->typename = SystemTypeName("bool");
result = transformExpr(pstate, (Node *) n, domVal); result = transformExpr(pstate, (Node *) n);
} }
break; break;
} }
@ -329,7 +328,7 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
/* transform the list of arguments */ /* transform the list of arguments */
foreach(args, fn->args) foreach(args, fn->args)
lfirst(args) = transformExpr(pstate, lfirst(args) = transformExpr(pstate,
(Node *) lfirst(args), domVal); (Node *) lfirst(args));
result = ParseFuncOrColumn(pstate, result = ParseFuncOrColumn(pstate,
fn->funcname, fn->funcname,
fn->args, fn->args,
@ -403,7 +402,7 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
List *elist; List *elist;
foreach(elist, left_list) foreach(elist, left_list)
lfirst(elist) = transformExpr(pstate, lfirst(elist), domVal); lfirst(elist) = transformExpr(pstate, lfirst(elist));
Assert(IsA(sublink->oper, A_Expr)); Assert(IsA(sublink->oper, A_Expr));
op = ((A_Expr *) sublink->oper)->name; op = ((A_Expr *) sublink->oper)->name;
@ -507,7 +506,7 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
(Node *) c->arg, (Node *) c->arg,
warg); warg);
} }
neww->expr = (Expr *) transformExpr(pstate, warg, domVal); neww->expr = (Expr *) transformExpr(pstate, warg);
neww->expr = (Expr *) coerce_to_boolean((Node *) neww->expr, neww->expr = (Expr *) coerce_to_boolean((Node *) neww->expr,
"CASE/WHEN"); "CASE/WHEN");
@ -524,7 +523,7 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
n->val.type = T_Null; n->val.type = T_Null;
warg = (Node *) n; warg = (Node *) n;
} }
neww->result = (Expr *) transformExpr(pstate, warg, domVal); neww->result = (Expr *) transformExpr(pstate, warg);
newargs = lappend(newargs, neww); newargs = lappend(newargs, neww);
typeids = lappendi(typeids, exprType((Node *) neww->result)); typeids = lappendi(typeids, exprType((Node *) neww->result));
@ -548,7 +547,7 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
n->val.type = T_Null; n->val.type = T_Null;
defresult = (Node *) n; defresult = (Node *) n;
} }
newc->defresult = (Expr *) transformExpr(pstate, defresult, domVal); newc->defresult = (Expr *) transformExpr(pstate, defresult);
/* /*
* Note: default result is considered the most significant * Note: default result is considered the most significant
@ -586,7 +585,7 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
{ {
NullTest *n = (NullTest *) expr; 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 */ /* the argument can be any type, so don't coerce it */
result = expr; result = expr;
break; break;
@ -623,7 +622,7 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
clausename = NULL; /* keep compiler quiet */ 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); b->arg = (Expr *) coerce_to_boolean((Node *) b->arg, clausename);
@ -631,21 +630,6 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
break; 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 * Quietly accept node types that may be presented when we are
* called on an already-transformed tree. * called on an already-transformed tree.
@ -663,6 +647,7 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
case T_FieldSelect: case T_FieldSelect:
case T_RelabelType: case T_RelabelType:
case T_ConstraintTest: case T_ConstraintTest:
case T_ConstraintTestValue:
{ {
result = (Node *) expr; result = (Node *) expr;
break; break;
@ -700,6 +685,7 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
int numnames = length(cref->fields); int numnames = length(cref->fields);
Node *node; Node *node;
RangeVar *rv; RangeVar *rv;
int levels_up;
/*---------- /*----------
* The allowed syntaxes are: * The allowed syntaxes are:
@ -740,18 +726,30 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
if (node == NULL) if (node == NULL)
{ {
/* /*
* Not known as a column of any range-table entry, so * Not known as a column of any range-table entry.
* try to find the name as a relation ... but not if *
* 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 * subscripts appear. Note also that only relations
* already entered into the rangetable will be * already entered into the rangetable will be
* recognized. * recognized.
* *
* This is a hack for backwards compatibility with * This is a hack for backwards compatibility with
* PostQUEL- inspired syntax. The preferred form now * PostQUEL-inspired syntax. The preferred form now
* is "rel.*". * is "rel.*".
*/ */
int levels_up;
if (cref->indirection == NIL && if (cref->indirection == NIL &&
refnameRangeTblEntry(pstate, NULL, name, refnameRangeTblEntry(pstate, NULL, name,
&levels_up) != NULL) &levels_up) != NULL)
@ -1055,7 +1053,8 @@ exprTypmod(Node *expr)
break; break;
case T_ConstraintTest: case T_ConstraintTest:
return exprTypmod((Node *) ((ConstraintTest *) expr)->arg); return exprTypmod((Node *) ((ConstraintTest *) expr)->arg);
case T_ConstraintTestValue:
return ((ConstraintTestValue *) expr)->typeMod;
default: default:
break; break;
} }

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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) if (ai->lidx)
{ {
subexpr = transformExpr(pstate, ai->lidx, NULL); subexpr = transformExpr(pstate, ai->lidx);
/* If it's not int4 already, try to coerce */ /* If it's not int4 already, try to coerce */
subexpr = coerce_to_target_type(subexpr, exprType(subexpr), subexpr = coerce_to_target_type(subexpr, exprType(subexpr),
INT4OID, -1, INT4OID, -1,
@ -292,7 +292,7 @@ transformArraySubscripts(ParseState *pstate,
} }
lowerIndexpr = lappend(lowerIndexpr, subexpr); lowerIndexpr = lappend(lowerIndexpr, subexpr);
} }
subexpr = transformExpr(pstate, ai->uidx, NULL); subexpr = transformExpr(pstate, ai->uidx);
/* If it's not int4 already, try to coerce */ /* If it's not int4 already, try to coerce */
subexpr = coerce_to_target_type(subexpr, exprType(subexpr), subexpr = coerce_to_target_type(subexpr, exprType(subexpr),
INT4OID, -1, INT4OID, -1,

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 */ /* Transform the node if caller didn't do it already */
if (expr == NULL) if (expr == NULL)
expr = transformExpr(pstate, node, NULL); expr = transformExpr(pstate, node);
if (IsA(expr, RangeVar)) if (IsA(expr, RangeVar))
elog(ERROR, "You can't use relation names alone in the target list, try relation.*."); elog(ERROR, "You can't use relation names alone in the target list, try relation.*.");

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 * * ecxt_per_query_memory is a relatively long-lived context (such as
* TransactionCommandContext); typically it's the same context the * TransactionCommandContext); typically it's the same context the
* ExprContext node itself is allocated in. This context can be * 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. * * ecxt_per_tuple_memory is a short-term context for expression results.
* As the name suggests, it will typically be reset once per tuple, * As the name suggests, it will typically be reset once per tuple,
* before we begin to evaluate expressions for that tuple. Each * 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 */ Datum *ecxt_aggvalues; /* precomputed values for Aggref nodes */
bool *ecxt_aggnulls; /* null flags for Aggref nodes */ bool *ecxt_aggnulls; /* null flags for Aggref nodes */
/* /* Value to substitute for ConstraintTestValue nodes in expression */
* Carry the domain value through the executor for application
* in a domain constraint
*/
Datum domainValue_datum; Datum domainValue_datum;
bool domainValue_isNull; bool domainValue_isNull;

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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_FuncWithArgs,
T_PrivTarget, T_PrivTarget,
T_InsertDefault, T_InsertDefault,
T_DomainConstraintValue,
T_CreateOpClassItem, T_CreateOpClassItem,
T_CompositeTypeStmt, T_CompositeTypeStmt,

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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; NodeTag type;
} InsertDefault; } 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 * SortGroupBy - for ORDER BY clause
*/ */

View File

@ -10,7 +10,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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; } ConstraintTest;
/* /*
* Placeholder node for the value to be processed by a domains * Placeholder node for the value to be processed by a domain's check
* check constraint. This is effectively like a Param; could we use * constraint. This is effectively like a Param, but can be implemented more
* a Param node instead? * 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 typedef struct ConstraintTestValue
{ {
Expr xpr; Expr xpr;
Oid typeId; Oid typeId; /* type for substituted value */
int32 typeMod; int32 typeMod; /* typemod for substituted value */
} ConstraintTestValue; } ConstraintTestValue;

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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); int levelsup);
extern bool contain_whole_tuple_var(Node *node, int varno, 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_clause(Node *node);
extern bool contain_var_tuple_clause(Node *node);
extern List *pull_var_clause(Node *node, bool includeUpperVars); extern List *pull_var_clause(Node *node, bool includeUpperVars);
extern Node *flatten_join_alias_vars(Node *node, List *rtable, bool force); extern Node *flatten_join_alias_vars(Node *node, List *rtable, bool force);

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 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 Oid exprType(Node *expr);
extern int32 exprTypmod(Node *expr); extern int32 exprTypmod(Node *expr);
extern bool exprIsLengthCoercion(Node *expr, int32 *coercedTypmod); extern bool exprIsLengthCoercion(Node *expr, int32 *coercedTypmod);

View File

@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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) */ List *p_namespace; /* current lookup namespace (join items) */
int p_last_resno; /* last targetlist resno assigned */ int p_last_resno; /* last targetlist resno assigned */
List *p_forUpdate; /* FOR UPDATE clause, if any (see gram.y) */ 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_hasAggs;
bool p_hasSubLinks; bool p_hasSubLinks;
bool p_is_insert; bool p_is_insert;

View File

@ -115,7 +115,7 @@ INSERT INTO nulltest DEFAULT VALUES;
ERROR: Domain dnotnull does not allow NULL 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', 'c'); -- Good
insert into nulltest values ('a', 'b', 'c', 'd', NULL); 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'); insert into nulltest values ('a', 'b', 'c', 'd', 'a');
ERROR: ExecInsert: rejected due to CHECK constraint "nulltest_col5" on "nulltest" ERROR: ExecInsert: rejected due to CHECK constraint "nulltest_col5" on "nulltest"
INSERT INTO nulltest values (NULL, 'b', 'c', 'd', 'd'); 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 INSERT INTO nulltest values ('a', 'b', 'c', NULL, 'd'); -- Good
-- Test copy -- Test copy
COPY nulltest FROM stdin; --fail 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 lost synchronization with server, resetting connection
SET autocommit TO 'on'; SET autocommit TO 'on';
-- Last row is bad -- Last row is bad