diff --git a/doc/src/sgml/ref/create_domain.sgml b/doc/src/sgml/ref/create_domain.sgml
index b7d5e606d3e602019fc358deba84020527df96bd..bd4114688f6347d40009cad51a6a8ede8227b0b2 100644
--- a/doc/src/sgml/ref/create_domain.sgml
+++ b/doc/src/sgml/ref/create_domain.sgml
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_domain.sgml,v 1.6 2002/09/20 03:39:15 momjian Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_domain.sgml,v 1.7 2002/11/15 02:50:05 momjian Exp $
 PostgreSQL documentation
 -->
 
@@ -200,16 +200,6 @@ CREATE TABLE countrylist (id INT4, country country_code);
   </para>
  </refsect1>
 
- <refsect1 id="SQL-CREATEDOMAIN-compatibility">
-  <title>Compatibility</title>
-
-  <para>
-   SQL99 defines CREATE DOMAIN, but says that the only allowed constraint
-   type is CHECK constraints.  CHECK constraints for domains are not yet
-   supported by <productname>PostgreSQL</productname>.
-  </para>
- </refsect1>
-
  <refsect1 id="SQL-CREATEDOMAIN-see-also">
   <title>See Also</title>
 
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 9956672c12af6f96b7baef284e24429a7bff078d..f8f667e24a9d8f01f4c89b27ca86b66aba61cb09 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.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.
diff --git a/src/backend/catalog/pg_constraint.c b/src/backend/catalog/pg_constraint.c
index e03e545beb37f5c4ea8929c8ad9cb24c08e5dffb..7cd105928c331309c96539c82ef20bbc9a30d3f0 100644
--- a/src/backend/catalog/pg_constraint.c
+++ b/src/backend/catalog/pg_constraint.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/pg_constraint.c,v 1.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);
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 8023ba834204b070580e314b0d7ebd30549e3dd2..cda8687e448c872b2185eb44e8589c52b2f48119 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.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.
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index a573cac27def844350bafebb51f94965780f2fd4..ab0608a08a9cdeba90c52d98959e2e3a30d6c142 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/typecmds.c,v 1.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
@@ -36,10 +36,17 @@
 #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.
diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c
index 5718983ca101fb794c55b0a36fd4d6943b77e950..1612a2d9ea2b3dd474a4ea5cd391e0a36e1926cd 100644
--- a/src/backend/executor/execQual.c
+++ b/src/backend/executor/execQual.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.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));
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index c354abf5dad8490b2fa3da910fae467bda7ab994..9dc29584e82ddc2fce048508073b8a6223b42c17 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -15,7 +15,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.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",
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index ab84f5d3d2021094e6fde8f165643559c3e97a09..68e93e48b08c47bb7ed291c30ddb82cfe2e4aca6 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -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",
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index c5b5a493583669774389e247dc3f4d9d424cd633..2d1f2236c9bfb108902b23bac2669f8476783b6f 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -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 ",
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index 568bf8ee1e4fbea1831b7d37dea48037798b7d2f..9b2198ec5a57eb965a03625a4c3556d4381f8d89 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.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);
 
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index f55c988bfc5d4a32d8fc85c1cce7fdfb8b8de712..e7b4e3b5dbc6476dad2a87a833e1eb3310eec49a 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.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:
 			{
 				/*
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index 30c8e8f15b999e0f375571ba38947ad7e4aae802..18144f7b94136c904258afdf9e31e3ce8529b696 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- *	$Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.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))
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 724424220b671f3d79cb56483919e3a26efc68c8..b3ca71013c99cf0ce2dab4bceeb556d2c8d88c07 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.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
 		;
diff --git a/src/backend/parser/keywords.c b/src/backend/parser/keywords.c
index b86ffa522e4e3f45d3ba4996c8e1f11c11f010a9..de8a6e09b1a664d89cd7ae5c21fd1582bf436d55 100644
--- a/src/backend/parser/keywords.c
+++ b/src/backend/parser/keywords.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.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},
diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c
index 245c0ba422bab57987c85830876c8158c9947898..d9638753746f7db869102ea2f6ea2731d0dcf5ed 100644
--- a/src/backend/parser/parse_clause.c
+++ b/src/backend/parser/parse_clause.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.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)
 	{
diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c
index 4870b24de07fe892e91f8a1a8d0bcba021fed836..a24af2de3e1a1c4767f5c12017f51ddb08df33ca 100644
--- a/src/backend/parser/parse_coerce.c
+++ b/src/backend/parser/parse_coerce.c
@@ -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;
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index 3873fd37f0de436dd1669b0a7602f9c862724480..9a4a9c8bc91e33fb226d0a883db5fef03782bd32 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.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));
diff --git a/src/backend/parser/parse_node.c b/src/backend/parser/parse_node.c
index f0bb1856ab38c9b0e97c24d8fc54ad2d72a78a7b..608a67921c128863a8f4a1784745468f52fb5e56 100644
--- a/src/backend/parser/parse_node.c
+++ b/src/backend/parser/parse_node.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.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,
diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c
index c03db4f8b4b36fbf65e84a1c2190be0a3a1bb74c..1a2da6da1eb354fe1723a90e20951056314b4961 100644
--- a/src/backend/parser/parse_target.c
+++ b/src/backend/parser/parse_target.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.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.*.");
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 796eaa05069b07e56d32d9d7324033e32752878c..9250faff27a7ab274d0f18293212f32bd0207445 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -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;
diff --git a/src/include/catalog/indexing.h b/src/include/catalog/indexing.h
index fce84e72ae98912ef4736966cefec336abab522b..4a76a27dec6529d429b29e7c4f0eeeffe17ad4a4 100644
--- a/src/include/catalog/indexing.h
+++ b/src/include/catalog/indexing.h
@@ -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));
diff --git a/src/include/catalog/pg_constraint.h b/src/include/catalog/pg_constraint.h
index ffe6a740ca80ba47014a4a548935c5db07c88bb0..80ff185579ed25a9cd4de6bdfd5d858930b6a3fb 100644
--- a/src/include/catalog/pg_constraint.h
+++ b/src/include/catalog/pg_constraint.h
@@ -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 */
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index f62d1cb8159f06a649b609765666ce85d99742bd..f955815926d90586eebfb40e98be1d57088ad1ed 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: execnodes.h,v 1.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;
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index cec753092108e48aaf4da4ba45018bc644883c9a..112eac34680bd8cbc9db92c6f17c836168f69904 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: nodes.h,v 1.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,
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 962452992e80c59b70f23563bcec6d61d1d1787f..1198a81de5e6fbb4cfc17d6dedea4649a4487ac8 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parsenodes.h,v 1.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)
  *
diff --git a/src/include/optimizer/var.h b/src/include/optimizer/var.h
index a153c4d05709f27fb01aa9c5edc49656ab4363b8..68ffc8e373a7e48bfacf25a20a12550ffdc96a3e 100644
--- a/src/include/optimizer/var.h
+++ b/src/include/optimizer/var.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: var.h,v 1.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);
 
diff --git a/src/include/parser/parse_expr.h b/src/include/parser/parse_expr.h
index a7af335dd123961c442eb2dbd00fb4082d3888ae..bcf84912acf89e6aa4131f45bb455226b673222f 100644
--- a/src/include/parser/parse_expr.h
+++ b/src/include/parser/parse_expr.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parse_expr.h,v 1.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);
diff --git a/src/test/regress/expected/domain.out b/src/test/regress/expected/domain.out
index e82ce6fdf08ecf2a95cb92096130db68c95a7c5e..92c9cc2cc00d9c7c8201b091d38cc2dfd33526ff 100644
--- a/src/test/regress/expected/domain.out
+++ b/src/test/regress/expected/domain.out
@@ -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);
diff --git a/src/test/regress/sql/domain.sql b/src/test/regress/sql/domain.sql
index 4d210cd4aa7fcbd2e9b83c0d0ebb8aaa57d4f612..65fba7466fd5bd5f2d58a7bc73b2a0257719cf9a 100644
--- a/src/test/regress/sql/domain.sql
+++ b/src/test/regress/sql/domain.sql
@@ -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;