PostgreSQL Source Code git master
partprune.h File Reference
Include dependency graph for partprune.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  PartitionPruneContext
 

Macros

#define PruneCxtStateIdx(partnatts, step_id, keyno)    ((partnatts) * (step_id) + (keyno))
 

Typedefs

typedef struct PartitionPruneContext PartitionPruneContext
 

Functions

PartitionPruneInfomake_partition_pruneinfo (struct PlannerInfo *root, struct RelOptInfo *parentrel, List *subpaths, List *prunequal)
 
Bitmapsetprune_append_rel_partitions (struct RelOptInfo *rel)
 
Bitmapsetget_matching_partitions (PartitionPruneContext *context, List *pruning_steps)
 

Macro Definition Documentation

◆ PruneCxtStateIdx

#define PruneCxtStateIdx (   partnatts,
  step_id,
  keyno 
)     ((partnatts) * (step_id) + (keyno))

Definition at line 70 of file partprune.h.

Typedef Documentation

◆ PartitionPruneContext

Function Documentation

◆ get_matching_partitions()

Bitmapset * get_matching_partitions ( PartitionPruneContext context,
List pruning_steps 
)

Definition at line 817 of file partprune.c.

818{
819 Bitmapset *result;
820 int num_steps = list_length(pruning_steps),
821 i;
822 PruneStepResult **results,
823 *final_result;
824 ListCell *lc;
825 bool scan_default;
826
827 /* If there are no pruning steps then all partitions match. */
828 if (num_steps == 0)
829 {
830 Assert(context->nparts > 0);
831 return bms_add_range(NULL, 0, context->nparts - 1);
832 }
833
834 /*
835 * Allocate space for individual pruning steps to store its result. Each
836 * slot will hold a PruneStepResult after performing a given pruning step.
837 * Later steps may use the result of one or more earlier steps. The
838 * result of applying all pruning steps is the value contained in the slot
839 * of the last pruning step.
840 */
841 results = (PruneStepResult **)
842 palloc0(num_steps * sizeof(PruneStepResult *));
843 foreach(lc, pruning_steps)
844 {
845 PartitionPruneStep *step = lfirst(lc);
846
847 switch (nodeTag(step))
848 {
849 case T_PartitionPruneStepOp:
850 results[step->step_id] =
852 (PartitionPruneStepOp *) step);
853 break;
854
855 case T_PartitionPruneStepCombine:
856 results[step->step_id] =
859 results);
860 break;
861
862 default:
863 elog(ERROR, "invalid pruning step type: %d",
864 (int) nodeTag(step));
865 }
866 }
867
868 /*
869 * At this point we know the offsets of all the datums whose corresponding
870 * partitions need to be in the result, including special null-accepting
871 * and default partitions. Collect the actual partition indexes now.
872 */
873 final_result = results[num_steps - 1];
874 Assert(final_result != NULL);
875 i = -1;
876 result = NULL;
877 scan_default = final_result->scan_default;
878 while ((i = bms_next_member(final_result->bound_offsets, i)) >= 0)
879 {
880 int partindex;
881
882 Assert(i < context->boundinfo->nindexes);
883 partindex = context->boundinfo->indexes[i];
884
885 if (partindex < 0)
886 {
887 /*
888 * In range partitioning cases, if a partition index is -1 it
889 * means that the bound at the offset is the upper bound for a
890 * range not covered by any partition (other than a possible
891 * default partition). In hash partitioning, the same means no
892 * partition has been defined for the corresponding remainder
893 * value.
894 *
895 * In either case, the value is still part of the queried range of
896 * values, so mark to scan the default partition if one exists.
897 */
898 scan_default |= partition_bound_has_default(context->boundinfo);
899 continue;
900 }
901
902 result = bms_add_member(result, partindex);
903 }
904
905 /* Add the null and/or default partition if needed and present. */
906 if (final_result->scan_null)
907 {
910 result = bms_add_member(result, context->boundinfo->null_index);
911 }
912 if (scan_default)
913 {
917 result = bms_add_member(result, context->boundinfo->default_index);
918 }
919
920 return result;
921}
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1306
Bitmapset * bms_add_range(Bitmapset *a, int lower, int upper)
Definition: bitmapset.c:1019
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:815
#define Assert(condition)
Definition: c.h:815
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
int i
Definition: isn.c:72
void * palloc0(Size size)
Definition: mcxt.c:1347
#define nodeTag(nodeptr)
Definition: nodes.h:133
@ PARTITION_STRATEGY_LIST
Definition: parsenodes.h:883
@ PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:884
#define partition_bound_has_default(bi)
Definition: partbounds.h:99
#define partition_bound_accepts_nulls(bi)
Definition: partbounds.h:98
static PruneStepResult * perform_pruning_base_step(PartitionPruneContext *context, PartitionPruneStepOp *opstep)
Definition: partprune.c:3415
static PruneStepResult * perform_pruning_combine_step(PartitionPruneContext *context, PartitionPruneStepCombine *cstep, PruneStepResult **step_results)
Definition: partprune.c:3563
#define lfirst(lc)
Definition: pg_list.h:172
static int list_length(const List *l)
Definition: pg_list.h:152
PartitionBoundInfo boundinfo
Definition: partprune.h:54
Bitmapset * bound_offsets
Definition: partprune.c:133

