diff options
Diffstat (limited to 'src/backend/optimizer/plan/createplan.c')
-rw-r--r-- | src/backend/optimizer/plan/createplan.c | 279 |
1 files changed, 193 insertions, 86 deletions
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index c049f5d86b6..96dc3327b7f 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.95 2000/08/13 02:50:06 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.96 2000/09/12 21:06:53 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -42,36 +42,47 @@ static IndexScan *create_indexscan_node(Query *root, IndexPath *best_path, static TidScan *create_tidscan_node(TidPath *best_path, List *tlist, List *scan_clauses); static NestLoop *create_nestloop_node(NestPath *best_path, List *tlist, - List *clauses, Plan *outer_node, List *outer_tlist, - Plan *inner_node, List *inner_tlist); + List *joinclauses, List *otherclauses, + Plan *outer_node, List *outer_tlist, + Plan *inner_node, List *inner_tlist); static MergeJoin *create_mergejoin_node(MergePath *best_path, List *tlist, - List *clauses, Plan *outer_node, List *outer_tlist, - Plan *inner_node, List *inner_tlist); + List *joinclauses, List *otherclauses, + Plan *outer_node, List *outer_tlist, + Plan *inner_node, List *inner_tlist); static HashJoin *create_hashjoin_node(HashPath *best_path, List *tlist, - List *clauses, Plan *outer_node, List *outer_tlist, - Plan *inner_node, List *inner_tlist); + List *joinclauses, List *otherclauses, + Plan *outer_node, List *outer_tlist, + Plan *inner_node, List *inner_tlist); static List *fix_indxqual_references(List *indexquals, IndexPath *index_path); static List *fix_indxqual_sublist(List *indexqual, int baserelid, Oid relam, Form_pg_index index); static Node *fix_indxqual_operand(Node *node, int baserelid, Form_pg_index index, Oid *opclass); +static SeqScan *make_seqscan(List *qptlist, List *qpqual, Index scanrelid); static IndexScan *make_indexscan(List *qptlist, List *qpqual, Index scanrelid, List *indxid, List *indxqual, List *indxqualorig, ScanDirection indexscandir); static TidScan *make_tidscan(List *qptlist, List *qpqual, Index scanrelid, List *tideval); -static NestLoop *make_nestloop(List *qptlist, List *qpqual, Plan *lefttree, - Plan *righttree); -static HashJoin *make_hashjoin(List *tlist, List *qpqual, - List *hashclauses, Plan *lefttree, Plan *righttree); +static NestLoop *make_nestloop(List *tlist, + List *joinclauses, List *otherclauses, + Plan *lefttree, Plan *righttree, + JoinType jointype); +static HashJoin *make_hashjoin(List *tlist, + List *joinclauses, List *otherclauses, + List *hashclauses, + Plan *lefttree, Plan *righttree, + JoinType jointype); static Hash *make_hash(List *tlist, Node *hashkey, Plan *lefttree); -static MergeJoin *make_mergejoin(List *tlist, List *qpqual, - List *mergeclauses, Plan *righttree, Plan *lefttree); +static MergeJoin *make_mergejoin(List *tlist, + List *joinclauses, List *otherclauses, + List *mergeclauses, + Plan *lefttree, Plan *righttree, + JoinType jointype); static void copy_path_costsize(Plan *dest, Path *src); static void copy_plan_costsize(Plan *dest, Plan *src); -static SeqScan *make_seqscan(List *qptlist, List *qpqual, Index scanrelid); /* * create_plan @@ -195,7 +206,8 @@ create_join_node(Query *root, JoinPath *best_path, List *tlist) List *outer_tlist; Plan *inner_node; List *inner_tlist; - List *clauses; + List *joinclauses; + List *otherclauses; Join *retval = NULL; outer_node = create_plan(root, best_path->outerjoinpath); @@ -204,14 +216,25 @@ create_join_node(Query *root, JoinPath *best_path, List *tlist) inner_node = create_plan(root, best_path->innerjoinpath); inner_tlist = inner_node->targetlist; - clauses = get_actual_clauses(best_path->joinrestrictinfo); + if (IS_OUTER_JOIN(best_path->jointype)) + { + get_actual_join_clauses(best_path->joinrestrictinfo, + &joinclauses, &otherclauses); + } + else + { + /* We can treat all clauses alike for an inner join */ + joinclauses = get_actual_clauses(best_path->joinrestrictinfo); + otherclauses = NIL; + } switch (best_path->path.pathtype) { case T_MergeJoin: retval = (Join *) create_mergejoin_node((MergePath *) best_path, tlist, - clauses, + joinclauses, + otherclauses, outer_node, outer_tlist, inner_node, @@ -220,7 +243,8 @@ create_join_node(Query *root, JoinPath *best_path, List *tlist) case T_HashJoin: retval = (Join *) create_hashjoin_node((HashPath *) best_path, tlist, - clauses, + joinclauses, + otherclauses, outer_node, outer_tlist, inner_node, @@ -229,7 +253,8 @@ create_join_node(Query *root, JoinPath *best_path, List *tlist) case T_NestLoop: retval = (Join *) create_nestloop_node((NestPath *) best_path, tlist, - clauses, + joinclauses, + otherclauses, outer_node, outer_tlist, inner_node, @@ -411,30 +436,6 @@ create_indexscan_node(Query *root, return scan_node; } -static TidScan * -make_tidscan(List *qptlist, - List *qpqual, - Index scanrelid, - List *tideval) -{ - TidScan *node = makeNode(TidScan); - Plan *plan = &node->scan.plan; - - /* cost should be inserted by caller */ - plan->state = (EState *) NULL; - plan->targetlist = qptlist; - plan->qual = qpqual; - plan->lefttree = NULL; - plan->righttree = NULL; - node->scan.scanrelid = scanrelid; - node->tideval = copyObject(tideval); /* XXX do we really need a - * copy? */ - node->needRescan = false; - node->scan.scanstate = (CommonScanState *) NULL; - - return node; -} - /* * create_tidscan_node * Returns a tidscan node for the base relation scanned by 'best_path' @@ -488,7 +489,8 @@ create_tidscan_node(TidPath *best_path, List *tlist, List *scan_clauses) static NestLoop * create_nestloop_node(NestPath *best_path, List *tlist, - List *clauses, + List *joinclauses, + List *otherclauses, Plan *outer_node, List *outer_tlist, Plan *inner_node, @@ -535,7 +537,8 @@ create_nestloop_node(NestPath *best_path, * attnos, and may have been commuted as well). */ if (length(indxqualorig) == 1) /* single indexscan? */ - clauses = set_difference(clauses, lfirst(indxqualorig)); + joinclauses = set_difference(joinclauses, + lfirst(indxqualorig)); /* only refs to outer vars get changed in the inner indexqual */ innerscan->indxqualorig = join_references(indxqualorig, @@ -577,15 +580,26 @@ create_nestloop_node(NestPath *best_path, inner_node); } + /* + * Set quals to contain INNER/OUTER var references. + */ + joinclauses = join_references(joinclauses, + outer_tlist, + inner_tlist, + (Index) 0); + otherclauses = join_references(otherclauses, + outer_tlist, + inner_tlist, + (Index) 0); + join_node = make_nestloop(tlist, - join_references(clauses, - outer_tlist, - inner_tlist, - (Index) 0), + joinclauses, + otherclauses, outer_node, - inner_node); + inner_node, + best_path->jointype); - copy_path_costsize(&join_node->join, &best_path->path); + copy_path_costsize(&join_node->join.plan, &best_path->path); return join_node; } @@ -593,14 +607,14 @@ create_nestloop_node(NestPath *best_path, static MergeJoin * create_mergejoin_node(MergePath *best_path, List *tlist, - List *clauses, + List *joinclauses, + List *otherclauses, Plan *outer_node, List *outer_tlist, Plan *inner_node, List *inner_tlist) { - List *qpqual, - *mergeclauses; + List *mergeclauses; MergeJoin *join_node; mergeclauses = get_actual_clauses(best_path->path_mergeclauses); @@ -610,10 +624,18 @@ create_mergejoin_node(MergePath *best_path, * the list of quals that must be checked as qpquals. Set those * clauses to contain INNER/OUTER var references. */ - qpqual = join_references(set_difference(clauses, mergeclauses), - outer_tlist, - inner_tlist, - (Index) 0); + joinclauses = join_references(set_difference(joinclauses, mergeclauses), + outer_tlist, + inner_tlist, + (Index) 0); + + /* + * Fix the additional qpquals too. + */ + otherclauses = join_references(otherclauses, + outer_tlist, + inner_tlist, + (Index) 0); /* * Now set the references in the mergeclauses and rearrange them so @@ -640,13 +662,54 @@ create_mergejoin_node(MergePath *best_path, inner_node, best_path->innersortkeys); + /* + * The executor requires the inner side of a mergejoin to support "mark" + * and "restore" operations. Not all plan types do, so we must be careful + * not to generate an invalid plan. If necessary, an invalid inner plan + * can be handled by inserting a Materialize node. + * + * Since the inner side must be ordered, and only Sorts and IndexScans can + * create order to begin with, you might think there's no problem --- but + * you'd be wrong. Nestloop and merge joins can *preserve* the order of + * their inputs, so they can be selected as the input of a mergejoin, + * and that won't work in the present executor. + * + * Doing this here is a bit of a kluge since the cost of the Materialize + * wasn't taken into account in our earlier decisions. But Materialize + * is hard to estimate a cost for, and the above consideration shows that + * this is a rare case anyway, so this seems an acceptable way to proceed. + * + * This check must agree with ExecMarkPos/ExecRestrPos in + * executor/execAmi.c! + */ + switch (nodeTag(inner_node)) + { + case T_SeqScan: + case T_IndexScan: + case T_Material: + case T_Sort: + /* OK, these inner plans support mark/restore */ + break; + + default: + /* Ooops, need to materialize the inner plan */ + inner_node = (Plan *) make_material(inner_tlist, + inner_node); + break; + } + + /* + * Now we can build the mergejoin node. + */ join_node = make_mergejoin(tlist, - qpqual, + joinclauses, + otherclauses, mergeclauses, + outer_node, inner_node, - outer_node); + best_path->jpath.jointype); - copy_path_costsize(&join_node->join, &best_path->jpath.path); + copy_path_costsize(&join_node->join.plan, &best_path->jpath.path); return join_node; } @@ -654,13 +717,13 @@ create_mergejoin_node(MergePath *best_path, static HashJoin * create_hashjoin_node(HashPath *best_path, List *tlist, - List *clauses, + List *joinclauses, + List *otherclauses, Plan *outer_node, List *outer_tlist, Plan *inner_node, List *inner_tlist) { - List *qpqual; List *hashclauses; HashJoin *join_node; Hash *hash_node; @@ -679,10 +742,18 @@ create_hashjoin_node(HashPath *best_path, * the list of quals that must be checked as qpquals. Set those * clauses to contain INNER/OUTER var references. */ - qpqual = join_references(set_difference(clauses, hashclauses), - outer_tlist, - inner_tlist, - (Index) 0); + joinclauses = join_references(set_difference(joinclauses, hashclauses), + outer_tlist, + inner_tlist, + (Index) 0); + + /* + * Fix the additional qpquals too. + */ + otherclauses = join_references(otherclauses, + outer_tlist, + inner_tlist, + (Index) 0); /* * Now set the references in the hashclauses and rearrange them so @@ -701,12 +772,14 @@ create_hashjoin_node(HashPath *best_path, */ hash_node = make_hash(inner_tlist, innerhashkey, inner_node); join_node = make_hashjoin(tlist, - qpqual, + joinclauses, + otherclauses, hashclauses, outer_node, - (Plan *) hash_node); + (Plan *) hash_node, + best_path->jpath.jointype); - copy_path_costsize(&join_node->join, &best_path->jpath.path); + copy_path_costsize(&join_node->join.plan, &best_path->jpath.path); return join_node; } @@ -1065,45 +1138,75 @@ make_indexscan(List *qptlist, return node; } +static TidScan * +make_tidscan(List *qptlist, + List *qpqual, + Index scanrelid, + List *tideval) +{ + TidScan *node = makeNode(TidScan); + Plan *plan = &node->scan.plan; + + /* cost should be inserted by caller */ + plan->state = (EState *) NULL; + plan->targetlist = qptlist; + plan->qual = qpqual; + plan->lefttree = NULL; + plan->righttree = NULL; + node->scan.scanrelid = scanrelid; + node->tideval = copyObject(tideval); /* XXX do we really need a + * copy? */ + node->needRescan = false; + node->scan.scanstate = (CommonScanState *) NULL; + + return node; +} + static NestLoop * -make_nestloop(List *qptlist, - List *qpqual, +make_nestloop(List *tlist, + List *joinclauses, + List *otherclauses, Plan *lefttree, - Plan *righttree) + Plan *righttree, + JoinType jointype) { NestLoop *node = makeNode(NestLoop); - Plan *plan = &node->join; + Plan *plan = &node->join.plan; /* cost should be inserted by caller */ plan->state = (EState *) NULL; - plan->targetlist = qptlist; - plan->qual = qpqual; + plan->targetlist = tlist; + plan->qual = otherclauses; plan->lefttree = lefttree; plan->righttree = righttree; - node->nlstate = (NestLoopState *) NULL; + node->join.jointype = jointype; + node->join.joinqual = joinclauses; return node; } static HashJoin * make_hashjoin(List *tlist, - List *qpqual, + List *joinclauses, + List *otherclauses, List *hashclauses, Plan *lefttree, - Plan *righttree) + Plan *righttree, + JoinType jointype) { HashJoin *node = makeNode(HashJoin); - Plan *plan = &node->join; + Plan *plan = &node->join.plan; /* cost should be inserted by caller */ plan->state = (EState *) NULL; plan->targetlist = tlist; - plan->qual = qpqual; + plan->qual = otherclauses; plan->lefttree = lefttree; plan->righttree = righttree; node->hashclauses = hashclauses; - node->hashdone = false; + node->join.jointype = jointype; + node->join.joinqual = joinclauses; return node; } @@ -1133,21 +1236,25 @@ make_hash(List *tlist, Node *hashkey, Plan *lefttree) static MergeJoin * make_mergejoin(List *tlist, - List *qpqual, + List *joinclauses, + List *otherclauses, List *mergeclauses, + Plan *lefttree, Plan *righttree, - Plan *lefttree) + JoinType jointype) { MergeJoin *node = makeNode(MergeJoin); - Plan *plan = &node->join; + Plan *plan = &node->join.plan; /* cost should be inserted by caller */ plan->state = (EState *) NULL; plan->targetlist = tlist; - plan->qual = qpqual; + plan->qual = otherclauses; plan->lefttree = lefttree; plan->righttree = righttree; node->mergeclauses = mergeclauses; + node->join.jointype = jointype; + node->join.joinqual = joinclauses; return node; } |