aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser/parse_clause.c
diff options
context:
space:
mode:
authorThomas G. Lockhart <lockhart@fourpalms.org>1998-05-29 14:00:24 +0000
committerThomas G. Lockhart <lockhart@fourpalms.org>1998-05-29 14:00:24 +0000
commit8536c962614a55d33baa283a7901bb167a43978a (patch)
treed674201859f82cf92296a5fc079b5bfcaf1c4f8b /src/backend/parser/parse_clause.c
parent329083a97e2b5de1191f50451a253c224c833605 (diff)
downloadpostgresql-8536c962614a55d33baa283a7901bb167a43978a.tar.gz
postgresql-8536c962614a55d33baa283a7901bb167a43978a.zip
Do type conversion to match columns in UNION clauses.
Currently force the type to match the _first_ select in the union. Move oper_select_candidate() from parse_func.c to parse_oper.c. Throw error inside of oper_inexact() if no match for binary operators. Check more carefully that types can be coerced even if there is only one candidate operator in oper_inexact(). Fix up error messages for more uniform look. Remove unused code. Fix up comments.
Diffstat (limited to 'src/backend/parser/parse_clause.c')
-rw-r--r--src/backend/parser/parse_clause.c67
1 files changed, 49 insertions, 18 deletions
diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c
index 06c7cdee5f2..8fb8e185587 100644
--- a/src/backend/parser/parse_clause.c
+++ b/src/backend/parser/parse_clause.c
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.16 1998/05/21 03:53:50 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.17 1998/05/29 14:00:19 thomas Exp $
*
*-------------------------------------------------------------------------
*/
@@ -25,12 +25,15 @@
#include "parser/parse_oper.h"
#include "parser/parse_relation.h"
#include "parser/parse_target.h"
+#include "parser/parse_coerce.h"
+
static TargetEntry *
find_targetlist_entry(ParseState *pstate,
SortGroupBy *sortgroupby, List *tlist);
static void parseFromClause(ParseState *pstate, List *frmList);
+
/*
* makeRangeTable -
* make a range table with the specified relation (optional) and the
@@ -78,8 +81,7 @@ transformWhereClause(ParseState *pstate, Node *a_expr)
if (exprType(qual) != BOOLOID)
{
- elog(ERROR,
- "where clause must return type bool, not %s",
+ elog(ERROR, "WHERE clause must return type bool, not type %s",
typeidTypeName(exprType(qual)));
}
return qual;
@@ -167,7 +169,7 @@ find_targetlist_entry(ParseState *pstate, SortGroupBy *sortgroupby, List *tlist)
if (real_rtable_pos == test_rtable_pos)
{
if (target_result != NULL)
- elog(ERROR, "Order/Group By '%s' is ambiguous", sortgroupby->name);
+ elog(ERROR, "ORDER/GROUP BY '%s' is ambiguous", sortgroupby->name);
else
target_result = target;
}
@@ -175,7 +177,7 @@ find_targetlist_entry(ParseState *pstate, SortGroupBy *sortgroupby, List *tlist)
else
{
if (target_result != NULL)
- elog(ERROR, "Order/Group By '%s' is ambiguous", sortgroupby->name);
+ elog(ERROR, "ORDER/GROUP BY '%s' is ambiguous", sortgroupby->name);
else
target_result = target;
}
@@ -372,7 +374,7 @@ transformSortClause(ParseState *pstate,
break;
}
if (i == NIL)
- elog(ERROR, "The field specified in the UNIQUE ON clause is not in the targetlist");
+ elog(ERROR, "All fields in the UNIQUE ON clause must appear in the target list");
foreach(s, sortlist)
{
@@ -392,23 +394,29 @@ transformSortClause(ParseState *pstate,
sortlist = lappend(sortlist, sortcl);
}
}
-
}
return sortlist;
}
-/*
- * transformUnionClause -
- * transform a Union clause
- *
+/* transformUnionClause()
+ * Transform a UNION clause.
+ * Note that the union clause is actually a fully-formed select structure.
+ * So, it is evaluated as a select, then the resulting target fields
+ * are matched up to ensure correct types in the results.
+ * The select clause parsing is done recursively, so the unions are evaluated
+ * right-to-left. One might want to look at all columns from all clauses before
+ * trying to coerce, but unless we keep track of the call depth we won't know
+ * when to do this because of the recursion.
+ * Let's just try matching in pairs for now (right to left) and see if it works.
+ * - thomas 1998-05-22
*/
List *
transformUnionClause(List *unionClause, List *targetlist)
{
- List *union_list = NIL;
+ List *union_list = NIL;
QueryTreeList *qlist;
- int i;
+ int i;
if (unionClause)
{
@@ -421,13 +429,36 @@ transformUnionClause(List *unionClause, List *targetlist)
List *next_target;
if (length(targetlist) != length(qlist->qtrees[i]->targetList))
- elog(ERROR,"Each UNION query must have the same number of columns.");
+ elog(ERROR,"Each UNION clause must have the same number of columns");
foreach(next_target, qlist->qtrees[i]->targetList)
{
- if (((TargetEntry *)lfirst(prev_target))->resdom->restype !=
- ((TargetEntry *)lfirst(next_target))->resdom->restype)
- elog(ERROR,"Each UNION query must have identical target types.");
+ Oid itype;
+ Oid otype;
+ otype = ((TargetEntry *)lfirst(prev_target))->resdom->restype;
+ itype = ((TargetEntry *)lfirst(next_target))->resdom->restype;
+ if (itype != otype)
+ {
+ Node *expr;
+
+ expr = ((TargetEntry *)lfirst(next_target))->expr;
+ expr = coerce_target_expr(NULL, expr, itype, otype);
+ if (expr == NULL)
+ {
+ elog(ERROR,"Unable to transform %s to %s"
+ "\n\tEach UNION clause must have compatible target types",
+ typeidTypeName(itype),
+ typeidTypeName(otype));
+ }
+ ((TargetEntry *)lfirst(next_target))->expr = expr;
+ ((TargetEntry *)lfirst(next_target))->resdom->restype = otype;
+ }
+ /* both are UNKNOWN? then evaluate as text... */
+ else if (itype == UNKNOWNOID)
+ {
+ ((TargetEntry *)lfirst(next_target))->resdom->restype = TEXTOID;
+ ((TargetEntry *)lfirst(prev_target))->resdom->restype = TEXTOID;
+ }
prev_target = lnext(prev_target);
}
union_list = lappend(union_list, qlist->qtrees[i]);
@@ -436,4 +467,4 @@ transformUnionClause(List *unionClause, List *targetlist)
}
else
return NIL;
-}
+} /* transformUnionClause() */