Add DOMAIN check constraints.
authorBruce Momjian
Fri, 15 Nov 2002 02:50:21 +0000 (02:50 +0000)
committerBruce Momjian
Fri, 15 Nov 2002 02:50:21 +0000 (02:50 +0000)
Rod Taylor

29 files changed:
doc/src/sgml/ref/create_domain.sgml
src/backend/catalog/heap.c
src/backend/catalog/pg_constraint.c
src/backend/commands/tablecmds.c
src/backend/commands/typecmds.c
src/backend/executor/execQual.c
src/backend/nodes/copyfuncs.c
src/backend/nodes/equalfuncs.c
src/backend/nodes/outfuncs.c
src/backend/nodes/readfuncs.c
src/backend/optimizer/util/clauses.c
src/backend/parser/analyze.c
src/backend/parser/gram.y
src/backend/parser/keywords.c
src/backend/parser/parse_clause.c
src/backend/parser/parse_coerce.c
src/backend/parser/parse_expr.c
src/backend/parser/parse_node.c
src/backend/parser/parse_target.c
src/backend/utils/adt/ruleutils.c
src/include/catalog/indexing.h
src/include/catalog/pg_constraint.h
src/include/nodes/execnodes.h
src/include/nodes/nodes.h
src/include/nodes/parsenodes.h
src/include/optimizer/var.h
src/include/parser/parse_expr.h
src/test/regress/expected/domain.out
src/test/regress/sql/domain.sql

index b7d5e606d3e602019fc358deba84020527df96bd..bd4114688f6347d40009cad51a6a8ede8227b0b2 100644 (file)
@@ -1,5 +1,5 @@
 
 
@@ -200,16 +200,6 @@ CREATE TABLE countrylist (id INT4, country country_code);
   
  
 
-  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
 
