Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 1b1d3d9

Browse files
committed
Remove ph_may_need from PlaceHolderInfo, with attendant simplifications.
The planner logic that attempted to make a preliminary estimate of the ph_needed levels for PlaceHolderVars seems to be completely broken by lateral references. Fortunately, the potential join order optimization that this code supported seems to be of relatively little value in practice; so let's just get rid of it rather than trying to fix it. Getting rid of this allows fairly substantial simplifications in placeholder.c, too, so planning in such cases should be a bit faster. Issue noted while pursuing bugs reported by Jeremy Evans and Antonin Houska, though this doesn't in itself fix either of their reported cases. What this does do is prevent an Assert crash in the kind of query illustrated by the added regression test. (I'm not sure that the plan for that query is stable enough across platforms to be usable as a regression test output ... but we'll soon find out from the buildfarm.) Back-patch to 9.3. The problem case can't arise without LATERAL, so no need to touch older branches.
1 parent 5368a23 commit 1b1d3d9

File tree

10 files changed

+103
-135
lines changed

10 files changed

+103
-135
lines changed

src/backend/nodes/copyfuncs.c

-1
Original file line numberDiff line numberDiff line change
@@ -1957,7 +1957,6 @@ _copyPlaceHolderInfo(const PlaceHolderInfo *from)
19571957
COPY_NODE_FIELD(ph_var);
19581958
COPY_BITMAPSET_FIELD(ph_eval_at);
19591959
COPY_BITMAPSET_FIELD(ph_needed);
1960-
COPY_BITMAPSET_FIELD(ph_may_need);
19611960
COPY_SCALAR_FIELD(ph_width);
19621961

19631962
return newnode;

src/backend/nodes/equalfuncs.c

-1
Original file line numberDiff line numberDiff line change
@@ -822,7 +822,6 @@ _equalPlaceHolderInfo(const PlaceHolderInfo *a, const PlaceHolderInfo *b)
822822
COMPARE_NODE_FIELD(ph_var);
823823
COMPARE_BITMAPSET_FIELD(ph_eval_at);
824824
COMPARE_BITMAPSET_FIELD(ph_needed);
825-
COMPARE_BITMAPSET_FIELD(ph_may_need);
826825
COMPARE_SCALAR_FIELD(ph_width);
827826

828827
return true;

src/backend/nodes/outfuncs.c

-1
Original file line numberDiff line numberDiff line change
@@ -1939,7 +1939,6 @@ _outPlaceHolderInfo(StringInfo str, const PlaceHolderInfo *node)
19391939
WRITE_NODE_FIELD(ph_var);
19401940
WRITE_BITMAPSET_FIELD(ph_eval_at);
19411941
WRITE_BITMAPSET_FIELD(ph_needed);
1942-
WRITE_BITMAPSET_FIELD(ph_may_need);
19431942
WRITE_INT_FIELD(ph_width);
19441943
}
19451944

src/backend/optimizer/plan/analyzejoins.c

-2
Original file line numberDiff line numberDiff line change
@@ -388,8 +388,6 @@ remove_rel_from_query(PlannerInfo *root, int relid, Relids joinrelids)
388388
phinfo->ph_eval_at = bms_add_member(phinfo->ph_eval_at, relid);
389389

390390
phinfo->ph_needed = bms_del_member(phinfo->ph_needed, relid);
391-
/* ph_may_need probably isn't used after this, but fix it anyway */
392-
phinfo->ph_may_need = bms_del_member(phinfo->ph_may_need, relid);
393391
}
394392

