1
1
#include "postgres.h"
2
2
#include "optimizer/paths.h"
3
3
#include "nodes_common.h"
4
+ #include "pickyappend.h"
4
5
5
6
7
+ static void
8
+ free_child_scan_common_array (ChildScanCommon * cur_plans ,int n )
9
+ {
10
+ int i ;
11
+
12
+ if (!cur_plans )
13
+ return ;
14
+
15
+ /* We shouldn't free inner objects e.g. Plans here */
16
+ for (i = 0 ;i < n ;i ++ )
17
+ pfree (cur_plans [i ]);
18
+
19
+ pfree (cur_plans );
20
+ }
21
+
22
+ static void
23
+ transform_plans_into_states (PickyAppendState * scan_state ,
24
+ ChildScanCommon * selected_plans ,int n ,
25
+ EState * estate )
26
+ {
27
+ int i ;
28
+
29
+ for (i = 0 ;i < n ;i ++ )
30
+ {
31
+ ChildScanCommon child = selected_plans [i ];
32
+ PreservedPlanState * pps ;
33
+ bool pps_found ;
34
+
35
+ pps = (PreservedPlanState * )hash_search (scan_state -> plan_state_table ,
36
+ (const void * )& child -> relid ,
37
+ HASH_ENTER ,& pps_found );
38
+
39
+ /* Create new node since this plan hasn't been used yet */
40
+ if (!pps_found )
41
+ {
42
+ pps -> ps = ExecInitNode (child -> content .plan ,estate ,0 );
43
+ /* Explain and clear_plan_states rely on this list */
44
+ scan_state -> css .custom_ps = lappend (scan_state -> css .custom_ps ,pps -> ps );
45
+ }
46
+
47
+ /* Node with params will be ReScanned */
48
+ if (scan_state -> css .ss .ps .chgParam )
49
+ UpdateChangedParamSet (pps -> ps ,scan_state -> css .ss .ps .chgParam );
50
+
51
+ /*
52
+ * We should ReScan this node manually since
53
+ * ExecProcNode won't do this for us in this case.
54
+ */
55
+ if (!pps -> ps -> chgParam )
56
+ ExecReScan (pps -> ps );
57
+
58
+ child -> content .plan_state = pps -> ps ;
59
+ }
60
+ }
61
+
62
+ static ChildScanCommon *
63
+ select_required_plans (HTAB * children_table ,Oid * parts ,int nparts ,int * nres )
64
+ {
65
+ int allocated = 10 ;
66
+ int used = 0 ;
67
+ ChildScanCommon * result = palloc (10 * sizeof (ChildScanCommon ));
68
+ int i ;
69
+
70
+ for (i = 0 ;i < nparts ;i ++ )
71
+ {
72
+ ChildScanCommon child_copy ;
73
+ ChildScanCommon child = hash_search (children_table ,
74
+ (const void * )& parts [i ],
75
+ HASH_FIND ,NULL );
76
+ if (!child )
77
+ continue ;
78
+
79
+ if (allocated <=used )
80
+ {
81
+ allocated *=2 ;
82
+ result = repalloc (result ,allocated * sizeof (ChildScanCommon ));
83
+ }
84
+
85
+ child_copy = palloc (sizeof (ChildScanCommonData ));
86
+ memcpy (child_copy ,child ,sizeof (ChildScanCommonData ));
87
+
88
+ result [used ++ ]= child_copy ;
89
+ }
90
+
91
+ * nres = used ;
92
+ return result ;
93
+ }
94
+
95
+ /* Transform partition ranges into plain array of partition Oids */
96
+ static Oid *
97
+ get_partition_oids (List * ranges ,int * n ,PartRelationInfo * prel )
98
+ {
99
+ ListCell * range_cell ;
100
+ int allocated = 10 ;
101
+ int used = 0 ;
102
+ Oid * result = palloc (allocated * sizeof (Oid ));
103
+ Oid * children = dsm_array_get_pointer (& prel -> children );
104
+
105
+ foreach (range_cell ,ranges )
106
+ {
107
+ int i ;
108
+ int a = irange_lower (lfirst_irange (range_cell ));
109
+ int b = irange_upper (lfirst_irange (range_cell ));
110
+
111
+ for (i = a ;i <=b ;i ++ )
112
+ {
113
+ if (allocated <=used )
114
+ {
115
+ allocated *=2 ;
116
+ result = repalloc (result ,allocated * sizeof (Oid ));
117
+ }
118
+
119
+ Assert (i < prel -> children_count );
120
+ result [used ++ ]= children [i ];
121
+ }
122
+ }
123
+
124
+ * n = used ;
125
+ return result ;
126
+ }
127
+
6
128
/* Compare plans by 'original_order' */
7
129
static int
8
130
cmp_child_scan_common_by_orig_order (const void * ap ,
@@ -19,8 +141,255 @@ cmp_child_scan_common_by_orig_order(const void *ap,
19
141
return 0 ;
20
142
}
21
143
144
+ static void
145
+ pack_pickyappend_private (CustomScan * cscan ,PickyAppendPath * path )
146
+ {
147
+ ChildScanCommon * children = path -> children ;
148
+ int nchildren = path -> nchildren ;
149
+ List * custom_private = NIL ;
150
+ List * custom_oids = NIL ;
151
+ int i ;
152
+
153
+ for (i = 0 ;i < nchildren ;i ++ )
154
+ {
155
+ /* We've already filled 'custom_paths' in create_pickyappend_path */
156
+ custom_oids = lappend_oid (custom_oids ,children [i ]-> relid );
157
+ pfree (children [i ]);
158
+ }
159
+
160
+ /* Save main table and partition relids */
161
+ custom_private = list_make2 (list_make1_oid (path -> relid ),custom_oids );
162
+
163
+ cscan -> custom_private = custom_private ;
164
+ }
165
+
166
+ static void
167
+ unpack_pickyappend_private (PickyAppendState * scan_state ,CustomScan * cscan )
168
+ {
169
+ ListCell * oid_cell ;
170
+ ListCell * plan_cell ;
171
+ List * custom_oids = (List * )lsecond (cscan -> custom_private );
172
+ int nchildren = list_length (custom_oids );
173
+ HTAB * children_table = scan_state -> children_table ;
174
+ HASHCTL * children_table_config = & scan_state -> children_table_config ;
175
+ int i ;
176
+
177
+ memset (children_table_config ,0 ,sizeof (HASHCTL ));
178
+ children_table_config -> keysize = sizeof (Oid );
179
+ children_table_config -> entrysize = sizeof (ChildScanCommonData );
180
+
181
+ children_table = hash_create ("Plan storage" ,nchildren ,
182
+ children_table_config ,
183
+ HASH_ELEM |HASH_BLOBS );
184
+
185
+ i = 0 ;
186
+ forboth (oid_cell ,custom_oids ,plan_cell ,cscan -> custom_plans )
187
+ {
188
+ bool child_found ;
189
+ Oid cur_oid = lfirst_oid (oid_cell );
190
+
191
+ ChildScanCommon child = hash_search (children_table ,
192
+ (const void * )& cur_oid ,
193
+ HASH_ENTER ,& child_found );
194
+
195
+ Assert (!child_found );/* there should be no collisions */
196
+
197
+ child -> content .plan = (Plan * )lfirst (plan_cell );
198
+ child -> original_order = i ++ ;/* will be used in EXPLAIN */
199
+ }
200
+
201
+ scan_state -> children_table = children_table ;
202
+ scan_state -> relid = linitial_oid (linitial (cscan -> custom_private ));
203
+ }
204
+
205
+ Path *
206
+ create_append_path_common (PlannerInfo * root ,
207
+ AppendPath * inner_append ,
208
+ ParamPathInfo * param_info ,
209
+ List * picky_clauses ,
210
+ CustomPathMethods * path_methods )
211
+ {
212
+ RelOptInfo * innerrel = inner_append -> path .parent ;
213
+ ListCell * lc ;
214
+ int i ;
215
+
216
+ RangeTblEntry * inner_entry = root -> simple_rte_array [innerrel -> relid ];
217
+
218
+ PickyAppendPath * result ;
219
+
220
+ result = palloc0 (sizeof (PickyAppendPath ));
221
+ NodeSetTag (result ,T_CustomPath );
222
+
223
+ result -> cpath .path .pathtype = T_CustomScan ;
224
+ result -> cpath .path .parent = innerrel ;
225
+ result -> cpath .path .param_info = param_info ;
226
+ result -> cpath .path .pathkeys = NIL ;
227
+ #if PG_VERSION_NUM >=90600
228
+ result -> cpath .path .pathtarget = inner_append -> path .pathtarget ;
229
+ #endif
230
+ result -> cpath .path .rows = inner_append -> path .rows ;
231
+ result -> cpath .flags = 0 ;
232
+ result -> cpath .methods = path_methods ;
233
+
234
+ /* TODO: real costs */
235
+ result -> cpath .path .startup_cost = 0 ;
236
+ result -> cpath .path .total_cost = 0 ;
237
+
238
+ /* Set 'partitioned column'-related clauses */
239
+ result -> cpath .custom_private = picky_clauses ;
240
+ result -> cpath .custom_paths = NIL ;
241
+
242
+ Assert (inner_entry -> relid != 0 );
243
+ result -> relid = inner_entry -> relid ;
244
+
245
+ result -> nchildren = list_length (inner_append -> subpaths );
246
+ result -> children = palloc (result -> nchildren * sizeof (ChildScanCommon ));
247
+ i = 0 ;
248
+ foreach (lc ,inner_append -> subpaths )
249
+ {
250
+ Path * path = lfirst (lc );
251
+ Index relindex = path -> parent -> relid ;
252
+ ChildScanCommon child = palloc (sizeof (ChildScanCommonData ));
253
+
254
+ child -> content .path = path ;
255
+ child -> relid = root -> simple_rte_array [relindex ]-> relid ;
256
+ Assert (child -> relid != InvalidOid );
257
+
258
+ result -> cpath .custom_paths = lappend (result -> cpath .custom_paths ,
259
+ child -> content .path );
260
+ result -> children [i ]= child ;
261
+
262
+ i ++ ;
263
+ }
264
+
265
+ return & result -> cpath .path ;
266
+ }
267
+
268
+ Plan *
269
+ create_append_plan_common (PlannerInfo * root ,RelOptInfo * rel ,
270
+ CustomPath * best_path ,List * tlist ,
271
+ List * clauses ,List * custom_plans ,
272
+ CustomScanMethods * scan_methods )
273
+ {
274
+ PickyAppendPath * gpath = (PickyAppendPath * )best_path ;
275
+ CustomScan * cscan ;
276
+
277
+ cscan = makeNode (CustomScan );
278
+ cscan -> scan .plan .qual = NIL ;
279
+ cscan -> scan .plan .targetlist = tlist ;
280
+ cscan -> custom_scan_tlist = tlist ;
281
+ cscan -> scan .scanrelid = 0 ;
282
+
283
+ cscan -> custom_exprs = gpath -> cpath .custom_private ;
284
+ cscan -> custom_plans = custom_plans ;
285
+
286
+ cscan -> methods = scan_methods ;
287
+
288
+ pack_pickyappend_private (cscan ,gpath );
289
+
290
+ return & cscan -> scan .plan ;
291
+ }
292
+
293
+ Node *
294
+ create_append_scan_state_common (CustomScan * node ,
295
+ CustomExecMethods * exec_methods ,
296
+ uint32 size )
297
+ {
298
+ PickyAppendState * scan_state = palloc0 (size );
299
+
300
+ NodeSetTag (scan_state ,T_CustomScanState );
301
+ scan_state -> css .flags = node -> flags ;
302
+ scan_state -> css .methods = exec_methods ;
303
+ scan_state -> custom_exprs = node -> custom_exprs ;
304
+
305
+ unpack_pickyappend_private (scan_state ,node );
306
+
307
+ /* Fill in relation info using main table's relid */
308
+ scan_state -> prel = get_pathman_relation_info (scan_state -> relid ,NULL );
309
+ Assert (scan_state -> prel );
310
+
311
+ scan_state -> cur_plans = NULL ;
312
+ scan_state -> ncur_plans = 0 ;
313
+ scan_state -> running_idx = 0 ;
314
+
315
+ return (Node * )scan_state ;
316
+ }
317
+
318
+ void
319
+ begin_append_common (CustomScanState * node ,EState * estate ,int eflags )
320
+ {
321
+ PickyAppendState * scan_state = (PickyAppendState * )node ;
322
+ HTAB * plan_state_table = scan_state -> plan_state_table ;
323
+ HASHCTL * plan_state_table_config = & scan_state -> plan_state_table_config ;
324
+
325
+ memset (plan_state_table_config ,0 ,sizeof (HASHCTL ));
326
+ plan_state_table_config -> keysize = sizeof (Oid );
327
+ plan_state_table_config -> entrysize = sizeof (PreservedPlanState );
328
+
329
+ plan_state_table = hash_create ("PlanState storage" ,128 ,
330
+ plan_state_table_config ,
331
+ HASH_ELEM |HASH_BLOBS );
332
+
333
+ scan_state -> plan_state_table = plan_state_table ;
334
+ scan_state -> custom_expr_states = (List * )ExecInitExpr ((Expr * )scan_state -> custom_exprs ,
335
+ (PlanState * )scan_state );
336
+ }
337
+
338
+ void
339
+ end_append_common (CustomScanState * node )
340
+ {
341
+ PickyAppendState * scan_state = (PickyAppendState * )node ;
342
+
343
+ clear_plan_states (& scan_state -> css );
344
+ hash_destroy (scan_state -> plan_state_table );
345
+ hash_destroy (scan_state -> children_table );
346
+ }
347
+
348
+ void
349
+ rescan_append_common (CustomScanState * node )
350
+ {
351
+ PickyAppendState * scan_state = (PickyAppendState * )node ;
352
+ ExprContext * econtext = node -> ss .ps .ps_ExprContext ;
353
+ PartRelationInfo * prel = scan_state -> prel ;
354
+ List * ranges ;
355
+ ListCell * lc ;
356
+ Oid * parts ;
357
+ int nparts ;
358
+
359
+ ranges = list_make1_int (make_irange (0 ,prel -> children_count - 1 , false));
360
+
361
+ foreach (lc ,scan_state -> custom_exprs )
362
+ {
363
+ WrapperNode * wn ;
364
+ WalkerContext wcxt ;
365
+
366
+ wcxt .econtext = econtext ;
367
+ wn = walk_expr_tree (& wcxt , (Expr * )lfirst (lc ),prel );
368
+
369
+ ranges = irange_list_intersect (ranges ,wn -> rangeset );
370
+ }
371
+
372
+ /* Get Oids of the required partitions */
373
+ parts = get_partition_oids (ranges ,& nparts ,prel );
374
+
375
+ /* Select new plans for this run using 'parts' */
376
+ free_child_scan_common_array (scan_state -> cur_plans ,scan_state -> ncur_plans );
377
+ scan_state -> cur_plans = select_required_plans (scan_state -> children_table ,
378
+ parts ,nparts ,
379
+ & scan_state -> ncur_plans );
380
+ pfree (parts );
381
+
382
+ /* Transform selected plans into executable plan states */
383
+ transform_plans_into_states (scan_state ,
384
+ scan_state -> cur_plans ,
385
+ scan_state -> ncur_plans ,
386
+ scan_state -> css .ss .ps .state );
387
+
388
+ scan_state -> running_idx = 0 ;
389
+ }
390
+
22
391
void
23
- explain_common (CustomScanState * node ,HTAB * children_table ,ExplainState * es )
392
+ explain_append_common (CustomScanState * node ,HTAB * children_table ,ExplainState * es )
24
393
{
25
394
/* Construct excess PlanStates */
26
395
if (!es -> analyze )