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] =
858  (PartitionPruneStepCombine *) step,
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  {
908  Assert(context->strategy == PARTITION_STRATEGY_LIST);
910  result = bms_add_member(result, context->boundinfo->null_index);
911  }
912  if (scan_default)
913  {
914  Assert(context->strategy == PARTITION_STRATEGY_LIST ||
915  context->strategy == PARTITION_STRATEGY_RANGE);
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_member(Bitmapset *a, int x)
Definition: bitmapset.c:815
Bitmapset * bms_add_range(Bitmapset *a, int lower, int upper)
Definition: bitmapset.c:1019
#define Assert(condition)
Definition: c.h:858
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
int i
Definition: isn.c:73
void * palloc0(Size size)
Definition: mcxt.c:1346
#define nodeTag(nodeptr)
Definition: nodes.h:133
@ PARTITION_STRATEGY_LIST
Definition: parsenodes.h:872
@ PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:873
#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:3416
static PruneStepResult * perform_pruning_combine_step(PartitionPruneContext *context, PartitionPruneStepCombine *cstep, PruneStepResult **step_results)
Definition: partprune.c:3564
#define lfirst(lc)
Definition: pg_list.h:172
static int list_length(const List *l)
Definition: pg_list.h:152
tree context
Definition: radixtree.h:1833
Bitmapset * bound_offsets
Definition: partprune.c:133

References Assert, bms_add_member(), bms_add_range(), bms_next_member(), PruneStepResult::bound_offsets, context, elog, ERROR, i, lfirst, list_length(), nodeTag, 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, and PartitionPruneStep::step_id.

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_join(Bitmapset *a, Bitmapset *b)
Definition: bitmapset.c:1230
int bms_num_members(const Bitmapset *a)
Definition: bitmapset.c:751
Bitmapset * bms_del_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:1161
List * lappend(List *list, void *datum)
Definition: list.c:339
void pfree(void *pointer)
Definition: mcxt.c:1520
#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:1052
@ RELOPT_OTHER_MEMBER_REL
Definition: pathnodes.h:819
#define NIL
Definition: pg_list.h:68
tree ctl root
Definition: radixtree.h:1884
RelOptInfo * find_base_rel(PlannerInfo *root, int relid)
Definition: relnode.c:414
Index parent_relid
Definition: pathnodes.h:2958
Definition: pg_list.h:54
Bitmapset * other_subplans
Definition: plannodes.h:1429
Index relid
Definition: pathnodes.h:908
RelOptKind reloptkind
Definition: pathnodes.h:855

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;
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));
795  context.ppccontext = CurrentMemoryContext;
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:152
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
List * baserestrictinfo
Definition: pathnodes.h:975

References Assert, RelOptInfo::baserestrictinfo, bms_add_range(), context, GeneratePruningStepsContext::contradictory, CurrentMemoryContext, enable_partition_pruning, gen_partprune_steps(), get_matching_partitions(), list_length(), NIL, RelOptInfo::nparts, palloc0(), PARTTARGET_PLANNER, and GeneratePruningStepsContext::steps.

Referenced by expand_partitioned_rtentry().