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