References Assert, bms_add_member(), bms_add_range(), bms_next_member(), PruneStepResult::bound_offsets, PartitionPruneContext::boundinfo, PartitionBoundInfoData::default_index, elog, ERROR, i, PartitionBoundInfoData::indexes, lfirst, list_length(), nodeTag, PartitionPruneContext::nparts, PartitionBoundInfoData::null_index, palloc0(), partition_bound_accepts_nulls, partition_bound_has_default, PARTITION_STRATEGY_LIST, PARTITION_STRATEGY_RANGE, perform_pruning_base_step(), perform_pruning_combine_step(), PruneStepResult::scan_default, PruneStepResult::scan_null, PartitionPruneStep::step_id, and PartitionPruneContext::strategy.

Referenced by find_matching_subplans_recurse(), and prune_append_rel_partitions().

◆ make_partition_pruneinfo()

PartitionPruneInfo * make_partition_pruneinfo ( struct PlannerInfo root,
struct RelOptInfo parentrel,
List subpaths,
List prunequal 
)

Definition at line 220 of file partprune.c.

223{
224 PartitionPruneInfo *pruneinfo;
225 Bitmapset *allmatchedsubplans = NULL;
226 List *allpartrelids;
227 List *prunerelinfos;
228 int *relid_subplan_map;
229 ListCell *lc;
230 int i;
231
232 /*
233 * Scan the subpaths to see which ones are scans of partition child
234 * relations, and identify their parent partitioned rels. (Note: we must
235 * restrict the parent partitioned rels to be parentrel or children of
236 * parentrel, otherwise we couldn't translate prunequal to match.)
237 *
238 * Also construct a temporary array to map from partition-child-relation
239 * relid to the index in 'subpaths' of the scan plan for that partition.
240 * (Use of "subplan" rather than "subpath" is a bit of a misnomer, but
241 * we'll let it stand.) For convenience, we use 1-based indexes here, so
242 * that zero can represent an un-filled array entry.
243 */
244 allpartrelids = NIL;
245 relid_subplan_map = palloc0(sizeof(int) * root->simple_rel_array_size);
246
247 i = 1;
248 foreach(lc, subpaths)
249 {
250 Path *path = (Path *) lfirst(lc);
251 RelOptInfo *pathrel = path->parent;
252
253 /* We don't consider partitioned joins here */
254 if (pathrel->reloptkind == RELOPT_OTHER_MEMBER_REL)
255 {
256 RelOptInfo *prel = pathrel;
257 Bitmapset *partrelids = NULL;
258
259 /*
260 * Traverse up to the pathrel's topmost partitioned parent,
261 * collecting parent relids as we go; but stop if we reach
262 * parentrel. (Normally, a pathrel's topmost partitioned parent
263 * is either parentrel or a UNION ALL appendrel child of
264 * parentrel. But when handling partitionwise joins of
265 * multi-level partitioning trees, we can see an append path whose
266 * parentrel is an intermediate partitioned table.)
267 */
268 do
269 {
270 AppendRelInfo *appinfo;
271
272 Assert(prel->relid < root->simple_rel_array_size);
273 appinfo = root->append_rel_array[prel->relid];
274 prel = find_base_rel(root, appinfo->parent_relid);
275 if (!IS_PARTITIONED_REL(prel))
276 break; /* reached a non-partitioned parent */
277 /* accept this level as an interesting parent */
278 partrelids = bms_add_member(partrelids, prel->relid);
279 if (prel == parentrel)
280 break; /* don't traverse above parentrel */
281 } while (prel->reloptkind == RELOPT_OTHER_MEMBER_REL);
282
283 if (partrelids)
284 {
285 /*
286 * Found some relevant parent partitions, which may or may not
287 * overlap with partition trees we already found. Add new
288 * information to the allpartrelids list.
289 */
290 allpartrelids = add_part_relids(allpartrelids, partrelids);
291 /* Also record the subplan in relid_subplan_map[] */
292 /* No duplicates please */
293 Assert(relid_subplan_map[pathrel->relid] == 0);
294 relid_subplan_map[pathrel->relid] = i;
295 }
296 }
297 i++;
298 }
299
300 /*
301 * We now build a PartitionedRelPruneInfo for each topmost partitioned rel
302 * (omitting any that turn out not to have useful pruning quals).
303 */
304 prunerelinfos = NIL;
305 foreach(lc, allpartrelids)
306 {
307 Bitmapset *partrelids = (Bitmapset *) lfirst(lc);
308 List *pinfolist;
309 Bitmapset *matchedsubplans = NULL;
310
311 pinfolist = make_partitionedrel_pruneinfo(root, parentrel,
312 prunequal,
313 partrelids,
314 relid_subplan_map,
315 &matchedsubplans);
316
317 /* When pruning is possible, record the matched subplans */
318 if (pinfolist != NIL)
319 {
320 prunerelinfos = lappend(prunerelinfos, pinfolist);
321 allmatchedsubplans = bms_join(matchedsubplans,
322 allmatchedsubplans);
323 }
324 }
325
326 pfree(relid_subplan_map);
327
328 /*
329 * If none of the partition hierarchies had any useful run-time pruning
330 * quals, then we can just not bother with run-time pruning.
331 */
332 if (prunerelinfos == NIL)
333 return NULL;
334
335 /* Else build the result data structure */
336 pruneinfo = makeNode(PartitionPruneInfo);
337 pruneinfo->prune_infos = prunerelinfos;
338
339 /*
340 * Some subplans may not belong to any of the identified partitioned rels.
341 * This can happen for UNION ALL queries which include a non-partitioned
342 * table, or when some of the hierarchies aren't run-time prunable. Build
343 * a bitmapset of the indexes of all such subplans, so that the executor
344 * can identify which subplans should never be pruned.
345 */
346 if (bms_num_members(allmatchedsubplans) < list_length(subpaths))
347 {
348 Bitmapset *other_subplans;
349
350 /* Create the complement of allmatchedsubplans */
351 other_subplans = bms_add_range(NULL, 0, list_length(subpaths) - 1);
352 other_subplans = bms_del_members(other_subplans, allmatchedsubplans);
353
354 pruneinfo->other_subplans = other_subplans;
355 }
356 else
357 pruneinfo->other_subplans = NULL;
358
359 return pruneinfo;
360}
Bitmapset * bms_del_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:1161
int bms_num_members(const Bitmapset *a)
Definition: bitmapset.c:751
Bitmapset * bms_join(Bitmapset *a, Bitmapset *b)
Definition: bitmapset.c:1230
List * lappend(List *list, void *datum)
Definition: list.c:339
void pfree(void *pointer)
Definition: mcxt.c:1521
#define makeNode(_type_)
Definition: nodes.h:155
static List * add_part_relids(List *allpartrelids, Bitmapset *partrelids)
Definition: partprune.c:392
static List * make_partitionedrel_pruneinfo(PlannerInfo *root, RelOptInfo *parentrel, List *prunequal, Bitmapset *partrelids, int *relid_subplan_map, Bitmapset **matchedsubplans)
Definition: partprune.c:438
#define IS_PARTITIONED_REL(rel)
Definition: pathnodes.h:1062
@ RELOPT_OTHER_MEMBER_REL
Definition: pathnodes.h:829
#define NIL
Definition: pg_list.h:68
tree ctl root
Definition: radixtree.h:1857
RelOptInfo * find_base_rel(PlannerInfo *root, int relid)
Definition: relnode.c:414
Index parent_relid
Definition: pathnodes.h:2980
Definition: pg_list.h:54
Bitmapset * other_subplans
Definition: plannodes.h:1429
Index relid
Definition: pathnodes.h:918
RelOptKind reloptkind
Definition: pathnodes.h:865