index 9956672c12af6f96b7baef284e24429a7bff078d..f8f667e24a9d8f01f4c89b27ca86b66aba61cb09 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.234 2002/11/11 22:19:21 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.235 2002/11/15 02:50:05 momjian Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -1500,7 +1500,8 @@ AddRelationRawConstraints(Relation rel,
 
            ccname = cdef->name;
            /* Check against pre-existing constraints */
-           if (ConstraintNameIsUsed(RelationGetRelid(rel),
+           if (ConstraintNameIsUsed(CONSTRAINT_RELATION,
+                                    RelationGetRelid(rel),
                                     RelationGetNamespace(rel),
                                     ccname))
                elog(ERROR, "constraint \"%s\" already exists for relation \"%s\"",
@@ -1534,7 +1535,8 @@ AddRelationRawConstraints(Relation rel,
                 * pre-existing constraints, nor with any auto-generated
                 * names so far.
                 */
-               ccname = GenerateConstraintName(RelationGetRelid(rel),
+               ccname = GenerateConstraintName(CONSTRAINT_RELATION,
+                                               RelationGetRelid(rel),
                                                RelationGetNamespace(rel),
                                                &constr_name_ctr);
 
@@ -1565,7 +1567,7 @@ AddRelationRawConstraints(Relation rel,
        /*
         * Transform raw parsetree to executable expression.
         */
-       expr = transformExpr(pstate, cdef->raw_expr);
+       expr = transformExpr(pstate, cdef->raw_expr, NULL);
 
        /*
         * Make sure it yields a boolean result.
@@ -1694,7 +1696,7 @@ cookDefault(ParseState *pstate,
    /*
     * Transform raw parsetree to executable expression.
     */
-   expr = transformExpr(pstate, raw_default);
+   expr = transformExpr(pstate, raw_default, NULL);
 
    /*
     * Make sure default expr does not refer to any vars.
index e03e545beb37f5c4ea8929c8ad9cb24c08e5dffb..7cd105928c331309c96539c82ef20bbc9a30d3f0 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/catalog/pg_constraint.c,v 1.7 2002/09/22 00:37:09 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/catalog/pg_constraint.c,v 1.8 2002/11/15 02:50:05 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -190,6 +190,19 @@ CreateConstraintEntry(const char *constraintName,
        }
    }
 
+   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,7 +275,7 @@ CreateConstraintEntry(const char *constraintName,
  * this test is not very meaningful.
  */
 bool
-ConstraintNameIsUsed(Oid relId, Oid relNamespace, const char *cname)
+ConstraintNameIsUsed(CONSTRAINTCATEGORY conCat, Oid objId, Oid objNamespace, const char *cname)
 {
    bool        found;
    Relation    conDesc;
@@ -280,7 +293,7 @@ ConstraintNameIsUsed(Oid relId, Oid relNamespace, const char *cname)
 
    ScanKeyEntryInitialize(&skey[1], 0x0,
                           Anum_pg_constraint_connamespace, F_OIDEQ,
-                          ObjectIdGetDatum(relNamespace));
+                          ObjectIdGetDatum(objNamespace));
 
    conscan = systable_beginscan(conDesc, ConstraintNameNspIndex, true,
                                 SnapshotNow, 2, skey);
@@ -289,7 +302,12 @@ ConstraintNameIsUsed(Oid relId, Oid relNamespace, const char *cname)
    {
        Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tup);
 
-       if (con->conrelid == relId)
+       if (conCat == CONSTRAINT_RELATION && con->conrelid == objId)
+       {
+           found = true;
+           break;
+       }
+       else if (conCat == CONSTRAINT_DOMAIN && con->contypid == objId)
        {
            found = true;
            break;
@@ -314,7 +332,7 @@ ConstraintNameIsUsed(Oid relId, Oid relNamespace, const char *cname)
  * someone else might choose the same name concurrently!
  */
 char *
-GenerateConstraintName(Oid relId, Oid relNamespace, int *counter)
+GenerateConstraintName(CONSTRAINTCATEGORY conCat, Oid objId, Oid objNamespace, int *counter)
 {
    bool        found;
    Relation    conDesc;
@@ -347,7 +365,7 @@ GenerateConstraintName(Oid relId, Oid relNamespace, int *counter)
 
        ScanKeyEntryInitialize(&skey[1], 0x0,
                               Anum_pg_constraint_connamespace, F_OIDEQ,
-                              ObjectIdGetDatum(relNamespace));
+                              ObjectIdGetDatum(objNamespace));
 
        conscan = systable_beginscan(conDesc, ConstraintNameNspIndex, true,
                                     SnapshotNow, 2, skey);
@@ -356,7 +374,12 @@ GenerateConstraintName(Oid relId, Oid relNamespace, int *counter)
        {
            Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tup);
 
-           if (con->conrelid == relId)
+           if (conCat == CONSTRAINT_RELATION && con->conrelid == objId)
+           {
+               found = true;
+               break;
+           }
+           else if (conCat == CONSTRAINT_DOMAIN && con->contypid == objId)
            {
                found = true;
                break;
@@ -415,10 +438,13 @@ RemoveConstraintById(Oid conId)
    con = (Form_pg_constraint) GETSTRUCT(tup);
 
    /*
-    * If the constraint is for a relation, open and exclusive-lock the
-    * relation it's for.
+    * If the constraint is for a 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 other constraints.
+    * XXX not clear what we should lock, if anything, for assert constraints.
     */
    if (OidIsValid(con->conrelid))
    {
@@ -463,6 +489,34 @@ RemoveConstraintById(Oid conId)
        /* Keep lock on constraint's rel until end of xact */
        heap_close(rel, NoLock);
    }
+   /* Lock the domain row in pg_type */
+   else if (OidIsValid(con->contypid))
+   {
+       Relation    typRel;
+       HeapTuple   typTup;
+       ScanKeyData typKey[1];
+       SysScanDesc typScan;
+
+       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 */
    simple_heap_delete(conDesc, &tup->t_self);
index 8023ba834204b070580e314b0d7ebd30549e3dd2..cda8687e448c872b2185eb44e8589c52b2f48119 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.53 2002/11/11 22:19:21 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.54 2002/11/15 02:50:05 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -2632,14 +2632,16 @@ AlterTableAddConstraint(Oid myrelid, bool recurse,
                     */
                    if (constr->name)
                    {
-                       if (ConstraintNameIsUsed(RelationGetRelid(rel),
+                       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(RelationGetRelid(rel),
+                       constr->name = GenerateConstraintName(CONSTRAINT_RELATION,
+                                                             RelationGetRelid(rel),
                                                              RelationGetNamespace(rel),
                                                              &counter);
 
@@ -2668,7 +2670,8 @@ AlterTableAddConstraint(Oid myrelid, bool recurse,
                     */
                    if (fkconstraint->constr_name)
                    {
-                       if (ConstraintNameIsUsed(RelationGetRelid(rel),
+                       if (ConstraintNameIsUsed(CONSTRAINT_RELATION,
+                                                  RelationGetRelid(rel),
                                               RelationGetNamespace(rel),
                                              fkconstraint->constr_name))
                            elog(ERROR, "constraint \"%s\" already exists for relation \"%s\"",
@@ -2676,7 +2679,8 @@ AlterTableAddConstraint(Oid myrelid, bool recurse,
                                 RelationGetRelationName(rel));
                    }
                    else
-                       fkconstraint->constr_name = GenerateConstraintName(RelationGetRelid(rel),
+                       fkconstraint->constr_name = GenerateConstraintName(CONSTRAINT_RELATION,
+                                                  RelationGetRelid(rel),
                                               RelationGetNamespace(rel),
                                                               &counter);
 
@@ -2734,7 +2738,7 @@ AlterTableAddCheckConstraint(Relation rel, Constraint *constr)
    /*
     * Convert the A_EXPR in raw_expr into an EXPR
     */
-   expr = transformExpr(pstate, constr->raw_expr);
+   expr = transformExpr(pstate, constr->raw_expr, NULL);
 
    /*
     * Make sure it yields a boolean result.
index a573cac27def844350bafebb51f94965780f2fd4..ab0608a08a9cdeba90c52d98959e2e3a30d6c142 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/commands/typecmds.c,v 1.16 2002/11/11 22:19:22 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/commands/typecmds.c,v 1.17 2002/11/15 02:50:06 momjian Exp $
  *
  * DESCRIPTION
  *   The "DefineFoo" routines take the parse tree and pick out the
 #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,7 +413,8 @@ DefineDomain(CreateDomainStmt *stmt)
    List       *listptr;
    Oid         basetypeoid;
    Oid         domainoid;
-   Form_pg_type baseType;
+   Form_pg_type    baseType;
+   int         counter = 0;
 
    /* Convert list of names to a name and namespace */
    domainNamespace = QualifiedNameGetCreationNamespace(stmt->domainname,
@@ -484,17 +492,21 @@ DefineDomain(CreateDomainStmt *stmt)
    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().
+    * Run through constraints manually to avoid the additional
+    * processing conducted by DefineRelation() and friends.
     */
    foreach(listptr, schema)
    {
-       Constraint *colDef = lfirst(listptr);
+       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,26 +558,26 @@ DefineDomain(CreateDomainStmt *stmt)
                    elog(ERROR, "CREATE DOMAIN has conflicting NULL / NOT NULL constraint");
                typNotNull = false;
                nullDefined = true;
-               break;
+               break;
 
-           case CONSTR_UNIQUE:
-               elog(ERROR, "CREATE DOMAIN / UNIQUE indexes not supported");
-               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_PRIMARY:
+               elog(ERROR, "CREATE DOMAIN / PRIMARY KEY indexes not supported");
+               break;
 
-           case CONSTR_CHECK:
-               elog(ERROR, "DefineDomain: CHECK Constraints 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;
+           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");
@@ -591,12 +603,139 @@ DefineDomain(CreateDomainStmt *stmt)
                   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 */
+                  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 5718983ca101fb794c55b0a36fd4d6943b77e950..1612a2d9ea2b3dd474a4ea5cd391e0a36e1926cd 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.108 2002/09/04 20:31:17 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.109 2002/11/15 02:50:06 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -72,6 +72,9 @@ static Datum ExecEvalBooleanTest(BooleanTest *btest, ExprContext *econtext,
 static Datum ExecEvalConstraintTest(ConstraintTest *constraint,
                       ExprContext *econtext,
                       bool *isNull, ExprDoneCond *isDone);
+static Datum ExecEvalConstraintTestValue(ConstraintTestValue *conVal,
+                      ExprContext *econtext,
+                      bool *isNull, ExprDoneCond *isDone);
 
 
 /*----------
@@ -1551,6 +1554,23 @@ ExecEvalBooleanTest(BooleanTest *btest,
    }
 }
 
+/*
+ * ExecEvalConstraintTestValue
+ *
+ * Return the value stored by constraintTest.
+ */
+static Datum
+ExecEvalConstraintTestValue(ConstraintTestValue *conVal, ExprContext *econtext,
+                           bool *isNull, ExprDoneCond *isDone)
+{
+   /*
+    * If the Datum hasn't been set, then it's ExecEvalConstraintTest
+    * hasn't been called.
+    */
+   *isNull = econtext->domainValue_isNull;
+   return econtext->domainValue_datum;
+}
+
 /*
  * ExecEvalConstraintTest
  *
@@ -1571,11 +1591,22 @@ ExecEvalConstraintTest(ConstraintTest *constraint, ExprContext *econtext,
        case CONSTR_TEST_NOTNULL:
            if (*isNull)
                elog(ERROR, "Domain %s does not allow NULL values",
-                    constraint->name);
+                    constraint->domname);
            break;
        case CONSTR_TEST_CHECK:
-           /* TODO: Add CHECK Constraints to domains */
-           elog(ERROR, "Domain CHECK Constraints not yet implemented");
+           {
+               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,7 +1808,12 @@ ExecEvalExpr(Node *expression,
                                              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 c354abf5dad8490b2fa3da910fae467bda7ab994..9dc29584e82ddc2fce048508073b8a6223b42c17 100644 (file)
@@ -15,7 +15,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.217 2002/11/11 22:19:22 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.218 2002/11/15 02:50:06 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1056,11 +1056,35 @@ _copyConstraintTest(ConstraintTest *from)
    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)
 {
@@ -3252,6 +3276,9 @@ copyObject(void *from)
        case T_ConstraintTest:
            retval = _copyConstraintTest(from);
            break;
+       case T_ConstraintTestValue:
+           retval = _copyConstraintTestValue(from);
+           break;
        case T_FkConstraint:
            retval = _copyFkConstraint(from);
            break;
@@ -3264,6 +3291,9 @@ copyObject(void *from)
        case T_InsertDefault:
            retval = _copyInsertDefault(from);
            break;
+       case T_DomainConstraintValue:
+           retval = _copyDomainConstraintValue(from);
+           break;
 
        default:
            elog(ERROR, "copyObject: don't know how to copy node type %d",
index ab84f5d3d2021094e6fde8f165643559c3e97a09..68e93e48b08c47bb7ed291c30ddb82cfe2e4aca6 100644 (file)
@@ -20,7 +20,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.163 2002/11/11 22:19:22 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.164 2002/11/15 02:50:06 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1971,15 +1971,32 @@ _equalConstraintTest(ConstraintTest *a, ConstraintTest *b)
        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)
 {
@@ -2438,6 +2455,9 @@ equal(void *a, void *b)
        case T_ConstraintTest:
            retval = _equalConstraintTest(a, b);
            break;
+       case T_ConstraintTestValue:
+           retval = _equalConstraintTestValue(a, b);
+           break;
        case T_FkConstraint:
            retval = _equalFkConstraint(a, b);
            break;
@@ -2450,6 +2470,9 @@ equal(void *a, void *b)
        case T_InsertDefault:
            retval = _equalInsertDefault(a, b);
            break;
+       case T_DomainConstraintValue:
+           retval = _equalDomainConstraintValue(a, b);
+           break;
 
        default:
            elog(WARNING, "equal: don't know whether nodes of type %d are equal",
index c5b5a493583669774389e247dc3f4d9d424cd633..2d1f2236c9bfb108902b23bac2669f8476783b6f 100644 (file)
@@ -5,7 +5,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.179 2002/11/11 22:19:22 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.180 2002/11/15 02:50:07 momjian Exp $
  *
  * NOTES
  *   Every (plan) node in POSTGRES has an associated "out" routine which
@@ -1525,10 +1525,32 @@ _outConstraintTest(StringInfo str, ConstraintTest *node)
    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'
@@ -1796,9 +1818,15 @@ _outNode(StringInfo str, void *obj)
            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:
                elog(WARNING, "_outNode: don't know how to print type %d ",
index 568bf8ee1e4fbea1831b7d37dea48037798b7d2f..9b2198ec5a57eb965a03625a4c3556d4381f8d89 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.136 2002/11/06 00:00:44 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.137 2002/11/15 02:50:07 momjian Exp $
  *
  * NOTES
  *   Most of the read functions for plan nodes are tested. (In fact, they
@@ -949,12 +949,56 @@ _readConstraintTest(void)
    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 */
 
    return local_node;
 }
 
+/* ----------------
+ *     _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
  *
@@ -2300,6 +2344,10 @@ parsePlanString(void)
        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 f55c988bfc5d4a32d8fc85c1cce7fdfb8b8de712..e7b4e3b5dbc6476dad2a87a833e1eb3310eec49a 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.110 2002/11/06 22:31:24 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.111 2002/11/15 02:50:07 momjian Exp $
  *
  * HISTORY
  *   AUTHOR            DATE            MAJOR EVENT
@@ -1926,6 +1926,8 @@ expression_tree_walker(Node *node,
            if (walker(((ConstraintTest *) node)->arg, context))
                return true;
            return walker(((ConstraintTest *) node)->check_expr, context);
+       case T_ConstraintTestValue:
+           break;
        case T_SubLink:
            {
                SubLink    *sublink = (SubLink *) node;
@@ -2310,6 +2312,15 @@ expression_tree_mutator(Node *node,
                return (Node *) newnode;
            }
            break;
+       case T_ConstraintTestValue:
+           {
+               ConstraintTestValue *ctest = (ConstraintTestValue *) node;
+               ConstraintTestValue *newnode;
+
+               FLATCOPY(newnode, ctest, ConstraintTestValue);
+               return (Node *) newnode;
+           }
+           break;
        case T_SubLink:
            {
                /*
index 30c8e8f15b999e0f375571ba38947ad7e4aae802..18144f7b94136c904258afdf9e31e3ce8529b696 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.253 2002/10/21 22:06:19 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.254 2002/11/15 02:50:07 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -2401,7 +2401,7 @@ transformExecuteStmt(ParseState *pstate, ExecuteStmt *stmt)
            Oid         expected_type_id,
                        given_type_id;
 
-           expr = transformExpr(pstate, expr);
+           expr = transformExpr(pstate, expr, NULL);
 
            /* Cannot contain subselects or aggregates */
            if (contain_subplans(expr))
index 724424220b671f3d79cb56483919e3a26efc68c8..b3ca71013c99cf0ce2dab4bceeb556d2c8d88c07 100644 (file)
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.377 2002/11/13 00:44:08 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.378 2002/11/15 02:50:08 momjian Exp $
  *
  * HISTORY
  *   AUTHOR            DATE            MAJOR EVENT
@@ -393,7 +393,7 @@ static void doNegateFloat(Value *v);
    UNENCRYPTED UNION UNIQUE UNKNOWN UNLISTEN UNTIL
    UPDATE USAGE USER USING
 
-   VACUUM VALID VALIDATOR VALUES VARCHAR VARYING
+   VACUUM VALID VALIDATOR VALUE VALUES VARCHAR VARYING
    VERBOSE VERSION VIEW VOLATILE
 
    WHEN WHERE WITH WITHOUT WORK WRITE
@@ -6406,6 +6406,11 @@ c_expr:      columnref                               { $$ = (Node *) $1; }
                    n->subselect = $2;
                    $$ = (Node *)n;
                }
+           | VALUE
+               {
+                   DomainConstraintValue *n = makeNode(DomainConstraintValue);
+                   $$ = (Node *)n;
+               }
        ;
 
 /*
@@ -7315,6 +7320,7 @@ reserved_keyword:
            | UNIQUE
            | USER
            | USING
+           | VALUE
            | WHEN
            | WHERE
        ;
index b86ffa522e4e3f45d3ba4996c8e1f11c11f010a9..de8a6e09b1a664d89cd7ae5c21fd1582bf436d55 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.130 2002/11/13 00:44:09 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.131 2002/11/15 02:50:08 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -314,6 +314,7 @@ static const ScanKeyword ScanKeywords[] = {
    {"vacuum", VACUUM},
    {"valid", VALID},
    {"validator", VALIDATOR},
+   {"value", VALUE},
    {"values", VALUES},
    {"varchar", VARCHAR},
    {"varying", VARYING},
index 245c0ba422bab57987c85830876c8158c9947898..d9638753746f7db869102ea2f6ea2731d0dcf5ed 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.98 2002/09/18 21:35:22 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.99 2002/11/15 02:50:08 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -283,7 +283,7 @@ transformJoinUsingClause(ParseState *pstate, List *leftVars, List *rightVars)
     * transformJoinOnClause() does.  Just invoke transformExpr() to fix
     * up the operators, and we're done.
     */
-   result = transformExpr(pstate, result);
+   result = transformExpr(pstate, result, NULL);
 
    result = coerce_to_boolean(result, "JOIN/USING");
 
@@ -317,7 +317,7 @@ transformJoinOnClause(ParseState *pstate, JoinExpr *j,
    pstate->p_namespace = makeList2(j->larg, j->rarg);
 
    /* This part is just like transformWhereClause() */
-   result = transformExpr(pstate, j->quals);
+   result = transformExpr(pstate, j->quals, NULL);
 
    result = coerce_to_boolean(result, "JOIN/ON");
 
@@ -478,7 +478,7 @@ transformRangeFunction(ParseState *pstate, RangeFunction *r)
    save_namespace = pstate->p_namespace;
    pstate->p_namespace = NIL;
 
-   funcexpr = transformExpr(pstate, r->funccallnode);
+   funcexpr = transformExpr(pstate, r->funccallnode, NULL);
 
    pstate->p_namespace = save_namespace;
 
@@ -961,7 +961,7 @@ transformWhereClause(ParseState *pstate, Node *clause)
    if (clause == NULL)
        return NULL;
 
-   qual = transformExpr(pstate, clause);
+   qual = transformExpr(pstate, clause, NULL);
 
    qual = coerce_to_boolean(qual, "WHERE");
 
@@ -1104,7 +1104,7 @@ findTargetlistEntry(ParseState *pstate, Node *node, List *tlist, int clause)
     * willing to match a resjunk target here, though the above cases must
     * ignore resjunk targets.
     */
-   expr = transformExpr(pstate, node);
+   expr = transformExpr(pstate, node, NULL);
 
    foreach(tl, tlist)
    {
index 4870b24de07fe892e91f8a1a8d0bcba021fed836..a24af2de3e1a1c4767f5c12017f51ddb08df33ca 100644 (file)
@@ -8,13 +8,18 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.85 2002/10/24 22:09:00 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.86 2002/11/15 02:50:09 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
 #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,8 +410,14 @@ coerce_type_constraints(Node *arg, Oid typeId, CoercionForm cformat)
    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,7 +430,45 @@ coerce_type_constraints(Node *arg, Oid typeId, CoercionForm cformat)
        if (typTup->typnotnull && notNull == NULL)
            notNull = pstrdup(NameStr(typTup->typname));
 
-       /* TODO: Add CHECK Constraints to domains */
+       /* 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')
        {
@@ -452,7 +501,8 @@ coerce_type_constraints(Node *arg, Oid typeId, CoercionForm cformat)
 
        r->arg = arg;
        r->testtype = CONSTR_TEST_NOTNULL;
-       r->name = notNull;
+       r->name = "NOT NULL";
+       r->domname = notNull;
        r->check_expr = NULL;
 
        arg = (Node *) r;
index 3873fd37f0de436dd1669b0a7602f9c862724480..9a4a9c8bc91e33fb226d0a883db5fef03782bd32 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.129 2002/09/18 21:35:22 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.130 2002/11/15 02:50:09 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -20,6 +20,7 @@
 #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,7 +84,7 @@ parse_expr_init(void)
  * input and output of transformExpr; see SubLink for example.
  */
 Node *
-transformExpr(ParseState *pstate, Node *expr)
+transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
 {
    Node       *result = NULL;
 
@@ -152,7 +153,7 @@ transformExpr(ParseState *pstate, Node *expr)
                ExprFieldSelect *efs = (ExprFieldSelect *) expr;
                List       *fields;
 
-               result = transformExpr(pstate, efs->arg);
+               result = transformExpr(pstate, efs->arg, domVal);
                /* handle qualification, if any */
                foreach(fields, efs->fields)
                {
@@ -169,7 +170,7 @@ transformExpr(ParseState *pstate, Node *expr)
        case T_TypeCast:
            {
                TypeCast   *tc = (TypeCast *) expr;
-               Node       *arg = transformExpr(pstate, tc->arg);
+               Node       *arg = transformExpr(pstate, tc->arg, domVal);
 
                result = typecast_expression(arg, tc->typename);
                break;
@@ -204,14 +205,14 @@ transformExpr(ParseState *pstate, Node *expr)
                                    n->arg = a->lexpr;
 
                                result = transformExpr(pstate,
-                                                      (Node *) n);
+                                                      (Node *) n, domVal);
                            }
                            else
                            {
                                Node       *lexpr = transformExpr(pstate,
-                                                              a->lexpr);
+                                                              a->lexpr, domVal);
                                Node       *rexpr = transformExpr(pstate,
-                                                              a->rexpr);
+                                                              a->rexpr, domVal);
 
                                result = (Node *) make_op(a->name,
                                                          lexpr,
@@ -222,9 +223,9 @@ transformExpr(ParseState *pstate, Node *expr)
                    case AND:
                        {
                            Node       *lexpr = transformExpr(pstate,
-                                                             a->lexpr);
+                                                             a->lexpr, domVal);
                            Node       *rexpr = transformExpr(pstate,
-                                                             a->rexpr);
+                                                             a->rexpr, domVal);
                            Expr       *expr = makeNode(Expr);
 
                            lexpr = coerce_to_boolean(lexpr, "AND");
@@ -239,9 +240,9 @@ transformExpr(ParseState *pstate, Node *expr)
                    case OR:
                        {
                            Node       *lexpr = transformExpr(pstate,
-                                                             a->lexpr);
+                                                             a->lexpr, domVal);
                            Node       *rexpr = transformExpr(pstate,
-                                                             a->rexpr);
+                                                             a->rexpr, domVal);
                            Expr       *expr = makeNode(Expr);
 
                            lexpr = coerce_to_boolean(lexpr, "OR");
@@ -256,7 +257,7 @@ transformExpr(ParseState *pstate, Node *expr)
                    case NOT:
                        {
                            Node       *rexpr = transformExpr(pstate,
-                                                             a->rexpr);
+                                                             a->rexpr, domVal);
                            Expr       *expr = makeNode(Expr);
 
                            rexpr = coerce_to_boolean(rexpr, "NOT");
@@ -270,9 +271,9 @@ transformExpr(ParseState *pstate, Node *expr)
                    case DISTINCT:
                        {
                            Node       *lexpr = transformExpr(pstate,
-                                                             a->lexpr);
+                                                             a->lexpr, domVal);
                            Node       *rexpr = transformExpr(pstate,
-                                                             a->rexpr);
+                                                             a->rexpr, domVal);
 
                            result = (Node *) make_op(a->name,
                                                      lexpr,
@@ -293,7 +294,7 @@ transformExpr(ParseState *pstate, Node *expr)
                             * Will result in a boolean constant node.
                             */
                            Node       *lexpr = transformExpr(pstate,
-                                                             a->lexpr);
+                                                             a->lexpr, domVal);
 
                            ltype = exprType(lexpr);
                            foreach(telem, (List *) a->rexpr)
@@ -317,7 +318,7 @@ transformExpr(ParseState *pstate, Node *expr)
                            n->val.val.str = (matched ? "t" : "f");
                            n->typename = SystemTypeName("bool");
 
-                           result = transformExpr(pstate, (Node *) n);
+                           result = transformExpr(pstate, (Node *) n, domVal);
                        }
                        break;
                }
@@ -331,7 +332,7 @@ transformExpr(ParseState *pstate, Node *expr)
                /* transform the list of arguments */
                foreach(args, fn->args)
                    lfirst(args) = transformExpr(pstate,
-                                                (Node *) lfirst(args));
+                                                (Node *) lfirst(args), domVal);
                result = ParseFuncOrColumn(pstate,
                                           fn->funcname,
                                           fn->args,
@@ -405,7 +406,7 @@ transformExpr(ParseState *pstate, Node *expr)
                    List       *elist;
 
                    foreach(elist, left_list)
-                       lfirst(elist) = transformExpr(pstate, lfirst(elist));
+                       lfirst(elist) = transformExpr(pstate, lfirst(elist), domVal);
 
                    Assert(IsA(sublink->oper, A_Expr));
                    op = ((A_Expr *) sublink->oper)->name;
@@ -504,7 +505,7 @@ transformExpr(ParseState *pstate, Node *expr)
                        warg = (Node *) makeSimpleA_Expr(OP, "=",
                                                         c->arg, warg);
                    }
-                   neww->expr = transformExpr(pstate, warg);
+                   neww->expr = transformExpr(pstate, warg, domVal);
 
                    neww->expr = coerce_to_boolean(neww->expr, "CASE/WHEN");
 
@@ -520,7 +521,7 @@ transformExpr(ParseState *pstate, Node *expr)
                        n->val.type = T_Null;
                        warg = (Node *) n;
                    }
-                   neww->result = transformExpr(pstate, warg);
+                   neww->result = transformExpr(pstate, warg, domVal);
 
                    newargs = lappend(newargs, neww);
                    typeids = lappendi(typeids, exprType(neww->result));
@@ -544,7 +545,7 @@ transformExpr(ParseState *pstate, Node *expr)
                    n->val.type = T_Null;
                    defresult = (Node *) n;
                }
-               newc->defresult = transformExpr(pstate, defresult);
+               newc->defresult = transformExpr(pstate, defresult, domVal);
 
                /*
                 * Note: default result is considered the most significant
@@ -580,7 +581,7 @@ transformExpr(ParseState *pstate, Node *expr)
            {
                NullTest   *n = (NullTest *) expr;
 
-               n->arg = transformExpr(pstate, n->arg);
+               n->arg = transformExpr(pstate, n->arg, domVal);
                /* the argument can be any type, so don't coerce it */
                result = expr;
                break;
@@ -617,7 +618,7 @@ transformExpr(ParseState *pstate, Node *expr)
                        clausename = NULL;      /* keep compiler quiet */
                }
 
-               b->arg = transformExpr(pstate, b->arg);
+               b->arg = transformExpr(pstate, b->arg, domVal);
 
                b->arg = coerce_to_boolean(b->arg, clausename);
 
@@ -625,6 +626,13 @@ transformExpr(ParseState *pstate, Node *expr)
                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.
@@ -936,6 +944,9 @@ exprType(Node *expr)
        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",
                 nodeTag(expr));
index f0bb1856ab38c9b0e97c24d8fc54ad2d72a78a7b..608a67921c128863a8f4a1784745468f52fb5e56 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.72 2002/11/13 00:39:47 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.73 2002/11/15 02:50:09 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -277,7 +277,7 @@ transformArraySubscripts(ParseState *pstate,
        {
            if (ai->lidx)
            {
-               subexpr = transformExpr(pstate, 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,
@@ -299,7 +299,7 @@ transformArraySubscripts(ParseState *pstate,
            }
            lowerIndexpr = lappend(lowerIndexpr, subexpr);
        }
-       subexpr = transformExpr(pstate, ai->uidx);
+       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 c03db4f8b4b36fbf65e84a1c2190be0a3a1bb74c..1a2da6da1eb354fe1723a90e20951056314b4961 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.91 2002/09/28 20:00:19 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.92 2002/11/15 02:50:09 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -56,7 +56,7 @@ transformTargetEntry(ParseState *pstate,
 
    /* Transform the node if caller didn't do it already */
    if (expr == NULL)
-       expr = transformExpr(pstate, node);
+       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 796eaa05069b07e56d32d9d7324033e32752878c..9250faff27a7ab274d0f18293212f32bd0207445 100644 (file)
@@ -3,7 +3,7 @@
  *             back to source text
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.124 2002/09/19 23:40:56 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.125 2002/11/15 02:50:09 momjian Exp $
  *
  *   This software is copyrighted by Jan Wieck - Hamburg.
  *
@@ -2226,6 +2226,12 @@ get_rule_expr(Node *node, deparse_context *context,
            }
            break;
 
+       case T_ConstraintTestValue:
+           {
+               appendStringInfo(buf, "VALUE");
+           }
+           break;
+
        case T_SubLink:
            get_sublink_expr(node, context);
            break;
index fce84e72ae98912ef4736966cefec336abab522b..4a76a27dec6529d429b29e7c4f0eeeffe17ad4a4 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: indexing.h,v 1.76 2002/10/18 20:33:57 tgl Exp $
+ * $Id: indexing.h,v 1.77 2002/11/15 02:50:10 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -40,6 +40,7 @@
 #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,6 +130,8 @@ DECLARE_UNIQUE_INDEX(pg_class_relname_nsp_index on pg_class using btree(relname
 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 ffe6a740ca80ba47014a4a548935c5db07c88bb0..80ff185579ed25a9cd4de6bdfd5d858930b6a3fb 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pg_constraint.h,v 1.4 2002/09/22 00:37:09 tgl Exp $
+ * $Id: pg_constraint.h,v 1.5 2002/11/15 02:50:10 momjian Exp $
  *
  * NOTES
  *   the genbki.sh script reads this file and generates .bki
@@ -140,6 +140,15 @@ typedef FormData_pg_constraint *Form_pg_constraint;
  * 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,10 +175,10 @@ extern Oid CreateConstraintEntry(const char *constraintName,
 
 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 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 f62d1cb8159f06a649b609765666ce85d99742bd..f955815926d90586eebfb40e98be1d57088ad1ed 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: execnodes.h,v 1.77 2002/11/06 22:31:24 tgl Exp $
+ * $Id: execnodes.h,v 1.78 2002/11/15 02:50:10 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -113,6 +113,13 @@ typedef struct ExprContext
    Datum      *ecxt_aggvalues; /* precomputed values for Aggref nodes */
    bool       *ecxt_aggnulls;  /* null flags for Aggref nodes */
 
+   /*
+    * Carry the domain value through the executor for application
+    * in a domain constraint
+    */
+   Datum       domainValue_datum;
+   bool        domainValue_isNull;
+
    /* Functions to call back when ExprContext is shut down */
    ExprContext_CB *ecxt_callbacks;
 } ExprContext;
index cec753092108e48aaf4da4ba45018bc644883c9a..112eac34680bd8cbc9db92c6f17c836168f69904 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: nodes.h,v 1.122 2002/11/10 02:17:25 momjian Exp $
+ * $Id: nodes.h,v 1.123 2002/11/15 02:50:10 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -171,6 +171,7 @@ typedef enum NodeTag
    T_ViewStmt,
    T_LoadStmt,
    T_CreateDomainStmt,
+   T_DomainConstraintValue,
    T_CreatedbStmt,
    T_DropdbStmt,
    T_VacuumStmt,
@@ -231,6 +232,7 @@ typedef enum NodeTag
    T_NullTest,
    T_BooleanTest,
    T_ConstraintTest,
+   T_ConstraintTestValue,
    T_CaseExpr,
    T_CaseWhen,
    T_FkConstraint,
index 962452992e80c59b70f23563bcec6d61d1d1787f..1198a81de5e6fbb4cfc17d6dedea4649a4487ac8 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parsenodes.h,v 1.213 2002/11/13 00:44:09 momjian Exp $
+ * $Id: parsenodes.h,v 1.214 2002/11/15 02:50:12 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -285,9 +285,26 @@ typedef struct ConstraintTest
    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 a153c4d05709f27fb01aa9c5edc49656ab4363b8..68ffc8e373a7e48bfacf25a20a12550ffdc96a3e 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: var.h,v 1.21 2002/06/20 20:29:51 momjian Exp $
+ * $Id: var.h,v 1.22 2002/11/15 02:50:21 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -22,6 +22,7 @@ extern bool contain_var_reference(Node *node, int varno, int varattno,
                      int levelsup);
 extern bool contain_whole_tuple_var(Node *node, int varno, int levelsup);
 extern bool contain_var_clause(Node *node);
+extern bool contain_var_tuple_clause(Node *node);
 extern List *pull_var_clause(Node *node, bool includeUpperVars);
 extern Node *flatten_join_alias_vars(Node *node, List *rtable, bool force);
 
index a7af335dd123961c442eb2dbd00fb4082d3888ae..bcf84912acf89e6aa4131f45bb455226b673222f 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parse_expr.h,v 1.28 2002/06/20 20:29:51 momjian Exp $
+ * $Id: parse_expr.h,v 1.29 2002/11/15 02:50:21 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -21,7 +21,8 @@
 extern int max_expr_depth;
 extern bool Transform_null_equals;
 
-extern Node *transformExpr(ParseState *pstate, Node *expr);
+
+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 e82ce6fdf08ecf2a95cb92096130db68c95a7c5e..92c9cc2cc00d9c7c8201b091d38cc2dfd33526ff 100644 (file)
@@ -103,35 +103,43 @@ drop domain domainint4arr restrict;
 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');  -- Good
-INSERT INTO nulltest values (NULL, 'b', 'c', 'd');
+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');
+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');
+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); -- Good
+INSERT INTO nulltest values ('a', 'b', 'c', NULL, 'd'); -- Good
 -- Test copy
 COPY nulltest FROM stdin; --fail
-ERROR:  copy: line 1, CopyFrom: Fail to add null value in not null attribute col3
+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 
-------+------+------+------
- a    | b    | c    | d
- a    | b    | c    | 
- a    | b    | c    | 
-(3 rows)
+ 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 4d210cd4aa7fcbd2e9b83c0d0ebb8aaa57d4f612..65fba7466fd5bd5f2d58a7bc73b2a0257719cf9a 100644 (file)
@@ -83,29 +83,36 @@ 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;
-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
+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
+a  b   \N  d   \N
 \.
 
 SET autocommit TO 'on';
 
+-- Last row is bad
 COPY nulltest FROM stdin;
-a  b   c   \N
+a  b   c   \N  c
+a  b   c   \N  d
+a  b   c   \N  a
 \.
 
 select * from nulltest;