-<!-- $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>
<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>
<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>
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
* 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.
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)))
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);
}
|
(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;
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;