References add_part_relids(), Assert, bms_add_member(), bms_add_range(), bms_del_members(), bms_join(), bms_num_members(), find_base_rel(), i, IS_PARTITIONED_REL, lappend(), lfirst, list_length(), make_partitionedrel_pruneinfo(), makeNode, NIL, PartitionPruneInfo::other_subplans, palloc0(), AppendRelInfo::parent_relid, pfree(), PartitionPruneInfo::prune_infos, RelOptInfo::relid, RELOPT_OTHER_MEMBER_REL, RelOptInfo::reloptkind, and root.

Referenced by create_append_plan(), and create_merge_append_plan().

◆ prune_append_rel_partitions()

Bitmapset * prune_append_rel_partitions ( struct RelOptInfo rel)

Definition at line 750 of file partprune.c.

751{
752 List *clauses = rel->baserestrictinfo;
753 List *pruning_steps;
755 PartitionPruneContext context;
756
757 Assert(rel->part_scheme != NULL);
758
759 /* If there are no partitions, return the empty set */
760 if (rel->nparts == 0)
761 return NULL;
762
763 /*
764 * If pruning is disabled or if there are no clauses to prune with, return
765 * all partitions.
766 */
767 if (!enable_partition_pruning || clauses == NIL)
768 return bms_add_range(NULL, 0, rel->nparts - 1);
769
770 /*
771 * Process clauses to extract pruning steps that are usable at plan time.
772 * If the clauses are found to be contradictory, we can return the empty
773 * set.
774 */
776 &gcontext);
777 if (gcontext.contradictory)
778 return NULL;
779 pruning_steps = gcontext.steps;
780
781 /* If there's nothing usable, return all partitions */
782 if (pruning_steps == NIL)
783 return bms_add_range(NULL, 0, rel->nparts - 1);
784
785 /* Set up PartitionPruneContext */
786 context.strategy = rel->part_scheme->strategy;
787 context.partnatts = rel->part_scheme->partnatts;
788 context.nparts = rel->nparts;
789 context.boundinfo = rel->boundinfo;
790 context.partcollation = rel->part_scheme->partcollation;
791 context.partsupfunc = rel->part_scheme->partsupfunc;
792 context.stepcmpfuncs = (FmgrInfo *) palloc0(sizeof(FmgrInfo) *
793 context.partnatts *
794 list_length(pruning_steps));
796
797 /* These are not valid when being called from the planner */
798 context.planstate = NULL;
799 context.exprcontext = NULL;
800 context.exprstates = NULL;
801
802 /* Actual pruning happens here. */
803 return get_matching_partitions(&context, pruning_steps);
804}
bool enable_partition_pruning
Definition: costsize.c:163
MemoryContext CurrentMemoryContext
Definition: mcxt.c:143
Bitmapset * get_matching_partitions(PartitionPruneContext *context, List *pruning_steps)
Definition: partprune.c:817
@ PARTTARGET_PLANNER
Definition: partprune.c:93
static void gen_partprune_steps(RelOptInfo *rel, List *clauses, PartClauseTarget target, GeneratePruningStepsContext *context)
Definition: partprune.c:714
Definition: fmgr.h:57
FmgrInfo * partsupfunc
Definition: partprune.h:56
ExprContext * exprcontext
Definition: partprune.h:60
MemoryContext ppccontext
Definition: partprune.h:58
PlanState * planstate
Definition: partprune.h:59
FmgrInfo * stepcmpfuncs
Definition: partprune.h:57
ExprState ** exprstates
Definition: partprune.h:61
List * baserestrictinfo
Definition: pathnodes.h:985

References Assert, RelOptInfo::baserestrictinfo, bms_add_range(), PartitionPruneContext::boundinfo, GeneratePruningStepsContext::contradictory, CurrentMemoryContext, enable_partition_pruning, PartitionPruneContext::exprcontext, PartitionPruneContext::exprstates, gen_partprune_steps(), get_matching_partitions(), list_length(), NIL, RelOptInfo::nparts, PartitionPruneContext::nparts, palloc0(), PartitionPruneContext::partcollation, PartitionPruneContext::partnatts, PartitionPruneContext::partsupfunc, PARTTARGET_PLANNER, PartitionPruneContext::planstate, PartitionPruneContext::ppccontext, PartitionPruneContext::stepcmpfuncs, GeneratePruningStepsContext::steps, and PartitionPruneContext::strategy.

Referenced by expand_partitioned_rtentry().