*** a/src/backend/commands/typecmds.c
--- b/src/backend/commands/typecmds.c
***************
*** 86,91 **** static Oid	findTypeSendFunction(List *procname, Oid typeOid);
--- 86,92 ----
  static Oid	findTypeTypmodinFunction(List *procname);
  static Oid	findTypeTypmodoutFunction(List *procname);
  static Oid	findTypeAnalyzeFunction(List *procname, Oid typeOid);
+ static void	validateDomainConstraint(Oid domainoid, char *ccbin);
  static List *get_rels_with_domain(Oid domainOid, LOCKMODE lockmode);
  static void checkDomainOwner(HeapTuple tup);
  static void checkEnumOwner(HeapTuple tup);
***************
*** 1941,1954 **** AlterDomainAddConstraint(List *names, Node *newConstraint)
  	Relation	typrel;
  	HeapTuple	tup;
  	Form_pg_type typTup;
- 	List	   *rels;
- 	ListCell   *rt;
- 	EState	   *estate;
- 	ExprContext *econtext;
- 	char	   *ccbin;
- 	Expr	   *expr;
- 	ExprState  *exprstate;
  	Constraint *constr;
  
  	/* Make a TypeName so we can use standard type lookup machinery */
  	typename = makeTypeNameFromNameList(names);
--- 1942,1949 ----
  	Relation	typrel;
  	HeapTuple	tup;
  	Form_pg_type typTup;
  	Constraint *constr;
+ 	char	   *ccbin;
  
  	/* Make a TypeName so we can use standard type lookup machinery */
  	typename = makeTypeNameFromNameList(names);
***************
*** 2027,2036 **** AlterDomainAddConstraint(List *names, Node *newConstraint)
  								constr, NameStr(typTup->typname));
  
  	/*
! 	 * Test all values stored in the attributes based on the domain the
! 	 * constraint is being added to.
  	 */
! 	expr = (Expr *) stringToNode(ccbin);
  
  	/* Need an EState to run ExecEvalExpr */
  	estate = CreateExecutorState();
--- 2022,2147 ----
  								constr, NameStr(typTup->typname));
  
  	/*
! 	 * If requested to validate the constraint, test all values stored in the
! 	 * attributes based on the domain the constraint is being added to.
! 	 */
! 	if (!constr->skip_validation)
! 		validateDomainConstraint(domainoid, ccbin);
! 
! 	/* Clean up */
! 	heap_close(typrel, RowExclusiveLock);
! }
! 
! /*
!  * AlterDomainValidateConstraint
!  *
!  * Implements the ALTER DOMAIN .. VALIDATE CONSTRAINT statement.
!  */
! void
! AlterDomainValidateConstraint(List *names, char *constrName)
! {
! 	TypeName   *typename;
! 	Oid			domainoid;
! 	Relation	typrel;
! 	Relation	conrel;
! 	HeapTuple	tup;
! 	Form_pg_type typTup;
! 	Form_pg_constraint con;
! 	Form_pg_constraint copy_con;
! 	char	   *conbin;
! 	SysScanDesc	scan;
! 	Datum		val;
! 	bool		found = false;
! 	bool		isnull;
! 	HeapTuple	tuple;
! 	HeapTuple	copyTuple;
! 	ScanKeyData	key;
! 
! 	/* Make a TypeName so we can use standard type lookup machinery */
! 	typename = makeTypeNameFromNameList(names);
! 	domainoid = typenameTypeId(NULL, typename);
! 
! 	/* Look up the domain in the type table */
! 	typrel = heap_open(TypeRelationId, AccessShareLock);
! 
! 	tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(domainoid));
! 	if (!HeapTupleIsValid(tup))
! 		elog(ERROR, "cache lookup failed for type %u", domainoid);
! 	typTup = (Form_pg_type) GETSTRUCT(tup);
! 
! 	/* Check it's a domain and check user has permission for ALTER DOMAIN */
! 	checkDomainOwner(tup);
! 
! 	/*
! 	 * Find and check the target constraint
  	 */
