UNION work for UNION ALL and other union stuff.
authorBruce Momjian
Sat, 27 Dec 1997 06:41:41 +0000 (06:41 +0000)
committerBruce Momjian
Sat, 27 Dec 1997 06:41:41 +0000 (06:41 +0000)
src/backend/executor/nodeAppend.c
src/backend/nodes/outfuncs.c
src/backend/nodes/readfuncs.c
src/backend/optimizer/plan/planner.c
src/backend/optimizer/prep/prepunion.c
src/backend/parser/analyze.c
src/include/nodes/parsenodes.h
src/include/nodes/plannodes.h

index 3c073101275edd573767bb3c77d0ed3882aa02a3..cdc0e56a1b7042d8d246e8901087c306ba9c853e 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/executor/nodeAppend.c,v 1.9 1997/09/08 21:43:10 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/executor/nodeAppend.c,v 1.10 1997/12/27 06:40:50 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -34,7 +34,7 @@
  *           nil   nil      ...    ...    ...
  *                              subplans
  *
- *     Append nodes are currently used to support inheritance
+ *     Append nodes are currently used to unions, and to support inheritance
  *     queries, where several relations need to be scanned.
  *     For example, in our standard person/student/employee/student-emp
  *     example, where student and employee inherit from person
@@ -85,6 +85,7 @@ exec_append_initialize_next(Append *node)
 
    int         whichplan;
    int         nplans;
+   List       *rts;
    List       *rtentries;
    ResTarget  *rtentry;
 
@@ -101,6 +102,7 @@ exec_append_initialize_next(Append *node)
 
    whichplan = unionstate->as_whichplan;
    nplans = unionstate->as_nplans;
+   rts = node->unionrts;
    rtentries = node->unionrtentries;
 
    if (whichplan < 0)
@@ -140,27 +142,28 @@ exec_append_initialize_next(Append *node)
        if (node->unionrelid > 0)
        {
            rtentry = nth(whichplan, rtentries);
-           if (rtentry == NULL)
-               elog(DEBUG, "exec_append_initialize_next: rtentry is nil");
+           Assert(rtentry != NULL);
 
            unionrelid = node->unionrelid;
 
            rt_store(unionrelid, rangeTable, rtentry);
-
-           if (unionstate->as_junkFilter_list)
-           {
-               estate->es_junkFilter =
-                   (JunkFilter *) nth(whichplan,
-                                      unionstate->as_junkFilter_list);
-           }
-           if (unionstate->as_result_relation_info_list)
-           {
-               estate->es_result_relation_info =
-                   (RelationInfo *) nth(whichplan,
-                              unionstate->as_result_relation_info_list);
-           }
-           result_slot->ttc_whichplan = whichplan;
        }
+       else
+           estate->es_range_table = nth(whichplan, rts);
+       
+       if (unionstate->as_junkFilter_list)
+       {
+           estate->es_junkFilter =
+               (JunkFilter *) nth(whichplan,
+                                  unionstate->as_junkFilter_list);
+       }
+       if (unionstate->as_result_relation_info_list)
+       {
+           estate->es_result_relation_info =
+               (RelationInfo *) nth(whichplan,
+                          unionstate->as_result_relation_info_list);
+       }
+       result_slot->ttc_whichplan = whichplan;
 
        return TRUE;
    }
@@ -439,8 +442,7 @@ ExecProcAppend(Append *node)
        if (exec_append_initialize_next(node))
        {
            ExecSetSlotDescriptorIsNew(result_slot, true);
-           return
-               ExecProcAppend(node);
+           return ExecProcAppend(node);
        }
        else
            return ExecClearTuple(result_slot);
index 7b4bfc61e3154f1e17907ca4457fb78112d6509a..a7fa85d31f821bb87f133899dbb9ee82bc3b7557 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.13 1997/12/23 19:50:54 thomas Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.14 1997/12/27 06:40:54 momjian Exp $
  *
  * NOTES
  *   Every (plan) node in POSTGRES has an associated "out" routine which
@@ -194,7 +194,7 @@ _outQuery(StringInfo str, Query *node)
    sprintf(buf, " :qual ");
    appendStringInfo(str, buf);
    _outNode(str, node->qual);
-
+   /* how are we handling aggregates, sort, and group by? bjm 1997/12/26 */
 }
 
 /*
index 2fd639aaf48e166050a3bc8717c2acd5b699eca4..8f1e6ff2655717da9c0c6bd948928687249269c5 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.11 1997/12/18 12:53:59 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.12 1997/12/27 06:40:59 momjian Exp $
  *
  * NOTES
  *   Most of the read functions for plan nodes are tested. (In fact, they
@@ -119,6 +119,7 @@ _readQuery()
 
    token = lsptok(NULL, &length);      /* skip :qual */
    local_node->qual = nodeRead(true);
+   /* how are we handling aggregates, sort, and group by? bjm 1997/12/26 */
 
    return (local_node);
 }
