? configure.lineno
Index: src/backend/commands/tablecmds.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/commands/tablecmds.c,v
retrieving revision 1.16
diff -c -r1.16 tablecmds.c
*** src/backend/commands/tablecmds.c	2002/05/21 22:05:54	1.16
--- src/backend/commands/tablecmds.c	2002/06/22 04:08:12
***************
*** 49,55 ****
  #include "utils/relcache.h"
  
  
- static List *MergeDomainAttributes(List *schema);
  static List *MergeAttributes(List *schema, List *supers, bool istemp,
  				List **supOids, List **supconstr, bool *supHasOids);
  static bool change_varattnos_of_a_node(Node *node, const AttrNumber *newattno);
--- 49,54 ----
***************
*** 124,136 ****
  	}
  
  	/*
- 	 * Merge domain attributes into the known columns before processing table
- 	 * inheritance.  Otherwise we risk adding double constraints to a
- 	 * domain-type column that's inherited.
- 	 */
- 	schema = MergeDomainAttributes(schema);
- 
- 	/*
  	 * Look up inheritance ancestors and generate relation schema,
  	 * including inherited attributes.
  	 */
--- 123,128 ----
***************
*** 327,375 ****
  	heap_close(rel, NoLock);
  
  	heap_truncate(relid);
- }
- 
- 
- /*
-  * MergeDomainAttributes
-  *      Returns a new table schema with the constraints, types, and other
-  *      attributes of domains resolved for fields using a domain as
-  *      their type.
-  */
- static List *
- MergeDomainAttributes(List *schema)
- {
- 	List	   *entry;
- 
- 	/*
- 	 * Loop through the table elements supplied. These should
- 	 * never include inherited domains else they'll be
- 	 * double (or more) processed.
- 	 */
- 	foreach(entry, schema)
- 	{
- 		ColumnDef  *coldef = lfirst(entry);
- 		HeapTuple  tuple;
- 		Form_pg_type typeTup;
- 
- 		tuple = typenameType(coldef->typename);
- 		typeTup = (Form_pg_type) GETSTRUCT(tuple);
- 
- 		if (typeTup->typtype == 'd')
- 		{
- 			/* Force the column to have the correct typmod. */
- 			coldef->typename->typmod = typeTup->typtypmod;
- 			/* XXX more to do here? */
- 		}
- 
- 		/* Enforce type NOT NULL || column definition NOT NULL -> NOT NULL */
- 		/* Currently only used for domains, but could be valid for all */
- 		coldef->is_not_null |= typeTup->typnotnull;
- 
- 		ReleaseSysCache(tuple);
- 	}
- 
- 	return schema;
  }
  
  /*----------
--- 319,324 ----
Index: src/backend/executor/execQual.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/executor/execQual.c,v
retrieving revision 1.93
diff -c -r1.93 execQual.c
*** src/backend/executor/execQual.c	2002/05/12 23:43:02	1.93
--- src/backend/executor/execQual.c	2002/06/22 04:08:18
***************
*** 64,69 ****
--- 64,71 ----
  				 bool *isNull, ExprDoneCond *isDone);
  static Datum ExecEvalBooleanTest(BooleanTest *btest, ExprContext *econtext,
  					bool *isNull, ExprDoneCond *isDone);
+ static Datum ExecEvalConstraint(Constraint *constraint, ExprContext *econtext,
+ 								bool *isNull, ExprDoneCond *isDone);
  
  
  /*----------
***************
*** 1149,1154 ****
--- 1151,1193 ----
  	}
  }
  
+ /*
+  * ExecEvalConstraint
+  *
+  * Test the constraint against the data provided.  If the data fits
+  * within the constraint specifications, pass it through (return the
+  * datum) otherwise throw an error.
+  */
+ static Datum
+ ExecEvalConstraint(Constraint *constraint, ExprContext *econtext,
+ 				   bool *isNull, ExprDoneCond *isDone)
+ {
+ 	Datum		result;
+ 
+ 	result = ExecEvalExpr(constraint->raw_expr, econtext, isNull, isDone);
+ 
+ 	/* Test for the constraint type */
+ 	switch(constraint->contype)
+ 	{
+ 		case CONSTR_NOTNULL:
+ 			if (*isNull)
+ 			{
+ 				elog(ERROR, "Domain %s does not allow NULL values", constraint->name);
+ 			}
+ 			break;
+ 		case CONSTR_CHECK:
+ 
+ 				elog(ERROR, "ExecEvalConstraint: Domain CHECK Constraints not yet implemented");
+ 			break;
+ 		default:
+ 			elog(ERROR, "ExecEvalConstraint: Constraint type unknown");
+ 			break;
+ 	}
+ 
+ 	/* If all has gone well (constraint did not fail) return the datum */
+ 	return result;
+ }
+ 
  /* ----------------------------------------------------------------
   *		ExecEvalBooleanTest
   *
***************
*** 1391,1396 ****
--- 1430,1441 ----
  									econtext,
  									isNull,
  									isDone);
+ 			break;
+ 		case T_Constraint:
+ 			retDatum = ExecEvalConstraint((Constraint *) expression,
+ 										 econtext,
+ 										 isNull,
+ 										 isDone);
  			break;
  		case T_CaseExpr:
  			retDatum = ExecEvalCase((CaseExpr *) expression,
Index: src/backend/optimizer/util/clauses.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v
retrieving revision 1.100
diff -c -r1.100 clauses.c
*** src/backend/optimizer/util/clauses.c	2002/05/18 18:49:41	1.100
--- src/backend/optimizer/util/clauses.c	2002/06/22 04:08:24
***************
*** 1786,1791 ****
--- 1786,1793 ----
  					return true;
  			}
  			break;
+ 		case T_Constraint:
+ 			return walker(((Constraint *) node)->raw_expr, context);
  		case T_NullTest:
  			return walker(((NullTest *) node)->arg, context);
  		case T_BooleanTest:
***************
*** 2140,2145 ****
--- 2142,2161 ----
  				return (Node *) newnode;
  			}
  			break;
+ 		case T_Constraint:
+ 			{
+ 				/*
+ 				 * Used for confirming domains.  Only needed fields
+ 				 * within the executor are the name, raw expression
+ 				 * and constraint type.
+ 				 */
+ 				Constraint *con = (Constraint *) node;
+ 				Constraint *newnode;
+ 
+ 				FLATCOPY(newnode, con, Constraint);
+ 				MUTATE(newnode->raw_expr, con->raw_expr, Node *);
+ 				return (Node *) newnode;
+ 			}
  		case T_NullTest:
  			{
  				NullTest   *ntest = (NullTest *) node;
Index: src/backend/parser/gram.y
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/parser/gram.y,v
retrieving revision 2.323
diff -c -r2.323 gram.y
*** src/backend/parser/gram.y	2002/06/15 03:00:03	2.323
--- src/backend/parser/gram.y	2002/06/22 04:08:34
***************
*** 6709,6732 ****
  makeTypeCast(Node *arg, TypeName *typename)
  {
  	/*
! 	 * If arg is an A_Const, just stick the typename into the
! 	 * field reserved for it --- unless there's something there already!
! 	 * (We don't want to collapse x::type1::type2 into just x::type2.)
! 	 * Otherwise, generate a TypeCast node.
  	 */
! 	if (IsA(arg, A_Const) &&
! 		((A_Const *) arg)->typename == NULL)
! 	{
! 		((A_Const *) arg)->typename = typename;
! 		return arg;
! 	}
! 	else
! 	{
! 		TypeCast *n = makeNode(TypeCast);
! 		n->arg = arg;
! 		n->typename = typename;
! 		return (Node *) n;
! 	}
  }
  
  static Node *
--- 6709,6724 ----
  makeTypeCast(Node *arg, TypeName *typename)
  {
  	/*
! 	 * Simply generate a TypeCast node.
! 	 *
! 	 * Earlier we would determine whether an A_Const would
! 	 * be acceptable, however Domains require coerce_type()
! 	 * to process them -- applying constraints as required. 
  	 */
! 	TypeCast *n = makeNode(TypeCast);
! 	n->arg = arg;
! 	n->typename = typename;
! 	return (Node *) n;
  }
  
  static Node *
Index: src/backend/parser/parse_coerce.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/parser/parse_coerce.c,v
retrieving revision 2.73
diff -c -r2.73 parse_coerce.c
*** src/backend/parser/parse_coerce.c	2002/05/17 22:35:12	2.73
--- src/backend/parser/parse_coerce.c	2002/06/22 04:08:35
***************
*** 33,40 ****
  static Node *build_func_call(Oid funcid, Oid rettype, List *args);
  static Oid	find_coercion_function(Oid targetTypeId, Oid inputTypeId,
  								   Oid secondArgType, bool isExplicit);
  
- 
  /* coerce_type()
   * Convert a function argument to a different type.
   */
--- 33,40 ----
  static Node *build_func_call(Oid funcid, Oid rettype, List *args);
  static Oid	find_coercion_function(Oid targetTypeId, Oid inputTypeId,
  								   Oid secondArgType, bool isExplicit);
+ static Node	*TypeConstraints(Node *arg, Oid typeId);
  
  /* coerce_type()
   * Convert a function argument to a different type.
   */
***************
*** 48,54 ****
  		targetTypeId == InvalidOid ||
  		node == NULL)
  	{
! 		/* no conversion needed */
  		result = node;
  	}
  	else if (inputTypeId == UNKNOWNOID && IsA(node, Const))
