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:
parent
ff7349694f
commit
b0422b215c
@ -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>
|
||||||
|
@ -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>
|
||||||
|
@ -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.
|
||||||
|
@ -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
|
||||||
{
|
{
|
||||||
|
@ -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.
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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",
|
||||||
|
@ -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;
|
||||||
|
@ -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",
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
|
@ -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:
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
@ -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))
|
||||||
|
@ -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
|
||||||
;
|
;
|
||||||
|
@ -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},
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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,8 +726,22 @@ 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.
|
||||||
@ -750,8 +750,6 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
|
|||||||
* 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;
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
@ -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.*.");
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
|
||||||
|
@ -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
|
||||||
*/
|
*/
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user