index cc3d9dfd7f83784bcde00eb9186bf0b5992d219f..5c5e80f333d23617b0645058c6463b987bd285c2 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.16 1997/12/24 06:06:01 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.17 1997/12/27 06:41:07 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -72,8 +72,6 @@ planner(Query *parse)
 {
    List       *tlist = parse->targetList;
    List       *rangetable = parse->rtable;
-   char       *uniqueflag = parse->uniqueFlag;
-   List       *sortclause = parse->sortClause;
 
    Plan       *result_plan = (Plan *) NULL;
 
@@ -83,7 +81,7 @@ planner(Query *parse)
 
    if (parse->unionClause)
    {
-       result_plan = (Plan *) plan_union_queries(0, /* none */
+       result_plan = (Plan *) plan_union_queries(  0, /* none */
                                                    parse,
                                                    UNION_FLAG);
        /* XXX do we need to do this? bjm 12/19/97 */
@@ -173,16 +171,16 @@ planner(Query *parse)
     * the optimization step later.
     */
 
-   if (uniqueflag)
+   if (parse->uniqueFlag)
    {
-       Plan       *sortplan = make_sortplan(tlist, sortclause, result_plan);
+       Plan       *sortplan = make_sortplan(tlist, parse->sortClause, result_plan);
 
-       return ((Plan *) make_unique(tlist, sortplan, uniqueflag));
+       return ((Plan *) make_unique(tlist, sortplan, parse->uniqueFlag));
    }
    else
    {
-       if (sortclause)
-           return (make_sortplan(tlist, sortclause, result_plan));
+       if (parse->sortClause)
+           return (make_sortplan(tlist, parse->sortClause, result_plan));
        else
            return ((Plan *) result_plan);
    }
index 91d4f777092b1ee8d28a6037243697162edaedd3..c0386d2a126ad7b14d18bc5c56e05fde9f1b1c09 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.14 1997/12/26 06:02:26 vadim Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.15 1997/12/27 06:41:17 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -23,6 +23,7 @@
 #include "nodes/relation.h"
 
 #include "parser/parsetree.h"
+#include "parser/parse_clause.h"
 
 #include "utils/elog.h"
 #include "utils/lsyscache.h"
@@ -42,7 +43,7 @@ static Query *subst_rangetable(Query *root, Index index,
                 RangeTblEntry *new_entry);
 static void fix_parsetree_attnums(Index rt_index, Oid old_relid,
                      Oid new_relid, Query *parsetree);
-static Append *make_append(List *unionplans, Index rt_index,
+static Append *make_append(List *unionplans, List *unionrts, Index rt_index,
            List *union_rt_entries, List *tlist);
 
 
@@ -136,73 +137,102 @@ plan_union_queries(Index rt_index,
                   Query *parse,
                   UnionFlag flag)
 {
-   List       *rangetable = parse->rtable;
-   RangeTblEntry *rt_entry = rt_fetch(rt_index, rangetable);
-   List       *union_relids = NIL;
    List       *union_plans = NIL;
-   List       *union_rt_entries = NIL;
 
    switch (flag)
    {
        case INHERITS_FLAG:
-           union_relids =
-               find_all_inheritors(lconsi(rt_entry->relid,
-                                          NIL),
-                                   NIL);
-           /*
-            * Remove the flag for this relation, since we're about to handle it
-            * (do it before recursing!). XXX destructive parse tree change
-            */
-           switch (flag)
            {
-               case INHERITS_FLAG:
-                   rt_fetch(rt_index, rangetable)->inh = false;
-                   break;
-               default:
-                   break;
-           }
-       
-           /*
-            * XXX - can't find any reason to sort union-relids as paul did, so
-            * we're leaving it out for now (maybe forever) - jeff & lp
-            *
-            * [maybe so. btw, jeff & lp did the lisp conversion, according to Paul.
-            * -- ay 10/94.]
-            */
-           union_plans = plan_union_query(union_relids, rt_index, rt_entry,
-                                          parse, flag, &union_rt_entries);
-       
-           return (make_append(union_plans,
-                               rt_index,
-                               union_rt_entries,
-                               ((Plan *) lfirst(union_plans))->targetlist));
-           break;
+               List       *rangetable = parse->rtable;
+               RangeTblEntry *rt_entry = rt_fetch(rt_index, rangetable);
+               List       *union_rt_entries = NIL;
+               List       *union_relids = NIL;
+   
+               union_relids =
+                   find_all_inheritors(lconsi(rt_entry->relid,
+                                              NIL),
+                                       NIL);
+               /*
+                * Remove the flag for this relation, since we're about to handle it
+                * (do it before recursing!). XXX destructive parse tree change
+                */
+               switch (flag)
+               {
+                   case INHERITS_FLAG:
+                       rt_fetch(rt_index, rangetable)->inh = false;
+                       break;
+                   default:
+                       break;
+               }
            
+               /*
+                * XXX - can't find any reason to sort union-relids as paul did, so
+                * we're leaving it out for now (maybe forever) - jeff & lp
+                *
+                * [maybe so. btw, jeff & lp did the lisp conversion, according to Paul.
+                * -- ay 10/94.]
+                */
+               union_plans = plan_union_query(union_relids, rt_index, rt_entry,
+                                              parse, flag, &union_rt_entries);
+   
+               return (make_append(union_plans,
+                                   NULL,
+                                   rt_index,
+                                   union_rt_entries,
+                                   ((Plan *) lfirst(union_plans))->targetlist));
+               break;
+           }           
        case UNION_FLAG:
            {
-               List *ulist, *hold_union, *union_plans;
+               List *ulist, *hold_union, *union_plans, *union_rts;
 
                hold_union = parse->unionClause;
                parse->unionClause = NULL; /* prevent looping */
 
                union_plans = lcons(planner(parse), NIL);
-               
+               union_rts = lcons(parse->rtable, NIL);
                foreach(ulist, hold_union)
-                   union_plans = lappend(union_plans, planner(lfirst(ulist)));
-               return (make_append(union_plans,
-                                   rt_index, rangetable,
+               {
+                   Query *u = lfirst(ulist);
+
+                   union_plans = lappend(union_plans, planner(u));
+                   union_rts = lappend(union_rts, u->rtable);
+               }
+
+               /* We have already split UNION and UNION ALL */
+               if (!((Query *)lfirst(hold_union))->unionall)
+               {
+                   parse->uniqueFlag = "*";
+                   parse->sortClause = transformSortClause(NULL, NIL,
+                       ((Plan *)lfirst(union_plans))->targetlist, "*");
+               }
+               else
+               {
+               /* needed so we don't take the flag from the first query */
+                   parse->uniqueFlag = NULL;
+                   parse->sortClause = NIL;
+               }
+
+               parse->havingQual = NULL;
+               parse->qry_numAgg = 0;
+               parse->qry_aggs = NULL;
+
+               return (make_append(union_plans, union_rts,
+                                   rt_index /* is 0, none */, NULL,
                            ((Plan *) lfirst(union_plans))->targetlist));
            }
            break;
 
+#ifdef NOT_USED
        case VERSION_FLAG:
            union_relids = VersionGetParents(rt_entry->relid);
            break;
-
+#endif
        default:
            /* do nothing */
            break;
    }
+   return NULL;
    
    return ((Append*)NULL);     /* to make gcc happy */
 }
@@ -392,6 +422,7 @@ fix_parsetree_attnums(Index rt_index,
 
 static Append *
 make_append(List *unionplans,
+           List *unionrts,
            Index rt_index,
            List *union_rt_entries,
            List *tlist)
@@ -399,6 +430,7 @@ make_append(List *unionplans,
    Append     *node = makeNode(Append);
 
    node->unionplans = unionplans;
+   node->unionrts = unionrts;
    node->unionrelid = rt_index;
    node->unionrtentries = union_rt_entries;
    node->plan.cost = 0.0;
index 05a1ecf3352b49ffa2f09ec1696fb4910ea6499b..edc9ae2be6b71a988f739a30f9b0f2eec5b6055a 100644 (file)
@@ -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;
index a6b9a400ea559a6f98b6e9a706dee13b6bbdc139..d288d66aa364df26bb86d8491a4188ee2c06a72b 100644 (file)
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parsenodes.h,v 1.39 1997/12/24 06:06:53 momjian Exp $
+ * $Id: parsenodes.h,v 1.40 1997/12/27 06:41:39 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -43,7 +43,8 @@ typedef struct Query
    char       *into;           /* portal (cursor) name */
    bool        isPortal;       /* is this a retrieve into portal? */
    bool        isBinary;       /* binary portal? */
-
+   bool        unionall;       /* union without unique sort */
+   
    char       *uniqueFlag;     /* NULL, '*', or Unique attribute name */
    List       *sortClause;     /* a list of SortClause's */
 
@@ -636,7 +637,7 @@ typedef struct RetrieveStmt
    Node       *havingClause;   /* having conditional-expression */
    List       *unionClause;    /* union subselect parameters */
    List       *sortClause;     /* sort clause (a list of SortGroupBy's) */
-   int         unionall;       /* union without unique sort */
+   bool        unionall;       /* union without unique sort */
 } RetrieveStmt;
 
 
index 63447c936922a6be1208b8d31d182cfcde9895a8..2dc464c2a7af104299a498bca52bc7f9ba707129 100644 (file)
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: plannodes.h,v 1.11 1997/12/18 12:54:37 momjian Exp $
+ * $Id: plannodes.h,v 1.12 1997/12/27 06:41:41 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -119,6 +119,7 @@ typedef struct Append
 {
    Plan        plan;
    List       *unionplans;
+   List       *unionrts;
    Index       unionrelid;
    List       *unionrtentries;
    AppendState *unionstate;