Skip to content

Commit da48f47

Browse files
committed
perform ReScan in pickyappend_exec (required for IndexScans), restore previous EXPLAIN behavior
1 parent 5b2c983 commit da48f47

File tree

3 files changed

+72
-13
lines changed

3 files changed

+72
-13
lines changed

nodes_common.c

Lines changed: 65 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,23 @@
1313
#include "pickyappend.h"
1414

1515

16+
17+
/* Compare plans by 'original_order' */
18+
static int
19+
cmp_child_scan_common_by_orig_order(const void *ap,
20+
const void *bp)
21+
{
22+
ChildScanCommon a = *(ChildScanCommon *) ap;
23+
ChildScanCommon b = *(ChildScanCommon *) bp;
24+
25+
if (a->original_order > b->original_order)
26+
return 1;
27+
else if (a->original_order < b->original_order)
28+
return -1;
29+
else
30+
return 0;
31+
}
32+
1633
static void
1734
free_child_scan_common_array(ChildScanCommon *cur_plans, int n)
1835
{
@@ -165,6 +182,7 @@ unpack_pickyappend_private(PickyAppendState *scan_state, CustomScan *cscan)
165182
int nchildren = list_length(custom_oids);
166183
HTAB *children_table = scan_state->children_table;
167184
HASHCTL *children_table_config = &scan_state->children_table_config;
185+
int i;
168186

169187
memset(children_table_config, 0, sizeof(HASHCTL));
170188
children_table_config->keysize = sizeof(Oid);
@@ -174,6 +192,7 @@ unpack_pickyappend_private(PickyAppendState *scan_state, CustomScan *cscan)
174192
children_table_config,
175193
HASH_ELEM | HASH_BLOBS);
176194

195+
i = 0;
177196
forboth (oid_cell, custom_oids, plan_cell, cscan->custom_plans)
178197
{
179198
bool child_found;
@@ -186,6 +205,7 @@ unpack_pickyappend_private(PickyAppendState *scan_state, CustomScan *cscan)
186205
Assert(!child_found); /* there should be no collisions */
187206

188207
child->content.plan = (Plan *) lfirst(plan_cell);
208+
child->original_order = i++; /* will be used in EXPLAIN */
189209
}
190210

191211
scan_state->children_table = children_table;
@@ -323,18 +343,6 @@ begin_append_common(CustomScanState *node, EState *estate, int eflags)
323343
scan_state->plan_state_table = plan_state_table;
324344
scan_state->custom_expr_states = (List *) ExecInitExpr((Expr *) scan_state->custom_exprs,
325345
(PlanState *) scan_state);
326-
327-
/*
328-
* ExecProcNode() won't ReScan plans without params, do this
329-
* provided that there are no external PARAM_EXEC params.
330-
*
331-
* rescan_append_common is required for prepared statements,
332-
* but at the same time we don't want it to be called several
333-
* times within a single run (for example, ExecNestLoop calls
334-
* ExecReScan itself)
335-
*/
336-
if (!node->ss.ps.chgParam && bms_is_empty(node->ss.ps.plan->extParam))
337-
rescan_append_common(node);
338346
}
339347

340348
void
@@ -393,5 +401,49 @@ rescan_append_common(CustomScanState *node)
393401
void
394402
explain_append_common(CustomScanState *node, HTAB* children_table, ExplainState *es)
395403
{
396-
/* Nothing to do here */
404+
PickyAppendState *scan_state = (PickyAppendState *) node;
405+
406+
/* Construct excess PlanStates */
407+
if (!es->analyze)
408+
{
409+
int allocated = 10;
410+
int used = 0;
411+
ChildScanCommon *custom_ps = palloc(allocated * sizeof(ChildScanCommon));
412+
ChildScanCommon child;
413+
HASH_SEQ_STATUS seqstat;
414+
int i;
415+
416+
/* There can't be any nodes since we're not scanning anything */
417+
Assert(!node->custom_ps);
418+
419+
hash_seq_init(&seqstat, scan_state->children_table);
420+
421+
while ((child = (ChildScanCommon) hash_seq_search(&seqstat)))
422+
{
423+
if (allocated <= used)
424+
{
425+
allocated *= 2;
426+
custom_ps = repalloc(custom_ps, allocated * sizeof(ChildScanCommon));
427+
}
428+
429+
custom_ps[used++] = child;
430+
}
431+
432+
/*
433+
* We have to restore the original plan order
434+
* which has been lost within the hash table
435+
*/
436+
qsort(custom_ps, used, sizeof(ChildScanCommon),
437+
cmp_child_scan_common_by_orig_order);
438+
439+
/*
440+
* These PlanStates will be used by EXPLAIN,
441+
* pickyappend_end will destroy them eventually
442+
*/
443+
for (i = 0; i < used; i++)
444+
node->custom_ps = lappend(node->custom_ps,
445+
ExecInitNode(custom_ps[i]->content.plan,
446+
node->ss.ps.state,
447+
0));
448+
}
397449
}

nodes_common.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ typedef struct
3333
Plan *plan;
3434
PlanState *plan_state;
3535
} content;
36+
37+
int original_order; /* for sorting in EXPLAIN */
3638
} ChildScanCommonData;
3739

3840
typedef ChildScanCommonData *ChildScanCommon;

pickyappend.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ pickyappend_exec(CustomScanState *node)
6060
{
6161
PickyAppendState *scan_state = (PickyAppendState *) node;
6262

63+
if (scan_state->ncur_plans == 0)
64+
ExecReScan(&node->ss.ps);
65+
6366
while (scan_state->running_idx < scan_state->ncur_plans)
6467
{
6568
ChildScanCommon child = scan_state->cur_plans[scan_state->running_idx];
@@ -85,6 +88,8 @@ pickyappend_exec(CustomScanState *node)
8588
scan_state->running_idx++;
8689
}
8790

91+
/* Force ReScan */
92+
scan_state->ncur_plans = 0;
8893
return NULL;
8994
}
9095

0 commit comments

Comments
 (0)