aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/commands/tablecmds.c53
-rw-r--r--src/backend/executor/execQual.c47
-rw-r--r--src/backend/optimizer/util/clauses.c18
-rw-r--r--src/backend/parser/gram.y28
-rw-r--r--src/backend/parser/parse_coerce.c109
-rw-r--r--src/backend/parser/parse_expr.c9
-rw-r--r--src/backend/parser/parse_type.c26
-rw-r--r--src/backend/utils/cache/lsyscache.c39
-rw-r--r--src/include/utils/lsyscache.h3
-rw-r--r--src/test/regress/expected/domain.out31
-rw-r--r--src/test/regress/sql/domain.sql12
11 files changed, 263 insertions, 112 deletions
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index b92bf4bba16..901090c70ac 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.18 2002/07/01 15:27:46 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.19 2002/07/06 20:16:35 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -48,7 +48,6 @@
#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);
@@ -123,13 +122,6 @@ DefineRelation(CreateStmt *stmt, char relkind)
}
/*
- * 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.
*/
@@ -328,49 +320,6 @@ TruncateRelation(const RangeVar *relation)
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;
-}
-
/*----------
* MergeAttributes
* Returns new schema given initial schema and superclasses.
diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c
index 789251b70e7..6bb2b5fa942 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.96 2002/07/04 16:44:08 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.97 2002/07/06 20:16:35 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -66,6 +66,8 @@ static Datum ExecEvalNullTest(NullTest *ntest, ExprContext *econtext,
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);
/*----------
@@ -1226,6 +1228,43 @@ ExecEvalNullTest(NullTest *ntest,
}
}
+/*
+ * 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
*
@@ -1473,6 +1512,12 @@ ExecEvalExpr(Node *expression,
isNull,
isDone);
break;
+ case T_Constraint:
+ retDatum = ExecEvalConstraint((Constraint *) expression,
+ econtext,
+ isNull,
+ isDone);
+ break;
case T_CaseExpr:
retDatum = ExecEvalCase((CaseExpr *) expression,
econtext,
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 5b0ae52f7c6..889a10b9ee3 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.102 2002/07/04 15:23:58 thomas Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.103 2002/07/06 20:16:35 momjian Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -1882,6 +1882,8 @@ expression_tree_walker(Node *node,
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:
@@ -2236,6 +2238,20 @@ expression_tree_mutator(Node *node,
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;
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 410caf72e0a..e8e5aeabc77 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.336 2002/07/04 15:23:59 thomas Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.337 2002/07/06 20:16:35 momjian Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -6968,24 +6968,16 @@ static Node *
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.
+ * 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.
*/
- 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;
- }
+ TypeCast *n = makeNode(TypeCast);
+ n->arg = arg;
+ n->typename = typename;
+ return (Node *) n;
}
static Node *
diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c
index 3c441509b1d..b258368626a 100644
--- a/src/backend/parser/parse_coerce.c
+++ b/src/backend/parser/parse_coerce.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.74 2002/06/20 20:29:32 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.75 2002/07/06 20:16:36 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -33,7 +33,7 @@ static Oid PreferredType(CATEGORY category, Oid type);
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,7 +48,7 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
targetTypeId == InvalidOid ||
node == NULL)
{
- /* no conversion needed */
+ /* no conversion needed, but constraints may need to be applied */
result = node;
}
else if (inputTypeId == UNKNOWNOID && IsA(node, Const))
@@ -72,6 +72,7 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
Const *con = (Const *) node;
Const *newcon = makeNode(Const);
Type targetType = typeidType(targetTypeId);
+ Oid baseTypeId = getBaseType(targetTypeId);
newcon->consttype = targetTypeId;
newcon->constlen = typeLen(targetType);
@@ -83,14 +84,16 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
{
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,8 +106,17 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
* 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.
*/
- result = (Node *) makeRelabelType(node, targetTypeId, -1);
+ 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,8 +137,8 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
*
* For domains, we use the coercion function for the base type.
*/
- Oid baseTypeId = getBaseType(targetTypeId);
Oid funcId;
+ Oid baseTypeId = getBaseType(targetTypeId);
funcId = find_coercion_function(baseTypeId,
getBaseType(inputTypeId),
@@ -138,9 +150,12 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
result = build_func_call(funcId, baseTypeId, makeList1(node));
- /* if domain, relabel with domain type ID */
+ /*
+ * If domain, relabel with domain type ID and test against domain
+ * constraints
+ */
if (targetTypeId != baseTypeId)
- result = (Node *) makeRelabelType(result, targetTypeId, -1);
+ result = (Node *) TypeConstraints(result, targetTypeId);
/*
* If the input is a constant, apply the type conversion function
@@ -275,6 +290,21 @@ coerce_type_typmod(ParseState *pstate, Node *node,
{
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.
@@ -282,12 +312,8 @@ coerce_type_typmod(ParseState *pstate, Node *node,
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;
@@ -301,10 +327,6 @@ coerce_type_typmod(ParseState *pstate, Node *node,
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;
@@ -805,3 +827,58 @@ build_func_call(Oid funcid, Oid rettype, List *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;
+}
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index ac4a5b6e5f3..d93aeb55b5d 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.120 2002/07/04 15:24:01 thomas Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.121 2002/07/06 20:16:36 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -864,7 +864,7 @@ exprType(Node *expr)
TargetEntry *tent;
if (!qtree || !IsA(qtree, Query))
- elog(ERROR, "Cannot get type for untransformed sublink");
+ elog(ERROR, "exprType: Cannot get type for untransformed sublink");
tent = (TargetEntry *) lfirst(qtree->targetList);
type = tent->resdom->restype;
}
@@ -881,6 +881,9 @@ exprType(Node *expr)
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;
@@ -888,7 +891,7 @@ exprType(Node *expr)
type = BOOLOID;
break;
default:
- elog(ERROR, "Do not know how to get type for %d node",
+ elog(ERROR, "exprType: Do not know how to get type for %d node",
nodeTag(expr));
break;
}
diff --git a/src/backend/parser/parse_type.c b/src/backend/parser/parse_type.c
index 04cefb29904..14510a69b1b 100644
--- a/src/backend/parser/parse_type.c
+++ b/src/backend/parser/parse_type.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_type.c,v 1.43 2002/06/20 20:29:33 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_type.c,v 1.44 2002/07/06 20:16:36 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -450,7 +450,7 @@ parseTypeString(const char *str, Oid *type_id, int32 *typmod)
List *raw_parsetree_list;
SelectStmt *stmt;
ResTarget *restarget;
- A_Const *aconst;
+ TypeCast *typecast;
TypeName *typename;
initStringInfo(&buf);
@@ -463,7 +463,7 @@ parseTypeString(const char *str, Oid *type_id, int32 *typmod)
* paranoia is justified since the string might contain anything.
*/
if (length(raw_parsetree_list) != 1)
- elog(ERROR, "Invalid type name '%s'", str);
+ elog(ERROR, "parseTypeString: Invalid type name '%s'", str);
stmt = (SelectStmt *) lfirst(raw_parsetree_list);
if (stmt == NULL ||
!IsA(stmt, SelectStmt) ||
@@ -479,25 +479,23 @@ parseTypeString(const char *str, Oid *type_id, int32 *typmod)
stmt->limitCount != NULL ||
stmt->forUpdate != NIL ||
stmt->op != SETOP_NONE)
- elog(ERROR, "Invalid type name '%s'", str);
+ elog(ERROR, "parseTypeString: Invalid type name '%s'", str);
if (length(stmt->targetList) != 1)
- elog(ERROR, "Invalid type name '%s'", str);
+ 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, "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;
+ 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, "Invalid type name '%s'", str);
-
+ elog(ERROR, "parseTypeString: Invalid type name '%s'", str);
*type_id = typenameTypeId(typename);
*typmod = typename->typmod;
diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c
index 233910a85c3..5063225afce 100644
--- a/src/backend/utils/cache/lsyscache.c
+++ b/src/backend/utils/cache/lsyscache.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.74 2002/06/20 20:29:39 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.75 2002/07/06 20:16:36 momjian Exp $
*
* NOTES
* Eventually, the index information should go through here, too.
@@ -1058,6 +1058,43 @@ getBaseType(Oid typid)
}
/*
+ * 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),
diff --git a/src/include/utils/lsyscache.h b/src/include/utils/lsyscache.h
index 32d5dc1744e..ca361ebc2cc 100644
--- a/src/include/utils/lsyscache.h
+++ b/src/include/utils/lsyscache.h
@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: lsyscache.h,v 1.53 2002/06/20 20:29:53 momjian Exp $
+ * $Id: lsyscache.h,v 1.54 2002/07/06 20:16:36 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -52,6 +52,7 @@ extern void get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval);
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,
diff --git a/src/test/regress/expected/domain.out b/src/test/regress/expected/domain.out
index 7127215869a..078d2386bf9 100644
--- a/src/test/regress/expected/domain.out
+++ b/src/test/regress/expected/domain.out
@@ -11,6 +11,15 @@ create domain domainvarchar varchar(5);
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,7 +89,7 @@ drop table domarrtest;
drop domain domainint4arr restrict;
drop domain domaintextarr restrict;
create domain dnotnull varchar(15) NOT NULL;
-create domain dnull varchar(15) NULL;
+create domain dnull varchar(15);
create table nulltest
( col1 dnotnull
, col2 dnotnull NULL -- NOT NULL in the domain cannot be overridden
@@ -88,12 +97,12 @@ create table nulltest
, col4 dnull
);
INSERT INTO nulltest DEFAULT VALUES;
-ERROR: ExecAppend: Fail to add null value in not null attribute col1
+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: ExecAppend: Fail to add null value in not null attribute col1
+ERROR: Domain dnotnull does not allow NULL values
INSERT INTO nulltest values ('a', NULL, 'c', 'd');
-ERROR: ExecAppend: Fail to add null value in not null attribute col2
+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,6 +113,20 @@ select * from nulltest;
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;
diff --git a/src/test/regress/sql/domain.sql b/src/test/regress/sql/domain.sql
index cecb876c386..055c377decb 100644
--- a/src/test/regress/sql/domain.sql
+++ b/src/test/regress/sql/domain.sql
@@ -17,6 +17,9 @@ create domain domainnumeric numeric(8,2);
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,7 +68,7 @@ drop domain domaintextarr restrict;
create domain dnotnull varchar(15) NOT NULL;
-create domain dnull varchar(15) NULL;
+create domain dnull varchar(15);
create table nulltest
( col1 dnotnull
@@ -81,6 +84,13 @@ INSERT INTO nulltest values ('a', 'b', NULL, 'd');
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;