diff --git a/doc/src/sgml/typeconv.sgml b/doc/src/sgml/typeconv.sgml
index c5373aa753330cdc379784a7117ea0f637ac1d7c..7cf3efdb1ae4018fd87cb7cdca078a06445ce111 100644
--- a/doc/src/sgml/typeconv.sgml
+++ b/doc/src/sgml/typeconv.sgml
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/typeconv.sgml,v 1.52 2007/06/05 21:31:04 tgl Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/typeconv.sgml,v 1.53 2007/11/26 16:46:50 tgl Exp $ -->
 
 <chapter Id="typeconv">
 <title>Type Conversion</title>
@@ -843,11 +843,19 @@ data type.
 <title>Type Resolution for <literal>UNION</literal>, <literal>CASE</literal>,
 and Related Constructs</title>
 
+<step performance="required">
+<para>
+If all inputs are of the same type, and it is not <type>unknown</type>,
+resolve as that type.  Otherwise, replace any domain types in the list with
+their underlying base types.
+</para>
+</step>
+
 <step performance="required">
 <para>
 If all inputs are of type <type>unknown</type>, resolve as type
 <type>text</type> (the preferred type of the string category).
-Otherwise, ignore the <type>unknown</type> inputs while choosing the result type.
+Otherwise, the <type>unknown</type> inputs will be ignored.
 </para>
 </step>
 
@@ -860,14 +868,23 @@ If the non-unknown inputs are not all of the same type category, fail.
 <step performance="required">
 <para>
 Choose the first non-unknown input type which is a preferred type in
-that category or allows all the non-unknown inputs to be implicitly
-converted to it.
+that category, if there is one.
+</para>
+</step>
+
+<step performance="required">
+<para>
+Otherwise, choose the last non-unknown input type that allows all the
+preceding non-unknown inputs to be implicitly converted to it.  (There
+always is such a type, since at least the first type in the list must
+satisfy this condition.)
 </para>
 </step>
 
 <step performance="required">
 <para>
-Convert all inputs to the selected type.
+Convert all inputs to the selected type.  Fail if there is not a
+conversion from a given input to the selected type.
 </para>
 </step>
 </procedure>
diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c
index 98b9aba238f133690bf269fba7cff0c0266267fc..aeda66fc26db8c6c8defbcf796f3d0b9d5873e77 100644
--- a/src/backend/parser/parse_coerce.c
+++ b/src/backend/parser/parse_coerce.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.158 2007/11/15 21:14:37 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.159 2007/11/26 16:46:50 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -958,7 +958,7 @@ coerce_to_specific_type(ParseState *pstate, Node *node,
  *		This is used for determining the output type of CASE and UNION
  *		constructs.
  *
- * typeids is a nonempty list of type OIDs.  Note that earlier items
+ * 'typeids' is a nonempty list of type OIDs.  Note that earlier items
  * in the list will be preferred if there is doubt.
  * 'context' is a phrase to use in the error message if we fail to select
  * a usable type.
@@ -971,7 +971,28 @@ select_common_type(List *typeids, const char *context)
 	ListCell   *type_item;
 
 	Assert(typeids != NIL);
-	ptype = getBaseType(linitial_oid(typeids));
+	ptype = linitial_oid(typeids);
+
+	/*
+	 * If all input types are valid and exactly the same, just pick that type.
+	 * This is the only way that we will resolve the result as being a domain
+	 * type; otherwise domains are smashed to their base types for comparison.
+	 */
+	if (ptype != UNKNOWNOID)
+	{
+		for_each_cell(type_item, lnext(list_head(typeids)))
+		{
+			Oid		ntype = lfirst_oid(type_item);
+
+			if (ntype != ptype)
+				break;
+		}
+		if (type_item == NULL)			/* got to the end of the list? */
+			return ptype;
+	}
+
+	/* Nope, so set up for the full algorithm */
+	ptype = getBaseType(ptype);
 	pcategory = TypeCategory(ptype);
 
 	for_each_cell(type_item, lnext(list_head(typeids)))
@@ -979,11 +1000,11 @@ select_common_type(List *typeids, const char *context)
 		Oid			ntype = getBaseType(lfirst_oid(type_item));
 
 		/* move on to next one if no new information... */
-		if ((ntype != InvalidOid) && (ntype != UNKNOWNOID) && (ntype != ptype))
+		if (ntype != UNKNOWNOID && ntype != ptype)
 		{
-			if ((ptype == InvalidOid) || ptype == UNKNOWNOID)
+			if (ptype == UNKNOWNOID)
 			{
-				/* so far, only nulls so take anything... */
+				/* so far, only unknowns so take anything... */
 				ptype = ntype;
 				pcategory = TypeCategory(ptype);
 			}
diff --git a/src/test/regress/expected/domain.out b/src/test/regress/expected/domain.out
index b951ce8caa8752e36a0e52a38437ad590267aaa1..a80eae7d590ba69e8b07d4d61b931f23143f13bc 100644
--- a/src/test/regress/expected/domain.out
+++ b/src/test/regress/expected/domain.out
@@ -69,6 +69,25 @@ from basictest;
            |       
 (3 rows)
 
+-- check that union/case/coalesce type resolution handles domains properly
+select coalesce(4::domainint4, 7) is of (int4) as t;
+ t 
+---
+ t
+(1 row)
+
+select coalesce(4::domainint4, 7) is of (domainint4) as f;
+ f 
+---
+ f
+(1 row)
+
+select coalesce(4::domainint4, 7::domainint4) is of (domainint4) as t;
+ t 
+---
+ t
+(1 row)
+
 drop table basictest;
 drop domain domainvarchar restrict;
 drop domain domainnumeric restrict;
diff --git a/src/test/regress/sql/domain.sql b/src/test/regress/sql/domain.sql
index 7a4ec383d20cac750f67d0dc54c3eb22cb7ae782..1e5295899b22347da3217a389378255fe0438cef 100644
--- a/src/test/regress/sql/domain.sql
+++ b/src/test/regress/sql/domain.sql
@@ -58,6 +58,11 @@ select * from basictest;
 select testtext || testvarchar as concat, testnumeric + 42 as sum
 from basictest;
 
+-- check that union/case/coalesce type resolution handles domains properly
+select coalesce(4::domainint4, 7) is of (int4) as t;
+select coalesce(4::domainint4, 7) is of (domainint4) as f;
+select coalesce(4::domainint4, 7::domainint4) is of (domainint4) as t;
+
 drop table basictest;
 drop domain domainvarchar restrict;
 drop domain domainnumeric restrict;