Commit 4ce24c8a authored by Bruce Momjian's avatar Bruce Momjian

UNION work for UNION ALL and other union stuff.

parent 2730c4a4
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * 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 @@ ...@@ -34,7 +34,7 @@
* nil nil ... ... ... * nil nil ... ... ...
* subplans * 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. * queries, where several relations need to be scanned.
* For example, in our standard person/student/employee/student-emp * For example, in our standard person/student/employee/student-emp
* example, where student and employee inherit from person * example, where student and employee inherit from person
...@@ -85,6 +85,7 @@ exec_append_initialize_next(Append *node) ...@@ -85,6 +85,7 @@ exec_append_initialize_next(Append *node)
int whichplan; int whichplan;
int nplans; int nplans;
List *rts;
List *rtentries; List *rtentries;
ResTarget *rtentry; ResTarget *rtentry;
...@@ -101,6 +102,7 @@ exec_append_initialize_next(Append *node) ...@@ -101,6 +102,7 @@ exec_append_initialize_next(Append *node)
whichplan = unionstate->as_whichplan; whichplan = unionstate->as_whichplan;
nplans = unionstate->as_nplans; nplans = unionstate->as_nplans;
rts = node->unionrts;
rtentries = node->unionrtentries; rtentries = node->unionrtentries;
if (whichplan < 0) if (whichplan < 0)
...@@ -140,27 +142,28 @@ exec_append_initialize_next(Append *node) ...@@ -140,27 +142,28 @@ exec_append_initialize_next(Append *node)
if (node->unionrelid > 0) if (node->unionrelid > 0)
{ {
rtentry = nth(whichplan, rtentries); rtentry = nth(whichplan, rtentries);
if (rtentry == NULL) Assert(rtentry != NULL);
elog(DEBUG, "exec_append_initialize_next: rtentry is nil");
unionrelid = node->unionrelid; unionrelid = node->unionrelid;
rt_store(unionrelid, rangeTable, rtentry); 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; return TRUE;
} }
...@@ -439,8 +442,7 @@ ExecProcAppend(Append *node) ...@@ -439,8 +442,7 @@ ExecProcAppend(Append *node)
if (exec_append_initialize_next(node)) if (exec_append_initialize_next(node))
{ {
ExecSetSlotDescriptorIsNew(result_slot, true); ExecSetSlotDescriptorIsNew(result_slot, true);
return return ExecProcAppend(node);
ExecProcAppend(node);
} }
else else
return ExecClearTuple(result_slot); return ExecClearTuple(result_slot);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* Every (plan) node in POSTGRES has an associated "out" routine which * Every (plan) node in POSTGRES has an associated "out" routine which
...@@ -194,7 +194,7 @@ _outQuery(StringInfo str, Query *node) ...@@ -194,7 +194,7 @@ _outQuery(StringInfo str, Query *node)
sprintf(buf, " :qual "); sprintf(buf, " :qual ");
appendStringInfo(str, buf); appendStringInfo(str, buf);
_outNode(str, node->qual); _outNode(str, node->qual);
/* how are we handling aggregates, sort, and group by? bjm 1997/12/26 */
} }
/* /*
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* Most of the read functions for plan nodes are tested. (In fact, they * Most of the read functions for plan nodes are tested. (In fact, they
...@@ -119,6 +119,7 @@ _readQuery() ...@@ -119,6 +119,7 @@ _readQuery()
token = lsptok(NULL, &length); /* skip :qual */ token = lsptok(NULL, &length); /* skip :qual */
local_node->qual = nodeRead(true); local_node->qual = nodeRead(true);
/* how are we handling aggregates, sort, and group by? bjm 1997/12/26 */
return (local_node); return (local_node);
} }
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -72,8 +72,6 @@ planner(Query *parse)
{ {
List *tlist = parse->targetList; List *tlist = parse->targetList;
List *rangetable = parse->rtable; List *rangetable = parse->rtable;
char *uniqueflag = parse->uniqueFlag;
List *sortclause = parse->sortClause;
Plan *result_plan = (Plan *) NULL; Plan *result_plan = (Plan *) NULL;
...@@ -83,7 +81,7 @@ planner(Query *parse) ...@@ -83,7 +81,7 @@ planner(Query *parse)
if (parse->unionClause) if (parse->unionClause)
{ {
result_plan = (Plan *) plan_union_queries(0, /* none */ result_plan = (Plan *) plan_union_queries( 0, /* none */
parse, parse,
UNION_FLAG); UNION_FLAG);
/* XXX do we need to do this? bjm 12/19/97 */ /* XXX do we need to do this? bjm 12/19/97 */
...@@ -173,16 +171,16 @@ planner(Query *parse) ...@@ -173,16 +171,16 @@ planner(Query *parse)
* the optimization step later. * 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 else
{ {
if (sortclause) if (parse->sortClause)
return (make_sortplan(tlist, sortclause, result_plan)); return (make_sortplan(tlist, parse->sortClause, result_plan));
else else
return ((Plan *) result_plan); return ((Plan *) result_plan);
} }
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * 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 @@ ...@@ -23,6 +23,7 @@
#include "nodes/relation.h" #include "nodes/relation.h"
#include "parser/parsetree.h" #include "parser/parsetree.h"
#include "parser/parse_clause.h"
#include "utils/elog.h" #include "utils/elog.h"
#include "utils/lsyscache.h" #include "utils/lsyscache.h"
...@@ -42,7 +43,7 @@ static Query *subst_rangetable(Query *root, Index index, ...@@ -42,7 +43,7 @@ static Query *subst_rangetable(Query *root, Index index,
RangeTblEntry *new_entry); RangeTblEntry *new_entry);
static void fix_parsetree_attnums(Index rt_index, Oid old_relid, static void fix_parsetree_attnums(Index rt_index, Oid old_relid,
Oid new_relid, Query *parsetree); 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); List *union_rt_entries, List *tlist);
...@@ -136,73 +137,102 @@ plan_union_queries(Index rt_index, ...@@ -136,73 +137,102 @@ plan_union_queries(Index rt_index,
Query *parse, Query *parse,
UnionFlag flag) UnionFlag flag)
{ {
List *rangetable = parse->rtable;
RangeTblEntry *rt_entry = rt_fetch(rt_index, rangetable);
List *union_relids = NIL;
List *union_plans = NIL; List *union_plans = NIL;
List *union_rt_entries = NIL;
switch (flag) switch (flag)
{ {
case INHERITS_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: List *rangetable = parse->rtable;
rt_fetch(rt_index, rangetable)->inh = false; RangeTblEntry *rt_entry = rt_fetch(rt_index, rangetable);
break; List *union_rt_entries = NIL;
default: List *union_relids = NIL;
break;
} union_relids =
find_all_inheritors(lconsi(rt_entry->relid,
/* NIL),
* XXX - can't find any reason to sort union-relids as paul did, so NIL);
* we're leaving it out for now (maybe forever) - jeff & lp /*
* * Remove the flag for this relation, since we're about to handle it
* [maybe so. btw, jeff & lp did the lisp conversion, according to Paul. * (do it before recursing!). XXX destructive parse tree change
* -- ay 10/94.] */
*/ switch (flag)
union_plans = plan_union_query(union_relids, rt_index, rt_entry, {
parse, flag, &union_rt_entries); case INHERITS_FLAG:
rt_fetch(rt_index, rangetable)->inh = false;
return (make_append(union_plans, break;
rt_index, default:
union_rt_entries, break;
((Plan *) lfirst(union_plans))->targetlist)); }
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: case UNION_FLAG:
{ {
List *ulist, *hold_union, *union_plans; List *ulist, *hold_union, *union_plans, *union_rts;
hold_union = parse->unionClause; hold_union = parse->unionClause;
parse->unionClause = NULL; /* prevent looping */ parse->unionClause = NULL; /* prevent looping */
union_plans = lcons(planner(parse), NIL); union_plans = lcons(planner(parse), NIL);
union_rts = lcons(parse->rtable, NIL);
foreach(ulist, hold_union) foreach(ulist, hold_union)
union_plans = lappend(union_plans, planner(lfirst(ulist))); {
return (make_append(union_plans, Query *u = lfirst(ulist);
rt_index, rangetable,
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)); ((Plan *) lfirst(union_plans))->targetlist));
} }
break; break;
#ifdef NOT_USED
case VERSION_FLAG: case VERSION_FLAG:
union_relids = VersionGetParents(rt_entry->relid); union_relids = VersionGetParents(rt_entry->relid);
break; break;
#endif
default: default:
/* do nothing */ /* do nothing */
break; break;
} }
return NULL;
return ((Append*)NULL); /* to make gcc happy */ return ((Append*)NULL); /* to make gcc happy */
} }
...@@ -392,6 +422,7 @@ fix_parsetree_attnums(Index rt_index, ...@@ -392,6 +422,7 @@ fix_parsetree_attnums(Index rt_index,
static Append * static Append *
make_append(List *unionplans, make_append(List *unionplans,
List *unionrts,
Index rt_index, Index rt_index,
List *union_rt_entries, List *union_rt_entries,
List *tlist) List *tlist)
...@@ -399,6 +430,7 @@ make_append(List *unionplans, ...@@ -399,6 +430,7 @@ make_append(List *unionplans,
Append *node = makeNode(Append); Append *node = makeNode(Append);
node->unionplans = unionplans; node->unionplans = unionplans;
node->unionrts = unionrts;
node->unionrelid = rt_index; node->unionrelid = rt_index;
node->unionrtentries = union_rt_entries; node->unionrtentries = union_rt_entries;
node->plan.cost = 0.0; node->plan.cost = 0.0;
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -839,16 +839,75 @@ transformSelectStmt(ParseState *pstate, RetrieveStmt *stmt)
if (pstate->p_numAgg > 0) if (pstate->p_numAgg > 0)
finalizeAggregates(pstate, qry); finalizeAggregates(pstate, qry);
qry->unionall = stmt->unionall; /* in child, so unionClause may be false */
if (stmt->unionClause) if (stmt->unionClause)
{ {
List *ulist = NIL; List *ulist = NIL;
QueryTreeList *qlist; QueryTreeList *qlist;
int i; int i, last_union = -1;
bool union_all_found = false, union_found = false;
qlist = parse_analyze(stmt->unionClause); 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++) 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 else
qry->unionClause = NULL; qry->unionClause = NULL;
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* *
* Copyright (c) 1994, Regents of the University of California * 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 ...@@ -43,7 +43,8 @@ typedef struct Query
char *into; /* portal (cursor) name */ char *into; /* portal (cursor) name */
bool isPortal; /* is this a retrieve into portal? */ bool isPortal; /* is this a retrieve into portal? */
bool isBinary; /* binary portal? */ bool isBinary; /* binary portal? */
bool unionall; /* union without unique sort */
char *uniqueFlag; /* NULL, '*', or Unique attribute name */ char *uniqueFlag; /* NULL, '*', or Unique attribute name */
List *sortClause; /* a list of SortClause's */ List *sortClause; /* a list of SortClause's */
...@@ -636,7 +637,7 @@ typedef struct RetrieveStmt ...@@ -636,7 +637,7 @@ typedef struct RetrieveStmt
Node *havingClause; /* having conditional-expression */ Node *havingClause; /* having conditional-expression */
List *unionClause; /* union subselect parameters */ List *unionClause; /* union subselect parameters */
List *sortClause; /* sort clause (a list of SortGroupBy's) */ List *sortClause; /* sort clause (a list of SortGroupBy's) */
int unionall; /* union without unique sort */ bool unionall; /* union without unique sort */
} RetrieveStmt; } RetrieveStmt;
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* *
* Copyright (c) 1994, Regents of the University of California * 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 ...@@ -119,6 +119,7 @@ typedef struct Append
{ {
Plan plan; Plan plan;
List *unionplans; List *unionplans;
List *unionrts;
Index unionrelid; Index unionrelid;
List *unionrtentries; List *unionrtentries;
AppendState *unionstate; AppendState *unionstate;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment