mirror of https://github.com/postgres/postgres
Revise searching of subplan target lists to use something more efficient
than tlist_member calls. Building a large join tlist is still O(N^2), but with a much smaller constant factor than before.
This commit is contained in:
parent
0725065b37
commit
39cee73889
|
@ -9,7 +9,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/optimizer/plan/setrefs.c,v 1.110 2005/05/22 22:30:19 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/optimizer/plan/setrefs.c,v 1.111 2005/06/10 00:28:54 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -25,20 +25,34 @@
|
||||||
#include "utils/lsyscache.h"
|
#include "utils/lsyscache.h"
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
Index varno; /* RT index of Var */
|
||||||
|
AttrNumber varattno; /* attr number of Var */
|
||||||
|
AttrNumber resno; /* TLE position of Var */
|
||||||
|
} tlist_vinfo;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
List *tlist; /* underlying target list */
|
||||||
|
int num_vars; /* number of plain Var tlist entries */
|
||||||
|
bool has_non_vars; /* are there non-plain-Var entries? */
|
||||||
|
/* array of num_vars entries: */
|
||||||
|
tlist_vinfo vars[1]; /* VARIABLE LENGTH ARRAY */
|
||||||
|
} indexed_tlist; /* VARIABLE LENGTH STRUCT */
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
List *rtable;
|
List *rtable;
|
||||||
List *outer_tlist;
|
indexed_tlist *outer_itlist;
|
||||||
List *inner_tlist;
|
indexed_tlist *inner_itlist;
|
||||||
Index acceptable_rel;
|
Index acceptable_rel;
|
||||||
bool tlists_have_non_vars;
|
|
||||||
} join_references_context;
|
} join_references_context;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
|
indexed_tlist *subplan_itlist;
|
||||||
Index subvarno;
|
Index subvarno;
|
||||||
List *subplan_targetlist;
|
|
||||||
bool tlist_has_non_vars;
|
|
||||||
} replace_vars_with_subplan_refs_context;
|
} replace_vars_with_subplan_refs_context;
|
||||||
|
|
||||||
static Plan *set_subqueryscan_references(SubqueryScan *plan, List *rtable);
|
static Plan *set_subqueryscan_references(SubqueryScan *plan, List *rtable);
|
||||||
|
@ -51,22 +65,25 @@ static bool fix_expr_references_walker(Node *node, void *context);
|
||||||
static void set_join_references(Join *join, List *rtable);
|
static void set_join_references(Join *join, List *rtable);
|
||||||
static void set_inner_join_references(Plan *inner_plan,
|
static void set_inner_join_references(Plan *inner_plan,
|
||||||
List *rtable,
|
List *rtable,
|
||||||
List *outer_tlist,
|
indexed_tlist *outer_itlist);
|
||||||
bool tlists_have_non_vars);
|
|
||||||
static void set_uppernode_references(Plan *plan, Index subvarno);
|
static void set_uppernode_references(Plan *plan, Index subvarno);
|
||||||
static bool targetlist_has_non_vars(List *tlist);
|
static indexed_tlist *build_tlist_index(List *tlist);
|
||||||
|
static Var *search_indexed_tlist_for_var(Var *var,
|
||||||
|
indexed_tlist *itlist,
|
||||||
|
Index newvarno);
|
||||||
|
static Var *search_indexed_tlist_for_non_var(Node *node,
|
||||||
|
indexed_tlist *itlist,
|
||||||
|
Index newvarno);
|
||||||
static List *join_references(List *clauses,
|
static List *join_references(List *clauses,
|
||||||
List *rtable,
|
List *rtable,
|
||||||
List *outer_tlist,
|
indexed_tlist *outer_itlist,
|
||||||
List *inner_tlist,
|
indexed_tlist *inner_itlist,
|
||||||
Index acceptable_rel,
|
Index acceptable_rel);
|
||||||
bool tlists_have_non_vars);
|
|
||||||
static Node *join_references_mutator(Node *node,
|
static Node *join_references_mutator(Node *node,
|
||||||
join_references_context *context);
|
join_references_context *context);
|
||||||
static Node *replace_vars_with_subplan_refs(Node *node,
|
static Node *replace_vars_with_subplan_refs(Node *node,
|
||||||
Index subvarno,
|
indexed_tlist *subplan_itlist,
|
||||||
List *subplan_targetlist,
|
Index subvarno);
|
||||||
bool tlist_has_non_vars);
|
|
||||||
static Node *replace_vars_with_subplan_refs_mutator(Node *node,
|
static Node *replace_vars_with_subplan_refs_mutator(Node *node,
|
||||||
replace_vars_with_subplan_refs_context *context);
|
replace_vars_with_subplan_refs_context *context);
|
||||||
static bool fix_opfuncids_walker(Node *node, void *context);
|
static bool fix_opfuncids_walker(Node *node, void *context);
|
||||||
|
@ -689,32 +706,28 @@ set_join_references(Join *join, List *rtable)
|
||||||
{
|
{
|
||||||
Plan *outer_plan = join->plan.lefttree;
|
Plan *outer_plan = join->plan.lefttree;
|
||||||
Plan *inner_plan = join->plan.righttree;
|
Plan *inner_plan = join->plan.righttree;
|
||||||
List *outer_tlist = outer_plan->targetlist;
|
indexed_tlist *outer_itlist;
|
||||||
List *inner_tlist = inner_plan->targetlist;
|
indexed_tlist *inner_itlist;
|
||||||
bool tlists_have_non_vars;
|
|
||||||
|
|
||||||
tlists_have_non_vars = targetlist_has_non_vars(outer_tlist) ||
|
outer_itlist = build_tlist_index(outer_plan->targetlist);
|
||||||
targetlist_has_non_vars(inner_tlist);
|
inner_itlist = build_tlist_index(inner_plan->targetlist);
|
||||||
|
|
||||||
/* All join plans have tlist, qual, and joinqual */
|
/* All join plans have tlist, qual, and joinqual */
|
||||||
join->plan.targetlist = join_references(join->plan.targetlist,
|
join->plan.targetlist = join_references(join->plan.targetlist,
|
||||||
rtable,
|
rtable,
|
||||||
outer_tlist,
|
outer_itlist,
|
||||||
inner_tlist,
|
inner_itlist,
|
||||||
(Index) 0,
|
(Index) 0);
|
||||||
tlists_have_non_vars);
|
|
||||||
join->plan.qual = join_references(join->plan.qual,
|
join->plan.qual = join_references(join->plan.qual,
|
||||||
rtable,
|
rtable,
|
||||||
outer_tlist,
|
outer_itlist,
|
||||||
inner_tlist,
|
inner_itlist,
|
||||||
(Index) 0,
|
(Index) 0);
|
||||||
tlists_have_non_vars);
|
|
||||||
join->joinqual = join_references(join->joinqual,
|
join->joinqual = join_references(join->joinqual,
|
||||||
rtable,
|
rtable,
|
||||||
outer_tlist,
|
outer_itlist,
|
||||||
inner_tlist,
|
inner_itlist,
|
||||||
(Index) 0,
|
(Index) 0);
|
||||||
tlists_have_non_vars);
|
|
||||||
|
|
||||||
/* Now do join-type-specific stuff */
|
/* Now do join-type-specific stuff */
|
||||||
if (IsA(join, NestLoop))
|
if (IsA(join, NestLoop))
|
||||||
|
@ -722,8 +735,7 @@ set_join_references(Join *join, List *rtable)
|
||||||
/* This processing is split out to handle possible recursion */
|
/* This processing is split out to handle possible recursion */
|
||||||
set_inner_join_references(inner_plan,
|
set_inner_join_references(inner_plan,
|
||||||
rtable,
|
rtable,
|
||||||
outer_tlist,
|
outer_itlist);
|
||||||
tlists_have_non_vars);
|
|
||||||
}
|
}
|
||||||
else if (IsA(join, MergeJoin))
|
else if (IsA(join, MergeJoin))
|
||||||
{
|
{
|
||||||
|
@ -731,10 +743,9 @@ set_join_references(Join *join, List *rtable)
|
||||||
|
|
||||||
mj->mergeclauses = join_references(mj->mergeclauses,
|
mj->mergeclauses = join_references(mj->mergeclauses,
|
||||||
rtable,
|
rtable,
|
||||||
outer_tlist,
|
outer_itlist,
|
||||||
inner_tlist,
|
inner_itlist,
|
||||||
(Index) 0,
|
(Index) 0);
|
||||||
tlists_have_non_vars);
|
|
||||||
}
|
}
|
||||||
else if (IsA(join, HashJoin))
|
else if (IsA(join, HashJoin))
|
||||||
{
|
{
|
||||||
|
@ -742,11 +753,13 @@ set_join_references(Join *join, List *rtable)
|
||||||
|
|
||||||
hj->hashclauses = join_references(hj->hashclauses,
|
hj->hashclauses = join_references(hj->hashclauses,
|
||||||
rtable,
|
rtable,
|
||||||
outer_tlist,
|
outer_itlist,
|
||||||
inner_tlist,
|
inner_itlist,
|
||||||
(Index) 0,
|
(Index) 0);
|
||||||
tlists_have_non_vars);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pfree(outer_itlist);
|
||||||
|
pfree(inner_itlist);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -760,8 +773,7 @@ set_join_references(Join *join, List *rtable)
|
||||||
static void
|
static void
|
||||||
set_inner_join_references(Plan *inner_plan,
|
set_inner_join_references(Plan *inner_plan,
|
||||||
List *rtable,
|
List *rtable,
|
||||||
List *outer_tlist,
|
indexed_tlist *outer_itlist)
|
||||||
bool tlists_have_non_vars)
|
|
||||||
{
|
{
|
||||||
if (IsA(inner_plan, IndexScan))
|
if (IsA(inner_plan, IndexScan))
|
||||||
{
|
{
|
||||||
|
@ -782,16 +794,14 @@ set_inner_join_references(Plan *inner_plan,
|
||||||
/* only refs to outer vars get changed in the inner qual */
|
/* only refs to outer vars get changed in the inner qual */
|
||||||
innerscan->indexqualorig = join_references(indexqualorig,
|
innerscan->indexqualorig = join_references(indexqualorig,
|
||||||
rtable,
|
rtable,
|
||||||
outer_tlist,
|
outer_itlist,
|
||||||
NIL,
|
NULL,
|
||||||
innerrel,
|
innerrel);
|
||||||
tlists_have_non_vars);
|
|
||||||
innerscan->indexqual = join_references(innerscan->indexqual,
|
innerscan->indexqual = join_references(innerscan->indexqual,
|
||||||
rtable,
|
rtable,
|
||||||
outer_tlist,
|
outer_itlist,
|
||||||
NIL,
|
NULL,
|
||||||
innerrel,
|
innerrel);
|
||||||
tlists_have_non_vars);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We must fix the inner qpqual too, if it has join
|
* We must fix the inner qpqual too, if it has join
|
||||||
|
@ -801,10 +811,9 @@ set_inner_join_references(Plan *inner_plan,
|
||||||
if (NumRelids((Node *) inner_plan->qual) > 1)
|
if (NumRelids((Node *) inner_plan->qual) > 1)
|
||||||
inner_plan->qual = join_references(inner_plan->qual,
|
inner_plan->qual = join_references(inner_plan->qual,
|
||||||
rtable,
|
rtable,
|
||||||
outer_tlist,
|
outer_itlist,
|
||||||
NIL,
|
NULL,
|
||||||
innerrel,
|
innerrel);
|
||||||
tlists_have_non_vars);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (IsA(inner_plan, BitmapIndexScan))
|
else if (IsA(inner_plan, BitmapIndexScan))
|
||||||
|
@ -823,16 +832,14 @@ set_inner_join_references(Plan *inner_plan,
|
||||||
/* only refs to outer vars get changed in the inner qual */
|
/* only refs to outer vars get changed in the inner qual */
|
||||||
innerscan->indexqualorig = join_references(indexqualorig,
|
innerscan->indexqualorig = join_references(indexqualorig,
|
||||||
rtable,
|
rtable,
|
||||||
outer_tlist,
|
outer_itlist,
|
||||||
NIL,
|
NULL,
|
||||||
innerrel,
|
innerrel);
|
||||||
tlists_have_non_vars);
|
|
||||||
innerscan->indexqual = join_references(innerscan->indexqual,
|
innerscan->indexqual = join_references(innerscan->indexqual,
|
||||||
rtable,
|
rtable,
|
||||||
outer_tlist,
|
outer_itlist,
|
||||||
NIL,
|
NULL,
|
||||||
innerrel,
|
innerrel);
|
||||||
tlists_have_non_vars);
|
|
||||||
/* no need to fix inner qpqual */
|
/* no need to fix inner qpqual */
|
||||||
Assert(inner_plan->qual == NIL);
|
Assert(inner_plan->qual == NIL);
|
||||||
}
|
}
|
||||||
|
@ -854,10 +861,9 @@ set_inner_join_references(Plan *inner_plan,
|
||||||
/* only refs to outer vars get changed in the inner qual */
|
/* only refs to outer vars get changed in the inner qual */
|
||||||
innerscan->bitmapqualorig = join_references(bitmapqualorig,
|
innerscan->bitmapqualorig = join_references(bitmapqualorig,
|
||||||
rtable,
|
rtable,
|
||||||
outer_tlist,
|
outer_itlist,
|
||||||
NIL,
|
NULL,
|
||||||
innerrel,
|
innerrel);
|
||||||
tlists_have_non_vars);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We must fix the inner qpqual too, if it has join
|
* We must fix the inner qpqual too, if it has join
|
||||||
|
@ -867,16 +873,14 @@ set_inner_join_references(Plan *inner_plan,
|
||||||
if (NumRelids((Node *) inner_plan->qual) > 1)
|
if (NumRelids((Node *) inner_plan->qual) > 1)
|
||||||
inner_plan->qual = join_references(inner_plan->qual,
|
inner_plan->qual = join_references(inner_plan->qual,
|
||||||
rtable,
|
rtable,
|
||||||
outer_tlist,
|
outer_itlist,
|
||||||
NIL,
|
NULL,
|
||||||
innerrel,
|
innerrel);
|
||||||
tlists_have_non_vars);
|
|
||||||
|
|
||||||
/* Now recurse */
|
/* Now recurse */
|
||||||
set_inner_join_references(inner_plan->lefttree,
|
set_inner_join_references(inner_plan->lefttree,
|
||||||
rtable,
|
rtable,
|
||||||
outer_tlist,
|
outer_itlist);
|
||||||
tlists_have_non_vars);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (IsA(inner_plan, BitmapAnd))
|
else if (IsA(inner_plan, BitmapAnd))
|
||||||
|
@ -889,8 +893,7 @@ set_inner_join_references(Plan *inner_plan,
|
||||||
{
|
{
|
||||||
set_inner_join_references((Plan *) lfirst(l),
|
set_inner_join_references((Plan *) lfirst(l),
|
||||||
rtable,
|
rtable,
|
||||||
outer_tlist,
|
outer_itlist);
|
||||||
tlists_have_non_vars);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (IsA(inner_plan, BitmapOr))
|
else if (IsA(inner_plan, BitmapOr))
|
||||||
|
@ -903,8 +906,7 @@ set_inner_join_references(Plan *inner_plan,
|
||||||
{
|
{
|
||||||
set_inner_join_references((Plan *) lfirst(l),
|
set_inner_join_references((Plan *) lfirst(l),
|
||||||
rtable,
|
rtable,
|
||||||
outer_tlist,
|
outer_itlist);
|
||||||
tlists_have_non_vars);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (IsA(inner_plan, TidScan))
|
else if (IsA(inner_plan, TidScan))
|
||||||
|
@ -914,10 +916,9 @@ set_inner_join_references(Plan *inner_plan,
|
||||||
|
|
||||||
innerscan->tideval = join_references(innerscan->tideval,
|
innerscan->tideval = join_references(innerscan->tideval,
|
||||||
rtable,
|
rtable,
|
||||||
outer_tlist,
|
outer_itlist,
|
||||||
NIL,
|
NULL,
|
||||||
innerrel,
|
innerrel);
|
||||||
tlists_have_non_vars);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -941,17 +942,14 @@ static void
|
||||||
set_uppernode_references(Plan *plan, Index subvarno)
|
set_uppernode_references(Plan *plan, Index subvarno)
|
||||||
{
|
{
|
||||||
Plan *subplan = plan->lefttree;
|
Plan *subplan = plan->lefttree;
|
||||||
List *subplan_targetlist,
|
indexed_tlist *subplan_itlist;
|
||||||
*output_targetlist;
|
List *output_targetlist;
|
||||||
ListCell *l;
|
ListCell *l;
|
||||||
bool tlist_has_non_vars;
|
|
||||||
|
|
||||||
if (subplan != NULL)
|
if (subplan != NULL)
|
||||||
subplan_targetlist = subplan->targetlist;
|
subplan_itlist = build_tlist_index(subplan->targetlist);
|
||||||
else
|
else
|
||||||
subplan_targetlist = NIL;
|
subplan_itlist = build_tlist_index(NIL);
|
||||||
|
|
||||||
tlist_has_non_vars = targetlist_has_non_vars(subplan_targetlist);
|
|
||||||
|
|
||||||
output_targetlist = NIL;
|
output_targetlist = NIL;
|
||||||
foreach(l, plan->targetlist)
|
foreach(l, plan->targetlist)
|
||||||
|
@ -960,9 +958,8 @@ set_uppernode_references(Plan *plan, Index subvarno)
|
||||||
Node *newexpr;
|
Node *newexpr;
|
||||||
|
|
||||||
newexpr = replace_vars_with_subplan_refs((Node *) tle->expr,
|
newexpr = replace_vars_with_subplan_refs((Node *) tle->expr,
|
||||||
subvarno,
|
subplan_itlist,
|
||||||
subplan_targetlist,
|
subvarno);
|
||||||
tlist_has_non_vars);
|
|
||||||
tle = flatCopyTargetEntry(tle);
|
tle = flatCopyTargetEntry(tle);
|
||||||
tle->expr = (Expr *) newexpr;
|
tle->expr = (Expr *) newexpr;
|
||||||
output_targetlist = lappend(output_targetlist, tle);
|
output_targetlist = lappend(output_targetlist, tle);
|
||||||
|
@ -971,30 +968,127 @@ set_uppernode_references(Plan *plan, Index subvarno)
|
||||||
|
|
||||||
plan->qual = (List *)
|
plan->qual = (List *)
|
||||||
replace_vars_with_subplan_refs((Node *) plan->qual,
|
replace_vars_with_subplan_refs((Node *) plan->qual,
|
||||||
subvarno,
|
subplan_itlist,
|
||||||
subplan_targetlist,
|
subvarno);
|
||||||
tlist_has_non_vars);
|
|
||||||
|
pfree(subplan_itlist);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* targetlist_has_non_vars --- are there any non-Var entries in tlist?
|
* build_tlist_index --- build an index data structure for a child tlist
|
||||||
*
|
*
|
||||||
* In most cases, subplan tlists will be "flat" tlists with only Vars.
|
* In most cases, subplan tlists will be "flat" tlists with only Vars,
|
||||||
* Checking for this allows us to save comparisons in common cases.
|
* so we try to optimize that case by extracting information about Vars
|
||||||
|
* in advance. Matching a parent tlist to a child is still an O(N^2)
|
||||||
|
* operation, but at least with a much smaller constant factor than plain
|
||||||
|
* tlist_member() searches.
|
||||||
|
*
|
||||||
|
* The result of this function is an indexed_tlist struct to pass to
|
||||||
|
* search_indexed_tlist_for_var() or search_indexed_tlist_for_non_var().
|
||||||
|
* When done, the indexed_tlist may be freed with a single pfree().
|
||||||
*/
|
*/
|
||||||
static bool
|
static indexed_tlist *
|
||||||
targetlist_has_non_vars(List *tlist)
|
build_tlist_index(List *tlist)
|
||||||
{
|
{
|
||||||
|
indexed_tlist *itlist;
|
||||||
|
tlist_vinfo *vinfo;
|
||||||
ListCell *l;
|
ListCell *l;
|
||||||
|
|
||||||
|
/* Create data structure with enough slots for all tlist entries */
|
||||||
|
itlist = (indexed_tlist *)
|
||||||
|
palloc(offsetof(indexed_tlist, vars) +
|
||||||
|
list_length(tlist) * sizeof(tlist_vinfo));
|
||||||
|
|
||||||
|
itlist->tlist = tlist;
|
||||||
|
itlist->has_non_vars = false;
|
||||||
|
|
||||||
|
/* Find the Vars and fill in the index array */
|
||||||
|
vinfo = itlist->vars;
|
||||||
foreach(l, tlist)
|
foreach(l, tlist)
|
||||||
{
|
{
|
||||||
TargetEntry *tle = (TargetEntry *) lfirst(l);
|
TargetEntry *tle = (TargetEntry *) lfirst(l);
|
||||||
|
|
||||||
if (tle->expr && !IsA(tle->expr, Var))
|
if (tle->expr && IsA(tle->expr, Var))
|
||||||
return true;
|
{
|
||||||
|
Var *var = (Var *) tle->expr;
|
||||||
|
|
||||||
|
vinfo->varno = var->varno;
|
||||||
|
vinfo->varattno = var->varattno;
|
||||||
|
vinfo->resno = tle->resno;
|
||||||
|
vinfo++;
|
||||||
}
|
}
|
||||||
return false;
|
else
|
||||||
|
itlist->has_non_vars = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
itlist->num_vars = (vinfo - itlist->vars);
|
||||||
|
|
||||||
|
return itlist;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* search_indexed_tlist_for_var --- find a Var in an indexed tlist
|
||||||
|
*
|
||||||
|
* If a match is found, return a copy of the given Var with suitably
|
||||||
|
* modified varno/varattno (to wit, newvarno and the resno of the TLE entry).
|
||||||
|
* If no match, return NULL.
|
||||||
|
*/
|
||||||
|
static Var *
|
||||||
|
search_indexed_tlist_for_var(Var *var, indexed_tlist *itlist, Index newvarno)
|
||||||
|
{
|
||||||
|
Index varno = var->varno;
|
||||||
|
AttrNumber varattno = var->varattno;
|
||||||
|
tlist_vinfo *vinfo;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
vinfo = itlist->vars;
|
||||||
|
i = itlist->num_vars;
|
||||||
|
while (i-- > 0)
|
||||||
|
{
|
||||||
|
if (vinfo->varno == varno && vinfo->varattno == varattno)
|
||||||
|
{
|
||||||
|
/* Found a match */
|
||||||
|
Var *newvar = (Var *) copyObject(var);
|
||||||
|
|
||||||
|
newvar->varno = newvarno;
|
||||||
|
newvar->varattno = vinfo->resno;
|
||||||
|
return newvar;
|
||||||
|
}
|
||||||
|
vinfo++;
|
||||||
|
}
|
||||||
|
return NULL; /* no match */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* search_indexed_tlist_for_non_var --- find a non-Var in an indexed tlist
|
||||||
|
*
|
||||||
|
* If a match is found, return a Var constructed to reference the tlist item.
|
||||||
|
* If no match, return NULL.
|
||||||
|
*
|
||||||
|
* NOTE: it is a waste of time to call this if !itlist->has_non_vars
|
||||||
|
*/
|
||||||
|
static Var *
|
||||||
|
search_indexed_tlist_for_non_var(Node *node,
|
||||||
|
indexed_tlist *itlist, Index newvarno)
|
||||||
|
{
|
||||||
|
TargetEntry *tle;
|
||||||
|
|
||||||
|
tle = tlist_member(node, itlist->tlist);
|
||||||
|
if (tle)
|
||||||
|
{
|
||||||
|
/* Found a matching subplan output expression */
|
||||||
|
Var *newvar;
|
||||||
|
|
||||||
|
newvar = makeVar(newvarno,
|
||||||
|
tle->resno,
|
||||||
|
exprType((Node *) tle->expr),
|
||||||
|
exprTypmod((Node *) tle->expr),
|
||||||
|
0);
|
||||||
|
newvar->varnoold = 0; /* wasn't ever a plain Var */
|
||||||
|
newvar->varoattno = 0;
|
||||||
|
return newvar;
|
||||||
|
}
|
||||||
|
return NULL; /* no match */
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1012,12 +1106,13 @@ targetlist_has_non_vars(List *tlist)
|
||||||
*
|
*
|
||||||
* For a normal join, acceptable_rel should be zero so that any failure to
|
* For a normal join, acceptable_rel should be zero so that any failure to
|
||||||
* match a Var will be reported as an error. For the indexscan case,
|
* match a Var will be reported as an error. For the indexscan case,
|
||||||
* pass inner_tlist = NIL and acceptable_rel = the ID of the inner relation.
|
* pass inner_itlist = NULL and acceptable_rel = the ID of the inner relation.
|
||||||
*
|
*
|
||||||
* 'clauses' is the targetlist or list of join clauses
|
* 'clauses' is the targetlist or list of join clauses
|
||||||
* 'rtable' is the current range table
|
* 'rtable' is the current range table
|
||||||
* 'outer_tlist' is the target list of the outer join relation
|
* 'outer_itlist' is the indexed target list of the outer join relation
|
||||||
* 'inner_tlist' is the target list of the inner join relation, or NIL
|
* 'inner_itlist' is the indexed target list of the inner join relation,
|
||||||
|
* or NULL
|
||||||
* 'acceptable_rel' is either zero or the rangetable index of a relation
|
* 'acceptable_rel' is either zero or the rangetable index of a relation
|
||||||
* whose Vars may appear in the clause without provoking an error.
|
* whose Vars may appear in the clause without provoking an error.
|
||||||
*
|
*
|
||||||
|
@ -1027,18 +1122,16 @@ targetlist_has_non_vars(List *tlist)
|
||||||
static List *
|
static List *
|
||||||
join_references(List *clauses,
|
join_references(List *clauses,
|
||||||
List *rtable,
|
List *rtable,
|
||||||
List *outer_tlist,
|
indexed_tlist *outer_itlist,
|
||||||
List *inner_tlist,
|
indexed_tlist *inner_itlist,
|
||||||
Index acceptable_rel,
|
Index acceptable_rel)
|
||||||
bool tlists_have_non_vars)
|
|
||||||
{
|
{
|
||||||
join_references_context context;
|
join_references_context context;
|
||||||
|
|
||||||
context.rtable = rtable;
|
context.rtable = rtable;
|
||||||
context.outer_tlist = outer_tlist;
|
context.outer_itlist = outer_itlist;
|
||||||
context.inner_tlist = inner_tlist;
|
context.inner_itlist = inner_itlist;
|
||||||
context.acceptable_rel = acceptable_rel;
|
context.acceptable_rel = acceptable_rel;
|
||||||
context.tlists_have_non_vars = tlists_have_non_vars;
|
|
||||||
return (List *) join_references_mutator((Node *) clauses, &context);
|
return (List *) join_references_mutator((Node *) clauses, &context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1046,30 +1139,26 @@ static Node *
|
||||||
join_references_mutator(Node *node,
|
join_references_mutator(Node *node,
|
||||||
join_references_context *context)
|
join_references_context *context)
|
||||||
{
|
{
|
||||||
|
Var *newvar;
|
||||||
|
|
||||||
if (node == NULL)
|
if (node == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
if (IsA(node, Var))
|
if (IsA(node, Var))
|
||||||
{
|
{
|
||||||
Var *var = (Var *) node;
|
Var *var = (Var *) node;
|
||||||
TargetEntry *tle;
|
|
||||||
|
|
||||||
/* First look for the var in the input tlists */
|
/* First look for the var in the input tlists */
|
||||||
tle = tlist_member((Node *) var, context->outer_tlist);
|
newvar = search_indexed_tlist_for_var(var,
|
||||||
if (tle)
|
context->outer_itlist,
|
||||||
{
|
OUTER);
|
||||||
Var *newvar = (Var *) copyObject(var);
|
if (newvar)
|
||||||
|
|
||||||
newvar->varno = OUTER;
|
|
||||||
newvar->varattno = tle->resno;
|
|
||||||
return (Node *) newvar;
|
return (Node *) newvar;
|
||||||
}
|
if (context->inner_itlist)
|
||||||
tle = tlist_member((Node *) var, context->inner_tlist);
|
|
||||||
if (tle)
|
|
||||||
{
|
{
|
||||||
Var *newvar = (Var *) copyObject(var);
|
newvar = search_indexed_tlist_for_var(var,
|
||||||
|
context->inner_itlist,
|
||||||
newvar->varno = INNER;
|
INNER);
|
||||||
newvar->varattno = tle->resno;
|
if (newvar)
|
||||||
return (Node *) newvar;
|
return (Node *) newvar;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1081,41 +1170,22 @@ join_references_mutator(Node *node,
|
||||||
elog(ERROR, "variable not found in subplan target lists");
|
elog(ERROR, "variable not found in subplan target lists");
|
||||||
}
|
}
|
||||||
/* Try matching more complex expressions too, if tlists have any */
|
/* Try matching more complex expressions too, if tlists have any */
|
||||||
if (context->tlists_have_non_vars)
|
if (context->outer_itlist->has_non_vars)
|
||||||
{
|
{
|
||||||
TargetEntry *tle;
|
newvar = search_indexed_tlist_for_non_var(node,
|
||||||
|
context->outer_itlist,
|
||||||
tle = tlist_member(node, context->outer_tlist);
|
OUTER);
|
||||||
if (tle)
|
if (newvar)
|
||||||
{
|
|
||||||
/* Found a matching subplan output expression */
|
|
||||||
Var *newvar;
|
|
||||||
|
|
||||||
newvar = makeVar(OUTER,
|
|
||||||
tle->resno,
|
|
||||||
exprType((Node *) tle->expr),
|
|
||||||
exprTypmod((Node *) tle->expr),
|
|
||||||
0);
|
|
||||||
newvar->varnoold = 0; /* wasn't ever a plain Var */
|
|
||||||
newvar->varoattno = 0;
|
|
||||||
return (Node *) newvar;
|
return (Node *) newvar;
|
||||||
}
|
}
|
||||||
tle = tlist_member(node, context->inner_tlist);
|
if (context->inner_itlist && context->inner_itlist->has_non_vars)
|
||||||
if (tle)
|
|
||||||
{
|
{
|
||||||
/* Found a matching subplan output expression */
|
newvar = search_indexed_tlist_for_non_var(node,
|
||||||
Var *newvar;
|
context->inner_itlist,
|
||||||
|
INNER);
|
||||||
newvar = makeVar(INNER,
|
if (newvar)
|
||||||
tle->resno,
|
|
||||||
exprType((Node *) tle->expr),
|
|
||||||
exprTypmod((Node *) tle->expr),
|
|
||||||
0);
|
|
||||||
newvar->varnoold = 0; /* wasn't ever a plain Var */
|
|
||||||
newvar->varoattno = 0;
|
|
||||||
return (Node *) newvar;
|
return (Node *) newvar;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return expression_tree_mutator(node,
|
return expression_tree_mutator(node,
|
||||||
join_references_mutator,
|
join_references_mutator,
|
||||||
(void *) context);
|
(void *) context);
|
||||||
|
@ -1131,16 +1201,15 @@ join_references_mutator(Node *node,
|
||||||
* --- so this routine should only be applied to nodes whose subplans'
|
* --- so this routine should only be applied to nodes whose subplans'
|
||||||
* targetlists were generated via flatten_tlist() or some such method.
|
* targetlists were generated via flatten_tlist() or some such method.
|
||||||
*
|
*
|
||||||
* If tlist_has_non_vars is true, then we try to match whole subexpressions
|
* If itlist->has_non_vars is true, then we try to match whole subexpressions
|
||||||
* against elements of the subplan tlist, so that we can avoid recomputing
|
* against elements of the subplan tlist, so that we can avoid recomputing
|
||||||
* expressions that were already computed by the subplan. (This is relatively
|
* expressions that were already computed by the subplan. (This is relatively
|
||||||
* expensive, so we don't want to try it in the common case where the
|
* expensive, so we don't want to try it in the common case where the
|
||||||
* subplan tlist is just a flattened list of Vars.)
|
* subplan tlist is just a flattened list of Vars.)
|
||||||
*
|
*
|
||||||
* 'node': the tree to be fixed (a target item or qual)
|
* 'node': the tree to be fixed (a target item or qual)
|
||||||
|
* 'subplan_itlist': indexed target list for subplan
|
||||||
* 'subvarno': varno to be assigned to all Vars
|
* 'subvarno': varno to be assigned to all Vars
|
||||||
* 'subplan_targetlist': target list for subplan
|
|
||||||
* 'tlist_has_non_vars': true if subplan_targetlist contains non-Var exprs
|
|
||||||
*
|
*
|
||||||
* The resulting tree is a copy of the original in which all Var nodes have
|
* The resulting tree is a copy of the original in which all Var nodes have
|
||||||
* varno = subvarno, varattno = resno of corresponding subplan target.
|
* varno = subvarno, varattno = resno of corresponding subplan target.
|
||||||
|
@ -1148,15 +1217,13 @@ join_references_mutator(Node *node,
|
||||||
*/
|
*/
|
||||||
static Node *
|
static Node *
|
||||||
replace_vars_with_subplan_refs(Node *node,
|
replace_vars_with_subplan_refs(Node *node,
|
||||||
Index subvarno,
|
indexed_tlist *subplan_itlist,
|
||||||
List *subplan_targetlist,
|
Index subvarno)
|
||||||
bool tlist_has_non_vars)
|
|
||||||
{
|
{
|
||||||
replace_vars_with_subplan_refs_context context;
|
replace_vars_with_subplan_refs_context context;
|
||||||
|
|
||||||
|
context.subplan_itlist = subplan_itlist;
|
||||||
context.subvarno = subvarno;
|
context.subvarno = subvarno;
|
||||||
context.subplan_targetlist = subplan_targetlist;
|
|
||||||
context.tlist_has_non_vars = tlist_has_non_vars;
|
|
||||||
return replace_vars_with_subplan_refs_mutator(node, &context);
|
return replace_vars_with_subplan_refs_mutator(node, &context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1164,43 +1231,30 @@ static Node *
|
||||||
replace_vars_with_subplan_refs_mutator(Node *node,
|
replace_vars_with_subplan_refs_mutator(Node *node,
|
||||||
replace_vars_with_subplan_refs_context *context)
|
replace_vars_with_subplan_refs_context *context)
|
||||||
{
|
{
|
||||||
|
Var *newvar;
|
||||||
|
|
||||||
if (node == NULL)
|
if (node == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
if (IsA(node, Var))
|
if (IsA(node, Var))
|
||||||
{
|
{
|
||||||
Var *var = (Var *) node;
|
Var *var = (Var *) node;
|
||||||
TargetEntry *tle;
|
|
||||||
Var *newvar;
|
|
||||||
|
|
||||||
tle = tlist_member((Node *) var, context->subplan_targetlist);
|
newvar = search_indexed_tlist_for_var(var,
|
||||||
if (!tle)
|
context->subplan_itlist,
|
||||||
|
context->subvarno);
|
||||||
|
if (!newvar)
|
||||||
elog(ERROR, "variable not found in subplan target list");
|
elog(ERROR, "variable not found in subplan target list");
|
||||||
newvar = (Var *) copyObject(var);
|
|
||||||
newvar->varno = context->subvarno;
|
|
||||||
newvar->varattno = tle->resno;
|
|
||||||
return (Node *) newvar;
|
return (Node *) newvar;
|
||||||
}
|
}
|
||||||
/* Try matching more complex expressions too, if tlist has any */
|
/* Try matching more complex expressions too, if tlist has any */
|
||||||
if (context->tlist_has_non_vars)
|
if (context->subplan_itlist->has_non_vars)
|
||||||
{
|
{
|
||||||
TargetEntry *tle;
|
newvar = search_indexed_tlist_for_non_var(node,
|
||||||
|
context->subplan_itlist,
|
||||||
tle = tlist_member(node, context->subplan_targetlist);
|
context->subvarno);
|
||||||
if (tle)
|
if (newvar)
|
||||||
{
|
|
||||||
/* Found a matching subplan output expression */
|
|
||||||
Var *newvar;
|
|
||||||
|
|
||||||
newvar = makeVar(context->subvarno,
|
|
||||||
tle->resno,
|
|
||||||
exprType((Node *) tle->expr),
|
|
||||||
exprTypmod((Node *) tle->expr),
|
|
||||||
0);
|
|
||||||
newvar->varnoold = 0; /* wasn't ever a plain Var */
|
|
||||||
newvar->varoattno = 0;
|
|
||||||
return (Node *) newvar;
|
return (Node *) newvar;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return expression_tree_mutator(node,
|
return expression_tree_mutator(node,
|
||||||
replace_vars_with_subplan_refs_mutator,
|
replace_vars_with_subplan_refs_mutator,
|
||||||
(void *) context);
|
(void *) context);
|
||||||
|
|
Loading…
Reference in New Issue