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
-->
@ -30,7 +30,7 @@ CREATE DOMAIN <replaceable class="parameter">domainname</replaceable> [AS] <repl
where <replaceable class="PARAMETER">constraint</replaceable> is:
[ CONSTRAINT <replaceable class="PARAMETER">constraint_name</replaceable> ]
{ NOT NULL | NULL }
{ NOT NULL | NULL | CHECK (<replaceable class="PARAMETER">expression</replaceable>) }
</synopsis>
<refsect2 id="R2-SQL-CREATEDOMAIN-1">
@ -128,6 +128,25 @@ where <replaceable class="PARAMETER">constraint</replaceable> is:
</listitem>
</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>
</para>
</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">
@ -24,6 +24,7 @@ CDATA means the content is "SGML-free", so you can write without
worries about funny characters.
-->
<literallayout><![CDATA[
Domains now support CHECK constraints
]]></literallayout>
</sect1>

View File

@ -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.

View File

@ -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
{

View File

@ -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.

View File

@ -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;
}

View File

@ -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",

View File

@ -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;

View File

@ -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",

View File

@ -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;

View File

@ -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

View File

@ -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:
{
/*

View File

@ -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))

View File

@ -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
;

View File

@ -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},

View File

@ -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)
{

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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,

View File

@ -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.*.");

View File

@ -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;

View File

@ -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,

View File

@ -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
*/

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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