diff options
Diffstat (limited to 'src/backend/optimizer/prep/prepunion.c')
-rw-r--r-- | src/backend/optimizer/prep/prepunion.c | 382 |
1 files changed, 223 insertions, 159 deletions
diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c index c0386d2a126..5cb89aac867 100644 --- a/src/backend/optimizer/prep/prepunion.c +++ b/src/backend/optimizer/prep/prepunion.c @@ -7,7 +7,7 @@ * * * 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/planmain.h" -static List *plan_union_query(List *relids, Index rt_index, - RangeTblEntry *rt_entry, Query *parse, UnionFlag flag, +static List *plan_inherit_query(List *relids, Index rt_index, + RangeTblEntry *rt_entry, Query *parse, List **union_rtentriesPtr); static RangeTblEntry *new_rangetable_entry(Oid new_relid, RangeTblEntry *old_entry); @@ -48,83 +48,158 @@ static Append *make_append(List *unionplans, List *unionrts, Index rt_index, /* - * find-all-inheritors - - * Returns a list of relids corresponding to relations that inherit - * attributes from any relations listed in either of the argument relid - * lists. + * plan-union-queries-- + * + * Plans the queries for a given UNION. + * + * Returns a list containing a list of plans and a list of rangetables */ -List * -find_all_inheritors(List *unexamined_relids, - List *examined_relids) +Append * +plan_union_queries(Query *parse) { - List *new_inheritors = NIL; - List *new_examined_relids = NIL; - List *new_unexamined_relids = NIL; - + List *union_plans = NIL, *ulist, *unionall_queries, *union_rts, + *last_union = NIL; + bool union_all_found = false, union_found = false, + last_unionall_flag = false; + /* - * Find all relations which inherit from members of - * 'unexamined-relids' and store them in 'new-inheritors'. + * 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 + * } + * */ - List *rels = NIL; - List *newrels = NIL; - foreach(rels, unexamined_relids) + foreach(ulist, parse->unionClause) { - newrels = (List *) LispUnioni(find_inheritance_children(lfirsti(rels)), - newrels); - } - new_inheritors = newrels; + Query *union_query = lfirst(ulist); - new_examined_relids = (List *) LispUnioni(examined_relids, unexamined_relids); - new_unexamined_relids = set_differencei(new_inheritors, - new_examined_relids); + if (union_query->unionall) + union_all_found = true; + else + { + union_found = true; + last_union = ulist; + } + last_unionall_flag = union_query->unionall; + } - if (new_unexamined_relids == NULL) + /* Is this a simple one */ + if (!union_all_found || + !union_found || + /* A trailing UNION negates the affect of earlier UNION ALLs */ + !last_unionall_flag) { - return (new_examined_relids); + 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 { - return (find_all_inheritors(new_unexamined_relids, - new_examined_relids)); - } -} + /* + * 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. + */ -/* - * first-matching-rt-entry - - * Given a rangetable, find the first rangetable entry that represents - * the appropriate special case. - * - * Returns a rangetable index., Returns -1 if no matches - */ -int -first_matching_rt_entry(List *rangetable, UnionFlag flag) -{ - int count = 0; - List *temp = NIL; + /* save off everthing past the last UNION */ + unionall_queries = lnext(last_union); - foreach(temp, rangetable) - { - RangeTblEntry *rt_entry = lfirst(temp); + /* 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); - switch (flag) + /* Append the remainging UNION ALLs */ + foreach(ulist, unionall_queries) { - case INHERITS_FLAG: - if (rt_entry->inh) - return count + 1; - break; - default: - break; + Query *unionall_query = lfirst(ulist); + + union_plans = lappend(union_plans, planner(unionall_query)); + union_rts = lappend(union_rts, unionall_query->rtable); } - count++; } + + /* 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 (-1); + return (make_append(union_plans, + union_rts, + 0, + NULL, + ((Plan *) lfirst(union_plans))->targetlist)); } /* - * plan-union-queries-- + * plan-inherit-queries-- * * Plans the queries for a given parent relation. * @@ -133,122 +208,45 @@ first_matching_rt_entry(List *rangetable, UnionFlag flag) * XXX - what exactly does this mean, look for make_append */ Append * -plan_union_queries(Index rt_index, - Query *parse, - UnionFlag flag) +plan_inherit_queries(Query *parse, Index rt_index) { 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 */ + List *rangetable = parse->rtable; + RangeTblEntry *rt_entry = rt_fetch(rt_index, rangetable); + List *union_rt_entries = NIL; + List *union_relids = NIL; - 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; + 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; - return (make_append(union_plans, union_rts, - rt_index /* is 0, none */, NULL, - ((Plan *) lfirst(union_plans))->targetlist)); - } - break; + union_plans = plan_inherit_query(union_relids, rt_index, rt_entry, + parse, &union_rt_entries); -#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 */ + return (make_append(union_plans, + NULL, + rt_index, + union_rt_entries, + ((Plan *) lfirst(union_plans))->targetlist)); } - /* - * plan-union-query-- + * plan-inherit-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, +plan_inherit_query(List *relids, Index rt_index, RangeTblEntry *rt_entry, Query *root, - UnionFlag flag, List **union_rtentriesPtr) { List *i; @@ -292,6 +290,74 @@ plan_union_query(List *relids, } /* + * find-all-inheritors - + * Returns a list of relids corresponding to relations that inherit + * attributes from any relations listed in either of the argument relid + * lists. + */ +List * +find_all_inheritors(List *unexamined_relids, + List *examined_relids) +{ + List *new_inheritors = NIL; + List *new_examined_relids = NIL; + List *new_unexamined_relids = NIL; + + /* + * Find all relations which inherit from members of + * 'unexamined-relids' and store them in 'new-inheritors'. + */ + List *rels = NIL; + List *newrels = NIL; + + foreach(rels, unexamined_relids) + { + newrels = (List *) LispUnioni(find_inheritance_children(lfirsti(rels)), + newrels); + } + new_inheritors = newrels; + + new_examined_relids = (List *) LispUnioni(examined_relids, unexamined_relids); + new_unexamined_relids = set_differencei(new_inheritors, + new_examined_relids); + + if (new_unexamined_relids == NULL) + { + return (new_examined_relids); + } + else + { + return (find_all_inheritors(new_unexamined_relids, + new_examined_relids)); + } +} + +/* + * first-inherit-rt-entry - + * Given a rangetable, find the first rangetable entry that represents + * the appropriate special case. + * + * Returns a rangetable index., Returns -1 if no matches + */ +int +first_inherit_rt_entry(List *rangetable) +{ + int count = 0; + List *temp = NIL; + + foreach(temp, rangetable) + { + RangeTblEntry *rt_entry = lfirst(temp); + + if (rt_entry->inh) + return count + 1; + count++; + } + + return -1; +} + +/* * new-rangetable-entry - * Replaces the name and relid of 'old-entry' with the values for * 'new-relid'. @@ -367,8 +433,6 @@ fix_parsetree_attnums_nodes(Index rt_index, Oid old_typeid, new_typeid; -/* old_typeid = RelationIdGetTypeId(old_relid);*/ -/* new_typeid = RelationIdGetTypeId(new_relid);*/ old_typeid = old_relid; new_typeid = new_relid; |