Skip to content

Commit c4b0063

Browse files
committed
generic PickyAppend for prepared statements, remove redundant EXPLAIN-related code
1 parent 2a7ac06 commit c4b0063

File tree

5 files changed

+111
-65
lines changed

5 files changed

+111
-65
lines changed

hooks.c

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#include "optimizer/cost.h"
33
#include "optimizer/restrictinfo.h"
44
#include "hooks.h"
5+
#include "utils.h"
56
#include "pathman.h"
67
#include "pickyappend.h"
78

@@ -239,6 +240,63 @@ pathman_rel_pathlist_hook(PlannerInfo *root, RelOptInfo *rel, Index rti, RangeTb
239240
rel->pathlist = NIL;
240241
set_append_rel_pathlist(root, rel, rti, rte, pathkeyAsc, pathkeyDesc);
241242
set_append_rel_size(root, rel, rti, rte);
243+
244+
foreach (lc, rel->pathlist)
245+
{
246+
AppendPath *cur_path = (AppendPath *) lfirst(lc);
247+
Relids inner_required = PATH_REQ_OUTER((Path *) cur_path);
248+
ParamPathInfo *ppi = get_appendrel_parampathinfo(rel, inner_required);
249+
Path *inner_path;
250+
ListCell *subpath_cell;
251+
List *picky_quals = NIL;
252+
253+
if (!IsA(cur_path, AppendPath) ||
254+
rel->has_eclass_joins ||
255+
rel->joininfo)
256+
{
257+
continue;
258+
}
259+
260+
foreach (subpath_cell, cur_path->subpaths)
261+
{
262+
Path *subpath = (Path *) lfirst(subpath_cell);
263+
RelOptInfo *child_rel = subpath->parent;
264+
List *quals;
265+
ListCell *qual_cell;
266+
ReplaceVarsContext repl_var_cxt;
267+
268+
repl_var_cxt.child = subpath->parent;
269+
repl_var_cxt.parent = rel;
270+
repl_var_cxt.sublevels_up = 0;
271+
272+
quals = extract_actual_clauses(child_rel->baserestrictinfo, false);
273+
274+
/* Do not proceed if there's a rel containing quals without params */
275+
if (!clause_contains_extern_params((Node *) quals))
276+
break;
277+
278+
/* Replace child Vars with a parent rel's Var */
279+
quals = (List *) replace_child_vars_with_parent_var((Node *) quals,
280+
&repl_var_cxt);
281+
282+
/* Combine unique 'picky' quals */
283+
foreach (qual_cell, quals)
284+
picky_quals = list_append_unique(picky_quals,
285+
(Node *) lfirst(qual_cell));
286+
}
287+
288+
/*
289+
* Dismiss PickyAppend if there
290+
* are no parameterized quals
291+
*/
292+
if (picky_quals == NIL)
293+
continue;
294+
295+
inner_path = create_pickyappend_path(root, cur_path,
296+
ppi, picky_quals);
297+
298+
add_path(rel, inner_path);
299+
}
242300
}
243301

244302
/* Invoke original hook if needed */

nodes_common.c

Lines changed: 14 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ transform_plans_into_states(PickyAppendState *scan_state,
5252
* We should ReScan this node manually since
5353
* ExecProcNode won't do this for us in this case.
5454
*/
55-
if (!pps->ps->chgParam)
55+
if (bms_is_empty(pps->ps->chgParam))
5656
ExecReScan(pps->ps);
5757

5858
child->content.plan_state = pps->ps;
@@ -125,22 +125,6 @@ get_partition_oids(List *ranges, int *n, PartRelationInfo *prel)
125125
return result;
126126
}
127127

128-
/* Compare plans by 'original_order' */
129-
static int
130-
cmp_child_scan_common_by_orig_order(const void *ap,
131-
const void *bp)
132-
{
133-
ChildScanCommon a = *(ChildScanCommon *) ap;
134-
ChildScanCommon b = *(ChildScanCommon *) bp;
135-
136-
if (a->original_order > b->original_order)
137-
return 1;
138-
else if (a->original_order < b->original_order)
139-
return -1;
140-
else
141-
return 0;
142-
}
143-
144128
static void
145129
pack_pickyappend_private(CustomScan *cscan, PickyAppendPath *path)
146130
{
@@ -172,7 +156,6 @@ unpack_pickyappend_private(PickyAppendState *scan_state, CustomScan *cscan)
172156
int nchildren = list_length(custom_oids);
173157
HTAB *children_table = scan_state->children_table;
174158
HASHCTL *children_table_config = &scan_state->children_table_config;
175-
int i;
176159

177160
memset(children_table_config, 0, sizeof(HASHCTL));
178161
children_table_config->keysize = sizeof(Oid);
@@ -182,7 +165,6 @@ unpack_pickyappend_private(PickyAppendState *scan_state, CustomScan *cscan)
182165
children_table_config,
183166
HASH_ELEM | HASH_BLOBS);
184167

