aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser/analyze.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/parser/analyze.c')
-rw-r--r--src/backend/parser/analyze.c69
1 files changed, 64 insertions, 5 deletions
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index 05a1ecf3352..edc9ae2be6b 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.56 1997/12/24 06:06:18 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.57 1997/12/27 06:41:26 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -839,16 +839,75 @@ transformSelectStmt(ParseState *pstate, RetrieveStmt *stmt)
if (pstate->p_numAgg > 0)
finalizeAggregates(pstate, qry);
+ qry->unionall = stmt->unionall; /* in child, so unionClause may be false */
+
if (stmt->unionClause)
{
List *ulist = NIL;
QueryTreeList *qlist;
- int i;
-
+ int i, last_union = -1;
+ bool union_all_found = false, union_found = false;
+
qlist = parse_analyze(stmt->unionClause);
+
+ /*
+ * Do we need to split up our unions because we have UNION
+ * and UNION ALL?
+ */
for (i=0; i < qlist->len; i++)
- ulist = lappend(ulist, qlist->qtrees[i]);
- qry->unionClause = ulist;
+ {
+ if (qlist->qtrees[i]->unionall)
+ union_all_found = true;
+ else
+ {
+ union_found = true;
+ last_union = i;
+ }
+ }
+
+ /* A trailing UNION negates the affect of earlier UNION ALLs */
+ if (!union_all_found ||
+ !union_found ||
+ /* last entry is a UNION */
+ !qlist->qtrees[qlist->len-1]->unionall)
+ {
+ for (i=0; i < qlist->len; i++)
+ ulist = lappend(ulist, qlist->qtrees[i]);
+ qry->unionClause = ulist;
+ }
+ else
+ {
+ List *union_list = NIL;
+ Query *hold_qry;
+
+ /*
+ * We have mixed unions and non-unions, so we concentrate on
+ * the last UNION in the list.
+ */
+ for (i=0; i <= last_union; i++)
+ {
+ qlist->qtrees[i]->unionall = false; /*make queries consistent*/
+ union_list = lappend(union_list, qlist->qtrees[i]);
+ }
+
+ /*
+ * Make the first UNION ALL after the last UNION our new
+ * top query
+ */
+ hold_qry = qry;
+ qry = qlist->qtrees[last_union + 1];
+ qry->unionClause = lcons(hold_qry, NIL); /* UNION queries */
+ hold_qry->unionall = true; /* UNION ALL this into other queries */
+ hold_qry->unionClause = union_list;
+
+ /*
+ * The first UNION ALL after the last UNION is our anchor,
+ * we skip it.
+ */
+ for (i=last_union + 2; i < qlist->len; i++)
+ /* all queries are UNION ALL */
+ qry->unionClause = lappend(qry->unionClause, qlist->qtrees[i]);
+ }
}
else
qry->unionClause = NULL;