*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
* 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
int whichplan;
int nplans;
+ List *rts;
List *rtentries;
ResTarget *rtentry;
whichplan = unionstate->as_whichplan;
nplans = unionstate->as_nplans;
+ rts = node->unionrts;
rtentries = node->unionrtentries;
if (whichplan < 0)
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;
}
if (exec_append_initialize_next(node))
{
ExecSetSlotDescriptorIsNew(result_slot, true);
- return
- ExecProcAppend(node);
+ return ExecProcAppend(node);
}
else
return ExecClearTuple(result_slot);
*
*
* 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
sprintf(buf, " :qual ");
appendStringInfo(str, buf);
_outNode(str, node->qual);
-
+ /* how are we handling aggregates, sort, and group by? bjm 1997/12/26 */
}
/*
*
*
* 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
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);
}
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
{
List *tlist = parse->targetList;
List *rangetable = parse->rtable;
- char *uniqueflag = parse->uniqueFlag;
- List *sortclause = parse->sortClause;
Plan *result_plan = (Plan *) NULL;
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 */
* 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);
}
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
#include "nodes/relation.h"
#include "parser/parsetree.h"
+#include "parser/parse_clause.h"
#include "utils/elog.h"
#include "utils/lsyscache.h"
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);
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 */
}
static Append *
make_append(List *unionplans,
+ List *unionrts,
Index rt_index,
List *union_rt_entries,
List *tlist)
Append *node = makeNode(Append);
node->unionplans = unionplans;
+ node->unionrts = unionrts;
node->unionrelid = rt_index;
node->unionrtentries = union_rt_entries;
node->plan.cost = 0.0;
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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;
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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 */
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;
*
* 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 $
*
*-------------------------------------------------------------------------
*/
{
Plan plan;
List *unionplans;
+ List *unionrts;
Index unionrelid;
List *unionrtentries;
AppendState *unionstate;