--- 48,54 ----
  		targetTypeId == InvalidOid ||
  		node == NULL)
  	{
! 		/* no conversion needed, but constraints may need to be applied */
  		result = node;
  	}
  	else if (inputTypeId == UNKNOWNOID && IsA(node, Const))
***************
*** 72,77 ****
--- 72,78 ----
  		Const	   *con = (Const *) node;
  		Const	   *newcon = makeNode(Const);
  		Type		targetType = typeidType(targetTypeId);
+ 		Oid			baseTypeId = getBaseType(targetTypeId);
  
  		newcon->consttype = targetTypeId;
  		newcon->constlen = typeLen(targetType);
***************
*** 83,96 ****
  		{
  			char	   *val = DatumGetCString(DirectFunctionCall1(unknownout,
  													   con->constvalue));
- 
  			newcon->constvalue = stringTypeDatum(targetType, val, atttypmod);
  			pfree(val);
  		}
  
  		ReleaseSysCache(targetType);
  
  		result = (Node *) newcon;
  	}
  	else if (IsBinaryCompatible(inputTypeId, targetTypeId))
  	{
--- 84,99 ----
  		{
  			char	   *val = DatumGetCString(DirectFunctionCall1(unknownout,
  													   con->constvalue));
  			newcon->constvalue = stringTypeDatum(targetType, val, atttypmod);
  			pfree(val);
  		}
  
  		ReleaseSysCache(targetType);
  
+ 		/* Test for domain, and apply appropriate constraints */
  		result = (Node *) newcon;
+ 		if (targetTypeId != baseTypeId)
+ 			result = (Node *) TypeConstraints(result, targetTypeId);
  	}
  	else if (IsBinaryCompatible(inputTypeId, targetTypeId))
  	{
***************
*** 103,110 ****
  		 * default -1 typmod, to save a possible length-coercion later?
  		 * Would work if both types have same interpretation of typmod,
  		 * which is likely but not certain.
  		 */
! 		result = (Node *) makeRelabelType(node, targetTypeId, -1);
  	}
  	else if (typeInheritsFrom(inputTypeId, targetTypeId))
  	{
--- 106,122 ----
  		 * default -1 typmod, to save a possible length-coercion later?
  		 * Would work if both types have same interpretation of typmod,
  		 * which is likely but not certain.
+ 		 *
+ 		 * Domains may have value restrictions beyond the base type that
+ 		 * must be accounted for.
  		 */
! 		Oid			baseTypeId = getBaseType(targetTypeId);
! 		result = node;
! 		if (targetTypeId != baseTypeId)
! 			result = (Node *) TypeConstraints(result, targetTypeId);
! 
! 		result = (Node *) makeRelabelType(result, targetTypeId, -1);
! 
  	}
  	else if (typeInheritsFrom(inputTypeId, targetTypeId))
  	{
***************
*** 125,132 ****
  		 *
  		 * For domains, we use the coercion function for the base type.
  		 */
- 		Oid			baseTypeId = getBaseType(targetTypeId);
  		Oid			funcId;
  
  		funcId = find_coercion_function(baseTypeId,
  										getBaseType(inputTypeId),
--- 137,144 ----
  		 *
  		 * For domains, we use the coercion function for the base type.
  		 */
  		Oid			funcId;
+ 		Oid			baseTypeId = getBaseType(targetTypeId);
  
  		funcId = find_coercion_function(baseTypeId,
  										getBaseType(inputTypeId),
***************
*** 138,146 ****
  
  		result = build_func_call(funcId, baseTypeId, makeList1(node));
  
! 		/* if domain, relabel with domain type ID */
  		if (targetTypeId != baseTypeId)
! 			result = (Node *) makeRelabelType(result, targetTypeId, -1);
  
  		/*
  		 * If the input is a constant, apply the type conversion function
--- 150,161 ----
  
  		result = build_func_call(funcId, baseTypeId, makeList1(node));
  
! 		/*
! 		 * If domain, relabel with domain type ID and test against domain
! 		 * constraints
! 		 */
  		if (targetTypeId != baseTypeId)
! 			result = (Node *) TypeConstraints(result, targetTypeId);
  
  		/*
  		 * If the input is a constant, apply the type conversion function
***************
*** 275,293 ****
  {
  	Oid			baseTypeId;
  	Oid			funcId;
  
  	/*
  	 * A negative typmod is assumed to mean that no coercion is wanted.
  	 */
  	if (atttypmod < 0 || atttypmod == exprTypmod(node))
  		return node;
  
- 	/* If given type is a domain, use base type instead */
- 	baseTypeId = getBaseType(targetTypeId);
- 
  	/* Note this is always implicit coercion */
  	funcId = find_coercion_function(baseTypeId, baseTypeId, INT4OID, false);
- 
  	if (OidIsValid(funcId))
  	{
  		Const	   *cons;
--- 290,319 ----
  {
  	Oid			baseTypeId;
  	Oid			funcId;
+ 	int32		domainTypMod = NULL;
+ 
+ 	/* If given type is a domain, use base type instead */
+ 	baseTypeId = getBaseTypeTypeMod(targetTypeId, &domainTypMod);
  
+ 
  	/*
+ 	 * Use the domain typmod rather than what was supplied if the
+ 	 * domain was empty.  atttypmod will always be -1 if domains are in use.
+ 	 */
+ 	if (baseTypeId != targetTypeId)
+ 	{
+ 		Assert(atttypmod < 0);
+ 		atttypmod = domainTypMod;
+ 	}
+ 
+ 	/*
  	 * A negative typmod is assumed to mean that no coercion is wanted.
  	 */
  	if (atttypmod < 0 || atttypmod == exprTypmod(node))
  		return node;
  
  	/* Note this is always implicit coercion */
  	funcId = find_coercion_function(baseTypeId, baseTypeId, INT4OID, false);
  	if (OidIsValid(funcId))
  	{
  		Const	   *cons;
***************
*** 301,310 ****
  						 false);
  
  		node = build_func_call(funcId, baseTypeId, makeList2(node, cons));
- 
- 		/* relabel if it's domain case */
- 		if (targetTypeId != baseTypeId)
- 			node = (Node *) makeRelabelType(node, targetTypeId, atttypmod);
  	}
  
  	return node;
--- 327,332 ----
***************
*** 804,807 ****
--- 826,884 ----
  	expr->args = args;
  
  	return (Node *) expr;
+ }
+ 
+ /*
+  * Create an expression tree to enforce the constraints (if any)
+  * which should be applied by the type.
+  */
+ static Node *
+ TypeConstraints(Node *arg, Oid typeId)
+ {
+ 	char   *notNull = NULL;
+ 
+ 	for (;;)
+ 	{
+ 		HeapTuple	tup;
+ 		Form_pg_type typTup;
+ 
+ 		tup = SearchSysCache(TYPEOID,
+ 							 ObjectIdGetDatum(typeId),
+ 							 0, 0, 0);
+ 		if (!HeapTupleIsValid(tup))
+ 			elog(ERROR, "getBaseType: failed to lookup type %u", typeId);
+ 		typTup = (Form_pg_type) GETSTRUCT(tup);
+ 
+ 		/* Test for NOT NULL Constraint */
+ 		if (typTup->typnotnull && notNull == NULL)
+ 			notNull = NameStr(typTup->typname);
+ 
+ 		/* TODO: Add CHECK Constraints to domains */
+ 
+ 		if (typTup->typtype != 'd')
+ 		{
+ 			/* Not a domain, so done */
+ 			ReleaseSysCache(tup);
+ 			break;
+ 		}
+ 
+ 		typeId = typTup->typbasetype;
+ 		ReleaseSysCache(tup);
+ 	}
+ 
+ 	/*
+ 	 * Only need to add one NOT NULL check regardless of how many 
+ 	 * domains in the tree request it.
+ 	 */
+ 	if (notNull != NULL) {
+ 		Constraint *r = makeNode(Constraint);
+ 
+ 		r->raw_expr = arg;
+ 		r->contype = CONSTR_NOTNULL;
+ 		r->name	= notNull; 
+ 
+ 		arg = (Node *) r;
+ 	}	
+ 
+ 	return arg;
  }
Index: src/backend/parser/parse_expr.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/parser/parse_expr.c,v
retrieving revision 1.118
diff -c -r1.118 parse_expr.c
*** src/backend/parser/parse_expr.c	2002/05/17 22:35:13	1.118
--- src/backend/parser/parse_expr.c	2002/06/22 04:08:41
***************
*** 853,859 ****
  					TargetEntry *tent;
  
  					if (!qtree || !IsA(qtree, Query))
! 						elog(ERROR, "Cannot get type for untransformed sublink");
  					tent = (TargetEntry *) lfirst(qtree->targetList);
  					type = tent->resdom->restype;
  				}
--- 853,859 ----
  					TargetEntry *tent;
  
  					if (!qtree || !IsA(qtree, Query))
! 						elog(ERROR, "exprType: Cannot get type for untransformed sublink");
  					tent = (TargetEntry *) lfirst(qtree->targetList);
  					type = tent->resdom->restype;
  				}
***************
*** 870,875 ****
--- 870,878 ----
  		case T_CaseWhen:
  			type = exprType(((CaseWhen *) expr)->result);
  			break;
+ 		case T_Constraint:
+ 			type = exprType(((Constraint *) expr)->raw_expr);
+ 			break;
  		case T_NullTest:
  			type = BOOLOID;
  			break;
***************
*** 877,883 ****
  			type = BOOLOID;
  			break;
  		default:
! 			elog(ERROR, "Do not know how to get type for %d node",
  				 nodeTag(expr));
  			break;
  	}
