aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser/parse_clause.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2000-10-05 19:11:39 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2000-10-05 19:11:39 +0000
commit05e3d0ee8666b74f11ffad16f46e372459d6e53e (patch)
treeb273892bfda60f6bad315e84aaa2e9826e226931 /src/backend/parser/parse_clause.c
parent5292637f52c6db8a22f99177f228273cb69fc510 (diff)
downloadpostgresql-05e3d0ee8666b74f11ffad16f46e372459d6e53e.tar.gz
postgresql-05e3d0ee8666b74f11ffad16f46e372459d6e53e.zip
Reimplementation of UNION/INTERSECT/EXCEPT. INTERSECT/EXCEPT now meet the
SQL92 semantics, including support for ALL option. All three can be used in subqueries and views. DISTINCT and ORDER BY work now in views, too. This rewrite fixes many problems with cross-datatype UNIONs and INSERT/SELECT where the SELECT yields different datatypes than the INSERT needs. I did that by making UNION subqueries and SELECT in INSERT be treated like subselects-in-FROM, thereby allowing an extra level of targetlist where the datatype conversions can be inserted safely. INITDB NEEDED!
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