? configure.lineno
? src/backend/catalog/.pg_constraint.c.swp
? src/backend/optimizer/util/.var.c.swp
Index: doc/src/sgml/ref/create_domain.sgml
===================================================================
RCS file: /projects/cvsroot/pgsql-server/doc/src/sgml/ref/create_domain.sgml,v
retrieving revision 1.6
diff -c -r1.6 create_domain.sgml
*** doc/src/sgml/ref/create_domain.sgml 2002/09/20 03:39:15 1.6
--- doc/src/sgml/ref/create_domain.sgml 2002/11/08 19:47:53
***************
*** 200,215 ****
-
- Compatibility
-
-
- SQL99 defines CREATE DOMAIN, but says that the only allowed constraint
- type is CHECK constraints. CHECK constraints for domains are not yet
- supported by PostgreSQL.
-
-
-
See Also
--- 200,205 ----
Index: src/backend/catalog/heap.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/backend/catalog/heap.c,v
retrieving revision 1.232
diff -c -r1.232 heap.c
*** src/backend/catalog/heap.c 2002/10/21 22:06:18 1.232
--- src/backend/catalog/heap.c 2002/11/08 19:47:53
***************
*** 1487,1493 ****
ccname = cdef->name;
/* Check against pre-existing constraints */
! if (ConstraintNameIsUsed(RelationGetRelid(rel),
RelationGetNamespace(rel),
ccname))
elog(ERROR, "constraint \"%s\" already exists for relation \"%s\"",
--- 1487,1494 ----
ccname = cdef->name;
/* Check against pre-existing constraints */
! if (ConstraintNameIsUsed(CONSTRAINT_RELATION,
! RelationGetRelid(rel),
RelationGetNamespace(rel),
ccname))
elog(ERROR, "constraint \"%s\" already exists for relation \"%s\"",
***************
*** 1521,1527 ****
* pre-existing constraints, nor with any auto-generated
* names so far.
*/
! ccname = GenerateConstraintName(RelationGetRelid(rel),
RelationGetNamespace(rel),
&constr_name_ctr);
--- 1522,1529 ----
* pre-existing constraints, nor with any auto-generated
* names so far.
*/
! ccname = GenerateConstraintName(CONSTRAINT_RELATION,
! RelationGetRelid(rel),
RelationGetNamespace(rel),
&constr_name_ctr);
***************
*** 1552,1558 ****
/*
* Transform raw parsetree to executable expression.
*/
! expr = transformExpr(pstate, cdef->raw_expr);
/*
* Make sure it yields a boolean result.
--- 1554,1560 ----
/*
* Transform raw parsetree to executable expression.
*/
! expr = transformExpr(pstate, cdef->raw_expr, NULL);
/*
* Make sure it yields a boolean result.
***************
*** 1681,1687 ****
/*
* Transform raw parsetree to executable expression.
*/
! expr = transformExpr(pstate, raw_default);
/*
* Make sure default expr does not refer to any vars.
--- 1683,1689 ----
/*
* Transform raw parsetree to executable expression.
*/
! expr = transformExpr(pstate, raw_default, NULL);
/*
* Make sure default expr does not refer to any vars.
Index: src/backend/catalog/pg_constraint.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/backend/catalog/pg_constraint.c,v
retrieving revision 1.7
diff -c -r1.7 pg_constraint.c
*** src/backend/catalog/pg_constraint.c 2002/09/22 00:37:09 1.7
--- src/backend/catalog/pg_constraint.c 2002/11/08 19:47:53
***************
*** 190,195 ****
--- 190,208 ----
}
}
+ if (OidIsValid(domainId))
+ {
+ /*
+ * Register auto dependency from constraint to owning domain
+ */
+ ObjectAddress domobject;
+
+ domobject.classId = RelOid_pg_type;
+ domobject.objectId = domainId;
+
+ recordDependencyOn(&conobject, &domobject, DEPENDENCY_AUTO);
+ }
+
if (OidIsValid(foreignRelId))
{
/*
***************
*** 262,268 ****
* this test is not very meaningful.
*/
bool
! ConstraintNameIsUsed(Oid relId, Oid relNamespace, const char *cname)
{
bool found;
Relation conDesc;
--- 275,281 ----
* this test is not very meaningful.
*/
bool
! ConstraintNameIsUsed(CONSTRAINTCATEGORY conCat, Oid objId, Oid objNamespace, const char *cname)
{
bool found;
Relation conDesc;
***************
*** 280,286 ****
ScanKeyEntryInitialize(&skey[1], 0x0,
Anum_pg_constraint_connamespace, F_OIDEQ,
! ObjectIdGetDatum(relNamespace));
conscan = systable_beginscan(conDesc, ConstraintNameNspIndex, true,
SnapshotNow, 2, skey);
--- 293,299 ----
ScanKeyEntryInitialize(&skey[1], 0x0,
Anum_pg_constraint_connamespace, F_OIDEQ,
! ObjectIdGetDatum(objNamespace));
conscan = systable_beginscan(conDesc, ConstraintNameNspIndex, true,
SnapshotNow, 2, skey);
***************
*** 289,299 ****
{
Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tup);
! if (con->conrelid == relId)
{
found = true;
break;
}
}
systable_endscan(conscan);
--- 302,317 ----
{
Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tup);
! if (conCat == CONSTRAINT_RELATION && con->conrelid == objId)
{
found = true;
break;
}
+ else if (conCat == CONSTRAINT_DOMAIN && con->contypid == objId)
+ {
+ found = true;
+ break;
+ }
}
systable_endscan(conscan);
***************
*** 314,320 ****
* someone else might choose the same name concurrently!
*/
char *
! GenerateConstraintName(Oid relId, Oid relNamespace, int *counter)
{
bool found;
Relation conDesc;
--- 332,338 ----
* someone else might choose the same name concurrently!
*/
char *
! GenerateConstraintName(CONSTRAINTCATEGORY conCat, Oid objId, Oid objNamespace, int *counter)
{
bool found;
Relation conDesc;
***************
*** 347,353 ****
ScanKeyEntryInitialize(&skey[1], 0x0,
Anum_pg_constraint_connamespace, F_OIDEQ,
! ObjectIdGetDatum(relNamespace));
conscan = systable_beginscan(conDesc, ConstraintNameNspIndex, true,
SnapshotNow, 2, skey);
--- 365,371 ----
ScanKeyEntryInitialize(&skey[1], 0x0,
Anum_pg_constraint_connamespace, F_OIDEQ,
! ObjectIdGetDatum(objNamespace));
conscan = systable_beginscan(conDesc, ConstraintNameNspIndex, true,
SnapshotNow, 2, skey);
***************
*** 356,366 ****
{
Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tup);
! if (con->conrelid == relId)
{
found = true;
break;
}
}
systable_endscan(conscan);
--- 374,389 ----
{
Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tup);
! if (conCat == CONSTRAINT_RELATION && con->conrelid == objId)
{
found = true;
break;
}
+ else if (conCat == CONSTRAINT_DOMAIN && con->contypid == objId)
+ {
+ found = true;
+ break;
+ }
}
systable_endscan(conscan);
***************
*** 415,424 ****
con = (Form_pg_constraint) GETSTRUCT(tup);
/*
! * If the constraint is for a relation, open and exclusive-lock the
! * relation it's for.
*
! * XXX not clear what we should lock, if anything, for other constraints.
*/
if (OidIsValid(con->conrelid))
{
--- 438,450 ----
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.
*/
if (OidIsValid(con->conrelid))
{
***************
*** 462,467 ****
--- 488,521 ----
/* 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;
+
+ typRel = heap_openr(TypeRelationName, RowExclusiveLock);
+
+ ScanKeyEntryInitialize(&typKey[0], 0x0,
+ Anum_pg_constraint_contypid, F_OIDEQ,
+ ObjectIdGetDatum(con->contypid));
+
+ typScan = systable_beginscan(typRel, TypeOidIndex, true,
+ SnapshotNow, 1, 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);
}
/* Fry the constraint itself */
Index: src/backend/commands/tablecmds.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/backend/commands/tablecmds.c,v
retrieving revision 1.51
diff -c -r1.51 tablecmds.c
*** src/backend/commands/tablecmds.c 2002/11/02 22:02:08 1.51
--- src/backend/commands/tablecmds.c 2002/11/08 19:47:54
***************
*** 2614,2627 ****
*/
if (constr->name)
{
! if (ConstraintNameIsUsed(RelationGetRelid(rel),
RelationGetNamespace(rel),
constr->name))
elog(ERROR, "constraint \"%s\" already exists for relation \"%s\"",
constr->name, RelationGetRelationName(rel));
}
else
! constr->name = GenerateConstraintName(RelationGetRelid(rel),
RelationGetNamespace(rel),
&counter);
--- 2614,2629 ----
*/
if (constr->name)
{
! if (ConstraintNameIsUsed(CONSTRAINT_RELATION,
! RelationGetRelid(rel),
RelationGetNamespace(rel),
constr->name))
elog(ERROR, "constraint \"%s\" already exists for relation \"%s\"",
constr->name, RelationGetRelationName(rel));
}
else
! constr->name = GenerateConstraintName(CONSTRAINT_RELATION,
! RelationGetRelid(rel),
RelationGetNamespace(rel),
&counter);
***************
*** 2650,2656 ****
*/
if (fkconstraint->constr_name)
{
! if (ConstraintNameIsUsed(RelationGetRelid(rel),
RelationGetNamespace(rel),
fkconstraint->constr_name))
elog(ERROR, "constraint \"%s\" already exists for relation \"%s\"",
--- 2652,2659 ----
*/
if (fkconstraint->constr_name)
{
! if (ConstraintNameIsUsed(CONSTRAINT_RELATION,
! RelationGetRelid(rel),
RelationGetNamespace(rel),
fkconstraint->constr_name))
elog(ERROR, "constraint \"%s\" already exists for relation \"%s\"",
***************
*** 2658,2664 ****
RelationGetRelationName(rel));
}
else
! fkconstraint->constr_name = GenerateConstraintName(RelationGetRelid(rel),
RelationGetNamespace(rel),
&counter);
--- 2661,2668 ----
RelationGetRelationName(rel));
}
else
! fkconstraint->constr_name = GenerateConstraintName(CONSTRAINT_RELATION,
! RelationGetRelid(rel),
RelationGetNamespace(rel),
&counter);
***************
*** 2716,2722 ****
/*
* Convert the A_EXPR in raw_expr into an EXPR
*/
! expr = transformExpr(pstate, constr->raw_expr);
/*
* Make sure it yields a boolean result.
--- 2720,2726 ----
/*
* Convert the A_EXPR in raw_expr into an EXPR
*/
! expr = transformExpr(pstate, constr->raw_expr, NULL);
/*
* Make sure it yields a boolean result.
Index: src/backend/commands/typecmds.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/backend/commands/typecmds.c,v
retrieving revision 1.15
diff -c -r1.15 typecmds.c
*** src/backend/commands/typecmds.c 2002/09/21 18:39:25 1.15
--- src/backend/commands/typecmds.c 2002/11/08 19:47:54
***************
*** 36,45 ****
--- 36,52 ----
#include "catalog/dependency.h"
#include "catalog/heap.h"
#include "catalog/namespace.h"
+ #include "catalog/pg_constraint.h"
#include "catalog/pg_type.h"
#include "commands/defrem.h"
#include "commands/tablecmds.h"
#include "miscadmin.h"
+ #include "nodes/nodes.h"
+ #include "optimizer/clauses.h"
+ #include "optimizer/planmain.h"
+ #include "optimizer/var.h"
+ #include "parser/parse_coerce.h"
+ #include "parser/parse_expr.h"
#include "parser/parse_func.h"
#include "parser/parse_type.h"
#include "utils/acl.h"
***************
*** 406,412 ****
List *listptr;
Oid basetypeoid;
Oid domainoid;
! Form_pg_type baseType;
/* Convert list of names to a name and namespace */
domainNamespace = QualifiedNameGetCreationNamespace(stmt->domainname,
--- 413,420 ----
List *listptr;
Oid basetypeoid;
Oid domainoid;
! Form_pg_type baseType;
! int counter = 0;
/* Convert list of names to a name and namespace */
domainNamespace = QualifiedNameGetCreationNamespace(stmt->domainname,
***************
*** 484,500 ****
basetypelem = baseType->typelem;
/*
! * Run through constraints manually to avoid the additional processing
! * conducted by DefineRelation() and friends.
! *
! * Besides, we don't want any constraints to be cooked. We'll do that
! * when the table is created via MergeDomainAttributes().
*/
foreach(listptr, schema)
{
! Constraint *colDef = lfirst(listptr);
ParseState *pstate;
switch (colDef->contype)
{
/*
--- 492,512 ----
basetypelem = baseType->typelem;
/*
! * Run through constraints manually to avoid the additional
! * processing conducted by DefineRelation() and friends.
*/
foreach(listptr, schema)
{
! Node *newConstraint = lfirst(listptr);
! Constraint *colDef;
ParseState *pstate;
+ /* Prior to processing, confirm that it is not a foreign key constraint */
+ if (nodeTag(newConstraint) == T_FkConstraint)
+ elog(ERROR, "CREATE DOMAIN / FOREIGN KEY constraints not supported");
+
+ colDef = (Constraint *) newConstraint;
+
switch (colDef->contype)
{
/*
***************
*** 546,572 ****
elog(ERROR, "CREATE DOMAIN has conflicting NULL / NOT NULL constraint");
typNotNull = false;
nullDefined = true;
! break;
! case CONSTR_UNIQUE:
! elog(ERROR, "CREATE DOMAIN / UNIQUE indexes not supported");
! break;
!
! case CONSTR_PRIMARY:
! elog(ERROR, "CREATE DOMAIN / PRIMARY KEY indexes not supported");
! break;
- case CONSTR_CHECK:
- elog(ERROR, "DefineDomain: CHECK Constraints not supported");
- break;
-
- case CONSTR_ATTR_DEFERRABLE:
- case CONSTR_ATTR_NOT_DEFERRABLE:
- case CONSTR_ATTR_DEFERRED:
- case CONSTR_ATTR_IMMEDIATE:
- elog(ERROR, "DefineDomain: DEFERRABLE, NON DEFERRABLE, DEFERRED and IMMEDIATE not supported");
- break;
-
default:
elog(ERROR, "DefineDomain: unrecognized constraint node type");
break;
--- 558,584 ----
elog(ERROR, "CREATE DOMAIN has conflicting NULL / NOT NULL constraint");
typNotNull = false;
nullDefined = true;
! break;
! case CONSTR_UNIQUE:
! elog(ERROR, "CREATE DOMAIN / UNIQUE indexes not supported");
! break;
!
! case CONSTR_PRIMARY:
! elog(ERROR, "CREATE DOMAIN / PRIMARY KEY indexes not supported");
! break;
!
! /* Check constraints are handled after domain creation */
! case CONSTR_CHECK:
! break;
!
! case CONSTR_ATTR_DEFERRABLE:
! case CONSTR_ATTR_NOT_DEFERRABLE:
! case CONSTR_ATTR_DEFERRED:
! case CONSTR_ATTR_IMMEDIATE:
! elog(ERROR, "DefineDomain: DEFERRABLE, NON DEFERRABLE, DEFERRED and IMMEDIATE not supported");
! break;
default:
elog(ERROR, "DefineDomain: unrecognized constraint node type");
break;
***************
*** 591,602 ****
basetypeoid, /* base type ID */
defaultValue, /* default type value (text) */
defaultValueBin, /* default type value (binary) */
! byValue, /* passed by value */
! alignment, /* required alignment */
! storage, /* TOAST strategy */
! stmt->typename->typmod, /* typeMod value */
! typNDims, /* Array dimensions for base type */
! typNotNull); /* Type NOT NULL */
/*
* Add any dependencies needed for the default expression.
--- 603,741 ----
basetypeoid, /* base type ID */
defaultValue, /* default type value (text) */
defaultValueBin, /* default type value (binary) */
! byValue, /* passed by value */
! alignment, /* required alignment */
! storage, /* TOAST strategy */
! stmt->typename->typmod, /* typeMod value */
! typNDims, /* Array dimensions for base type */
! typNotNull); /* Type NOT NULL */
!
! /*
! * Process constraints which refer to the domain ID returned by TypeCreate
! */
! foreach(listptr, schema)
! {
! Constraint *constr = lfirst(listptr);
! ParseState *pstate;
!
! switch (constr->contype)
! {
! case CONSTR_CHECK:
! {
! Node *expr;
! char *ccsrc;
! char *ccbin;
! ConstraintTestValue *domVal;
!
! /*
! * Assign or validate constraint name
! */
! if (constr->name)
! {
! if (ConstraintNameIsUsed(CONSTRAINT_DOMAIN,
! domainoid,
! domainNamespace,
! constr->name))
! elog(ERROR, "constraint \"%s\" already exists for domain \"%s\"",
! constr->name,
! domainName);
! }
! else
! constr->name = GenerateConstraintName(CONSTRAINT_DOMAIN,
! domainoid,
! domainNamespace,
! &counter);
!
! /*
! * 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.
! */
! domVal = makeNode(ConstraintTestValue);
! domVal->typeId = basetypeoid;
! domVal->typeMod = stmt->typename->typmod;
!
! expr = transformExpr(pstate, constr->raw_expr, domVal);
!
! /*
! * 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.
! */
! expr = coerce_to_boolean(expr, "CHECK");
!
! /*
! * Make sure no outside relations are
! * referred to.
! */
! if (length(pstate->p_rtable) != 0)
! elog(ERROR, "Relations cannot be referenced in domain CHECK constraint");
!
! /*
! * No subplans or aggregates, either...
! */
! if (contain_subplans(expr))
! elog(ERROR, "cannot use subselect in CHECK constraint expression");
! if (contain_agg_clause(expr))
! elog(ERROR, "cannot use aggregate function in CHECK constraint expression");
!
! /*
! * Might as well try to reduce any constant expressions.
! */
! expr = eval_const_expressions(expr);
!
! /*
! * Must fix opids in operator clauses.
! */
! fix_opids(expr);
!
! ccbin = nodeToString(expr);
!
! /*
! * Deparse it. Since VARNOs aren't allowed in domain
! * constraints, relation context isn't required as anything
! * other than a shell.
! */
! ccsrc = deparse_expression(expr,
! deparse_context_for(domainName,
! InvalidOid),
! false, false);
!
! /* Write the constraint */
! CreateConstraintEntry(constr->name, /* Constraint Name */
! domainNamespace, /* namespace */
! CONSTRAINT_CHECK, /* Constraint Type */
! false, /* Is Deferrable */
! false, /* Is Deferred */
! InvalidOid, /* not a relation constraint */
! NULL,
! 0,
! domainoid, /* domain constraint */
! InvalidOid, /* Foreign key fields */
! NULL,
! 0,
! ' ',
! ' ',
! ' ',
! InvalidOid,
! expr, /* Tree form check constraint */
! ccbin, /* Binary form check constraint */
! ccsrc); /* Source form check constraint */
! }
! break;
! default:
! break;
! }
! }
/*
* Add any dependencies needed for the default expression.
Index: src/backend/executor/execQual.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/backend/executor/execQual.c,v
retrieving revision 1.108
diff -c -r1.108 execQual.c
*** src/backend/executor/execQual.c 2002/09/04 20:31:17 1.108
--- src/backend/executor/execQual.c 2002/11/08 19:47:55
***************
*** 72,77 ****
--- 72,80 ----
static Datum ExecEvalConstraintTest(ConstraintTest *constraint,
ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone);
+ static Datum ExecEvalConstraintTestValue(ConstraintTestValue *conVal,
+ ExprContext *econtext,
+ bool *isNull, ExprDoneCond *isDone);
/*----------
***************
*** 1552,1557 ****
--- 1555,1577 ----
}
/*
+ * 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
*
* Test the constraint against the data provided. If the data fits
***************
*** 1571,1581 ****
case CONSTR_TEST_NOTNULL:
if (*isNull)
elog(ERROR, "Domain %s does not allow NULL values",
! constraint->name);
break;
case CONSTR_TEST_CHECK:
! /* TODO: Add CHECK Constraints to domains */
! elog(ERROR, "Domain CHECK Constraints not yet implemented");
break;
default:
elog(ERROR, "ExecEvalConstraintTest: Constraint type unknown");
--- 1591,1612 ----
case CONSTR_TEST_NOTNULL:
if (*isNull)
elog(ERROR, "Domain %s does not allow NULL values",
! constraint->domname);
break;
case CONSTR_TEST_CHECK:
! {
! Datum conResult;
!
! /* Var with attnum == UnassignedAttrNum uses the result */
! econtext->domainValue_datum = result;
! econtext->domainValue_isNull = *isNull;
!
! conResult = ExecEvalExpr(constraint->check_expr, econtext, isNull, isDone);
!
! if (!DatumGetBool(conResult))
! elog(ERROR, "Domain %s constraint %s failed",
! constraint->name, constraint->domname);
! }
break;
default:
elog(ERROR, "ExecEvalConstraintTest: Constraint type unknown");
***************
*** 1777,1783 ****
isNull,
isDone);
break;
!
default:
elog(ERROR, "ExecEvalExpr: unknown expression type %d",
nodeTag(expression));
--- 1808,1819 ----
isNull,
isDone);
break;
! case T_ConstraintTestValue:
! retDatum = ExecEvalConstraintTestValue((ConstraintTestValue *) expression,
! econtext,
! isNull,
! isDone);
! break;
default:
elog(ERROR, "ExecEvalExpr: unknown expression type %d",
nodeTag(expression));
Index: src/backend/nodes/copyfuncs.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/backend/nodes/copyfuncs.c,v
retrieving revision 1.216
diff -c -r1.216 copyfuncs.c
*** src/backend/nodes/copyfuncs.c 2002/11/06 22:31:23 1.216
--- src/backend/nodes/copyfuncs.c 2002/11/08 19:47:56
***************
*** 1056,1066 ****
--- 1056,1090 ----
newnode->testtype = from->testtype;
if (from->name)
newnode->name = pstrdup(from->name);
+ if (from->domname)
+ newnode->domname = pstrdup(from->domname);
Node_Copy(from, newnode, check_expr);
return newnode;
}
+ static ConstraintTestValue *
+ _copyConstraintTestValue(ConstraintTestValue *from)
+ {
+ ConstraintTestValue *newnode = makeNode(ConstraintTestValue);
+
+ /*
+ * copy remainder of node
+ */
+ newnode->typeId = from->typeId;
+ newnode->typeMod = from->typeMod;
+
+ return newnode;
+ }
+
+ static DomainConstraintValue *
+ _copyDomainConstraintValue(DomainConstraintValue *from)
+ {
+ DomainConstraintValue *newnode = makeNode(DomainConstraintValue);
+
+ return newnode;
+ }
+
static ArrayRef *
_copyArrayRef(ArrayRef *from)
{
***************
*** 3251,3256 ****
--- 3275,3283 ----
case T_ConstraintTest:
retval = _copyConstraintTest(from);
break;
+ case T_ConstraintTestValue:
+ retval = _copyConstraintTestValue(from);
+ break;
case T_FkConstraint:
retval = _copyFkConstraint(from);
break;
***************
*** 3262,3267 ****
--- 3289,3297 ----
break;
case T_InsertDefault:
retval = _copyInsertDefault(from);
+ break;
+ case T_DomainConstraintValue:
+ retval = _copyDomainConstraintValue(from);
break;
default:
Index: src/backend/nodes/equalfuncs.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/backend/nodes/equalfuncs.c,v
retrieving revision 1.162
diff -c -r1.162 equalfuncs.c
*** src/backend/nodes/equalfuncs.c 2002/11/06 00:00:43 1.162
--- src/backend/nodes/equalfuncs.c 2002/11/08 19:47:56
***************
*** 1969,1983 ****
return false;
if (!equalstr(a->name, b->name))
return false;
if (!equal(a->check_expr, b->check_expr))
return false;
return true;
}
/*
* Stuff from pg_list.h
*/
-
static bool
_equalValue(Value *a, Value *b)
{
--- 1969,2000 ----
return false;
if (!equalstr(a->name, b->name))
return false;
+ if (!equalstr(a->domname, b->domname))
+ return false;
if (!equal(a->check_expr, b->check_expr))
return false;
return true;
}
+ static bool
+ _equalConstraintTestValue(ConstraintTestValue *a, ConstraintTestValue *b)
+ {
+ if (a->typeId != b->typeId)
+ return false;
+ if (a->typeMod != b->typeMod)
+ return false;
+ return true;
+ }
+
+ static bool
+ _equalDomainConstraintValue(DomainConstraintValue *a, DomainConstraintValue *b)
+ {
+ return true;
+ }
+
/*
* Stuff from pg_list.h
*/
static bool
_equalValue(Value *a, Value *b)
{
***************
*** 2436,2441 ****
--- 2453,2461 ----
case T_ConstraintTest:
retval = _equalConstraintTest(a, b);
break;
+ case T_ConstraintTestValue:
+ retval = _equalConstraintTestValue(a, b);
+ break;
case T_FkConstraint:
retval = _equalFkConstraint(a, b);
break;
***************
*** 2447,2452 ****
--- 2467,2475 ----
break;
case T_InsertDefault:
retval = _equalInsertDefault(a, b);
+ break;
+ case T_DomainConstraintValue:
+ retval = _equalDomainConstraintValue(a, b);
break;
default:
Index: src/backend/nodes/outfuncs.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/backend/nodes/outfuncs.c,v
retrieving revision 1.178
diff -c -r1.178 outfuncs.c
*** src/backend/nodes/outfuncs.c 2002/11/06 22:31:24 1.178
--- src/backend/nodes/outfuncs.c 2002/11/08 19:47:56
***************
*** 1524,1534 ****
--- 1524,1556 ----
appendStringInfo(str, " :testtype %d :name ",
(int) node->testtype);
_outToken(str, node->name);
+ appendStringInfo(str, " :domain ");
+ _outToken(str, node->domname);
appendStringInfo(str, " :check_expr ");
_outNode(str, node->check_expr);
}
/*
+ * ConstraintTestValue
+ */
+ static void
+ _outConstraintTestValue(StringInfo str, ConstraintTestValue *node)
+ {
+ appendStringInfo(str, " CONSTRAINTTESTVALUE :typeid %u :typemod %d ",
+ node->typeId,
+ node->typeMod);
+ }
+
+ /*
+ * DomainConstraintValue
+ */
+ static void
+ _outDomainConstraintValue(StringInfo str, DomainConstraintValue *node)
+ {
+ appendStringInfo(str, " DOMAINCONSTRAINTVALUE ");
+ }
+
+ /*
* _outNode -
* converts a Node into ascii string and append it to 'str'
*/
***************
*** 1795,1802 ****
--- 1817,1830 ----
case T_ConstraintTest:
_outConstraintTest(str, obj);
break;
+ case T_ConstraintTestValue:
+ _outConstraintTestValue(str, obj);
+ break;
case T_FuncCall:
_outFuncCall(str, obj);
+ break;
+ case T_DomainConstraintValue:
+ _outDomainConstraintValue(str, obj);
break;
default:
Index: src/backend/nodes/readfuncs.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/backend/nodes/readfuncs.c,v
retrieving revision 1.136
diff -c -r1.136 readfuncs.c
*** src/backend/nodes/readfuncs.c 2002/11/06 00:00:44 1.136
--- src/backend/nodes/readfuncs.c 2002/11/08 19:47:56
***************
*** 949,954 ****
--- 949,958 ----
token = pg_strtok(&length); /* now read it */
local_node->name = nullable_string(token, length);
+ token = pg_strtok(&length); /* get :domname */
+ token = pg_strtok(&length); /* get domname */
+ local_node->domname = nullable_string(token, length);
+
token = pg_strtok(&length); /* eat :check_expr */
local_node->check_expr = nodeRead(true); /* now read it */
***************
*** 956,961 ****
--- 960,1005 ----
}
/* ----------------
+ * _readConstraintTestValue
+ *
+ * ConstraintTestValue is a subclass of Node
+ * ----------------
+ */
+ static ConstraintTestValue *
+ _readConstraintTestValue(void)
+ {
+ ConstraintTestValue *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(ConstraintTestValue);
+ token = pg_strtok(&length); /* eat :typeid */
+ token = pg_strtok(&length); /* get typeid */
+ local_node->typeId = atooid(token);
+ token = pg_strtok(&length); /* eat :typemod */
+ token = pg_strtok(&length); /* get typemod */
+ local_node->typeMod = atoi(token);
+
+ return local_node;
+ }
+
+ /* ----------------
+ * _readDomainConstraintValue
+ *
+ * DomainConstraintValue is a subclass of Node
+ * ----------------
+ */
+ static DomainConstraintValue *
+ _readDomainConstraintValue(void)
+ {
+ DomainConstraintValue *local_node;
+
+ local_node = makeNode(DomainConstraintValue);
+
+ return local_node;
+ }
+
+ /* ----------------
* _readVar
*
* Var is a subclass of Expr
***************
*** 2300,2305 ****
--- 2344,2353 ----
return_value = _readBooleanTest();
else if (length == 14 && strncmp(token, "CONSTRAINTTEST", length) == 0)
return_value = _readConstraintTest();
+ else if (length == 21 && strncmp(token, "DOMAINCONSTRAINTVALUE", length) == 0)
+ return_value = _readDomainConstraintValue();
+ else if (length == 19 && strncmp(token, "CONSTRAINTTESTVALUE", length) == 0)
+ return_value = _readConstraintTestValue();
else
elog(ERROR, "badly formatted planstring \"%.10s\"...", token);
Index: src/backend/optimizer/util/clauses.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/backend/optimizer/util/clauses.c,v
retrieving revision 1.110
diff -c -r1.110 clauses.c
*** src/backend/optimizer/util/clauses.c 2002/11/06 22:31:24 1.110
--- src/backend/optimizer/util/clauses.c 2002/11/08 19:47:58
***************
*** 1926,1931 ****
--- 1926,1933 ----
if (walker(((ConstraintTest *) node)->arg, context))
return true;
return walker(((ConstraintTest *) node)->check_expr, context);
+ case T_ConstraintTestValue:
+ break;
case T_SubLink:
{
SubLink *sublink = (SubLink *) node;
***************
*** 2307,2312 ****
--- 2309,2323 ----
FLATCOPY(newnode, ctest, ConstraintTest);
MUTATE(newnode->arg, ctest->arg, Node *);
MUTATE(newnode->check_expr, ctest->check_expr, Node *);
+ return (Node *) newnode;
+ }
+ break;
+ case T_ConstraintTestValue:
+ {
+ ConstraintTestValue *ctest = (ConstraintTestValue *) node;
+ ConstraintTestValue *newnode;
+
+ FLATCOPY(newnode, ctest, ConstraintTestValue);
return (Node *) newnode;
}
break;
Index: src/backend/parser/analyze.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/backend/parser/analyze.c,v
retrieving revision 1.253
diff -c -r1.253 analyze.c
*** src/backend/parser/analyze.c 2002/10/21 22:06:19 1.253
--- src/backend/parser/analyze.c 2002/11/08 19:47:58
***************
*** 2401,2407 ****
Oid expected_type_id,
given_type_id;
! expr = transformExpr(pstate, expr);
/* Cannot contain subselects or aggregates */
if (contain_subplans(expr))
--- 2401,2407 ----
Oid expected_type_id,
given_type_id;
! expr = transformExpr(pstate, expr, NULL);
/* Cannot contain subselects or aggregates */
if (contain_subplans(expr))
Index: src/backend/parser/gram.y
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/backend/parser/gram.y,v
retrieving revision 2.373
diff -c -r2.373 gram.y
*** src/backend/parser/gram.y 2002/11/02 18:41:21 2.373
--- src/backend/parser/gram.y 2002/11/08 19:47:59
***************
*** 389,395 ****
UNENCRYPTED UNION UNIQUE UNKNOWN UNLISTEN UNTIL
UPDATE USAGE USER USING
! VACUUM VALID VALIDATOR VALUES VARCHAR VARYING
VERBOSE VERSION VIEW VOLATILE
WHEN WHERE WITH WITHOUT WORK WRITE
--- 389,395 ----
UNENCRYPTED UNION UNIQUE UNKNOWN UNLISTEN UNTIL
UPDATE USAGE USER USING
! VACUUM VALID VALIDATOR VALUE VALUES VARCHAR VARYING
VERBOSE VERSION VIEW VOLATILE
WHEN WHERE WITH WITHOUT WORK WRITE
***************
*** 6386,6391 ****
--- 6386,6396 ----
n->subselect = $2;
$$ = (Node *)n;
}
+ | VALUE
+ {
+ DomainConstraintValue *n = makeNode(DomainConstraintValue);
+ $$ = (Node *)n;
+ }
;
/*
***************
*** 7292,7297 ****
--- 7297,7303 ----
| UNIQUE
| USER
| USING
+ | VALUE
| WHEN
| WHERE
;
Index: src/backend/parser/keywords.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/backend/parser/keywords.c,v
retrieving revision 1.127
diff -c -r1.127 keywords.c
*** src/backend/parser/keywords.c 2002/09/18 21:35:22 1.127
--- src/backend/parser/keywords.c 2002/11/08 19:48:00
***************
*** 311,316 ****
--- 311,317 ----
{"vacuum", VACUUM},
{"valid", VALID},
{"validator", VALIDATOR},
+ {"value", VALUE},
{"values", VALUES},
{"varchar", VARCHAR},
{"varying", VARYING},
Index: src/backend/parser/parse_clause.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/backend/parser/parse_clause.c,v
retrieving revision 1.98
diff -c -r1.98 parse_clause.c
*** src/backend/parser/parse_clause.c 2002/09/18 21:35:22 1.98
--- src/backend/parser/parse_clause.c 2002/11/08 19:48:00
***************
*** 283,289 ****
* transformJoinOnClause() does. Just invoke transformExpr() to fix
* up the operators, and we're done.
*/
! result = transformExpr(pstate, result);
result = coerce_to_boolean(result, "JOIN/USING");
--- 283,289 ----
* transformJoinOnClause() does. Just invoke transformExpr() to fix
* up the operators, and we're done.
*/
! result = transformExpr(pstate, result, NULL);
result = coerce_to_boolean(result, "JOIN/USING");
***************
*** 317,323 ****
pstate->p_namespace = makeList2(j->larg, j->rarg);
/* This part is just like transformWhereClause() */
! result = transformExpr(pstate, j->quals);
result = coerce_to_boolean(result, "JOIN/ON");
--- 317,323 ----
pstate->p_namespace = makeList2(j->larg, j->rarg);
/* This part is just like transformWhereClause() */
! result = transformExpr(pstate, j->quals, NULL);
result = coerce_to_boolean(result, "JOIN/ON");
***************
*** 478,484 ****
save_namespace = pstate->p_namespace;
pstate->p_namespace = NIL;
! funcexpr = transformExpr(pstate, r->funccallnode);
pstate->p_namespace = save_namespace;
--- 478,484 ----
save_namespace = pstate->p_namespace;
pstate->p_namespace = NIL;
! funcexpr = transformExpr(pstate, r->funccallnode, NULL);
pstate->p_namespace = save_namespace;
***************
*** 961,967 ****
if (clause == NULL)
return NULL;
! qual = transformExpr(pstate, clause);
qual = coerce_to_boolean(qual, "WHERE");
--- 961,967 ----
if (clause == NULL)
return NULL;
! qual = transformExpr(pstate, clause, NULL);
qual = coerce_to_boolean(qual, "WHERE");
***************
*** 1104,1110 ****
* willing to match a resjunk target here, though the above cases must
* ignore resjunk targets.
*/
! expr = transformExpr(pstate, node);
foreach(tl, tlist)
{
--- 1104,1110 ----
* willing to match a resjunk target here, though the above cases must
* ignore resjunk targets.
*/
! expr = transformExpr(pstate, node, NULL);
foreach(tl, tlist)
{
Index: src/backend/parser/parse_coerce.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/backend/parser/parse_coerce.c,v
retrieving revision 2.85
diff -c -r2.85 parse_coerce.c
*** src/backend/parser/parse_coerce.c 2002/10/24 22:09:00 2.85
--- src/backend/parser/parse_coerce.c 2002/11/08 19:48:00
***************
*** 14,20 ****
--- 14,25 ----
*/
#include "postgres.h"
+ #include "access/genam.h"
+ #include "access/heapam.h"
+ #include "catalog/catname.h"
+ #include "catalog/indexing.h"
#include "catalog/pg_cast.h"
+ #include "catalog/pg_constraint.h"
#include "catalog/pg_proc.h"
#include "nodes/makefuncs.h"
#include "optimizer/clauses.h"
***************
*** 405,412 ****
--- 410,423 ----
for (;;)
{
HeapTuple tup;
+ HeapTuple conTup;
Form_pg_type typTup;
+ ScanKeyData key[1];
+ int nkeys = 0;
+ SysScanDesc scan;
+ Relation conRel;
+
tup = SearchSysCache(TYPEOID,
ObjectIdGetDatum(typeId),
0, 0, 0);
***************
*** 419,426 ****
if (typTup->typnotnull && notNull == NULL)
notNull = pstrdup(NameStr(typTup->typname));
! /* TODO: Add CHECK Constraints to domains */
if (typTup->typtype != 'd')
{
/* Not a domain, so done */
--- 430,475 ----
if (typTup->typnotnull && notNull == NULL)
notNull = pstrdup(NameStr(typTup->typname));
! /* Add CHECK Constraints to domains */
! conRel = heap_openr(ConstraintRelationName, RowShareLock);
+ ScanKeyEntryInitialize(&key[nkeys++], 0x0,
+ Anum_pg_constraint_contypid, F_OIDEQ,
+ ObjectIdGetDatum(typeId));
+
+ scan = systable_beginscan(conRel, ConstraintTypidIndex, true,
+ SnapshotNow, nkeys, key);
+
+ while (HeapTupleIsValid(conTup = systable_getnext(scan)))
+ {
+ Datum val;
+ bool isNull;
+ ConstraintTest *r = makeNode(ConstraintTest);
+ Form_pg_constraint c = (Form_pg_constraint) GETSTRUCT(conTup);
+
+ /* Not expecting conbin to be NULL, but we'll test for it anyway */
+ val = fastgetattr(conTup,
+ Anum_pg_constraint_conbin,
+ conRel->rd_att, &isNull);
+
+ if (isNull)
+ elog(ERROR, "coerce_type_constraints: domain %s constraint %s has NULL conbin",
+ NameStr(typTup->typname), NameStr(c->conname));
+
+ r->arg = arg;
+ 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))));
+
+ arg = (Node *) r;
+ }
+
+ systable_endscan(scan);
+ heap_close(conRel, RowShareLock);
+
if (typTup->typtype != 'd')
{
/* Not a domain, so done */
***************
*** 452,458 ****
r->arg = arg;
r->testtype = CONSTR_TEST_NOTNULL;
! r->name = notNull;
r->check_expr = NULL;
arg = (Node *) r;
--- 501,508 ----
r->arg = arg;
r->testtype = CONSTR_TEST_NOTNULL;
! r->name = "NOT NULL";
! r->domname = notNull;
r->check_expr = NULL;
arg = (Node *) r;
Index: src/backend/parser/parse_expr.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/backend/parser/parse_expr.c,v
retrieving revision 1.129
diff -c -r1.129 parse_expr.c
*** src/backend/parser/parse_expr.c 2002/09/18 21:35:22 1.129
--- src/backend/parser/parse_expr.c 2002/11/08 19:48:00
***************
*** 20,25 ****
--- 20,26 ----
#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"
***************
*** 83,89 ****
* input and output of transformExpr; see SubLink for example.
*/
Node *
! transformExpr(ParseState *pstate, Node *expr)
{
Node *result = NULL;
--- 84,90 ----
* input and output of transformExpr; see SubLink for example.
*/
Node *
! transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
{
Node *result = NULL;
***************
*** 152,158 ****
ExprFieldSelect *efs = (ExprFieldSelect *) expr;
List *fields;
! result = transformExpr(pstate, efs->arg);
/* handle qualification, if any */
foreach(fields, efs->fields)
{
--- 153,159 ----
ExprFieldSelect *efs = (ExprFieldSelect *) expr;
List *fields;
! result = transformExpr(pstate, efs->arg, domVal);
/* handle qualification, if any */
foreach(fields, efs->fields)
{
***************
*** 169,175 ****
case T_TypeCast:
{
TypeCast *tc = (TypeCast *) expr;
! Node *arg = transformExpr(pstate, tc->arg);
result = typecast_expression(arg, tc->typename);
break;
--- 170,176 ----
case T_TypeCast:
{
TypeCast *tc = (TypeCast *) expr;
! Node *arg = transformExpr(pstate, tc->arg, domVal);
result = typecast_expression(arg, tc->typename);
break;
***************
*** 204,217 ****
n->arg = a->lexpr;
result = transformExpr(pstate,
! (Node *) n);
}
else
{
Node *lexpr = transformExpr(pstate,
! a->lexpr);
Node *rexpr = transformExpr(pstate,
! a->rexpr);
result = (Node *) make_op(a->name,
lexpr,
--- 205,218 ----
n->arg = a->lexpr;
result = transformExpr(pstate,
! (Node *) n, domVal);
}
else
{
Node *lexpr = transformExpr(pstate,
! a->lexpr, domVal);
Node *rexpr = transformExpr(pstate,
! a->rexpr, domVal);
result = (Node *) make_op(a->name,
lexpr,
***************
*** 222,230 ****
case AND:
{
Node *lexpr = transformExpr(pstate,
! a->lexpr);
Node *rexpr = transformExpr(pstate,
! a->rexpr);
Expr *expr = makeNode(Expr);
lexpr = coerce_to_boolean(lexpr, "AND");
--- 223,231 ----
case AND:
{
Node *lexpr = transformExpr(pstate,
! a->lexpr, domVal);
Node *rexpr = transformExpr(pstate,
! a->rexpr, domVal);
Expr *expr = makeNode(Expr);
lexpr = coerce_to_boolean(lexpr, "AND");
***************
*** 239,247 ****
case OR:
{
Node *lexpr = transformExpr(pstate,
! a->lexpr);
Node *rexpr = transformExpr(pstate,
! a->rexpr);
Expr *expr = makeNode(Expr);
lexpr = coerce_to_boolean(lexpr, "OR");
--- 240,248 ----
case OR:
{
Node *lexpr = transformExpr(pstate,
! a->lexpr, domVal);
Node *rexpr = transformExpr(pstate,
! a->rexpr, domVal);
Expr *expr = makeNode(Expr);
lexpr = coerce_to_boolean(lexpr, "OR");
***************
*** 256,262 ****
case NOT:
{
Node *rexpr = transformExpr(pstate,
! a->rexpr);
Expr *expr = makeNode(Expr);
rexpr = coerce_to_boolean(rexpr, "NOT");
--- 257,263 ----
case NOT:
{
Node *rexpr = transformExpr(pstate,
! a->rexpr, domVal);
Expr *expr = makeNode(Expr);
rexpr = coerce_to_boolean(rexpr, "NOT");
***************
*** 270,278 ****
case DISTINCT:
{
Node *lexpr = transformExpr(pstate,
! a->lexpr);
Node *rexpr = transformExpr(pstate,
! a->rexpr);
result = (Node *) make_op(a->name,
lexpr,
--- 271,279 ----
case DISTINCT:
{
Node *lexpr = transformExpr(pstate,
! a->lexpr, domVal);
Node *rexpr = transformExpr(pstate,
! a->rexpr, domVal);
result = (Node *) make_op(a->name,
lexpr,
***************
*** 293,299 ****
* Will result in a boolean constant node.
*/
Node *lexpr = transformExpr(pstate,
! a->lexpr);
ltype = exprType(lexpr);
foreach(telem, (List *) a->rexpr)
--- 294,300 ----
* Will result in a boolean constant node.
*/
Node *lexpr = transformExpr(pstate,
! a->lexpr, domVal);
ltype = exprType(lexpr);
foreach(telem, (List *) a->rexpr)
***************
*** 317,323 ****
n->val.val.str = (matched ? "t" : "f");
n->typename = SystemTypeName("bool");
! result = transformExpr(pstate, (Node *) n);
}
break;
}
--- 318,324 ----
n->val.val.str = (matched ? "t" : "f");
n->typename = SystemTypeName("bool");
! result = transformExpr(pstate, (Node *) n, domVal);
}
break;
}
***************
*** 331,337 ****
/* transform the list of arguments */
foreach(args, fn->args)
lfirst(args) = transformExpr(pstate,
! (Node *) lfirst(args));
result = ParseFuncOrColumn(pstate,
fn->funcname,
fn->args,
--- 332,338 ----
/* transform the list of arguments */
foreach(args, fn->args)
lfirst(args) = transformExpr(pstate,
! (Node *) lfirst(args), domVal);
result = ParseFuncOrColumn(pstate,
fn->funcname,
fn->args,
***************
*** 405,411 ****
List *elist;
foreach(elist, left_list)
! lfirst(elist) = transformExpr(pstate, lfirst(elist));
Assert(IsA(sublink->oper, A_Expr));
op = ((A_Expr *) sublink->oper)->name;
--- 406,412 ----
List *elist;
foreach(elist, left_list)
! lfirst(elist) = transformExpr(pstate, lfirst(elist), domVal);
Assert(IsA(sublink->oper, A_Expr));
op = ((A_Expr *) sublink->oper)->name;
***************
*** 504,510 ****
warg = (Node *) makeSimpleA_Expr(OP, "=",
c->arg, warg);
}
! neww->expr = transformExpr(pstate, warg);
neww->expr = coerce_to_boolean(neww->expr, "CASE/WHEN");
--- 505,511 ----
warg = (Node *) makeSimpleA_Expr(OP, "=",
c->arg, warg);
}
! neww->expr = transformExpr(pstate, warg, domVal);
neww->expr = coerce_to_boolean(neww->expr, "CASE/WHEN");
***************
*** 520,526 ****
n->val.type = T_Null;
warg = (Node *) n;
}
! neww->result = transformExpr(pstate, warg);
newargs = lappend(newargs, neww);
typeids = lappendi(typeids, exprType(neww->result));
--- 521,527 ----
n->val.type = T_Null;
warg = (Node *) n;
}
! neww->result = transformExpr(pstate, warg, domVal);
newargs = lappend(newargs, neww);
typeids = lappendi(typeids, exprType(neww->result));
***************
*** 544,550 ****
n->val.type = T_Null;
defresult = (Node *) n;
}
! newc->defresult = transformExpr(pstate, defresult);
/*
* Note: default result is considered the most significant
--- 545,551 ----
n->val.type = T_Null;
defresult = (Node *) n;
}
! newc->defresult = transformExpr(pstate, defresult, domVal);
/*
* Note: default result is considered the most significant
***************
*** 580,586 ****
{
NullTest *n = (NullTest *) expr;
! n->arg = transformExpr(pstate, n->arg);
/* the argument can be any type, so don't coerce it */
result = expr;
break;
--- 581,587 ----
{
NullTest *n = (NullTest *) expr;
! n->arg = transformExpr(pstate, n->arg, domVal);
/* the argument can be any type, so don't coerce it */
result = expr;
break;
***************
*** 617,623 ****
clausename = NULL; /* keep compiler quiet */
}
! b->arg = transformExpr(pstate, b->arg);
b->arg = coerce_to_boolean(b->arg, clausename);
--- 618,624 ----
clausename = NULL; /* keep compiler quiet */
}
! b->arg = transformExpr(pstate, b->arg, domVal);
b->arg = coerce_to_boolean(b->arg, clausename);
***************
*** 625,630 ****
--- 626,638 ----
break;
}
+ case T_DomainConstraintValue:
+ {
+ result = (Node *) copyObject(domVal);
+
+ break;
+ }
+
/*********************************************
* Quietly accept node types that may be presented when we are
* called on an already-transformed tree.
***************
*** 935,940 ****
--- 943,951 ----
break;
case T_ConstraintTest:
type = exprType(((ConstraintTest *) expr)->arg);
+ break;
+ case T_ConstraintTestValue:
+ type = ((ConstraintTestValue *) expr)->typeId;
break;
default:
elog(ERROR, "exprType: Do not know how to get type for %d node",
Index: src/backend/parser/parse_node.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/backend/parser/parse_node.c,v
retrieving revision 1.69
diff -c -r1.69 parse_node.c
*** src/backend/parser/parse_node.c 2002/09/18 21:35:22 1.69
--- src/backend/parser/parse_node.c 2002/11/08 19:48:01
***************
*** 278,284 ****
{
if (ai->lidx)
{
! subexpr = transformExpr(pstate, ai->lidx);
/* If it's not int4 already, try to coerce */
subexpr = coerce_to_target_type(subexpr, exprType(subexpr),
INT4OID, -1,
--- 278,284 ----
{
if (ai->lidx)
{
! subexpr = transformExpr(pstate, ai->lidx, NULL);
/* If it's not int4 already, try to coerce */
subexpr = coerce_to_target_type(subexpr, exprType(subexpr),
INT4OID, -1,
***************
*** 300,306 ****
}
lowerIndexpr = lappend(lowerIndexpr, subexpr);
}
! subexpr = transformExpr(pstate, ai->uidx);
/* If it's not int4 already, try to coerce */
subexpr = coerce_to_target_type(subexpr, exprType(subexpr),
INT4OID, -1,
--- 300,306 ----
}
lowerIndexpr = lappend(lowerIndexpr, subexpr);
}
! subexpr = transformExpr(pstate, ai->uidx, NULL);
/* If it's not int4 already, try to coerce */
subexpr = coerce_to_target_type(subexpr, exprType(subexpr),
INT4OID, -1,
Index: src/backend/parser/parse_target.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/backend/parser/parse_target.c,v
retrieving revision 1.91
diff -c -r1.91 parse_target.c
*** src/backend/parser/parse_target.c 2002/09/28 20:00:19 1.91
--- src/backend/parser/parse_target.c 2002/11/08 19:48:01
***************
*** 56,62 ****
/* Transform the node if caller didn't do it already */
if (expr == NULL)
! expr = transformExpr(pstate, node);
if (IsA(expr, RangeVar))
elog(ERROR, "You can't use relation names alone in the target list, try relation.*.");
--- 56,62 ----
/* Transform the node if caller didn't do it already */
if (expr == NULL)
! expr = transformExpr(pstate, node, NULL);
if (IsA(expr, RangeVar))
elog(ERROR, "You can't use relation names alone in the target list, try relation.*.");
Index: src/backend/utils/adt/ruleutils.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/backend/utils/adt/ruleutils.c,v
retrieving revision 1.124
diff -c -r1.124 ruleutils.c
*** src/backend/utils/adt/ruleutils.c 2002/09/19 23:40:56 1.124
--- src/backend/utils/adt/ruleutils.c 2002/11/08 19:48:03
***************
*** 2226,2231 ****
--- 2226,2237 ----
}
break;
+ case T_ConstraintTestValue:
+ {
+ appendStringInfo(buf, "VALUE");
+ }
+ break;
+
case T_SubLink:
get_sublink_expr(node, context);
break;
Index: src/include/catalog/indexing.h
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/include/catalog/indexing.h,v
retrieving revision 1.76
diff -c -r1.76 indexing.h
*** src/include/catalog/indexing.h 2002/10/18 20:33:57 1.76
--- src/include/catalog/indexing.h 2002/11/08 19:48:04
***************
*** 40,45 ****
--- 40,46 ----
#define ConstraintNameNspIndex "pg_constraint_conname_nsp_index"
#define ConstraintOidIndex "pg_constraint_oid_index"
#define ConstraintRelidIndex "pg_constraint_conrelid_index"
+ #define ConstraintTypidIndex "pg_constraint_contypid_index"
#define ConversionDefaultIndex "pg_conversion_default_index"
#define ConversionNameNspIndex "pg_conversion_name_nsp_index"
#define ConversionOidIndex "pg_conversion_oid_index"
***************
*** 129,134 ****
--- 130,137 ----
DECLARE_INDEX(pg_constraint_conname_nsp_index on pg_constraint using btree(conname name_ops, connamespace oid_ops));
/* This following index is not used for a cache and is not unique */
DECLARE_INDEX(pg_constraint_conrelid_index on pg_constraint using btree(conrelid oid_ops));
+ /* This following index is not used for a cache and is not unique */
+ DECLARE_INDEX(pg_constraint_contypid_index on pg_constraint using btree(contypid oid_ops));
DECLARE_UNIQUE_INDEX(pg_constraint_oid_index on pg_constraint using btree(oid oid_ops));
DECLARE_UNIQUE_INDEX(pg_conversion_default_index on pg_conversion using btree(connamespace oid_ops, conforencoding int4_ops, contoencoding int4_ops, oid oid_ops));
DECLARE_UNIQUE_INDEX(pg_conversion_name_nsp_index on pg_conversion using btree(conname name_ops, connamespace oid_ops));
Index: src/include/catalog/pg_constraint.h
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/include/catalog/pg_constraint.h,v
retrieving revision 1.4
diff -c -r1.4 pg_constraint.h
*** src/include/catalog/pg_constraint.h 2002/09/22 00:37:09 1.4
--- src/include/catalog/pg_constraint.h 2002/11/08 19:48:04
***************
*** 140,145 ****
--- 140,154 ----
* the FKCONSTR_MATCH_xxx constants defined in parsenodes.h.
*/
+ /*
+ * Used for constraint support functions where the
+ * and conrelid, contypid columns being looked up
+ */
+ typedef enum CONSTRAINTCATEGORY {
+ CONSTRAINT_RELATION,
+ CONSTRAINT_DOMAIN,
+ CONSTRAINT_ASSERTION
+ } CONSTRAINTCATEGORY;
/*
* prototypes for functions in pg_constraint.c
***************
*** 166,175 ****
extern void RemoveConstraintById(Oid conId);
! extern bool ConstraintNameIsUsed(Oid relId, Oid relNamespace,
! const char *cname);
! extern char *GenerateConstraintName(Oid relId, Oid relNamespace,
! int *counter);
extern bool ConstraintNameIsGenerated(const char *cname);
#endif /* PG_CONSTRAINT_H */
--- 175,184 ----
extern void RemoveConstraintById(Oid conId);
! extern bool ConstraintNameIsUsed(CONSTRAINTCATEGORY conCat, Oid objId, Oid objNamespace,
! const char *cname);
! extern char *GenerateConstraintName(CONSTRAINTCATEGORY conCat, Oid objId, Oid objNamespace,
! int *counter);
extern bool ConstraintNameIsGenerated(const char *cname);
#endif /* PG_CONSTRAINT_H */
Index: src/include/nodes/execnodes.h
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/include/nodes/execnodes.h,v
retrieving revision 1.77
diff -c -r1.77 execnodes.h
*** src/include/nodes/execnodes.h 2002/11/06 22:31:24 1.77
--- src/include/nodes/execnodes.h 2002/11/08 19:48:04
***************
*** 113,118 ****
--- 113,125 ----
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
+ */
+ Datum domainValue_datum;
+ bool domainValue_isNull;
+
/* Functions to call back when ExprContext is shut down */
ExprContext_CB *ecxt_callbacks;
} ExprContext;
Index: src/include/nodes/nodes.h
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/include/nodes/nodes.h,v
retrieving revision 1.121
diff -c -r1.121 nodes.h
*** src/include/nodes/nodes.h 2002/11/06 00:00:44 1.121
--- src/include/nodes/nodes.h 2002/11/08 19:48:04
***************
*** 171,176 ****
--- 171,177 ----
T_ViewStmt,
T_LoadStmt,
T_CreateDomainStmt,
+ T_DomainConstraintValue,
T_CreatedbStmt,
T_DropdbStmt,
T_VacuumStmt,
***************
*** 231,236 ****
--- 232,238 ----
T_NullTest,
T_BooleanTest,
T_ConstraintTest,
+ T_ConstraintTestValue,
T_CaseExpr,
T_CaseWhen,
T_FkConstraint,
Index: src/include/nodes/parsenodes.h
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/include/nodes/parsenodes.h,v
retrieving revision 1.210
diff -c -r1.210 parsenodes.h
*** src/include/nodes/parsenodes.h 2002/11/06 00:00:44 1.210
--- src/include/nodes/parsenodes.h 2002/11/08 19:48:04
***************
*** 285,292 ****
--- 285,309 ----
Node *arg; /* input expression */
ConstraintTestType testtype; /* test type */
char *name; /* name of constraint (for error msgs) */
+ char *domname; /* name of domain (for error messages) */
Node *check_expr; /* for CHECK test, a boolean expression */
} ConstraintTest;
+
+ /*
+ * Placeholder node for the value to be processed by a domains
+ * check constraint.
+ */
+ typedef struct DomainConstraintValue
+ {
+ NodeTag type;
+ } DomainConstraintValue;
+
+ typedef struct ConstraintTestValue
+ {
+ NodeTag type;
+ Oid typeId;
+ int32 typeMod;
+ } ConstraintTestValue;
/*
* ColumnDef - column definition (used in various creates)
Index: src/include/optimizer/var.h
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/include/optimizer/var.h,v
retrieving revision 1.21
diff -c -r1.21 var.h
*** src/include/optimizer/var.h 2002/06/20 20:29:51 1.21
--- src/include/optimizer/var.h 2002/11/08 19:48:04
***************
*** 22,27 ****
--- 22,28 ----
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);
Index: src/include/parser/parse_expr.h
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/include/parser/parse_expr.h,v
retrieving revision 1.28
diff -c -r1.28 parse_expr.h
*** src/include/parser/parse_expr.h 2002/06/20 20:29:51 1.28
--- src/include/parser/parse_expr.h 2002/11/08 19:48:04
***************
*** 21,27 ****
extern int max_expr_depth;
extern bool Transform_null_equals;
! extern Node *transformExpr(ParseState *pstate, Node *expr);
extern Oid exprType(Node *expr);
extern int32 exprTypmod(Node *expr);
extern bool exprIsLengthCoercion(Node *expr, int32 *coercedTypmod);
--- 21,28 ----
extern int max_expr_depth;
extern bool Transform_null_equals;
!
! extern Node *transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal);
extern Oid exprType(Node *expr);
extern int32 exprTypmod(Node *expr);
extern bool exprIsLengthCoercion(Node *expr, int32 *coercedTypmod);
Index: src/test/regress/expected/domain.out
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/test/regress/expected/domain.out,v
retrieving revision 1.12
diff -c -r1.12 domain.out
*** src/test/regress/expected/domain.out 2002/10/19 01:35:43 1.12
--- src/test/regress/expected/domain.out 2002/11/08 19:48:06
***************
*** 103,137 ****
drop domain domaintextarr restrict;
create domain dnotnull varchar(15) NOT NULL;
create domain dnull varchar(15);
create table nulltest
( col1 dnotnull
, col2 dnotnull NULL -- NOT NULL in the domain cannot be overridden
, col3 dnull NOT NULL
, col4 dnull
);
INSERT INTO nulltest DEFAULT VALUES;
ERROR: Domain dnotnull does not allow NULL values
! INSERT INTO nulltest values ('a', 'b', 'c', 'd'); -- Good
! INSERT INTO nulltest values (NULL, 'b', 'c', 'd');
ERROR: Domain dnotnull does not allow NULL values
! INSERT INTO nulltest values ('a', NULL, 'c', 'd');
ERROR: Domain dnotnull does not allow NULL values
! INSERT INTO nulltest values ('a', 'b', NULL, 'd');
ERROR: ExecInsert: Fail to add null value in not null attribute col3
! INSERT INTO nulltest values ('a', 'b', 'c', NULL); -- Good
-- Test copy
COPY nulltest FROM stdin; --fail
! ERROR: copy: line 1, CopyFrom: Fail to add null value in not null attribute col3
lost synchronization with server, resetting connection
SET autocommit TO 'on';
COPY nulltest FROM stdin;
select * from nulltest;
! col1 | col2 | col3 | col4
! ------+------+------+------
! a | b | c | d
! a | b | c |
! a | b | c |
! (3 rows)
-- Test out coerced (casted) constraints
SELECT cast('1' as dnotnull);
--- 103,145 ----
drop domain domaintextarr restrict;
create domain dnotnull varchar(15) NOT NULL;
create domain dnull varchar(15);
+ create domain dcheck varchar(15) NOT NULL CHECK (VALUE = 'a' OR VALUE = 'c' OR VALUE = 'd');
create table nulltest
( col1 dnotnull
, col2 dnotnull NULL -- NOT NULL in the domain cannot be overridden
, col3 dnull NOT NULL
, col4 dnull
+ , col5 dcheck CHECK (col5 IN ('c', 'd'))
);
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: Domain $1 constraint dcheck failed
! 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');
ERROR: Domain dnotnull does not allow NULL values
! INSERT INTO nulltest values ('a', NULL, 'c', 'd', 'c');
ERROR: Domain dnotnull does not allow NULL values
! INSERT INTO nulltest values ('a', 'b', NULL, 'd', 'c');
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, Domain $1 constraint dcheck failed
lost synchronization with server, resetting connection
SET autocommit TO 'on';
+ -- Last row is bad
COPY nulltest FROM stdin;
+ ERROR: copy: line 3, CopyFrom: rejected due to CHECK constraint "nulltest_col5" on "nulltest"
+ lost synchronization with server, resetting connection
select * from nulltest;
! col1 | col2 | col3 | col4 | col5
! ------+------+------+------+------
! a | b | c | d | c
! a | b | c | | d
! (2 rows)
-- Test out coerced (casted) constraints
SELECT cast('1' as dnotnull);
Index: src/test/regress/sql/domain.sql
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/test/regress/sql/domain.sql,v
retrieving revision 1.9
diff -c -r1.9 domain.sql
*** src/test/regress/sql/domain.sql 2002/10/19 01:35:43 1.9
--- src/test/regress/sql/domain.sql 2002/11/08 19:48:06
***************
*** 83,111 ****
create domain dnotnull varchar(15) NOT NULL;
create domain dnull varchar(15);
create table nulltest
( col1 dnotnull
, col2 dnotnull NULL -- NOT NULL in the domain cannot be overridden
, col3 dnull NOT NULL
, col4 dnull
);
INSERT INTO nulltest DEFAULT VALUES;
! INSERT INTO nulltest values ('a', 'b', 'c', 'd'); -- Good
! INSERT INTO nulltest values (NULL, 'b', 'c', 'd');
! INSERT INTO nulltest values ('a', NULL, 'c', 'd');
! INSERT INTO nulltest values ('a', 'b', NULL, 'd');
! INSERT INTO nulltest values ('a', 'b', 'c', NULL); -- Good
-- Test copy
COPY nulltest FROM stdin; --fail
! a b \N d
\.
SET autocommit TO 'on';
COPY nulltest FROM stdin;
! a b c \N
\.
select * from nulltest;
--- 83,118 ----
create domain dnotnull varchar(15) NOT NULL;
create domain dnull varchar(15);
+ create domain dcheck varchar(15) NOT NULL CHECK (VALUE = 'a' OR VALUE = 'c' OR VALUE = 'd');
create table nulltest
( col1 dnotnull
, col2 dnotnull NULL -- NOT NULL in the domain cannot be overridden
, col3 dnull NOT NULL
, col4 dnull
+ , col5 dcheck CHECK (col5 IN ('c', 'd'))
);
INSERT INTO nulltest DEFAULT VALUES;
! 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', 'a');
! INSERT INTO nulltest values (NULL, 'b', 'c', 'd', 'd');
! INSERT INTO nulltest values ('a', NULL, 'c', 'd', 'c');
! INSERT INTO nulltest values ('a', 'b', NULL, 'd', 'c');
! INSERT INTO nulltest values ('a', 'b', 'c', NULL, 'd'); -- Good
-- Test copy
COPY nulltest FROM stdin; --fail
! a b \N d \N
\.
SET autocommit TO 'on';
+ -- Last row is bad
COPY nulltest FROM stdin;
! a b c \N c
! a b c \N d
! a b c \N a
\.
select * from nulltest;