@@ -20,12 +20,30 @@ CustomScanMethodspickyappend_plan_methods;
20
20
CustomExecMethods pickyappend_exec_methods ;
21
21
22
22
23
+ /*
24
+ * Element of the plan_state_table
25
+ */
23
26
typedef struct
24
27
{
25
28
Oid relid ;/* relid of the corresponding partition */
26
29
PlanState * ps ;
27
30
}PreservedPlanState ;
28
31
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
+ }
29
47
30
48
static void
31
49
free_child_scan_common_array (ChildScanCommon * cur_plans ,int n )
@@ -45,14 +63,11 @@ free_child_scan_common_array(ChildScanCommon *cur_plans, int n)
45
63
static void
46
64
clear_plan_states (PickyAppendState * scan_state )
47
65
{
48
- PreservedPlanState * pps ;
49
- HASH_SEQ_STATUS seqstat ;
66
+ ListCell * state_cell ;
50
67
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 )
54
69
{
55
- ExecEndNode (pps -> ps );
70
+ ExecEndNode (( PlanState * ) lfirst ( state_cell ) );
56
71
}
57
72
}
58
73
@@ -73,15 +88,25 @@ transform_plans_into_states(PickyAppendState *scan_state,
73
88
(const void * )& child -> relid ,
74
89
HASH_ENTER ,& pps_found );
75
90
91
+ /* Create new node since this plan hasn't been used yet */
76
92
if (!pps_found )
77
93
{
78
94
pps -> ps = ExecInitNode (child -> content .plan ,estate ,0 );
95
+ /* Explain and clear_plan_states rely on this list */
79
96
scan_state -> css .custom_ps = lappend (scan_state -> css .custom_ps ,pps -> ps );
80
97
}
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 )
82
108
ExecReScan (pps -> ps );
83
109
84
- child -> content_type = CHILD_PLAN_STATE ;
85
110
child -> content .plan_state = pps -> ps ;
86
111
}
87
112
}
@@ -119,6 +144,7 @@ select_required_plans(HTAB *children_table, Oid *parts, int nparts, int *nres)
119
144
return result ;
120
145
}
121
146
147
+ /* Transform partition ranges into plain array of partition Oids */
122
148
static Oid *
123
149
get_partition_oids (List * ranges ,int * n ,PartRelationInfo * prel )
124
150
{
@@ -216,7 +242,6 @@ create_pickyappend_path(PlannerInfo *root,
216
242
Index relindex = path -> parent -> relid ;
217
243
ChildScanCommon child = palloc (sizeof (ChildScanCommonData ));
218
244
219
- child -> content_type = CHILD_PATH ;
220
245
child -> content .path = path ;
221
246
child -> relid = root -> simple_rte_array [relindex ]-> relid ;
222
247
Assert (child -> relid != InvalidOid );
@@ -305,6 +330,7 @@ save_pickyappend_private(CustomScan *cscan, PickyAppendPath *path)
305
330
pfree (children [i ]);
306
331
}
307
332
333
+ /* Save main table and partition relids */
308
334
custom_private = list_make2 (list_make1_oid (path -> relid ),custom_oids );
309
335
310
336
cscan -> custom_private = custom_private ;
@@ -319,24 +345,30 @@ unpack_pickyappend_private(PickyAppendState *scan_state, CustomScan *cscan)
319
345
int nchildren = list_length (custom_oids );
320
346
HTAB * children_table = scan_state -> children_table ;
321
347
HASHCTL * children_table_config = & scan_state -> children_table_config ;
348
+ int i ;
322
349
323
350
memset (children_table_config ,0 ,sizeof (HASHCTL ));
324
351
children_table_config -> keysize = sizeof (Oid );
325
352
children_table_config -> entrysize = sizeof (ChildScanCommonData );
326
353
327
354
children_table = hash_create ("Plan storage" ,nchildren ,
328
- children_table_config ,HASH_ELEM |HASH_BLOBS );
355
+ children_table_config ,
356
+ HASH_ELEM |HASH_BLOBS );
329
357
358
+ i = 0 ;
330
359
forboth (oid_cell ,custom_oids ,plan_cell ,cscan -> custom_plans )
331
360
{
332
- Oid cur_oid = lfirst_oid (oid_cell );
361
+ bool child_found ;
362
+ Oid cur_oid = lfirst_oid (oid_cell );
333
363
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 */
337
369
338
- child -> content_type = CHILD_PLAN ;
339
370
child -> content .plan = (Plan * )lfirst (plan_cell );
371
+ child -> original_order = i ++ ;/* will be used in EXPLAIN */
340
372
}
341
373
342
374
scan_state -> children_table = children_table ;
@@ -379,7 +411,9 @@ pickyappend_create_scan_state(CustomScan *node)
379
411
380
412
unpack_pickyappend_private (scan_state ,node );
381
413
414
+ /* Fill in relation info using main table's relid */
382
415
scan_state -> prel = get_pathman_relation_info (scan_state -> relid ,NULL );
416
+ Assert (scan_state -> prel );
383
417
384
418
scan_state -> cur_plans = NULL ;
385
419
scan_state -> ncur_plans = 0 ;
@@ -400,7 +434,8 @@ pickyappend_begin(CustomScanState *node, EState *estate, int eflags)
400
434
plan_state_table_config -> entrysize = sizeof (PreservedPlanState );
401
435
402
436
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 );
404
439
405
440
scan_state -> plan_state_table = plan_state_table ;
406
441
scan_state -> custom_expr_states = (List * )ExecInitExpr ((Expr * )scan_state -> custom_exprs ,
@@ -474,9 +509,10 @@ pickyappend_rescan(CustomScanState *node)
474
509
ranges = irange_list_intersect (ranges ,wn -> rangeset );
475
510
}
476
511
512
+ /* Get Oids of the required partitions */
477
513
parts = get_partition_oids (ranges ,& nparts ,prel );
478
514
479
- /* Select new plans for thispass */
515
+ /* Select new plans for thisrun using 'parts' */
480
516
free_child_scan_common_array (scan_state -> cur_plans ,scan_state -> ncur_plans );
481
517
scan_state -> cur_plans = select_required_plans (scan_state -> children_table ,
482
518
parts ,nparts ,
@@ -490,11 +526,54 @@ pickyappend_rescan(CustomScanState *node)
490
526
scan_state -> css .ss .ps .state );
491
527
492
528
scan_state -> running_idx = 0 ;
493
-
494
- /* elog(LOG, "nparts: %d, plans: %d", nparts, nplans); */
495
529
}
496
530
497
531
void
498
532
pickyppend_explain (CustomScanState * node ,List * ancestors ,ExplainState * es )
499
533
{
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
+ }
500
579
}