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

IN clauses appearing at top level of WHERE can now be handled as joins.

There are two implementation techniques: the executor understands a new
JOIN_IN jointype, which emits at most one matching row per left-hand row,
or the result of the IN's sub-select can be fed through a DISTINCT filter
and then joined as an ordinary relation.
Along the way, some minor code cleanup in the optimizer; notably, break
out most of the jointree-rearrangement preprocessing in planner.c and
put it in a new file prep/prepjointree.c.
This commit is contained in:
Tom Lane
2003-01-20 18:55:07 +00:00
parent be2b660ecd
commit bdfbfde1b1
47 changed files with 2075 additions and 875 deletions

View File

@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.131 2003/01/15 23:10:32 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.132 2003/01/20 18:54:52 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -26,6 +26,7 @@
#include "optimizer/restrictinfo.h"
#include "optimizer/tlist.h"
#include "optimizer/var.h"
#include "parser/parse_clause.h"
#include "parser/parse_expr.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
@ -36,6 +37,7 @@ static Join *create_join_plan(Query *root, JoinPath *best_path);
static Append *create_append_plan(Query *root, AppendPath *best_path);
static Result *create_result_plan(Query *root, ResultPath *best_path);
static Material *create_material_plan(Query *root, MaterialPath *best_path);
static Plan *create_unique_plan(Query *root, UniquePath *best_path);
static SeqScan *create_seqscan_plan(Path *best_path, List *tlist,
List *scan_clauses);
static IndexScan *create_indexscan_plan(Query *root, IndexPath *best_path,
@ -146,6 +148,10 @@ create_plan(Query *root, Path *best_path)
plan = (Plan *) create_material_plan(root,
(MaterialPath *) best_path);
break;
case T_Unique:
plan = (Plan *) create_unique_plan(root,
(UniquePath *) best_path);
break;
default:
elog(ERROR, "create_plan: unknown pathtype %d",
best_path->pathtype);
@ -399,6 +405,97 @@ create_material_plan(Query *root, MaterialPath *best_path)
return plan;
}
/*
* create_unique_plan
* Create a Unique plan for 'best_path' and (recursively) plans
* for its subpaths.
*
* Returns a Plan node.
*/
static Plan *
create_unique_plan(Query *root, UniquePath *best_path)
{
Plan *plan;
Plan *subplan;
List *sub_targetlist;
List *l;
subplan = create_plan(root, best_path->subpath);
/*
* If the subplan came from an IN subselect (currently always the case),
* we need to instantiate the correct output targetlist for the subselect,
* rather than using the flattened tlist.
*/
sub_targetlist = NIL;
foreach(l, root->in_info_list)
{
InClauseInfo *ininfo = (InClauseInfo *) lfirst(l);
if (sameseti(ininfo->righthand, best_path->path.parent->relids))
{
sub_targetlist = ininfo->sub_targetlist;
break;
}
}
if (sub_targetlist)
{
/*
* Transform list of plain Vars into targetlist
*/
List *newtlist = NIL;
int resno = 1;
foreach(l, sub_targetlist)
{
Node *tlexpr = lfirst(l);
TargetEntry *tle;
tle = makeTargetEntry(makeResdom(resno,
exprType(tlexpr),
exprTypmod(tlexpr),
NULL,
false),
(Expr *) tlexpr);
newtlist = lappend(newtlist, tle);
resno++;
}
/*
* If the top plan node can't do projections, we need to add a
* Result node to help it along.
*
* Currently, the only non-projection-capable plan type
* we can see here is Append.
*/
if (IsA(subplan, Append))
subplan = (Plan *) make_result(newtlist, NULL, subplan);
else
subplan->targetlist = newtlist;
}
if (best_path->use_hash)
{
elog(ERROR, "create_unique_plan: hash case not implemented yet");
plan = NULL;
}
else
{
List *sort_tlist;
List *sortList;
sort_tlist = new_unsorted_tlist(subplan->targetlist);
sortList = addAllTargetsToSortList(NIL, sort_tlist);
plan = (Plan *) make_sort_from_sortclauses(root, sort_tlist,
subplan, sortList);
plan = (Plan *) make_unique(sort_tlist, plan, sortList);
}
plan->plan_rows = best_path->rows;
return plan;
}
/*****************************************************************************
*
@ -1548,6 +1645,52 @@ make_sort_from_pathkeys(Query *root, Plan *lefttree,
return make_sort(root, sort_tlist, lefttree, numsortkeys);
}
/*
* make_sort_from_sortclauses
* Create sort plan to sort according to given sortclauses
*
* 'tlist' is the targetlist
* 'lefttree' is the node which yields input tuples
* 'sortcls' is a list of SortClauses
*/
Sort *
make_sort_from_sortclauses(Query *root, List *tlist,
Plan *lefttree, List *sortcls)
{
List *sort_tlist;
List *i;
int keyno = 0;
/*
* First make a copy of the tlist so that we don't corrupt the
* original.
*/
sort_tlist = new_unsorted_tlist(tlist);
foreach(i, sortcls)
{
SortClause *sortcl = (SortClause *) lfirst(i);
TargetEntry *tle = get_sortgroupclause_tle(sortcl, sort_tlist);
Resdom *resdom = tle->resdom;
/*
* Check for the possibility of duplicate order-by clauses --- the
* parser should have removed 'em, but the executor will get
* terribly confused if any get through!
*/
if (resdom->reskey == 0)
{
/* OK, insert the ordering info needed by the executor. */
resdom->reskey = ++keyno;
resdom->reskeyop = sortcl->sortop;
}
}
Assert(keyno > 0);
return make_sort(root, sort_tlist, lefttree, keyno);
}
Material *
make_material(List *tlist, Plan *lefttree)
{