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