Skip to content

Commit 3629c43

Browse files
committed
extract common code from PickyAppend & ArrangeAppend
1 parent 8f33649 commit 3629c43

File tree

4 files changed

+412
-337
lines changed

4 files changed

+412
-337
lines changed

nodes_common.c

Lines changed: 370 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,130 @@
11
#include "postgres.h"
22
#include "optimizer/paths.h"
33
#include "nodes_common.h"
4+
#include "pickyappend.h"
45

56

7+
static void
8+
free_child_scan_common_array(ChildScanCommon *cur_plans, int n)
9+
{
10+
int i;
11+
12+
if (!cur_plans)
13+
return;
14+
15+
/* We shouldn't free inner objects e.g. Plans here */
16+
for (i = 0; i < n; i++)
17+
pfree(cur_plans[i]);
18+
19+
pfree(cur_plans);
20+
}
21+
22+
static void
23+
transform_plans_into_states(PickyAppendState *scan_state,
24+
ChildScanCommon *selected_plans, int n,
25+
EState *estate)
26+
{
27+
int i;
28+
29+
for (i = 0; i < n; i++)
30+
{
31+
ChildScanCommon child = selected_plans[i];
32+
PreservedPlanState *pps;
33+
bool pps_found;
34+
35+
pps = (PreservedPlanState *) hash_search(scan_state->plan_state_table,
36+
(const void *) &child->relid,
37+
HASH_ENTER, &pps_found);
38+
39+
/* Create new node since this plan hasn't been used yet */
40+
if (!pps_found)
41+
{
42+
pps->ps = ExecInitNode(child->content.plan, estate, 0);
43+
/* Explain and clear_plan_states rely on this list */
44+
scan_state->css.custom_ps = lappend(scan_state->css.custom_ps, pps->ps);
45+
}
46+
47+
/* Node with params will be ReScanned */
48+
if (scan_state->css.ss.ps.chgParam)
49+
UpdateChangedParamSet(pps->ps, scan_state->css.ss.ps.chgParam);
50+
51+
/*
52+
* We should ReScan this node manually since
53+
* ExecProcNode won't do this for us in this case.
54+
*/
55+
if (!pps->ps->chgParam)
56+
ExecReScan(pps->ps);
57+
58+
child->content.plan_state = pps->ps;
59+
}
60+
}
61+
62+
static ChildScanCommon *
63+
select_required_plans(HTAB *children_table, Oid *parts, int nparts, int *nres)
64+
{
65+
int allocated = 10;
66+
int used = 0;
67+
ChildScanCommon *result = palloc(10 * sizeof(ChildScanCommon));
68+
int i;
69+
70+
for (i = 0; i < nparts; i++)
71+
{
72+
ChildScanCommon child_copy;
73+
ChildScanCommon child = hash_search(children_table,
74+
(const void *) &parts[i],
75+
HASH_FIND, NULL);
76+
if (!child)
77+
continue;
78+
79+
if (allocated <= used)
80+
{
81+
allocated *= 2;
82+
result = repalloc(result, allocated * sizeof(ChildScanCommon));
83+
}
84+
85+
child_copy = palloc(sizeof(ChildScanCommonData));
86+
memcpy(child_copy, child, sizeof(ChildScanCommonData));
87+
88+
result[used++] = child_copy;
89+
}
90+
91+
*nres = used;
92+
return result;
93+
}
94+
95+
/* Transform partition ranges into plain array of partition Oids */
96+
static Oid *
97+
get_partition_oids(List *ranges, int *n, PartRelationInfo *prel)
98+
{
99+
ListCell *range_cell;
100+
int allocated = 10;
101+
int used = 0;
102+
Oid *result = palloc(allocated * sizeof(Oid));
103+
Oid *children = dsm_array_get_pointer(&prel->children);
104+
105+
foreach (range_cell, ranges)
106+
{
107+
int i;
108+
int a = irange_lower(lfirst_irange(range_cell));
109+
int b = irange_upper(lfirst_irange(range_cell));
110+
111+
for (i = a; i <= b; i++)
112+
{
113+
if (allocated <= used)
114+
{
115+
allocated *= 2;
116+
result = repalloc(result, allocated * sizeof(Oid));
117+
}
118+
119+
Assert(i < prel->children_count);
120+
result[used++] = children[i];
121+
}
122+
}
123+
124+
*n = used;
125+
return result;
126+
}
127+
6128
/* Compare plans by 'original_order' */
7129
static int
8130
cmp_child_scan_common_by_orig_order(const void *ap,
@@ -19,8 +141,255 @@ cmp_child_scan_common_by_orig_order(const void *ap,
19141
return 0;
20142
}
21143

144+
static void
145+
pack_pickyappend_private(CustomScan *cscan, PickyAppendPath *path)
146+
{
147+
ChildScanCommon *children = path->children;
148+
int nchildren = path->nchildren;
149+
List *custom_private = NIL;
150+
List *custom_oids = NIL;
151+
int i;
152+
153+
for (i = 0; i < nchildren; i++)
154+
{
155+
/* We've already filled 'custom_paths' in create_pickyappend_path */
156+
custom_oids = lappend_oid(custom_oids, children[i]->relid);
157+
pfree(children[i]);
158+
}
159+
160+
/* Save main table and partition relids */
161+
custom_private = list_make2(list_make1_oid(path->relid), custom_oids);
162+
163+
cscan->custom_private = custom_private;
164+
}
165+
166+
static void
167+
unpack_pickyappend_private(PickyAppendState *scan_state, CustomScan *cscan)
168+
{
169+
ListCell *oid_cell;
170+
ListCell *plan_cell;
171+
List *custom_oids = (List *) lsecond(cscan->custom_private);
172+
int nchildren = list_length(custom_oids);
173+
HTAB *children_table = scan_state->children_table;
174+
HASHCTL *children_table_config = &scan_state->children_table_config;
175+
int i;
176+
177+
memset(children_table_config, 0, sizeof(HASHCTL));
178+
children_table_config->keysize = sizeof(Oid);
179+
children_table_config->entrysize = sizeof(ChildScanCommonData);
180+
181+
children_table = hash_create("Plan storage", nchildren,
182+
children_table_config,
183+
HASH_ELEM | HASH_BLOBS);
184+
185+
i = 0;
186+
forboth (oid_cell, custom_oids, plan_cell, cscan->custom_plans)
187+
{
188+
bool child_found;
189+
Oid cur_oid = lfirst_oid(oid_cell);
190+
191+
ChildScanCommon child = hash_search(children_table,
192+
(const void *) &cur_oid,
193+
HASH_ENTER, &child_found);
194+
195+
Assert(!child_found); /* there should be no collisions */
196+
197+
child->content.plan = (Plan *) lfirst(plan_cell);
198+
child->original_order = i++; /* will be used in EXPLAIN */
199+
}
200+
201+
scan_state->children_table = children_table;
202+
scan_state->relid = linitial_oid(linitial(cscan->custom_private));
203+
}
204+
205+
Path *
206+
create_append_path_common(PlannerInfo *root,
207+
AppendPath *inner_append,
208+
ParamPathInfo *param_info,
209+
List *picky_clauses,
210+
CustomPathMethods *path_methods)
211+
{
212+
RelOptInfo *innerrel = inner_append->path.parent;
213+
ListCell *lc;
214+
int i;
215+
216+
RangeTblEntry *inner_entry = root->simple_rte_array[innerrel->relid];
217+
218+
PickyAppendPath *result;
219+
220+
result = palloc0(sizeof(PickyAppendPath));
221+
NodeSetTag(result, T_CustomPath);
222+
223+
result->cpath.path.pathtype = T_CustomScan;
224+
result->cpath.path.parent = innerrel;
225+
result->cpath.path.param_info = param_info;
226+
result->cpath.path.pathkeys = NIL;
227+
#if PG_VERSION_NUM >= 90600
228+
result->cpath.path.pathtarget = inner_append->path.pathtarget;
229+
#endif
230+
result->cpath.path.rows = inner_append->path.rows;
231+
result->cpath.flags = 0;
232+
result->cpath.methods = path_methods;
233+
234+
/* TODO: real costs */
235+
result->cpath.path.startup_cost = 0;
236+
result->cpath.path.total_cost = 0;
237+
238+
/* Set 'partitioned column'-related clauses */
239+
result->cpath.custom_private = picky_clauses;
240+
result->cpath.custom_paths = NIL;
241+
242+
Assert(inner_entry->relid != 0);
243+
result->relid = inner_entry->relid;
244+
245+
result->nchildren = list_length(inner_append->subpaths);
246+
result->children = palloc(result->nchildren * sizeof(ChildScanCommon));
247+
i = 0;
248+
foreach (lc, inner_append->subpaths)
249+
{
250+
Path *path = lfirst(lc);
251+
Index relindex = path->parent->relid;
252+
ChildScanCommon child = palloc(sizeof(ChildScanCommonData));
253+
254+
child->content.path = path;
255+
child->relid = root->simple_rte_array[relindex]->relid;
256+
Assert(child->relid != InvalidOid);
257+
258+
result->cpath.custom_paths = lappend(result->cpath.custom_paths,
259+
child->content.path);
260+
result->children[i] = child;
261+
262+
i++;
263+
}
264+
265+
return &result->cpath.path;
266+
}
267+
268+
Plan *
269+
create_append_plan_common(PlannerInfo* root, RelOptInfo* rel,
270+
CustomPath* best_path, List* tlist,
271+
List* clauses, List* custom_plans,
272+
CustomScanMethods *scan_methods)
273+
{
274+
PickyAppendPath *gpath = (PickyAppendPath *) best_path;
275+
CustomScan *cscan;
276+
277+
cscan = makeNode(CustomScan);
278+
cscan->scan.plan.qual = NIL;
279+
cscan->scan.plan.targetlist = tlist;
280+
cscan->custom_scan_tlist = tlist;
281+
cscan->scan.scanrelid = 0;
282+
283+
cscan->custom_exprs = gpath->cpath.custom_private;
284+
cscan->custom_plans = custom_plans;
285+
286+
cscan->methods = scan_methods;
287+
288+
pack_pickyappend_private(cscan, gpath);
289+
290+
return &cscan->scan.plan;
291+
}
292+
293+
Node *
294+
create_append_scan_state_common(CustomScan* node,
295+
CustomExecMethods *exec_methods,
296+
uint32 size)
297+
{
298+
PickyAppendState *scan_state = palloc0(size);
299+
300+
NodeSetTag(scan_state, T_CustomScanState);
301+
scan_state->css.flags = node->flags;
302+
scan_state->css.methods = exec_methods;
303+
scan_state->custom_exprs = node->custom_exprs;
304+
305+
unpack_pickyappend_private(scan_state, node);
306+
307+
/* Fill in relation info using main table's relid */
308+
scan_state->prel = get_pathman_relation_info(scan_state->relid, NULL);
309+
Assert(scan_state->prel);
310+
311+
scan_state->cur_plans = NULL;
312+
scan_state->ncur_plans = 0;
313+
scan_state->running_idx = 0;
314+
315+
return (Node *) scan_state;
316+
}
317+
318+
void
319+
begin_append_common(CustomScanState *node, EState *estate, int eflags)
320+
{
321+
PickyAppendState *scan_state = (PickyAppendState *) node;
322+
HTAB *plan_state_table = scan_state->plan_state_table;
323+
HASHCTL *plan_state_table_config = &scan_state->plan_state_table_config;
324+
325+
memset(plan_state_table_config, 0, sizeof(HASHCTL));
326+
plan_state_table_config->keysize = sizeof(Oid);
327+
plan_state_table_config->entrysize = sizeof(PreservedPlanState);
328+
329+
plan_state_table = hash_create("PlanState storage", 128,
330+
plan_state_table_config,
331+
HASH_ELEM | HASH_BLOBS);
332+
333+
scan_state->plan_state_table = plan_state_table;
334+
scan_state->custom_expr_states = (List *) ExecInitExpr((Expr *) scan_state->custom_exprs,
335+
(PlanState *) scan_state);
336+
}
337+
338+
void
339+
end_append_common(CustomScanState *node)
340+
{
341+
PickyAppendState *scan_state = (PickyAppendState *) node;
342+
343+
clear_plan_states(&scan_state->css);
344+
hash_destroy(scan_state->plan_state_table);
345+
hash_destroy(scan_state->children_table);
346+
}
347+
348+
void
349+
rescan_append_common(CustomScanState *node)
350+
{
351+
PickyAppendState *scan_state = (PickyAppendState *) node;
352+
ExprContext *econtext = node->ss.ps.ps_ExprContext;
353+
PartRelationInfo *prel = scan_state->prel;
354+
List *ranges;
355+
ListCell *lc;
356+
Oid *parts;
357+
int nparts;
358+
359+
ranges = list_make1_int(make_irange(0, prel->children_count - 1, false));
360+
361+
foreach (lc, scan_state->custom_exprs)
362+
{
363+
WrapperNode *wn;
364+
WalkerContext wcxt;
365+
366+
wcxt.econtext = econtext;
367+
wn = walk_expr_tree(&wcxt, (Expr *) lfirst(lc), prel);
368+
369+
ranges = irange_list_intersect(ranges, wn->rangeset);
370+
}
371+
372+
/* Get Oids of the required partitions */
373+
parts = get_partition_oids(ranges, &nparts, prel);
374+
375+
/* Select new plans for this run using 'parts' */
376+
free_child_scan_common_array(scan_state->cur_plans, scan_state->ncur_plans);
377+
scan_state->cur_plans = select_required_plans(scan_state->children_table,
378+
parts, nparts,
379+
&scan_state->ncur_plans);
380+
pfree(parts);
381+
382+
/* Transform selected plans into executable plan states */
383+
transform_plans_into_states(scan_state,
384+
scan_state->cur_plans,
385+
scan_state->ncur_plans,
386+
scan_state->css.ss.ps.state);
387+
388+
scan_state->running_idx = 0;
389+
}
390+
22391
void
23-
explain_common(CustomScanState *node, HTAB* children_table, ExplainState *es)
392+
explain_append_common(CustomScanState *node, HTAB* children_table, ExplainState *es)
24393
{
25394
/* Construct excess PlanStates */
26395
if (!es->analyze)

0 commit comments

Comments
 (0)