185-
i = 0;
186168
forboth (oid_cell, custom_oids, plan_cell, cscan->custom_plans)
187169
{
188170
bool child_found;
@@ -195,7 +177,6 @@ unpack_pickyappend_private(PickyAppendState *scan_state, CustomScan *cscan)
195177
Assert(!child_found); /* there should be no collisions */
196178

197179
child->content.plan = (Plan *) lfirst(plan_cell);
198-
child->original_order = i++; /* will be used in EXPLAIN */
199180
}
200181

201182
scan_state->children_table = children_table;
@@ -333,6 +314,18 @@ begin_append_common(CustomScanState *node, EState *estate, int eflags)
333314
scan_state->plan_state_table = plan_state_table;
334315
scan_state->custom_expr_states = (List *) ExecInitExpr((Expr *) scan_state->custom_exprs,
335316
(PlanState *) scan_state);
317+
318+
/*
319+
* ExecProcNode() won't ReScan plans without params, do this
320+
* provided that there are no external PARAM_EXEC params.
321+
*
322+
* rescan_append_common is required for prepared statements,
323+
* but at the same time we don't want it to be called several
324+
* times within a single run (for example, ExecNestLoop calls
325+
* ExecReScan itself)
326+
*/
327+
if (!node->ss.ps.chgParam && bms_is_empty(node->ss.ps.plan->extParam))
328+
rescan_append_common(node);
336329
}
337330

338331
void
@@ -391,47 +384,5 @@ rescan_append_common(CustomScanState *node)
391384
void
392385
explain_append_common(CustomScanState *node, HTAB* children_table, ExplainState *es)
393386
{
394-
/* Construct excess PlanStates */
395-
if (!es->analyze)
396-
{
397-
int allocated = 10;
398-
int used = 0;
399-
ChildScanCommon *custom_ps = palloc(allocated * sizeof(ChildScanCommon));
400-
ChildScanCommon child;
401-
HASH_SEQ_STATUS seqstat;
402-
int i;
403-
404-
/* There can't be any nodes since we're not scanning anything */
405-
Assert(!node->custom_ps);
406-
407-
hash_seq_init(&seqstat, children_table);
408-
409-
while ((child = (ChildScanCommon) hash_seq_search(&seqstat)))
410-
{
411-
if (allocated <= used)
412-
{
413-
allocated *= 2;
414-
custom_ps = repalloc(custom_ps, allocated * sizeof(ChildScanCommon));
415-
}
416-
417-
custom_ps[used++] = child;
418-
}
419-
420-
/*
421-
* We have to restore the original plan order
422-
* which has been lost within the hash table
423-
*/
424-
qsort(custom_ps, used, sizeof(ChildScanCommon),
425-
cmp_child_scan_common_by_orig_order);
426-
427-
/*
428-
* These PlanStates will be used by EXPLAIN,
429-
* arrangeappend_end will destroy them eventually
430-
*/
431-
for (i = 0; i < used; i++)
432-
node->custom_ps = lappend(node->custom_ps,
433-
ExecInitNode(custom_ps[i]->content.plan,
434-
node->ss.ps.state,
435-
0));
436-
}
387+
/* Nothing to do here */
437388
}

nodes_common.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@ typedef struct
2424
Plan *plan;
2525
PlanState *plan_state;
2626
} content;
27-
28-
int original_order; /* for sorting in EXPLAIN */
2927
} ChildScanCommonData;
3028

3129
typedef ChildScanCommonData *ChildScanCommon;

utils.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#include "nodes/nodeFuncs.h"
33
#include "parser/parse_param.h"
44
#include "utils/builtins.h"
5+
#include "rewrite/rewriteManip.h"
56

67

78
static bool clause_contains_extern_params_walker(Node *node, void *context);
@@ -31,3 +32,30 @@ clause_contains_extern_params_walker(Node *node, void *context)
3132
clause_contains_extern_params_walker,
3233
context);
3334
}
35+
36+
static Node *
37+
replace_child_var(Var *var, replace_rte_variables_context *context)
38+
{
39+
ReplaceVarsContext *cxt = (ReplaceVarsContext *) context->callback_arg;
40+
Var *new_var;
41+
42+
new_var = makeNode(Var);
43+
memcpy(new_var, var, sizeof(Var));
44+
45+
/*
46+
* Replace a partition's Var with a Var
47+
* pointing to the PickyAppend's results
48+
*/
49+
new_var->varno = cxt->parent->relid;
50+
new_var->location = -1;
51+
new_var->varnoold = 0;
52+
53+
return (Node *) new_var;
54+
}
55+
56+
Node *
57+
replace_child_vars_with_parent_var(Node *node, ReplaceVarsContext *context)
58+
{
59+
return replace_rte_variables(node, context->child->relid, context->sublevels_up,
60+
replace_child_var, (void *) context, NULL);
61+
}

utils.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,19 @@
22
#define UTILS_H
33

44
#include "postgres.h"
5+
#include "nodes/relation.h"
56
#include "nodes/nodeFuncs.h"
67

8+
typedef struct
9+
{
10+
RelOptInfo *child;
11+
RelOptInfo *parent;
12+
int sublevels_up;
13+
} ReplaceVarsContext;
14+
715
bool clause_contains_extern_params(Node *clause);
816

17+
Node * replace_child_vars_with_parent_var(Node *node,
18+
ReplaceVarsContext *context);
19+
920
#endif

0 commit comments

Comments
 (0)