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:
@ -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)
|
||||
{
|
||||
|
Reference in New Issue
Block a user