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-2020, 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 "executor/executor.h"
25 #include "miscadmin.h"
26 #include "nodes/makefuncs.h"
27 #include "nodes/nodeFuncs.h"
28 #include "parser/parse_coerce.h"
30 #include "partitioning/partdesc.h"
31 #include "partitioning/partprune.h"
32 #include "utils/builtins.h"
33 #include "utils/datum.h"
34 #include "utils/fmgroids.h"
35 #include "utils/hashutils.h"
36 #include "utils/lsyscache.h"
37 #include "utils/partcache.h"
38 #include "utils/ruleutils.h"
39 #include "utils/snapmgr.h"
40 #include "utils/syscache.h"
41 
42 /*
43  * When qsort'ing partition bounds after reading from the catalog, each bound
44  * is represented with one of the following structs.
45  */
46 
47 /* One bound of a hash partition */
48 typedef struct PartitionHashBound
49 {
50  int modulus;
51  int remainder;
52  int index;
54 
55 /* One value coming from some (index'th) list partition */
56 typedef struct PartitionListValue
57 {
58  int index;
61 
62 /* One bound of a range partition */
63 typedef struct PartitionRangeBound
64 {
65  int index;
66  Datum *datums; /* range bound datums */
67  PartitionRangeDatumKind *kind; /* the kind of each datum */
68  bool lower; /* this is the lower (vs upper) bound */
70 
71 static int32 qsort_partition_hbound_cmp(const void *a, const void *b);
72 static int32 qsort_partition_list_value_cmp(const void *a, const void *b,
73  void *arg);
74 static int32 qsort_partition_rbound_cmp(const void *a, const void *b,
75  void *arg);
77  int nparts, PartitionKey key, int **mapping);
79  int nparts, PartitionKey key, int **mapping);
81  int nparts, PartitionKey key, int **mapping);
83  List *datums, bool lower);
84 static int32 partition_hbound_cmp(int modulus1, int remainder1, int modulus2,
85  int remainder2);
86 static int32 partition_rbound_cmp(int partnatts, FmgrInfo *partsupfunc,
87  Oid *partcollation, Datum *datums1,
88  PartitionRangeDatumKind *kind1, bool lower1,
90 static int partition_range_bsearch(int partnatts, FmgrInfo *partsupfunc,
91  Oid *partcollation,
92  PartitionBoundInfo boundinfo,
93  PartitionRangeBound *probe, bool *is_equal);
95 static Expr *make_partition_op_expr(PartitionKey key, int keynum,
96  uint16 strategy, Expr *arg1, Expr *arg2);
98  StrategyNumber strategy, bool *need_relabel);
99 static List *get_qual_for_hash(Relation parent, PartitionBoundSpec *spec);
100 static List *get_qual_for_list(Relation parent, PartitionBoundSpec *spec);
101 static List *get_qual_for_range(Relation parent, PartitionBoundSpec *spec,
102  bool for_default);
103 static void get_range_key_properties(PartitionKey key, int keynum,
104  PartitionRangeDatum *ldatum,
105  PartitionRangeDatum *udatum,
106  ListCell **partexprs_item,
107  Expr **keyCol,
108  Const **lower_val, Const **upper_val);
110 
111 /*
112  * get_qual_from_partbound
113  * Given a parser node for partition bound, return the list of executable
114  * expressions as partition constraint
115  */
116 List *
118  PartitionBoundSpec *spec)
119 {
121  List *my_qual = NIL;
122 
123  Assert(key != NULL);
124 
125  switch (key->strategy)
126  {
129  my_qual = get_qual_for_hash(parent, spec);
130  break;
131 
134  my_qual = get_qual_for_list(parent, spec);
135  break;
136 
139  my_qual = get_qual_for_range(parent, spec, false);
140  break;
141 
142  default:
143  elog(ERROR, "unexpected partition strategy: %d",
144  (int) key->strategy);
145  }
146 
147  return my_qual;
148 }
149 
150 /*
151  * partition_bounds_create
152  * Build a PartitionBoundInfo struct from a list of PartitionBoundSpec
153  * nodes
154  *
155  * This function creates a PartitionBoundInfo and fills the values of its
156  * various members based on the input list. Importantly, 'datums' array will
157  * contain Datum representation of individual bounds (possibly after
158  * de-duplication as in case of range bounds), sorted in a canonical order
159  * defined by qsort_partition_* functions of respective partitioning methods.
160  * 'indexes' array will contain as many elements as there are bounds (specific
161  * exceptions to this rule are listed in the function body), which represent
162  * the 0-based canonical positions of partitions.
163  *
164  * Upon return from this function, *mapping is set to an array of
165  * list_length(boundspecs) elements, each of which maps the original index of
166  * a partition to its canonical index.
167  *
168  * Note: The objects returned by this function are wholly allocated in the
169  * current memory context.
170  */
173  PartitionKey key, int **mapping)
174 {
175  int i;
176 
177  Assert(nparts > 0);
178 
179  /*
180  * For each partitioning method, we first convert the partition bounds
181  * from their parser node representation to the internal representation,
182  * along with any additional preprocessing (such as de-duplicating range
183  * bounds). Resulting bound datums are then added to the 'datums' array
184  * in PartitionBoundInfo. For each datum added, an integer indicating the
185  * canonical partition index is added to the 'indexes' array.
186  *
187  * For each bound, we remember its partition's position (0-based) in the
188  * original list to later map it to the canonical index.
189  */
190 
191  /*
192  * Initialize mapping array with invalid values, this is filled within
193  * each sub-routine below depending on the bound type.
194  */
195  *mapping = (int *) palloc(sizeof(int) * nparts);
196  for (i = 0; i < nparts; i++)
197  (*mapping)[i] = -1;
198 
199  switch (key->strategy)
200  {
202  return create_hash_bounds(boundspecs, nparts, key, mapping);
203 
205  return create_list_bounds(boundspecs, nparts, key, mapping);
206 
208  return create_range_bounds(boundspecs, nparts, key, mapping);
209 
210  default:
211  elog(ERROR, "unexpected partition strategy: %d",
212  (int) key->strategy);
213  break;
214  }
215 
216  Assert(false);
217  return NULL; /* keep compiler quiet */
218 }
219 
220 /*
221  * create_hash_bounds
222  * Create a PartitionBoundInfo for a hash partitioned table
223  */
224 static PartitionBoundInfo
225 create_hash_bounds(PartitionBoundSpec **boundspecs, int nparts,
226  PartitionKey key, int **mapping)
227 {
228  PartitionBoundInfo boundinfo;
229  PartitionHashBound **hbounds = NULL;
230  int i;
231  int ndatums = 0;
232  int greatest_modulus;
233 
234  boundinfo = (PartitionBoundInfoData *)
236  boundinfo->strategy = key->strategy;
237  /* No special hash partitions. */
238  boundinfo->null_index = -1;
239  boundinfo->default_index = -1;
240 
241  ndatums = nparts;
242  hbounds = (PartitionHashBound **)
243  palloc(nparts * sizeof(PartitionHashBound *));
244 
245  /* Convert from node to the internal representation */
246  for (i = 0; i < nparts; i++)
247  {
248  PartitionBoundSpec *spec = boundspecs[i];
249 
250  if (spec->strategy != PARTITION_STRATEGY_HASH)
251  elog(ERROR, "invalid strategy in partition bound spec");
252 
253  hbounds[i] = (PartitionHashBound *) palloc(sizeof(PartitionHashBound));
254  hbounds[i]->modulus = spec->modulus;
255  hbounds[i]->remainder = spec->remainder;
256  hbounds[i]->index = i;
257  }
258 
259  /* Sort all the bounds in ascending order */
260  qsort(hbounds, nparts, sizeof(PartitionHashBound *),
262 
263  /* After sorting, moduli are now stored in ascending order. */
264  greatest_modulus = hbounds[ndatums - 1]->modulus;
265 
266  boundinfo->ndatums = ndatums;
267  boundinfo->datums = (Datum **) palloc0(ndatums * sizeof(Datum *));
268  boundinfo->indexes = (int *) palloc(greatest_modulus * sizeof(int));
269  for (i = 0; i < greatest_modulus; i++)
270  boundinfo->indexes[i] = -1;
271 
272  /*
273  * For hash partitioning, there are as many datums (modulus and remainder
274  * pairs) as there are partitions. Indexes are simply values ranging from
275  * 0 to (nparts - 1).
276  */
277  for (i = 0; i < nparts; i++)
278  {
279  int modulus = hbounds[i]->modulus;
280  int remainder = hbounds[i]->remainder;
281 
282  boundinfo->datums[i] = (Datum *) palloc(2 * sizeof(Datum));
283  boundinfo->datums[i][0] = Int32GetDatum(modulus);
284  boundinfo->datums[i][1] = Int32GetDatum(remainder);
285 
286  while (remainder < greatest_modulus)
287  {
288  /* overlap? */
289  Assert(boundinfo->indexes[remainder] == -1);
290  boundinfo->indexes[remainder] = i;
291  remainder += modulus;
292  }
293 
294  (*mapping)[hbounds[i]->index] = i;
295  pfree(hbounds[i]);
296  }
297  pfree(hbounds);
298 
299  return boundinfo;
300 }
301 
302 /*
303  * create_list_bounds
304  * Create a PartitionBoundInfo for a list partitioned table
305  */
306 static PartitionBoundInfo
307 create_list_bounds(PartitionBoundSpec **boundspecs, int nparts,
308  PartitionKey key, int **mapping)
309 {
310  PartitionBoundInfo boundinfo;
311  PartitionListValue **all_values = NULL;
312  ListCell *cell;
313  int i = 0;
314  int ndatums = 0;
315  int next_index = 0;
316  int default_index = -1;
317  int null_index = -1;
318  List *non_null_values = NIL;
319 
320  boundinfo = (PartitionBoundInfoData *)
322  boundinfo->strategy = key->strategy;
323  /* Will be set correctly below. */
324  boundinfo->null_index = -1;
325  boundinfo->default_index = -1;
326 
327  /* Create a unified list of non-null values across all partitions. */
328  for (i = 0; i < nparts; i++)
329  {
330  PartitionBoundSpec *spec = boundspecs[i];
331  ListCell *c;
332 
333  if (spec->strategy != PARTITION_STRATEGY_LIST)
334  elog(ERROR, "invalid strategy in partition bound spec");
335 
336  /*
337  * Note the index of the partition bound spec for the default
338  * partition. There's no datum to add to the list on non-null datums
339  * for this partition.
340  */
341  if (spec->is_default)
342  {
343  default_index = i;
344  continue;
345  }
346 
347  foreach(c, spec->listdatums)
348  {
349  Const *val = castNode(Const, lfirst(c));
350  PartitionListValue *list_value = NULL;
351 
352  if (!val->constisnull)
353  {
354  list_value = (PartitionListValue *)
355  palloc0(sizeof(PartitionListValue));
356  list_value->index = i;
357  list_value->value = val->constvalue;
358  }
359  else
360  {
361  /*
362  * Never put a null into the values array; save the index of
363  * the partition that stores nulls, instead.
364  */
365  if (null_index != -1)
366  elog(ERROR, "found null more than once");
367  null_index = i;
368  }
369 
370  if (list_value)
371  non_null_values = lappend(non_null_values, list_value);
372  }
373  }
374 
375  ndatums = list_length(non_null_values);
376 
377  /*
378  * Collect all list values in one array. Alongside the value, we also save
379  * the index of partition the value comes from.
380  */
381  all_values = (PartitionListValue **)
382  palloc(ndatums * sizeof(PartitionListValue *));
383  i = 0;
384  foreach(cell, non_null_values)
385  {
386  PartitionListValue *src = lfirst(cell);
387 
388  all_values[i] = (PartitionListValue *)
389  palloc(sizeof(PartitionListValue));
390  all_values[i]->value = src->value;
391  all_values[i]->index = src->index;
392  i++;
393  }
394 
395  qsort_arg(all_values, ndatums, sizeof(PartitionListValue *),
396  qsort_partition_list_value_cmp, (void *) key);
397 
398  boundinfo->ndatums = ndatums;
399  boundinfo->datums = (Datum **) palloc0(ndatums * sizeof(Datum *));
400  boundinfo->indexes = (int *) palloc(ndatums * sizeof(int));
401 
402  /*
403  * Copy values. Canonical indexes are values ranging from 0 to (nparts -
404  * 1) assigned to each partition such that all datums of a given partition
405  * receive the same value. The value for a given partition is the index of
406  * that partition's smallest datum in the all_values[] array.
407  */
408  for (i = 0; i < ndatums; i++)
409  {
410  int orig_index = all_values[i]->index;
411 
412  boundinfo->datums[i] = (Datum *) palloc(sizeof(Datum));
413  boundinfo->datums[i][0] = datumCopy(all_values[i]->value,
414  key->parttypbyval[0],
415  key->parttyplen[0]);
416 
417  /* If the old index has no mapping, assign one */
418  if ((*mapping)[orig_index] == -1)
419  (*mapping)[orig_index] = next_index++;
420 
421  boundinfo->indexes[i] = (*mapping)[orig_index];
422  }
423 
424  /*
425  * Set the canonical value for null_index, if any.
426  *
427  * It is possible that the null-accepting partition has not been assigned
428  * an index yet, which could happen if such partition accepts only null
429  * and hence not handled in the above loop which only looked at non-null
430  * values.
431  */
432  if (null_index != -1)
433  {
434  Assert(null_index >= 0);
435  if ((*mapping)[null_index] == -1)
436  (*mapping)[null_index] = next_index++;
437  boundinfo->null_index = (*mapping)[null_index];
438  }
439 
440  /* Set the canonical value for default_index, if any. */
441  if (default_index != -1)
442  {
443  /*
444  * The default partition accepts any value not specified in the lists
445  * of other partitions, hence it should not get mapped index while
446  * assigning those for non-null datums.
447  */
448  Assert(default_index >= 0);
449  Assert((*mapping)[default_index] == -1);
450  (*mapping)[default_index] = next_index++;
451  boundinfo->default_index = (*mapping)[default_index];
452  }
453 
454  /* All partitions must now have been assigned canonical indexes. */
455  Assert(next_index == nparts);
456  return boundinfo;
457 }
458 
459 /*
460  * create_range_bounds
461  * Create a PartitionBoundInfo for a range partitioned table
462  */
463 static PartitionBoundInfo
464 create_range_bounds(PartitionBoundSpec **boundspecs, int nparts,
465  PartitionKey key, int **mapping)
466 {
467  PartitionBoundInfo boundinfo;
468  PartitionRangeBound **rbounds = NULL;
469  PartitionRangeBound **all_bounds,
470  *prev;
471  int i,
472  k;
473  int ndatums = 0;
474  int default_index = -1;
475  int next_index = 0;
476 
477  boundinfo = (PartitionBoundInfoData *)
479  boundinfo->strategy = key->strategy;
480  /* There is no special null-accepting range partition. */
481  boundinfo->null_index = -1;
482  /* Will be set correctly below. */
483  boundinfo->default_index = -1;
484 
485  all_bounds = (PartitionRangeBound **)
486  palloc0(2 * nparts * sizeof(PartitionRangeBound *));
487 
488  /* Create a unified list of range bounds across all the partitions. */
489  ndatums = 0;
490  for (i = 0; i < nparts; i++)
491  {
492  PartitionBoundSpec *spec = boundspecs[i];
494  *upper;
495 
496  if (spec->strategy != PARTITION_STRATEGY_RANGE)
497  elog(ERROR, "invalid strategy in partition bound spec");
498 
499  /*
500  * Note the index of the partition bound spec for the default
501  * partition. There's no datum to add to the all_bounds array for
502  * this partition.
503  */
504  if (spec->is_default)
505  {
506  default_index = i;
507  continue;
508  }
509 
510  lower = make_one_partition_rbound(key, i, spec->lowerdatums, true);
511  upper = make_one_partition_rbound(key, i, spec->upperdatums, false);
512  all_bounds[ndatums++] = lower;
513  all_bounds[ndatums++] = upper;
514  }
515 
516  Assert(ndatums == nparts * 2 ||
517  (default_index != -1 && ndatums == (nparts - 1) * 2));
518 
519  /* Sort all the bounds in ascending order */
520  qsort_arg(all_bounds, ndatums,
521  sizeof(PartitionRangeBound *),
523  (void *) key);
524 
525  /* Save distinct bounds from all_bounds into rbounds. */
526  rbounds = (PartitionRangeBound **)
527  palloc(ndatums * sizeof(PartitionRangeBound *));
528  k = 0;
529  prev = NULL;
530  for (i = 0; i < ndatums; i++)
531  {
532  PartitionRangeBound *cur = all_bounds[i];
533  bool is_distinct = false;
534  int j;
535 
536  /* Is the current bound distinct from the previous one? */
537  for (j = 0; j < key->partnatts; j++)
538  {
539  Datum cmpval;
540 
541  if (prev == NULL || cur->kind[j] != prev->kind[j])
542  {
543  is_distinct = true;
544  break;
545  }
546 
547  /*
548  * If the bounds are both MINVALUE or MAXVALUE, stop now and treat
549  * them as equal, since any values after this point must be
550  * ignored.
551  */
552  if (cur->kind[j] != PARTITION_RANGE_DATUM_VALUE)
553  break;
554 
555  cmpval = FunctionCall2Coll(&key->partsupfunc[j],
556  key->partcollation[j],
557  cur->datums[j],
558  prev->datums[j]);
559  if (DatumGetInt32(cmpval) != 0)
560  {
561  is_distinct = true;
562  break;
563  }
564  }
565 
566  /*
567  * Only if the bound is distinct save it into a temporary array, i.e,
568  * rbounds which is later copied into boundinfo datums array.
569  */
570  if (is_distinct)
571  rbounds[k++] = all_bounds[i];
572 
573  prev = cur;
574  }
575 
576  /* Update ndatums to hold the count of distinct datums. */
577  ndatums = k;
578 
579  /*
580  * Add datums to boundinfo. Canonical indexes are values ranging from 0
581  * to nparts - 1, assigned in that order to each partition's upper bound.
582  * For 'datums' elements that are lower bounds, there is -1 in the
583  * 'indexes' array to signify that no partition exists for the values less
584  * than such a bound and greater than or equal to the previous upper
585  * bound.
586  */
587  boundinfo->ndatums = ndatums;
588  boundinfo->datums = (Datum **) palloc0(ndatums * sizeof(Datum *));
589  boundinfo->kind = (PartitionRangeDatumKind **)
590  palloc(ndatums *
591  sizeof(PartitionRangeDatumKind *));
592 
593  /*
594  * For range partitioning, an additional value of -1 is stored as the last
595  * element.
596  */
597  boundinfo->indexes = (int *) palloc((ndatums + 1) * sizeof(int));
598 
599  for (i = 0; i < ndatums; i++)
600  {
601  int j;
602 
603  boundinfo->datums[i] = (Datum *) palloc(key->partnatts *
604  sizeof(Datum));
605  boundinfo->kind[i] = (PartitionRangeDatumKind *)
606  palloc(key->partnatts *
607  sizeof(PartitionRangeDatumKind));
608  for (j = 0; j < key->partnatts; j++)
609  {
610  if (rbounds[i]->kind[j] == PARTITION_RANGE_DATUM_VALUE)
611  boundinfo->datums[i][j] =
612  datumCopy(rbounds[i]->datums[j],
613  key->parttypbyval[j],
614  key->parttyplen[j]);
615  boundinfo->kind[i][j] = rbounds[i]->kind[j];
616  }
617 
618  /*
619  * There is no mapping for invalid indexes.
620  *
621  * Any lower bounds in the rbounds array have invalid indexes
622  * assigned, because the values between the previous bound (if there
623  * is one) and this (lower) bound are not part of the range of any
624  * existing partition.
625  */
626  if (rbounds[i]->lower)
627  boundinfo->indexes[i] = -1;
628  else
629  {
630  int orig_index = rbounds[i]->index;
631 
632  /* If the old index has no mapping, assign one */
633  if ((*mapping)[orig_index] == -1)
634  (*mapping)[orig_index] = next_index++;
635 
636  boundinfo->indexes[i] = (*mapping)[orig_index];
637  }
638  }
639 
640  /* Set the canonical value for default_index, if any. */
641  if (default_index != -1)
642  {
643  Assert(default_index >= 0 && (*mapping)[default_index] == -1);
644  (*mapping)[default_index] = next_index++;
645  boundinfo->default_index = (*mapping)[default_index];
646  }
647 
648  /* The extra -1 element. */
649  Assert(i == ndatums);
650  boundinfo->indexes[i] = -1;
651 
652  /* All partitions must now have been assigned canonical indexes. */
653  Assert(next_index == nparts);
654  return boundinfo;
655 }
656 
657 /*
658  * Are two partition bound collections logically equal?
659  *
660  * Used in the keep logic of relcache.c (ie, in RelationClearRelation()).
661  * This is also useful when b1 and b2 are bound collections of two separate
662  * relations, respectively, because PartitionBoundInfo is a canonical
663  * representation of partition bounds.
664  */
665 bool
666 partition_bounds_equal(int partnatts, int16 *parttyplen, bool *parttypbyval,
668 {
669  int i;
670 
671  if (b1->strategy != b2->strategy)
672  return false;
673 
674  if (b1->ndatums != b2->ndatums)
675  return false;
676 
677  if (b1->null_index != b2->null_index)
678  return false;
679 
680  if (b1->default_index != b2->default_index)
681  return false;
682 
684  {
685  int greatest_modulus = get_hash_partition_greatest_modulus(b1);
686 
687  /*
688  * If two hash partitioned tables have different greatest moduli,
689  * their partition schemes don't match.
690  */
691  if (greatest_modulus != get_hash_partition_greatest_modulus(b2))
692  return false;
693 
694  /*
695  * We arrange the partitions in the ascending order of their moduli
696  * and remainders. Also every modulus is factor of next larger
697  * modulus. Therefore we can safely store index of a given partition
698  * in indexes array at remainder of that partition. Also entries at
699  * (remainder + N * modulus) positions in indexes array are all same
700  * for (modulus, remainder) specification for any partition. Thus
701  * datums array from both the given bounds are same, if and only if
702  * their indexes array will be same. So, it suffices to compare
703  * indexes array.
704  */
705  for (i = 0; i < greatest_modulus; i++)
706  if (b1->indexes[i] != b2->indexes[i])
707  return false;
708 
709 #ifdef USE_ASSERT_CHECKING
710 
711  /*
712  * Nonetheless make sure that the bounds are indeed same when the
713  * indexes match. Hash partition bound stores modulus and remainder
714  * at b1->datums[i][0] and b1->datums[i][1] position respectively.
715  */
716  for (i = 0; i < b1->ndatums; i++)
717  Assert((b1->datums[i][0] == b2->datums[i][0] &&
718  b1->datums[i][1] == b2->datums[i][1]));
719 #endif
720  }
721  else
722  {
723  for (i = 0; i < b1->ndatums; i++)
724  {
725  int j;
726 
727  for (j = 0; j < partnatts; j++)
728  {
729  /* For range partitions, the bounds might not be finite. */
730  if (b1->kind != NULL)
731  {
732  /* The different kinds of bound all differ from each other */
733  if (b1->kind[i][j] != b2->kind[i][j])
734  return false;
735 
736  /*
737  * Non-finite bounds are equal without further
738  * examination.
739  */
740  if (b1->kind[i][j] != PARTITION_RANGE_DATUM_VALUE)
741  continue;
742  }
743 
744  /*
745  * Compare the actual values. Note that it would be both
746  * incorrect and unsafe to invoke the comparison operator
747  * derived from the partitioning specification here. It would
748  * be incorrect because we want the relcache entry to be
749  * updated for ANY change to the partition bounds, not just
750  * those that the partitioning operator thinks are
751  * significant. It would be unsafe because we might reach
752  * this code in the context of an aborted transaction, and an
753  * arbitrary partitioning operator might not be safe in that
754  * context. datumIsEqual() should be simple enough to be
755  * safe.
756  */
757  if (!datumIsEqual(b1->datums[i][j], b2->datums[i][j],
758  parttypbyval[j], parttyplen[j]))
759  return false;
760  }
761 
762  if (b1->indexes[i] != b2->indexes[i])
763  return false;
764  }
765 
766  /* There are ndatums+1 indexes in case of range partitions */
767  if (b1->strategy == PARTITION_STRATEGY_RANGE &&
768  b1->indexes[i] != b2->indexes[i])
769  return false;
770  }
771  return true;
772 }
773 
774 /*
775  * Return a copy of given PartitionBoundInfo structure. The data types of bounds
776  * are described by given partition key specification.
777  *
778  * Note: it's important that this function and its callees not do any catalog
779  * access, nor anything else that would result in allocating memory other than
780  * the returned data structure. Since this is called in a long-lived context,
781  * that would result in unwanted memory leaks.
782  */
786 {
788  int i;
789  int ndatums;
790  int partnatts;
791  int num_indexes;
792 
794 
795  dest->strategy = src->strategy;
796  ndatums = dest->ndatums = src->ndatums;
797  partnatts = key->partnatts;
798 
799  num_indexes = get_partition_bound_num_indexes(src);
800 
801  /* List partitioned tables have only a single partition key. */
802  Assert(key->strategy != PARTITION_STRATEGY_LIST || partnatts == 1);
803 
804  dest->datums = (Datum **) palloc(sizeof(Datum *) * ndatums);
805 
806  if (src->kind != NULL)
807  {
808  dest->kind = (PartitionRangeDatumKind **) palloc(ndatums *
809  sizeof(PartitionRangeDatumKind *));
810  for (i = 0; i < ndatums; i++)
811  {
812  dest->kind[i] = (PartitionRangeDatumKind *) palloc(partnatts *
813  sizeof(PartitionRangeDatumKind));
814 
815  memcpy(dest->kind[i], src->kind[i],
816  sizeof(PartitionRangeDatumKind) * key->partnatts);
817  }
818  }
819  else
820  dest->kind = NULL;
821 
822  for (i = 0; i < ndatums; i++)
823  {
824  int j;
825 
826  /*
827  * For a corresponding to hash partition, datums array will have two
828  * elements - modulus and remainder.
829  */
830  bool hash_part = (key->strategy == PARTITION_STRATEGY_HASH);
831  int natts = hash_part ? 2 : partnatts;
832 
833  dest->datums[i] = (Datum *) palloc(sizeof(Datum) * natts);
834 
835  for (j = 0; j < natts; j++)
836  {
837  bool byval;
838  int typlen;
839 
840  if (hash_part)
841  {
842  typlen = sizeof(int32); /* Always int4 */
843  byval = true; /* int4 is pass-by-value */
844  }
845  else
846  {
847  byval = key->parttypbyval[j];
848  typlen = key->parttyplen[j];
849  }
850 
851  if (dest->kind == NULL ||
852  dest->kind[i][j] == PARTITION_RANGE_DATUM_VALUE)
853  dest->datums[i][j] = datumCopy(src->datums[i][j],
854  byval, typlen);
855  }
856  }
857 
858  dest->indexes = (int *) palloc(sizeof(int) * num_indexes);
859  memcpy(dest->indexes, src->indexes, sizeof(int) * num_indexes);
860 
861  dest->null_index = src->null_index;
862  dest->default_index = src->default_index;
863 
864  return dest;
865 }
866 
867 /*
868  * partitions_are_ordered
869  * Determine whether the partitions described by 'boundinfo' are ordered,
870  * that is partitions appearing earlier in the PartitionDesc sequence
871  * contain partition keys strictly less than those appearing later.
872  * Also, if NULL values are possible, they must come in the last
873  * partition defined in the PartitionDesc.
874  *
875  * If out of order, or there is insufficient info to know the order,
876  * then we return false.
877  */
878 bool
880 {
881  Assert(boundinfo != NULL);
882 
883  switch (boundinfo->strategy)
884  {
886 
887  /*
888  * RANGE-type partitioning guarantees that the partitions can be
889  * scanned in the order that they're defined in the PartitionDesc
890  * to provide sequential, non-overlapping ranges of tuples.
891  * However, if a DEFAULT partition exists then it doesn't work, as
892  * that could contain tuples from either below or above the
893  * defined range, or tuples belonging to gaps between partitions.
894  */
895  if (!partition_bound_has_default(boundinfo))
896  return true;
897  break;
898 
900 
901  /*
902  * LIST partitioning can also guarantee ordering, but only if the
903  * partitions don't accept interleaved values. We could likely
904  * check for this by looping over the PartitionBound's indexes
905  * array to check that the indexes are in order. For now, let's
906  * just keep it simple and just accept LIST partitioning when
907  * there's no DEFAULT partition, exactly one value per partition,
908  * and optionally a NULL partition that does not accept any other
909  * values. Such a NULL partition will come last in the
910  * PartitionDesc, and the other partitions will be properly
911  * ordered. This is a cheap test to make as it does not require
912  * any per-partition processing. Maybe we'd like to handle more
913  * complex cases in the future.
914  */
915  if (partition_bound_has_default(boundinfo))
916  return false;
917 
918  if (boundinfo->ndatums + partition_bound_accepts_nulls(boundinfo)
919  == nparts)
920  return true;
921  break;
922 
923  default:
924  /* HASH, or some other strategy */
925  break;
926  }
927 
928  return false;
929 }
930 
931 /*
932  * check_new_partition_bound
933  *
934  * Checks if the new partition's bound overlaps any of the existing partitions
935  * of parent. Also performs additional checks as necessary per strategy.
936  */
937 void
939  PartitionBoundSpec *spec)
940 {
942  PartitionDesc partdesc = RelationGetPartitionDesc(parent);
943  PartitionBoundInfo boundinfo = partdesc->boundinfo;
944  ParseState *pstate = make_parsestate(NULL);
945  int with = -1;
946  bool overlap = false;
947 
948  if (spec->is_default)
949  {
950  /*
951  * The default partition bound never conflicts with any other
952  * partition's; if that's what we're attaching, the only possible
953  * problem is that one already exists, so check for that and we're
954  * done.
955  */
956  if (boundinfo == NULL || !partition_bound_has_default(boundinfo))
957  return;
958 
959  /* Default partition already exists, error out. */
960  ereport(ERROR,
961  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
962  errmsg("partition \"%s\" conflicts with existing default partition \"%s\"",
963  relname, get_rel_name(partdesc->oids[boundinfo->default_index])),
964  parser_errposition(pstate, spec->location)));
965  }
966 
967  switch (key->strategy)
968  {
970  {
972  Assert(spec->remainder >= 0 && spec->remainder < spec->modulus);
973 
974  if (partdesc->nparts > 0)
975  {
976  Datum **datums = boundinfo->datums;
977  int ndatums = boundinfo->ndatums;
978  int greatest_modulus;
979  int remainder;
980  int offset;
981  bool valid_modulus = true;
982  int prev_modulus, /* Previous largest modulus */
983  next_modulus; /* Next largest modulus */
984 
985  /*
986  * Check rule that every modulus must be a factor of the
987  * next larger modulus. For example, if you have a bunch
988  * of partitions that all have modulus 5, you can add a
989  * new partition with modulus 10 or a new partition with
990  * modulus 15, but you cannot add both a partition with
991  * modulus 10 and a partition with modulus 15, because 10
992  * is not a factor of 15.
993  *
994  * Get the greatest (modulus, remainder) pair contained in
995  * boundinfo->datums that is less than or equal to the
996  * (spec->modulus, spec->remainder) pair.
997  */
998  offset = partition_hash_bsearch(boundinfo,
999  spec->modulus,
1000  spec->remainder);
1001  if (offset < 0)
1002  {
1003  next_modulus = DatumGetInt32(datums[0][0]);
1004  valid_modulus = (next_modulus % spec->modulus) == 0;
1005  }
1006  else
1007  {
1008  prev_modulus = DatumGetInt32(datums[offset][0]);
1009  valid_modulus = (spec->modulus % prev_modulus) == 0;
1010 
1011  if (valid_modulus && (offset + 1) < ndatums)
1012  {
1013  next_modulus = DatumGetInt32(datums[offset + 1][0]);
1014  valid_modulus = (next_modulus % spec->modulus) == 0;
1015  }
1016  }
1017 
1018  if (!valid_modulus)
1019  ereport(ERROR,
1020  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1021  errmsg("every hash partition modulus must be a factor of the next larger modulus")));
1022 
1023  greatest_modulus = get_hash_partition_greatest_modulus(boundinfo);
1024  remainder = spec->remainder;
1025 
1026  /*
1027  * Normally, the lowest remainder that could conflict with
1028  * the new partition is equal to the remainder specified
1029  * for the new partition, but when the new partition has a
1030  * modulus higher than any used so far, we need to adjust.
1031  */
1032  if (remainder >= greatest_modulus)
1033  remainder = remainder % greatest_modulus;
1034 
1035  /* Check every potentially-conflicting remainder. */
1036  do
1037  {
1038  if (boundinfo->indexes[remainder] != -1)
1039  {
1040  overlap = true;
1041  with = boundinfo->indexes[remainder];
1042  break;
1043  }
1044  remainder += spec->modulus;
1045  } while (remainder < greatest_modulus);
1046  }
1047 
1048  break;
1049  }
1050 
1052  {
1054 
1055  if (partdesc->nparts > 0)
1056  {
1057  ListCell *cell;
1058 
1059  Assert(boundinfo &&
1060  boundinfo->strategy == PARTITION_STRATEGY_LIST &&
1061  (boundinfo->ndatums > 0 ||
1062  partition_bound_accepts_nulls(boundinfo) ||
1063  partition_bound_has_default(boundinfo)));
1064 
1065  foreach(cell, spec->listdatums)
1066  {
1067  Const *val = castNode(Const, lfirst(cell));
1068 
1069  if (!val->constisnull)
1070  {
1071  int offset;
1072  bool equal;
1073 
1074  offset = partition_list_bsearch(&key->partsupfunc[0],
1075  key->partcollation,
1076  boundinfo,
1077  val->constvalue,
1078  &equal);
1079  if (offset >= 0 && equal)
1080  {
1081  overlap = true;
1082  with = boundinfo->indexes[offset];
1083  break;
1084  }
1085  }
1086  else if (partition_bound_accepts_nulls(boundinfo))
1087  {
1088  overlap = true;
1089  with = boundinfo->null_index;
1090  break;
1091  }
1092  }
1093  }
1094 
1095  break;
1096  }
1097 
1099  {
1101  *upper;
1102 
1104  lower = make_one_partition_rbound(key, -1, spec->lowerdatums, true);
1105  upper = make_one_partition_rbound(key, -1, spec->upperdatums, false);
1106 
1107  /*
1108  * First check if the resulting range would be empty with
1109  * specified lower and upper bounds
1110  */
1112  key->partcollation, lower->datums,
1113  lower->kind, true, upper) >= 0)
1114  {
1115  ereport(ERROR,
1116  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1117  errmsg("empty range bound specified for partition \"%s\"",
1118  relname),
1119  errdetail("Specified lower bound %s is greater than or equal to upper bound %s.",
1122  parser_errposition(pstate, spec->location)));
1123  }
1124 
1125  if (partdesc->nparts > 0)
1126  {
1127  int offset;
1128  bool equal;
1129 
1130  Assert(boundinfo &&
1131  boundinfo->strategy == PARTITION_STRATEGY_RANGE &&
1132  (boundinfo->ndatums > 0 ||
1133  partition_bound_has_default(boundinfo)));
1134 
1135  /*
1136  * Test whether the new lower bound (which is treated
1137  * inclusively as part of the new partition) lies inside
1138  * an existing partition, or in a gap.
1139  *
1140  * If it's inside an existing partition, the bound at
1141  * offset + 1 will be the upper bound of that partition,
1142  * and its index will be >= 0.
1143  *
1144  * If it's in a gap, the bound at offset + 1 will be the
1145  * lower bound of the next partition, and its index will
1146  * be -1. This is also true if there is no next partition,
1147  * since the index array is initialised with an extra -1
1148  * at the end.
1149  */
1150  offset = partition_range_bsearch(key->partnatts,
1151  key->partsupfunc,
1152  key->partcollation,
1153  boundinfo, lower,
1154  &equal);
1155 
1156  if (boundinfo->indexes[offset + 1] < 0)
1157  {
1158  /*
1159  * Check that the new partition will fit in the gap.
1160  * For it to fit, the new upper bound must be less
1161  * than or equal to the lower bound of the next
1162  * partition, if there is one.
1163  */
1164  if (offset + 1 < boundinfo->ndatums)
1165  {
1166  int32 cmpval;
1167  Datum *datums;
1169  bool is_lower;
1170 
1171  datums = boundinfo->datums[offset + 1];
1172  kind = boundinfo->kind[offset + 1];
1173  is_lower = (boundinfo->indexes[offset + 1] == -1);
1174 
1175  cmpval = partition_rbound_cmp(key->partnatts,
1176  key->partsupfunc,
1177  key->partcollation,
1178  datums, kind,
1179  is_lower, upper);
1180  if (cmpval < 0)
1181  {
1182  /*
1183  * The new partition overlaps with the
1184  * existing partition between offset + 1 and
1185  * offset + 2.
1186  */
1187  overlap = true;
1188  with = boundinfo->indexes[offset + 2];
1189  }
1190  }
1191  }
1192  else
1193  {
1194  /*
1195  * The new partition overlaps with the existing
1196  * partition between offset and offset + 1.
1197  */
1198  overlap = true;
1199  with = boundinfo->indexes[offset + 1];
1200  }
1201  }
1202 
1203  break;
1204  }
1205 
1206  default:
1207  elog(ERROR, "unexpected partition strategy: %d",
1208  (int) key->strategy);
1209  }
1210 
1211  if (overlap)
1212  {
1213  Assert(with >= 0);
1214  ereport(ERROR,
1215  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1216  errmsg("partition \"%s\" would overlap partition \"%s\"",
1217  relname, get_rel_name(partdesc->oids[with])),
1218  parser_errposition(pstate, spec->location)));
1219  }
1220 }
1221 
1222 /*
1223  * check_default_partition_contents
1224  *
1225  * This function checks if there exists a row in the default partition that
1226  * would properly belong to the new partition being added. If it finds one,
1227  * it throws an error.
1228  */
1229 void
1231  PartitionBoundSpec *new_spec)
1232 {
1233  List *new_part_constraints;
1234  List *def_part_constraints;
1235  List *all_parts;
1236  ListCell *lc;
1237 
1238  new_part_constraints = (new_spec->strategy == PARTITION_STRATEGY_LIST)
1239  ? get_qual_for_list(parent, new_spec)
1240  : get_qual_for_range(parent, new_spec, false);
1241  def_part_constraints =
1242  get_proposed_default_constraint(new_part_constraints);
1243 
1244  /*
1245  * Map the Vars in the constraint expression from parent's attnos to
1246  * default_rel's.
1247  */
1248  def_part_constraints =
1249  map_partition_varattnos(def_part_constraints, 1, default_rel,
1250  parent);
1251 
1252  /*
1253  * If the existing constraints on the default partition imply that it will
1254  * not contain any row that would belong to the new partition, we can
1255  * avoid scanning the default partition.
1256  */
1257  if (PartConstraintImpliedByRelConstraint(default_rel, def_part_constraints))
1258  {
1259  ereport(DEBUG1,
1260  (errmsg("updated partition constraint for default partition \"%s\" is implied by existing constraints",
1261  RelationGetRelationName(default_rel))));
1262  return;
1263  }
1264 
1265  /*
1266  * Scan the default partition and its subpartitions, and check for rows
1267  * that do not satisfy the revised partition constraints.
1268  */
1269  if (default_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1270  all_parts = find_all_inheritors(RelationGetRelid(default_rel),
1271  AccessExclusiveLock, NULL);
1272  else
1273  all_parts = list_make1_oid(RelationGetRelid(default_rel));
1274 
1275  foreach(lc, all_parts)
1276  {
1277  Oid part_relid = lfirst_oid(lc);
1278  Relation part_rel;
1279  Expr *partition_constraint;
1280  EState *estate;
1281  ExprState *partqualstate = NULL;
1282  Snapshot snapshot;
1283  ExprContext *econtext;
1284  TableScanDesc scan;
1285  MemoryContext oldCxt;
1286  TupleTableSlot *tupslot;
1287 
1288  /* Lock already taken above. */
1289  if (part_relid != RelationGetRelid(default_rel))
1290  {
1291  part_rel = table_open(part_relid, NoLock);
1292 
1293  /*
1294  * Map the Vars in the constraint expression from default_rel's
1295  * the sub-partition's.
1296  */
1297  partition_constraint = make_ands_explicit(def_part_constraints);
1298  partition_constraint = (Expr *)
1299  map_partition_varattnos((List *) partition_constraint, 1,
1300  part_rel, default_rel);
1301 
1302  /*
1303  * If the partition constraints on default partition child imply
1304  * that it will not contain any row that would belong to the new
1305  * partition, we can avoid scanning the child table.
1306  */
1308  def_part_constraints))
1309  {
1310  ereport(DEBUG1,
1311  (errmsg("updated partition constraint for default partition \"%s\" is implied by existing constraints",
1312  RelationGetRelationName(part_rel))));
1313 
1314  table_close(part_rel, NoLock);
1315  continue;
1316  }
1317  }
1318  else
1319  {
1320  part_rel = default_rel;
1321  partition_constraint = make_ands_explicit(def_part_constraints);
1322  }
1323 
1324  /*
1325  * Only RELKIND_RELATION relations (i.e. leaf partitions) need to be
1326  * scanned.
1327  */
1328  if (part_rel->rd_rel->relkind != RELKIND_RELATION)
1329  {
1330  if (part_rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
1331  ereport(WARNING,
1332  (errcode(ERRCODE_CHECK_VIOLATION),
1333  errmsg("skipped scanning foreign table \"%s\" which is a partition of default partition \"%s\"",
1334  RelationGetRelationName(part_rel),
1335  RelationGetRelationName(default_rel))));
1336 
1337  if (RelationGetRelid(default_rel) != RelationGetRelid(part_rel))
1338  table_close(part_rel, NoLock);
1339 
1340  continue;
1341  }
1342 
1343  estate = CreateExecutorState();
1344 
1345  /* Build expression execution states for partition check quals */
1346  partqualstate = ExecPrepareExpr(partition_constraint, estate);
1347 
1348  econtext = GetPerTupleExprContext(estate);
1349  snapshot = RegisterSnapshot(GetLatestSnapshot());
1350  tupslot = table_slot_create(part_rel, &estate->es_tupleTable);
1351  scan = table_beginscan(part_rel, snapshot, 0, NULL);
1352 
1353  /*
1354  * Switch to per-tuple memory context and reset it for each tuple
1355  * produced, so we don't leak memory.
1356  */
1358 
1359  while (table_scan_getnextslot(scan, ForwardScanDirection, tupslot))
1360  {
1361  econtext->ecxt_scantuple = tupslot;
1362 
1363  if (!ExecCheck(partqualstate, econtext))
1364  ereport(ERROR,
1365  (errcode(ERRCODE_CHECK_VIOLATION),
1366  errmsg("updated partition constraint for default partition \"%s\" would be violated by some row",
1367  RelationGetRelationName(default_rel))));
1368 
1369  ResetExprContext(econtext);
1371  }
1372 
1373  MemoryContextSwitchTo(oldCxt);
1374  table_endscan(scan);
1375  UnregisterSnapshot(snapshot);
1377  FreeExecutorState(estate);
1378 
1379  if (RelationGetRelid(default_rel) != RelationGetRelid(part_rel))
1380  table_close(part_rel, NoLock); /* keep the lock until commit */
1381  }
1382 }
1383 
1384 /*
1385  * get_hash_partition_greatest_modulus
1386  *
1387  * Returns the greatest modulus of the hash partition bound. The greatest
1388  * modulus will be at the end of the datums array because hash partitions are
1389  * arranged in the ascending order of their moduli and remainders.
1390  */
1391 int
1393 {
1394  Assert(bound && bound->strategy == PARTITION_STRATEGY_HASH);
1395  Assert(bound->datums && bound->ndatums > 0);
1396  Assert(DatumGetInt32(bound->datums[bound->ndatums - 1][0]) > 0);
1397 
1398  return DatumGetInt32(bound->datums[bound->ndatums - 1][0]);
1399 }
1400 
1401 /*
1402  * make_one_partition_rbound
1403  *
1404  * Return a PartitionRangeBound given a list of PartitionRangeDatum elements
1405  * and a flag telling whether the bound is lower or not. Made into a function
1406  * because there are multiple sites that want to use this facility.
1407  */
1408 static PartitionRangeBound *
1410 {
1411  PartitionRangeBound *bound;
1412  ListCell *lc;
1413  int i;
1414 
1415  Assert(datums != NIL);
1416 
1417  bound = (PartitionRangeBound *) palloc0(sizeof(PartitionRangeBound));
1418  bound->index = index;
1419  bound->datums = (Datum *) palloc0(key->partnatts * sizeof(Datum));
1420  bound->kind = (PartitionRangeDatumKind *) palloc0(key->partnatts *
1421  sizeof(PartitionRangeDatumKind));
1422  bound->lower = lower;
1423 
1424  i = 0;
1425  foreach(lc, datums)
1426  {
1428 
1429  /* What's contained in this range datum? */
1430  bound->kind[i] = datum->kind;
1431 
1432  if (datum->kind == PARTITION_RANGE_DATUM_VALUE)
1433  {
1434  Const *val = castNode(Const, datum->value);
1435 
1436  if (val->constisnull)
1437  elog(ERROR, "invalid range bound datum");
1438  bound->datums[i] = val->constvalue;
1439  }
1440 
1441  i++;
1442  }
1443 
1444  return bound;
1445 }
1446 
1447 /*
1448  * partition_rbound_cmp
1449  *
1450  * Return for two range bounds whether the 1st one (specified in datums1,
1451  * kind1, and lower1) is <, =, or > the bound specified in *b2.
1452  *
1453  * partnatts, partsupfunc and partcollation give the number of attributes in the
1454  * bounds to be compared, comparison function to be used and the collations of
1455  * attributes, respectively.
1456  *
1457  * Note that if the values of the two range bounds compare equal, then we take
1458  * into account whether they are upper or lower bounds, and an upper bound is
1459  * considered to be smaller than a lower bound. This is important to the way
1460  * that RelationBuildPartitionDesc() builds the PartitionBoundInfoData
1461  * structure, which only stores the upper bound of a common boundary between
1462  * two contiguous partitions.
1463  */
1464 static int32
1465 partition_rbound_cmp(int partnatts, FmgrInfo *partsupfunc,
1466  Oid *partcollation,
1467  Datum *datums1, PartitionRangeDatumKind *kind1,
1468  bool lower1, PartitionRangeBound *b2)
1469 {
1470  int32 cmpval = 0; /* placate compiler */
1471  int i;
1472  Datum *datums2 = b2->datums;
1473  PartitionRangeDatumKind *kind2 = b2->kind;
1474  bool lower2 = b2->lower;
1475 
1476  for (i = 0; i < partnatts; i++)
1477  {
1478  /*
1479  * First, handle cases where the column is unbounded, which should not
1480  * invoke the comparison procedure, and should not consider any later
1481  * columns. Note that the PartitionRangeDatumKind enum elements
1482  * compare the same way as the values they represent.
1483  */
1484  if (kind1[i] < kind2[i])
1485  return -1;
1486  else if (kind1[i] > kind2[i])
1487  return 1;
1488  else if (kind1[i] != PARTITION_RANGE_DATUM_VALUE)
1489 
1490  /*
1491  * The column bounds are both MINVALUE or both MAXVALUE. No later
1492  * columns should be considered, but we still need to compare
1493  * whether they are upper or lower bounds.
1494  */
1495  break;
1496 
1497  cmpval = DatumGetInt32(FunctionCall2Coll(&partsupfunc[i],
1498  partcollation[i],
1499  datums1[i],
1500  datums2[i]));
1501  if (cmpval != 0)
1502  break;
1503  }
1504 
1505  /*
1506  * If the comparison is anything other than equal, we're done. If they
1507  * compare equal though, we still have to consider whether the boundaries
1508  * are inclusive or exclusive. Exclusive one is considered smaller of the
1509  * two.
1510  */
1511  if (cmpval == 0 && lower1 != lower2)
1512  cmpval = lower1 ? 1 : -1;
1513 
1514  return cmpval;
1515 }
1516 
1517 /*
1518  * partition_rbound_datum_cmp
1519  *
1520  * Return whether range bound (specified in rb_datums and rb_kind)
1521  * is <, =, or > partition key of tuple (tuple_datums)
1522  *
1523  * n_tuple_datums, partsupfunc and partcollation give number of attributes in
1524  * the bounds to be compared, comparison function to be used and the collations
1525  * of attributes resp.
1526  *
1527  */
1528 int32
1529 partition_rbound_datum_cmp(FmgrInfo *partsupfunc, Oid *partcollation,
1530  Datum *rb_datums, PartitionRangeDatumKind *rb_kind,
1531  Datum *tuple_datums, int n_tuple_datums)
1532 {
1533  int i;
1534  int32 cmpval = -1;
1535 
1536  for (i = 0; i < n_tuple_datums; i++)
1537  {
1538  if (rb_kind[i] == PARTITION_RANGE_DATUM_MINVALUE)
1539  return -1;
1540  else if (rb_kind[i] == PARTITION_RANGE_DATUM_MAXVALUE)
1541  return 1;
1542 
1543  cmpval = DatumGetInt32(FunctionCall2Coll(&partsupfunc[i],
1544  partcollation[i],
1545  rb_datums[i],
1546  tuple_datums[i]));
1547  if (cmpval != 0)
1548  break;
1549  }
1550 
1551  return cmpval;
1552 }
1553 
1554 /*
1555  * partition_hbound_cmp
1556  *
1557  * Compares modulus first, then remainder if modulus is equal.
1558  */
1559 static int32
1560 partition_hbound_cmp(int modulus1, int remainder1, int modulus2, int remainder2)
1561 {
1562  if (modulus1 < modulus2)
1563  return -1;
1564  if (modulus1 > modulus2)
1565  return 1;
1566  if (modulus1 == modulus2 && remainder1 != remainder2)
1567  return (remainder1 > remainder2) ? 1 : -1;
1568  return 0;
1569 }
1570 
1571 /*
1572  * partition_list_bsearch
1573  * Returns the index of the greatest bound datum that is less than equal
1574  * to the given value or -1 if all of the bound datums are greater
1575  *
1576  * *is_equal is set to true if the bound datum at the returned index is equal
1577  * to the input value.
1578  */
1579 int
1580 partition_list_bsearch(FmgrInfo *partsupfunc, Oid *partcollation,
1581  PartitionBoundInfo boundinfo,
1582  Datum value, bool *is_equal)
1583 {
1584  int lo,
1585  hi,
1586  mid;
1587 
1588  lo = -1;
1589  hi = boundinfo->ndatums - 1;
1590  while (lo < hi)
1591  {
1592  int32 cmpval;
1593 
1594  mid = (lo + hi + 1) / 2;
1595  cmpval = DatumGetInt32(FunctionCall2Coll(&partsupfunc[0],
1596  partcollation[0],
1597  boundinfo->datums[mid][0],
1598  value));
1599  if (cmpval <= 0)
1600  {
1601  lo = mid;
1602  *is_equal = (cmpval == 0);
1603  if (*is_equal)
1604  break;
1605  }
1606  else
1607  hi = mid - 1;
1608  }
1609 
1610  return lo;
1611 }
1612 
1613 /*
1614  * partition_range_bsearch
1615  * Returns the index of the greatest range bound that is less than or
1616  * equal to the given range bound or -1 if all of the range bounds are
1617  * greater
1618  *
1619  * *is_equal is set to true if the range bound at the returned index is equal
1620  * to the input range bound
1621  */
1622 static int
1623 partition_range_bsearch(int partnatts, FmgrInfo *partsupfunc,
1624  Oid *partcollation,
1625  PartitionBoundInfo boundinfo,
1626  PartitionRangeBound *probe, bool *is_equal)
1627 {
1628  int lo,
1629  hi,
1630  mid;
1631 
1632  lo = -1;
1633  hi = boundinfo->ndatums - 1;
1634  while (lo < hi)
1635  {
1636  int32 cmpval;
1637 
1638  mid = (lo + hi + 1) / 2;
1639  cmpval = partition_rbound_cmp(partnatts, partsupfunc,
1640  partcollation,
1641  boundinfo->datums[mid],
1642  boundinfo->kind[mid],
1643  (boundinfo->indexes[mid] == -1),
1644  probe);
1645  if (cmpval <= 0)
1646  {
1647  lo = mid;
1648  *is_equal = (cmpval == 0);
1649 
1650  if (*is_equal)
1651  break;
1652  }
1653  else
1654  hi = mid - 1;
1655  }
1656 
1657  return lo;
1658 }
1659 
1660 /*
1661  * partition_range_bsearch
1662  * Returns the index of the greatest range bound that is less than or
1663  * equal to the given tuple or -1 if all of the range bounds are greater
1664  *
1665  * *is_equal is set to true if the range bound at the returned index is equal
1666  * to the input tuple.
1667  */
1668 int
1669 partition_range_datum_bsearch(FmgrInfo *partsupfunc, Oid *partcollation,
1670  PartitionBoundInfo boundinfo,
1671  int nvalues, Datum *values, bool *is_equal)
1672 {
1673  int lo,
1674  hi,
1675  mid;
1676 
1677  lo = -1;
1678  hi = boundinfo->ndatums - 1;
1679  while (lo < hi)
1680  {
1681  int32 cmpval;
1682 
1683  mid = (lo + hi + 1) / 2;
1684  cmpval = partition_rbound_datum_cmp(partsupfunc,
1685  partcollation,
1686  boundinfo->datums[mid],
1687  boundinfo->kind[mid],
1688  values,
1689  nvalues);
1690  if (cmpval <= 0)
1691  {
1692  lo = mid;
1693  *is_equal = (cmpval == 0);
1694 
1695  if (*is_equal)
1696  break;
1697  }
1698  else
1699  hi = mid - 1;
1700  }
1701 
1702  return lo;
1703 }
1704 
1705 /*
1706  * partition_hash_bsearch
1707  * Returns the index of the greatest (modulus, remainder) pair that is
1708  * less than or equal to the given (modulus, remainder) pair or -1 if
1709  * all of them are greater
1710  */
1711 int
1713  int modulus, int remainder)
1714 {
1715  int lo,
1716  hi,
1717  mid;
1718 
1719  lo = -1;
1720  hi = boundinfo->ndatums - 1;
1721  while (lo < hi)
1722  {
1723  int32 cmpval,
1724  bound_modulus,
1725  bound_remainder;
1726 
1727  mid = (lo + hi + 1) / 2;
1728  bound_modulus = DatumGetInt32(boundinfo->datums[mid][0]);
1729  bound_remainder = DatumGetInt32(boundinfo->datums[mid][1]);
1730  cmpval = partition_hbound_cmp(bound_modulus, bound_remainder,
1731  modulus, remainder);
1732  if (cmpval <= 0)
1733  {
1734  lo = mid;
1735 
1736  if (cmpval == 0)
1737  break;
1738  }
1739  else
1740  hi = mid - 1;
1741  }
1742 
1743  return lo;
1744 }
1745 
1746 /*
1747  * qsort_partition_hbound_cmp
1748  *
1749  * Hash bounds are sorted by modulus, then by remainder.
1750  */
1751 static int32
1752 qsort_partition_hbound_cmp(const void *a, const void *b)
1753 {
1754  PartitionHashBound *h1 = (*(PartitionHashBound *const *) a);
1755  PartitionHashBound *h2 = (*(PartitionHashBound *const *) b);
1756 
1757  return partition_hbound_cmp(h1->modulus, h1->remainder,
1758  h2->modulus, h2->remainder);
1759 }
1760 
1761 /*
1762  * qsort_partition_list_value_cmp
1763  *
1764  * Compare two list partition bound datums.
1765  */
1766 static int32
1767 qsort_partition_list_value_cmp(const void *a, const void *b, void *arg)
1768 {
1769  Datum val1 = (*(PartitionListValue *const *) a)->value,
1770  val2 = (*(PartitionListValue *const *) b)->value;
1771  PartitionKey key = (PartitionKey) arg;
1772 
1774  key->partcollation[0],
1775  val1, val2));
1776 }
1777 
1778 /*
1779  * qsort_partition_rbound_cmp
1780  *
1781  * Used when sorting range bounds across all range partitions.
1782  */
1783 static int32
1784 qsort_partition_rbound_cmp(const void *a, const void *b, void *arg)
1785 {
1786  PartitionRangeBound *b1 = (*(PartitionRangeBound *const *) a);
1787  PartitionRangeBound *b2 = (*(PartitionRangeBound *const *) b);
1788  PartitionKey key = (PartitionKey) arg;
1789 
1790  return partition_rbound_cmp(key->partnatts, key->partsupfunc,
1791  key->partcollation, b1->datums, b1->kind,
1792  b1->lower, b2);
1793 }
1794 
1795 /*
1796  * get_partition_bound_num_indexes
1797  *
1798  * Returns the number of the entries in the partition bound indexes array.
1799  */
1800 static int
1802 {
1803  int num_indexes;
1804 
1805  Assert(bound);
1806 
1807  switch (bound->strategy)
1808  {
1810 
1811  /*
1812  * The number of the entries in the indexes array is same as the
1813  * greatest modulus.
1814  */
1815  num_indexes = get_hash_partition_greatest_modulus(bound);
1816  break;
1817 
1819  num_indexes = bound->ndatums;
1820  break;
1821 
1823  /* Range partitioned table has an extra index. */
1824  num_indexes = bound->ndatums + 1;
1825  break;
1826 
1827  default:
1828  elog(ERROR, "unexpected partition strategy: %d",
1829  (int) bound->strategy);
1830  }
1831 
1832  return num_indexes;
1833 }
1834 
1835 /*
1836  * get_partition_operator
1837  *
1838  * Return oid of the operator of the given strategy for the given partition
1839  * key column. It is assumed that the partitioning key is of the same type as
1840  * the chosen partitioning opclass, or at least binary-compatible. In the
1841  * latter case, *need_relabel is set to true if the opclass is not of a
1842  * polymorphic type (indicating a RelabelType node needed on top), otherwise
1843  * false.
1844  */
1845 static Oid
1847  bool *need_relabel)
1848 {
1849  Oid operoid;
1850 
1851  /*
1852  * Get the operator in the partitioning opfamily using the opclass'
1853  * declared input type as both left- and righttype.
1854  */
1855  operoid = get_opfamily_member(key->partopfamily[col],
1856  key->partopcintype[col],
1857  key->partopcintype[col],
1858  strategy);
1859  if (!OidIsValid(operoid))
1860  elog(ERROR, "missing operator %d(%u,%u) in partition opfamily %u",
1861  strategy, key->partopcintype[col], key->partopcintype[col],
1862  key->partopfamily[col]);
1863 
1864  /*
1865  * If the partition key column is not of the same type as the operator
1866  * class and not polymorphic, tell caller to wrap the non-Const expression
1867  * in a RelabelType. This matches what parse_coerce.c does.
1868  */
1869  *need_relabel = (key->parttypid[col] != key->partopcintype[col] &&
1870  key->partopcintype[col] != RECORDOID &&
1871  !IsPolymorphicType(key->partopcintype[col]));
1872 
1873  return operoid;
1874 }
1875 
1876 /*
1877  * make_partition_op_expr
1878  * Returns an Expr for the given partition key column with arg1 and
1879  * arg2 as its leftop and rightop, respectively
1880  */
1881 static Expr *
1883  uint16 strategy, Expr *arg1, Expr *arg2)
1884 {
1885  Oid operoid;
1886  bool need_relabel = false;
1887  Expr *result = NULL;
1888 
1889  /* Get the correct btree operator for this partitioning column */
1890  operoid = get_partition_operator(key, keynum, strategy, &need_relabel);
1891 
1892  /*
1893  * Chosen operator may be such that the non-Const operand needs to be
1894  * coerced, so apply the same; see the comment in
1895  * get_partition_operator().
1896  */
1897  if (!IsA(arg1, Const) &&
1898  (need_relabel ||
1899  key->partcollation[keynum] != key->parttypcoll[keynum]))
1900  arg1 = (Expr *) makeRelabelType(arg1,
1901  key->partopcintype[keynum],
1902  -1,
1903  key->partcollation[keynum],
1905 
1906  /* Generate the actual expression */
1907  switch (key->strategy)
1908  {
1910  {
1911  List *elems = (List *) arg2;
1912  int nelems = list_length(elems);
1913 
1914  Assert(nelems >= 1);
1915  Assert(keynum == 0);
1916 
1917  if (nelems > 1 &&
1918  !type_is_array(key->parttypid[keynum]))
1919  {
1920  ArrayExpr *arrexpr;
1921  ScalarArrayOpExpr *saopexpr;
1922 
1923  /* Construct an ArrayExpr for the right-hand inputs */
1924  arrexpr = makeNode(ArrayExpr);
1925  arrexpr->array_typeid =
1926  get_array_type(key->parttypid[keynum]);
1927  arrexpr->array_collid = key->parttypcoll[keynum];
1928  arrexpr->element_typeid = key->parttypid[keynum];
1929  arrexpr->elements = elems;
1930  arrexpr->multidims = false;
1931  arrexpr->location = -1;
1932 
1933  /* Build leftop = ANY (rightop) */
1934  saopexpr = makeNode(ScalarArrayOpExpr);
1935  saopexpr->opno = operoid;
1936  saopexpr->opfuncid = get_opcode(operoid);
1937  saopexpr->useOr = true;
1938  saopexpr->inputcollid = key->partcollation[keynum];
1939  saopexpr->args = list_make2(arg1, arrexpr);
1940  saopexpr->location = -1;
1941 
1942  result = (Expr *) saopexpr;
1943  }
1944  else
1945  {
1946  List *elemops = NIL;
1947  ListCell *lc;
1948 
1949  foreach(lc, elems)
1950  {
1951  Expr *elem = lfirst(lc),
1952  *elemop;
1953 
1954  elemop = make_opclause(operoid,
1955  BOOLOID,
1956  false,
1957  arg1, elem,
1958  InvalidOid,
1959  key->partcollation[keynum]);
1960  elemops = lappend(elemops, elemop);
1961  }
1962 
1963  result = nelems > 1 ? makeBoolExpr(OR_EXPR, elemops, -1) : linitial(elemops);
1964  }
1965  break;
1966  }
1967 
1969  result = make_opclause(operoid,
1970  BOOLOID,
1971  false,
1972  arg1, arg2,
1973  InvalidOid,
1974  key->partcollation[keynum]);
1975  break;
1976 
1977  default:
1978  elog(ERROR, "invalid partitioning strategy");
1979  break;
1980  }
1981 
1982  return result;
1983 }
1984 
1985 /*
1986  * get_qual_for_hash
1987  *
1988  * Returns a CHECK constraint expression to use as a hash partition's
1989  * constraint, given the parent relation and partition bound structure.
1990  *
1991  * The partition constraint for a hash partition is always a call to the
1992  * built-in function satisfies_hash_partition().
1993  */
1994 static List *
1996 {
1998  FuncExpr *fexpr;
1999  Node *relidConst;
2000  Node *modulusConst;
2001  Node *remainderConst;
2002  List *args;
2003  ListCell *partexprs_item;
2004  int i;
2005 
2006  /* Fixed arguments. */
2007  relidConst = (Node *) makeConst(OIDOID,
2008  -1,
2009  InvalidOid,
2010  sizeof(Oid),
2012  false,
2013  true);
2014 
2015  modulusConst = (Node *) makeConst(INT4OID,
2016  -1,
2017  InvalidOid,
2018  sizeof(int32),
2019  Int32GetDatum(spec->modulus),
2020  false,
2021  true);
2022 
2023  remainderConst = (Node *) makeConst(INT4OID,
2024  -1,
2025  InvalidOid,
2026  sizeof(int32),
2027  Int32GetDatum(spec->remainder),
2028  false,
2029  true);
2030 
2031  args = list_make3(relidConst, modulusConst, remainderConst);
2032  partexprs_item = list_head(key->partexprs);
2033 
2034  /* Add an argument for each key column. */
2035  for (i = 0; i < key->partnatts; i++)
2036  {
2037  Node *keyCol;
2038 
2039  /* Left operand */
2040  if (key->partattrs[i] != 0)
2041  {
2042  keyCol = (Node *) makeVar(1,
2043  key->partattrs[i],
2044  key->parttypid[i],
2045  key->parttypmod[i],
2046  key->parttypcoll[i],
2047  0);
2048  }
2049  else
2050  {
2051  keyCol = (Node *) copyObject(lfirst(partexprs_item));
2052  partexprs_item = lnext(key->partexprs, partexprs_item);
2053  }
2054 
2055  args = lappend(args, keyCol);
2056  }
2057 
2058  fexpr = makeFuncExpr(F_SATISFIES_HASH_PARTITION,
2059  BOOLOID,
2060  args,
2061  InvalidOid,
2062  InvalidOid,
2064 
2065  return list_make1(fexpr);
2066 }
2067 
2068 /*
2069  * get_qual_for_list
2070  *
2071  * Returns an implicit-AND list of expressions to use as a list partition's
2072  * constraint, given the parent relation and partition bound structure.
2073  *
2074  * The function returns NIL for a default partition when it's the only
2075  * partition since in that case there is no constraint.
2076  */
2077 static List *
2079 {
2081  List *result;
2082  Expr *keyCol;
2083  Expr *opexpr;
2084  NullTest *nulltest;
2085  ListCell *cell;
2086  List *elems = NIL;
2087  bool list_has_null = false;
2088 
2089  /*
2090  * Only single-column list partitioning is supported, so we are worried
2091  * only about the partition key with index 0.
2092  */
2093  Assert(key->partnatts == 1);
2094 
2095  /* Construct Var or expression representing the partition column */
2096  if (key->partattrs[0] != 0)
2097  keyCol = (Expr *) makeVar(1,
2098  key->partattrs[0],
2099  key->parttypid[0],
2100  key->parttypmod[0],
2101  key->parttypcoll[0],
2102  0);
2103  else
2104  keyCol = (Expr *) copyObject(linitial(key->partexprs));
2105 
2106  /*
2107  * For default list partition, collect datums for all the partitions. The
2108  * default partition constraint should check that the partition key is
2109  * equal to none of those.
2110  */
2111  if (spec->is_default)
2112  {
2113  int i;
2114  int ndatums = 0;
2115  PartitionDesc pdesc = RelationGetPartitionDesc(parent);
2116  PartitionBoundInfo boundinfo = pdesc->boundinfo;
2117 
2118  if (boundinfo)
2119  {
2120  ndatums = boundinfo->ndatums;
2121 
2122  if (partition_bound_accepts_nulls(boundinfo))
2123  list_has_null = true;
2124  }
2125 
2126  /*
2127  * If default is the only partition, there need not be any partition
2128  * constraint on it.
2129  */
2130  if (ndatums == 0 && !list_has_null)
2131  return NIL;
2132 
2133  for (i = 0; i < ndatums; i++)
2134  {
2135  Const *val;
2136 
2137  /*
2138  * Construct Const from known-not-null datum. We must be careful
2139  * to copy the value, because our result has to be able to outlive
2140  * the relcache entry we're copying from.
2141  */
2142  val = makeConst(key->parttypid[0],
2143  key->parttypmod[0],
2144  key->parttypcoll[0],
2145  key->parttyplen[0],
2146  datumCopy(*boundinfo->datums[i],
2147  key->parttypbyval[0],
2148  key->parttyplen[0]),
2149  false, /* isnull */
2150  key->parttypbyval[0]);
2151 
2152  elems = lappend(elems, val);
2153  }
2154  }
2155  else
2156  {
2157  /*
2158  * Create list of Consts for the allowed values, excluding any nulls.
2159  */
2160  foreach(cell, spec->listdatums)
2161  {
2162  Const *val = castNode(Const, lfirst(cell));
2163 
2164  if (val->constisnull)
2165  list_has_null = true;
2166  else
2167  elems = lappend(elems, copyObject(val));
2168  }
2169  }
2170 
2171  if (elems)
2172  {
2173  /*
2174  * Generate the operator expression from the non-null partition
2175  * values.
2176  */
2178  keyCol, (Expr *) elems);
2179  }
2180  else
2181  {
2182  /*
2183  * If there are no partition values, we don't need an operator
2184  * expression.
2185  */
2186  opexpr = NULL;
2187  }
2188 
2189  if (!list_has_null)
2190  {
2191  /*
2192  * Gin up a "col IS NOT NULL" test that will be AND'd with the main
2193  * expression. This might seem redundant, but the partition routing
2194  * machinery needs it.
2195  */
2196  nulltest = makeNode(NullTest);
2197  nulltest->arg = keyCol;
2198  nulltest->nulltesttype = IS_NOT_NULL;
2199  nulltest->argisrow = false;
2200  nulltest->location = -1;
2201 
2202  result = opexpr ? list_make2(nulltest, opexpr) : list_make1(nulltest);
2203  }
2204  else
2205  {
2206  /*
2207  * Gin up a "col IS NULL" test that will be OR'd with the main
2208  * expression.
2209  */
2210  nulltest = makeNode(NullTest);
2211  nulltest->arg = keyCol;
2212  nulltest->nulltesttype = IS_NULL;
2213  nulltest->argisrow = false;
2214  nulltest->location = -1;
2215 
2216  if (opexpr)
2217  {
2218  Expr *or;
2219 
2220  or = makeBoolExpr(OR_EXPR, list_make2(nulltest, opexpr), -1);
2221  result = list_make1(or);
2222  }
2223  else
2224  result = list_make1(nulltest);
2225  }
2226 
2227  /*
2228  * Note that, in general, applying NOT to a constraint expression doesn't
2229  * necessarily invert the set of rows it accepts, because NOT (NULL) is
2230  * NULL. However, the partition constraints we construct here never
2231  * evaluate to NULL, so applying NOT works as intended.
2232  */
2233  if (spec->is_default)
2234  {
2235  result = list_make1(make_ands_explicit(result));
2236  result = list_make1(makeBoolExpr(NOT_EXPR, result, -1));
2237  }
2238 
2239  return result;
2240 }
2241 
2242 /*
2243  * get_qual_for_range
2244  *
2245  * Returns an implicit-AND list of expressions to use as a range partition's
2246  * constraint, given the parent relation and partition bound structure.
2247  *
2248  * For a multi-column range partition key, say (a, b, c), with (al, bl, cl)
2249  * as the lower bound tuple and (au, bu, cu) as the upper bound tuple, we
2250  * generate an expression tree of the following form:
2251  *
2252  * (a IS NOT NULL) and (b IS NOT NULL) and (c IS NOT NULL)
2253  * AND
2254  * (a > al OR (a = al AND b > bl) OR (a = al AND b = bl AND c >= cl))
2255  * AND
2256  * (a < au OR (a = au AND b < bu) OR (a = au AND b = bu AND c < cu))
2257  *
2258  * It is often the case that a prefix of lower and upper bound tuples contains
2259  * the same values, for example, (al = au), in which case, we will emit an
2260  * expression tree of the following form:
2261  *
2262  * (a IS NOT NULL) and (b IS NOT NULL) and (c IS NOT NULL)
2263  * AND
2264  * (a = al)
2265  * AND
2266  * (b > bl OR (b = bl AND c >= cl))
2267  * AND
2268  * (b < bu OR (b = bu AND c < cu))
2269  *
2270  * If a bound datum is either MINVALUE or MAXVALUE, these expressions are
2271  * simplified using the fact that any value is greater than MINVALUE and less
2272  * than MAXVALUE. So, for example, if cu = MAXVALUE, c < cu is automatically
2273  * true, and we need not emit any expression for it, and the last line becomes
2274  *
2275  * (b < bu) OR (b = bu), which is simplified to (b <= bu)
2276  *
2277  * In most common cases with only one partition column, say a, the following
2278  * expression tree will be generated: a IS NOT NULL AND a >= al AND a < au
2279  *
2280  * For default partition, it returns the negation of the constraints of all
2281  * the other partitions.
2282  *
2283  * External callers should pass for_default as false; we set it to true only
2284  * when recursing.
2285  */
2286 static List *
2288  bool for_default)
2289 {
2290  List *result = NIL;
2291  ListCell *cell1,
2292  *cell2,
2293  *partexprs_item,
2294  *partexprs_item_saved;
2295  int i,
2296  j;
2297  PartitionRangeDatum *ldatum,
2298  *udatum;
2300  Expr *keyCol;
2301  Const *lower_val,
2302  *upper_val;
2303  List *lower_or_arms,
2304  *upper_or_arms;
2305  int num_or_arms,
2306  current_or_arm;
2307  ListCell *lower_or_start_datum,
2308  *upper_or_start_datum;
2309  bool need_next_lower_arm,
2310  need_next_upper_arm;
2311 
2312  if (spec->is_default)
2313  {
2314  List *or_expr_args = NIL;
2315  PartitionDesc pdesc = RelationGetPartitionDesc(parent);
2316  Oid *inhoids = pdesc->oids;
2317  int nparts = pdesc->nparts,
2318  i;
2319 
2320  for (i = 0; i < nparts; i++)
2321  {
2322  Oid inhrelid = inhoids[i];
2323  HeapTuple tuple;
2324  Datum datum;
2325  bool isnull;
2326  PartitionBoundSpec *bspec;
2327 
2328  tuple = SearchSysCache1(RELOID, inhrelid);
2329  if (!HeapTupleIsValid(tuple))
2330  elog(ERROR, "cache lookup failed for relation %u", inhrelid);
2331 
2332  datum = SysCacheGetAttr(RELOID, tuple,
2333  Anum_pg_class_relpartbound,
2334  &isnull);
2335  if (isnull)
2336  elog(ERROR, "null relpartbound for relation %u", inhrelid);
2337 
2338  bspec = (PartitionBoundSpec *)
2340  if (!IsA(bspec, PartitionBoundSpec))
2341  elog(ERROR, "expected PartitionBoundSpec");
2342 
2343  if (!bspec->is_default)
2344  {
2345  List *part_qual;
2346 
2347  part_qual = get_qual_for_range(parent, bspec, true);
2348 
2349  /*
2350  * AND the constraints of the partition and add to
2351  * or_expr_args
2352  */
2353  or_expr_args = lappend(or_expr_args, list_length(part_qual) > 1
2354  ? makeBoolExpr(AND_EXPR, part_qual, -1)
2355  : linitial(part_qual));
2356  }
2357  ReleaseSysCache(tuple);
2358  }
2359 
2360  if (or_expr_args != NIL)
2361  {
2362  Expr *other_parts_constr;
2363 
2364  /*
2365  * Combine the constraints obtained for non-default partitions
2366  * using OR. As requested, each of the OR's args doesn't include
2367  * the NOT NULL test for partition keys (which is to avoid its
2368  * useless repetition). Add the same now.
2369  */
2370  other_parts_constr =
2373  list_length(or_expr_args) > 1
2374  ? makeBoolExpr(OR_EXPR, or_expr_args,
2375  -1)
2376  : linitial(or_expr_args)),
2377  -1);
2378 
2379  /*
2380  * Finally, the default partition contains everything *NOT*
2381  * contained in the non-default partitions.
2382  */
2383  result = list_make1(makeBoolExpr(NOT_EXPR,
2384  list_make1(other_parts_constr), -1));
2385  }
2386 
2387  return result;
2388  }
2389 
2390  lower_or_start_datum = list_head(spec->lowerdatums);
2391  upper_or_start_datum = list_head(spec->upperdatums);
2392  num_or_arms = key->partnatts;
2393 
2394  /*
2395  * If it is the recursive call for default, we skip the get_range_nulltest
2396  * to avoid accumulating the NullTest on the same keys for each partition.
2397  */
2398  if (!for_default)
2399  result = get_range_nulltest(key);
2400 
2401  /*
2402  * Iterate over the key columns and check if the corresponding lower and
2403  * upper datums are equal using the btree equality operator for the
2404  * column's type. If equal, we emit single keyCol = common_value
2405  * expression. Starting from the first column for which the corresponding
2406  * lower and upper bound datums are not equal, we generate OR expressions
2407  * as shown in the function's header comment.
2408  */
2409  i = 0;
2410  partexprs_item = list_head(key->partexprs);
2411  partexprs_item_saved = partexprs_item; /* placate compiler */
2412  forboth(cell1, spec->lowerdatums, cell2, spec->upperdatums)
2413  {
2414  EState *estate;
2415  MemoryContext oldcxt;
2416  Expr *test_expr;
2417  ExprState *test_exprstate;
2418  Datum test_result;
2419  bool isNull;
2420 
2421  ldatum = castNode(PartitionRangeDatum, lfirst(cell1));
2422  udatum = castNode(PartitionRangeDatum, lfirst(cell2));
2423 
2424  /*
2425  * Since get_range_key_properties() modifies partexprs_item, and we
2426  * might need to start over from the previous expression in the later
2427  * part of this function, save away the current value.
2428  */
2429  partexprs_item_saved = partexprs_item;
2430 
2431  get_range_key_properties(key, i, ldatum, udatum,
2432  &partexprs_item,
2433  &keyCol,
2434  &lower_val, &upper_val);
2435 
2436  /*
2437  * If either value is NULL, the corresponding partition bound is
2438  * either MINVALUE or MAXVALUE, and we treat them as unequal, because
2439  * even if they're the same, there is no common value to equate the
2440  * key column with.
2441  */
2442  if (!lower_val || !upper_val)
2443  break;
2444 
2445  /* Create the test expression */
2446  estate = CreateExecutorState();
2447  oldcxt = MemoryContextSwitchTo(estate->es_query_cxt);
2448  test_expr = make_partition_op_expr(key, i, BTEqualStrategyNumber,
2449  (Expr *) lower_val,
2450  (Expr *) upper_val);
2451  fix_opfuncids((Node *) test_expr);
2452  test_exprstate = ExecInitExpr(test_expr, NULL);
2453  test_result = ExecEvalExprSwitchContext(test_exprstate,
2454  GetPerTupleExprContext(estate),
2455  &isNull);
2456  MemoryContextSwitchTo(oldcxt);
2457  FreeExecutorState(estate);
2458 
2459  /* If not equal, go generate the OR expressions */
2460  if (!DatumGetBool(test_result))
2461  break;
2462 
2463  /*
2464  * The bounds for the last key column can't be equal, because such a
2465  * range partition would never be allowed to be defined (it would have
2466  * an empty range otherwise).
2467  */
2468  if (i == key->partnatts - 1)
2469  elog(ERROR, "invalid range bound specification");
2470 
2471  /* Equal, so generate keyCol = lower_val expression */
2472  result = lappend(result,
2474  keyCol, (Expr *) lower_val));
2475 
2476  i++;
2477  }
2478 
2479  /* First pair of lower_val and upper_val that are not equal. */
2480  lower_or_start_datum = cell1;
2481  upper_or_start_datum = cell2;
2482 
2483  /* OR will have as many arms as there are key columns left. */
2484  num_or_arms = key->partnatts - i;
2485  current_or_arm = 0;
2486  lower_or_arms = upper_or_arms = NIL;
2487  need_next_lower_arm = need_next_upper_arm = true;
2488  while (current_or_arm < num_or_arms)
2489  {
2490  List *lower_or_arm_args = NIL,
2491  *upper_or_arm_args = NIL;
2492 
2493  /* Restart scan of columns from the i'th one */
2494  j = i;
2495  partexprs_item = partexprs_item_saved;
2496 
2497  for_both_cell(cell1, spec->lowerdatums, lower_or_start_datum,
2498  cell2, spec->upperdatums, upper_or_start_datum)
2499  {
2500  PartitionRangeDatum *ldatum_next = NULL,
2501  *udatum_next = NULL;
2502 
2503  ldatum = castNode(PartitionRangeDatum, lfirst(cell1));
2504  if (lnext(spec->lowerdatums, cell1))
2505  ldatum_next = castNode(PartitionRangeDatum,
2506  lfirst(lnext(spec->lowerdatums, cell1)));
2507  udatum = castNode(PartitionRangeDatum, lfirst(cell2));
2508  if (lnext(spec->upperdatums, cell2))
2509  udatum_next = castNode(PartitionRangeDatum,
2510  lfirst(lnext(spec->upperdatums, cell2)));
2511  get_range_key_properties(key, j, ldatum, udatum,
2512  &partexprs_item,
2513  &keyCol,
2514  &lower_val, &upper_val);
2515 
2516  if (need_next_lower_arm && lower_val)
2517  {
2518  uint16 strategy;
2519 
2520  /*
2521  * For the non-last columns of this arm, use the EQ operator.
2522  * For the last column of this arm, use GT, unless this is the
2523  * last column of the whole bound check, or the next bound
2524  * datum is MINVALUE, in which case use GE.
2525  */
2526  if (j - i < current_or_arm)
2527  strategy = BTEqualStrategyNumber;
2528  else if (j == key->partnatts - 1 ||
2529  (ldatum_next &&
2530  ldatum_next->kind == PARTITION_RANGE_DATUM_MINVALUE))
2531  strategy = BTGreaterEqualStrategyNumber;
2532  else
2533  strategy = BTGreaterStrategyNumber;
2534 
2535  lower_or_arm_args = lappend(lower_or_arm_args,
2536  make_partition_op_expr(key, j,
2537  strategy,
2538  keyCol,
2539  (Expr *) lower_val));
2540  }
2541 
2542  if (need_next_upper_arm && upper_val)
2543  {
2544  uint16 strategy;
2545 
2546  /*
2547  * For the non-last columns of this arm, use the EQ operator.
2548  * For the last column of this arm, use LT, unless the next
2549  * bound datum is MAXVALUE, in which case use LE.
2550  */
2551  if (j - i < current_or_arm)
2552  strategy = BTEqualStrategyNumber;
2553  else if (udatum_next &&
2554  udatum_next->kind == PARTITION_RANGE_DATUM_MAXVALUE)
2555  strategy = BTLessEqualStrategyNumber;
2556  else
2557  strategy = BTLessStrategyNumber;
2558 
2559  upper_or_arm_args = lappend(upper_or_arm_args,
2560  make_partition_op_expr(key, j,
2561  strategy,
2562  keyCol,
2563  (Expr *) upper_val));
2564  }
2565 
2566  /*
2567  * Did we generate enough of OR's arguments? First arm considers
2568  * the first of the remaining columns, second arm considers first
2569  * two of the remaining columns, and so on.
2570  */
2571  ++j;
2572  if (j - i > current_or_arm)
2573  {
2574  /*
2575  * We must not emit any more arms if the new column that will
2576  * be considered is unbounded, or this one was.
2577  */
2578  if (!lower_val || !ldatum_next ||
2579  ldatum_next->kind != PARTITION_RANGE_DATUM_VALUE)
2580  need_next_lower_arm = false;
2581  if (!upper_val || !udatum_next ||
2582  udatum_next->kind != PARTITION_RANGE_DATUM_VALUE)
2583  need_next_upper_arm = false;
2584  break;
2585  }
2586  }
2587 
2588  if (lower_or_arm_args != NIL)
2589  lower_or_arms = lappend(lower_or_arms,
2590  list_length(lower_or_arm_args) > 1
2591  ? makeBoolExpr(AND_EXPR, lower_or_arm_args, -1)
2592  : linitial(lower_or_arm_args));
2593 
2594  if (upper_or_arm_args != NIL)
2595  upper_or_arms = lappend(upper_or_arms,
2596  list_length(upper_or_arm_args) > 1
2597  ? makeBoolExpr(AND_EXPR, upper_or_arm_args, -1)
2598  : linitial(upper_or_arm_args));
2599 
2600  /* If no work to do in the next iteration, break away. */
2601  if (!need_next_lower_arm && !need_next_upper_arm)
2602  break;
2603 
2604  ++current_or_arm;
2605  }
2606 
2607  /*
2608  * Generate the OR expressions for each of lower and upper bounds (if
2609  * required), and append to the list of implicitly ANDed list of
2610  * expressions.
2611  */
2612  if (lower_or_arms != NIL)
2613  result = lappend(result,
2614  list_length(lower_or_arms) > 1
2615  ? makeBoolExpr(OR_EXPR, lower_or_arms, -1)
2616  : linitial(lower_or_arms));
2617  if (upper_or_arms != NIL)
2618  result = lappend(result,
2619  list_length(upper_or_arms) > 1
2620  ? makeBoolExpr(OR_EXPR, upper_or_arms, -1)
2621  : linitial(upper_or_arms));
2622 
2623  /*
2624  * As noted above, for non-default, we return list with constant TRUE. If
2625  * the result is NIL during the recursive call for default, it implies
2626  * this is the only other partition which can hold every value of the key
2627  * except NULL. Hence we return the NullTest result skipped earlier.
2628  */
2629  if (result == NIL)
2630  result = for_default
2631  ? get_range_nulltest(key)
2632  : list_make1(makeBoolConst(true, false));
2633 
2634  return result;
2635 }
2636 
2637 /*
2638  * get_range_key_properties
2639  * Returns range partition key information for a given column
2640  *
2641  * This is a subroutine for get_qual_for_range, and its API is pretty
2642  * specialized to that caller.
2643  *
2644  * Constructs an Expr for the key column (returned in *keyCol) and Consts
2645  * for the lower and upper range limits (returned in *lower_val and
2646  * *upper_val). For MINVALUE/MAXVALUE limits, NULL is returned instead of
2647  * a Const. All of these structures are freshly palloc'd.
2648  *
2649  * *partexprs_item points to the cell containing the next expression in
2650  * the key->partexprs list, or NULL. It may be advanced upon return.
2651  */
2652 static void
2654  PartitionRangeDatum *ldatum,
2655  PartitionRangeDatum *udatum,
2656  ListCell **partexprs_item,
2657  Expr **keyCol,
2658  Const **lower_val, Const **upper_val)
2659 {
2660  /* Get partition key expression for this column */
2661  if (key->partattrs[keynum] != 0)
2662  {
2663  *keyCol = (Expr *) makeVar(1,
2664  key->partattrs[keynum],
2665  key->parttypid[keynum],
2666  key->parttypmod[keynum],
2667  key->parttypcoll[keynum],
2668  0);
2669  }
2670  else
2671  {
2672  if (*partexprs_item == NULL)
2673  elog(ERROR, "wrong number of partition key expressions");
2674  *keyCol = copyObject(lfirst(*partexprs_item));
2675  *partexprs_item = lnext(key->partexprs, *partexprs_item);
2676  }
2677 
2678  /* Get appropriate Const nodes for the bounds */
2679  if (ldatum->kind == PARTITION_RANGE_DATUM_VALUE)
2680  *lower_val = castNode(Const, copyObject(ldatum->value));
2681  else
2682  *lower_val = NULL;
2683 
2684  if (udatum->kind == PARTITION_RANGE_DATUM_VALUE)
2685  *upper_val = castNode(Const, copyObject(udatum->value));
2686  else
2687  *upper_val = NULL;
2688 }
2689 
2690 /*
2691  * get_range_nulltest
2692  *
2693  * A non-default range partition table does not currently allow partition
2694  * keys to be null, so emit an IS NOT NULL expression for each key column.
2695  */
2696 static List *
2698 {
2699  List *result = NIL;
2700  NullTest *nulltest;
2701  ListCell *partexprs_item;
2702  int i;
2703 
2704  partexprs_item = list_head(key->partexprs);
2705  for (i = 0; i < key->partnatts; i++)
2706  {
2707  Expr *keyCol;
2708 
2709  if (key->partattrs[i] != 0)
2710  {
2711  keyCol = (Expr *) makeVar(1,
2712  key->partattrs[i],
2713  key->parttypid[i],
2714  key->parttypmod[i],
2715  key->parttypcoll[i],
2716  0);
2717  }
2718  else
2719  {
2720  if (partexprs_item == NULL)
2721  elog(ERROR, "wrong number of partition key expressions");
2722  keyCol = copyObject(lfirst(partexprs_item));
2723  partexprs_item = lnext(key->partexprs, partexprs_item);
2724  }
2725 
2726  nulltest = makeNode(NullTest);
2727  nulltest->arg = keyCol;
2728  nulltest->nulltesttype = IS_NOT_NULL;
2729  nulltest->argisrow = false;
2730  nulltest->location = -1;
2731  result = lappend(result, nulltest);
2732  }
2733 
2734  return result;
2735 }
2736 
2737 /*
2738  * compute_partition_hash_value
2739  *
2740  * Compute the hash value for given partition key values.
2741  */
2742 uint64
2743 compute_partition_hash_value(int partnatts, FmgrInfo *partsupfunc, Oid *partcollation,
2744  Datum *values, bool *isnull)
2745 {
2746  int i;
2747  uint64 rowHash = 0;
2749 
2750  for (i = 0; i < partnatts; i++)
2751  {
2752  /* Nulls are just ignored */
2753  if (!isnull[i])
2754  {
2755  Datum hash;
2756 
2757  Assert(OidIsValid(partsupfunc[i].fn_oid));
2758 
2759  /*
2760  * Compute hash for each datum value by calling respective
2761  * datatype-specific hash functions of each partition key
2762  * attribute.
2763  */
2764  hash = FunctionCall2Coll(&partsupfunc[i], partcollation[i],
2765  values[i], seed);
2766 
2767  /* Form a single 64-bit hash value */
2768  rowHash = hash_combine64(rowHash, DatumGetUInt64(hash));
2769  }
2770  }
2771 
2772  return rowHash;
2773 }
2774 
2775 /*
2776  * satisfies_hash_partition
2777  *
2778  * This is an SQL-callable function for use in hash partition constraints.
2779  * The first three arguments are the parent table OID, modulus, and remainder.
2780  * The remaining arguments are the value of the partitioning columns (or
2781  * expressions); these are hashed and the results are combined into a single
2782  * hash value by calling hash_combine64.
2783  *
2784  * Returns true if remainder produced when this computed single hash value is
2785  * divided by the given modulus is equal to given remainder, otherwise false.
2786  *
2787  * See get_qual_for_hash() for usage.
2788  */
2789 Datum
2791 {
2792  typedef struct ColumnsHashData
2793  {
2794  Oid relid;
2795  int nkeys;
2796  Oid variadic_type;
2797  int16 variadic_typlen;
2798  bool variadic_typbyval;
2799  char variadic_typalign;
2800  Oid partcollid[PARTITION_MAX_KEYS];
2801  FmgrInfo partsupfunc[FLEXIBLE_ARRAY_MEMBER];
2802  } ColumnsHashData;
2803  Oid parentId;
2804  int modulus;
2805  int remainder;
2807  ColumnsHashData *my_extra;
2808  uint64 rowHash = 0;
2809 
2810  /* Return null if the parent OID, modulus, or remainder is NULL. */
2811  if (PG_ARGISNULL(0) || PG_ARGISNULL(1) || PG_ARGISNULL(2))
2812  PG_RETURN_NULL();
2813  parentId = PG_GETARG_OID(0);
2814  modulus = PG_GETARG_INT32(1);
2815  remainder = PG_GETARG_INT32(2);
2816 
2817  /* Sanity check modulus and remainder. */
2818  if (modulus <= 0)
2819  ereport(ERROR,
2820  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2821  errmsg("modulus for hash partition must be a positive integer")));
2822  if (remainder < 0)
2823  ereport(ERROR,
2824  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2825  errmsg("remainder for hash partition must be a non-negative integer")));
2826  if (remainder >= modulus)
2827  ereport(ERROR,
2828  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2829  errmsg("remainder for hash partition must be less than modulus")));
2830 
2831  /*
2832  * Cache hash function information.
2833  */
2834  my_extra = (ColumnsHashData *) fcinfo->flinfo->fn_extra;
2835  if (my_extra == NULL || my_extra->relid != parentId)
2836  {
2837  Relation parent;
2838  PartitionKey key;
2839  int j;
2840 
2841  /* Open parent relation and fetch partition key info */
2842  parent = try_relation_open(parentId, AccessShareLock);
2843  if (parent == NULL)
2844  PG_RETURN_NULL();
2845  key = RelationGetPartitionKey(parent);
2846 
2847  /* Reject parent table that is not hash-partitioned. */
2848  if (parent->rd_rel->relkind != RELKIND_PARTITIONED_TABLE ||
2850  ereport(ERROR,
2851  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2852  errmsg("\"%s\" is not a hash partitioned table",
2853  get_rel_name(parentId))));
2854 
2855  if (!get_fn_expr_variadic(fcinfo->flinfo))
2856  {
2857  int nargs = PG_NARGS() - 3;
2858 
2859  /* complain if wrong number of column values */
2860  if (key->partnatts != nargs)
2861  ereport(ERROR,
2862  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2863  errmsg("number of partitioning columns (%d) does not match number of partition keys provided (%d)",
2864  key->partnatts, nargs)));
2865 
2866  /* allocate space for our cache */
2867  fcinfo->flinfo->fn_extra =
2868  MemoryContextAllocZero(fcinfo->flinfo->fn_mcxt,
2869  offsetof(ColumnsHashData, partsupfunc) +
2870  sizeof(FmgrInfo) * nargs);
2871  my_extra = (ColumnsHashData *) fcinfo->flinfo->fn_extra;
2872  my_extra->relid = parentId;
2873  my_extra->nkeys = key->partnatts;
2874  memcpy(my_extra->partcollid, key->partcollation,
2875  key->partnatts * sizeof(Oid));
2876 
2877  /* check argument types and save fmgr_infos */
2878  for (j = 0; j < key->partnatts; ++j)
2879  {
2880  Oid argtype = get_fn_expr_argtype(fcinfo->flinfo, j + 3);
2881 
2882  if (argtype != key->parttypid[j] && !IsBinaryCoercible(argtype, key->parttypid[j]))
2883  ereport(ERROR,
2884  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2885  errmsg("column %d of the partition key has type \"%s\", but supplied value is of type \"%s\"",
2886  j + 1, format_type_be(key->parttypid[j]), format_type_be(argtype))));
2887 
2888  fmgr_info_copy(&my_extra->partsupfunc[j],
2889  &key->partsupfunc[j],
2890  fcinfo->flinfo->fn_mcxt);
2891  }
2892  }
2893  else
2894  {
2895  ArrayType *variadic_array = PG_GETARG_ARRAYTYPE_P(3);
2896 
2897  /* allocate space for our cache -- just one FmgrInfo in this case */
2898  fcinfo->flinfo->fn_extra =
2899  MemoryContextAllocZero(fcinfo->flinfo->fn_mcxt,
2900  offsetof(ColumnsHashData, partsupfunc) +
2901  sizeof(FmgrInfo));
2902  my_extra = (ColumnsHashData *) fcinfo->flinfo->fn_extra;
2903  my_extra->relid = parentId;
2904  my_extra->nkeys = key->partnatts;
2905  my_extra->variadic_type = ARR_ELEMTYPE(variadic_array);
2906  get_typlenbyvalalign(my_extra->variadic_type,
2907  &my_extra->variadic_typlen,
2908  &my_extra->variadic_typbyval,
2909  &my_extra->variadic_typalign);
2910  my_extra->partcollid[0] = key->partcollation[0];
2911 
2912  /* check argument types */
2913  for (j = 0; j < key->partnatts; ++j)
2914  if (key->parttypid[j] != my_extra->variadic_type)
2915  ereport(ERROR,
2916  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2917  errmsg("column %d of the partition key has type \"%s\", but supplied value is of type \"%s\"",
2918  j + 1,
2919  format_type_be(key->parttypid[j]),
2920  format_type_be(my_extra->variadic_type))));
2921 
2922  fmgr_info_copy(&my_extra->partsupfunc[0],
2923  &key->partsupfunc[0],
2924  fcinfo->flinfo->fn_mcxt);
2925  }
2926 
2927  /* Hold lock until commit */
2928  relation_close(parent, NoLock);
2929  }
2930 
2931  if (!OidIsValid(my_extra->variadic_type))
2932  {
2933  int nkeys = my_extra->nkeys;
2934  int i;
2935 
2936  /*
2937  * For a non-variadic call, neither the number of arguments nor their
2938  * types can change across calls, so avoid the expense of rechecking
2939  * here.
2940  */
2941 
2942  for (i = 0; i < nkeys; i++)
2943  {
2944  Datum hash;
2945 
2946  /* keys start from fourth argument of function. */
2947  int argno = i + 3;
2948 
2949  if (PG_ARGISNULL(argno))
2950  continue;
2951 
2952  hash = FunctionCall2Coll(&my_extra->partsupfunc[i],
2953  my_extra->partcollid[i],
2954  PG_GETARG_DATUM(argno),
2955  seed);
2956 
2957  /* Form a single 64-bit hash value */
2958  rowHash = hash_combine64(rowHash, DatumGetUInt64(hash));
2959  }
2960  }
2961  else
2962  {
2963  ArrayType *variadic_array = PG_GETARG_ARRAYTYPE_P(3);
2964  int i;
2965  int nelems;
2966  Datum *datum;
2967  bool *isnull;
2968 
2969  deconstruct_array(variadic_array,
2970  my_extra->variadic_type,
2971  my_extra->variadic_typlen,
2972  my_extra->variadic_typbyval,
2973  my_extra->variadic_typalign,
2974  &datum, &isnull, &nelems);
2975 
2976  /* complain if wrong number of column values */
2977  if (nelems != my_extra->nkeys)
2978  ereport(ERROR,
2979  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2980  errmsg("number of partitioning columns (%d) does not match number of partition keys provided (%d)",
2981  my_extra->nkeys, nelems)));
2982 
2983  for (i = 0; i < nelems; i++)
2984  {
2985  Datum hash;
2986 
2987  if (isnull[i])
2988  continue;
2989 
2990  hash = FunctionCall2Coll(&my_extra->partsupfunc[0],
2991  my_extra->partcollid[0],
2992  datum[i],
2993  seed);
2994 
2995  /* Form a single 64-bit hash value */
2996  rowHash = hash_combine64(rowHash, DatumGetUInt64(hash));
2997  }
2998  }
2999 
3000  PG_RETURN_BOOL(rowHash % modulus == remainder);
3001 }
Datum constvalue
Definition: primnodes.h:214
TupleTableSlot * table_slot_create(Relation relation, List **reglist)
Definition: tableam.c:77
#define list_make2(x1, x2)
Definition: pg_list.h:229
#define list_make3(x1, x2, x3)
Definition: pg_list.h:231
signed short int16
Definition: c.h:346
bool multidims
Definition: primnodes.h:992
#define NIL
Definition: pg_list.h:65
#define PG_GETARG_INT32(n)
Definition: fmgr.h:264
Definition: fmgr.h:56
PartitionRangeDatumKind ** kind
Definition: partbounds.h:64
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
static int partition_range_bsearch(int partnatts, FmgrInfo *partsupfunc, Oid *partcollation, PartitionBoundInfo boundinfo, PartitionRangeBound *probe, bool *is_equal)
Definition: partbounds.c:1623
PartitionRangeDatumKind * kind
Definition: partbounds.c:67
static Datum ExecEvalExprSwitchContext(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:300
#define DEBUG1
Definition: elog.h:25
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
#define BTGreaterStrategyNumber
Definition: stratnum.h:33
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:419
MemoryContext fn_mcxt
Definition: fmgr.h:65
static int32 qsort_partition_hbound_cmp(const void *a, const void *b)
Definition: partbounds.c:1752
Snapshot RegisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:865
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:321
#define DatumGetInt32(X)
Definition: postgres.h:472
void check_new_partition_bound(char *relname, Relation parent, PartitionBoundSpec *spec)
Definition: partbounds.c:938
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:3018
Oid * partopfamily
Definition: partcache.h:33
Datum lower(PG_FUNCTION_ARGS)
Definition: oracle_compat.c:43
FmgrInfo * partsupfunc
Definition: partcache.h:35
#define castNode(_type_, nodeptr)
Definition: nodes.h:594
static List * get_qual_for_hash(Relation parent, PartitionBoundSpec *spec)
Definition: partbounds.c:1995
PartitionRangeDatumKind
Definition: parsenodes.h:834
void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, char *typalign)
Definition: lsyscache.c:2049
#define PG_GETARG_DATUM(n)
Definition: fmgr.h:263
Oid get_array_type(Oid typid)
Definition: lsyscache.c:2554
void fix_opfuncids(Node *node)
Definition: nodeFuncs.c:1587
#define UInt64GetDatum(X)
Definition: postgres.h:648
bool datumIsEqual(Datum value1, Datum value2, bool typByVal, int typLen)
Definition: datum.c:221
List * get_qual_from_partbound(Relation rel, Relation parent, PartitionBoundSpec *spec)
Definition: partbounds.c:117
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
PartitionRangeDatumKind kind
Definition: parsenodes.h:845
#define AccessShareLock
Definition: lockdefs.h:36
static struct @145 value
Definition: nodes.h:525
struct cursor * cur
Definition: ecpg.c:28
bool get_fn_expr_variadic(FmgrInfo *flinfo)
Definition: fmgr.c:1936
uint16 StrategyNumber
Definition: stratnum.h:22
int errcode(int sqlerrcode)
Definition: elog.c:608
static List * get_range_nulltest(PartitionKey key)
Definition: partbounds.c:2697
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:1784
#define PARTITION_MAX_KEYS
Oid array_typeid
Definition: primnodes.h:988
char * format_type_be(Oid type_oid)
Definition: format_type.c:326
Datum upper(PG_FUNCTION_ARGS)
Definition: oracle_compat.c:74
List * partexprs
Definition: partcache.h:30
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1150
static bool table_scan_getnextslot(TableScanDesc sscan, ScanDirection direction, TupleTableSlot *slot)
Definition: tableam.h:890
PartitionKey RelationGetPartitionKey(Relation rel)
Definition: partcache.c:54
struct PartitionRangeBound PartitionRangeBound
Form_pg_class rd_rel
Definition: rel.h:84
NameData relname
Definition: pg_class.h:35
unsigned int Oid
Definition: postgres_ext.h:31
Const * makeConst(Oid consttype, int32 consttypmod, Oid constcollid, int constlen, Datum constvalue, bool constisnull, bool constbyval)
Definition: makefuncs.c:297
#define OidIsValid(objectId)
Definition: c.h:645
ExprState * ExecPrepareExpr(Expr *node, EState *estate)
Definition: execExpr.c:490
Expr * make_opclause(Oid opno, Oid opresulttype, bool opretset, Expr *leftop, Expr *rightop, Oid opcollid, Oid inputcollid)
Definition: makefuncs.c:607
Relation try_relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:89
signed int int32
Definition: c.h:347
Expr * makeBoolExpr(BoolExprType boolop, List *args, int location)
Definition: makefuncs.c:367
PartitionBoundInfo boundinfo
Definition: partdesc.h:29
#define BTLessEqualStrategyNumber
Definition: stratnum.h:30
ParseState * make_parsestate(ParseState *parentParseState)
Definition: parse_node.c:43
Definition: type.h:89
#define list_make1(x1)
Definition: pg_list.h:227
void FreeExecutorState(EState *estate)
Definition: execUtils.c:190
static Expr * make_partition_op_expr(PartitionKey key, int keynum, uint16 strategy, Expr *arg1, Expr *arg2)
Definition: partbounds.c:1882
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:2653
#define GetPerTupleExprContext(estate)
Definition: executor.h:501
static PartitionRangeBound * make_one_partition_rbound(PartitionKey key, int index, List *datums, bool lower)
Definition: partbounds.c:1409
#define PG_GETARG_ARRAYTYPE_P(n)
Definition: array.h:251
int partition_range_datum_bsearch(FmgrInfo *partsupfunc, Oid *partcollation, PartitionBoundInfo boundinfo, int nvalues, Datum *values, bool *is_equal)
Definition: partbounds.c:1669
unsigned short uint16
Definition: c.h:358
void pfree(void *pointer)
Definition: mcxt.c:1056
MemoryContext es_query_cxt
Definition: execnodes.h:549
Oid * parttypcoll
Definition: partcache.h:46
#define linitial(l)
Definition: pg_list.h:195
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
static TableScanDesc table_beginscan(Relation rel, Snapshot snapshot, int nkeys, struct ScanKeyData *key)
Definition: tableam.h:754
Oid get_fn_expr_argtype(FmgrInfo *flinfo, int argnum)
Definition: fmgr.c:1802
Node * makeBoolConst(bool value, bool isnull)
Definition: makefuncs.c:355
Expr * arg
Definition: primnodes.h:1219
void check_default_partition_contents(Relation parent, Relation default_rel, PartitionBoundSpec *new_spec)
Definition: partbounds.c:1230
static PartitionBoundInfo create_hash_bounds(PartitionBoundSpec **boundspecs, int nparts, PartitionKey key, int **mapping)
Definition: partbounds.c:225
void fmgr_info_copy(FmgrInfo *dstinfo, FmgrInfo *srcinfo, MemoryContext destcxt)
Definition: fmgr.c:610
int get_hash_partition_greatest_modulus(PartitionBoundInfo bound)
Definition: partbounds.c:1392
char * c
static PartitionBoundInfo create_list_bounds(PartitionBoundSpec **boundspecs, int nparts, PartitionKey key, int **mapping)
Definition: partbounds.c:307
#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:1529
List * get_proposed_default_constraint(List *new_part_constraints)
Definition: partition.c:345
RelabelType * makeRelabelType(Expr *arg, Oid rtype, int32 rtypmod, Oid rcollid, CoercionForm rformat)
Definition: makefuncs.c:400
#define PG_GETARG_OID(n)
Definition: fmgr.h:270
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:1224
int errdetail(const char *fmt,...)
Definition: elog.c:955
Oid get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype, int16 strategy)
Definition: lsyscache.c:163
#define DatumGetBool(X)
Definition: postgres.h:393
static int32 partition_hbound_cmp(int modulus1, int remainder1, int modulus2, int remainder2)
Definition: partbounds.c:1560
PartitionDesc RelationGetPartitionDesc(Relation rel)
Definition: partdesc.c:65
#define RelationGetRelationName(relation)
Definition: rel.h:462
#define partition_bound_has_default(bi)
Definition: partbounds.h:75
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:1712
List * elements
Definition: primnodes.h:991
static int get_partition_bound_num_indexes(PartitionBoundInfo b)
Definition: partbounds.c:1801
#define ereport(elevel, rest)
Definition: elog.h:141
Var * makeVar(Index varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:66
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:130
EState * CreateExecutorState(void)
Definition: execUtils.c:88
char * get_range_partbound_string(List *bound_datums)
Definition: ruleutils.c:11338
void UnregisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:907
bool IsBinaryCoercible(Oid srctype, Oid targettype)
List * lappend(List *list, void *datum)
Definition: list.c:322
void qsort_arg(void *base, size_t nel, size_t elsize, qsort_arg_comparator cmp, void *arg)
Definition: qsort_arg.c:113
#define WARNING
Definition: elog.h:40
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1116
static uint64 hash_combine64(uint64 a, uint64 b)
Definition: hashutils.h:48
Oid * partcollation
Definition: partcache.h:38
#define TextDatumGetCString(d)
Definition: builtins.h:84
PartitionBoundInfo partition_bounds_copy(PartitionBoundInfo src, PartitionKey key)
Definition: partbounds.c:784
List * es_tupleTable
Definition: execnodes.h:551
void * palloc0(Size size)
Definition: mcxt.c:980
int location
Definition: primnodes.h:993
AttrNumber * partattrs
Definition: partcache.h:28
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:349
uintptr_t Datum
Definition: postgres.h:367
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1164
#define for_both_cell(cell1, list1, initcell1, cell2, list2, initcell2)
Definition: pg_list.h:441
Expr * make_ands_explicit(List *andclauses)
Definition: makefuncs.c:705
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1377
#define list_make1_oid(x1)
Definition: pg_list.h:249
static Oid get_partition_operator(PartitionKey key, int col, StrategyNumber strategy, bool *need_relabel)
Definition: partbounds.c:1846
#define PARTITION_STRATEGY_HASH
Definition: parsenodes.h:798
NullTestType nulltesttype
Definition: primnodes.h:1220
#define partition_bound_accepts_nulls(bi)
Definition: partbounds.h:74
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:839
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:1580
uint64 compute_partition_hash_value(int partnatts, FmgrInfo *partsupfunc, Oid *partcollation, Datum *values, bool *isnull)
Definition: partbounds.c:2743
#define InvalidOid
Definition: postgres_ext.h:36
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1092
static int32 partition_rbound_cmp(int partnatts, FmgrInfo *partsupfunc, Oid *partcollation, Datum *datums1, PartitionRangeDatumKind *kind1, bool lower1, PartitionRangeBound *b2)
Definition: partbounds.c:1465
static List * get_qual_for_range(Relation parent, PartitionBoundSpec *spec, bool for_default)
Definition: partbounds.c:2287
#define DatumGetUInt64(X)
Definition: postgres.h:634
#define makeNode(_type_)
Definition: nodes.h:573
bool partitions_are_ordered(PartitionBoundInfo boundinfo, int nparts)
Definition: partbounds.c:879
bool * parttypbyval
Definition: partcache.h:44
#define PG_ARGISNULL(n)
Definition: fmgr.h:204
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
#define Assert(condition)
Definition: c.h:739
#define lfirst(lc)
Definition: pg_list.h:190
int16 * parttyplen
Definition: partcache.h:43
Oid array_collid
Definition: primnodes.h:989
int location
Definition: primnodes.h:1222
static int list_length(const List *l)
Definition: pg_list.h:169
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:110
TupleTableSlot * ecxt_scantuple
Definition: execnodes.h:223
#define type_is_array(typid)
Definition: lsyscache.h:184
#define PG_NARGS()
Definition: fmgr.h:198
#define HASH_PARTITION_SEED
Definition: partition.h:20
#define PARTITION_STRATEGY_LIST
Definition: parsenodes.h:799
Snapshot GetLatestSnapshot(void)
Definition: snapmgr.c:381
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:506
Oid element_typeid
Definition: primnodes.h:990
void deconstruct_array(ArrayType *array, Oid elmtype, int elmlen, bool elmbyval, char elmalign, Datum **elemsp, bool **nullsp, int *nelemsp)
Definition: arrayfuncs.c:3461
static void table_endscan(TableScanDesc scan)
Definition: tableam.h:849
static Datum values[MAXATTR]
Definition: bootstrap.c:167
#define PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:800
#define AccessExclusiveLock
Definition: lockdefs.h:45
List * find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents)
Definition: pg_inherits.c:165
#define Int32GetDatum(X)
Definition: postgres.h:479
static PartitionBoundInfo create_range_bounds(PartitionBoundSpec **boundspecs, int nparts, PartitionKey key, int **mapping)
Definition: partbounds.c:464
void * palloc(Size size)
Definition: mcxt.c:949
int errmsg(const char *fmt,...)
Definition: elog.c:822
bool partition_bounds_equal(int partnatts, int16 *parttyplen, bool *parttypbyval, PartitionBoundInfo b1, PartitionBoundInfo b2)
Definition: partbounds.c:666
Oid * partopcintype
Definition: partcache.h:34
#define elog(elevel,...)
Definition: elog.h:228
int i
void * arg
bool ExecCheck(ExprState *state, ExprContext *econtext)
Definition: execExpr.c:597
bool argisrow
Definition: primnodes.h:1221
Datum satisfies_hash_partition(PG_FUNCTION_ARGS)
Definition: partbounds.c:2790
#define PG_FUNCTION_ARGS
Definition: fmgr.h:188
ExprState * ExecInitExpr(Expr *node, PlanState *parent)
Definition: execExpr.c:121
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:99
struct PartitionBoundInfoData * PartitionBoundInfo
Definition: partdefs.h:16
#define qsort(a, b, c, d)
Definition: port.h:491
#define copyObject(obj)
Definition: nodes.h:641
#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:1767
Definition: pg_list.h:50
static unsigned hash(unsigned *uv, int n)
Definition: rege_dfa.c:541
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1730
#define ARR_ELEMTYPE(a)
Definition: array.h:280
List * map_partition_varattnos(List *expr, int fromrel_varno, Relation to_rel, Relation from_rel)
Definition: partition.c:198
#define RelationGetRelid(relation)
Definition: rel.h:428
PartitionBoundInfo partition_bounds_create(PartitionBoundSpec **boundspecs, int nparts, PartitionKey key, int **mapping)
Definition: partbounds.c:172
long val
Definition: informix.c:664
#define PG_RETURN_NULL()
Definition: fmgr.h:335
static List * get_qual_for_list(Relation parent, PartitionBoundSpec *spec)
Definition: partbounds.c:2078
bool constisnull
Definition: primnodes.h:215
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define offsetof(type, field)
Definition: c.h:662
#define BTGreaterEqualStrategyNumber
Definition: stratnum.h:32
#define ResetExprContext(econtext)
Definition: executor.h:495
#define lfirst_oid(lc)
Definition: pg_list.h:192
bool PartConstraintImpliedByRelConstraint(Relation scanrel, List *partConstraint)
Definition: tablecmds.c:15766
FuncExpr * makeFuncExpr(Oid funcid, Oid rettype, List *args, Oid funccollid, Oid inputcollid, CoercionForm fformat)
Definition: makefuncs.c:517
struct PartitionKeyData * PartitionKey
Definition: partdefs.h:18
struct PartitionHashBound PartitionHashBound