1919#include "utils/lsyscache.h"
2020
2121
22+ #define ALLOC_EXP 2
23+
24+
2225bool pg_pathman_enable_partition_filter = true;
2326
2427CustomScanMethods partition_filter_plan_methods ;
@@ -27,6 +30,7 @@ CustomExecMethodspartition_filter_exec_methods;
2730
2831static void partition_filter_visitor (Plan * plan ,void * context );
2932static List * pfilter_build_tlist (List * tlist );
33+ static int append_rri_to_estate (EState * estate ,ResultRelInfo * rri ,int cur_allocated );
3034
3135
3236void
@@ -86,7 +90,7 @@ check_acl_for_partition(EState *estate,
8690rte -> relkind = part_rel -> rd_rel -> relkind ;
8791rte -> requiredPerms = ACL_INSERT ;
8892
89- /* Check permissions for current partition */
93+ /*FIXME: Check permissions for partition */
9094ExecCheckRTPerms (list_make1 (rte ), true);
9195
9296/* TODO: append RTE to estate->es_range_table */
@@ -125,40 +129,51 @@ init_result_parts_storage(ResultPartsStorage *parts_storage,
125129
126130parts_storage -> on_new_rri_holder_callback = on_new_rri_holder_cb ;
127131parts_storage -> callback_arg = on_new_rri_holder_cb_arg ;
132+
133+ /* Partitions must remain locked till transaction's end */
134+ parts_storage -> head_open_lock_mode = RowExclusiveLock ;
135+ parts_storage -> heap_close_lock_mode = NoLock ;
128136}
129137
130138/*
131139 * Free ResultPartsStorage (close relations etc).
132140 */
133141void
134- fini_result_parts_storage (ResultPartsStorage * parts_storage )
142+ fini_result_parts_storage (ResultPartsStorage * parts_storage , bool close_rels )
135143{
136- HASH_SEQ_STATUS stat ;
137- ResultRelInfoHolder * rri_holder ;/* ResultRelInfo holder */
138-
139- hash_seq_init (& stat ,parts_storage -> result_rels_table );
140- while ((rri_holder = (ResultRelInfoHolder * )hash_seq_search (& stat ))!= NULL )
144+ /* Close partitions and their indices if asked to */
145+ if (close_rels )
141146{
142- ExecCloseIndices (rri_holder -> result_rel_info );
143- heap_close (rri_holder -> result_rel_info -> ri_RelationDesc ,
144- RowExclusiveLock );
147+ HASH_SEQ_STATUS stat ;
148+ ResultRelInfoHolder * rri_holder ;/* ResultRelInfo holder */
149+
150+ hash_seq_init (& stat ,parts_storage -> result_rels_table );
151+ while ((rri_holder = (ResultRelInfoHolder * )hash_seq_search (& stat ))!= NULL )
152+ {
153+ ExecCloseIndices (rri_holder -> result_rel_info );
154+
155+ heap_close (rri_holder -> result_rel_info -> ri_RelationDesc ,
156+ parts_storage -> heap_close_lock_mode );
157+ }
145158}
159+
160+ /* Finally destroy hash table */
146161hash_destroy (parts_storage -> result_rels_table );
147162}
148163
149164/*
150165 * Find a ResultRelInfo for the partition using ResultPartsStorage.
151166 */
152167ResultRelInfoHolder *
153- scan_result_parts_storage (Oid partid ,ResultPartsStorage * storage )
168+ scan_result_parts_storage (Oid partid ,ResultPartsStorage * parts_storage )
154169{
155170#define CopyToResultRelInfo (field_name ) \
156- ( part_result_rel_info->field_name =storage ->saved_rel_info->field_name )
171+ ( part_result_rel_info->field_name =parts_storage ->saved_rel_info->field_name )
157172
158173ResultRelInfoHolder * rri_holder ;
159174bool found ;
160175
161- rri_holder = hash_search (storage -> result_rels_table ,
176+ rri_holder = hash_search (parts_storage -> result_rels_table ,
162177 (const void * )& partid ,
163178HASH_ENTER ,& found );
164179
@@ -167,16 +182,16 @@ scan_result_parts_storage(Oid partid, ResultPartsStorage *storage)
167182{
168183ResultRelInfo * part_result_rel_info = makeNode (ResultRelInfo );
169184
185+ /* Check that 'saved_rel_info' is set */
186+ if (!parts_storage -> saved_rel_info )
187+ elog (ERROR ,"ResultPartsStorage contains no saved_rel_info" );
188+
170189InitResultRelInfo (part_result_rel_info ,
171- heap_open (partid ,RowExclusiveLock ),
172- 0 ,
190+ heap_open (partid ,parts_storage -> head_open_lock_mode ),
191+ parts_storage -> saved_rel_info -> ri_RangeTableIndex ,
1731920 );/* TODO: select suitable options */
174193
175- ExecOpenIndices (part_result_rel_info ,storage -> speculative_inserts );
176-
177- /* Check that 'saved_rel_info' is set */
178- if (!storage -> saved_rel_info )
179- elog (ERROR ,"ResultPartsStorage contains no saved_rel_info" );
194+ ExecOpenIndices (part_result_rel_info ,parts_storage -> speculative_inserts );
180195
181196/* Copy necessary fields from saved ResultRelInfo */
182197CopyToResultRelInfo (ri_WithCheckOptions );
@@ -189,18 +204,21 @@ scan_result_parts_storage(Oid partid, ResultPartsStorage *storage)
189204/* ri_ConstraintExprs will be initialized by ExecRelCheck() */
190205part_result_rel_info -> ri_ConstraintExprs = NULL ;
191206
192- /* Make 'range table index' point to the parent relation */
193- part_result_rel_info -> ri_RangeTableIndex =
194- storage -> saved_rel_info -> ri_RangeTableIndex ;
195-
196207/* Now fill the ResultRelInfo holder */
197208rri_holder -> partid = partid ;
198209rri_holder -> result_rel_info = part_result_rel_info ;
199210
211+ /* Add ResultRelInfo to storage->es_alloc_result_rels */
212+ parts_storage -> es_alloc_result_rels =
213+ append_rri_to_estate (parts_storage -> estate ,
214+ part_result_rel_info ,
215+ parts_storage -> es_alloc_result_rels );
216+
200217/* Call on_new_rri_holder_callback() if needed */
201- if (storage -> on_new_rri_holder_callback )
202- storage -> on_new_rri_holder_callback (storage -> estate ,rri_holder ,
203- storage -> callback_arg );
218+ if (parts_storage -> on_new_rri_holder_callback )
219+ parts_storage -> on_new_rri_holder_callback (parts_storage -> estate ,
220+ rri_holder ,
221+ parts_storage -> callback_arg );
204222}
205223
206224return rri_holder ;
@@ -412,8 +430,8 @@ partition_filter_end(CustomScanState *node)
412430{
413431PartitionFilterState * state = (PartitionFilterState * )node ;
414432
415- /*Close cached relations */
416- fini_result_parts_storage (& state -> result_parts );
433+ /*Executor will close rels via estate->es_result_relations */
434+ fini_result_parts_storage (& state -> result_parts , false );
417435
418436Assert (list_length (node -> custom_ps )== 1 );
419437ExecEndNode ((PlanState * )linitial (node -> custom_ps ));
@@ -432,6 +450,29 @@ partition_filter_explain(CustomScanState *node, List *ancestors, ExplainState *e
432450/* Nothing to do here now */
433451}
434452
453+ static int
454+ append_rri_to_estate (EState * estate ,ResultRelInfo * rri ,int cur_allocated )
455+ {
456+ int result_rels_allocated = cur_allocated ;
457+
458+ if (result_rels_allocated <=estate -> es_num_result_relations )
459+ {
460+ ResultRelInfo * rri_array = estate -> es_result_relations ;
461+
462+ result_rels_allocated = result_rels_allocated * ALLOC_EXP + 1 ;
463+ estate -> es_result_relations = palloc (result_rels_allocated *
464+ sizeof (ResultRelInfo ));
465+ memcpy (estate -> es_result_relations ,
466+ rri_array ,
467+ estate -> es_num_result_relations * sizeof (ResultRelInfo ));
468+ }
469+
470+ /* Append ResultRelInfo to 'es_result_relations' array */
471+ estate -> es_result_relations [estate -> es_num_result_relations ++ ]= * rri ;
472+
473+ return result_rels_allocated ;
474+ }
475+
435476/*
436477 * Build partition filter's target list pointing to subplan tuple's elements
437478 */
@@ -465,9 +506,9 @@ pfilter_build_tlist(List *tlist)
465506}
466507
467508/*
468- * Add partition filters to ModifyTable node's children
509+ * Add partition filters to ModifyTable node's children.
469510 *
470- * 'context' should point to the PlannedStmt->rtable
511+ * 'context' should point to the PlannedStmt->rtable.
471512 */
472513static void
473514partition_filter_visitor (Plan * plan ,void * context )