! 	conrel = heap_open(ConstraintRelationId, RowExclusiveLock);
! 	ScanKeyInit(&key,
! 				Anum_pg_constraint_contypid,
! 				BTEqualStrategyNumber, F_OIDEQ,
! 				ObjectIdGetDatum(domainoid));
! 	scan = systable_beginscan(conrel, ConstraintTypidIndexId,
! 							  true, SnapshotNow, 1, &key);
! 
! 	while (HeapTupleIsValid(tuple = systable_getnext(scan)))
! 	{
! 		con = (Form_pg_constraint) GETSTRUCT(tuple);
! 		if (strcmp(NameStr(con->conname), constrName) == 0)
! 		{
! 			found = true;
! 			break;
! 		}
! 	}
! 
! 	if (!found)
! 		ereport(ERROR,
! 				(errcode(ERRCODE_UNDEFINED_OBJECT),
! 				 errmsg("constraint \"%s\" of domain \"%s\" does not exist",
! 						constrName, NameStr(con->conname))));
! 
! 	if (con->contype != CONSTRAINT_CHECK)
! 		ereport(ERROR,
! 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
! 				 errmsg("constraint \"%s\" of domain \"%s\" is not a check constraint",
! 						constrName, NameStr(con->conname))));
! 
! 	val = SysCacheGetAttr(CONSTROID, tuple,
! 						  Anum_pg_constraint_conbin,
! 						  &isnull);
! 	if (isnull)
! 		elog(ERROR, "null conbin for constraint %u",
! 			 HeapTupleGetOid(tuple));
! 	conbin = TextDatumGetCString(val);
! 
! 	validateDomainConstraint(domainoid, conbin);
! 
! 	/*
! 	 * Now update the catalog, while we have the door open.
! 	 */
! 	copyTuple = heap_copytuple(tuple);
! 	copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple);
! 	copy_con->convalidated = true;
! 	simple_heap_update(conrel, &copyTuple->t_self, copyTuple);
! 	CatalogUpdateIndexes(conrel, copyTuple);
! 	heap_freetuple(copyTuple);
! 
! 	systable_endscan(scan);
! 
! 	heap_close(typrel, AccessShareLock);
! 	heap_close(conrel, RowExclusiveLock);
! 
! 	ReleaseSysCache(tup);
! }
! 
! static void
! validateDomainConstraint(Oid domainoid, char *ccbin)
! {
! 	Expr	   *expr = (Expr *) stringToNode(ccbin);
! 	List	   *rels;
! 	ListCell   *rt;
! 	EState	   *estate;
! 	ExprContext *econtext;
! 	ExprState  *exprstate;
  
  	/* Need an EState to run ExecEvalExpr */
  	estate = CreateExecutorState();
***************
*** 2079,2085 **** AlterDomainAddConstraint(List *names, Node *newConstraint)
  					ereport(ERROR,
  							(errcode(ERRCODE_CHECK_VIOLATION),
  							 errmsg("column \"%s\" of table \"%s\" contains values that violate the new constraint",
! 								NameStr(tupdesc->attrs[attnum - 1]->attname),
  									RelationGetRelationName(testrel))));
  			}
  
--- 2190,2196 ----
  					ereport(ERROR,
  							(errcode(ERRCODE_CHECK_VIOLATION),
  							 errmsg("column \"%s\" of table \"%s\" contains values that violate the new constraint",
! 									NameStr(tupdesc->attrs[attnum - 1]->attname),
  									RelationGetRelationName(testrel))));
  			}
  
***************
*** 2092,2102 **** AlterDomainAddConstraint(List *names, Node *newConstraint)
  	}
  
  	FreeExecutorState(estate);
- 
- 	/* Clean up */
- 	heap_close(typrel, RowExclusiveLock);
  }
- 
  /*
   * get_rels_with_domain
   *
--- 2203,2209 ----
***************
*** 2416,2422 **** domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
  						  CONSTRAINT_CHECK,		/* Constraint Type */
  						  false,	/* Is Deferrable */
  						  false,	/* Is Deferred */
! 						  true, /* Is Validated */
  						  InvalidOid,	/* not a relation constraint */
  						  NULL,
  						  0,
--- 2523,2529 ----
  						  CONSTRAINT_CHECK,		/* Constraint Type */
  						  false,	/* Is Deferrable */
  						  false,	/* Is Deferred */
! 						  !constr->skip_validation, /* Is Validated */
  						  InvalidOid,	/* not a relation constraint */
  						  NULL,
  						  0,
*** a/src/backend/parser/gram.y
--- b/src/backend/parser/gram.y
***************
*** 7576,7581 **** AlterDomainStmt:
--- 7576,7590 ----
  					n->behavior = $7;
  					$$ = (Node *)n;
  				}
+ 			/* ALTER DOMAIN <domain> VALIDATE CONSTRAINT <name> */
+ 			| ALTER DOMAIN_P any_name VALIDATE CONSTRAINT name
+ 				{
+ 					AlterDomainStmt *n = makeNode(AlterDomainStmt);
+ 					n->subtype = 'V';
+ 					n->typeName = $3;
+ 					n->name = $6;
+ 					$$ = (Node *)n;
+ 				}
  			;
  
  opt_as:		AS										{}
*** a/src/backend/tcop/utility.c
--- b/src/backend/tcop/utility.c
***************
*** 820,825 **** standard_ProcessUtility(Node *parsetree,
--- 820,829 ----
  												  stmt->name,
  												  stmt->behavior);
  						break;
+ 					case 'V':	/* VALIDATE CONSTRAINT */
+ 						AlterDomainValidateConstraint(stmt->typeName,
+ 													  stmt->name);
+ 						break;
  					default:	/* oops */
  						elog(ERROR, "unrecognized alter domain type: %d",
  							 (int) stmt->subtype);
*** a/src/include/commands/typecmds.h
--- b/src/include/commands/typecmds.h
***************
*** 31,36 **** extern Oid	AssignTypeArrayOid(void);
--- 31,37 ----
  extern void AlterDomainDefault(List *names, Node *defaultRaw);
  extern void AlterDomainNotNull(List *names, bool notNull);
  extern void AlterDomainAddConstraint(List *names, Node *constr);
+ extern void AlterDomainValidateConstraint(List *names, char *constrName);
  extern void AlterDomainDropConstraint(List *names, const char *constrName,
  						  DropBehavior behavior);
  