395393
/*

src/backend/optimizer/plan/initsplan.c

+9-27
Original file line numberDiff line numberDiff line change
@@ -155,10 +155,9 @@ build_base_rel_tlists(PlannerInfo *root, List *final_tlist)
155155
* The list may also contain PlaceHolderVars. These don't necessarily
156156
* have a single owning relation; we keep their attr_needed info in
157157
* root->placeholder_list instead. If create_new_ph is true, it's OK
158-
* to create new PlaceHolderInfos, and we also have to update ph_may_need;
159-
* otherwise, the PlaceHolderInfos must already exist, and we should only
160-
* update their ph_needed. (It should be true before deconstruct_jointree
161-
* begins, and false after that.)
158+
* to create new PlaceHolderInfos; otherwise, the PlaceHolderInfos must
159+
* already exist, and we should only update their ph_needed. (This should
160+
* be true before deconstruct_jointree begins, and false after that.)
162161
*/
163162
void
164163
add_vars_to_targetlist(PlannerInfo *root, List *vars,
@@ -196,20 +195,8 @@ add_vars_to_targetlist(PlannerInfo *root, List *vars,
196195
PlaceHolderInfo *phinfo = find_placeholder_info(root, phv,
197196
create_new_ph);
198197

199-
/* Always adjust ph_needed */
200198
phinfo->ph_needed = bms_add_members(phinfo->ph_needed,
201199
where_needed);
202-
203-
/*
204-
* If we are creating PlaceHolderInfos, mark them with the correct
205-
* maybe-needed locations. Otherwise, it's too late to change
206-
* that, so we'd better not have set ph_needed to more than
207-
* ph_may_need.
208-
*/
209-
if (create_new_ph)
210-
mark_placeholder_maybe_needed(root, phinfo, where_needed);
211-
else
212-
Assert(bms_is_subset(phinfo->ph_needed, phinfo->ph_may_need));
213200
}
214201
else
215202
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
@@ -235,7 +222,7 @@ add_vars_to_targetlist(PlannerInfo *root, List *vars,
235222
* means setting suitable where_needed values for them.
236223
*
237224
* This has to run before deconstruct_jointree, since it might result in
238-
* creation of PlaceHolderInfos or extension of their ph_may_need sets.
225+
* creation of PlaceHolderInfos.
239226
*/
240227
void
241228
find_lateral_references(PlannerInfo *root)
@@ -1005,11 +992,11 @@ make_outerjoininfo(PlannerInfo *root,
1005992

1006993
/*
1007994
* Examine PlaceHolderVars. If a PHV is supposed to be evaluated within
1008-
* this join's nullable side, and it may get used above this join, then
1009-
* ensure that min_righthand contains the full eval_at set of the PHV.
1010-
* This ensures that the PHV actually can be evaluated within the RHS.
1011-
* Note that this works only because we should already have determined the
1012-
* final eval_at level for any PHV syntactically within this join.
995+
* this join's nullable side, then ensure that min_righthand contains the
996+
* full eval_at set of the PHV. This ensures that the PHV actually can be
997+
* evaluated within the RHS. Note that this works only because we should
998+
* already have determined the final eval_at level for any PHV
999+
* syntactically within this join.
10131000
*/
10141001
foreach(l, root->placeholder_list)
10151002
{
@@ -1020,11 +1007,6 @@ make_outerjoininfo(PlannerInfo *root,
10201007
if (!bms_is_subset(ph_syn_level, right_rels))
10211008
continue;
10221009

1023-
/* We can also ignore it if it's certainly not used above this join */
1024-
/* XXX this test is probably overly conservative */
1025-
if (bms_is_subset(phinfo->ph_may_need, min_righthand))
1026-
continue;
1027-
10281010
/* Else, prevent join from being formed before we eval the PHV */
10291011
min_righthand = bms_add_members(min_righthand, phinfo->ph_eval_at);
10301012
}

src/backend/optimizer/util/placeholder.c

+26-88
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,8 @@
2323
#include "utils/lsyscache.h"
2424

2525
/* Local functions */
26-
static Relids find_placeholders_recurse(PlannerInfo *root, Node *jtnode);
27-
static void mark_placeholders_in_expr(PlannerInfo *root, Node *expr,
28-
Relids relids);
26+
static void find_placeholders_recurse(PlannerInfo *root, Node *jtnode);
27+
static void find_placeholders_in_expr(PlannerInfo *root, Node *expr);
2928

3029

3130
/*
@@ -90,16 +89,23 @@ find_placeholder_info(PlannerInfo *root, PlaceHolderVar *phv,
9089

9190
phinfo->phid = phv->phid;
9291
phinfo->ph_var = copyObject(phv);
92+
/* initialize ph_eval_at as the set of contained relids */
9393
phinfo->ph_eval_at = pull_varnos((Node *) phv);
9494
/* ph_eval_at may change later, see update_placeholder_eval_levels */
9595
phinfo->ph_needed = NULL; /* initially it's unused */
96-
phinfo->ph_may_need = NULL;
9796
/* for the moment, estimate width using just the datatype info */
9897
phinfo->ph_width = get_typavgwidth(exprType((Node *) phv->phexpr),
9998
exprTypmod((Node *) phv->phexpr));
10099

101100
root->placeholder_list = lappend(root->placeholder_list, phinfo);
102101

102+
/*
103+
* The PHV's contained expression may contain other, lower-level PHVs. We
104+
* now know we need to get those into the PlaceHolderInfo list, too, so we
105+
* may as well do that immediately.
106+
*/
107+
find_placeholders_in_expr(root, (Node *) phinfo->ph_var->phexpr);
108+
103109
return phinfo;
104110
}
105111

@@ -119,7 +125,7 @@ find_placeholders_in_jointree(PlannerInfo *root)
119125
/* Start recursion at top of jointree */
120126
Assert(root->parse->jointree != NULL &&
121127
IsA(root->parse->jointree, FromExpr));
122-
(void) find_placeholders_recurse(root, (Node *) root->parse->jointree);
128+
find_placeholders_recurse(root, (Node *) root->parse->jointree);
123129
}
124130
}
125131

@@ -128,81 +134,59 @@ find_placeholders_in_jointree(PlannerInfo *root)
128134
* One recursion level of find_placeholders_in_jointree.
129135
*
130136
* jtnode is the current jointree node to examine.
131-
*
132-
* The result is the set of base Relids contained in or below jtnode.
133-
* This is just an internal convenience, it's not used at the top level.
134137
*/
135-
static Relids
138+
static void
136139
find_placeholders_recurse(PlannerInfo *root, Node *jtnode)
137140
{
138-
Relids jtrelids;
139-
140141
if (jtnode == NULL)
141-
return NULL;
142+
return;
142143
if (IsA(jtnode, RangeTblRef))
143144
{
144-
int varno = ((RangeTblRef *) jtnode)->rtindex;
145-
146-
/* No quals to deal with, just return correct result */
147-
jtrelids = bms_make_singleton(varno);
145+
/* No quals to deal with here */
148146
}
149147
else if (IsA(jtnode, FromExpr))
150148
{
151149
FromExpr *f = (FromExpr *) jtnode;
152150
ListCell *l;
153151

154152
/*
155-
* First, recurse to handle child joins, and form their relid set.
153+
* First, recurse to handle child joins.
156154
*/
157-
jtrelids = NULL;
158155
foreach(l, f->fromlist)
159156
{
160-
Relids sub_relids;
161-
162-
sub_relids = find_placeholders_recurse(root, lfirst(l));
163-
jtrelids = bms_join(jtrelids, sub_relids);
157+
find_placeholders_recurse(root, lfirst(l));
164158
}
165159

166160
/*
167161
* Now process the top-level quals.
168162
*/
169-
mark_placeholders_in_expr(root, f->quals, jtrelids);
163+
find_placeholders_in_expr(root, f->quals);
170164
}
171165
else if (IsA(jtnode, JoinExpr))
172166
{
173167
JoinExpr *j = (JoinExpr *) jtnode;
174-
Relids leftids,
175-
rightids;
176168

177169
/*
178-
* First, recurse to handle child joins, and form their relid set.
170+
* First, recurse to handle child joins.
179171
*/
180-
leftids = find_placeholders_recurse(root, j->larg);
181-
rightids = find_placeholders_recurse(root, j->rarg);
182-
jtrelids = bms_join(leftids, rightids);
172+
find_placeholders_recurse(root, j->larg);
173+
find_placeholders_recurse(root, j->rarg);
183174

184175
/* Process the qual clauses */
185-
mark_placeholders_in_expr(root, j->quals, jtrelids);
176+
find_placeholders_in_expr(root, j->quals);
186177
}
187178
else
188-
{
189179
elog(ERROR, "unrecognized node type: %d",
190180
(int) nodeTag(jtnode));
191-
jtrelids = NULL; /* keep compiler quiet */
192-
}
193-
return jtrelids;
194181
}
195182

196183
/*
197-
* mark_placeholders_in_expr
198-
* Find all PlaceHolderVars in the given expression, and mark them
199-
* as possibly needed at the specified join level.
200-
*
201-
* relids is the syntactic join level to mark as the "maybe needed" level
202-
* for each PlaceHolderVar found in the expression.
184+
* find_placeholders_in_expr
185+
* Find all PlaceHolderVars in the given expression, and create
186+
* PlaceHolderInfo entries for them.
203187
*/
204188
static void
205-
mark_placeholders_in_expr(PlannerInfo *root, Node *expr, Relids relids)
189+
find_placeholders_in_expr(PlannerInfo *root, Node *expr)
206190
{
207191
List *vars;
208192
ListCell *vl;
@@ -217,63 +201,17 @@ mark_placeholders_in_expr(PlannerInfo *root, Node *expr, Relids relids)
217201
foreach(vl, vars)
218202
{
219203
PlaceHolderVar *phv = (PlaceHolderVar *) lfirst(vl);
220-
PlaceHolderInfo *phinfo;
221204

222205
/* Ignore any plain Vars */
223206
if (!IsA(phv, PlaceHolderVar))
224207
continue;
225208

226209
/* Create a PlaceHolderInfo entry if there's not one already */
227-
phinfo = find_placeholder_info(root, phv, true);
228-
229-
/* Mark it, and recursively process any contained placeholders */
230-
mark_placeholder_maybe_needed(root, phinfo, relids);
210+
(void) find_placeholder_info(root, phv, true);
231211
}
232212
list_free(vars);
233213
}
234214

235-
/*
236-
* mark_placeholder_maybe_needed
237-
* Mark a placeholder as possibly needed at the specified join level.
238-
*
239-
* relids is the syntactic join level to mark as the "maybe needed" level
240-
* for the placeholder.
241-
*
242-
* This is called during an initial scan of the query's targetlist and quals
243-
* before we begin deconstruct_jointree. Once we begin deconstruct_jointree,
244-
* all active placeholders must be present in root->placeholder_list with
245-
* their correct ph_may_need values, because make_outerjoininfo and
246-
* update_placeholder_eval_levels require this info to be available while
247-
* we crawl up the join tree.
248-
*/
249-
void
250-
mark_placeholder_maybe_needed(PlannerInfo *root, PlaceHolderInfo *phinfo,
251-
Relids relids)
252-
{
253-
Relids est_eval_level;
254-
255-
/* Mark the PHV as possibly needed at the given syntactic level */
256-
phinfo->ph_may_need = bms_add_members(phinfo->ph_may_need, relids);
257-
258-
/*
259-
* This is a bit tricky: the PHV's contained expression may contain other,
260-
* lower-level PHVs. We need to get those into the PlaceHolderInfo list,
261-
* but they aren't going to be needed where the outer PHV is referenced.
262-
* Rather, they'll be needed where the outer PHV is evaluated. We can
263-
* estimate that conservatively as the syntactic location of the PHV's
264-
* expression, but not less than the level of any Vars it contains.
265-
* (Normally the Vars would come from below the syntactic location anyway,
266-
* but this might not be true if the PHV contains any LATERAL references.)
267-
*/
268-
est_eval_level = bms_union(phinfo->ph_var->phrels, phinfo->ph_eval_at);
269-
270-
/* Now recurse to take care of any such PHVs */
271-
mark_placeholders_in_expr(root, (Node *) phinfo->ph_var->phexpr,
272-
est_eval_level);
273-
274-
bms_free(est_eval_level);
275-
}
276-
277215
/*
278216
* update_placeholder_eval_levels
279217
* Adjust the target evaluation levels for placeholders

src/include/nodes/relation.h

+3-13
Original file line numberDiff line numberDiff line change
@@ -1465,18 +1465,9 @@ typedef struct AppendRelInfo
14651465
* then allow it to bubble up like a Var until the ph_needed join level.
14661466
* ph_needed has the same definition as attr_needed for a regular Var.
14671467
*
1468-
* ph_may_need is an initial estimate of ph_needed, formed using the
1469-
* syntactic locations of references to the PHV. We need this in order to
1470-
* determine whether the PHV reference forces a join ordering constraint:
1471-
* if the PHV has to be evaluated below the nullable side of an outer join,
1472-
* and then used above that outer join, we must constrain join order to ensure
1473-
* there's a valid place to evaluate the PHV below the join. The final
1474-
* actual ph_needed level might be lower than ph_may_need, but we can't
1475-
* determine that until later on. Fortunately this doesn't matter for what
1476-
* we need ph_may_need for: if there's a PHV reference syntactically
1477-
* above the outer join, it's not going to be allowed to drop below the outer
1478-
* join, so we would come to the same conclusions about join order even if
1479-
* we had the final ph_needed value to compare to.
1468+
* Notice that when ph_eval_at is a join rather than a single baserel, the
1469+
* PlaceHolderInfo may create constraints on join order: the ph_eval_at join
1470+
* has to be formed below any outer joins that should null the PlaceHolderVar.
14801471
*
14811472
* We create a PlaceHolderInfo only after determining that the PlaceHolderVar
14821473
* is actually referenced in the plan tree, so that unreferenced placeholders
@@ -1491,7 +1482,6 @@ typedef struct PlaceHolderInfo
14911482
PlaceHolderVar *ph_var; /* copy of PlaceHolderVar tree */
14921483
Relids ph_eval_at; /* lowest level we can evaluate value at */
14931484
Relids ph_needed; /* highest level the value is needed at */
1494-
Relids ph_may_need; /* highest level it might be needed at */
14951485
int32 ph_width; /* estimated attribute width */
14961486
} PlaceHolderInfo;
14971487

src/include/optimizer/placeholder.h

-2
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,6 @@ extern PlaceHolderVar *make_placeholder_expr(PlannerInfo *root, Expr *expr,
2222
extern PlaceHolderInfo *find_placeholder_info(PlannerInfo *root,
2323
PlaceHolderVar *phv, bool create_new_ph);
2424
extern void find_placeholders_in_jointree(PlannerInfo *root);
25-
extern void mark_placeholder_maybe_needed(PlannerInfo *root,
26-
PlaceHolderInfo *phinfo, Relids relids);
2725
extern void update_placeholder_eval_levels(PlannerInfo *root,
2826
SpecialJoinInfo *new_sjinfo);
2927
extern void fix_placeholder_input_needed_levels(PlannerInfo *root);

0 commit comments

Comments
 (0)