]> granicus.if.org Git - postgresql/commitdiff
UNION work for UNION ALL and other union stuff.
authorBruce Momjian <bruce@momjian.us>
Sat, 27 Dec 1997 06:41:41 +0000 (06:41 +0000)
committerBruce Momjian <bruce@momjian.us>
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;