Commit 07daff63 authored by Tom Lane's avatar Tom Lane

Fix select_common_type() so that it can select a domain type, if all inputs

to a UNION, CASE, or related construct are of the same domain type.  The
main part of this routine smashes domains to their base types, which seems
necessary because the logic involves TypeCategory() and IsPreferredType(),
neither of which work usefully on domains.  However, we can add a first
pass that just detects whether all the inputs are exactly the same type,
and if so accept that without question (so long as it's not UNKNOWN).
Per recent gripe from Dean Rasheed.

In passing, remove some tests for InvalidOid, which have clearly been dead
code for quite some time now, because getBaseType() would fail on that input.

Also, clarify the manual's not-very-precise description of the existing
algorithm's behavior.
parent 3f398e4a
<!-- $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"> <chapter Id="typeconv">
<title>Type Conversion</title> <title>Type Conversion</title>
...@@ -843,11 +843,19 @@ data type. ...@@ -843,11 +843,19 @@ data type.
<title>Type Resolution for <literal>UNION</literal>, <literal>CASE</literal>, <title>Type Resolution for <literal>UNION</literal>, <literal>CASE</literal>,
and Related Constructs</title> 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"> <step performance="required">
<para> <para>
If all inputs are of type <type>unknown</type>, resolve as type If all inputs are of type <type>unknown</type>, resolve as type
<type>text</type> (the preferred type of the string category). <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> </para>
</step> </step>
...@@ -860,14 +868,23 @@ If the non-unknown inputs are not all of the same type category, fail. ...@@ -860,14 +868,23 @@ If the non-unknown inputs are not all of the same type category, fail.
<step performance="required"> <step performance="required">
<para> <para>
Choose the first non-unknown input type which is a preferred type in 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 that category, if there is one.
converted to it. </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> </para>
</step> </step>
<step performance="required"> <step performance="required">
<para> <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> </para>
</step> </step>
</procedure> </procedure>
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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, ...@@ -958,7 +958,7 @@ coerce_to_specific_type(ParseState *pstate, Node *node,
* This is used for determining the output type of CASE and UNION * This is used for determining the output type of CASE and UNION
* constructs. * 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. * 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 * 'context' is a phrase to use in the error message if we fail to select
* a usable type. * a usable type.
...@@ -971,7 +971,28 @@ select_common_type(List *typeids, const char *context) ...@@ -971,7 +971,28 @@ select_common_type(List *typeids, const char *context)
ListCell *type_item; ListCell *type_item;
Assert(typeids != NIL); 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); pcategory = TypeCategory(ptype);
for_each_cell(type_item, lnext(list_head(typeids))) for_each_cell(type_item, lnext(list_head(typeids)))
...@@ -979,11 +1000,11 @@ select_common_type(List *typeids, const char *context) ...@@ -979,11 +1000,11 @@ select_common_type(List *typeids, const char *context)
Oid ntype = getBaseType(lfirst_oid(type_item)); Oid ntype = getBaseType(lfirst_oid(type_item));
/* move on to next one if no new information... */ /* 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; ptype = ntype;
pcategory = TypeCategory(ptype); pcategory = TypeCategory(ptype);
} }
......
...@@ -69,6 +69,25 @@ from basictest; ...@@ -69,6 +69,25 @@ from basictest;
| |
(3 rows) (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 table basictest;
drop domain domainvarchar restrict; drop domain domainvarchar restrict;
drop domain domainnumeric restrict; drop domain domainnumeric restrict;
......
...@@ -58,6 +58,11 @@ select * from basictest; ...@@ -58,6 +58,11 @@ select * from basictest;
select testtext || testvarchar as concat, testnumeric + 42 as sum select testtext || testvarchar as concat, testnumeric + 42 as sum
from basictest; 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 table basictest;
drop domain domainvarchar restrict; drop domain domainvarchar restrict;
drop domain domainnumeric restrict; drop domain domainnumeric restrict;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment