aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser/parse_clause.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/parser/parse_clause.c')
-rw-r--r--src/backend/parser/parse_clause.c136
1 files changed, 17 insertions, 119 deletions
diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c
index cc849ebf07b..20233ed1950 100644
--- a/src/backend/parser/parse_clause.c
+++ b/src/backend/parser/parse_clause.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.68 2000/09/29 18:21:36 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.69 2000/10/05 19:11:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -347,7 +347,8 @@ transformTableEntry(ParseState *pstate, RangeVar *r)
static RangeTblRef *
transformRangeSubselect(ParseState *pstate, RangeSubselect *r)
{
- SelectStmt *subquery = (SelectStmt *) r->subquery;
+ List *save_rtable;
+ List *save_joinlist;
List *parsetrees;
Query *query;
RangeTblEntry *rte;
@@ -362,19 +363,21 @@ transformRangeSubselect(ParseState *pstate, RangeSubselect *r)
elog(ERROR, "sub-select in FROM must have an alias");
/*
- * subquery node might not be SelectStmt if user wrote something like
- * FROM (SELECT ... UNION SELECT ...). Our current implementation of
- * UNION/INTERSECT/EXCEPT is too messy to deal with here, so punt until
- * we redesign querytrees to make it more reasonable.
+ * Analyze and transform the subquery. This is a bit tricky because
+ * we don't want the subquery to be able to see any FROM items already
+ * created in the current query (per SQL92, the scope of a FROM item
+ * does not include other FROM items). But it does need to be able to
+ * see any further-up parent states, so we can't just pass a null parent
+ * pstate link. So, temporarily make the current query level have an
+ * empty rtable and joinlist.
*/
- if (subquery == NULL || !IsA(subquery, SelectStmt))
- elog(ERROR, "Set operations not yet supported in subselects in FROM");
-
- /*
- * Analyze and transform the subquery as if it were an independent
- * statement (we do NOT want it to see the outer query as a parent).
- */
- parsetrees = parse_analyze(makeList1(subquery), NULL);
+ save_rtable = pstate->p_rtable;
+ save_joinlist = pstate->p_joinlist;
+ pstate->p_rtable = NIL;
+ pstate->p_joinlist = NIL;
+ parsetrees = parse_analyze(makeList1(r->subquery), pstate);
+ pstate->p_rtable = save_rtable;
+ pstate->p_joinlist = save_joinlist;
/*
* Check that we got something reasonable. Some of these conditions
@@ -1181,108 +1184,3 @@ exprIsInSortList(Node *expr, List *sortList, List *targetList)
}
return false;
}
-
-/* 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
- */
-#ifdef NOT_USED
-static List *
-transformUnionClause(List *unionClause, List *targetlist)
-{
- List *union_list = NIL;
- List *qlist,
- *qlist_item;
-
- if (unionClause)
- {
- /* recursion */
- qlist = parse_analyze(unionClause, NULL);
-
- foreach(qlist_item, qlist)
- {
- Query *query = (Query *) lfirst(qlist_item);
- List *prev_target = targetlist;
- List *next_target;
- int prev_len = 0,
- next_len = 0;
-
- foreach(prev_target, targetlist)
- if (!((TargetEntry *) lfirst(prev_target))->resdom->resjunk)
- prev_len++;
-
- foreach(next_target, query->targetList)
- if (!((TargetEntry *) lfirst(next_target))->resdom->resjunk)
- next_len++;
-
- if (prev_len != next_len)
- elog(ERROR, "Each UNION clause must have the same number of columns");
-
- foreach(next_target, query->targetList)
- {
- Oid itype;
- Oid otype;
-
- otype = ((TargetEntry *) lfirst(prev_target))->resdom->restype;
- itype = ((TargetEntry *) lfirst(next_target))->resdom->restype;
-
- /* one or both is a NULL column? then don't convert... */
- if (otype == InvalidOid)
- {
- /* propagate a known type forward, if available */
- if (itype != InvalidOid)
- ((TargetEntry *) lfirst(prev_target))->resdom->restype = itype;
-#if FALSE
- else
- {
- ((TargetEntry *) lfirst(prev_target))->resdom->restype = UNKNOWNOID;
- ((TargetEntry *) lfirst(next_target))->resdom->restype = UNKNOWNOID;
- }
-#endif
- }
- else if (itype == InvalidOid)
- {
- }
- /* they don't match in type? then convert... */
- else if (itype != otype)
- {
- Node *expr;
-
- expr = ((TargetEntry *) lfirst(next_target))->expr;
- expr = CoerceTargetExpr(NULL, expr, itype, otype, -1);
- 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, query);
- }
- return union_list;
- }
- else
- return NIL;
-}
-
-#endif