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+
1633static void
1734free_child_scan_common_array (ChildScanCommon * cur_plans ,int n )
1835{
@@ -165,6 +182,7 @@ unpack_pickyappend_private(PickyAppendState *scan_state, CustomScan *cscan)
165182int nchildren = list_length (custom_oids );
166183HTAB * children_table = scan_state -> children_table ;
167184HASHCTL * children_table_config = & scan_state -> children_table_config ;
185+ int i ;
168186
169187memset (children_table_config ,0 ,sizeof (HASHCTL ));
170188children_table_config -> keysize = sizeof (Oid );
@@ -174,6 +192,7 @@ unpack_pickyappend_private(PickyAppendState *scan_state, CustomScan *cscan)
174192children_table_config ,
175193HASH_ELEM |HASH_BLOBS );
176194
195+ i = 0 ;
177196forboth (oid_cell ,custom_oids ,plan_cell ,cscan -> custom_plans )
178197{
179198bool child_found ;
@@ -186,6 +205,7 @@ unpack_pickyappend_private(PickyAppendState *scan_state, CustomScan *cscan)
186205Assert (!child_found );/* there should be no collisions */
187206
188207child -> content .plan = (Plan * )lfirst (plan_cell );
208+ child -> original_order = i ++ ;/* will be used in EXPLAIN */
189209}
190210
191211scan_state -> children_table = children_table ;
@@ -323,18 +343,6 @@ begin_append_common(CustomScanState *node, EState *estate, int eflags)
323343scan_state -> plan_state_table = plan_state_table ;
324344scan_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
340348void
@@ -393,5 +401,49 @@ rescan_append_common(CustomScanState *node)
393401void
394402explain_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}