39
39
#include "postgres.h"
40
40
41
41
#include "executor/execdebug.h"
42
+ #include "executor/execPartition.h"
42
43
#include "executor/nodeMergeAppend.h"
43
44
#include "lib/binaryheap.h"
44
45
#include "miscadmin.h"
@@ -65,8 +66,10 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags)
65
66
{
66
67
MergeAppendState * mergestate = makeNode (MergeAppendState );
67
68
PlanState * * mergeplanstates ;
69
+ Bitmapset * validsubplans ;
68
70
int nplans ;
69
- int i ;
71
+ int i ,
72
+ j ;
70
73
ListCell * lc ;
71
74
72
75
/* check for unsupported flags */
@@ -78,19 +81,80 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags)
78
81
*/
79
82
ExecLockNonLeafAppendTables (node -> partitioned_rels ,estate );
80
83
81
- /*
82
- * Set up empty vector of subplan states
83
- */
84
- nplans = list_length (node -> mergeplans );
85
-
86
- mergeplanstates = (PlanState * * )palloc0 (nplans * sizeof (PlanState * ));
87
-
88
84
/*
89
85
* create new MergeAppendState for our node
90
86
*/
91
87
mergestate -> ps .plan = (Plan * )node ;
92
88
mergestate -> ps .state = estate ;
93
89
mergestate -> ps .ExecProcNode = ExecMergeAppend ;
90
+ mergestate -> ms_noopscan = false;
91
+
92
+ /* If run-time partition pruning is enabled, then set that up now */
93
+ if (node -> part_prune_infos != NIL )
94
+ {
95
+ PartitionPruneState * prunestate ;
96
+
97
+ /* We may need an expression context to evaluate partition exprs */
98
+ ExecAssignExprContext (estate ,& mergestate -> ps );
99
+
100
+ prunestate = ExecCreatePartitionPruneState (& mergestate -> ps ,
101
+ node -> part_prune_infos );
102
+ mergestate -> ms_prune_state = prunestate ;
103
+
104
+ /* Perform an initial partition prune, if required. */
105
+ if (prunestate -> do_initial_prune )
106
+ {
107
+ /* Determine which subplans survive initial pruning */
108
+ validsubplans = ExecFindInitialMatchingSubPlans (prunestate ,
109
+ list_length (node -> mergeplans ));
110
+
111
+ /*
112
+ * The case where no subplans survive pruning must be handled
113
+ * specially. The problem here is that code in explain.c requires
114
+ * an Append to have at least one subplan in order for it to
115
+ * properly determine the Vars in that subplan's targetlist. We
116
+ * sidestep this issue by just initializing the first subplan and
117
+ * setting ms_noopscan to true to indicate that we don't really
118
+ * need to scan any subnodes.
119
+ */
120
+ if (bms_is_empty (validsubplans ))
121
+ {
122
+ mergestate -> ms_noopscan = true;
123
+
124
+ /* Mark the first as valid so that it's initialized below */
125
+ validsubplans = bms_make_singleton (0 );
126
+ }
127
+
128
+ nplans = bms_num_members (validsubplans );
129
+ }
130
+ else
131
+ {
132
+ /* We'll need to initialize all subplans */
133
+ nplans = list_length (node -> mergeplans );
134
+ validsubplans = bms_add_range (NULL ,0 ,nplans - 1 );
135
+ }
136
+
137
+ /*
138
+ * If no runtime pruning is required, we can fill ms_valid_subplans
139
+ * immediately, preventing later calls to ExecFindMatchingSubPlans.
140
+ */
141
+ if (!prunestate -> do_exec_prune )
142
+ mergestate -> ms_valid_subplans = bms_add_range (NULL ,0 ,nplans - 1 );
143
+ }
144
+ else
145
+ {
146
+ nplans = list_length (node -> mergeplans );
147
+
148
+ /*
149
+ * When run-time partition pruning is not enabled we can just mark all
150
+ * subplans as valid; they must also all be initialized.
151
+ */
152
+ mergestate -> ms_valid_subplans = validsubplans =
153
+ bms_add_range (NULL ,0 ,nplans - 1 );
154
+ mergestate -> ms_prune_state = NULL ;
155
+ }
156
+
157
+ mergeplanstates = (PlanState * * )palloc (nplans * sizeof (PlanState * ));
94
158
mergestate -> mergeplans = mergeplanstates ;
95
159
mergestate -> ms_nplans = nplans ;
96
160
@@ -101,26 +165,24 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags)
101
165
/*
102
166
* Miscellaneous initialization
103
167
*
104
- * MergeAppend plans don't have expression contexts because they never
105
- * call ExecQual or ExecProject.
106
- */
107
-
108
- /*
109
168
* MergeAppend nodes do have Result slots, which hold pointers to tuples,
110
169
* so we have to initialize them.
111
170
*/
112
171
ExecInitResultTupleSlotTL (estate ,& mergestate -> ps );
113
172
114
173
/*
115
- * call ExecInitNode on each of the plans to be executed and save the
116
- * results into thearray "mergeplans" .
174
+ * call ExecInitNode on each of thevalid plans to be executed and save
175
+ *the results into themergeplanstates array .
117
176
*/
118
- i = 0 ;
177
+ j = i = 0 ;
119
178
foreach (lc ,node -> mergeplans )
120
179
{
121
- Plan * initNode = (Plan * )lfirst (lc );
180
+ if (bms_is_member (i ,validsubplans ))
181
+ {
182
+ Plan * initNode = (Plan * )lfirst (lc );
122
183
123
- mergeplanstates [i ]= ExecInitNode (initNode ,estate ,eflags );
184
+ mergeplanstates [j ++ ]= ExecInitNode (initNode ,estate ,eflags );
185
+ }
124
186
i ++ ;
125
187
}
126
188
@@ -178,11 +240,25 @@ ExecMergeAppend(PlanState *pstate)
178
240
179
241
if (!node -> ms_initialized )
180
242
{
243
+ /* Nothing to do if all subplans were pruned */
244
+ if (node -> ms_noopscan )
245
+ return ExecClearTuple (node -> ps .ps_ResultTupleSlot );
246
+
181
247
/*
182
- * First time through: pull the first tuple from each subplan, and set
183
- * up the heap.
248
+ * If we've yet to determine the valid subplans then do so now. If
249
+ * run-time pruning is disabled then the valid subplans will always be
250
+ * set to all subplans.
184
251
*/
185
- for (i = 0 ;i < node -> ms_nplans ;i ++ )
252
+ if (node -> ms_valid_subplans == NULL )
253
+ node -> ms_valid_subplans =
254
+ ExecFindMatchingSubPlans (node -> ms_prune_state );
255
+
256
+ /*
257
+ * First time through: pull the first tuple from each valid subplan,
258
+ * and set up the heap.
259
+ */
260
+ i = -1 ;
261
+ while ((i = bms_next_member (node -> ms_valid_subplans ,i )) >=0 )
186
262
{
187
263
node -> ms_slots [i ]= ExecProcNode (node -> mergeplans [i ]);
188
264
if (!TupIsNull (node -> ms_slots [i ]))
@@ -288,13 +364,32 @@ ExecEndMergeAppend(MergeAppendState *node)
288
364
*/
289
365
for (i = 0 ;i < nplans ;i ++ )
290
366
ExecEndNode (mergeplans [i ]);
367
+
368
+ /*
369
+ * release any resources associated with run-time pruning
370
+ */
371
+ if (node -> ms_prune_state )
372
+ ExecDestroyPartitionPruneState (node -> ms_prune_state );
291
373
}
292
374
293
375
void
294
376
ExecReScanMergeAppend (MergeAppendState * node )
295
377
{
296
378
int i ;
297
379
380
+ /*
381
+ * If any PARAM_EXEC Params used in pruning expressions have changed, then
382
+ * we'd better unset the valid subplans so that they are reselected for
383
+ * the new parameter values.
384
+ */
385
+ if (node -> ms_prune_state &&
386
+ bms_overlap (node -> ps .chgParam ,
387
+ node -> ms_prune_state -> execparamids ))
388
+ {
389
+ bms_free (node -> ms_valid_subplans );
390
+ node -> ms_valid_subplans = NULL ;
391
+ }
392
+
298
393
for (i = 0 ;i < node -> ms_nplans ;i ++ )
299
394
{
300
395
PlanState * subnode = node -> mergeplans [i ];