--- 880,886 ----
  			type = BOOLOID;
  			break;
  		default:
! 			elog(ERROR, "exprType: Do not know how to get type for %d node",
  				 nodeTag(expr));
  			break;
  	}
Index: src/backend/parser/parse_type.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/parser/parse_type.c,v
retrieving revision 1.42
diff -c -r1.42 parse_type.c
*** src/backend/parser/parse_type.c	2002/05/17 22:35:13	1.42
--- src/backend/parser/parse_type.c	2002/06/22 04:08:42
***************
*** 450,456 ****
  	List	   *raw_parsetree_list;
  	SelectStmt *stmt;
  	ResTarget  *restarget;
! 	A_Const    *aconst;
  	TypeName   *typename;
  
  	initStringInfo(&buf);
--- 450,456 ----
  	List	   *raw_parsetree_list;
  	SelectStmt *stmt;
  	ResTarget  *restarget;
! 	TypeCast   *typecast;   
  	TypeName   *typename;
  
  	initStringInfo(&buf);
***************
*** 463,469 ****
  	 * paranoia is justified since the string might contain anything.
  	 */
  	if (length(raw_parsetree_list) != 1)
! 		elog(ERROR, "Invalid type name '%s'", str);
  	stmt = (SelectStmt *) lfirst(raw_parsetree_list);
  	if (stmt == NULL ||
  		!IsA(stmt, SelectStmt) ||
--- 463,469 ----
  	 * paranoia is justified since the string might contain anything.
  	 */
  	if (length(raw_parsetree_list) != 1)
! 		elog(ERROR, "parseTypeString: Invalid type name '%s'", str);
  	stmt = (SelectStmt *) lfirst(raw_parsetree_list);
  	if (stmt == NULL ||
  		!IsA(stmt, SelectStmt) ||
***************
*** 479,503 ****
  		stmt->limitCount != NULL ||
  		stmt->forUpdate != NIL ||
  		stmt->op != SETOP_NONE)
! 		elog(ERROR, "Invalid type name '%s'", str);
  	if (length(stmt->targetList) != 1)
! 		elog(ERROR, "Invalid type name '%s'", str);
  	restarget = (ResTarget *) lfirst(stmt->targetList);
  	if (restarget == NULL ||
  		!IsA(restarget, ResTarget) ||
  		restarget->name != NULL ||
  		restarget->indirection != NIL)
! 		elog(ERROR, "Invalid type name '%s'", str);
! 	aconst = (A_Const *) restarget->val;
! 	if (aconst == NULL ||
! 		!IsA(aconst, A_Const) ||
! 		aconst->val.type != T_Null)
! 		elog(ERROR, "Invalid type name '%s'", str);
! 	typename = aconst->typename;
  	if (typename == NULL ||
  		!IsA(typename, TypeName))
! 		elog(ERROR, "Invalid type name '%s'", str);
! 
  	*type_id = typenameTypeId(typename);
  	*typmod = typename->typmod;
  
--- 479,501 ----
  		stmt->limitCount != NULL ||
  		stmt->forUpdate != NIL ||
  		stmt->op != SETOP_NONE)
