1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-19 13:42:17 +03:00

First cut at full support for OUTER JOINs. There are still a few loose

ends to clean up (see my message of same date to pghackers), but mostly
it works.  INITDB REQUIRED!
This commit is contained in:
Tom Lane
2000-09-12 21:07:18 +00:00
parent b5c0ab278b
commit ed5003c584
93 changed files with 6386 additions and 4262 deletions

View File

@@ -14,7 +14,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planmain.c,v 1.58 2000/08/13 02:50:07 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planmain.c,v 1.59 2000/09/12 21:06:54 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -28,6 +28,7 @@
#include "optimizer/paths.h"
#include "optimizer/planmain.h"
#include "optimizer/tlist.h"
#include "parser/parsetree.h"
#include "utils/memutils.h"
@@ -41,11 +42,8 @@ static Plan *subplanner(Query *root, List *flat_tlist, List *qual,
* not any fancier features.
*
* tlist is the target list the query should produce (NOT root->targetList!)
* qual is the qualification of the query (likewise!)
* tuple_fraction is the fraction of tuples we expect will be retrieved
*
* qual must already have been converted to implicit-AND form.
*
* Note: the Query node now also includes a query_pathkeys field, which
* is both an input and an output of query_planner(). The input value
* signals query_planner that the indicated sort order is wanted in the
@@ -75,9 +73,9 @@ static Plan *subplanner(Query *root, List *flat_tlist, List *qual,
Plan *
query_planner(Query *root,
List *tlist,
List *qual,
double tuple_fraction)
{
List *normal_qual;
List *noncachable_qual;
List *constant_qual;
List *var_only_tlist;
@@ -96,7 +94,7 @@ query_planner(Query *root,
root->query_pathkeys = NIL; /* signal unordered result */
/* Make childless Result node to evaluate given tlist. */
return (Plan *) make_result(tlist, (Node *) qual, (Plan *) NULL);
return (Plan *) make_result(tlist, root->qual, (Plan *) NULL);
}
/*
@@ -111,10 +109,12 @@ query_planner(Query *root,
* noncachable functions but no vars, such as "WHERE random() < 0.5".
* These cannot be treated as normal restriction or join quals, but
* they're not constants either. Instead, attach them to the qpqual
* of the top-level plan, so that they get evaluated once per potential
* of the top plan, so that they get evaluated once per potential
* output tuple.
*/
qual = pull_constant_clauses(qual, &noncachable_qual, &constant_qual);
normal_qual = pull_constant_clauses((List *) root->qual,
&noncachable_qual,
&constant_qual);
/*
* Create a target list that consists solely of (resdom var) target
@@ -132,7 +132,7 @@ query_planner(Query *root,
/*
* Choose the best access path and build a plan for it.
*/
subplan = subplanner(root, var_only_tlist, qual, tuple_fraction);
subplan = subplanner(root, var_only_tlist, normal_qual, tuple_fraction);
/*
* Handle the noncachable quals.
@@ -188,6 +188,8 @@ subplanner(Query *root,
List *qual,
double tuple_fraction)
{
List *joined_rels;
List *brel;
RelOptInfo *final_rel;
Plan *resultplan;
MemoryContext mycontext;
@@ -196,7 +198,7 @@ subplanner(Query *root,
Path *presortedpath;
/*
* Initialize the targetlist and qualification, adding entries to
* Examine the targetlist and qualifications, adding entries to
* base_rel_list as relation references are found (e.g., in the
* qualification, the targetlist, etc.). Restrict and join clauses
* are added to appropriate lists belonging to the mentioned
@@ -207,13 +209,29 @@ subplanner(Query *root,
root->join_rel_list = NIL;
root->equi_key_list = NIL;
make_var_only_tlist(root, flat_tlist);
build_base_rel_tlists(root, flat_tlist);
(void) add_join_quals_to_rels(root, (Node *) root->jointree);
/* this must happen after add_join_quals_to_rels: */
add_restrict_and_join_to_rels(root, qual);
/*
* Make sure we have RelOptInfo nodes for all relations used.
* Make sure we have RelOptInfo nodes for all relations to be joined.
*/
add_missing_rels_to_query(root);
joined_rels = add_missing_rels_to_query(root, (Node *) root->jointree);
/*
* Check that the join tree includes all the base relations used in
* the query --- otherwise, the parser or rewriter messed up.
*/
foreach(brel, root->base_rel_list)
{
RelOptInfo *baserel = (RelOptInfo *) lfirst(brel);
int relid = lfirsti(baserel->relids);
if (! ptrMember(baserel, joined_rels))
elog(ERROR, "Internal error: no jointree entry for rel %s (%d)",
rt_fetch(relid, root->rtable)->eref->relname, relid);
}
/*
* Use the completed lists of equijoined keys to deduce any implied
@@ -258,12 +276,11 @@ subplanner(Query *root,
* We expect to end up here for a trivial INSERT ... VALUES query
* (which will have a target relation, so it gets past
* query_planner's check for empty range table; but the target rel
* is unreferenced and not marked inJoinSet, so we find there is
* nothing to join).
* is not in the join tree, so we find there is nothing to join).
*
* It's also possible to get here if the query was rewritten by the
* rule processor (creating rangetable entries not marked
* inJoinSet) but the rules either did nothing or were simplified
* rule processor (creating dummy rangetable entries that are not in
* the join tree) but the rules either did nothing or were simplified
* to nothing by constant-expression folding. So, don't complain.
*/
root->query_pathkeys = NIL; /* signal unordered result */