So I was informed today that UNION types integer and text cannot be
matched. Alright, but it failed to tell which particular expressions
in this 3-branch, 30-columns-each UNION clause in a 100-line statement
it was talking about. So I made the attached patch to give some better
pointers. Example:
peter=# values(0,1), (1::bigint,2), ('text'::text,3);
ERROR: 42804: VALUES types bigint at position 2 and text at position 3
cannot be matched in instance 1
I'm not sure about the terminology "position" and "instance"; they're
just two coordinates to get at the problem.
None of this will help if you have multiple unrelated clauses that
invoke select_common_type(), but that might be better handled using the
parser location mechanism.
Comments?
--
Peter Eisentraut
http://developer.postgresql.org/~petere/
diff -ur ../cvs-pgsql/src/backend/parser/analyze.c ./src/backend/parser/analyze.c
--- ../cvs-pgsql/src/backend/parser/analyze.c 2007-03-13 10:59:04.000000000 +0100
+++ ./src/backend/parser/analyze.c 2007-04-23 21:23:23.000000000 +0200
@@ -2195,7 +2195,7 @@
*/
for (i = 0; i < sublist_length; i++)
{
- coltypes[i] = select_common_type(coltype_lists[i], "VALUES");
+ coltypes[i] = select_common_type(coltype_lists[i], "VALUES", sublist_length > 1 ? i + 1 : 0);
}
newExprsLists = NIL;
@@ -2632,6 +2632,7 @@
ListCell *lcm;
ListCell *rcm;
const char *context;
+ int count;
context = (stmt->op == SETOP_UNION ? "UNION" :
(stmt->op == SETOP_INTERSECT ? "INTERSECT" :
@@ -2665,6 +2666,7 @@
/* don't have a "foreach4", so chase two of the lists by hand */
lcm = list_head(lcoltypmods);
rcm = list_head(rcoltypmods);
+ count = 0;
forboth(lct, lcoltypes, rct, rcoltypes)
{
Oid lcoltype = lfirst_oid(lct);
@@ -2674,9 +2676,12 @@
Oid rescoltype;
int32 rescoltypmod;
+ count++;
+
/* select common type, same as CASE et al */
rescoltype = select_common_type(list_make2_oid(lcoltype, rcoltype),
- context);
+ context,
+ list_length(lcoltypes) > 1 ? count : 0);
/* if same type and same typmod, use typmod; else default */
if (lcoltype == rcoltype && lcoltypmod == rcoltypmod)
rescoltypmod = lcoltypmod;
diff -ur ../cvs-pgsql/src/backend/parser/parse_clause.c ./src/backend/parser/parse_clause.c
--- ../cvs-pgsql/src/backend/parser/parse_clause.c 2007-02-03 14:08:51.000000000 +0100
+++ ./src/backend/parser/parse_clause.c 2007-04-23 21:13:14.000000000 +0200
@@ -965,7 +965,7 @@
{
outcoltype = select_common_type(list_make2_oid(l_colvar->vartype,
r_colvar->vartype),
- "JOIN/USING");
+ "JOIN/USING", 0);
outcoltypmod = -1; /* ie, unknown */
}
else if (outcoltypmod != r_colvar->vartypmod)
diff -ur ../cvs-pgsql/src/backend/parser/parse_coerce.c ./src/backend/parser/parse_coerce.c
--- ../cvs-pgsql/src/backend/parser/parse_coerce.c 2007-04-03 22:26:05.000000000 +0200
+++ ./src/backend/parser/parse_coerce.c 2007-04-23 21:52:52.000000000 +0200
@@ -932,23 +932,31 @@
* 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.
+ * a usable type. 'instance_no' is to decorate the error message in case
+ * there are multiple invocations of this function for a clause.
*/
Oid
-select_common_type(List *typeids, const char *context)
+select_common_type(List *typeids, const char *context, int instance_no)
{
Oid ptype;
CATEGORY pcategory;
ListCell *type_item;
+ int ptype_pos;
+ int ntype_pos;
Assert(typeids != NIL);
ptype = getBaseType(linitial_oid(typeids));
+ ptype_pos = 1;
pcategory = TypeCategory(ptype);
+ ntype_pos = 1;
+
for_each_cell(type_item, lnext(list_head(typeids)))
{
Oid ntype = getBaseType(lfirst_oid(type_item));
+ ntype_pos++;
+
/* move on to next one if no new information... */
if ((ntype != InvalidOid) && (ntype != UNKNOWNOID) && (ntype != ptype))
{
@@ -956,6 +964,7 @@
{
/* so far, only nulls so take anything... */
ptype = ntype;
+ ptype_pos = ntype_pos;
pcategory = TypeCategory(ptype);
}
else if (TypeCategory(ntype) != pcategory)
@@ -968,10 +977,20 @@
/*------
translator: first %s is name of a SQL construct, eg CASE */
- errmsg("%s types %s and %s cannot be matched",
- context,
- format_type_be(ptype),
- format_type_be(ntype))));
+ (instance_no > 0
+ ? errmsg("%s types %s at position %d and %s at position %d cannot be matched in instance %d",
+ context,
+ format_type_be(ptype),
+ ptype_pos,
+ format_type_be(ntype),
+ ntype_pos,
+ instance_no)
+ : errmsg("%s types %s at position %d and %s at position %d cannot be matched",
+ context,
+ format_type_be(ptype),
+ ptype_pos,
+ format_type_be(ntype),
+ ntype_pos))));
}
else if (!IsPreferredType(pcategory, ptype) &&
can_coerce_type(1, &ptype, &ntype, COERCION_IMPLICIT) &&
@@ -982,6 +1001,7 @@
* other way; but if we have a preferred type, stay on it.
*/
ptype = ntype;
+ ptype_pos = ntype_pos;
pcategory = TypeCategory(ptype);
}
}
diff -ur ../cvs-pgsql/src/backend/parser/parse_expr.c ./src/backend/parser/parse_expr.c
--- ../cvs-pgsql/src/backend/parser/parse_expr.c 2007-04-03 22:26:05.000000000 +0200
+++ ./src/backend/parser/parse_expr.c 2007-04-23 21:13:00.000000000 +0200
@@ -870,7 +870,7 @@
* LHS' type is first in the list, it will be preferred when there is
* doubt (eg, when all the RHS items are unknown literals).
*/
- scalar_type = select_common_type(typeids, "IN");
+ scalar_type = select_common_type(typeids, "IN", 0);
/* Do we have an array type to use? */
array_type = get_array_type(scalar_type);
@@ -1074,7 +1074,7 @@
*/
typeids = lcons_oid(exprType((Node *) newc->defresult), typeids);
- ptype = select_common_type(typeids, "CASE");
+ ptype = select_common_type(typeids, "CASE", 0);
Assert(OidIsValid(ptype));
newc->casetype = ptype;
@@ -1249,7 +1249,7 @@
}
/* Select a common type for the elements */
- element_type = select_common_type(typeids, "ARRAY");
+ element_type = select_common_type(typeids, "ARRAY", 0);
/* Coerce arguments to common type if necessary */
foreach(element, newelems)
@@ -1325,7 +1325,7 @@
typeids = lappend_oid(typeids, exprType(newe));
}
- newc->coalescetype = select_common_type(typeids, "COALESCE");
+ newc->coalescetype = select_common_type(typeids, "COALESCE", 0);
/* Convert arguments if necessary */
foreach(args, newargs)
@@ -1363,7 +1363,7 @@
typeids = lappend_oid(typeids, exprType(newe));
}
- newm->minmaxtype = select_common_type(typeids, "GREATEST/LEAST");
+ newm->minmaxtype = select_common_type(typeids, "GREATEST/LEAST", 0);
/* Convert arguments if necessary */
foreach(args, newargs)
diff -ur ../cvs-pgsql/src/include/parser/parse_coerce.h ./src/include/parser/parse_coerce.h
--- ../cvs-pgsql/src/include/parser/parse_coerce.h 2007-04-01 10:57:50.000000000 +0200
+++ ./src/include/parser/parse_coerce.h 2007-04-23 21:08:47.000000000 +0200
@@ -59,7 +59,7 @@
Oid targetTypeId,
const char *constructName);
-extern Oid select_common_type(List *typeids, const char *context);
+extern Oid select_common_type(List *typeids, const char *context, int instance_no);
extern Node *coerce_to_common_type(ParseState *pstate, Node *node,
Oid targetTypeId,
const char *context);
---------------------------(end of broadcast)---------------------------
TIP 7: You can help support the PostgreSQL project by donating at
http://www.postgresql.org/about/donate