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 @@ CustomExecMethods partition_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,
8690 rte -> relkind = part_rel -> rd_rel -> relkind ;
8791 rte -> requiredPerms = ACL_INSERT ;
8892
89- /* Check permissions for current partition */
93+ /* FIXME: Check permissions for partition */
9094 ExecCheckRTPerms (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
126130 parts_storage -> on_new_rri_holder_callback = on_new_rri_holder_cb ;
127131 parts_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 */
146161 hash_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
158173 ResultRelInfoHolder * rri_holder ;
159174 bool 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 ,
163178 HASH_ENTER , & found );
164179
@@ -167,16 +182,16 @@ scan_result_parts_storage(Oid partid, ResultPartsStorage *storage)
167182 {
168183 ResultRelInfo * 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+
170189 InitResultRelInfo (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 ,
173192 0 ); /* 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 */
182197 CopyToResultRelInfo (ri_WithCheckOptions );
@@ -189,18 +204,21 @@ scan_result_parts_storage(Oid partid, ResultPartsStorage *storage)
189204 /* ri_ConstraintExprs will be initialized by ExecRelCheck() */
190205 part_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 */
197208 rri_holder -> partid = partid ;
198209 rri_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
206224 return rri_holder ;
@@ -412,8 +430,8 @@ partition_filter_end(CustomScanState *node)
412430{
413431 PartitionFilterState * 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
418436 Assert (list_length (node -> custom_ps ) == 1 );
419437 ExecEndNode ((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 )
0 commit comments