diff options
author | Thomas G. Lockhart <lockhart@fourpalms.org> | 1998-05-29 14:00:24 +0000 |
---|---|---|
committer | Thomas G. Lockhart <lockhart@fourpalms.org> | 1998-05-29 14:00:24 +0000 |
commit | 8536c962614a55d33baa283a7901bb167a43978a (patch) | |
tree | d674201859f82cf92296a5fc079b5bfcaf1c4f8b /src/backend/parser/parse_clause.c | |
parent | 329083a97e2b5de1191f50451a253c224c833605 (diff) | |
download | postgresql-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.c | 67 |
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() */ |