Skip to content

Commit 0b92348

Browse files
committed
fix ReScan in transform_plans_into_states(), show plans in EXPLAIN (without ANALYZE), more comments
1 parent 4a838d3 commit 0b92348

File tree

2 files changed

+106
-30
lines changed

2 files changed

+106
-30
lines changed

pickyappend.c

Lines changed: 98 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,30 @@ CustomScanMethods pickyappend_plan_methods;
2020
CustomExecMethods pickyappend_exec_methods;
2121

2222

23+
/*
24+
* Element of the plan_state_table
25+
*/
2326
typedef struct
2427
{
2528
Oid relid; /* relid of the corresponding partition */
2629
PlanState *ps;
2730
} PreservedPlanState;
2831

32+
/* Compare plans by 'original_order' */
33+
static int
34+
cmp_child_scan_common_by_orig_order(const void *ap,
35+
const void *bp)
36+
{
37+
ChildScanCommon a = *(ChildScanCommon *) ap;
38+
ChildScanCommon b = *(ChildScanCommon *) bp;
39+
40+
if (a->original_order > b->original_order)
41+
return 1;
42+
else if (a->original_order < b->original_order)
43+
return -1;
44+
else
45+
return 0;
46+
}
2947

3048
static void
3149
free_child_scan_common_array(ChildScanCommon *cur_plans, int n)
@@ -45,14 +63,11 @@ free_child_scan_common_array(ChildScanCommon *cur_plans, int n)
4563
static void
4664
clear_plan_states(PickyAppendState *scan_state)
4765
{
48-
PreservedPlanState *pps;
49-
HASH_SEQ_STATUS seqstat;
66+
ListCell *state_cell;
5067

51-
hash_seq_init(&seqstat, scan_state->plan_state_table);
52-
53-
while ((pps = (PreservedPlanState *) hash_seq_search(&seqstat)))
68+
foreach (state_cell, scan_state->css.custom_ps)
5469
{
55-
ExecEndNode(pps->ps);
70+
ExecEndNode((PlanState *) lfirst(state_cell));
5671
}
5772
}
5873

@@ -73,15 +88,25 @@ transform_plans_into_states(PickyAppendState *scan_state,
7388
(const void *) &child->relid,
7489
HASH_ENTER, &pps_found);
7590

91+
/* Create new node since this plan hasn't been used yet */
7692
if (!pps_found)
7793
{
7894
pps->ps = ExecInitNode(child->content.plan, estate, 0);
95+
/* Explain and clear_plan_states rely on this list */
7996
scan_state->css.custom_ps = lappend(scan_state->css.custom_ps, pps->ps);
8097
}
81-
else
98+
99+
/* Node with params will be ReScanned */
100+
if (scan_state->css.ss.ps.chgParam)
101+
UpdateChangedParamSet(pps->ps, scan_state->css.ss.ps.chgParam);
102+
103+
/*
104+
* We should ReScan this node manually since
105+
* ExecProcNode won't do this for us in this case.
106+
*/
107+
if (!pps->ps->chgParam)
82108
ExecReScan(pps->ps);
83109

84-
child->content_type = CHILD_PLAN_STATE;
85110
child->content.plan_state = pps->ps;
86111
}
87112
}
@@ -119,6 +144,7 @@ select_required_plans(HTAB *children_table, Oid *parts, int nparts, int *nres)
119144
return result;
120145
}
121146

147+
/* Transform partition ranges into plain array of partition Oids */
122148
static Oid *
123149
get_partition_oids(List *ranges, int *n, PartRelationInfo *prel)
124150
{
@@ -216,7 +242,6 @@ create_pickyappend_path(PlannerInfo *root,
216242
Index relindex = path->parent->relid;
217243
ChildScanCommon child = palloc(sizeof(ChildScanCommonData));
218244

219-
child->content_type = CHILD_PATH;
220245
child->content.path = path;
221246
child->relid = root->simple_rte_array[relindex]->relid;
222247
Assert(child->relid != InvalidOid);
@@ -305,6 +330,7 @@ save_pickyappend_private(CustomScan *cscan, PickyAppendPath *path)
305330
pfree(children[i]);
306331
}
307332

333+
/* Save main table and partition relids */
308334
custom_private = list_make2(list_make1_oid(path->relid), custom_oids);
309335

310336
cscan->custom_private = custom_private;
@@ -319,24 +345,30 @@ unpack_pickyappend_private(PickyAppendState *scan_state, CustomScan *cscan)
319345
int nchildren = list_length(custom_oids);
320346
HTAB *children_table = scan_state->children_table;
321347
HASHCTL *children_table_config = &scan_state->children_table_config;
348+
int i;
322349

323350
memset(children_table_config, 0, sizeof(HASHCTL));
324351
children_table_config->keysize = sizeof(Oid);
325352
children_table_config->entrysize = sizeof(ChildScanCommonData);
326353

327354
children_table = hash_create("Plan storage", nchildren,
328-
children_table_config, HASH_ELEM | HASH_BLOBS);
355+
children_table_config,
356+
HASH_ELEM | HASH_BLOBS);
329357

358+
i = 0;
330359
forboth (oid_cell, custom_oids, plan_cell, cscan->custom_plans)
331360
{
332-
Oid cur_oid = lfirst_oid(oid_cell);
361+
bool child_found;
362+
Oid cur_oid = lfirst_oid(oid_cell);
333363

334-
ChildScanCommon child = hash_search(children_table,
335-
(const void *) &cur_oid,
336-
HASH_ENTER, NULL);
364+
ChildScanCommon child = hash_search(children_table,
365+
(const void *) &cur_oid,
366+
HASH_ENTER, &child_found);
367+
368+
Assert(!child_found); /* there should be no collisions */
337369

338-
child->content_type = CHILD_PLAN;
339370
child->content.plan = (Plan *) lfirst(plan_cell);
371+
child->original_order = i++; /* will be used in EXPLAIN */
340372
}
341373

