PostgreSQL Source Code  git master
partbounds.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * partbounds.c
4  * Support routines for manipulating partition bounds
5  *
6  * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  * IDENTIFICATION
10  * src/backend/partitioning/partbounds.c
11  *
12  *-------------------------------------------------------------------------
13  */
14 
15 #include "postgres.h"
16 
17 #include "access/relation.h"
18 #include "access/table.h"
19 #include "access/tableam.h"
20 #include "catalog/partition.h"
21 #include "catalog/pg_inherits.h"
22 #include "catalog/pg_type.h"
23 #include "commands/tablecmds.h"
24 #include "common/hashfn.h"
25 #include "executor/executor.h"
26 #include "miscadmin.h"
27 #include "nodes/makefuncs.h"
28 #include "nodes/nodeFuncs.h"
29 #include "nodes/pathnodes.h"
30 #include "parser/parse_coerce.h"
32 #include "partitioning/partdesc.h"
33 #include "partitioning/partprune.h"
34 #include "utils/builtins.h"
35 #include "utils/datum.h"
36 #include "utils/fmgroids.h"
37 #include "utils/lsyscache.h"
38 #include "utils/partcache.h"
39 #include "utils/ruleutils.h"
40 #include "utils/snapmgr.h"
41 #include "utils/syscache.h"
42 
43 /*
44  * When qsort'ing partition bounds after reading from the catalog, each bound
45  * is represented with one of the following structs.
46  */
47 
48 /* One bound of a hash partition */
49 typedef struct PartitionHashBound
50 {
51  int modulus;
52  int remainder;
53  int index;
55 
56 /* One value coming from some (index'th) list partition */
57 typedef struct PartitionListValue
58 {
59  int index;
62 
63 /* One bound of a range partition */
64 typedef struct PartitionRangeBound
65 {
66  int index;
67  Datum *datums; /* range bound datums */
68  PartitionRangeDatumKind *kind; /* the kind of each datum */
69  bool lower; /* this is the lower (vs upper) bound */
71 
72 /*
73  * Mapping from partitions of a joining relation to partitions of a join
74  * relation being computed (a.k.a merged partitions)
75  */
76 typedef struct PartitionMap
77 {
78  int nparts; /* number of partitions */
79  int *merged_indexes; /* indexes of merged partitions */
80  bool *merged; /* flags to indicate whether partitions are
81  * merged with non-dummy partitions */
82  bool did_remapping; /* did we re-map partitions? */
83  int *old_indexes; /* old indexes of merged partitions if
84  * did_remapping */
85 } PartitionMap;
86 
87 /* Macro for comparing two range bounds */
88 #define compare_range_bounds(partnatts, partsupfunc, partcollations, \
89  bound1, bound2) \
90  (partition_rbound_cmp(partnatts, partsupfunc, partcollations, \
91  (bound1)->datums, (bound1)->kind, (bound1)->lower, \
92  bound2))
93 
94 static int32 qsort_partition_hbound_cmp(const void *a, const void *b);
95 static int32 qsort_partition_list_value_cmp(const void *a, const void *b,
96  void *arg);
97 static int32 qsort_partition_rbound_cmp(const void *a, const void *b,
98  void *arg);
100  int nparts, PartitionKey key, int **mapping);
102  int nparts, PartitionKey key, int **mapping);
104  int nparts, PartitionKey key, int **mapping);
105 static PartitionBoundInfo merge_list_bounds(FmgrInfo *partsupfunc,
106  Oid *collations,
107  RelOptInfo *outer_rel,
108  RelOptInfo *inner_rel,
109  JoinType jointype,
110  List **outer_parts,
111  List **inner_parts);
112 static PartitionBoundInfo merge_range_bounds(int partnatts,
113  FmgrInfo *partsupfuncs,
114  Oid *partcollations,
115  RelOptInfo *outer_rel,
116  RelOptInfo *inner_rel,
117  JoinType jointype,
118  List **outer_parts,
119  List **inner_parts);
120 static void init_partition_map(RelOptInfo *rel, PartitionMap *map);
121 static void free_partition_map(PartitionMap *map);
122 static bool is_dummy_partition(RelOptInfo *rel, int part_index);
123 static int merge_matching_partitions(PartitionMap *outer_map,
124  PartitionMap *inner_map,
125  int outer_part,
126  int inner_part,
127  int *next_index);
128 static int process_outer_partition(PartitionMap *outer_map,
129  PartitionMap *inner_map,
130  bool outer_has_default,
131  bool inner_has_default,
132  int outer_index,
133  int inner_default,
134  JoinType jointype,
135  int *next_index,
136  int *default_index);
137 static int process_inner_partition(PartitionMap *outer_map,
138  PartitionMap *inner_map,
139  bool outer_has_default,
140  bool inner_has_default,
141  int inner_index,
142  int outer_default,
143  JoinType jointype,
144  int *next_index,
145  int *default_index);
146 static void merge_null_partitions(PartitionMap *outer_map,
147  PartitionMap *inner_map,
148  bool outer_has_null,
149  bool inner_has_null,
150  int outer_null,
151  int inner_null,
152  JoinType jointype,
153  int *next_index,
154  int *null_index);
155 static void merge_default_partitions(PartitionMap *outer_map,
156  PartitionMap *inner_map,
157  bool outer_has_default,
158  bool inner_has_default,
159  int outer_default,
160  int inner_default,
161  JoinType jointype,
162  int *next_index,
163  int *default_index);
164 static int merge_partition_with_dummy(PartitionMap *map, int index,
165  int *next_index);
166 static void fix_merged_indexes(PartitionMap *outer_map,
167  PartitionMap *inner_map,
168  int nmerged, List *merged_indexes);
169 static void generate_matching_part_pairs(RelOptInfo *outer_rel,
170  RelOptInfo *inner_rel,
171  PartitionMap *outer_map,
172  PartitionMap *inner_map,
173  int nmerged,
174  List **outer_parts,
175  List **inner_parts);
177  List *merged_datums,
178  List *merged_kinds,
179  List *merged_indexes,
180  int null_index,
181  int default_index);
182 static int get_range_partition(RelOptInfo *rel,
184  int *lb_pos,
186  PartitionRangeBound *ub);
188  int *lb_pos,
190  PartitionRangeBound *ub);
191 static bool compare_range_partitions(int partnatts, FmgrInfo *partsupfuncs,
192  Oid *partcollations,
193  PartitionRangeBound *outer_lb,
194  PartitionRangeBound *outer_ub,
195  PartitionRangeBound *inner_lb,
196  PartitionRangeBound *inner_ub,
197  int *lb_cmpval, int *ub_cmpval);
198 static void get_merged_range_bounds(int partnatts, FmgrInfo *partsupfuncs,
199  Oid *partcollations, JoinType jointype,
200  PartitionRangeBound *outer_lb,
201  PartitionRangeBound *outer_ub,
202  PartitionRangeBound *inner_lb,
203  PartitionRangeBound *inner_ub,
204  int lb_cmpval, int ub_cmpval,
205  PartitionRangeBound *merged_lb,
206  PartitionRangeBound *merged_ub);
207 static void add_merged_range_bounds(int partnatts, FmgrInfo *partsupfuncs,
208  Oid *partcollations,
209  PartitionRangeBound *merged_lb,
210  PartitionRangeBound *merged_ub,
211  int merged_index,
212  List **merged_datums,
213  List **merged_kinds,
214  List **merged_indexes);
216  List *datums, bool lower);
217 static int32 partition_hbound_cmp(int modulus1, int remainder1, int modulus2,
218  int remainder2);
219 static int32 partition_rbound_cmp(int partnatts, FmgrInfo *partsupfunc,
220  Oid *partcollation, Datum *datums1,
221  PartitionRangeDatumKind *kind1, bool lower1,
222  PartitionRangeBound *b2);
223 static int partition_range_bsearch(int partnatts, FmgrInfo *partsupfunc,
224  Oid *partcollation,
225  PartitionBoundInfo boundinfo,
226  PartitionRangeBound *probe, int32 *cmpval);
227 static Expr *make_partition_op_expr(PartitionKey key, int keynum,
228  uint16 strategy, Expr *arg1, Expr *arg2);
230  StrategyNumber strategy, bool *need_relabel);
231 static List *get_qual_for_hash(Relation parent, PartitionBoundSpec *spec);
232 static List *get_qual_for_list(Relation parent, PartitionBoundSpec *spec);
233 static List *get_qual_for_range(Relation parent, PartitionBoundSpec *spec,
234  bool for_default);
235 static void get_range_key_properties(PartitionKey key, int keynum,
236  PartitionRangeDatum *ldatum,
237  PartitionRangeDatum *udatum,
238  ListCell **partexprs_item,
239  Expr **keyCol,
240  Const **lower_val, Const **upper_val);
242 
243 /*
244  * get_qual_from_partbound
245  * Given a parser node for partition bound, return the list of executable
246  * expressions as partition constraint
247  */
248 List *
250 {
252  List *my_qual = NIL;
253 
254  Assert(key != NULL);
255 
256  switch (key->strategy)
257  {
260  my_qual = get_qual_for_hash(parent, spec);
261  break;
262 
265  my_qual = get_qual_for_list(parent, spec);
266  break;
267 
270  my_qual = get_qual_for_range(parent, spec, false);
271  break;
272 
273  default:
274  elog(ERROR, "unexpected partition strategy: %d",
275  (int) key->strategy);
276  }
277 
278  return my_qual;
279 }
280 
281 /*
282  * partition_bounds_create
283  * Build a PartitionBoundInfo struct from a list of PartitionBoundSpec
284  * nodes
285  *
286  * This function creates a PartitionBoundInfo and fills the values of its
287  * various members based on the input list. Importantly, 'datums' array will
288  * contain Datum representation of individual bounds (possibly after
289  * de-duplication as in case of range bounds), sorted in a canonical order
290  * defined by qsort_partition_* functions of respective partitioning methods.
291  * 'indexes' array will contain as many elements as there are bounds (specific
292  * exceptions to this rule are listed in the function body), which represent
293  * the 0-based canonical positions of partitions.
294  *
295  * Upon return from this function, *mapping is set to an array of
296  * list_length(boundspecs) elements, each of which maps the original index of
297  * a partition to its canonical index.
298  *
299  * Note: The objects returned by this function are wholly allocated in the
300  * current memory context.
301  */
304  PartitionKey key, int **mapping)
305 {
306  int i;
307 
308  Assert(nparts > 0);
309 
310  /*
311  * For each partitioning method, we first convert the partition bounds
312  * from their parser node representation to the internal representation,
313  * along with any additional preprocessing (such as de-duplicating range
314  * bounds). Resulting bound datums are then added to the 'datums' array
315  * in PartitionBoundInfo. For each datum added, an integer indicating the
316  * canonical partition index is added to the 'indexes' array.
317  *
318  * For each bound, we remember its partition's position (0-based) in the
319  * original list to later map it to the canonical index.
320  */
321 
322  /*
323  * Initialize mapping array with invalid values, this is filled within
324  * each sub-routine below depending on the bound type.
325  */
326  *mapping = (int *) palloc(sizeof(int) * nparts);
327  for (i = 0; i < nparts; i++)
328  (*mapping)[i] = -1;
329 
330  switch (key->strategy)
331  {
333  return create_hash_bounds(boundspecs, nparts, key, mapping);
334 
336  return create_list_bounds(boundspecs, nparts, key, mapping);
337 
339  return create_range_bounds(boundspecs, nparts, key, mapping);
340 
341  default:
342  elog(ERROR, "unexpected partition strategy: %d",
343  (int) key->strategy);
344  break;
345  }
346 
347  Assert(false);
348  return NULL; /* keep compiler quiet */
349 }
350 
351 /*
352  * create_hash_bounds
353  * Create a PartitionBoundInfo for a hash partitioned table
354  */
355 static PartitionBoundInfo
356 create_hash_bounds(PartitionBoundSpec **boundspecs, int nparts,
357  PartitionKey key, int **mapping)
358 {
359  PartitionBoundInfo boundinfo;
360  PartitionHashBound *hbounds;
361  int i;
362  int greatest_modulus;
363  Datum *boundDatums;
364 
365  boundinfo = (PartitionBoundInfoData *)
367  boundinfo->strategy = key->strategy;
368  /* No special hash partitions. */
369  boundinfo->null_index = -1;
370  boundinfo->default_index = -1;
371 
372  hbounds = (PartitionHashBound *)
373  palloc(nparts * sizeof(PartitionHashBound));
374 
375  /* Convert from node to the internal representation */
376  for (i = 0; i < nparts; i++)
377  {
378  PartitionBoundSpec *spec = boundspecs[i];
379 
380  if (spec->strategy != PARTITION_STRATEGY_HASH)
381  elog(ERROR, "invalid strategy in partition bound spec");
382 
383  hbounds[i].modulus = spec->modulus;
384  hbounds[i].remainder = spec->remainder;
385  hbounds[i].index = i;
386  }
387 
388  /* Sort all the bounds in ascending order */
389  qsort(hbounds, nparts, sizeof(PartitionHashBound),
391 
392  /* After sorting, moduli are now stored in ascending order. */
393  greatest_modulus = hbounds[nparts - 1].modulus;
394 
395  boundinfo->ndatums = nparts;
396  boundinfo->datums = (Datum **) palloc0(nparts * sizeof(Datum *));
397  boundinfo->kind = NULL;
398  boundinfo->interleaved_parts = NULL;
399  boundinfo->nindexes = greatest_modulus;
400  boundinfo->indexes = (int *) palloc(greatest_modulus * sizeof(int));
401  for (i = 0; i < greatest_modulus; i++)
402  boundinfo->indexes[i] = -1;
403 
404  /*
405  * In the loop below, to save from allocating a series of small datum
406  * arrays, here we just allocate a single array and below we'll just
407  * assign a portion of this array per partition.
408  */
409  boundDatums = (Datum *) palloc(nparts * 2 * sizeof(Datum));
410 
411  /*
412  * For hash partitioning, there are as many datums (modulus and remainder
413  * pairs) as there are partitions. Indexes are simply values ranging from
414  * 0 to (nparts - 1).
415  */
416  for (i = 0; i < nparts; i++)
417  {
418  int modulus = hbounds[i].modulus;
419  int remainder = hbounds[i].remainder;
420 
421  boundinfo->datums[i] = &boundDatums[i * 2];
422  boundinfo->datums[i][0] = Int32GetDatum(modulus);
423  boundinfo->datums[i][1] = Int32GetDatum(remainder);
424 
425  while (remainder < greatest_modulus)
426  {
427  /* overlap? */
428  Assert(boundinfo->indexes[remainder] == -1);
429  boundinfo->indexes[remainder] = i;
430  remainder += modulus;
431  }
432 
433  (*mapping)[hbounds[i].index] = i;
434  }
435  pfree(hbounds);
436 
437  return boundinfo;
438 }
439 
440 /*
441  * get_non_null_list_datum_count
442  * Counts the number of non-null Datums in each partition.
443  */
444 static int
446 {
447  int i;
448  int count = 0;
449 
450  for (i = 0; i < nparts; i++)
451  {
452  ListCell *lc;
453 
454  foreach(lc, boundspecs[i]->listdatums)
455  {
456  Const *val = lfirst_node(Const, lc);
457 
458  if (!val->constisnull)
459  count++;
460  }
461  }
462 
463  return count;
464 }
465 
466 /*
467  * create_list_bounds
468  * Create a PartitionBoundInfo for a list partitioned table
469  */
470 static PartitionBoundInfo
471 create_list_bounds(PartitionBoundSpec **boundspecs, int nparts,
472  PartitionKey key, int **mapping)
473 {
474  PartitionBoundInfo boundinfo;
475  PartitionListValue *all_values;
476  int i;
477  int j;
478  int ndatums;
479  int next_index = 0;
480  int default_index = -1;
481  int null_index = -1;
482  Datum *boundDatums;
483 
484  boundinfo = (PartitionBoundInfoData *)
486  boundinfo->strategy = key->strategy;
487  /* Will be set correctly below. */
488  boundinfo->null_index = -1;
489  boundinfo->default_index = -1;
490 
491  ndatums = get_non_null_list_datum_count(boundspecs, nparts);
492  all_values = (PartitionListValue *)
493  palloc(ndatums * sizeof(PartitionListValue));
494 
495  /* Create a unified list of non-null values across all partitions. */
496  for (j = 0, i = 0; i < nparts; i++)
497  {
498  PartitionBoundSpec *spec = boundspecs[i];
499  ListCell *c;
500 
501  if (spec->strategy != PARTITION_STRATEGY_LIST)
502  elog(ERROR, "invalid strategy in partition bound spec");
503 
504  /*
505  * Note the index of the partition bound spec for the default
506  * partition. There's no datum to add to the list on non-null datums
507  * for this partition.
508  */
509  if (spec->is_default)
510  {
511  default_index = i;
512  continue;
513  }
514 
515  foreach(c, spec->listdatums)
516  {
517  Const *val = lfirst_node(Const, c);
518 
519  if (!val->constisnull)
520  {
521  all_values[j].index = i;
522  all_values[j].value = val->constvalue;
523  j++;
524  }
525  else
526  {
527  /*
528  * Never put a null into the values array; save the index of
529  * the partition that stores nulls, instead.
530  */
531  if (null_index != -1)
532  elog(ERROR, "found null more than once");
533  null_index = i;
534  }
535  }
536  }
537 
538  /* ensure we found a Datum for every slot in the all_values array */
539  Assert(j == ndatums);
540 
541  qsort_arg(all_values, ndatums, sizeof(PartitionListValue),
542  qsort_partition_list_value_cmp, (void *) key);
543 
544  boundinfo->ndatums = ndatums;
545  boundinfo->datums = (Datum **) palloc0(ndatums * sizeof(Datum *));
546  boundinfo->kind = NULL;
547  boundinfo->interleaved_parts = NULL;
548  boundinfo->nindexes = ndatums;
549  boundinfo->indexes = (int *) palloc(ndatums * sizeof(int));
550 
551  /*
552  * In the loop below, to save from allocating a series of small datum
553  * arrays, here we just allocate a single array and below we'll just
554  * assign a portion of this array per datum.
555  */
556  boundDatums = (Datum *) palloc(ndatums * sizeof(Datum));
557 
558  /*
559  * Copy values. Canonical indexes are values ranging from 0 to (nparts -
560  * 1) assigned to each partition such that all datums of a given partition
561  * receive the same value. The value for a given partition is the index of
562  * that partition's smallest datum in the all_values[] array.
563  */
564  for (i = 0; i < ndatums; i++)
565  {
566  int orig_index = all_values[i].index;
567 
568  boundinfo->datums[i] = &boundDatums[i];
569  boundinfo->datums[i][0] = datumCopy(all_values[i].value,
570  key->parttypbyval[0],
571  key->parttyplen[0]);
572 
573  /* If the old index has no mapping, assign one */
574  if ((*mapping)[orig_index] == -1)
575  (*mapping)[orig_index] = next_index++;
576 
577  boundinfo->indexes[i] = (*mapping)[orig_index];
578  }
579 
580  pfree(all_values);
581 
582  /*
583  * Set the canonical value for null_index, if any.
584  *
585  * It is possible that the null-accepting partition has not been assigned
586  * an index yet, which could happen if such partition accepts only null
587  * and hence not handled in the above loop which only looked at non-null
588  * values.
589  */
590  if (null_index != -1)
591  {
592  Assert(null_index >= 0);
593  if ((*mapping)[null_index] == -1)
594  (*mapping)[null_index] = next_index++;
595  boundinfo->null_index = (*mapping)[null_index];
596  }
597 
598  /* Set the canonical value for default_index, if any. */
599  if (default_index != -1)
600  {
601  /*
602  * The default partition accepts any value not specified in the lists
603  * of other partitions, hence it should not get mapped index while
604  * assigning those for non-null datums.
605  */
606  Assert(default_index >= 0);
607  Assert((*mapping)[default_index] == -1);
608  (*mapping)[default_index] = next_index++;
609  boundinfo->default_index = (*mapping)[default_index];
610  }
611 
612  /*
613  * Calculate interleaved partitions. Here we look for partitions which
614  * might be interleaved with other partitions and set a bit in
615  * interleaved_parts for any partitions which may be interleaved with
616  * another partition.
617  */
618 
619  /*
620  * There must be multiple partitions to have any interleaved partitions,
621  * otherwise there's nothing to interleave with.
622  */
623  if (nparts > 1)
624  {
625  /*
626  * Short-circuit check to see if only 1 Datum is allowed per
627  * partition. When this is true there's no need to do the more
628  * expensive checks to look for interleaved values.
629  */
630  if (boundinfo->ndatums +
631  partition_bound_accepts_nulls(boundinfo) +
632  partition_bound_has_default(boundinfo) != nparts)
633  {
634  int last_index = -1;
635 
636  /*
637  * Since the indexes array is sorted in Datum order, if any
638  * partitions are interleaved then it will show up by the
639  * partition indexes not being in ascending order. Here we check
640  * for that and record all partitions that are out of order.
641  */
642  for (i = 0; i < boundinfo->nindexes; i++)
643  {
644  int index = boundinfo->indexes[i];
645 
646  if (index < last_index)
647  boundinfo->interleaved_parts = bms_add_member(boundinfo->interleaved_parts,
648  index);
649 
650  /*
651  * Mark the NULL partition as interleaved if we find that it
652  * allows some other non-NULL Datum.
653  */
654  if (partition_bound_accepts_nulls(boundinfo) &&
655  index == boundinfo->null_index)
656  boundinfo->interleaved_parts = bms_add_member(boundinfo->interleaved_parts,
657  boundinfo->null_index);
658 
659  last_index = index;
660  }
661  }
662 
663  /*
664  * The DEFAULT partition is the "catch-all" partition that can contain
665  * anything that does not belong to any other partition. If there are
666  * any other partitions then the DEFAULT partition must be marked as
667  * interleaved.
668  */
669  if (partition_bound_has_default(boundinfo))
670  boundinfo->interleaved_parts = bms_add_member(boundinfo->interleaved_parts,
671  boundinfo->default_index);
672  }
673 
674 
675  /* All partitions must now have been assigned canonical indexes. */
676  Assert(next_index == nparts);
677  return boundinfo;
678 }
679 
680 /*
681  * create_range_bounds
682  * Create a PartitionBoundInfo for a range partitioned table
683  */
684 static PartitionBoundInfo
685 create_range_bounds(PartitionBoundSpec **boundspecs, int nparts,
686  PartitionKey key, int **mapping)
687 {
688  PartitionBoundInfo boundinfo;
689  PartitionRangeBound **rbounds = NULL;
690  PartitionRangeBound **all_bounds,
691  *prev;
692  int i,
693  k,
694  partnatts;
695  int ndatums = 0;
696  int default_index = -1;
697  int next_index = 0;
698  Datum *boundDatums;
699  PartitionRangeDatumKind *boundKinds;
700 
701  boundinfo = (PartitionBoundInfoData *)
703  boundinfo->strategy = key->strategy;
704  /* There is no special null-accepting range partition. */
705  boundinfo->null_index = -1;
706  /* Will be set correctly below. */
707  boundinfo->default_index = -1;
708 
709  all_bounds = (PartitionRangeBound **)
710  palloc0(2 * nparts * sizeof(PartitionRangeBound *));
711 
712  /* Create a unified list of range bounds across all the partitions. */
713  ndatums = 0;
714  for (i = 0; i < nparts; i++)
715  {
716  PartitionBoundSpec *spec = boundspecs[i];
718  *upper;
719 
720  if (spec->strategy != PARTITION_STRATEGY_RANGE)
721  elog(ERROR, "invalid strategy in partition bound spec");
722 
723  /*
724  * Note the index of the partition bound spec for the default
725  * partition. There's no datum to add to the all_bounds array for
726  * this partition.
727  */
728  if (spec->is_default)
729  {
730  default_index = i;
731  continue;
732  }
733 
734  lower = make_one_partition_rbound(key, i, spec->lowerdatums, true);
735  upper = make_one_partition_rbound(key, i, spec->upperdatums, false);
736  all_bounds[ndatums++] = lower;
737  all_bounds[ndatums++] = upper;
738  }
739 
740  Assert(ndatums == nparts * 2 ||
741  (default_index != -1 && ndatums == (nparts - 1) * 2));
742 
743  /* Sort all the bounds in ascending order */
744  qsort_arg(all_bounds, ndatums,
745  sizeof(PartitionRangeBound *),
747  (void *) key);
748 
749  /* Save distinct bounds from all_bounds into rbounds. */
750  rbounds = (PartitionRangeBound **)
751  palloc(ndatums * sizeof(PartitionRangeBound *));
752  k = 0;
753  prev = NULL;
754  for (i = 0; i < ndatums; i++)
755  {
756  PartitionRangeBound *cur = all_bounds[i];
757  bool is_distinct = false;
758  int j;
759 
760  /* Is the current bound distinct from the previous one? */
761  for (j = 0; j < key->partnatts; j++)
762  {
763  Datum cmpval;
764 
765  if (prev == NULL || cur->kind[j] != prev->kind[j])
766  {
767  is_distinct = true;
768  break;
769  }
770 
771  /*
772  * If the bounds are both MINVALUE or MAXVALUE, stop now and treat
773  * them as equal, since any values after this point must be
774  * ignored.
775  */
776  if (cur->kind[j] != PARTITION_RANGE_DATUM_VALUE)
777  break;
778 
779  cmpval = FunctionCall2Coll(&key->partsupfunc[j],
780  key->partcollation[j],
781  cur->datums[j],
782  prev->datums[j]);
783  if (DatumGetInt32(cmpval) != 0)
784  {
785  is_distinct = true;
786  break;
787  }
788  }
789 
790  /*
791  * Only if the bound is distinct save it into a temporary array, i.e,
792  * rbounds which is later copied into boundinfo datums array.
793  */
794  if (is_distinct)
795  rbounds[k++] = all_bounds[i];
796 
797  prev = cur;
798  }
799 
800  pfree(all_bounds);
801 
802  /* Update ndatums to hold the count of distinct datums. */
803  ndatums = k;
804 
805  /*
806  * Add datums to boundinfo. Canonical indexes are values ranging from 0
807  * to nparts - 1, assigned in that order to each partition's upper bound.
808  * For 'datums' elements that are lower bounds, there is -1 in the
809  * 'indexes' array to signify that no partition exists for the values less
810  * than such a bound and greater than or equal to the previous upper
811  * bound.
812  */
813  boundinfo->ndatums = ndatums;
814  boundinfo->datums = (Datum **) palloc0(ndatums * sizeof(Datum *));
815  boundinfo->kind = (PartitionRangeDatumKind **)
816  palloc(ndatums *
817  sizeof(PartitionRangeDatumKind *));
818  boundinfo->interleaved_parts = NULL;
819 
820  /*
821  * For range partitioning, an additional value of -1 is stored as the last
822  * element of the indexes[] array.
823  */
824  boundinfo->nindexes = ndatums + 1;
825  boundinfo->indexes = (int *) palloc((ndatums + 1) * sizeof(int));
826 
827  /*
828  * In the loop below, to save from allocating a series of small arrays,
829  * here we just allocate a single array for Datums and another for
830  * PartitionRangeDatumKinds, below we'll just assign a portion of these
831  * arrays in each loop.
832  */
833  partnatts = key->partnatts;
834  boundDatums = (Datum *) palloc(ndatums * partnatts * sizeof(Datum));
835  boundKinds = (PartitionRangeDatumKind *) palloc(ndatums * partnatts *
836  sizeof(PartitionRangeDatumKind));
837 
838  for (i = 0; i < ndatums; i++)
839  {
840  int j;
841 
842  boundinfo->datums[i] = &boundDatums[i * partnatts];
843  boundinfo->kind[i] = &boundKinds[i * partnatts];
844  for (j = 0; j < partnatts; j++)
845  {
846  if (rbounds[i]->kind[j] == PARTITION_RANGE_DATUM_VALUE)
847  boundinfo->datums[i][j] =
848  datumCopy(rbounds[i]->datums[j],
849  key->parttypbyval[j],
850  key->parttyplen[j]);
851  boundinfo->kind[i][j] = rbounds[i]->kind[j];
852  }
853 
854  /*
855  * There is no mapping for invalid indexes.
856  *
857  * Any lower bounds in the rbounds array have invalid indexes
858  * assigned, because the values between the previous bound (if there
859  * is one) and this (lower) bound are not part of the range of any
860  * existing partition.
861  */
862  if (rbounds[i]->lower)
863  boundinfo->indexes[i] = -1;
864  else
865  {
866  int orig_index = rbounds[i]->index;
867 
868  /* If the old index has no mapping, assign one */
869  if ((*mapping)[orig_index] == -1)
870  (*mapping)[orig_index] = next_index++;
871 
872  boundinfo->indexes[i] = (*mapping)[orig_index];
873  }
874  }
875 
876  pfree(rbounds);
877 
878  /* Set the canonical value for default_index, if any. */
879  if (default_index != -1)
880  {
881  Assert(default_index >= 0 && (*mapping)[default_index] == -1);
882  (*mapping)[default_index] = next_index++;
883  boundinfo->default_index = (*mapping)[default_index];
884  }
885 
886  /* The extra -1 element. */
887  Assert(i == ndatums);
888  boundinfo->indexes[i] = -1;
889 
890  /* All partitions must now have been assigned canonical indexes. */
891  Assert(next_index == nparts);
892  return boundinfo;
893 }
894 
895 /*
896  * Are two partition bound collections logically equal?
897  *
898  * Used in the keep logic of relcache.c (ie, in RelationClearRelation()).
899  * This is also useful when b1 and b2 are bound collections of two separate
900  * relations, respectively, because PartitionBoundInfo is a canonical
901  * representation of partition bounds.
902  */
903 bool
904 partition_bounds_equal(int partnatts, int16 *parttyplen, bool *parttypbyval,
906 {
907  int i;
908 
909  if (b1->strategy != b2->strategy)
910  return false;
911 
912  if (b1->ndatums != b2->ndatums)
913  return false;
914 
915  if (b1->nindexes != b2->nindexes)
916  return false;
917 
918  if (b1->null_index != b2->null_index)
919  return false;
920 
921  if (b1->default_index != b2->default_index)
922  return false;
923 
924  /* For all partition strategies, the indexes[] arrays have to match */
925  for (i = 0; i < b1->nindexes; i++)
926  {
927  if (b1->indexes[i] != b2->indexes[i])
928  return false;
929  }
930 
931  /* Finally, compare the datums[] arrays */
933  {
934  /*
935  * We arrange the partitions in the ascending order of their moduli
936  * and remainders. Also every modulus is factor of next larger
937  * modulus. Therefore we can safely store index of a given partition
938  * in indexes array at remainder of that partition. Also entries at
939  * (remainder + N * modulus) positions in indexes array are all same
940  * for (modulus, remainder) specification for any partition. Thus the
941  * datums arrays from the given bounds are the same, if and only if
942  * their indexes arrays are the same. So, it suffices to compare the
943  * indexes arrays.
944  *
945  * Nonetheless make sure that the bounds are indeed the same when the
946  * indexes match. Hash partition bound stores modulus and remainder
947  * at b1->datums[i][0] and b1->datums[i][1] position respectively.
948  */
949 #ifdef USE_ASSERT_CHECKING
950  for (i = 0; i < b1->ndatums; i++)
951  Assert((b1->datums[i][0] == b2->datums[i][0] &&
952  b1->datums[i][1] == b2->datums[i][1]));
953 #endif
954  }
955  else
956  {
957  for (i = 0; i < b1->ndatums; i++)
958  {
959  int j;
960 
961  for (j = 0; j < partnatts; j++)
962  {
963  /* For range partitions, the bounds might not be finite. */
964  if (b1->kind != NULL)
965  {
966  /* The different kinds of bound all differ from each other */
967  if (b1->kind[i][j] != b2->kind[i][j])
968  return false;
969 
970  /*
971  * Non-finite bounds are equal without further
972  * examination.
973  */
974  if (b1->kind[i][j] != PARTITION_RANGE_DATUM_VALUE)
975  continue;
976  }
977 
978  /*
979  * Compare the actual values. Note that it would be both
980  * incorrect and unsafe to invoke the comparison operator
981  * derived from the partitioning specification here. It would
982  * be incorrect because we want the relcache entry to be
983  * updated for ANY change to the partition bounds, not just
984  * those that the partitioning operator thinks are
985  * significant. It would be unsafe because we might reach
986  * this code in the context of an aborted transaction, and an
987  * arbitrary partitioning operator might not be safe in that
988  * context. datumIsEqual() should be simple enough to be
989  * safe.
990  */
991  if (!datumIsEqual(b1->datums[i][j], b2->datums[i][j],
992  parttypbyval[j], parttyplen[j]))
993  return false;
994  }
995  }
996  }
997  return true;
998 }
999 
1000 /*
1001  * Return a copy of given PartitionBoundInfo structure. The data types of bounds
1002  * are described by given partition key specification.
1003  *
1004  * Note: it's important that this function and its callees not do any catalog
1005  * access, nor anything else that would result in allocating memory other than
1006  * the returned data structure. Since this is called in a long-lived context,
1007  * that would result in unwanted memory leaks.
1008  */
1011  PartitionKey key)
1012 {
1014  int i;
1015  int ndatums;
1016  int nindexes;
1017  int partnatts;
1018  bool hash_part;
1019  int natts;
1020  Datum *boundDatums;
1021 
1023 
1024  dest->strategy = src->strategy;
1025  ndatums = dest->ndatums = src->ndatums;
1026  nindexes = dest->nindexes = src->nindexes;
1027  partnatts = key->partnatts;
1028 
1029  /* List partitioned tables have only a single partition key. */
1030  Assert(key->strategy != PARTITION_STRATEGY_LIST || partnatts == 1);
1031 
1032  dest->datums = (Datum **) palloc(sizeof(Datum *) * ndatums);
1033 
1034  if (src->kind != NULL)
1035  {
1036  PartitionRangeDatumKind *boundKinds;
1037 
1038  /* only RANGE partition should have a non-NULL kind */
1040 
1041  dest->kind = (PartitionRangeDatumKind **) palloc(ndatums *
1042  sizeof(PartitionRangeDatumKind *));
1043 
1044  /*
1045  * In the loop below, to save from allocating a series of small arrays
1046  * for storing the PartitionRangeDatumKind, we allocate a single chunk
1047  * here and use a smaller portion of it for each datum.
1048  */
1049  boundKinds = (PartitionRangeDatumKind *) palloc(ndatums * partnatts *
1050  sizeof(PartitionRangeDatumKind));
1051 
1052  for (i = 0; i < ndatums; i++)
1053  {
1054  dest->kind[i] = &boundKinds[i * partnatts];
1055  memcpy(dest->kind[i], src->kind[i],
1056  sizeof(PartitionRangeDatumKind) * partnatts);
1057  }
1058  }
1059  else
1060  dest->kind = NULL;
1061 
1062  /* copy interleaved partitions for LIST partitioned tables */
1064 
1065  /*
1066  * For hash partitioning, datums array will have two elements - modulus
1067  * and remainder.
1068  */
1069  hash_part = (key->strategy == PARTITION_STRATEGY_HASH);
1070  natts = hash_part ? 2 : partnatts;
1071  boundDatums = palloc(ndatums * natts * sizeof(Datum));
1072 
1073  for (i = 0; i < ndatums; i++)
1074  {
1075  int j;
1076 
1077  dest->datums[i] = &boundDatums[i * natts];
1078 
1079  for (j = 0; j < natts; j++)
1080  {
1081  bool byval;
1082  int typlen;
1083 
1084  if (hash_part)
1085  {
1086  typlen = sizeof(int32); /* Always int4 */
1087  byval = true; /* int4 is pass-by-value */
1088  }
1089  else
1090  {
1091  byval = key->parttypbyval[j];
1092  typlen = key->parttyplen[j];
1093  }
1094 
1095  if (dest->kind == NULL ||
1096  dest->kind[i][j] == PARTITION_RANGE_DATUM_VALUE)
1097  dest->datums[i][j] = datumCopy(src->datums[i][j],
1098  byval, typlen);
1099  }
1100  }
1101 
1102  dest->indexes = (int *) palloc(sizeof(int) * nindexes);
1103  memcpy(dest->indexes, src->indexes, sizeof(int) * nindexes);
1104 
1105  dest->null_index = src->null_index;
1106  dest->default_index = src->default_index;
1107 
1108  return dest;
1109 }
1110 
1111 /*
1112  * partition_bounds_merge
1113  * Check to see whether every partition of 'outer_rel' matches/overlaps
1114  * one partition of 'inner_rel' at most, and vice versa; and if so, build
1115  * and return the partition bounds for a join relation between the rels,
1116  * generating two lists of the matching/overlapping partitions, which are
1117  * returned to *outer_parts and *inner_parts respectively.
1118  *
1119  * The lists contain the same number of partitions, and the partitions at the
1120  * same positions in the lists indicate join pairs used for partitioned join.
1121  * If a partition on one side matches/overlaps multiple partitions on the other
1122  * side, this function returns NULL, setting *outer_parts and *inner_parts to
1123  * NIL.
1124  */
1127  FmgrInfo *partsupfunc, Oid *partcollation,
1128  RelOptInfo *outer_rel, RelOptInfo *inner_rel,
1129  JoinType jointype,
1130  List **outer_parts, List **inner_parts)
1131 {
1132  /*
1133  * Currently, this function is called only from try_partitionwise_join(),
1134  * so the join type should be INNER, LEFT, FULL, SEMI, or ANTI.
1135  */
1136  Assert(jointype == JOIN_INNER || jointype == JOIN_LEFT ||
1137  jointype == JOIN_FULL || jointype == JOIN_SEMI ||
1138  jointype == JOIN_ANTI);
1139 
1140  /* The partitioning strategies should be the same. */
1141  Assert(outer_rel->boundinfo->strategy == inner_rel->boundinfo->strategy);
1142 
1143  *outer_parts = *inner_parts = NIL;
1144  switch (outer_rel->boundinfo->strategy)
1145  {
1147 
1148  /*
1149  * For hash partitioned tables, we currently support partitioned
1150  * join only when they have exactly the same partition bounds.
1151  *
1152  * XXX: it might be possible to relax the restriction to support
1153  * cases where hash partitioned tables have missing partitions
1154  * and/or different moduli, but it's not clear if it would be
1155  * useful to support the former case since it's unusual to have
1156  * missing partitions. On the other hand, it would be useful to
1157  * support the latter case, but in that case, there is a high
1158  * probability that a partition on one side will match multiple
1159  * partitions on the other side, which is the scenario the current
1160  * implementation of partitioned join can't handle.
1161  */
1162  return NULL;
1163 
1165  return merge_list_bounds(partsupfunc,
1166  partcollation,
1167  outer_rel,
1168  inner_rel,
1169  jointype,
1170  outer_parts,
1171  inner_parts);
1172 
1174  return merge_range_bounds(partnatts,
1175  partsupfunc,
1176  partcollation,
1177  outer_rel,
1178  inner_rel,
1179  jointype,
1180  outer_parts,
1181  inner_parts);
1182 
1183  default:
1184  elog(ERROR, "unexpected partition strategy: %d",
1185  (int) outer_rel->boundinfo->strategy);
1186  return NULL; /* keep compiler quiet */
1187  }
1188 }
1189 
1190 /*
1191  * merge_list_bounds
1192  * Create the partition bounds for a join relation between list
1193  * partitioned tables, if possible
1194  *
1195  * In this function we try to find sets of matching partitions from both sides
1196  * by comparing list values stored in their partition bounds. Since the list
1197  * values appear in the ascending order, an algorithm similar to merge join is
1198  * used for that. If a partition on one side doesn't have a matching
1199  * partition on the other side, the algorithm tries to match it with the
1200  * default partition on the other side if any; if not, the algorithm tries to
1201  * match it with a dummy partition on the other side if it's on the
1202  * non-nullable side of an outer join. Also, if both sides have the default
1203  * partitions, the algorithm tries to match them with each other. We give up
1204  * if the algorithm finds a partition matching multiple partitions on the
1205  * other side, which is the scenario the current implementation of partitioned
1206  * join can't handle.
1207  */
1208 static PartitionBoundInfo
1209 merge_list_bounds(FmgrInfo *partsupfunc, Oid *partcollation,
1210  RelOptInfo *outer_rel, RelOptInfo *inner_rel,
1211  JoinType jointype,
1212  List **outer_parts, List **inner_parts)
1213 {
1214  PartitionBoundInfo merged_bounds = NULL;
1215  PartitionBoundInfo outer_bi = outer_rel->boundinfo;
1216  PartitionBoundInfo inner_bi = inner_rel->boundinfo;
1217  bool outer_has_default = partition_bound_has_default(outer_bi);
1218  bool inner_has_default = partition_bound_has_default(inner_bi);
1219  int outer_default = outer_bi->default_index;
1220  int inner_default = inner_bi->default_index;
1221  bool outer_has_null = partition_bound_accepts_nulls(outer_bi);
1222  bool inner_has_null = partition_bound_accepts_nulls(inner_bi);
1223  PartitionMap outer_map;
1224  PartitionMap inner_map;
1225  int outer_pos;
1226  int inner_pos;
1227  int next_index = 0;
1228  int null_index = -1;
1229  int default_index = -1;
1230  List *merged_datums = NIL;
1231  List *merged_indexes = NIL;
1232 
1233  Assert(*outer_parts == NIL);
1234  Assert(*inner_parts == NIL);
1235  Assert(outer_bi->strategy == inner_bi->strategy &&
1236  outer_bi->strategy == PARTITION_STRATEGY_LIST);
1237  /* List partitioning doesn't require kinds. */
1238  Assert(!outer_bi->kind && !inner_bi->kind);
1239 
1240  init_partition_map(outer_rel, &outer_map);
1241  init_partition_map(inner_rel, &inner_map);
1242 
1243  /*
1244  * If the default partitions (if any) have been proven empty, deem them
1245  * non-existent.
1246  */
1247  if (outer_has_default && is_dummy_partition(outer_rel, outer_default))
1248  outer_has_default = false;
1249  if (inner_has_default && is_dummy_partition(inner_rel, inner_default))
1250  inner_has_default = false;
1251 
1252  /*
1253  * Merge partitions from both sides. In each iteration we compare a pair
1254  * of list values, one from each side, and decide whether the
1255  * corresponding partitions match or not. If the two values match
1256  * exactly, move to the next pair of list values, otherwise move to the
1257  * next list value on the side with a smaller list value.
1258  */
1259  outer_pos = inner_pos = 0;
1260  while (outer_pos < outer_bi->ndatums || inner_pos < inner_bi->ndatums)
1261  {
1262  int outer_index = -1;
1263  int inner_index = -1;
1264  Datum *outer_datums;
1265  Datum *inner_datums;
1266  int cmpval;
1267  Datum *merged_datum = NULL;
1268  int merged_index = -1;
1269 
1270  if (outer_pos < outer_bi->ndatums)
1271  {
1272  /*
1273  * If the partition on the outer side has been proven empty,
1274  * ignore it and move to the next datum on the outer side.
1275  */
1276  outer_index = outer_bi->indexes[outer_pos];
1277  if (is_dummy_partition(outer_rel, outer_index))
1278  {
1279  outer_pos++;
1280  continue;
1281  }
1282  }
1283  if (inner_pos < inner_bi->ndatums)
1284  {
1285  /*
1286  * If the partition on the inner side has been proven empty,
1287  * ignore it and move to the next datum on the inner side.
1288  */
1289  inner_index = inner_bi->indexes[inner_pos];
1290  if (is_dummy_partition(inner_rel, inner_index))
1291  {
1292  inner_pos++;
1293  continue;
1294  }
1295  }
1296 
1297  /* Get the list values. */
1298  outer_datums = outer_pos < outer_bi->ndatums ?
1299  outer_bi->datums[outer_pos] : NULL;
1300  inner_datums = inner_pos < inner_bi->ndatums ?
1301  inner_bi->datums[inner_pos] : NULL;
1302 
1303  /*
1304  * We run this loop till both sides finish. This allows us to avoid
1305  * duplicating code to handle the remaining values on the side which
1306  * finishes later. For that we set the comparison parameter cmpval in
1307  * such a way that it appears as if the side which finishes earlier
1308  * has an extra value higher than any other value on the unfinished
1309  * side. That way we advance the values on the unfinished side till
1310  * all of its values are exhausted.
1311  */
1312  if (outer_pos >= outer_bi->ndatums)
1313  cmpval = 1;
1314  else if (inner_pos >= inner_bi->ndatums)
1315  cmpval = -1;
1316  else
1317  {
1318  Assert(outer_datums != NULL && inner_datums != NULL);
1319  cmpval = DatumGetInt32(FunctionCall2Coll(&partsupfunc[0],
1320  partcollation[0],
1321  outer_datums[0],
1322  inner_datums[0]));
1323  }
1324 
1325  if (cmpval == 0)
1326  {
1327  /* Two list values match exactly. */
1328  Assert(outer_pos < outer_bi->ndatums);
1329  Assert(inner_pos < inner_bi->ndatums);
1330  Assert(outer_index >= 0);
1331  Assert(inner_index >= 0);
1332 
1333  /*
1334  * Try merging both partitions. If successful, add the list value
1335  * and index of the merged partition below.
1336  */
1337  merged_index = merge_matching_partitions(&outer_map, &inner_map,
1338  outer_index, inner_index,
1339  &next_index);
1340  if (merged_index == -1)
1341  goto cleanup;
1342 
1343  merged_datum = outer_datums;
1344 
1345  /* Move to the next pair of list values. */
1346  outer_pos++;
1347  inner_pos++;
1348  }
1349  else if (cmpval < 0)
1350  {
1351  /* A list value missing from the inner side. */
1352  Assert(outer_pos < outer_bi->ndatums);
1353 
1354  /*
1355  * If the inner side has the default partition, or this is an
1356  * outer join, try to assign a merged partition to the outer
1357  * partition (see process_outer_partition()). Otherwise, the
1358  * outer partition will not contribute to the result.
1359  */
1360  if (inner_has_default || IS_OUTER_JOIN(jointype))
1361  {
1362  /* Get the outer partition. */
1363  outer_index = outer_bi->indexes[outer_pos];
1364  Assert(outer_index >= 0);
1365  merged_index = process_outer_partition(&outer_map,
1366  &inner_map,
1367  outer_has_default,
1368  inner_has_default,
1369  outer_index,
1370  inner_default,
1371  jointype,
1372  &next_index,
1373  &default_index);
1374  if (merged_index == -1)
1375  goto cleanup;
1376  merged_datum = outer_datums;
1377  }
1378 
1379  /* Move to the next list value on the outer side. */
1380  outer_pos++;
1381  }
1382  else
1383  {
1384  /* A list value missing from the outer side. */
1385  Assert(cmpval > 0);
1386  Assert(inner_pos < inner_bi->ndatums);
1387 
1388  /*
1389  * If the outer side has the default partition, or this is a FULL
1390  * join, try to assign a merged partition to the inner partition
1391  * (see process_inner_partition()). Otherwise, the inner
1392  * partition will not contribute to the result.
1393  */
1394  if (outer_has_default || jointype == JOIN_FULL)
1395  {
1396  /* Get the inner partition. */
1397  inner_index = inner_bi->indexes[inner_pos];
1398  Assert(inner_index >= 0);
1399  merged_index = process_inner_partition(&outer_map,
1400  &inner_map,
1401  outer_has_default,
1402  inner_has_default,
1403  inner_index,
1404  outer_default,
1405  jointype,
1406  &next_index,
1407  &default_index);
1408  if (merged_index == -1)
1409  goto cleanup;
1410  merged_datum = inner_datums;
1411  }
1412 
1413  /* Move to the next list value on the inner side. */
1414  inner_pos++;
1415  }
1416 
1417  /*
1418  * If we assigned a merged partition, add the list value and index of
1419  * the merged partition if appropriate.
1420  */
1421  if (merged_index >= 0 && merged_index != default_index)
1422  {
1423  merged_datums = lappend(merged_datums, merged_datum);
1424  merged_indexes = lappend_int(merged_indexes, merged_index);
1425  }
1426  }
1427 
1428  /*
1429  * If the NULL partitions (if any) have been proven empty, deem them
1430  * non-existent.
1431  */
1432  if (outer_has_null &&
1433  is_dummy_partition(outer_rel, outer_bi->null_index))
1434  outer_has_null = false;
1435  if (inner_has_null &&
1436  is_dummy_partition(inner_rel, inner_bi->null_index))
1437  inner_has_null = false;
1438 
1439  /* Merge the NULL partitions if any. */
1440  if (outer_has_null || inner_has_null)
1441  merge_null_partitions(&outer_map, &inner_map,
1442  outer_has_null, inner_has_null,
1443  outer_bi->null_index, inner_bi->null_index,
1444  jointype, &next_index, &null_index);
1445  else
1446  Assert(null_index == -1);
1447 
1448  /* Merge the default partitions if any. */
1449  if (outer_has_default || inner_has_default)
1450  merge_default_partitions(&outer_map, &inner_map,
1451  outer_has_default, inner_has_default,
1452  outer_default, inner_default,
1453  jointype, &next_index, &default_index);
1454  else
1455  Assert(default_index == -1);
1456 
1457  /* If we have merged partitions, create the partition bounds. */
1458  if (next_index > 0)
1459  {
1460  /* Fix the merged_indexes list if necessary. */
1461  if (outer_map.did_remapping || inner_map.did_remapping)
1462  {
1463  Assert(jointype == JOIN_FULL);
1464  fix_merged_indexes(&outer_map, &inner_map,
1465  next_index, merged_indexes);
1466  }
1467 
1468  /* Use maps to match partitions from inputs. */
1469  generate_matching_part_pairs(outer_rel, inner_rel,
1470  &outer_map, &inner_map,
1471  next_index,
1472  outer_parts, inner_parts);
1473  Assert(*outer_parts != NIL);
1474  Assert(*inner_parts != NIL);
1475  Assert(list_length(*outer_parts) == list_length(*inner_parts));
1476  Assert(list_length(*outer_parts) <= next_index);
1477 
1478  /* Make a PartitionBoundInfo struct to return. */
1479  merged_bounds = build_merged_partition_bounds(outer_bi->strategy,
1480  merged_datums,
1481  NIL,
1482  merged_indexes,
1483  null_index,
1484  default_index);
1485  Assert(merged_bounds);
1486  }
1487 
1488 cleanup:
1489  /* Free local memory before returning. */
1490  list_free(merged_datums);
1491  list_free(merged_indexes);
1492  free_partition_map(&outer_map);
1493  free_partition_map(&inner_map);
1494 
1495  return merged_bounds;
1496 }
1497 
1498 /*
1499  * merge_range_bounds
1500  * Create the partition bounds for a join relation between range
1501  * partitioned tables, if possible
1502  *
1503  * In this function we try to find sets of overlapping partitions from both
1504  * sides by comparing ranges stored in their partition bounds. Since the
1505  * ranges appear in the ascending order, an algorithm similar to merge join is
1506  * used for that. If a partition on one side doesn't have an overlapping
1507  * partition on the other side, the algorithm tries to match it with the
1508  * default partition on the other side if any; if not, the algorithm tries to
1509  * match it with a dummy partition on the other side if it's on the
1510  * non-nullable side of an outer join. Also, if both sides have the default
1511  * partitions, the algorithm tries to match them with each other. We give up
1512  * if the algorithm finds a partition overlapping multiple partitions on the
1513  * other side, which is the scenario the current implementation of partitioned
1514  * join can't handle.
1515  */
1516 static PartitionBoundInfo
1517 merge_range_bounds(int partnatts, FmgrInfo *partsupfuncs,
1518  Oid *partcollations,
1519  RelOptInfo *outer_rel, RelOptInfo *inner_rel,
1520  JoinType jointype,
1521  List **outer_parts, List **inner_parts)
1522 {
1523  PartitionBoundInfo merged_bounds = NULL;
1524  PartitionBoundInfo outer_bi = outer_rel->boundinfo;
1525  PartitionBoundInfo inner_bi = inner_rel->boundinfo;
1526  bool outer_has_default = partition_bound_has_default(outer_bi);
1527  bool inner_has_default = partition_bound_has_default(inner_bi);
1528  int outer_default = outer_bi->default_index;
1529  int inner_default = inner_bi->default_index;
1530  PartitionMap outer_map;
1531  PartitionMap inner_map;
1532  int outer_index;
1533  int inner_index;
1534  int outer_lb_pos;
1535  int inner_lb_pos;
1536  PartitionRangeBound outer_lb;
1537  PartitionRangeBound outer_ub;
1538  PartitionRangeBound inner_lb;
1539  PartitionRangeBound inner_ub;
1540  int next_index = 0;
1541  int default_index = -1;
1542  List *merged_datums = NIL;
1543  List *merged_kinds = NIL;
1544  List *merged_indexes = NIL;
1545 
1546  Assert(*outer_parts == NIL);
1547  Assert(*inner_parts == NIL);
1548  Assert(outer_bi->strategy == inner_bi->strategy &&
1549  outer_bi->strategy == PARTITION_STRATEGY_RANGE);
1550 
1551  init_partition_map(outer_rel, &outer_map);
1552  init_partition_map(inner_rel, &inner_map);
1553 
1554  /*
1555  * If the default partitions (if any) have been proven empty, deem them
1556  * non-existent.
1557  */
1558  if (outer_has_default && is_dummy_partition(outer_rel, outer_default))
1559  outer_has_default = false;
1560  if (inner_has_default && is_dummy_partition(inner_rel, inner_default))
1561  inner_has_default = false;
1562 
1563  /*
1564  * Merge partitions from both sides. In each iteration we compare a pair
1565  * of ranges, one from each side, and decide whether the corresponding
1566  * partitions match or not. If the two ranges overlap, move to the next
1567  * pair of ranges, otherwise move to the next range on the side with a
1568  * lower range. outer_lb_pos/inner_lb_pos keep track of the positions of
1569  * lower bounds in the datums arrays in the outer/inner
1570  * PartitionBoundInfos respectively.
1571  */
1572  outer_lb_pos = inner_lb_pos = 0;
1573  outer_index = get_range_partition(outer_rel, outer_bi, &outer_lb_pos,
1574  &outer_lb, &outer_ub);
1575  inner_index = get_range_partition(inner_rel, inner_bi, &inner_lb_pos,
1576  &inner_lb, &inner_ub);
1577  while (outer_index >= 0 || inner_index >= 0)
1578  {
1579  bool overlap;
1580  int ub_cmpval;
1581  int lb_cmpval;
1582  PartitionRangeBound merged_lb = {-1, NULL, NULL, true};
1583  PartitionRangeBound merged_ub = {-1, NULL, NULL, false};
1584  int merged_index = -1;
1585 
1586  /*
1587  * We run this loop till both sides finish. This allows us to avoid
1588  * duplicating code to handle the remaining ranges on the side which
1589  * finishes later. For that we set the comparison parameter cmpval in
1590  * such a way that it appears as if the side which finishes earlier
1591  * has an extra range higher than any other range on the unfinished
1592  * side. That way we advance the ranges on the unfinished side till
1593  * all of its ranges are exhausted.
1594  */
1595  if (outer_index == -1)
1596  {
1597  overlap = false;
1598  lb_cmpval = 1;
1599  ub_cmpval = 1;
1600  }
1601  else if (inner_index == -1)
1602  {
1603  overlap = false;
1604  lb_cmpval = -1;
1605  ub_cmpval = -1;
1606  }
1607  else
1608  overlap = compare_range_partitions(partnatts, partsupfuncs,
1609  partcollations,
1610  &outer_lb, &outer_ub,
1611  &inner_lb, &inner_ub,
1612  &lb_cmpval, &ub_cmpval);
1613 
1614  if (overlap)
1615  {
1616  /* Two ranges overlap; form a join pair. */
1617 
1618  PartitionRangeBound save_outer_ub;
1619  PartitionRangeBound save_inner_ub;
1620 
1621  /* Both partitions should not have been merged yet. */
1622  Assert(outer_index >= 0);
1623  Assert(outer_map.merged_indexes[outer_index] == -1 &&
1624  outer_map.merged[outer_index] == false);
1625  Assert(inner_index >= 0);
1626  Assert(inner_map.merged_indexes[inner_index] == -1 &&
1627  inner_map.merged[inner_index] == false);
1628 
1629  /*
1630  * Get the index of the merged partition. Both partitions aren't
1631  * merged yet, so the partitions should be merged successfully.
1632  */
1633  merged_index = merge_matching_partitions(&outer_map, &inner_map,
1634  outer_index, inner_index,
1635  &next_index);
1636  Assert(merged_index >= 0);
1637 
1638  /* Get the range bounds of the merged partition. */
1639  get_merged_range_bounds(partnatts, partsupfuncs,
1640  partcollations, jointype,
1641  &outer_lb, &outer_ub,
1642  &inner_lb, &inner_ub,
1643  lb_cmpval, ub_cmpval,
1644  &merged_lb, &merged_ub);
1645 
1646  /* Save the upper bounds of both partitions for use below. */
1647  save_outer_ub = outer_ub;
1648  save_inner_ub = inner_ub;
1649 
1650  /* Move to the next pair of ranges. */
1651  outer_index = get_range_partition(outer_rel, outer_bi, &outer_lb_pos,
1652  &outer_lb, &outer_ub);
1653  inner_index = get_range_partition(inner_rel, inner_bi, &inner_lb_pos,
1654  &inner_lb, &inner_ub);
1655 
1656  /*
1657  * If the range of a partition on one side overlaps the range of
1658  * the next partition on the other side, that will cause the
1659  * partition on one side to match at least two partitions on the
1660  * other side, which is the case that we currently don't support
1661  * partitioned join for; give up.
1662  */
1663  if (ub_cmpval > 0 && inner_index >= 0 &&
1664  compare_range_bounds(partnatts, partsupfuncs, partcollations,
1665  &save_outer_ub, &inner_lb) > 0)
1666  goto cleanup;
1667  if (ub_cmpval < 0 && outer_index >= 0 &&
1668  compare_range_bounds(partnatts, partsupfuncs, partcollations,
1669  &outer_lb, &save_inner_ub) < 0)
1670  goto cleanup;
1671 
1672  /*
1673  * A row from a non-overlapping portion (if any) of a partition on
1674  * one side might find its join partner in the default partition
1675  * (if any) on the other side, causing the same situation as
1676  * above; give up in that case.
1677  */
1678  if ((outer_has_default && (lb_cmpval > 0 || ub_cmpval < 0)) ||
1679  (inner_has_default && (lb_cmpval < 0 || ub_cmpval > 0)))
1680  goto cleanup;
1681  }
1682  else if (ub_cmpval < 0)
1683  {
1684  /* A non-overlapping outer range. */
1685 
1686  /* The outer partition should not have been merged yet. */
1687  Assert(outer_index >= 0);
1688  Assert(outer_map.merged_indexes[outer_index] == -1 &&
1689  outer_map.merged[outer_index] == false);
1690 
1691  /*
1692  * If the inner side has the default partition, or this is an
1693  * outer join, try to assign a merged partition to the outer
1694  * partition (see process_outer_partition()). Otherwise, the
1695  * outer partition will not contribute to the result.
1696  */
1697  if (inner_has_default || IS_OUTER_JOIN(jointype))
1698  {
1699  merged_index = process_outer_partition(&outer_map,
1700  &inner_map,
1701  outer_has_default,
1702  inner_has_default,
1703  outer_index,
1704  inner_default,
1705  jointype,
1706  &next_index,
1707  &default_index);
1708  if (merged_index == -1)
1709  goto cleanup;
1710  merged_lb = outer_lb;
1711  merged_ub = outer_ub;
1712  }
1713 
1714  /* Move to the next range on the outer side. */
1715  outer_index = get_range_partition(outer_rel, outer_bi, &outer_lb_pos,
1716  &outer_lb, &outer_ub);
1717  }
1718  else
1719  {
1720  /* A non-overlapping inner range. */
1721  Assert(ub_cmpval > 0);
1722 
1723  /* The inner partition should not have been merged yet. */
1724  Assert(inner_index >= 0);
1725  Assert(inner_map.merged_indexes[inner_index] == -1 &&
1726  inner_map.merged[inner_index] == false);
1727 
1728  /*
1729  * If the outer side has the default partition, or this is a FULL
1730  * join, try to assign a merged partition to the inner partition
1731  * (see process_inner_partition()). Otherwise, the inner
1732  * partition will not contribute to the result.
1733  */
1734  if (outer_has_default || jointype == JOIN_FULL)
1735  {
1736  merged_index = process_inner_partition(&outer_map,
1737  &inner_map,
1738  outer_has_default,
1739  inner_has_default,
1740  inner_index,
1741  outer_default,
1742  jointype,
1743  &next_index,
1744  &default_index);
1745  if (merged_index == -1)
1746  goto cleanup;
1747  merged_lb = inner_lb;
1748  merged_ub = inner_ub;
1749  }
1750 
1751  /* Move to the next range on the inner side. */
1752  inner_index = get_range_partition(inner_rel, inner_bi, &inner_lb_pos,
1753  &inner_lb, &inner_ub);
1754  }
1755 
1756  /*
1757  * If we assigned a merged partition, add the range bounds and index
1758  * of the merged partition if appropriate.
1759  */
1760  if (merged_index >= 0 && merged_index != default_index)
1761  add_merged_range_bounds(partnatts, partsupfuncs, partcollations,
1762  &merged_lb, &merged_ub, merged_index,
1763  &merged_datums, &merged_kinds,
1764  &merged_indexes);
1765  }
1766 
1767  /* Merge the default partitions if any. */
1768  if (outer_has_default || inner_has_default)
1769  merge_default_partitions(&outer_map, &inner_map,
1770  outer_has_default, inner_has_default,
1771  outer_default, inner_default,
1772  jointype, &next_index, &default_index);
1773  else
1774  Assert(default_index == -1);
1775 
1776  /* If we have merged partitions, create the partition bounds. */
1777  if (next_index > 0)
1778  {
1779  /*
1780  * Unlike the case of list partitioning, we wouldn't have re-merged
1781  * partitions, so did_remapping should be left alone.
1782  */
1783  Assert(!outer_map.did_remapping);
1784  Assert(!inner_map.did_remapping);
1785 
1786  /* Use maps to match partitions from inputs. */
1787  generate_matching_part_pairs(outer_rel, inner_rel,
1788  &outer_map, &inner_map,
1789  next_index,
1790  outer_parts, inner_parts);
1791  Assert(*outer_parts != NIL);
1792  Assert(*inner_parts != NIL);
1793  Assert(list_length(*outer_parts) == list_length(*inner_parts));
1794  Assert(list_length(*outer_parts) == next_index);
1795 
1796  /* Make a PartitionBoundInfo struct to return. */
1797  merged_bounds = build_merged_partition_bounds(outer_bi->strategy,
1798  merged_datums,
1799  merged_kinds,
1800  merged_indexes,
1801  -1,
1802  default_index);
1803  Assert(merged_bounds);
1804  }
1805 
1806 cleanup:
1807  /* Free local memory before returning. */
1808  list_free(merged_datums);
1809  list_free(merged_kinds);
1810  list_free(merged_indexes);
1811  free_partition_map(&outer_map);
1812  free_partition_map(&inner_map);
1813 
1814  return merged_bounds;
1815 }
1816 
1817 /*
1818  * init_partition_map
1819  * Initialize a PartitionMap struct for given relation
1820  */
1821 static void
1823 {
1824  int nparts = rel->nparts;
1825  int i;
1826 
1827  map->nparts = nparts;
1828  map->merged_indexes = (int *) palloc(sizeof(int) * nparts);
1829  map->merged = (bool *) palloc(sizeof(bool) * nparts);
1830  map->did_remapping = false;
1831  map->old_indexes = (int *) palloc(sizeof(int) * nparts);
1832  for (i = 0; i < nparts; i++)
1833  {
1834  map->merged_indexes[i] = map->old_indexes[i] = -1;
1835  map->merged[i] = false;
1836  }
1837 }
1838 
1839 /*
1840  * free_partition_map
1841  */
1842 static void
1844 {
1845  pfree(map->merged_indexes);
1846  pfree(map->merged);
1847  pfree(map->old_indexes);
1848 }
1849 
1850 /*
1851  * is_dummy_partition --- has partition been proven empty?
1852  */
1853 static bool
1854 is_dummy_partition(RelOptInfo *rel, int part_index)
1855 {
1856  RelOptInfo *part_rel;
1857 
1858  Assert(part_index >= 0);
1859  part_rel = rel->part_rels[part_index];
1860  if (part_rel == NULL || IS_DUMMY_REL(part_rel))
1861  return true;
1862  return false;
1863 }
1864 
1865 /*
1866  * merge_matching_partitions
1867  * Try to merge given outer/inner partitions, and return the index of a
1868  * merged partition produced from them if successful, -1 otherwise
1869  *
1870  * If the merged partition is newly created, *next_index is incremented.
1871  */
1872 static int
1874  int outer_index, int inner_index, int *next_index)
1875 {
1876  int outer_merged_index;
1877  int inner_merged_index;
1878  bool outer_merged;
1879  bool inner_merged;
1880 
1881  Assert(outer_index >= 0 && outer_index < outer_map->nparts);
1882  outer_merged_index = outer_map->merged_indexes[outer_index];
1883  outer_merged = outer_map->merged[outer_index];
1884  Assert(inner_index >= 0 && inner_index < inner_map->nparts);
1885  inner_merged_index = inner_map->merged_indexes[inner_index];
1886  inner_merged = inner_map->merged[inner_index];
1887 
1888  /*
1889  * Handle cases where we have already assigned a merged partition to each
1890  * of the given partitions.
1891  */
1892  if (outer_merged_index >= 0 && inner_merged_index >= 0)
1893  {
1894  /*
1895  * If the merged partitions are the same, no need to do anything;
1896  * return the index of the merged partitions. Otherwise, if each of
1897  * the given partitions has been merged with a dummy partition on the
1898  * other side, re-map them to either of the two merged partitions.
1899  * Otherwise, they can't be merged, so return -1.
1900  */
1901  if (outer_merged_index == inner_merged_index)
1902  {
1903  Assert(outer_merged);
1904  Assert(inner_merged);
1905  return outer_merged_index;
1906  }
1907  if (!outer_merged && !inner_merged)
1908  {
1909  /*
1910  * This can only happen for a list-partitioning case. We re-map
1911  * them to the merged partition with the smaller of the two merged
1912  * indexes to preserve the property that the canonical order of
1913  * list partitions is determined by the indexes assigned to the
1914  * smallest list value of each partition.
1915  */
1916  if (outer_merged_index < inner_merged_index)
1917  {
1918  outer_map->merged[outer_index] = true;
1919  inner_map->merged_indexes[inner_index] = outer_merged_index;
1920  inner_map->merged[inner_index] = true;
1921  inner_map->did_remapping = true;
1922  inner_map->old_indexes[inner_index] = inner_merged_index;
1923  return outer_merged_index;
1924  }
1925  else
1926  {
1927  inner_map->merged[inner_index] = true;
1928  outer_map->merged_indexes[outer_index] = inner_merged_index;
1929  outer_map->merged[outer_index] = true;
1930  outer_map->did_remapping = true;
1931  outer_map->old_indexes[outer_index] = outer_merged_index;
1932  return inner_merged_index;
1933  }
1934  }
1935  return -1;
1936  }
1937 
1938  /* At least one of the given partitions should not have yet been merged. */
1939  Assert(outer_merged_index == -1 || inner_merged_index == -1);
1940 
1941  /*
1942  * If neither of them has been merged, merge them. Otherwise, if one has
1943  * been merged with a dummy partition on the other side (and the other
1944  * hasn't yet been merged with anything), re-merge them. Otherwise, they
1945  * can't be merged, so return -1.
1946  */
1947  if (outer_merged_index == -1 && inner_merged_index == -1)
1948  {
1949  int merged_index = *next_index;
1950 
1951  Assert(!outer_merged);
1952  Assert(!inner_merged);
1953  outer_map->merged_indexes[outer_index] = merged_index;
1954  outer_map->merged[outer_index] = true;
1955  inner_map->merged_indexes[inner_index] = merged_index;
1956  inner_map->merged[inner_index] = true;
1957  *next_index = *next_index + 1;
1958  return merged_index;
1959  }
1960  if (outer_merged_index >= 0 && !outer_map->merged[outer_index])
1961  {
1962  Assert(inner_merged_index == -1);
1963  Assert(!inner_merged);
1964  inner_map->merged_indexes[inner_index] = outer_merged_index;
1965  inner_map->merged[inner_index] = true;
1966  outer_map->merged[outer_index] = true;
1967  return outer_merged_index;
1968  }
1969  if (inner_merged_index >= 0 && !inner_map->merged[inner_index])
1970  {
1971  Assert(outer_merged_index == -1);
1972  Assert(!outer_merged);
1973  outer_map->merged_indexes[outer_index] = inner_merged_index;
1974  outer_map->merged[outer_index] = true;
1975  inner_map->merged[inner_index] = true;
1976  return inner_merged_index;
1977  }
1978  return -1;
1979 }
1980 
1981 /*
1982  * process_outer_partition
1983  * Try to assign given outer partition a merged partition, and return the
1984  * index of the merged partition if successful, -1 otherwise
1985  *
1986  * If the partition is newly created, *next_index is incremented. Also, if it
1987  * is the default partition of the join relation, *default_index is set to the
1988  * index if not already done.
1989  */
1990 static int
1992  PartitionMap *inner_map,
1993  bool outer_has_default,
1994  bool inner_has_default,
1995  int outer_index,
1996  int inner_default,
1997  JoinType jointype,
1998  int *next_index,
1999  int *default_index)
2000 {
2001  int merged_index = -1;
2002 
2003  Assert(outer_index >= 0);
2004 
2005  /*
2006  * If the inner side has the default partition, a row from the outer
2007  * partition might find its join partner in the default partition; try
2008  * merging the outer partition with the default partition. Otherwise,
2009  * this should be an outer join, in which case the outer partition has to
2010  * be scanned all the way anyway; merge the outer partition with a dummy
2011  * partition on the other side.
2012  */
2013  if (inner_has_default)
2014  {
2015  Assert(inner_default >= 0);
2016 
2017  /*
2018  * If the outer side has the default partition as well, the default
2019  * partition on the inner side will have two matching partitions on
2020  * the other side: the outer partition and the default partition on
2021  * the outer side. Partitionwise join doesn't handle this scenario
2022  * yet.
2023  */
2024  if (outer_has_default)
2025  return -1;
2026 
2027  merged_index = merge_matching_partitions(outer_map, inner_map,
2028  outer_index, inner_default,
2029  next_index);
2030  if (merged_index == -1)
2031  return -1;
2032 
2033  /*
2034  * If this is a FULL join, the default partition on the inner side has
2035  * to be scanned all the way anyway, so the resulting partition will
2036  * contain all key values from the default partition, which any other
2037  * partition of the join relation will not contain. Thus the
2038  * resulting partition will act as the default partition of the join
2039  * relation; record the index in *default_index if not already done.
2040  */
2041  if (jointype == JOIN_FULL)
2042  {
2043  if (*default_index == -1)
2044  *default_index = merged_index;
2045  else
2046  Assert(*default_index == merged_index);
2047  }
2048  }
2049  else
2050  {
2051  Assert(IS_OUTER_JOIN(jointype));
2052  Assert(jointype != JOIN_RIGHT);
2053 
2054  /* If we have already assigned a partition, no need to do anything. */
2055  merged_index = outer_map->merged_indexes[outer_index];
2056  if (merged_index == -1)
2057  merged_index = merge_partition_with_dummy(outer_map, outer_index,
2058  next_index);
2059  }
2060  return merged_index;
2061 }
2062 
2063 /*
2064  * process_inner_partition
2065  * Try to assign given inner partition a merged partition, and return the
2066  * index of the merged partition if successful, -1 otherwise
2067  *
2068  * If the partition is newly created, *next_index is incremented. Also, if it
2069  * is the default partition of the join relation, *default_index is set to the
2070  * index if not already done.
2071  */
2072 static int
2074  PartitionMap *inner_map,
2075  bool outer_has_default,
2076  bool inner_has_default,
2077  int inner_index,
2078  int outer_default,
2079  JoinType jointype,
2080  int *next_index,
2081  int *default_index)
2082 {
2083  int merged_index = -1;
2084 
2085  Assert(inner_index >= 0);
2086 
2087  /*
2088  * If the outer side has the default partition, a row from the inner
2089  * partition might find its join partner in the default partition; try
2090  * merging the inner partition with the default partition. Otherwise,
2091  * this should be a FULL join, in which case the inner partition has to be
2092  * scanned all the way anyway; merge the inner partition with a dummy
2093  * partition on the other side.
2094  */
2095  if (outer_has_default)
2096  {
2097  Assert(outer_default >= 0);
2098 
2099  /*
2100  * If the inner side has the default partition as well, the default
2101  * partition on the outer side will have two matching partitions on
2102  * the other side: the inner partition and the default partition on
2103  * the inner side. Partitionwise join doesn't handle this scenario
2104  * yet.
2105  */
2106  if (inner_has_default)
2107  return -1;
2108 
2109  merged_index = merge_matching_partitions(outer_map, inner_map,
2110  outer_default, inner_index,
2111  next_index);
2112  if (merged_index == -1)
2113  return -1;
2114 
2115  /*
2116  * If this is an outer join, the default partition on the outer side
2117  * has to be scanned all the way anyway, so the resulting partition
2118  * will contain all key values from the default partition, which any
2119  * other partition of the join relation will not contain. Thus the
2120  * resulting partition will act as the default partition of the join
2121  * relation; record the index in *default_index if not already done.
2122  */
2123  if (IS_OUTER_JOIN(jointype))
2124  {
2125  Assert(jointype != JOIN_RIGHT);
2126  if (*default_index == -1)
2127  *default_index = merged_index;
2128  else
2129  Assert(*default_index == merged_index);
2130  }
2131  }
2132  else
2133  {
2134  Assert(jointype == JOIN_FULL);
2135 
2136  /* If we have already assigned a partition, no need to do anything. */
2137  merged_index = inner_map->merged_indexes[inner_index];
2138  if (merged_index == -1)
2139  merged_index = merge_partition_with_dummy(inner_map, inner_index,
2140  next_index);
2141  }
2142  return merged_index;
2143 }
2144 
2145 /*
2146  * merge_null_partitions
2147  * Merge the NULL partitions from a join's outer and inner sides.
2148  *
2149  * If the merged partition produced from them is the NULL partition of the join
2150  * relation, *null_index is set to the index of the merged partition.
2151  *
2152  * Note: We assume here that the join clause for a partitioned join is strict
2153  * because have_partkey_equi_join() requires that the corresponding operator
2154  * be mergejoinable, and we currently assume that mergejoinable operators are
2155  * strict (see MJEvalOuterValues()/MJEvalInnerValues()).
2156  */
2157 static void
2159  PartitionMap *inner_map,
2160  bool outer_has_null,
2161  bool inner_has_null,
2162  int outer_null,
2163  int inner_null,
2164  JoinType jointype,
2165  int *next_index,
2166  int *null_index)
2167 {
2168  bool consider_outer_null = false;
2169  bool consider_inner_null = false;
2170 
2171  Assert(outer_has_null || inner_has_null);
2172  Assert(*null_index == -1);
2173 
2174  /*
2175  * Check whether the NULL partitions have already been merged and if so,
2176  * set the consider_outer_null/consider_inner_null flags.
2177  */
2178  if (outer_has_null)
2179  {
2180  Assert(outer_null >= 0 && outer_null < outer_map->nparts);
2181  if (outer_map->merged_indexes[outer_null] == -1)
2182  consider_outer_null = true;
2183  }
2184  if (inner_has_null)
2185  {
2186  Assert(inner_null >= 0 && inner_null < inner_map->nparts);
2187  if (inner_map->merged_indexes[inner_null] == -1)
2188  consider_inner_null = true;
2189  }
2190 
2191  /* If both flags are set false, we don't need to do anything. */
2192  if (!consider_outer_null && !consider_inner_null)
2193  return;
2194 
2195  if (consider_outer_null && !consider_inner_null)
2196  {
2197  Assert(outer_has_null);
2198 
2199  /*
2200  * If this is an outer join, the NULL partition on the outer side has
2201  * to be scanned all the way anyway; merge the NULL partition with a
2202  * dummy partition on the other side. In that case
2203  * consider_outer_null means that the NULL partition only contains
2204  * NULL values as the key values, so the merged partition will do so;
2205  * treat it as the NULL partition of the join relation.
2206  */
2207  if (IS_OUTER_JOIN(jointype))
2208  {
2209  Assert(jointype != JOIN_RIGHT);
2210  *null_index = merge_partition_with_dummy(outer_map, outer_null,
2211  next_index);
2212  }
2213  }
2214  else if (!consider_outer_null && consider_inner_null)
2215  {
2216  Assert(inner_has_null);
2217 
2218  /*
2219  * If this is a FULL join, the NULL partition on the inner side has to
2220  * be scanned all the way anyway; merge the NULL partition with a
2221  * dummy partition on the other side. In that case
2222  * consider_inner_null means that the NULL partition only contains
2223  * NULL values as the key values, so the merged partition will do so;
2224  * treat it as the NULL partition of the join relation.
2225  */
2226  if (jointype == JOIN_FULL)
2227  *null_index = merge_partition_with_dummy(inner_map, inner_null,
2228  next_index);
2229  }
2230  else
2231  {
2232  Assert(consider_outer_null && consider_inner_null);
2233  Assert(outer_has_null);
2234  Assert(inner_has_null);
2235 
2236  /*
2237  * If this is an outer join, the NULL partition on the outer side (and
2238  * that on the inner side if this is a FULL join) have to be scanned
2239  * all the way anyway, so merge them. Note that each of the NULL
2240  * partitions isn't merged yet, so they should be merged successfully.
2241  * Like the above, each of the NULL partitions only contains NULL
2242  * values as the key values, so the merged partition will do so; treat
2243  * it as the NULL partition of the join relation.
2244  *
2245  * Note: if this an INNER/SEMI join, the join clause will never be
2246  * satisfied by two NULL values (see comments above), so both the NULL
2247  * partitions can be eliminated.
2248  */
2249  if (IS_OUTER_JOIN(jointype))
2250  {
2251  Assert(jointype != JOIN_RIGHT);
2252  *null_index = merge_matching_partitions(outer_map, inner_map,
2253  outer_null, inner_null,
2254  next_index);
2255  Assert(*null_index >= 0);
2256  }
2257  }
2258 }
2259 
2260 /*
2261  * merge_default_partitions
2262  * Merge the default partitions from a join's outer and inner sides.
2263  *
2264  * If the merged partition produced from them is the default partition of the
2265  * join relation, *default_index is set to the index of the merged partition.
2266  */
2267 static void
2269  PartitionMap *inner_map,
2270  bool outer_has_default,
2271  bool inner_has_default,
2272  int outer_default,
2273  int inner_default,
2274  JoinType jointype,
2275  int *next_index,
2276  int *default_index)
2277 {
2278  int outer_merged_index = -1;
2279  int inner_merged_index = -1;
2280 
2281  Assert(outer_has_default || inner_has_default);
2282 
2283  /* Get the merged partition indexes for the default partitions. */
2284  if (outer_has_default)
2285  {
2286  Assert(outer_default >= 0 && outer_default < outer_map->nparts);
2287  outer_merged_index = outer_map->merged_indexes[outer_default];
2288  }
2289  if (inner_has_default)
2290  {
2291  Assert(inner_default >= 0 && inner_default < inner_map->nparts);
2292  inner_merged_index = inner_map->merged_indexes[inner_default];
2293  }
2294 
2295  if (outer_has_default && !inner_has_default)
2296  {
2297  /*
2298  * If this is an outer join, the default partition on the outer side
2299  * has to be scanned all the way anyway; if we have not yet assigned a
2300  * partition, merge the default partition with a dummy partition on
2301  * the other side. The merged partition will act as the default
2302  * partition of the join relation (see comments in
2303  * process_inner_partition()).
2304  */
2305  if (IS_OUTER_JOIN(jointype))
2306  {
2307  Assert(jointype != JOIN_RIGHT);
2308  if (outer_merged_index == -1)
2309  {
2310  Assert(*default_index == -1);
2311  *default_index = merge_partition_with_dummy(outer_map,
2312  outer_default,
2313  next_index);
2314  }
2315  else
2316  Assert(*default_index == outer_merged_index);
2317  }
2318  else
2319  Assert(*default_index == -1);
2320  }
2321  else if (!outer_has_default && inner_has_default)
2322  {
2323  /*
2324  * If this is a FULL join, the default partition on the inner side has
2325  * to be scanned all the way anyway; if we have not yet assigned a
2326  * partition, merge the default partition with a dummy partition on
2327  * the other side. The merged partition will act as the default
2328  * partition of the join relation (see comments in
2329  * process_outer_partition()).
2330  */
2331  if (jointype == JOIN_FULL)
2332  {
2333  if (inner_merged_index == -1)
2334  {
2335  Assert(*default_index == -1);
2336  *default_index = merge_partition_with_dummy(inner_map,
2337  inner_default,
2338  next_index);
2339  }
2340  else
2341  Assert(*default_index == inner_merged_index);
2342  }
2343  else
2344  Assert(*default_index == -1);
2345  }
2346  else
2347  {
2348  Assert(outer_has_default && inner_has_default);
2349 
2350  /*
2351  * The default partitions have to be joined with each other, so merge
2352  * them. Note that each of the default partitions isn't merged yet
2353  * (see, process_outer_partition()/process_innerer_partition()), so
2354  * they should be merged successfully. The merged partition will act
2355  * as the default partition of the join relation.
2356  */
2357  Assert(outer_merged_index == -1);
2358  Assert(inner_merged_index == -1);
2359  Assert(*default_index == -1);
2360  *default_index = merge_matching_partitions(outer_map,
2361  inner_map,
2362  outer_default,
2363  inner_default,
2364  next_index);
2365  Assert(*default_index >= 0);
2366  }
2367 }
2368 
2369 /*
2370  * merge_partition_with_dummy
2371  * Assign given partition a new partition of a join relation
2372  *
2373  * Note: The caller assumes that the given partition doesn't have a non-dummy
2374  * matching partition on the other side, but if the given partition finds the
2375  * matching partition later, we will adjust the assignment.
2376  */
2377 static int
2378 merge_partition_with_dummy(PartitionMap *map, int index, int *next_index)
2379 {
2380  int merged_index = *next_index;
2381 
2382  Assert(index >= 0 && index < map->nparts);
2383  Assert(map->merged_indexes[index] == -1);
2384  Assert(!map->merged[index]);
2385  map->merged_indexes[index] = merged_index;
2386  /* Leave the merged flag alone! */
2387  *next_index = *next_index + 1;
2388  return merged_index;
2389 }
2390 
2391 /*
2392  * fix_merged_indexes
2393  * Adjust merged indexes of re-merged partitions
2394  */
2395 static void
2397  int nmerged, List *merged_indexes)
2398 {
2399  int *new_indexes;
2400  int merged_index;
2401  int i;
2402  ListCell *lc;
2403 
2404  Assert(nmerged > 0);
2405 
2406  new_indexes = (int *) palloc(sizeof(int) * nmerged);
2407  for (i = 0; i < nmerged; i++)
2408  new_indexes[i] = -1;
2409 
2410  /* Build the mapping of old merged indexes to new merged indexes. */
2411  if (outer_map->did_remapping)
2412  {
2413  for (i = 0; i < outer_map->nparts; i++)
2414  {
2415  merged_index = outer_map->old_indexes[i];
2416  if (merged_index >= 0)
2417  new_indexes[merged_index] = outer_map->merged_indexes[i];
2418  }
2419  }
2420  if (inner_map->did_remapping)
2421  {
2422  for (i = 0; i < inner_map->nparts; i++)
2423  {
2424  merged_index = inner_map->old_indexes[i];
2425  if (merged_index >= 0)
2426  new_indexes[merged_index] = inner_map->merged_indexes[i];
2427  }
2428  }
2429 
2430  /* Fix the merged_indexes list using the mapping. */
2431  foreach(lc, merged_indexes)
2432  {
2433  merged_index = lfirst_int(lc);
2434  Assert(merged_index >= 0);
2435  if (new_indexes[merged_index] >= 0)
2436  lfirst_int(lc) = new_indexes[merged_index];
2437  }
2438 
2439  pfree(new_indexes);
2440 }
2441 
2442 /*
2443  * generate_matching_part_pairs
2444  * Generate a pair of lists of partitions that produce merged partitions
2445  *
2446  * The lists of partitions are built in the order of merged partition indexes,
2447  * and returned in *outer_parts and *inner_parts.
2448  */
2449 static void
2451  PartitionMap *outer_map, PartitionMap *inner_map,
2452  int nmerged,
2453  List **outer_parts, List **inner_parts)
2454 {
2455  int outer_nparts = outer_map->nparts;
2456  int inner_nparts = inner_map->nparts;
2457  int *outer_indexes;
2458  int *inner_indexes;
2459  int max_nparts;
2460  int i;
2461 
2462  Assert(nmerged > 0);
2463  Assert(*outer_parts == NIL);
2464  Assert(*inner_parts == NIL);
2465 
2466  outer_indexes = (int *) palloc(sizeof(int) * nmerged);
2467  inner_indexes = (int *) palloc(sizeof(int) * nmerged);
2468  for (i = 0; i < nmerged; i++)
2469  outer_indexes[i] = inner_indexes[i] = -1;
2470 
2471  /* Set pairs of matching partitions. */
2472  Assert(outer_nparts == outer_rel->nparts);
2473  Assert(inner_nparts == inner_rel->nparts);
2474  max_nparts = Max(outer_nparts, inner_nparts);
2475  for (i = 0; i < max_nparts; i++)
2476  {
2477  if (i < outer_nparts)
2478  {
2479  int merged_index = outer_map->merged_indexes[i];
2480 
2481  if (merged_index >= 0)
2482  {
2483  Assert(merged_index < nmerged);
2484  outer_indexes[merged_index] = i;
2485  }
2486  }
2487  if (i < inner_nparts)
2488  {
2489  int merged_index = inner_map->merged_indexes[i];
2490 
2491  if (merged_index >= 0)
2492  {
2493  Assert(merged_index < nmerged);
2494  inner_indexes[merged_index] = i;
2495  }
2496  }
2497  }
2498 
2499  /* Build the list pairs. */
2500  for (i = 0; i < nmerged; i++)
2501  {
2502  int outer_index = outer_indexes[i];
2503  int inner_index = inner_indexes[i];
2504 
2505  /*
2506  * If both partitions are dummy, it means the merged partition that
2507  * had been assigned to the outer/inner partition was removed when
2508  * re-merging the outer/inner partition in
2509  * merge_matching_partitions(); ignore the merged partition.
2510  */
2511  if (outer_index == -1 && inner_index == -1)
2512  continue;
2513 
2514  *outer_parts = lappend(*outer_parts, outer_index >= 0 ?
2515  outer_rel->part_rels[outer_index] : NULL);
2516  *inner_parts = lappend(*inner_parts, inner_index >= 0 ?
2517  inner_rel->part_rels[inner_index] : NULL);
2518  }
2519 
2520  pfree(outer_indexes);
2521  pfree(inner_indexes);
2522 }
2523 
2524 /*
2525  * build_merged_partition_bounds
2526  * Create a PartitionBoundInfo struct from merged partition bounds
2527  */
2528 static PartitionBoundInfo
2529 build_merged_partition_bounds(char strategy, List *merged_datums,
2530  List *merged_kinds, List *merged_indexes,
2531  int null_index, int default_index)
2532 {
2533  PartitionBoundInfo merged_bounds;
2534  int ndatums = list_length(merged_datums);
2535  int pos;
2536  ListCell *lc;
2537 
2538  merged_bounds = (PartitionBoundInfo) palloc(sizeof(PartitionBoundInfoData));
2539  merged_bounds->strategy = strategy;
2540  merged_bounds->ndatums = ndatums;
2541 
2542  merged_bounds->datums = (Datum **) palloc(sizeof(Datum *) * ndatums);
2543  pos = 0;
2544  foreach(lc, merged_datums)
2545  merged_bounds->datums[pos++] = (Datum *) lfirst(lc);
2546 
2547  if (strategy == PARTITION_STRATEGY_RANGE)
2548  {
2549  Assert(list_length(merged_kinds) == ndatums);
2550  merged_bounds->kind = (PartitionRangeDatumKind **)
2551  palloc(sizeof(PartitionRangeDatumKind *) * ndatums);
2552  pos = 0;
2553  foreach(lc, merged_kinds)
2554  merged_bounds->kind[pos++] = (PartitionRangeDatumKind *) lfirst(lc);
2555 
2556  /* There are ndatums+1 indexes in the case of range partitioning. */
2557  merged_indexes = lappend_int(merged_indexes, -1);
2558  ndatums++;
2559  }
2560  else
2561  {
2562  Assert(strategy == PARTITION_STRATEGY_LIST);
2563  Assert(merged_kinds == NIL);
2564  merged_bounds->kind = NULL;
2565  }
2566 
2567  /* interleaved_parts is always NULL for join relations. */
2568  merged_bounds->interleaved_parts = NULL;
2569 
2570  Assert(list_length(merged_indexes) == ndatums);
2571  merged_bounds->nindexes = ndatums;
2572  merged_bounds->indexes = (int *) palloc(sizeof(int) * ndatums);
2573  pos = 0;
2574  foreach(lc, merged_indexes)
2575  merged_bounds->indexes[pos++] = lfirst_int(lc);
2576 
2577  merged_bounds->null_index = null_index;
2578  merged_bounds->default_index = default_index;
2579 
2580  return merged_bounds;
2581 }
2582 
2583 /*
2584  * get_range_partition
2585  * Get the next non-dummy partition of a range-partitioned relation,
2586  * returning the index of that partition
2587  *
2588  * *lb and *ub are set to the lower and upper bounds of that partition
2589  * respectively, and *lb_pos is advanced to the next lower bound, if any.
2590  */
2591 static int
2593  PartitionBoundInfo bi,
2594  int *lb_pos,
2595  PartitionRangeBound *lb,
2596  PartitionRangeBound *ub)
2597 {
2598  int part_index;
2599 
2601 
2602  do
2603  {
2604  part_index = get_range_partition_internal(bi, lb_pos, lb, ub);
2605  if (part_index == -1)
2606  return -1;
2607  } while (is_dummy_partition(rel, part_index));
2608 
2609  return part_index;
2610 }
2611 
2612 static int
2614  int *lb_pos,
2615  PartitionRangeBound *lb,
2616  PartitionRangeBound *ub)
2617 {
2618  /* Return the index as -1 if we've exhausted all lower bounds. */
2619  if (*lb_pos >= bi->ndatums)
2620  return -1;
2621 
2622  /* A lower bound should have at least one more bound after it. */
2623  Assert(*lb_pos + 1 < bi->ndatums);
2624 
2625  /* Set the lower bound. */
2626  lb->index = bi->indexes[*lb_pos];
2627  lb->datums = bi->datums[*lb_pos];
2628  lb->kind = bi->kind[*lb_pos];
2629  lb->lower = true;
2630  /* Set the upper bound. */
2631  ub->index = bi->indexes[*lb_pos + 1];
2632  ub->datums = bi->datums[*lb_pos + 1];
2633  ub->kind = bi->kind[*lb_pos + 1];
2634  ub->lower = false;
2635 
2636  /* The index assigned to an upper bound should be valid. */
2637  Assert(ub->index >= 0);
2638 
2639  /*
2640  * Advance the position to the next lower bound. If there are no bounds
2641  * left beyond the upper bound, we have reached the last lower bound.
2642  */
2643  if (*lb_pos + 2 >= bi->ndatums)
2644  *lb_pos = bi->ndatums;
2645  else
2646  {
2647  /*
2648  * If the index assigned to the bound next to the upper bound isn't
2649  * valid, that is the next lower bound; else, the upper bound is also
2650  * the lower bound of the next range partition.
2651  */
2652  if (bi->indexes[*lb_pos + 2] < 0)
2653  *lb_pos = *lb_pos + 2;
2654  else
2655  *lb_pos = *lb_pos + 1;
2656  }
2657 
2658  return ub->index;
2659 }
2660 
2661 /*
2662  * compare_range_partitions
2663  * Compare the bounds of two range partitions, and return true if the
2664  * two partitions overlap, false otherwise
2665  *
2666  * *lb_cmpval is set to -1, 0, or 1 if the outer partition's lower bound is
2667  * lower than, equal to, or higher than the inner partition's lower bound
2668  * respectively. Likewise, *ub_cmpval is set to -1, 0, or 1 if the outer
2669  * partition's upper bound is lower than, equal to, or higher than the inner
2670  * partition's upper bound respectively.
2671  */
2672 static bool
2673 compare_range_partitions(int partnatts, FmgrInfo *partsupfuncs,
2674  Oid *partcollations,
2675  PartitionRangeBound *outer_lb,
2676  PartitionRangeBound *outer_ub,
2677  PartitionRangeBound *inner_lb,
2678  PartitionRangeBound *inner_ub,
2679  int *lb_cmpval, int *ub_cmpval)
2680 {
2681  /*
2682  * Check if the outer partition's upper bound is lower than the inner
2683  * partition's lower bound; if so the partitions aren't overlapping.
2684  */
2685  if (compare_range_bounds(partnatts, partsupfuncs, partcollations,
2686  outer_ub, inner_lb) < 0)
2687  {
2688  *lb_cmpval = -1;
2689  *ub_cmpval = -1;
2690  return false;
2691  }
2692 
2693  /*
2694  * Check if the outer partition's lower bound is higher than the inner
2695  * partition's upper bound; if so the partitions aren't overlapping.
2696  */
2697  if (compare_range_bounds(partnatts, partsupfuncs, partcollations,
2698  outer_lb, inner_ub) > 0)
2699  {
2700  *lb_cmpval = 1;
2701  *ub_cmpval = 1;
2702  return false;
2703  }
2704 
2705  /* All other cases indicate overlapping partitions. */
2706  *lb_cmpval = compare_range_bounds(partnatts, partsupfuncs, partcollations,
2707  outer_lb, inner_lb);
2708  *ub_cmpval = compare_range_bounds(partnatts, partsupfuncs, partcollations,
2709  outer_ub, inner_ub);
2710  return true;
2711 }
2712 
2713 /*
2714  * get_merged_range_bounds
2715  * Given the bounds of range partitions to be joined, determine the bounds
2716  * of a merged partition produced from the range partitions
2717  *
2718  * *merged_lb and *merged_ub are set to the lower and upper bounds of the
2719  * merged partition.
2720  */
2721 static void
2722 get_merged_range_bounds(int partnatts, FmgrInfo *partsupfuncs,
2723  Oid *partcollations, JoinType jointype,
2724  PartitionRangeBound *outer_lb,
2725  PartitionRangeBound *outer_ub,
2726  PartitionRangeBound *inner_lb,
2727  PartitionRangeBound *inner_ub,
2728  int lb_cmpval, int ub_cmpval,
2729  PartitionRangeBound *merged_lb,
2730  PartitionRangeBound *merged_ub)
2731 {
2732  Assert(compare_range_bounds(partnatts, partsupfuncs, partcollations,
2733  outer_lb, inner_lb) == lb_cmpval);
2734  Assert(compare_range_bounds(partnatts, partsupfuncs, partcollations,
2735  outer_ub, inner_ub) == ub_cmpval);
2736 
2737  switch (jointype)
2738  {
2739  case JOIN_INNER:
2740  case JOIN_SEMI:
2741 
2742  /*
2743  * An INNER/SEMI join will have the rows that fit both sides, so
2744  * the lower bound of the merged partition will be the higher of
2745  * the two lower bounds, and the upper bound of the merged
2746  * partition will be the lower of the two upper bounds.
2747  */
2748  *merged_lb = (lb_cmpval > 0) ? *outer_lb : *inner_lb;
2749  *merged_ub = (ub_cmpval < 0) ? *outer_ub : *inner_ub;
2750  break;
2751 
2752  case JOIN_LEFT:
2753  case JOIN_ANTI:
2754 
2755  /*
2756  * A LEFT/ANTI join will have all the rows from the outer side, so
2757  * the bounds of the merged partition will be the same as the
2758  * outer bounds.
2759  */
2760  *merged_lb = *outer_lb;
2761  *merged_ub = *outer_ub;
2762  break;
2763 
2764  case JOIN_FULL:
2765 
2766  /*
2767  * A FULL join will have all the rows from both sides, so the
2768  * lower bound of the merged partition will be the lower of the
2769  * two lower bounds, and the upper bound of the merged partition
2770  * will be the higher of the two upper bounds.
2771  */
2772  *merged_lb = (lb_cmpval < 0) ? *outer_lb : *inner_lb;
2773  *merged_ub = (ub_cmpval > 0) ? *outer_ub : *inner_ub;
2774  break;
2775 
2776  default:
2777  elog(ERROR, "unrecognized join type: %d", (int) jointype);
2778  }
2779 }
2780 
2781 /*
2782  * add_merged_range_bounds
2783  * Add the bounds of a merged partition to the lists of range bounds
2784  */
2785 static void
2786 add_merged_range_bounds(int partnatts, FmgrInfo *partsupfuncs,
2787  Oid *partcollations,
2788  PartitionRangeBound *merged_lb,
2789  PartitionRangeBound *merged_ub,
2790  int merged_index,
2791  List **merged_datums,
2792  List **merged_kinds,
2793  List **merged_indexes)
2794 {
2795  int cmpval;
2796 
2797  if (!*merged_datums)
2798  {
2799  /* First merged partition */
2800  Assert(!*merged_kinds);
2801  Assert(!*merged_indexes);
2802  cmpval = 1;
2803  }
2804  else
2805  {
2806  PartitionRangeBound prev_ub;
2807 
2808  Assert(*merged_datums);
2809  Assert(*merged_kinds);
2810  Assert(*merged_indexes);
2811 
2812  /* Get the last upper bound. */
2813  prev_ub.index = llast_int(*merged_indexes);
2814  prev_ub.datums = (Datum *) llast(*merged_datums);
2815  prev_ub.kind = (PartitionRangeDatumKind *) llast(*merged_kinds);
2816  prev_ub.lower = false;
2817 
2818  /*
2819  * We pass lower1 = false to partition_rbound_cmp() to prevent it from
2820  * considering the last upper bound to be smaller than the lower bound
2821  * of the merged partition when the values of the two range bounds
2822  * compare equal.
2823  */
2824  cmpval = partition_rbound_cmp(partnatts, partsupfuncs, partcollations,
2825  merged_lb->datums, merged_lb->kind,
2826  false, &prev_ub);
2827  Assert(cmpval >= 0);
2828  }
2829 
2830  /*
2831  * If the lower bound is higher than the last upper bound, add the lower
2832  * bound with the index as -1 indicating that that is a lower bound; else,
2833  * the last upper bound will be reused as the lower bound of the merged
2834  * partition, so skip this.
2835  */
2836  if (cmpval > 0)
2837  {
2838  *merged_datums = lappend(*merged_datums, merged_lb->datums);
2839  *merged_kinds = lappend(*merged_kinds, merged_lb->kind);
2840  *merged_indexes = lappend_int(*merged_indexes, -1);
2841  }
2842 
2843  /* Add the upper bound and index of the merged partition. */
2844  *merged_datums = lappend(*merged_datums, merged_ub->datums);
2845  *merged_kinds = lappend(*merged_kinds, merged_ub->kind);
2846  *merged_indexes = lappend_int(*merged_indexes, merged_index);
2847 }
2848 
2849 /*
2850  * partitions_are_ordered
2851  * Determine whether the partitions described by 'boundinfo' are ordered,
2852  * that is partitions appearing earlier in the PartitionDesc sequence
2853  * contain partition keys strictly less than those appearing later.
2854  * Also, if NULL values are possible, they must come in the last
2855  * partition defined in the PartitionDesc. 'live_parts' marks which
2856  * partitions we should include when checking the ordering. Partitions
2857  * that do not appear in 'live_parts' are ignored.
2858  *
2859  * If out of order, or there is insufficient info to know the order,
2860  * then we return false.
2861  */
2862 bool
2864 {
2865  Assert(boundinfo != NULL);
2866 
2867  switch (boundinfo->strategy)
2868  {
2870 
2871  /*
2872  * RANGE-type partitioning guarantees that the partitions can be
2873  * scanned in the order that they're defined in the PartitionDesc
2874  * to provide sequential, non-overlapping ranges of tuples.
2875  * However, if a DEFAULT partition exists and it's contained
2876  * within live_parts, then the partitions are not ordered.
2877  */
2878  if (!partition_bound_has_default(boundinfo) ||
2879  !bms_is_member(boundinfo->default_index, live_parts))
2880  return true;
2881  break;
2882 
2884 
2885  /*
2886  * LIST partitioned are ordered providing none of live_parts
2887  * overlap with the partitioned table's interleaved partitions.
2888  */
2889  if (!bms_overlap(live_parts, boundinfo->interleaved_parts))
2890  return true;
2891 
2892  break;
2893  default:
2894  /* HASH, or some other strategy */
2895  break;
2896  }
2897 
2898  return false;
2899 }
2900 
2901 /*
2902  * check_new_partition_bound
2903  *
2904  * Checks if the new partition's bound overlaps any of the existing partitions
2905  * of parent. Also performs additional checks as necessary per strategy.
2906  */
2907 void
2909  PartitionBoundSpec *spec, ParseState *pstate)
2910 {
2912  PartitionDesc partdesc = RelationGetPartitionDesc(parent, false);
2913  PartitionBoundInfo boundinfo = partdesc->boundinfo;
2914  int with = -1;
2915  bool overlap = false;
2916  int overlap_location = -1;
2917 
2918  if (spec->is_default)
2919  {
2920  /*
2921  * The default partition bound never conflicts with any other
2922  * partition's; if that's what we're attaching, the only possible
2923  * problem is that one already exists, so check for that and we're
2924  * done.
2925  */
2926  if (boundinfo == NULL || !partition_bound_has_default(boundinfo))
2927  return;
2928 
2929  /* Default partition already exists, error out. */
2930  ereport(ERROR,
2931  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2932  errmsg("partition \"%s\" conflicts with existing default partition \"%s\"",
2933  relname, get_rel_name(partdesc->oids[boundinfo->default_index])),
2934  parser_errposition(pstate, spec->location)));
2935  }
2936 
2937  switch (key->strategy)
2938  {
2940  {
2942  Assert(spec->remainder >= 0 && spec->remainder < spec->modulus);
2943 
2944  if (partdesc->nparts > 0)
2945  {
2946  int greatest_modulus;
2947  int remainder;
2948  int offset;
2949 
2950  /*
2951  * Check rule that every modulus must be a factor of the
2952  * next larger modulus. (For example, if you have a bunch
2953  * of partitions that all have modulus 5, you can add a
2954  * new partition with modulus 10 or a new partition with
2955  * modulus 15, but you cannot add both a partition with
2956  * modulus 10 and a partition with modulus 15, because 10
2957  * is not a factor of 15.) We need only check the next
2958  * smaller and next larger existing moduli, relying on
2959  * previous enforcement of this rule to be sure that the
2960  * rest are in line.
2961  */
2962 
2963  /*
2964  * Get the greatest (modulus, remainder) pair contained in
2965  * boundinfo->datums that is less than or equal to the
2966  * (spec->modulus, spec->remainder) pair.
2967  */
2968  offset = partition_hash_bsearch(boundinfo,
2969  spec->modulus,
2970  spec->remainder);
2971  if (offset < 0)
2972  {
2973  int next_modulus;
2974 
2975  /*
2976  * All existing moduli are greater or equal, so the
2977  * new one must be a factor of the smallest one, which
2978  * is first in the boundinfo.
2979  */
2980  next_modulus = DatumGetInt32(boundinfo->datums[0][0]);
2981  if (next_modulus % spec->modulus != 0)
2982  ereport(ERROR,
2983  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2984  errmsg("every hash partition modulus must be a factor of the next larger modulus"),
2985  errdetail("The new modulus %d is not a factor of %d, the modulus of existing partition \"%s\".",
2986  spec->modulus, next_modulus,
2987  get_rel_name(partdesc->oids[0]))));
2988  }
2989  else
2990  {
2991  int prev_modulus;
2992 
2993  /*
2994  * We found the largest (modulus, remainder) pair less
2995  * than or equal to the new one. That modulus must be
2996  * a divisor of, or equal to, the new modulus.
2997  */
2998  prev_modulus = DatumGetInt32(boundinfo->datums[offset][0]);
2999 
3000  if (spec->modulus % prev_modulus != 0)
3001  ereport(ERROR,
3002  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
3003  errmsg("every hash partition modulus must be a factor of the next larger modulus"),
3004  errdetail("The new modulus %d is not divisible by %d, the modulus of existing partition \"%s\".",
3005  spec->modulus,
3006  prev_modulus,
3007  get_rel_name(partdesc->oids[offset]))));
3008 
3009  if (offset + 1 < boundinfo->ndatums)
3010  {
3011  int next_modulus;
3012 
3013  /*
3014  * Look at the next higher (modulus, remainder)
3015  * pair. That could have the same modulus and a
3016  * larger remainder than the new pair, in which
3017  * case we're good. If it has a larger modulus,
3018  * the new modulus must divide that one.
3019  */
3020  next_modulus = DatumGetInt32(boundinfo->datums[offset + 1][0]);
3021 
3022  if (next_modulus % spec->modulus != 0)
3023  ereport(ERROR,
3024  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
3025  errmsg("every hash partition modulus must be a factor of the next larger modulus"),
3026  errdetail("The new modulus %d is not a factor of %d, the modulus of existing partition \"%s\".",
3027  spec->modulus, next_modulus,
3028  get_rel_name(partdesc->oids[offset + 1]))));
3029  }
3030  }
3031 
3032  greatest_modulus = boundinfo->nindexes;
3033  remainder = spec->remainder;
3034 
3035  /*
3036  * Normally, the lowest remainder that could conflict with
3037  * the new partition is equal to the remainder specified
3038  * for the new partition, but when the new partition has a
3039  * modulus higher than any used so far, we need to adjust.
3040  */
3041  if (remainder >= greatest_modulus)
3042  remainder = remainder % greatest_modulus;
3043 
3044  /* Check every potentially-conflicting remainder. */
3045  do
3046  {
3047  if (boundinfo->indexes[remainder] != -1)
3048  {
3049  overlap = true;
3050  overlap_location = spec->location;
3051  with = boundinfo->indexes[remainder];
3052  break;
3053  }
3054  remainder += spec->modulus;
3055  } while (remainder < greatest_modulus);
3056  }
3057 
3058  break;
3059  }
3060 
3062  {
3064 
3065  if (partdesc->nparts > 0)
3066  {
3067  ListCell *cell;
3068 
3069  Assert(boundinfo &&
3070  boundinfo->strategy == PARTITION_STRATEGY_LIST &&
3071  (boundinfo->ndatums > 0 ||
3072  partition_bound_accepts_nulls(boundinfo) ||
3073  partition_bound_has_default(boundinfo)));
3074 
3075  foreach(cell, spec->listdatums)
3076  {
3077  Const *val = lfirst_node(Const, cell);
3078 
3079  overlap_location = val->location;
3080  if (!val->constisnull)
3081  {
3082  int offset;
3083  bool equal;
3084 
3085  offset = partition_list_bsearch(&key->partsupfunc[0],
3086  key->partcollation,
3087  boundinfo,
3088  val->constvalue,
3089  &equal);
3090  if (offset >= 0 && equal)
3091  {
3092  overlap = true;
3093  with = boundinfo->indexes[offset];
3094  break;
3095  }
3096  }
3097  else if (partition_bound_accepts_nulls(boundinfo))
3098  {
3099  overlap = true;
3100  with = boundinfo->null_index;
3101  break;
3102  }
3103  }
3104  }
3105 
3106  break;
3107  }
3108 
3110  {
3112  *upper;
3113  int cmpval;
3114 
3116  lower = make_one_partition_rbound(key, -1, spec->lowerdatums, true);
3117  upper = make_one_partition_rbound(key, -1, spec->upperdatums, false);
3118 
3119  /*
3120  * First check if the resulting range would be empty with
3121  * specified lower and upper bounds. partition_rbound_cmp
3122  * cannot return zero here, since the lower-bound flags are
3123  * different.
3124  */
3125  cmpval = partition_rbound_cmp(key->partnatts,
3126  key->partsupfunc,
3127  key->partcollation,
3128  lower->datums, lower->kind,
3129  true, upper);
3130  Assert(cmpval != 0);
3131  if (cmpval > 0)
3132  {
3133  /* Point to problematic key in the lower datums list. */
3134  PartitionRangeDatum *datum = list_nth(spec->lowerdatums,
3135  cmpval - 1);
3136 
3137  ereport(ERROR,
3138  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
3139  errmsg("empty range bound specified for partition \"%s\"",
3140  relname),
3141  errdetail("Specified lower bound %s is greater than or equal to upper bound %s.",
3144  parser_errposition(pstate, datum->location)));
3145  }
3146 
3147  if (partdesc->nparts > 0)
3148  {
3149  int offset;
3150 
3151  Assert(boundinfo &&
3152  boundinfo->strategy == PARTITION_STRATEGY_RANGE &&
3153  (boundinfo->ndatums > 0 ||
3154  partition_bound_has_default(boundinfo)));
3155 
3156  /*
3157  * Test whether the new lower bound (which is treated
3158  * inclusively as part of the new partition) lies inside
3159  * an existing partition, or in a gap.
3160  *
3161  * If it's inside an existing partition, the bound at
3162  * offset + 1 will be the upper bound of that partition,
3163  * and its index will be >= 0.
3164  *
3165  * If it's in a gap, the bound at offset + 1 will be the
3166  * lower bound of the next partition, and its index will
3167  * be -1. This is also true if there is no next partition,
3168  * since the index array is initialised with an extra -1
3169  * at the end.
3170  */
3171  offset = partition_range_bsearch(key->partnatts,
3172  key->partsupfunc,
3173  key->partcollation,
3174  boundinfo, lower,
3175  &cmpval);
3176 
3177  if (boundinfo->indexes[offset + 1] < 0)
3178  {
3179  /*
3180  * Check that the new partition will fit in the gap.
3181  * For it to fit, the new upper bound must be less
3182  * than or equal to the lower bound of the next
3183  * partition, if there is one.
3184  */
3185  if (offset + 1 < boundinfo->ndatums)
3186  {
3187  Datum *datums;
3189  bool is_lower;
3190 
3191  datums = boundinfo->datums[offset + 1];
3192  kind = boundinfo->kind[offset + 1];
3193  is_lower = (boundinfo->indexes[offset + 1] == -1);
3194 
3195  cmpval = partition_rbound_cmp(key->partnatts,
3196  key->partsupfunc,
3197  key->partcollation,
3198  datums, kind,
3199  is_lower, upper);
3200  if (cmpval < 0)
3201  {
3202  /*
3203  * Point to problematic key in the upper
3204  * datums list.
3205  */
3206  PartitionRangeDatum *datum =
3207  list_nth(spec->upperdatums, Abs(cmpval) - 1);
3208 
3209  /*
3210  * The new partition overlaps with the
3211  * existing partition between offset + 1 and
3212  * offset + 2.
3213  */
3214  overlap = true;
3215  overlap_location = datum->location;
3216  with = boundinfo->indexes[offset + 2];
3217  }
3218  }
3219  }
3220  else
3221  {
3222  /*
3223  * The new partition overlaps with the existing
3224  * partition between offset and offset + 1.
3225  */
3226  PartitionRangeDatum *datum;
3227 
3228  /*
3229  * Point to problematic key in the lower datums list;
3230  * if we have equality, point to the first one.
3231  */
3232  datum = cmpval == 0 ? linitial(spec->lowerdatums) :
3233  list_nth(spec->lowerdatums, Abs(cmpval) - 1);
3234  overlap = true;
3235  overlap_location = datum->location;
3236  with = boundinfo->indexes[offset + 1];
3237  }
3238  }
3239 
3240  break;
3241  }
3242 
3243  default:
3244  elog(ERROR, "unexpected partition strategy: %d",
3245  (int) key->strategy);
3246  }
3247 
3248  if (overlap)
3249  {
3250  Assert(with >= 0);
3251  ereport(ERROR,
3252  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
3253  errmsg("partition \"%s\" would overlap partition \"%s\"",
3254  relname, get_rel_name(partdesc->oids[with])),
3255  parser_errposition(pstate, overlap_location)));
3256  }
3257 }
3258 
3259 /*
3260  * check_default_partition_contents
3261  *
3262  * This function checks if there exists a row in the default partition that
3263  * would properly belong to the new partition being added. If it finds one,
3264  * it throws an error.
3265  */
3266 void
3268  PartitionBoundSpec *new_spec)
3269 {
3270  List *new_part_constraints;
3271  List *def_part_constraints;
3272  List *all_parts;
3273  ListCell *lc;
3274 
3275  new_part_constraints = (new_spec->strategy == PARTITION_STRATEGY_LIST)
3276  ? get_qual_for_list(parent, new_spec)
3277  : get_qual_for_range(parent, new_spec, false);
3278  def_part_constraints =
3279  get_proposed_default_constraint(new_part_constraints);
3280 
3281  /*
3282  * Map the Vars in the constraint expression from parent's attnos to
3283  * default_rel's.
3284  */
3285  def_part_constraints =
3286  map_partition_varattnos(def_part_constraints, 1, default_rel,
3287  parent);
3288 
3289  /*
3290  * If the existing constraints on the default partition imply that it will
3291  * not contain any row that would belong to the new partition, we can
3292  * avoid scanning the default partition.
3293  */
3294  if (PartConstraintImpliedByRelConstraint(default_rel, def_part_constraints))
3295  {
3296  ereport(DEBUG1,
3297  (errmsg_internal("updated partition constraint for default partition \"%s\" is implied by existing constraints",
3298  RelationGetRelationName(default_rel))));
3299  return;
3300  }
3301 
3302  /*
3303  * Scan the default partition and its subpartitions, and check for rows
3304  * that do not satisfy the revised partition constraints.
3305  */
3306  if (default_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
3307  all_parts = find_all_inheritors(RelationGetRelid(default_rel),
3308  AccessExclusiveLock, NULL);
3309  else
3310  all_parts = list_make1_oid(RelationGetRelid(default_rel));
3311 
3312  foreach(lc, all_parts)
3313  {
3314  Oid part_relid = lfirst_oid(lc);
3315  Relation part_rel;
3316  Expr *partition_constraint;
3317  EState *estate;
3318  ExprState *partqualstate = NULL;
3319  Snapshot snapshot;
3320  ExprContext *econtext;
3321  TableScanDesc scan;
3322  MemoryContext oldCxt;
3323  TupleTableSlot *tupslot;
3324 
3325  /* Lock already taken above. */
3326  if (part_relid != RelationGetRelid(default_rel))
3327  {
3328  part_rel = table_open(part_relid, NoLock);
3329 
3330  /*
3331  * Map the Vars in the constraint expression from default_rel's
3332  * the sub-partition's.
3333  */
3334  partition_constraint = make_ands_explicit(def_part_constraints);
3335  partition_constraint = (Expr *)
3336  map_partition_varattnos((List *) partition_constraint, 1,
3337  part_rel, default_rel);
3338 
3339  /*
3340  * If the partition constraints on default partition child imply
3341  * that it will not contain any row that would belong to the new
3342  * partition, we can avoid scanning the child table.
3343  */
3345  def_part_constraints))
3346  {
3347  ereport(DEBUG1,
3348  (errmsg_internal("updated partition constraint for default partition \"%s\" is implied by existing constraints",
3349  RelationGetRelationName(part_rel))));
3350 
3351  table_close(part_rel, NoLock);
3352  continue;
3353  }
3354  }
3355  else
3356  {
3357  part_rel = default_rel;
3358  partition_constraint = make_ands_explicit(def_part_constraints);
3359  }
3360 
3361  /*
3362  * Only RELKIND_RELATION relations (i.e. leaf partitions) need to be
3363  * scanned.
3364  */
3365  if (part_rel->rd_rel->relkind != RELKIND_RELATION)
3366  {
3367  if (part_rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
3368  ereport(WARNING,
3369  (errcode(ERRCODE_CHECK_VIOLATION),
3370  errmsg("skipped scanning foreign table \"%s\" which is a partition of default partition \"%s\"",
3371  RelationGetRelationName(part_rel),
3372  RelationGetRelationName(default_rel))));
3373 
3374  if (RelationGetRelid(default_rel) != RelationGetRelid(part_rel))
3375  table_close(part_rel, NoLock);
3376 
3377  continue;
3378  }
3379 
3380  estate = CreateExecutorState();
3381 
3382  /* Build expression execution states for partition check quals */
3383  partqualstate = ExecPrepareExpr(partition_constraint, estate);
3384 
3385  econtext = GetPerTupleExprContext(estate);
3386  snapshot = RegisterSnapshot(GetLatestSnapshot());
3387  tupslot = table_slot_create(part_rel, &estate->es_tupleTable);
3388  scan = table_beginscan(part_rel, snapshot, 0, NULL);
3389 
3390  /*
3391  * Switch to per-tuple memory context and reset it for each tuple
3392  * produced, so we don't leak memory.
3393  */
3395 
3396  while (table_scan_getnextslot(scan, ForwardScanDirection, tupslot))
3397  {
3398  econtext->ecxt_scantuple = tupslot;
3399 
3400  if (!ExecCheck(partqualstate, econtext))
3401  ereport(ERROR,
3402  (errcode(ERRCODE_CHECK_VIOLATION),
3403  errmsg("updated partition constraint for default partition \"%s\" would be violated by some row",
3404  RelationGetRelationName(default_rel)),
3405  errtable(default_rel)));
3406 
3407  ResetExprContext(econtext);
3409  }
3410 
3411  MemoryContextSwitchTo(oldCxt);
3412  table_endscan(scan);
3413  UnregisterSnapshot(snapshot);
3415  FreeExecutorState(estate);
3416 
3417  if (RelationGetRelid(default_rel) != RelationGetRelid(part_rel))
3418  table_close(part_rel, NoLock); /* keep the lock until commit */
3419  }
3420 }
3421 
3422 /*
3423  * get_hash_partition_greatest_modulus
3424  *
3425  * Returns the greatest modulus of the hash partition bound.
3426  * This is no longer used in the core code, but we keep it around
3427  * in case external modules are using it.
3428  */
3429 int
3431 {
3432  Assert(bound && bound->strategy == PARTITION_STRATEGY_HASH);
3433  return bound->nindexes;
3434 }
3435 
3436 /*
3437  * make_one_partition_rbound
3438  *
3439  * Return a PartitionRangeBound given a list of PartitionRangeDatum elements
3440  * and a flag telling whether the bound is lower or not. Made into a function
3441  * because there are multiple sites that want to use this facility.
3442  */
3443 static PartitionRangeBound *
3445 {
3446  PartitionRangeBound *bound;
3447  ListCell *lc;
3448  int i;
3449 
3450  Assert(datums != NIL);
3451 
3452  bound = (PartitionRangeBound *) palloc0(sizeof(PartitionRangeBound));
3453  bound->index = index;
3454  bound->datums = (Datum *) palloc0(key->partnatts * sizeof(Datum));
3455  bound->kind = (PartitionRangeDatumKind *) palloc0(key->partnatts *
3456  sizeof(PartitionRangeDatumKind));
3457  bound->lower = lower;
3458 
3459  i = 0;
3460  foreach(lc, datums)
3461  {
3463 
3464  /* What's contained in this range datum? */
3465  bound->kind[i] = datum->kind;
3466 
3467  if (datum->kind == PARTITION_RANGE_DATUM_VALUE)
3468  {
3469  Const *val = castNode(Const, datum->value);
3470 
3471  if (val->constisnull)
3472  elog(ERROR, "invalid range bound datum");
3473  bound->datums[i] = val->constvalue;
3474  }
3475 
3476  i++;
3477  }
3478 
3479  return bound;
3480 }
3481 
3482 /*
3483  * partition_rbound_cmp
3484  *
3485  * For two range bounds this decides whether the 1st one (specified by
3486  * datums1, kind1, and lower1) is <, =, or > the bound specified in *b2.
3487  *
3488  * 0 is returned if they are equal, otherwise a non-zero integer whose sign
3489  * indicates the ordering, and whose absolute value gives the 1-based
3490  * partition key number of the first mismatching column.
3491  *
3492  * partnatts, partsupfunc and partcollation give the number of attributes in the
3493  * bounds to be compared, comparison function to be used and the collations of
3494  * attributes, respectively.
3495  *
3496  * Note that if the values of the two range bounds compare equal, then we take
3497  * into account whether they are upper or lower bounds, and an upper bound is
3498  * considered to be smaller than a lower bound. This is important to the way
3499  * that RelationBuildPartitionDesc() builds the PartitionBoundInfoData
3500  * structure, which only stores the upper bound of a common boundary between
3501  * two contiguous partitions.
3502  */
3503 static int32
3504 partition_rbound_cmp(int partnatts, FmgrInfo *partsupfunc,
3505  Oid *partcollation,
3506  Datum *datums1, PartitionRangeDatumKind *kind1,
3507  bool lower1, PartitionRangeBound *b2)
3508 {
3509  int32 colnum = 0;
3510  int32 cmpval = 0; /* placate compiler */
3511  int i;
3512  Datum *datums2 = b2->datums;
3513  PartitionRangeDatumKind *kind2 = b2->kind;
3514  bool lower2 = b2->lower;
3515 
3516  for (i = 0; i < partnatts; i++)
3517  {
3518  /* Track column number in case we need it for result */
3519  colnum++;
3520 
3521  /*
3522  * First, handle cases where the column is unbounded, which should not
3523  * invoke the comparison procedure, and should not consider any later
3524  * columns. Note that the PartitionRangeDatumKind enum elements
3525  * compare the same way as the values they represent.
3526  */
3527  if (kind1[i] < kind2[i])
3528  return -colnum;
3529  else if (kind1[i] > kind2[i])
3530  return colnum;
3531  else if (kind1[i] != PARTITION_RANGE_DATUM_VALUE)
3532  {
3533  /*
3534  * The column bounds are both MINVALUE or both MAXVALUE. No later
3535  * columns should be considered, but we still need to compare
3536  * whether they are upper or lower bounds.
3537  */
3538  break;
3539  }
3540 
3541  cmpval = DatumGetInt32(FunctionCall2Coll(&partsupfunc[i],
3542  partcollation[i],
3543  datums1[i],
3544  datums2[i]));
3545  if (cmpval != 0)
3546  break;
3547  }
3548 
3549  /*
3550  * If the comparison is anything other than equal, we're done. If they
3551  * compare equal though, we still have to consider whether the boundaries
3552  * are inclusive or exclusive. Exclusive one is considered smaller of the
3553  * two.
3554  */
3555  if (cmpval == 0 && lower1 != lower2)
3556  cmpval = lower1 ? 1 : -1;
3557 
3558  return cmpval == 0 ? 0 : (cmpval < 0 ? -colnum : colnum);
3559 }
3560 
3561 /*
3562  * partition_rbound_datum_cmp
3563  *
3564  * Return whether range bound (specified in rb_datums and rb_kind)
3565  * is <, =, or > partition key of tuple (tuple_datums)
3566  *
3567  * n_tuple_datums, partsupfunc and partcollation give number of attributes in
3568  * the bounds to be compared, comparison function to be used and the collations
3569  * of attributes resp.
3570  */
3571 int32
3572 partition_rbound_datum_cmp(FmgrInfo *partsupfunc, Oid *partcollation,
3573  Datum *rb_datums, PartitionRangeDatumKind *rb_kind,
3574  Datum *tuple_datums, int n_tuple_datums)
3575 {
3576  int i;
3577  int32 cmpval = -1;
3578 
3579  for (i = 0; i < n_tuple_datums; i++)
3580  {
3581  if (rb_kind[i] == PARTITION_RANGE_DATUM_MINVALUE)
3582  return -1;
3583  else if (rb_kind[i] == PARTITION_RANGE_DATUM_MAXVALUE)
3584  return 1;
3585 
3586  cmpval = DatumGetInt32(FunctionCall2Coll(&partsupfunc[i],
3587  partcollation[i],
3588  rb_datums[i],
3589  tuple_datums[i]));
3590  if (cmpval != 0)
3591  break;
3592  }
3593 
3594  return cmpval;
3595 }
3596 
3597 /*
3598  * partition_hbound_cmp
3599  *
3600  * Compares modulus first, then remainder if modulus is equal.
3601  */
3602 static int32
3603 partition_hbound_cmp(int modulus1, int remainder1, int modulus2, int remainder2)
3604 {
3605  if (modulus1 < modulus2)
3606  return -1;
3607  if (modulus1 > modulus2)
3608  return 1;
3609  if (modulus1 == modulus2 && remainder1 != remainder2)
3610  return (remainder1 > remainder2) ? 1 : -1;
3611  return 0;
3612 }
3613 
3614 /*
3615  * partition_list_bsearch
3616  * Returns the index of the greatest bound datum that is less than equal
3617  * to the given value or -1 if all of the bound datums are greater
3618  *
3619  * *is_equal is set to true if the bound datum at the returned index is equal
3620  * to the input value.
3621  */
3622 int
3623 partition_list_bsearch(FmgrInfo *partsupfunc, Oid *partcollation,
3624  PartitionBoundInfo boundinfo,
3625  Datum value, bool *is_equal)
3626 {
3627  int lo,
3628  hi,
3629  mid;
3630 
3631  lo = -1;
3632  hi = boundinfo->ndatums - 1;
3633  while (lo < hi)
3634  {
3635  int32 cmpval;
3636 
3637  mid = (lo + hi + 1) / 2;
3638  cmpval = DatumGetInt32(FunctionCall2Coll(&partsupfunc[0],
3639  partcollation[0],
3640  boundinfo->datums[mid][0],
3641  value));
3642  if (cmpval <= 0)
3643  {
3644  lo = mid;
3645  *is_equal = (cmpval == 0);
3646  if (*is_equal)
3647  break;
3648  }
3649  else
3650  hi = mid - 1;
3651  }
3652 
3653  return lo;
3654 }
3655 
3656 /*
3657  * partition_range_bsearch
3658  * Returns the index of the greatest range bound that is less than or
3659  * equal to the given range bound or -1 if all of the range bounds are
3660  * greater
3661  *
3662  * Upon return from this function, *cmpval is set to 0 if the bound at the
3663  * returned index matches the input range bound exactly, otherwise a
3664  * non-zero integer whose sign indicates the ordering, and whose absolute
3665  * value gives the 1-based partition key number of the first mismatching
3666  * column.
3667  */
3668 static int
3669 partition_range_bsearch(int partnatts, FmgrInfo *partsupfunc,
3670  Oid *partcollation,
3671  PartitionBoundInfo boundinfo,
3672  PartitionRangeBound *probe, int32 *cmpval)
3673 {
3674  int lo,
3675  hi,
3676  mid;
3677 
3678  lo = -1;
3679  hi = boundinfo->ndatums - 1;
3680  while (lo < hi)
3681  {
3682  mid = (lo + hi + 1) / 2;
3683  *cmpval = partition_rbound_cmp(partnatts, partsupfunc,
3684  partcollation,
3685  boundinfo->datums[mid],
3686  boundinfo->kind[mid],
3687  (boundinfo->indexes[mid] == -1),
3688  probe);
3689  if (*cmpval <= 0)
3690  {
3691  lo = mid;
3692  if (*cmpval == 0)
3693  break;
3694  }
3695  else
3696  hi = mid - 1;
3697  }
3698 
3699  return lo;
3700 }
3701 
3702 /*
3703  * partition_range_datum_bsearch
3704  * Returns the index of the greatest range bound that is less than or
3705  * equal to the given tuple or -1 if all of the range bounds are greater
3706  *
3707  * *is_equal is set to true if the range bound at the returned index is equal
3708  * to the input tuple.
3709  */
3710 int
3711 partition_range_datum_bsearch(FmgrInfo *partsupfunc, Oid *partcollation,
3712  PartitionBoundInfo boundinfo,
3713  int nvalues, Datum *values, bool *is_equal)
3714 {
3715  int lo,
3716  hi,
3717  mid;
3718 
3719  lo = -1;
3720  hi = boundinfo->ndatums - 1;
3721  while (lo < hi)
3722  {
3723  int32 cmpval;
3724 
3725  mid = (lo + hi + 1) / 2;
3726  cmpval = partition_rbound_datum_cmp(partsupfunc,
3727  partcollation,
3728  boundinfo->datums[mid],
3729  boundinfo->kind[mid],
3730  values,
3731  nvalues);
3732  if (cmpval <= 0)
3733  {
3734  lo = mid;
3735  *is_equal = (cmpval == 0);
3736 
3737  if (*is_equal)
3738  break;
3739  }
3740  else
3741  hi = mid - 1;
3742  }
3743 
3744  return lo;
3745 }
3746 
3747 /*
3748  * partition_hash_bsearch
3749  * Returns the index of the greatest (modulus, remainder) pair that is
3750  * less than or equal to the given (modulus, remainder) pair or -1 if
3751  * all of them are greater
3752  */
3753 int
3755  int modulus, int remainder)
3756 {
3757  int lo,
3758  hi,
3759  mid;
3760 
3761  lo = -1;
3762  hi = boundinfo->ndatums - 1;
3763  while (lo < hi)
3764  {
3765  int32 cmpval,
3766  bound_modulus,
3767  bound_remainder;
3768 
3769  mid = (lo + hi + 1) / 2;
3770  bound_modulus = DatumGetInt32(boundinfo->datums[mid][0]);
3771  bound_remainder = DatumGetInt32(boundinfo->datums[mid][1]);
3772  cmpval = partition_hbound_cmp(bound_modulus, bound_remainder,
3773  modulus, remainder);
3774  if (cmpval <= 0)
3775  {
3776  lo = mid;
3777 
3778  if (cmpval == 0)
3779  break;
3780  }
3781  else
3782  hi = mid - 1;
3783  }
3784 
3785  return lo;
3786 }
3787 
3788 /*
3789  * qsort_partition_hbound_cmp
3790  *
3791  * Hash bounds are sorted by modulus, then by remainder.
3792  */
3793 static int32
3794 qsort_partition_hbound_cmp(const void *a, const void *b)
3795 {
3796  PartitionHashBound *const h1 = (PartitionHashBound *const) a;
3797  PartitionHashBound *const h2 = (PartitionHashBound *const) b;
3798 
3799  return partition_hbound_cmp(h1->modulus, h1->remainder,
3800  h2->modulus, h2->remainder);
3801 }
3802 
3803 /*
3804  * qsort_partition_list_value_cmp
3805  *
3806  * Compare two list partition bound datums.
3807  */
3808 static int32
3809 qsort_partition_list_value_cmp(const void *a, const void *b, void *arg)
3810 {
3811  Datum val1 = ((PartitionListValue *const) a)->value,
3812  val2 = ((PartitionListValue *const) b)->value;
3813  PartitionKey key = (PartitionKey) arg;
3814 
3816  key->partcollation[0],
3817  val1, val2));
3818 }
3819 
3820 /*
3821  * qsort_partition_rbound_cmp
3822  *
3823  * Used when sorting range bounds across all range partitions.
3824  */
3825 static int32
3826 qsort_partition_rbound_cmp(const void *a, const void *b, void *arg)
3827 {
3828  PartitionRangeBound *b1 = (*(PartitionRangeBound *const *) a);
3829  PartitionRangeBound *b2 = (*(PartitionRangeBound *const *) b);
3830  PartitionKey key = (PartitionKey) arg;
3831 
3832  return compare_range_bounds(key->partnatts, key->partsupfunc,
3833  key->partcollation,
3834  b1, b2);
3835 }
3836 
3837 /*
3838  * get_partition_operator
3839  *
3840  * Return oid of the operator of the given strategy for the given partition
3841  * key column. It is assumed that the partitioning key is of the same type as
3842  * the chosen partitioning opclass, or at least binary-compatible. In the
3843  * latter case, *need_relabel is set to true if the opclass is not of a
3844  * polymorphic type (indicating a RelabelType node needed on top), otherwise
3845  * false.
3846  */
3847 static Oid
3849  bool *need_relabel)
3850 {
3851  Oid operoid;
3852 
3853  /*
3854  * Get the operator in the partitioning opfamily using the opclass'
3855  * declared input type as both left- and righttype.
3856  */
3857  operoid = get_opfamily_member(key->partopfamily[col],
3858  key->partopcintype[col],
3859  key->partopcintype[col],
3860  strategy);
3861  if (!OidIsValid(operoid))
3862  elog(ERROR, "missing operator %d(%u,%u) in partition opfamily %u",
3863  strategy, key->partopcintype[col], key->partopcintype[col],
3864  key->partopfamily[col]);
3865 
3866  /*
3867  * If the partition key column is not of the same type as the operator
3868  * class and not polymorphic, tell caller to wrap the non-Const expression
3869  * in a RelabelType. This matches what parse_coerce.c does.
3870  */
3871  *need_relabel = (key->parttypid[col] != key->partopcintype[col] &&
3872  key->partopcintype[col] != RECORDOID &&
3873  !IsPolymorphicType(key->partopcintype[col]));
3874 
3875  return operoid;
3876 }
3877 
3878 /*
3879  * make_partition_op_expr
3880  * Returns an Expr for the given partition key column with arg1 and
3881  * arg2 as its leftop and rightop, respectively
3882  */
3883 static Expr *
3885  uint16 strategy, Expr *arg1, Expr *arg2)
3886 {
3887  Oid operoid;
3888  bool need_relabel = false;
3889  Expr *result = NULL;
3890 
3891  /* Get the correct btree operator for this partitioning column */
3892  operoid = get_partition_operator(key, keynum, strategy, &need_relabel);
3893 
3894  /*
3895  * Chosen operator may be such that the non-Const operand needs to be
3896  * coerced, so apply the same; see the comment in
3897  * get_partition_operator().
3898  */
3899  if (!IsA(arg1, Const) &&
3900  (need_relabel ||
3901  key->partcollation[keynum] != key->parttypcoll[keynum]))
3902  arg1 = (Expr *) makeRelabelType(arg1,
3903  key->partopcintype[keynum],
3904  -1,
3905  key->partcollation[keynum],
3907 
3908  /* Generate the actual expression */
3909  switch (key->strategy)
3910  {
3912  {
3913  List *elems = (List *) arg2;
3914  int nelems = list_length(elems);
3915 
3916  Assert(nelems >= 1);
3917  Assert(keynum == 0);
3918 
3919  if (nelems > 1 &&
3920  !type_is_array(key->parttypid[keynum]))
3921  {
3922  ArrayExpr *arrexpr;
3923  ScalarArrayOpExpr *saopexpr;
3924 
3925  /* Construct an ArrayExpr for the right-hand inputs */
3926  arrexpr = makeNode(ArrayExpr);
3927  arrexpr->array_typeid =
3928  get_array_type(key->parttypid[keynum]);
3929  arrexpr->array_collid = key->parttypcoll[keynum];
3930  arrexpr->element_typeid = key->parttypid[keynum];
3931  arrexpr->elements = elems;
3932  arrexpr->multidims = false;
3933  arrexpr->location = -1;
3934 
3935  /* Build leftop = ANY (rightop) */
3936  saopexpr = makeNode(ScalarArrayOpExpr);
3937  saopexpr->opno = operoid;
3938  saopexpr->opfuncid = get_opcode(operoid);
3939  saopexpr->hashfuncid = InvalidOid;
3940  saopexpr->negfuncid = InvalidOid;
3941  saopexpr->useOr = true;
3942  saopexpr->inputcollid = key->partcollation[keynum];
3943  saopexpr->args = list_make2(arg1, arrexpr);
3944  saopexpr->location = -1;
3945 
3946  result = (Expr *) saopexpr;
3947  }
3948  else
3949  {
3950  List *elemops = NIL;
3951  ListCell *lc;
3952 
3953  foreach(lc, elems)
3954  {
3955  Expr *elem = lfirst(lc),
3956  *elemop;
3957 
3958  elemop = make_opclause(operoid,
3959  BOOLOID,
3960  false,
3961  arg1, elem,
3962  InvalidOid,
3963  key->partcollation[keynum]);
3964  elemops = lappend(elemops, elemop);
3965  }
3966 
3967  result = nelems > 1 ? makeBoolExpr(OR_EXPR, elemops, -1) : linitial(elemops);
3968  }
3969  break;
3970  }
3971 
3973  result = make_opclause(operoid,
3974  BOOLOID,
3975  false,
3976  arg1, arg2,
3977  InvalidOid,
3978  key->partcollation[keynum]);
3979  break;
3980 
3981  default:
3982  elog(ERROR, "invalid partitioning strategy");
3983  break;
3984  }
3985 
3986  return result;
3987 }
3988 
3989 /*
3990  * get_qual_for_hash
3991  *
3992  * Returns a CHECK constraint expression to use as a hash partition's
3993  * constraint, given the parent relation and partition bound structure.
3994  *
3995  * The partition constraint for a hash partition is always a call to the
3996  * built-in function satisfies_hash_partition().
3997  */
3998 static List *
4000 {
4002  FuncExpr *fexpr;
4003  Node *relidConst;
4004  Node *modulusConst;
4005  Node *remainderConst;
4006  List *args;
4007  ListCell *partexprs_item;
4008  int i;
4009 
4010  /* Fixed arguments. */
4011  relidConst = (Node *) makeConst(OIDOID,
4012  -1,
4013  InvalidOid,
4014  sizeof(Oid),
4016  false,
4017  true);
4018 
4019  modulusConst = (Node *) makeConst(INT4OID,
4020  -1,
4021  InvalidOid,
4022  sizeof(int32),
4023  Int32GetDatum(spec->modulus),
4024  false,
4025  true);
4026 
4027  remainderConst = (Node *) makeConst(INT4OID,
4028  -1,
4029  InvalidOid,
4030  sizeof(int32),
4031  Int32GetDatum(spec->remainder),
4032  false,
4033  true);
4034 
4035  args = list_make3(relidConst, modulusConst, remainderConst);
4036  partexprs_item = list_head(key->partexprs);
4037 
4038  /* Add an argument for each key column. */
4039  for (i = 0; i < key->partnatts; i++)
4040  {
4041  Node *keyCol;
4042 
4043  /* Left operand */
4044  if (key->partattrs[i] != 0)
4045  {
4046  keyCol = (Node *) makeVar(1,
4047  key->partattrs[i],
4048  key->parttypid[i],
4049  key->parttypmod[i],
4050  key->parttypcoll[i],
4051  0);
4052  }
4053  else
4054  {
4055  keyCol = (Node *) copyObject(lfirst(partexprs_item));
4056  partexprs_item = lnext(key->partexprs, partexprs_item);
4057  }
4058 
4059  args = lappend(args, keyCol);
4060  }
4061 
4062  fexpr = makeFuncExpr(F_SATISFIES_HASH_PARTITION,
4063  BOOLOID,
4064  args,
4065  InvalidOid,
4066  InvalidOid,
4068 
4069  return list_make1(fexpr);
4070 }
4071 
4072 /*
4073  * get_qual_for_list
4074  *
4075  * Returns an implicit-AND list of expressions to use as a list partition's
4076  * constraint, given the parent relation and partition bound structure.
4077  *
4078  * The function returns NIL for a default partition when it's the only
4079  * partition since in that case there is no constraint.
4080  */
4081 static List *
4083 {
4085  List *result;
4086  Expr *keyCol;
4087  Expr *opexpr;
4088  NullTest *nulltest;
4089  ListCell *cell;
4090  List *elems = NIL;
4091  bool list_has_null = false;
4092 
4093  /*
4094  * Only single-column list partitioning is supported, so we are worried
4095  * only about the partition key with index 0.
4096  */
4097  Assert(key->partnatts == 1);
4098 
4099  /* Construct Var or expression representing the partition column */
4100  if (key->partattrs[0] != 0)
4101  keyCol = (Expr *) makeVar(1,
4102  key->partattrs[0],
4103  key->parttypid[0],
4104  key->parttypmod[0],
4105  key->parttypcoll[0],
4106  0);
4107  else
4108  keyCol = (Expr *) copyObject(linitial(key->partexprs));
4109 
4110  /*
4111  * For default list partition, collect datums for all the partitions. The
4112  * default partition constraint should check that the partition key is
4113  * equal to none of those.
4114  */
4115  if (spec->is_default)
4116  {
4117  int i;
4118  int ndatums = 0;
4119  PartitionDesc pdesc = RelationGetPartitionDesc(parent, false);
4120  PartitionBoundInfo boundinfo = pdesc->boundinfo;
4121 
4122  if (boundinfo)
4123  {
4124  ndatums = boundinfo->ndatums;
4125 
4126  if (partition_bound_accepts_nulls(boundinfo))
4127  list_has_null = true;
4128  }
4129 
4130  /*
4131  * If default is the only partition, there need not be any partition
4132  * constraint on it.
4133  */
4134  if (ndatums == 0 && !list_has_null)
4135  return NIL;
4136 
4137  for (i = 0; i < ndatums; i++)
4138  {
4139  Const *val;
4140 
4141  /*
4142  * Construct Const from known-not-null datum. We must be careful
4143  * to copy the value, because our result has to be able to outlive
4144  * the relcache entry we're copying from.
4145  */
4146  val = makeConst(key->parttypid[0],
4147  key->parttypmod[0],
4148  key->parttypcoll[0],
4149  key->parttyplen[0],
4150  datumCopy(*boundinfo->datums[i],
4151  key->parttypbyval[0],
4152  key->parttyplen[0]),
4153  false, /* isnull */
4154  key->parttypbyval[0]);
4155 
4156  elems = lappend(elems, val);
4157  }
4158  }
4159  else
4160  {
4161  /*
4162  * Create list of Consts for the allowed values, excluding any nulls.
4163  */
4164  foreach(cell, spec->listdatums)
4165  {
4166  Const *val = lfirst_node(Const, cell);
4167 
4168  if (val->constisnull)
4169  list_has_null = true;
4170  else
4171  elems = lappend(elems, copyObject(val));
4172  }
4173  }
4174 
4175  if (elems)
4176  {
4177  /*
4178  * Generate the operator expression from the non-null partition
4179  * values.
4180  */
4182  keyCol, (Expr *) elems);
4183  }
4184  else
4185  {
4186  /*
4187  * If there are no partition values, we don't need an operator
4188  * expression.
4189  */
4190  opexpr = NULL;
4191  }
4192 
4193  if (!list_has_null)
4194  {
4195  /*
4196  * Gin up a "col IS NOT NULL" test that will be ANDed with the main
4197  * expression. This might seem redundant, but the partition routing
4198  * machinery needs it.
4199  */
4200  nulltest = makeNode(NullTest);
4201  nulltest->arg = keyCol;
4202  nulltest->nulltesttype = IS_NOT_NULL;
4203  nulltest->argisrow = false;
4204  nulltest->location = -1;
4205 
4206  result = opexpr ? list_make2(nulltest, opexpr) : list_make1(nulltest);
4207  }
4208  else
4209  {
4210  /*
4211  * Gin up a "col IS NULL" test that will be OR'd with the main
4212  * expression.
4213  */
4214  nulltest = makeNode(NullTest);
4215  nulltest->arg = keyCol;
4216  nulltest->nulltesttype = IS_NULL;
4217  nulltest->argisrow = false;
4218  nulltest->location = -1;
4219 
4220  if (opexpr)
4221  {
4222  Expr *or;
4223 
4224  or = makeBoolExpr(OR_EXPR, list_make2(nulltest, opexpr), -1);
4225  result = list_make1(or);
4226  }
4227  else
4228  result = list_make1(nulltest);
4229  }
4230 
4231  /*
4232  * Note that, in general, applying NOT to a constraint expression doesn't
4233  * necessarily invert the set of rows it accepts, because NOT (NULL) is
4234  * NULL. However, the partition constraints we construct here never
4235  * evaluate to NULL, so applying NOT works as intended.
4236  */
4237  if (spec->is_default)
4238  {
4239  result = list_make1(make_ands_explicit(result));
4240  result = list_make1(makeBoolExpr(NOT_EXPR, result, -1));
4241  }
4242 
4243  return result;
4244 }
4245 
4246 /*
4247  * get_qual_for_range
4248  *
4249  * Returns an implicit-AND list of expressions to use as a range partition's
4250  * constraint, given the parent relation and partition bound structure.
4251  *
4252  * For a multi-column range partition key, say (a, b, c), with (al, bl, cl)
4253  * as the lower bound tuple and (au, bu, cu) as the upper bound tuple, we
4254  * generate an expression tree of the following form:
4255  *
4256  * (a IS NOT NULL) and (b IS NOT NULL) and (c IS NOT NULL)
4257  * AND
4258  * (a > al OR (a = al AND b > bl) OR (a = al AND b = bl AND c >= cl))
4259  * AND
4260  * (a < au OR (a = au AND b < bu) OR (a = au AND b = bu AND c < cu))
4261  *
4262  * It is often the case that a prefix of lower and upper bound tuples contains
4263  * the same values, for example, (al = au), in which case, we will emit an
4264  * expression tree of the following form:
4265  *
4266  * (a IS NOT NULL) and (b IS NOT NULL) and (c IS NOT NULL)
4267  * AND
4268  * (a = al)
4269  * AND
4270  * (b > bl OR (b = bl AND c >= cl))
4271  * AND
4272  * (b < bu OR (b = bu AND c < cu))
4273  *
4274  * If a bound datum is either MINVALUE or MAXVALUE, these expressions are
4275  * simplified using the fact that any value is greater than MINVALUE and less
4276  * than MAXVALUE. So, for example, if cu = MAXVALUE, c < cu is automatically
4277  * true, and we need not emit any expression for it, and the last line becomes
4278  *
4279  * (b < bu) OR (b = bu), which is simplified to (b <= bu)
4280  *
4281  * In most common cases with only one partition column, say a, the following
4282  * expression tree will be generated: a IS NOT NULL AND a >= al AND a < au
4283  *
4284  * For default partition, it returns the negation of the constraints of all
4285  * the other partitions.
4286  *
4287  * External callers should pass for_default as false; we set it to true only
4288  * when recursing.
4289  */
4290 static List *
4292  bool for_default)
4293 {
4294  List *result = NIL;
4295  ListCell *cell1,
4296  *cell2,
4297  *partexprs_item,
4298  *partexprs_item_saved;
4299  int i,
4300  j;
4301  PartitionRangeDatum *ldatum,
4302  *udatum;
4304  Expr *keyCol;
4305  Const *lower_val,
4306  *upper_val;
4307  List *lower_or_arms,
4308  *upper_or_arms;
4309  int num_or_arms,
4310  current_or_arm;
4311  ListCell *lower_or_start_datum,
4312  *upper_or_start_datum;
4313  bool need_next_lower_arm,
4314  need_next_upper_arm;
4315 
4316  if (spec->is_default)
4317  {
4318  List *or_expr_args = NIL;
4319  PartitionDesc pdesc = RelationGetPartitionDesc(parent, false);
4320  Oid *inhoids = pdesc->oids;
4321  int nparts = pdesc->nparts,
4322  i;
4323 
4324  for (i = 0; i < nparts; i++)
4325  {
4326  Oid inhrelid = inhoids[i];
4327  HeapTuple tuple;
4328  Datum datum;
4329  bool isnull;
4330  PartitionBoundSpec *bspec;
4331 
4332  tuple = SearchSysCache1(RELOID, inhrelid);
4333  if (!HeapTupleIsValid(tuple))
4334  elog(ERROR, "cache lookup failed for relation %u", inhrelid);
4335 
4336  datum = SysCacheGetAttr(RELOID, tuple,
4337  Anum_pg_class_relpartbound,
4338  &isnull);
4339  if (isnull)
4340  elog(ERROR, "null relpartbound for relation %u", inhrelid);
4341 
4342  bspec = (PartitionBoundSpec *)
4344  if (!IsA(bspec, PartitionBoundSpec))
4345  elog(ERROR, "expected PartitionBoundSpec");
4346 
4347  if (!bspec->is_default)
4348  {
4349  List *part_qual;
4350 
4351  part_qual = get_qual_for_range(parent, bspec, true);
4352 
4353  /*
4354  * AND the constraints of the partition and add to
4355  * or_expr_args
4356  */
4357  or_expr_args = lappend(or_expr_args, list_length(part_qual) > 1
4358  ? makeBoolExpr(AND_EXPR, part_qual, -1)
4359  : linitial(part_qual));
4360  }
4361  ReleaseSysCache(tuple);
4362  }
4363 
4364  if (or_expr_args != NIL)
4365  {
4366  Expr *other_parts_constr;
4367 
4368  /*
4369  * Combine the constraints obtained for non-default partitions
4370  * using OR. As requested, each of the OR's args doesn't include
4371  * the NOT NULL test for partition keys (which is to avoid its
4372  * useless repetition). Add the same now.
4373  */
4374  other_parts_constr =
4377  list_length(or_expr_args) > 1
4378  ? makeBoolExpr(OR_EXPR, or_expr_args,
4379  -1)
4380  : linitial(or_expr_args)),
4381  -1);
4382 
4383  /*
4384  * Finally, the default partition contains everything *NOT*
4385  * contained in the non-default partitions.
4386  */
4387  result = list_make1(makeBoolExpr(NOT_EXPR,
4388  list_make1(other_parts_constr), -1));
4389  }
4390 
4391  return result;
4392  }
4393 
4394  /*
4395  * If it is the recursive call for default, we skip the get_range_nulltest
4396  * to avoid accumulating the NullTest on the same keys for each partition.
4397  */
4398  if (!for_default)
4399  result = get_range_nulltest(key);
4400 
4401  /*
4402  * Iterate over the key columns and check if the corresponding lower and
4403  * upper datums are equal using the btree equality operator for the
4404  * column's type. If equal, we emit single keyCol = common_value
4405  * expression. Starting from the first column for which the corresponding
4406  * lower and upper bound datums are not equal, we generate OR expressions
4407  * as shown in the function's header comment.
4408  */
4409  i = 0;
4410  partexprs_item = list_head(key->partexprs);
4411  partexprs_item_saved = partexprs_item; /* placate compiler */
4412  forboth(cell1, spec->lowerdatums, cell2, spec->upperdatums)
4413  {
4414  EState *estate;
4415  MemoryContext oldcxt;
4416  Expr *test_expr;
4417  ExprState *test_exprstate;
4418  Datum test_result;
4419  bool isNull;
4420 
4421  ldatum = lfirst_node(PartitionRangeDatum, cell1);
4422  udatum = lfirst_node(PartitionRangeDatum, cell2);
4423 
4424  /*
4425  * Since get_range_key_properties() modifies partexprs_item, and we
4426  * might need to start over from the previous expression in the later
4427  * part of this function, save away the current value.
4428  */
4429  partexprs_item_saved = partexprs_item;
4430 
4431  get_range_key_properties(key, i, ldatum, udatum,
4432  &partexprs_item,
4433  &keyCol,
4434  &lower_val, &upper_val);
4435 
4436  /*
4437  * If either value is NULL, the corresponding partition bound is
4438  * either MINVALUE or MAXVALUE, and we treat them as unequal, because
4439  * even if they're the same, there is no common value to equate the
4440  * key column with.
4441  */
4442  if (!lower_val || !upper_val)
4443  break;
4444 
4445  /* Create the test expression */
4446  estate = CreateExecutorState();
4447  oldcxt = MemoryContextSwitchTo(estate->es_query_cxt);
4448  test_expr = make_partition_op_expr(key, i, BTEqualStrategyNumber,
4449  (Expr *) lower_val,
4450  (Expr *) upper_val);
4451  fix_opfuncids((Node *) test_expr);
4452  test_exprstate = ExecInitExpr(test_expr, NULL);
4453  test_result = ExecEvalExprSwitchContext(test_exprstate,
4454  GetPerTupleExprContext(estate),
4455  &isNull);
4456  MemoryContextSwitchTo(oldcxt);
4457  FreeExecutorState(estate);
4458 
4459  /* If not equal, go generate the OR expressions */
4460  if (!DatumGetBool(test_result))
4461  break;
4462 
4463  /*
4464  * The bounds for the last key column can't be equal, because such a
4465  * range partition would never be allowed to be defined (it would have
4466  * an empty range otherwise).
4467  */
4468  if (i == key->partnatts - 1)
4469  elog(ERROR, "invalid range bound specification");
4470 
4471  /* Equal, so generate keyCol = lower_val expression */
4472  result = lappend(result,
4474  keyCol, (Expr *) lower_val));
4475 
4476  i++;
4477  }
4478 
4479  /* First pair of lower_val and upper_val that are not equal. */
4480  lower_or_start_datum = cell1;
4481  upper_or_start_datum = cell2;
4482 
4483  /* OR will have as many arms as there are key columns left. */
4484  num_or_arms = key->partnatts - i;
4485  current_or_arm = 0;
4486  lower_or_arms = upper_or_arms = NIL;
4487  need_next_lower_arm = need_next_upper_arm = true;
4488  while (current_or_arm < num_or_arms)
4489  {
4490  List *lower_or_arm_args = NIL,
4491  *upper_or_arm_args = NIL;
4492 
4493  /* Restart scan of columns from the i'th one */
4494  j = i;
4495  partexprs_item = partexprs_item_saved;
4496 
4497  for_both_cell(cell1, spec->lowerdatums, lower_or_start_datum,
4498  cell2, spec->upperdatums, upper_or_start_datum)
4499  {
4500  PartitionRangeDatum *ldatum_next = NULL,
4501  *udatum_next = NULL;
4502 
4503  ldatum = lfirst_node(PartitionRangeDatum, cell1);
4504  if (lnext(spec->lowerdatums, cell1))
4505  ldatum_next = castNode(PartitionRangeDatum,
4506  lfirst(lnext(spec->lowerdatums, cell1)));
4507  udatum = lfirst_node(PartitionRangeDatum, cell2);
4508  if (lnext(spec->upperdatums, cell2))
4509  udatum_next = castNode(PartitionRangeDatum,
4510  lfirst(lnext(spec->upperdatums, cell2)));
4511  get_range_key_properties(key, j, ldatum, udatum,
4512  &partexprs_item,
4513  &keyCol,
4514  &lower_val, &upper_val);
4515 
4516  if (need_next_lower_arm && lower_val)
4517  {
4518  uint16 strategy;
4519 
4520  /*
4521  * For the non-last columns of this arm, use the EQ operator.
4522  * For the last column of this arm, use GT, unless this is the
4523  * last column of the whole bound check, or the next bound
4524  * datum is MINVALUE, in which case use GE.
4525  */
4526  if (j - i < current_or_arm)
4527  strategy = BTEqualStrategyNumber;
4528  else if (j == key->partnatts - 1 ||
4529  (ldatum_next &&
4530  ldatum_next->kind == PARTITION_RANGE_DATUM_MINVALUE))
4531  strategy = BTGreaterEqualStrategyNumber;
4532  else
4533  strategy = BTGreaterStrategyNumber;
4534 
4535  lower_or_arm_args = lappend(lower_or_arm_args,
4536  make_partition_op_expr(key, j,
4537  strategy,
4538  keyCol,
4539  (Expr *) lower_val));
4540  }
4541 
4542  if (need_next_upper_arm && upper_val)
4543  {
4544  uint16 strategy;
4545 
4546  /*
4547  * For the non-last columns of this arm, use the EQ operator.
4548  * For the last column of this arm, use LT, unless the next
4549  * bound datum is MAXVALUE, in which case use LE.
4550  */
4551  if (j - i < current_or_arm)
4552  strategy = BTEqualStrategyNumber;
4553  else if (udatum_next &&
4554  udatum_next->kind == PARTITION_RANGE_DATUM_MAXVALUE)
4555  strategy = BTLessEqualStrategyNumber;
4556  else
4557  strategy = BTLessStrategyNumber;
4558 
4559  upper_or_arm_args = lappend(upper_or_arm_args,
4560  make_partition_op_expr(key, j,
4561  strategy,
4562  keyCol,
4563  (Expr *) upper_val));
4564  }
4565 
4566  /*
4567  * Did we generate enough of OR's arguments? First arm considers
4568  * the first of the remaining columns, second arm considers first
4569  * two of the remaining columns, and so on.
4570  */
4571  ++j;
4572  if (j - i > current_or_arm)
4573  {
4574  /*
4575  * We must not emit any more arms if the new column that will
4576  * be considered is unbounded, or this one was.
4577  */
4578  if (!lower_val || !ldatum_next ||
4579  ldatum_next->kind != PARTITION_RANGE_DATUM_VALUE)
4580  need_next_lower_arm = false;
4581  if (!upper_val || !udatum_next ||
4582  udatum_next->kind != PARTITION_RANGE_DATUM_VALUE)
4583  need_next_upper_arm = false;
4584  break;
4585  }
4586  }
4587 
4588  if (lower_or_arm_args != NIL)
4589  lower_or_arms = lappend(lower_or_arms,
4590  list_length(lower_or_arm_args) > 1
4591  ? makeBoolExpr(AND_EXPR, lower_or_arm_args, -1)
4592  : linitial(lower_or_arm_args));
4593 
4594  if (upper_or_arm_args != NIL)
4595  upper_or_arms = lappend(upper_or_arms,
4596  list_length(upper_or_arm_args) > 1
4597  ? makeBoolExpr(AND_EXPR, upper_or_arm_args, -1)
4598  : linitial(upper_or_arm_args));
4599 
4600  /* If no work to do in the next iteration, break away. */
4601  if (!need_next_lower_arm && !need_next_upper_arm)
4602  break;
4603 
4604  ++current_or_arm;
4605  }
4606 
4607  /*
4608  * Generate the OR expressions for each of lower and upper bounds (if
4609  * required), and append to the list of implicitly ANDed list of
4610  * expressions.
4611  */
4612  if (lower_or_arms != NIL)
4613  result = lappend(result,
4614  list_length(lower_or_arms) > 1
4615  ? makeBoolExpr(OR_EXPR, lower_or_arms, -1)
4616  : linitial(lower_or_arms));
4617  if (upper_or_arms != NIL)
4618  result = lappend(result,
4619  list_length(upper_or_arms) > 1
4620  ? makeBoolExpr(OR_EXPR, upper_or_arms, -1)
4621  : linitial(upper_or_arms));
4622 
4623  /*
4624  * As noted above, for non-default, we return list with constant TRUE. If
4625  * the result is NIL during the recursive call for default, it implies
4626  * this is the only other partition which can hold every value of the key
4627  * except NULL. Hence we return the NullTest result skipped earlier.
4628  */
4629  if (result == NIL)
4630  result = for_default
4631  ? get_range_nulltest(key)
4632  : list_make1(makeBoolConst(true, false));
4633 
4634  return result;
4635 }
4636 
4637 /*
4638  * get_range_key_properties
4639  * Returns range partition key information for a given column
4640  *
4641  * This is a subroutine for get_qual_for_range, and its API is pretty
4642  * specialized to that caller.
4643  *
4644  * Constructs an Expr for the key column (returned in *keyCol) and Consts
4645  * for the lower and upper range limits (returned in *lower_val and
4646  * *upper_val). For MINVALUE/MAXVALUE limits, NULL is returned instead of
4647  * a Const. All of these structures are freshly palloc'd.
4648  *
4649  * *partexprs_item points to the cell containing the next expression in
4650  * the key->partexprs list, or NULL. It may be advanced upon return.
4651  */
4652 static void
4654  PartitionRangeDatum *ldatum,
4655  PartitionRangeDatum *udatum,
4656  ListCell **partexprs_item,
4657  Expr **keyCol,
4658  Const **lower_val, Const **upper_val)
4659 {
4660  /* Get partition key expression for this column */
4661  if (key->partattrs[keynum] != 0)
4662  {
4663  *keyCol = (Expr *) makeVar(1,
4664  key->partattrs[keynum],
4665  key->parttypid[keynum],
4666  key->parttypmod[keynum],
4667  key->parttypcoll[keynum],
4668  0);
4669  }
4670  else
4671  {
4672  if (*partexprs_item == NULL)
4673  elog(ERROR, "wrong number of partition key expressions");
4674  *keyCol = copyObject(lfirst(*partexprs_item));
4675  *partexprs_item = lnext(key->partexprs, *partexprs_item);
4676  }
4677 
4678  /* Get appropriate Const nodes for the bounds */
4679  if (ldatum->kind == PARTITION_RANGE_DATUM_VALUE)
4680  *lower_val = castNode(Const, copyObject(ldatum->value));
4681  else
4682  *lower_val = NULL;
4683 
4684  if (udatum->kind == PARTITION_RANGE_DATUM_VALUE)
4685  *upper_val = castNode(Const, copyObject(udatum->value));
4686  else
4687  *upper_val = NULL;
4688 }
4689 
4690 /*
4691  * get_range_nulltest
4692  *
4693  * A non-default range partition table does not currently allow partition
4694  * keys to be null, so emit an IS NOT NULL expression for each key column.
4695  */
4696 static List *
4698 {
4699  List *result = NIL;
4700  NullTest *nulltest;
4701  ListCell *partexprs_item;
4702  int i;
4703 
4704  partexprs_item = list_head(key->partexprs);
4705  for (i = 0; i < key->partnatts; i++)
4706  {
4707  Expr *keyCol;
4708 
4709  if (key->partattrs[i] != 0)
4710  {
4711  keyCol = (Expr *) makeVar(1,
4712  key->partattrs[i],
4713  key->parttypid[i],
4714  key->parttypmod[i],
4715  key->parttypcoll[i],
4716  0);
4717  }
4718  else
4719  {
4720  if (partexprs_item == NULL)
4721  elog(ERROR, "wrong number of partition key expressions");
4722  keyCol = copyObject(lfirst(partexprs_item));
4723  partexprs_item = lnext(key->partexprs, partexprs_item);
4724  }
4725 
4726  nulltest = makeNode(NullTest);
4727  nulltest->arg = keyCol;
4728  nulltest->nulltesttype = IS_NOT_NULL;
4729  nulltest->argisrow = false;
4730  nulltest->location = -1;
4731  result = lappend(result, nulltest);
4732  }
4733 
4734  return result;
4735 }
4736 
4737 /*
4738  * compute_partition_hash_value
4739  *
4740  * Compute the hash value for given partition key values.
4741  */
4742 uint64
4743 compute_partition_hash_value(int partnatts, FmgrInfo *partsupfunc, Oid *partcollation,
4744  Datum *values, bool *isnull)
4745 {
4746  int i;
4747  uint64 rowHash = 0;
4749 
4750  for (i = 0; i < partnatts; i++)
4751  {
4752  /* Nulls are just ignored */
4753  if (!isnull[i])
4754  {
4755  Datum hash;
4756 
4757  Assert(OidIsValid(partsupfunc[i].fn_oid));
4758 
4759  /*
4760  * Compute hash for each datum value by calling respective
4761  * datatype-specific hash functions of each partition key
4762  * attribute.
4763  */
4764  hash = FunctionCall2Coll(&partsupfunc[i], partcollation[i],
4765  values[i], seed);
4766 
4767  /* Form a single 64-bit hash value */
4768  rowHash = hash_combine64(rowHash, DatumGetUInt64(hash));
4769  }
4770  }
4771 
4772  return rowHash;
4773 }
4774 
4775 /*
4776  * satisfies_hash_partition
4777  *
4778  * This is an SQL-callable function for use in hash partition constraints.
4779  * The first three arguments are the parent table OID, modulus, and remainder.
4780  * The remaining arguments are the value of the partitioning columns (or
4781  * expressions); these are hashed and the results are combined into a single
4782  * hash value by calling hash_combine64.
4783  *
4784  * Returns true if remainder produced when this computed single hash value is
4785  * divided by the given modulus is equal to given remainder, otherwise false.
4786  * NB: it's important that this never return null, as the constraint machinery
4787  * would consider that to be a "pass".
4788  *
4789  * See get_qual_for_hash() for usage.
4790  */
4791 Datum
4793 {
4794  typedef struct ColumnsHashData
4795  {
4796  Oid relid;
4797  int nkeys;
4798  Oid variadic_type;
4799  int16 variadic_typlen;
4800  bool variadic_typbyval;
4801  char variadic_typalign;
4802  Oid partcollid[PARTITION_MAX_KEYS];
4803  FmgrInfo partsupfunc[FLEXIBLE_ARRAY_MEMBER];
4804  } ColumnsHashData;
4805  Oid parentId;
4806  int modulus;
4807  int remainder;
4809  ColumnsHashData *my_extra;
4810  uint64 rowHash = 0;
4811 
4812  /* Return false if the parent OID, modulus, or remainder is NULL. */
4813  if (PG_ARGISNULL(0) || PG_ARGISNULL(1) || PG_ARGISNULL(2))
4814  PG_RETURN_BOOL(false);
4815  parentId = PG_GETARG_OID(0);
4816  modulus = PG_GETARG_INT32(1);
4817  remainder = PG_GETARG_INT32(2);
4818 
4819  /* Sanity check modulus and remainder. */
4820  if (modulus <= 0)
4821  ereport(ERROR,
4822  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4823  errmsg("modulus for hash partition must be an integer value greater than zero")));
4824  if (remainder < 0)
4825  ereport(ERROR,
4826  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4827  errmsg("remainder for hash partition must be an integer value greater than or equal to zero")));
4828  if (remainder >= modulus)
4829  ereport(ERROR,
4830  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4831  errmsg("remainder for hash partition must be less than modulus")));
4832 
4833  /*
4834  * Cache hash function information.
4835  */
4836  my_extra = (ColumnsHashData *) fcinfo->flinfo->fn_extra;
4837  if (my_extra == NULL || my_extra->relid != parentId)
4838  {
4839  Relation parent;
4840  PartitionKey key;
4841  int j;
4842 
4843  /* Open parent relation and fetch partition key info */
4844  parent = relation_open(parentId, AccessShareLock);
4845  key = RelationGetPartitionKey(parent);
4846 
4847  /* Reject parent table that is not hash-partitioned. */
4848  if (key == NULL || key->strategy != PARTITION_STRATEGY_HASH)
4849  ereport(ERROR,
4850  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4851  errmsg("\"%s\" is not a hash partitioned table",
4852  get_rel_name(parentId))));
4853 
4854  if (!get_fn_expr_variadic(fcinfo->flinfo))
4855  {
4856  int nargs = PG_NARGS() - 3;
4857 
4858  /* complain if wrong number of column values */
4859  if (key->partnatts != nargs)
4860  ereport(ERROR,
4861  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4862  errmsg("number of partitioning columns (%d) does not match number of partition keys provided (%d)",
4863  key->partnatts, nargs)));
4864 
4865  /* allocate space for our cache */
4866  fcinfo->flinfo->fn_extra =
4867  MemoryContextAllocZero(fcinfo->flinfo->fn_mcxt,
4868  offsetof(ColumnsHashData, partsupfunc) +
4869  sizeof(FmgrInfo) * nargs);
4870  my_extra = (ColumnsHashData *) fcinfo->flinfo->fn_extra;
4871  my_extra->relid = parentId;
4872  my_extra->nkeys = key->partnatts;
4873  memcpy(my_extra->partcollid, key->partcollation,
4874  key->partnatts * sizeof(Oid));
4875 
4876  /* check argument types and save fmgr_infos */
4877  for (j = 0; j < key->partnatts; ++j)
4878  {
4879  Oid argtype = get_fn_expr_argtype(fcinfo->flinfo, j + 3);
4880 
4881  if (argtype != key->parttypid[j] && !IsBinaryCoercible(argtype, key->parttypid[j]))
4882  ereport(ERROR,
4883  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4884  errmsg("column %d of the partition key has type %s, but supplied value is of type %s",
4885  j + 1, format_type_be(key->parttypid[j]), format_type_be(argtype))));
4886 
4887  fmgr_info_copy(&my_extra->partsupfunc[j],
4888  &key->partsupfunc[j],
4889  fcinfo->flinfo->fn_mcxt);
4890  }
4891  }
4892  else
4893  {
4894  ArrayType *variadic_array = PG_GETARG_ARRAYTYPE_P(3);
4895 
4896  /* allocate space for our cache -- just one FmgrInfo in this case */
4897  fcinfo->flinfo->fn_extra =
4898  MemoryContextAllocZero(fcinfo->flinfo->fn_mcxt,
4899  offsetof(ColumnsHashData, partsupfunc) +
4900  sizeof(FmgrInfo));
4901  my_extra = (ColumnsHashData *) fcinfo->flinfo->fn_extra;
4902  my_extra->relid = parentId;
4903  my_extra->nkeys = key->partnatts;
4904  my_extra->variadic_type = ARR_ELEMTYPE(variadic_array);
4905  get_typlenbyvalalign(my_extra->variadic_type,
4906  &my_extra->variadic_typlen,
4907  &my_extra->variadic_typbyval,
4908  &my_extra->variadic_typalign);
4909  my_extra->partcollid[0] = key->partcollation[0];
4910 
4911  /* check argument types */
4912  for (j = 0; j < key->partnatts; ++j)
4913  if (key->parttypid[j] != my_extra->variadic_type)
4914  ereport(ERROR,
4915  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4916  errmsg("column %d of the partition key has type \"%s\", but supplied value is of type \"%s\"",
4917  j + 1,
4918  format_type_be(key->parttypid[j]),
4919  format_type_be(my_extra->variadic_type))));
4920 
4921  fmgr_info_copy(&my_extra->partsupfunc[0],
4922  &key->partsupfunc[0],
4923  fcinfo->flinfo->fn_mcxt);
4924  }
4925 
4926  /* Hold lock until commit */
4927  relation_close(parent, NoLock);
4928  }
4929 
4930  if (!OidIsValid(my_extra->variadic_type))
4931  {
4932  int nkeys = my_extra->nkeys;
4933  int i;
4934 
4935  /*
4936  * For a non-variadic call, neither the number of arguments nor their
4937  * types can change across calls, so avoid the expense of rechecking
4938  * here.
4939  */
4940 
4941  for (i = 0; i < nkeys; i++)
4942  {
4943  Datum hash;
4944 
4945  /* keys start from fourth argument of function. */
4946  int argno = i + 3;
4947 
4948  if (PG_ARGISNULL(argno))
4949  continue;
4950 
4951  hash = FunctionCall2Coll(&my_extra->partsupfunc[i],
4952  my_extra->partcollid[i],
4953  PG_GETARG_DATUM(argno),
4954  seed);
4955 
4956  /* Form a single 64-bit hash value */
4957  rowHash = hash_combine64(rowHash, DatumGetUInt64(hash));
4958  }
4959  }
4960  else
4961  {
4962  ArrayType *variadic_array = PG_GETARG_ARRAYTYPE_P(3);
4963  int i;
4964  int nelems;
4965  Datum *datum;
4966  bool *isnull;
4967 
4968  deconstruct_array(variadic_array,
4969  my_extra->variadic_type,
4970  my_extra->variadic_typlen,
4971  my_extra->variadic_typbyval,
4972  my_extra->variadic_typalign,
4973  &datum, &isnull, &nelems);
4974 
4975  /* complain if wrong number of column values */
4976  if (nelems != my_extra->nkeys)
4977  ereport(ERROR,
4978  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4979  errmsg("number of partitioning columns (%d) does not match number of partition keys provided (%d)",
4980  my_extra->nkeys, nelems)));
4981 
4982  for (i = 0; i < nelems; i++)
4983  {
4984  Datum hash;
4985 
4986  if (isnull[i])
4987  continue;
4988 
4989  hash = FunctionCall2Coll(&my_extra->partsupfunc[0],
4990  my_extra->partcollid[0],
4991  datum[i],
4992  seed);
4993 
4994  /* Form a single 64-bit hash value */
4995  rowHash = hash_combine64(rowHash, DatumGetUInt64(hash));
4996  }
4997  }
4998 
4999  PG_RETURN_BOOL(rowHash % modulus == remainder);
5000 }
Datum constvalue
Definition: primnodes.h:219
TupleTableSlot * table_slot_create(Relation relation, List **reglist)
Definition: tableam.c:91
#define list_make2(x1, x2)
Definition: pg_list.h:208
#define list_make3(x1, x2, x3)
Definition: pg_list.h:210
signed short int16
Definition: c.h:428
bool did_remapping
Definition: partbounds.c:82
static void generate_matching_part_pairs(RelOptInfo *outer_rel, RelOptInfo *inner_rel, PartitionMap *outer_map, PartitionMap *inner_map, int nmerged, List **outer_parts, List **inner_parts)
Definition: partbounds.c:2450
bool multidims
Definition: primnodes.h:1038
#define NIL
Definition: pg_list.h:65
static void get_merged_range_bounds(int partnatts, FmgrInfo *partsupfuncs, Oid *partcollations, JoinType jointype, PartitionRangeBound *outer_lb, PartitionRangeBound *outer_ub, PartitionRangeBound *inner_lb, PartitionRangeBound *inner_ub, int lb_cmpval, int ub_cmpval, PartitionRangeBound *merged_lb, PartitionRangeBound *merged_ub)
Definition: partbounds.c:2722
#define PG_GETARG_INT32(n)
Definition: fmgr.h:269
Definition: fmgr.h:56
static PartitionBoundInfo merge_list_bounds(FmgrInfo *partsupfunc, Oid *collations, RelOptInfo *outer_rel, RelOptInfo *inner_rel, JoinType jointype, List **outer_parts, List **inner_parts)
Definition: partbounds.c:1209
PartitionRangeDatumKind ** kind
Definition: partbounds.h:84
#define IsA(nodeptr, _type_)
Definition: nodes.h:589
PartitionRangeDatumKind * kind
Definition: partbounds.c:68
static Datum ExecEvalExprSwitchContext(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:331
#define DEBUG1
Definition: elog.h:25
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
#define BTGreaterStrategyNumber
Definition: stratnum.h:33
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:446
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:74
MemoryContext fn_mcxt
Definition: fmgr.h:65
static int32 qsort_partition_hbound_cmp(const void *a, const void *b)
Definition: partbounds.c:3794
List * get_qual_from_partbound(Relation parent, PartitionBoundSpec *spec)
Definition: partbounds.c:249
static PartitionBoundInfo build_merged_partition_bounds(char strategy, List *merged_datums, List *merged_kinds, List *merged_indexes, int null_index, int default_index)
Definition: partbounds.c:2529
Snapshot RegisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:825
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:322
#define DatumGetInt32(X)
Definition: postgres.h:516
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:3161
Oid * partopfamily
Definition: partcache.h:33
Datum lower(PG_FUNCTION_ARGS)
Definition: oracle_compat.c:46
FmgrInfo * partsupfunc
Definition: partcache.h:35
#define castNode(_type_, nodeptr)
Definition: nodes.h:607
static List * get_qual_for_hash(Relation parent, PartitionBoundSpec *spec)
Definition: partbounds.c:3999
PartitionRangeDatumKind
Definition: parsenodes.h:862
void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, char *typalign)
Definition: lsyscache.c:2218
static int merge_matching_partitions(PartitionMap *outer_map, PartitionMap *inner_map, int outer_part, int inner_part, int *next_index)
Definition: partbounds.c:1873
#define PG_GETARG_DATUM(n)
Definition: fmgr.h:268
Oid get_array_type(Oid typid)
Definition: lsyscache.c:2734
void fix_opfuncids(Node *node)
Definition: nodeFuncs.c:1652
#define UInt64GetDatum(X)
Definition: postgres.h:692
Bitmapset * interleaved_parts
Definition: partbounds.h:87
Var * makeVar(int varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:66
bool datumIsEqual(Datum value1, Datum value2, bool typByVal, int typLen)
Definition: datum.c:222
static int process_inner_partition(PartitionMap *outer_map, PartitionMap *inner_map, bool outer_has_default, bool inner_has_default, int inner_index, int outer_default, JoinType jointype, int *next_index, int *default_index)
Definition: partbounds.c:2073
#define llast(l)
Definition: pg_list.h:194
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define IS_OUTER_JOIN(jointype)
Definition: nodes.h:755
PartitionRangeDatumKind kind
Definition: parsenodes.h:873
#define AccessShareLock
Definition: lockdefs.h:36
bool partitions_are_ordered(PartitionBoundInfo boundinfo, Bitmapset *live_parts)
Definition: partbounds.c:2863
#define FLEXIBLE_ARRAY_MEMBER
Definition: c.h:350
Definition: nodes.h:538
struct cursor * cur
Definition: ecpg.c:28
bool get_fn_expr_variadic(FmgrInfo *flinfo)
Definition: fmgr.c:1934
uint16 StrategyNumber
Definition: stratnum.h:22
int errcode(int sqlerrcode)
Definition: elog.c:698
static bool compare_range_partitions(int partnatts, FmgrInfo *partsupfuncs, Oid *partcollations, PartitionRangeBound *outer_lb, PartitionRangeBound *outer_ub, PartitionRangeBound *inner_lb, PartitionRangeBound *inner_ub, int *lb_cmpval, int *ub_cmpval)
Definition: partbounds.c:2673
static List * get_range_nulltest(PartitionKey key)
Definition: partbounds.c:4697
void * stringToNode(const char *str)
Definition: read.c:89
static int32 qsort_partition_rbound_cmp(const void *a, const void *b, void *arg)
Definition: partbounds.c:3826
#define PARTITION_MAX_KEYS
Oid array_typeid
Definition: primnodes.h:1034
char * format_type_be(Oid type_oid)
Definition: format_type.c:339
Datum upper(PG_FUNCTION_ARGS)
Definition: oracle_compat.c:77
List * partexprs
Definition: partcache.h:30
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1148
static bool table_scan_getnextslot(TableScanDesc sscan, ScanDirection direction, TupleTableSlot *slot)
Definition: tableam.h:1032
PartitionKey RelationGetPartitionKey(Relation rel)
Definition: partcache.c:54
struct PartitionRangeBound PartitionRangeBound
Form_pg_class rd_rel
Definition: rel.h:109
NameData relname
Definition: pg_class.h:38
unsigned int Oid
Definition: postgres_ext.h:31
static PartitionBoundInfo merge_range_bounds(int partnatts, FmgrInfo *partsupfuncs, Oid *partcollations, RelOptInfo *outer_rel, RelOptInfo *inner_rel, JoinType jointype, List **outer_parts, List **inner_parts)
Definition: partbounds.c:1517
Const * makeConst(Oid consttype, int32 consttypmod, Oid constcollid, int constlen, Datum constvalue, bool constisnull, bool constbyval)
Definition: makefuncs.c:299
static uint64 hash_combine64(uint64 a, uint64 b)
Definition: hashfn.h:80
#define OidIsValid(objectId)
Definition: c.h:710
static void free_partition_map(PartitionMap *map)
Definition: partbounds.c:1843
ExprState * ExecPrepareExpr(Expr *node, EState *estate)
Definition: execExpr.c:746
Expr * make_opclause(Oid opno, Oid opresulttype, bool opretset, Expr *leftop, Expr *rightop, Oid opcollid, Oid inputcollid)
Definition: makefuncs.c:610
signed int int32
Definition: c.h:429
Expr * makeBoolExpr(BoolExprType boolop, List *args, int location)
Definition: makefuncs.c:369
PartitionBoundInfo boundinfo
Definition: partdesc.h:38
JoinType
Definition: nodes.h:706
#define BTLessEqualStrategyNumber
Definition: stratnum.h:30
static int get_range_partition_internal(PartitionBoundInfo bi, int *lb_pos, PartitionRangeBound *lb, PartitionRangeBound *ub)
Definition: partbounds.c:2613
#define Abs(x)
Definition: c.h:992
Definition: type.h:89
#define list_make1(x1)
Definition: pg_list.h:206
static void add_merged_range_bounds(int partnatts, FmgrInfo *partsupfuncs, Oid *partcollations, PartitionRangeBound *merged_lb, PartitionRangeBound *merged_ub, int merged_index, List **merged_datums, List **merged_kinds, List **merged_indexes)
Definition: partbounds.c:2786
void FreeExecutorState(EState *estate)
Definition: execUtils.c:186
static Expr * make_partition_op_expr(PartitionKey key, int keynum, uint16 strategy, Expr *arg1, Expr *arg2)
Definition: partbounds.c:3884
static void get_range_key_properties(PartitionKey key, int keynum, PartitionRangeDatum *ldatum, PartitionRangeDatum *udatum, ListCell **partexprs_item, Expr **keyCol, Const **lower_val, Const **upper_val)
Definition: partbounds.c:4653
#define GetPerTupleExprContext(estate)
Definition: executor.h:533
static PartitionRangeBound * make_one_partition_rbound(PartitionKey key, int index, List *datums, bool lower)
Definition: partbounds.c:3444
#define PG_GETARG_ARRAYTYPE_P(n)
Definition: array.h:256
int partition_range_datum_bsearch(FmgrInfo *partsupfunc, Oid *partcollation, PartitionBoundInfo boundinfo, int nvalues, Datum *values, bool *is_equal)
Definition: partbounds.c:3711
void check_new_partition_bound(char *relname, Relation parent, PartitionBoundSpec *spec, ParseState *pstate)
Definition: partbounds.c:2908
unsigned short uint16
Definition: c.h:440
void pfree(void *pointer)
Definition: mcxt.c:1169
MemoryContext es_query_cxt
Definition: execnodes.h:601
Oid * parttypcoll
Definition: partcache.h:46
#define linitial(l)
Definition: pg_list.h:174
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
#define ERROR
Definition: elog.h:46
static TableScanDesc table_beginscan(Relation rel, Snapshot snapshot, int nkeys, struct ScanKeyData *key)
Definition: tableam.h:883
#define lfirst_int(lc)
Definition: pg_list.h:170
static void * list_nth(const List *list, int n)
Definition: pg_list.h:278
Oid get_fn_expr_argtype(FmgrInfo *flinfo, int argnum)
Definition: fmgr.c:1800
static int get_non_null_list_datum_count(PartitionBoundSpec **boundspecs, int nparts)
Definition: partbounds.c:445
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
static void fix_merged_indexes(PartitionMap *outer_map, PartitionMap *inner_map, int nmerged, List *merged_indexes)
Definition: partbounds.c:2396
Node * makeBoolConst(bool value, bool isnull)
Definition: makefuncs.c:357
struct PartitionMap PartitionMap
Expr * arg
Definition: primnodes.h:1265
#define IS_DUMMY_REL(r)
Definition: pathnodes.h:1466
void check_default_partition_contents(Relation parent, Relation default_rel, PartitionBoundSpec *new_spec)
Definition: partbounds.c:3267
static PartitionBoundInfo create_hash_bounds(PartitionBoundSpec **boundspecs, int nparts, PartitionKey key, int **mapping)
Definition: partbounds.c:356
void fmgr_info_copy(FmgrInfo *dstinfo, FmgrInfo *srcinfo, MemoryContext destcxt)
Definition: fmgr.c:608
#define lfirst_node(type, lc)
Definition: pg_list.h:172
int get_hash_partition_greatest_modulus(PartitionBoundInfo bound)
Definition: partbounds.c:3430
char * c
static PartitionBoundInfo create_list_bounds(PartitionBoundSpec **boundspecs, int nparts, PartitionKey key, int **mapping)
Definition: partbounds.c:471
#define NoLock
Definition: lockdefs.h:34
int32 partition_rbound_datum_cmp(FmgrInfo *partsupfunc, Oid *partcollation, Datum *rb_datums, PartitionRangeDatumKind *rb_kind, Datum *tuple_datums, int n_tuple_datums)
Definition: partbounds.c:3572
List * get_proposed_default_constraint(List *new_part_constraints)
Definition: partition.c:368
RelabelType * makeRelabelType(Expr *arg, Oid rtype, int32 rtypmod, Oid rcollid, CoercionForm rformat)
Definition: makefuncs.c:402
#define PG_GETARG_OID(n)
Definition: fmgr.h:275
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:1254
PartitionDesc RelationGetPartitionDesc(Relation rel, bool omit_detached)
Definition: partdesc.c:72
int errdetail(const char *fmt,...)
Definition: elog.c:1042
int nparts
Definition: pathnodes.h:761
Oid get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype, int16 strategy)
Definition: lsyscache.c:164
#define DatumGetBool(X)
Definition: postgres.h:437
static int32 partition_hbound_cmp(int modulus1, int remainder1, int modulus2, int remainder2)
Definition: partbounds.c:3603
static int merge_partition_with_dummy(PartitionMap *map, int index, int *next_index)
Definition: partbounds.c:2378
bool * merged
Definition: partbounds.c:80
static bool is_dummy_partition(RelOptInfo *rel, int part_index)
Definition: partbounds.c:1854
#define RelationGetRelationName(relation)
Definition: rel.h:511
#define partition_bound_has_default(bi)
Definition: partbounds.h:99
static ListCell * list_head(const List *l)
Definition: pg_list.h:125
int partition_hash_bsearch(PartitionBoundInfo boundinfo, int modulus, int remainder)
Definition: partbounds.c:3754
List * elements
Definition: primnodes.h:1037
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:131
EState * CreateExecutorState(void)
Definition: execUtils.c:90
List * lappend_int(List *list, int datum)
Definition: list.c:354
char * get_range_partbound_string(List *bound_datums)
Definition: ruleutils.c:12020
void UnregisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:867
bool IsBinaryCoercible(Oid srctype, Oid targettype)
List * lappend(List *list, void *datum)
Definition: list.c:336
void qsort_arg(void *base, size_t nel, size_t elsize, qsort_arg_comparator cmp, void *arg)
#define WARNING
Definition: elog.h:40
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1150
Oid * partcollation
Definition: partcache.h:38
#define TextDatumGetCString(d)
Definition: builtins.h:87
PartitionBoundInfo partition_bounds_copy(PartitionBoundInfo src, PartitionKey key)
Definition: partbounds.c:1010
int location
Definition: primnodes.h:226
List * es_tupleTable
Definition: execnodes.h:603
void * palloc0(Size size)
Definition: mcxt.c:1093
int location
Definition: primnodes.h:1039
AttrNumber * partattrs
Definition: partcache.h:28
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:359
uintptr_t Datum
Definition: postgres.h:411
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1198
#define for_both_cell(cell1, list1, initcell1, cell2, list2, initcell2)
Definition: pg_list.h:468
Expr * make_ands_explicit(List *andclauses)
Definition: makefuncs.c:708
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1411
#define list_make1_oid(x1)
Definition: pg_list.h:236
static void cleanup(void)
Definition: bootstrap.c:697
struct PartitionBoundInfoData * boundinfo
Definition: pathnodes.h:764
static Oid get_partition_operator(PartitionKey key, int col, StrategyNumber strategy, bool *need_relabel)
Definition: partbounds.c:3848
#define PARTITION_STRATEGY_HASH
Definition: parsenodes.h:826
NullTestType nulltesttype
Definition: primnodes.h:1266
#define partition_bound_accepts_nulls(bi)
Definition: partbounds.h:98
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:906
static void init_partition_map(RelOptInfo *rel, PartitionMap *map)
Definition: partbounds.c:1822
struct PartitionListValue PartitionListValue
int32 * parttypmod
Definition: partcache.h:42
int partition_list_bsearch(FmgrInfo *partsupfunc, Oid *partcollation, PartitionBoundInfo boundinfo, Datum value, bool *is_equal)
Definition: partbounds.c:3623
uint64 compute_partition_hash_value(int partnatts, FmgrInfo *partsupfunc, Oid *partcollation, Datum *values, bool *isnull)
Definition: partbounds.c:4743
#define InvalidOid
Definition: postgres_ext.h:36
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1256
static struct @143 value
#define ereport(elevel,...)
Definition: elog.h:157
static int32 partition_rbound_cmp(int partnatts, FmgrInfo *partsupfunc, Oid *partcollation, Datum *datums1, PartitionRangeDatumKind *kind1, bool lower1, PartitionRangeBound *b2)
Definition: partbounds.c:3504
int errmsg_internal(const char *fmt,...)
Definition: elog.c:996
static List * get_qual_for_range(Relation parent, PartitionBoundSpec *spec, bool for_default)
Definition: partbounds.c:4291
#define DatumGetUInt64(X)
Definition: postgres.h:678
#define Max(x, y)
Definition: c.h:980
#define makeNode(_type_)
Definition: nodes.h:586
bool * parttypbyval
Definition: partcache.h:44
#define PG_ARGISNULL(n)
Definition: fmgr.h:209
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
int16 * parttyplen
Definition: partcache.h:43
static int partition_range_bsearch(int partnatts, FmgrInfo *partsupfunc, Oid *partcollation, PartitionBoundInfo boundinfo, PartitionRangeBound *probe, int32 *cmpval)
Definition: partbounds.c:3669
Oid array_collid
Definition: primnodes.h:1035
struct RelOptInfo ** part_rels
Definition: pathnodes.h:768
int location
Definition: primnodes.h:1268
static int list_length(const List *l)
Definition: pg_list.h:149
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:111
static void merge_default_partitions(PartitionMap *outer_map, PartitionMap *inner_map, bool outer_has_default, bool inner_has_default, int outer_default, int inner_default, JoinType jointype, int *next_index, int *default_index)
Definition: partbounds.c:2268
TupleTableSlot * ecxt_scantuple
Definition: execnodes.h:227
#define type_is_array(typid)
Definition: lsyscache.h:202
#define PG_NARGS()
Definition: fmgr.h:203
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:736
#define HASH_PARTITION_SEED
Definition: partition.h:20
#define PARTITION_STRATEGY_LIST
Definition: parsenodes.h:827
Snapshot GetLatestSnapshot(void)
Definition: snapmgr.c:325
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:538
Oid element_typeid
Definition: primnodes.h:1036
static int process_outer_partition(PartitionMap *outer_map, PartitionMap *inner_map, bool outer_has_default, bool inner_has_default, int outer_index, int inner_default, JoinType jointype, int *next_index, int *default_index)
Definition: partbounds.c:1991
bool bms_overlap(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:494
void deconstruct_array(ArrayType *array, Oid elmtype, int elmlen, bool elmbyval, char elmalign, Datum **elemsp, bool **nullsp, int *nelemsp)
Definition: arrayfuncs.c:3491
static void table_endscan(TableScanDesc scan)
Definition: tableam.h:991
static Datum values[MAXATTR]
Definition: bootstrap.c:156
#define PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:828
#define AccessExclusiveLock
Definition: lockdefs.h:45
List * find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents)
Definition: pg_inherits.c:256
#define Int32GetDatum(X)
Definition: postgres.h:523
static PartitionBoundInfo create_range_bounds(PartitionBoundSpec **boundspecs, int nparts, PartitionKey key, int **mapping)
Definition: partbounds.c:685
void * palloc(Size size)
Definition: mcxt.c:1062
int errmsg(const char *fmt,...)
Definition: elog.c:909
int * old_indexes
Definition: partbounds.c:83
bool partition_bounds_equal(int partnatts, int16 *parttyplen, bool *parttypbyval, PartitionBoundInfo b1, PartitionBoundInfo b2)
Definition: partbounds.c:904
Oid * partopcintype
Definition: partcache.h:34
void list_free(List *list)
Definition: list.c:1391
#define elog(elevel,...)
Definition: elog.h:232
int i
void * arg
bool ExecCheck(ExprState *state, ExprContext *econtext)
Definition: execExpr.c:853
#define compare_range_bounds(partnatts, partsupfunc, partcollations, bound1, bound2)
Definition: partbounds.c:88
bool argisrow
Definition: primnodes.h:1267
Datum satisfies_hash_partition(PG_FUNCTION_ARGS)
Definition: partbounds.c:4792
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
ExprState * ExecInitExpr(Expr *node, PlanState *parent)
Definition: execExpr.c:123
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:120
struct PartitionBoundInfoData * PartitionBoundInfo
Definition: partdefs.h:16
#define qsort(a, b, c, d)
Definition: port.h:505
#define copyObject(obj)
Definition: nodes.h:654
PartitionBoundInfo partition_bounds_merge(int partnatts, FmgrInfo *partsupfunc, Oid *partcollation, RelOptInfo *outer_rel, RelOptInfo *inner_rel, JoinType jointype, List **outer_parts, List **inner_parts)
Definition: partbounds.c:1126
#define BTLessStrategyNumber
Definition: stratnum.h:29
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
static int32 qsort_partition_list_value_cmp(const void *a, const void *b, void *arg)
Definition: partbounds.c:3809
Definition: pg_list.h:50
static unsigned hash(unsigned *uv, int n)
Definition: rege_dfa.c:715
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1899
int errtable(Relation rel)
Definition: relcache.c:5746
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:427
#define ARR_ELEMTYPE(a)
Definition: array.h:285
int * merged_indexes
Definition: partbounds.c:79
List * map_partition_varattnos(List *expr, int fromrel_varno, Relation to_rel, Relation from_rel)
Definition: partition.c:221
#define RelationGetRelid(relation)
Definition: rel.h:477
PartitionBoundInfo partition_bounds_create(PartitionBoundSpec **boundspecs, int nparts, PartitionKey key, int **mapping)
Definition: partbounds.c:303
long val
Definition: informix.c:664
static List * get_qual_for_list(Relation parent, PartitionBoundSpec *spec)
Definition: partbounds.c:4082
bool constisnull
Definition: primnodes.h:220
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define offsetof(type, field)
Definition: c.h:727
#define BTGreaterEqualStrategyNumber
Definition: stratnum.h:32
#define ResetExprContext(econtext)
Definition: executor.h:527
#define lfirst_oid(lc)
Definition: pg_list.h:171
bool PartConstraintImpliedByRelConstraint(Relation scanrel, List *partConstraint)
Definition: tablecmds.c:17067
FuncExpr * makeFuncExpr(Oid funcid, Oid rettype, List *args, Oid funccollid, Oid inputcollid, CoercionForm fformat)
Definition: makefuncs.c:519
struct PartitionKeyData * PartitionKey
Definition: partdefs.h:18
#define llast_int(l)
Definition: pg_list.h:195
static void merge_null_partitions(PartitionMap *outer_map, PartitionMap *inner_map, bool outer_has_null, bool inner_has_null, int outer_null, int inner_null, JoinType jointype, int *next_index, int *null_index)
Definition: partbounds.c:2158
static int get_range_partition(RelOptInfo *rel, PartitionBoundInfo bi, int *lb_pos, PartitionRangeBound *lb, PartitionRangeBound *ub)
Definition: partbounds.c:2592
struct PartitionHashBound PartitionHashBound