! 		elog(ERROR, "parseTypeString: Invalid type name '%s'", str);
  	if (length(stmt->targetList) != 1)
! 		elog(ERROR, "parseTypeString: Invalid type name '%s'", str);
  	restarget = (ResTarget *) lfirst(stmt->targetList);
  	if (restarget == NULL ||
  		!IsA(restarget, ResTarget) ||
  		restarget->name != NULL ||
  		restarget->indirection != NIL)
! 		elog(ERROR, "parseTypeString: Invalid type name '%s'", str);
! 	typecast = (TypeCast *) restarget->val;
! 	if (typecast == NULL ||
! 		!IsA(typecast->arg, A_Const))
! 		elog(ERROR, "parseTypeString: Invalid type name '%s'", str);
! 	typename = typecast->typename;
  	if (typename == NULL ||
  		!IsA(typename, TypeName))
! 		elog(ERROR, "parseTypeString: Invalid type name '%s'", str);
  	*type_id = typenameTypeId(typename);
  	*typmod = typename->typmod;
  
Index: src/backend/utils/cache/lsyscache.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v
retrieving revision 1.73
diff -c -r1.73 lsyscache.c
*** src/backend/utils/cache/lsyscache.c	2002/05/12 23:43:03	1.73
--- src/backend/utils/cache/lsyscache.c	2002/06/22 04:08:42
***************
*** 1058,1063 ****
--- 1058,1100 ----
  }
  
  /*
+  * getBaseTypeTypeMod
+  *		If the given type is a domain, return its base type;
+  *		otherwise return the type's own OID.
+  */
+ Oid
+ getBaseTypeTypeMod(Oid typid, int32 *typmod)
+ {
+ 	/*
+ 	 * We loop to find the bottom base type in a stack of domains.
+ 	 */
+ 	for (;;)
+ 	{
+ 		HeapTuple	tup;
+ 		Form_pg_type typTup;
+ 
+ 		tup = SearchSysCache(TYPEOID,
+ 							 ObjectIdGetDatum(typid),
+ 							 0, 0, 0);
+ 		if (!HeapTupleIsValid(tup))
+ 			elog(ERROR, "getBaseType: failed to lookup type %u", typid);
+ 		typTup = (Form_pg_type) GETSTRUCT(tup);
+ 		if (typTup->typtype != 'd')
+ 		{
+ 			/* Not a domain, so done */
+ 			ReleaseSysCache(tup);
+ 			break;
+ 		}
+ 
+ 		typid = typTup->typbasetype;
+ 		*typmod = typTup->typtypmod;
+ 		ReleaseSysCache(tup);
+ 	}
+ 
+ 	return typid;
+ }
+ 
+ /*
   * get_typavgwidth
   *
   *	  Given a type OID and a typmod value (pass -1 if typmod is unknown),
Index: src/include/utils/lsyscache.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/utils/lsyscache.h,v
retrieving revision 1.52
diff -c -r1.52 lsyscache.h
*** src/include/utils/lsyscache.h	2002/05/12 23:43:04	1.52
--- src/include/utils/lsyscache.h	2002/06/22 04:08:48
***************
*** 52,57 ****
--- 52,58 ----
  extern char get_typstorage(Oid typid);
  extern Node *get_typdefault(Oid typid);
  extern Oid getBaseType(Oid typid);
+ extern Oid getBaseTypeTypeMod(Oid typid, int32 *typmod);
  extern int32 get_typavgwidth(Oid typid, int32 typmod);
  extern int32 get_attavgwidth(Oid relid, AttrNumber attnum);
  extern bool get_attstatsslot(HeapTuple statstuple,
Index: src/test/regress/expected/domain.out
===================================================================
RCS file: /projects/cvsroot/pgsql/src/test/regress/expected/domain.out,v
retrieving revision 1.2
diff -c -r1.2 domain.out
*** src/test/regress/expected/domain.out	2002/03/20 19:45:12	1.2
--- src/test/regress/expected/domain.out	2002/06/22 04:08:50
***************
*** 11,16 ****
--- 11,25 ----
  create domain domainnumeric numeric(8,2);
  create domain domainint4 int4;
  create domain domaintext text;
+ -- Test coercions
+ SELECT cast('123456' as domainvarchar); -- fail
+ ERROR:  value too long for type character varying(5)
+ SELECT cast('12345' as domainvarchar); -- pass
+  domainvarchar 
+ ---------------
+  12345
+ (1 row)
+ 
  -- Test tables using domains
  create table basictest
             ( testint4 domainint4
***************
*** 80,86 ****
  drop domain domainint4arr restrict;
  drop domain domaintextarr restrict;
  create domain dnotnull varchar(15) NOT NULL;
! create domain dnull    varchar(15) NULL;
  create table nulltest
             ( col1 dnotnull
             , col2 dnotnull NULL  -- NOT NULL in the domain cannot be overridden
--- 89,95 ----
  drop domain domainint4arr restrict;
  drop domain domaintextarr restrict;
  create domain dnotnull varchar(15) NOT NULL;
! create domain dnull    varchar(15);
  create table nulltest
             ( col1 dnotnull
             , col2 dnotnull NULL  -- NOT NULL in the domain cannot be overridden
***************
*** 88,99 ****
             , col4 dnull
             );
  INSERT INTO nulltest DEFAULT VALUES;
! ERROR:  ExecAppend: Fail to add null value in not null attribute col1
  INSERT INTO nulltest values ('a', 'b', 'c', 'd');  -- Good
  INSERT INTO nulltest values (NULL, 'b', 'c', 'd');
! ERROR:  ExecAppend: Fail to add null value in not null attribute col1
  INSERT INTO nulltest values ('a', NULL, 'c', 'd');
! ERROR:  ExecAppend: Fail to add null value in not null attribute col2
  INSERT INTO nulltest values ('a', 'b', NULL, 'd');
  ERROR:  ExecAppend: Fail to add null value in not null attribute col3
  INSERT INTO nulltest values ('a', 'b', 'c', NULL); -- Good
--- 97,108 ----
             , col4 dnull
             );
  INSERT INTO nulltest DEFAULT VALUES;
! ERROR:  ExecAppend: Fail to add null value in not null attribute col3
  INSERT INTO nulltest values ('a', 'b', 'c', 'd');  -- Good
  INSERT INTO nulltest values (NULL, 'b', 'c', 'd');
! ERROR:  Domain dnotnull does not allow NULL values
  INSERT INTO nulltest values ('a', NULL, 'c', 'd');
! ERROR:  Domain dnotnull does not allow NULL values
  INSERT INTO nulltest values ('a', 'b', NULL, 'd');
  ERROR:  ExecAppend: Fail to add null value in not null attribute col3
  INSERT INTO nulltest values ('a', 'b', 'c', NULL); -- Good
***************
*** 104,109 ****
--- 113,132 ----
   a    | b    | c    | 
  (2 rows)
  
+ -- Test out coerced (casted) constraints
+ SELECT cast('1' as dnotnull);
+  dnotnull 
+ ----------
+  1
+ (1 row)
+ 
+ SELECT cast(NULL as dnotnull); -- fail
+ ERROR:  Domain dnotnull does not allow NULL values
+ SELECT cast(cast(NULL as dnull) as dnotnull); -- fail
+ ERROR:  Domain dnotnull does not allow NULL values
+ SELECT cast(col4 as dnotnull) from nulltest; -- fail
+ ERROR:  Domain dnotnull does not allow NULL values
+ -- cleanup
  drop table nulltest;
  drop domain dnotnull restrict;
  drop domain dnull restrict;
Index: src/test/regress/sql/domain.sql
===================================================================
RCS file: /projects/cvsroot/pgsql/src/test/regress/sql/domain.sql,v
retrieving revision 1.2
diff -c -r1.2 domain.sql
*** src/test/regress/sql/domain.sql	2002/03/20 19:45:13	1.2
--- src/test/regress/sql/domain.sql	2002/06/22 04:08:50
***************
*** 17,22 ****
--- 17,25 ----
  create domain domainint4 int4;
  create domain domaintext text;
  
+ -- Test coercions
+ SELECT cast('123456' as domainvarchar); -- fail
+ SELECT cast('12345' as domainvarchar); -- pass
  
  -- Test tables using domains
  create table basictest
***************
*** 65,71 ****
  
  
  create domain dnotnull varchar(15) NOT NULL;
! create domain dnull    varchar(15) NULL;
  
  create table nulltest
             ( col1 dnotnull
--- 68,74 ----
  
  
  create domain dnotnull varchar(15) NOT NULL;
! create domain dnull    varchar(15);
  
  create table nulltest
             ( col1 dnotnull
***************
*** 81,86 ****
--- 84,96 ----
  INSERT INTO nulltest values ('a', 'b', 'c', NULL); -- Good
  select * from nulltest;
  
+ -- Test out coerced (casted) constraints
+ SELECT cast('1' as dnotnull);
+ SELECT cast(NULL as dnotnull); -- fail
+ SELECT cast(cast(NULL as dnull) as dnotnull); -- fail
+ SELECT cast(col4 as dnotnull) from nulltest; -- fail
+ 
+ -- cleanup
  drop table nulltest;
  drop domain dnotnull restrict;
  drop domain dnull restrict;