342374
scan_state->children_table = children_table;
@@ -379,7 +411,9 @@ pickyappend_create_scan_state(CustomScan *node)
379411

380412
unpack_pickyappend_private(scan_state, node);
381413

414+
/* Fill in relation info using main table's relid */
382415
scan_state->prel = get_pathman_relation_info(scan_state->relid, NULL);
416+
Assert(scan_state->prel);
383417

384418
scan_state->cur_plans = NULL;
385419
scan_state->ncur_plans = 0;
@@ -400,7 +434,8 @@ pickyappend_begin(CustomScanState *node, EState *estate, int eflags)
400434
plan_state_table_config->entrysize = sizeof(PreservedPlanState);
401435

402436
plan_state_table = hash_create("PlanState storage", 128,
403-
plan_state_table_config, HASH_ELEM | HASH_BLOBS);
437+
plan_state_table_config,
438+
HASH_ELEM | HASH_BLOBS);
404439

405440
scan_state->plan_state_table = plan_state_table;
406441
scan_state->custom_expr_states = (List *) ExecInitExpr((Expr *) scan_state->custom_exprs,
@@ -474,9 +509,10 @@ pickyappend_rescan(CustomScanState *node)
474509
ranges = irange_list_intersect(ranges, wn->rangeset);
475510
}
476511

512+
/* Get Oids of the required partitions */
477513
parts = get_partition_oids(ranges, &nparts, prel);
478514

479-
/* Select new plans for this pass */
515+
/* Select new plans for this run using 'parts' */
480516
free_child_scan_common_array(scan_state->cur_plans, scan_state->ncur_plans);
481517
scan_state->cur_plans = select_required_plans(scan_state->children_table,
482518
parts, nparts,
@@ -490,11 +526,54 @@ pickyappend_rescan(CustomScanState *node)
490526
scan_state->css.ss.ps.state);
491527

492528
scan_state->running_idx = 0;
493-
494-
/* elog(LOG, "nparts: %d, plans: %d", nparts, nplans); */
495529
}
496530

497531
void
498532
pickyppend_explain(CustomScanState *node, List *ancestors, ExplainState *es)
499533
{
534+
PickyAppendState *scan_state = (PickyAppendState *) node;
535+
536+
/* Construct excess PlanStates */
537+
if (!es->analyze)
538+
{
539+
int allocated = 10;
540+
int used = 0;
541+
ChildScanCommon *custom_ps = palloc(allocated * sizeof(ChildScanCommon));
542+
ChildScanCommon child;
543+
HASH_SEQ_STATUS seqstat;
544+
int i;
545+
546+
/* There can't be any nodes since we're not scanning anything */
547+
Assert(!node->custom_ps);
548+
549+
hash_seq_init(&seqstat, scan_state->children_table);
550+
551+
while ((child = (ChildScanCommon) hash_seq_search(&seqstat)))
552+
{
553+
if (allocated <= used)
554+
{
555+
allocated *= 2;
556+
custom_ps = repalloc(custom_ps, allocated * sizeof(ChildScanCommon));
557+
}
558+
559+
custom_ps[used++] = child;
560+
}
561+
562+
/*
563+
* We have to restore the original plan order
564+
* which has been lost within the hash table
565+
*/
566+
qsort(custom_ps, used, sizeof(ChildScanCommon),
567+
cmp_child_scan_common_by_orig_order);
568+
569+
/*
570+
* These PlanStates will be used by EXPLAIN,
571+
* pickyappend_end will destroy them eventually
572+
*/
573+
for (i = 0; i < used; i++)
574+
node->custom_ps = lappend(node->custom_ps,
575+
ExecInitNode(custom_ps[i]->content.plan,
576+
node->ss.ps.state,
577+
0));
578+
}
500579
}

pickyappend.h

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,43 +11,40 @@ extern bool pg_pathman_enable_pickyappend;
1111

1212
typedef struct
1313
{
14-
Oid relid;
15-
16-
enum
17-
{
18-
CHILD_PATH = 0,
19-
CHILD_PLAN,
20-
CHILD_PLAN_STATE
21-
} content_type;
14+
Oid relid; /* partition relid */
2215

2316
union
2417
{
2518
Path *path;
2619
Plan *plan;
2720
PlanState *plan_state;
2821
} content;
22+
23+
int original_order; /* for sorting in EXPLAIN */
2924
} ChildScanCommonData;
3025

3126
typedef ChildScanCommonData *ChildScanCommon;
3227

3328
typedef struct
3429
{
3530
CustomPath cpath;
36-
Oid relid;
31+
Oid relid; /* relid of the partitioned table */
3732

38-
ChildScanCommon *children;
33+
ChildScanCommon *children; /* all available plans */
3934
int nchildren;
4035
} PickyAppendPath;
4136

4237
typedef struct
4338
{
4439
CustomScanState css;
45-
Oid relid;
40+
Oid relid; /* relid of the partitioned table */
4641
PartRelationInfo *prel;
4742

43+
/* Restrictions to be checked during ReScan and Exec */
4844
List *custom_exprs;
4945
List *custom_expr_states;
5046

47+
/* All available plans */
5148
HTAB *children_table;
5249
HASHCTL children_table_config;
5350

0 commit comments

Comments
 (0)