Cleanup of UNION ALL fix. Manual page updates.
This commit is contained in:
parent
4ce24c8aa9
commit
a01b085c78
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.17 1997/12/27 06:41:07 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.18 1997/12/29 01:12:45 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -76,14 +76,12 @@ planner(Query *parse)
|
|||||||
Plan *result_plan = (Plan *) NULL;
|
Plan *result_plan = (Plan *) NULL;
|
||||||
|
|
||||||
List *primary_qual;
|
List *primary_qual;
|
||||||
int rt_index;
|
Index rt_index;
|
||||||
|
|
||||||
|
|
||||||
if (parse->unionClause)
|
if (parse->unionClause)
|
||||||
{
|
{
|
||||||
result_plan = (Plan *) plan_union_queries( 0, /* none */
|
result_plan = (Plan *) plan_union_queries(parse);
|
||||||
parse,
|
|
||||||
UNION_FLAG);
|
|
||||||
/* XXX do we need to do this? bjm 12/19/97 */
|
/* XXX do we need to do this? bjm 12/19/97 */
|
||||||
tlist = preprocess_targetlist(tlist,
|
tlist = preprocess_targetlist(tlist,
|
||||||
parse->commandType,
|
parse->commandType,
|
||||||
@ -91,11 +89,9 @@ planner(Query *parse)
|
|||||||
parse->rtable);
|
parse->rtable);
|
||||||
}
|
}
|
||||||
else if ((rt_index =
|
else if ((rt_index =
|
||||||
first_matching_rt_entry(rangetable, INHERITS_FLAG)) != -1)
|
first_inherit_rt_entry(rangetable)) != -1)
|
||||||
{
|
{
|
||||||
result_plan = (Plan *) plan_union_queries((Index) rt_index,
|
result_plan = (Plan *) plan_inherit_queries(parse, rt_index);
|
||||||
parse,
|
|
||||||
INHERITS_FLAG);
|
|
||||||
/* XXX do we need to do this? bjm 12/19/97 */
|
/* XXX do we need to do this? bjm 12/19/97 */
|
||||||
tlist = preprocess_targetlist(tlist,
|
tlist = preprocess_targetlist(tlist,
|
||||||
parse->commandType,
|
parse->commandType,
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.15 1997/12/27 06:41:17 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.16 1997/12/29 01:12:48 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -34,8 +34,8 @@
|
|||||||
#include "optimizer/planner.h"
|
#include "optimizer/planner.h"
|
||||||
#include "optimizer/planmain.h"
|
#include "optimizer/planmain.h"
|
||||||
|
|
||||||
static List *plan_union_query(List *relids, Index rt_index,
|
static List *plan_inherit_query(List *relids, Index rt_index,
|
||||||
RangeTblEntry *rt_entry, Query *parse, UnionFlag flag,
|
RangeTblEntry *rt_entry, Query *parse,
|
||||||
List **union_rtentriesPtr);
|
List **union_rtentriesPtr);
|
||||||
static RangeTblEntry *new_rangetable_entry(Oid new_relid,
|
static RangeTblEntry *new_rangetable_entry(Oid new_relid,
|
||||||
RangeTblEntry *old_entry);
|
RangeTblEntry *old_entry);
|
||||||
@ -47,6 +47,248 @@ static Append *make_append(List *unionplans, List *unionrts, Index rt_index,
|
|||||||
List *union_rt_entries, List *tlist);
|
List *union_rt_entries, List *tlist);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* plan-union-queries--
|
||||||
|
*
|
||||||
|
* Plans the queries for a given UNION.
|
||||||
|
*
|
||||||
|
* Returns a list containing a list of plans and a list of rangetables
|
||||||
|
*/
|
||||||
|
Append *
|
||||||
|
plan_union_queries(Query *parse)
|
||||||
|
{
|
||||||
|
List *union_plans = NIL, *ulist, *unionall_queries, *union_rts,
|
||||||
|
*last_union = NIL;
|
||||||
|
bool union_all_found = false, union_found = false,
|
||||||
|
last_unionall_flag = false;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Do we need to split up our unions because we have UNION
|
||||||
|
* and UNION ALL?
|
||||||
|
*
|
||||||
|
* We are checking for the case of:
|
||||||
|
* SELECT 1
|
||||||
|
* UNION
|
||||||
|
* SELECT 2
|
||||||
|
* UNION
|
||||||
|
* SELECT 3
|
||||||
|
* UNION ALL
|
||||||
|
* SELECT 4
|
||||||
|
* UNION ALL
|
||||||
|
* SELECT 5
|
||||||
|
*
|
||||||
|
* where we have to do a DISTINCT on the output of the first three
|
||||||
|
* queries, then add the rest. If they have used UNION and
|
||||||
|
* UNION ALL, we grab all queries up to the last UNION query,
|
||||||
|
* make them their own UNION with the owner as the first query
|
||||||
|
* in the list. Then, we take the remaining queries, which is UNION
|
||||||
|
* ALL, and add them to the list of union queries.
|
||||||
|
*
|
||||||
|
* So the above query becomes:
|
||||||
|
*
|
||||||
|
* Append Node
|
||||||
|
* {
|
||||||
|
* Sort and Unique
|
||||||
|
* {
|
||||||
|
* Append Node
|
||||||
|
* {
|
||||||
|
* SELECT 1 This is really a sub-UNION,
|
||||||
|
* unionClause We run a DISTINCT on these.
|
||||||
|
* {
|
||||||
|
* SELECT 2
|
||||||
|
* SELECT 3
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* SELECT 4
|
||||||
|
* SELECT 5
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
foreach(ulist, parse->unionClause)
|
||||||
|
{
|
||||||
|
Query *union_query = lfirst(ulist);
|
||||||
|
|
||||||
|
if (union_query->unionall)
|
||||||
|
union_all_found = true;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
union_found = true;
|
||||||
|
last_union = ulist;
|
||||||
|
}
|
||||||
|
last_unionall_flag = union_query->unionall;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Is this a simple one */
|
||||||
|
if (!union_all_found ||
|
||||||
|
!union_found ||
|
||||||
|
/* A trailing UNION negates the affect of earlier UNION ALLs */
|
||||||
|
!last_unionall_flag)
|
||||||
|
{
|
||||||
|
List *hold_unionClause = parse->unionClause;
|
||||||
|
|
||||||
|
parse->unionClause = NIL; /* prevent recursion */
|
||||||
|
union_plans = lcons(planner(parse), NIL);
|
||||||
|
union_rts = lcons(parse->rtable, NIL);
|
||||||
|
|
||||||
|
foreach(ulist, hold_unionClause)
|
||||||
|
{
|
||||||
|
Query *union_query = lfirst(ulist);
|
||||||
|
|
||||||
|
union_plans = lappend(union_plans, planner(union_query));
|
||||||
|
union_rts = lappend(union_rts, union_query->rtable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* We have mixed unions and non-unions
|
||||||
|
*
|
||||||
|
* We need to restructure this to put the UNIONs on their own
|
||||||
|
* so we can do a DISTINCT.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* save off everthing past the last UNION */
|
||||||
|
unionall_queries = lnext(last_union);
|
||||||
|
|
||||||
|
/* clip off the list to remove the trailing UNION ALLs */
|
||||||
|
lnext(last_union) = NIL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Recursion, but UNION only.
|
||||||
|
* The last one is a UNION, so it will not come here in recursion,
|
||||||
|
*/
|
||||||
|
union_plans = lcons(planner(parse), NIL);
|
||||||
|
union_rts = lcons(parse->rtable, NIL);
|
||||||
|
|
||||||
|
/* Append the remainging UNION ALLs */
|
||||||
|
foreach(ulist, unionall_queries)
|
||||||
|
{
|
||||||
|
Query *unionall_query = lfirst(ulist);
|
||||||
|
|
||||||
|
union_plans = lappend(union_plans, planner(unionall_query));
|
||||||
|
union_rts = lappend(union_rts, unionall_query->rtable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We have already split UNION and UNION ALL and we made it consistent */
|
||||||
|
if (!last_unionall_flag)
|
||||||
|
{
|
||||||
|
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,
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
|
((Plan *) lfirst(union_plans))->targetlist));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* plan-inherit-queries--
|
||||||
|
*
|
||||||
|
* Plans the queries for a given parent relation.
|
||||||
|
*
|
||||||
|
* Returns a list containing a list of plans and a list of rangetable
|
||||||
|
* entries to be inserted into an APPEND node.
|
||||||
|
* XXX - what exactly does this mean, look for make_append
|
||||||
|
*/
|
||||||
|
Append *
|
||||||
|
plan_inherit_queries(Query *parse, Index rt_index)
|
||||||
|
{
|
||||||
|
List *union_plans = NIL;
|
||||||
|
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
rt_fetch(rt_index, rangetable)->inh = false;
|
||||||
|
|
||||||
|
union_plans = plan_inherit_query(union_relids, rt_index, rt_entry,
|
||||||
|
parse, &union_rt_entries);
|
||||||
|
|
||||||
|
return (make_append(union_plans,
|
||||||
|
NULL,
|
||||||
|
rt_index,
|
||||||
|
union_rt_entries,
|
||||||
|
((Plan *) lfirst(union_plans))->targetlist));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* plan-inherit-query--
|
||||||
|
* Returns a list of plans for 'relids' and a list of range table entries
|
||||||
|
* in union_rtentries.
|
||||||
|
*/
|
||||||
|
static List *
|
||||||
|
plan_inherit_query(List *relids,
|
||||||
|
Index rt_index,
|
||||||
|
RangeTblEntry *rt_entry,
|
||||||
|
Query *root,
|
||||||
|
List **union_rtentriesPtr)
|
||||||
|
{
|
||||||
|
List *i;
|
||||||
|
List *union_plans = NIL;
|
||||||
|
List *union_rtentries = NIL;
|
||||||
|
|
||||||
|
foreach(i, relids)
|
||||||
|
{
|
||||||
|
int relid = lfirsti(i);
|
||||||
|
RangeTblEntry *new_rt_entry = new_rangetable_entry(relid,
|
||||||
|
rt_entry);
|
||||||
|
Query *new_root = subst_rangetable(root,
|
||||||
|
rt_index,
|
||||||
|
new_rt_entry);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* reset the uniqueflag and sortclause in parse tree root, so that
|
||||||
|
* sorting will only be done once after append
|
||||||
|
*/
|
||||||
|
new_root->uniqueFlag = NULL;
|
||||||
|
new_root->sortClause = NULL;
|
||||||
|
new_root->groupClause = NULL;
|
||||||
|
if (new_root->qry_numAgg != 0)
|
||||||
|
{
|
||||||
|
new_root->qry_numAgg = 0;
|
||||||
|
pfree(new_root->qry_aggs);
|
||||||
|
new_root->qry_aggs = NULL;
|
||||||
|
del_agg_tlist_references(new_root->targetList);
|
||||||
|
}
|
||||||
|
fix_parsetree_attnums(rt_index,
|
||||||
|
rt_entry->relid,
|
||||||
|
relid,
|
||||||
|
new_root);
|
||||||
|
|
||||||
|
union_plans = lappend(union_plans, planner(new_root));
|
||||||
|
union_rtentries = lappend(union_rtentries, new_rt_entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
*union_rtentriesPtr = union_rtentries;
|
||||||
|
return (union_plans);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* find-all-inheritors -
|
* find-all-inheritors -
|
||||||
* Returns a list of relids corresponding to relations that inherit
|
* Returns a list of relids corresponding to relations that inherit
|
||||||
@ -91,14 +333,14 @@ find_all_inheritors(List *unexamined_relids,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* first-matching-rt-entry -
|
* first-inherit-rt-entry -
|
||||||
* Given a rangetable, find the first rangetable entry that represents
|
* Given a rangetable, find the first rangetable entry that represents
|
||||||
* the appropriate special case.
|
* the appropriate special case.
|
||||||
*
|
*
|
||||||
* Returns a rangetable index., Returns -1 if no matches
|
* Returns a rangetable index., Returns -1 if no matches
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
first_matching_rt_entry(List *rangetable, UnionFlag flag)
|
first_inherit_rt_entry(List *rangetable)
|
||||||
{
|
{
|
||||||
int count = 0;
|
int count = 0;
|
||||||
List *temp = NIL;
|
List *temp = NIL;
|
||||||
@ -107,188 +349,12 @@ first_matching_rt_entry(List *rangetable, UnionFlag flag)
|
|||||||
{
|
{
|
||||||
RangeTblEntry *rt_entry = lfirst(temp);
|
RangeTblEntry *rt_entry = lfirst(temp);
|
||||||
|
|
||||||
switch (flag)
|
if (rt_entry->inh)
|
||||||
{
|
return count + 1;
|
||||||
case INHERITS_FLAG:
|
|
||||||
if (rt_entry->inh)
|
|
||||||
return count + 1;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (-1);
|
return -1;
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* plan-union-queries--
|
|
||||||
*
|
|
||||||
* Plans the queries for a given parent relation.
|
|
||||||
*
|
|
||||||
* Returns a list containing a list of plans and a list of rangetable
|
|
||||||
* entries to be inserted into an APPEND node.
|
|
||||||
* XXX - what exactly does this mean, look for make_append
|
|
||||||
*/
|
|
||||||
Append *
|
|
||||||
plan_union_queries(Index rt_index,
|
|
||||||
Query *parse,
|
|
||||||
UnionFlag flag)
|
|
||||||
{
|
|
||||||
List *union_plans = NIL;
|
|
||||||
|
|
||||||
switch (flag)
|
|
||||||
{
|
|
||||||
case INHERITS_FLAG:
|
|
||||||
{
|
|
||||||
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, *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)
|
|
||||||
{
|
|
||||||
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 */
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* plan-union-query--
|
|
||||||
* Returns a list of plans for 'relids' and a list of range table entries
|
|
||||||
* in union_rtentries.
|
|
||||||
*/
|
|
||||||
static List *
|
|
||||||
plan_union_query(List *relids,
|
|
||||||
Index rt_index,
|
|
||||||
RangeTblEntry *rt_entry,
|
|
||||||
Query *root,
|
|
||||||
UnionFlag flag,
|
|
||||||
List **union_rtentriesPtr)
|
|
||||||
{
|
|
||||||
List *i;
|
|
||||||
List *union_plans = NIL;
|
|
||||||
List *union_rtentries = NIL;
|
|
||||||
|
|
||||||
foreach(i, relids)
|
|
||||||
{
|
|
||||||
int relid = lfirsti(i);
|
|
||||||
RangeTblEntry *new_rt_entry = new_rangetable_entry(relid,
|
|
||||||
rt_entry);
|
|
||||||
Query *new_root = subst_rangetable(root,
|
|
||||||
rt_index,
|
|
||||||
new_rt_entry);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* reset the uniqueflag and sortclause in parse tree root, so that
|
|
||||||
* sorting will only be done once after append
|
|
||||||
*/
|
|
||||||
new_root->uniqueFlag = NULL;
|
|
||||||
new_root->sortClause = NULL;
|
|
||||||
new_root->groupClause = NULL;
|
|
||||||
if (new_root->qry_numAgg != 0)
|
|
||||||
{
|
|
||||||
new_root->qry_numAgg = 0;
|
|
||||||
pfree(new_root->qry_aggs);
|
|
||||||
new_root->qry_aggs = NULL;
|
|
||||||
del_agg_tlist_references(new_root->targetList);
|
|
||||||
}
|
|
||||||
fix_parsetree_attnums(rt_index,
|
|
||||||
rt_entry->relid,
|
|
||||||
relid,
|
|
||||||
new_root);
|
|
||||||
|
|
||||||
union_plans = lappend(union_plans, planner(new_root));
|
|
||||||
union_rtentries = lappend(union_rtentries, new_rt_entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
*union_rtentriesPtr = union_rtentries;
|
|
||||||
return (union_plans);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -367,8 +433,6 @@ fix_parsetree_attnums_nodes(Index rt_index,
|
|||||||
Oid old_typeid,
|
Oid old_typeid,
|
||||||
new_typeid;
|
new_typeid;
|
||||||
|
|
||||||
/* old_typeid = RelationIdGetTypeId(old_relid);*/
|
|
||||||
/* new_typeid = RelationIdGetTypeId(new_relid);*/
|
|
||||||
old_typeid = old_relid;
|
old_typeid = old_relid;
|
||||||
new_typeid = new_relid;
|
new_typeid = new_relid;
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.57 1997/12/27 06:41:26 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.58 1997/12/29 01:12:55 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -840,77 +840,10 @@ transformSelectStmt(ParseState *pstate, RetrieveStmt *stmt)
|
|||||||
finalizeAggregates(pstate, qry);
|
finalizeAggregates(pstate, qry);
|
||||||
|
|
||||||
qry->unionall = stmt->unionall; /* in child, so unionClause may be false */
|
qry->unionall = stmt->unionall; /* in child, so unionClause may be false */
|
||||||
|
qry->unionClause = transformUnionClause(stmt->unionClause, qry->targetList);
|
||||||
|
|
||||||
if (stmt->unionClause)
|
if (qry->unionClause && stmt->sortClause)
|
||||||
{
|
elog(WARN, "You can not use ORDER BY with UNION", NULL);
|
||||||
List *ulist = NIL;
|
|
||||||
QueryTreeList *qlist;
|
|
||||||
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++)
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
|
|
||||||
return (Query *) qry;
|
return (Query *) qry;
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.3 1997/11/26 03:42:39 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.4 1997/12/29 01:12:58 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -18,6 +18,7 @@
|
|||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
#include "access/heapam.h"
|
#include "access/heapam.h"
|
||||||
#include "catalog/pg_type.h"
|
#include "catalog/pg_type.h"
|
||||||
|
#include "parser/analyze.h"
|
||||||
#include "parser/parse_clause.h"
|
#include "parser/parse_clause.h"
|
||||||
#include "parser/parse_expr.h"
|
#include "parser/parse_expr.h"
|
||||||
#include "parser/parse_node.h"
|
#include "parser/parse_node.h"
|
||||||
@ -371,3 +372,28 @@ transformSortClause(ParseState *pstate,
|
|||||||
|
|
||||||
return sortlist;
|
return sortlist;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* transformUnionClause -
|
||||||
|
* transform a Union clause
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
List *
|
||||||
|
transformUnionClause(List *unionClause, List *targetlist)
|
||||||
|
{
|
||||||
|
List *union_list = NIL;
|
||||||
|
QueryTreeList *qlist;
|
||||||
|
int i;
|
||||||
|
TargetEntry
|
||||||
|
if (unionClause)
|
||||||
|
{
|
||||||
|
qlist = parse_analyze(unionClause);
|
||||||
|
|
||||||
|
for (i=0; i < qlist->len; i++)
|
||||||
|
union_list = lappend(union_list, qlist->qtrees[i]);
|
||||||
|
/* we need to check return types are consistent here */
|
||||||
|
return union_list;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return NIL;
|
||||||
|
}
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright (c) 1994, Regents of the University of California
|
* Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: psqlHelp.h,v 1.34 1997/12/04 00:27:37 scrappy Exp $
|
* $Id: psqlHelp.h,v 1.35 1997/12/29 01:13:16 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -179,7 +179,12 @@ static struct _helpStruct QL_HELP[] = {
|
|||||||
"rollback [transaction|work]"},
|
"rollback [transaction|work]"},
|
||||||
{"select",
|
{"select",
|
||||||
"retrieve tuples",
|
"retrieve tuples",
|
||||||
"select [distinct on <attr>] <expr1> [as <attr1>], ... <exprN> [as <attrN>]\n\t[into table <class_name>] [from <from_list>]\n\t[where <qual>]\n\t[order by <attr1>\n\t\t[using <op1>],..<attrN> [[using <opN>] | ASC | DESC]];"},
|
"select [distinct on <attr>] <expr1> [as <attr1>], ... <exprN> [as <attrN>]\n\
|
||||||
|
\t[into table <class_name>]\n\
|
||||||
|
\t[from <from_list>]\n\
|
||||||
|
\t[where <qual>]\n\
|
||||||
|
\t[order by <attr1> [ASC | DESC] [using <op1>], ... <attrN> ]\n\
|
||||||
|
\t[union [all] select ...];"},
|
||||||
{"set",
|
{"set",
|
||||||
"set run-time environment",
|
"set run-time environment",
|
||||||
"set DateStyle to {'ISO' | 'SQL' | 'Postgres' | 'European' | 'US' | 'NonEuropean'}\nset GEQO to {'ON[=#]' | 'OFF'}\nset R_PLANS to {'ON' | 'OFF'}"},
|
"set DateStyle to {'ISO' | 'SQL' | 'Postgres' | 'European' | 'US' | 'NonEuropean'}\nset GEQO to {'ON[=#]' | 'OFF'}\nset R_PLANS to {'ON' | 'OFF'}"},
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright (c) 1994, Regents of the University of California
|
* Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: prep.h,v 1.10 1997/12/24 06:06:58 momjian Exp $
|
* $Id: prep.h,v 1.11 1997/12/29 01:13:23 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -27,18 +27,10 @@ extern List *cnfify(Expr *qual, bool removeAndFlag);
|
|||||||
extern List *preprocess_targetlist(List *tlist, int command_type,
|
extern List *preprocess_targetlist(List *tlist, int command_type,
|
||||||
Index result_relation, List *range_table);
|
Index result_relation, List *range_table);
|
||||||
|
|
||||||
/*
|
|
||||||
* prototypes for prepunion.h
|
|
||||||
*/
|
|
||||||
typedef enum UnionFlag
|
|
||||||
{
|
|
||||||
INHERITS_FLAG, UNION_FLAG, VERSION_FLAG
|
|
||||||
} UnionFlag;
|
|
||||||
|
|
||||||
extern List *find_all_inheritors(List *unexamined_relids,
|
extern List *find_all_inheritors(List *unexamined_relids,
|
||||||
List *examined_relids);
|
List *examined_relids);
|
||||||
extern int first_matching_rt_entry(List *rangetable, UnionFlag flag);
|
extern int first_inherit_rt_entry(List *rangetable);
|
||||||
extern Append *plan_union_queries(Index rt_index, Query *parse,
|
extern Append *plan_union_queries(Query *parse);
|
||||||
UnionFlag flag);
|
extern Append *plan_inherit_queries(Query *parse, Index rt_index);
|
||||||
|
|
||||||
#endif /* PREP_H */
|
#endif /* PREP_H */
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright (c) 1994, Regents of the University of California
|
* Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: parse_clause.h,v 1.3 1997/11/26 03:43:09 momjian Exp $
|
* $Id: parse_clause.h,v 1.4 1997/12/29 01:13:28 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -26,6 +26,7 @@ extern List *transformGroupClause(ParseState *pstate, List *grouplist,
|
|||||||
extern List *transformSortClause(ParseState *pstate,
|
extern List *transformSortClause(ParseState *pstate,
|
||||||
List *orderlist, List *targetlist,
|
List *orderlist, List *targetlist,
|
||||||
char *uniqueFlag);
|
char *uniqueFlag);
|
||||||
|
extern List *transformUnionClause(List *unionClause, List *targetlist);
|
||||||
|
|
||||||
#endif /* PARSE_CLAUSE_H */
|
#endif /* PARSE_CLAUSE_H */
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
.\" This is -*-nroff-*-
|
.\" This is -*-nroff-*-
|
||||||
.\" XXX standard disclaimer belongs here....
|
.\" XXX standard disclaimer belongs here....
|
||||||
.\" $Header: /cvsroot/pgsql/src/man/Attic/select.l,v 1.2 1996/12/11 00:28:09 momjian Exp $
|
.\" $Header: /cvsroot/pgsql/src/man/Attic/select.l,v 1.3 1997/12/29 01:13:37 momjian Exp $
|
||||||
.TH SELECT SQL 11/05/95 PostgreSQL PostgreSQL
|
.TH SELECT SQL 11/05/95 PostgreSQL PostgreSQL
|
||||||
.SH NAME
|
.SH NAME
|
||||||
select \(em retrieve instances from a class
|
select \(em retrieve instances from a class
|
||||||
@ -12,9 +12,10 @@ select \(em retrieve instances from a class
|
|||||||
[\fBinto\fR \fBtable\fR classname]
|
[\fBinto\fR \fBtable\fR classname]
|
||||||
[\fBfrom\fR from-list]
|
[\fBfrom\fR from-list]
|
||||||
[\fBwhere\fR where-clause]
|
[\fBwhere\fR where-clause]
|
||||||
[\fBgroup by\fR attr_name1 {, attr_name-i....}
|
[\fBgroup by\fR attr_name1 {, attr_name-i....}]
|
||||||
[\fBorder by\fR attr_name1
|
[\fBorder by\fR attr_name1 [\fBasc\fR | \fBdesc\fR] [\fBusing op1\fR] {, attr_namei...}]
|
||||||
[\fBusing op1\fR] {, attr_namei [\fBusing opi\fR] }
|
[\fBunion {all} select\fR ...]
|
||||||
|
|
||||||
.fi
|
.fi
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
.BR Select
|
.BR Select
|
||||||
|
Loading…
x
Reference in New Issue
Block a user