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 "common/hashfn.h"
25 #include "executor/executor.h"
26 #include "miscadmin.h"
27 #include "nodes/makefuncs.h"
28 #include "nodes/nodeFuncs.h"
29 #include "parser/parse_coerce.h"
31 #include "partitioning/partdesc.h"
32 #include "partitioning/partprune.h"
33 #include "utils/builtins.h"
34 #include "utils/datum.h"
35 #include "utils/fmgroids.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  bool hash_part;
793  int natts;
794 
796 
797  dest->strategy = src->strategy;
798  ndatums = dest->ndatums = src->ndatums;
799  partnatts = key->partnatts;
800 
801  num_indexes = get_partition_bound_num_indexes(src);
802 
803  /* List partitioned tables have only a single partition key. */
804  Assert(key->strategy != PARTITION_STRATEGY_LIST || partnatts == 1);
805 
806  dest->datums = (Datum **) palloc(sizeof(Datum *) * ndatums);
807 
808  if (src->kind != NULL)
809  {
810  dest->kind = (PartitionRangeDatumKind **) palloc(ndatums *
811  sizeof(PartitionRangeDatumKind *));
812  for (i = 0; i < ndatums; i++)
813  {
814  dest->kind[i] = (PartitionRangeDatumKind *) palloc(partnatts *
815  sizeof(PartitionRangeDatumKind));
816 
817  memcpy(dest->kind[i], src->kind[i],
818  sizeof(PartitionRangeDatumKind) * key->partnatts);
819  }
820  }
821  else
822  dest->kind = NULL;
823 
824  /*
825  * For hash partitioning, datums array will have two elements - modulus and
826  * remainder.
827  */
828  hash_part = (key->strategy == PARTITION_STRATEGY_HASH);
829  natts = hash_part ? 2 : partnatts;
830 
831  for (i = 0; i < ndatums; i++)
832  {
833  int j;
834 
835  dest->datums[i] = (Datum *) palloc(sizeof(Datum) * natts);
836 
837  for (j = 0; j < natts; j++)
838  {
839  bool byval;
840  int typlen;
841 
842  if (hash_part)
843  {
844  typlen = sizeof(int32); /* Always int4 */
845  byval = true; /* int4 is pass-by-value */
846  }
847  else
848  {
849  byval = key->parttypbyval[j];
850  typlen = key->parttyplen[j];
851  }
852 
853  if (dest->kind == NULL ||
854  dest->kind[i][j] == PARTITION_RANGE_DATUM_VALUE)
855  dest->datums[i][j] = datumCopy(src->datums[i][j],
856  byval, typlen);
857  }
858  }
859 
860  dest->indexes = (int *) palloc(sizeof(int) * num_indexes);
861  memcpy(dest->indexes, src->indexes, sizeof(int) * num_indexes);
862 
863  dest->null_index = src->null_index;
864  dest->default_index = src->default_index;
865 
866  return dest;
867 }
868 
869 /*
870  * partitions_are_ordered
871  * Determine whether the partitions described by 'boundinfo' are ordered,
872  * that is partitions appearing earlier in the PartitionDesc sequence
873  * contain partition keys strictly less than those appearing later.
874  * Also, if NULL values are possible, they must come in the last
875  * partition defined in the PartitionDesc.
876  *
877  * If out of order, or there is insufficient info to know the order,
878  * then we return false.
879  */
880 bool
882 {
883  Assert(boundinfo != NULL);
884 
885  switch (boundinfo->strategy)
886  {
888 
889  /*
890  * RANGE-type partitioning guarantees that the partitions can be
891  * scanned in the order that they're defined in the PartitionDesc
892  * to provide sequential, non-overlapping ranges of tuples.
893  * However, if a DEFAULT partition exists then it doesn't work, as
894  * that could contain tuples from either below or above the
895  * defined range, or tuples belonging to gaps between partitions.
896  */
897  if (!partition_bound_has_default(boundinfo))
898  return true;
899  break;
900 
902 
903  /*
904  * LIST partitioning can also guarantee ordering, but only if the
905  * partitions don't accept interleaved values. We could likely
906  * check for this by looping over the PartitionBound's indexes
907  * array to check that the indexes are in order. For now, let's
908  * just keep it simple and just accept LIST partitioning when
909  * there's no DEFAULT partition, exactly one value per partition,
910  * and optionally a NULL partition that does not accept any other
911  * values. Such a NULL partition will come last in the
912  * PartitionDesc, and the other partitions will be properly
913  * ordered. This is a cheap test to make as it does not require
914  * any per-partition processing. Maybe we'd like to handle more
915  * complex cases in the future.
916  */
917  if (partition_bound_has_default(boundinfo))
918  return false;
919 
920  if (boundinfo->ndatums + partition_bound_accepts_nulls(boundinfo)
921  == nparts)
922  return true;
923  break;
924 
925  default:
926  /* HASH, or some other strategy */
927  break;
928  }
929 
930  return false;
931 }
932 
933 /*
934  * check_new_partition_bound
935  *
936  * Checks if the new partition's bound overlaps any of the existing partitions
937  * of parent. Also performs additional checks as necessary per strategy.
938  */
939 void
941  PartitionBoundSpec *spec)
942 {
944  PartitionDesc partdesc = RelationGetPartitionDesc(parent);
945  PartitionBoundInfo boundinfo = partdesc->boundinfo;
946  ParseState *pstate = make_parsestate(NULL);
947  int with = -1;
948  bool overlap = false;
949 
950  if (spec->is_default)
951  {
952  /*
953  * The default partition bound never conflicts with any other
954  * partition's; if that's what we're attaching, the only possible
955  * problem is that one already exists, so check for that and we're
956  * done.
957  */
958  if (boundinfo == NULL || !partition_bound_has_default(boundinfo))
959  return;
960 
961  /* Default partition already exists, error out. */
962  ereport(ERROR,
963  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
964  errmsg("partition \"%s\" conflicts with existing default partition \"%s\"",
965  relname, get_rel_name(partdesc->oids[boundinfo->default_index])),
966  parser_errposition(pstate, spec->location)));
967  }
968 
969  switch (key->strategy)
970  {
972  {
974  Assert(spec->remainder >= 0 && spec->remainder < spec->modulus);
975 
976  if (partdesc->nparts > 0)
977  {
978  Datum **datums = boundinfo->datums;
979  int ndatums = boundinfo->ndatums;
980  int greatest_modulus;
981  int remainder;
982  int offset;
983  bool valid_modulus = true;
984  int prev_modulus, /* Previous largest modulus */
985  next_modulus; /* Next largest modulus */
986 
987  /*
988  * Check rule that every modulus must be a factor of the
989  * next larger modulus. For example, if you have a bunch
990  * of partitions that all have modulus 5, you can add a
991  * new partition with modulus 10 or a new partition with
992  * modulus 15, but you cannot add both a partition with
993  * modulus 10 and a partition with modulus 15, because 10
994  * is not a factor of 15.
995  *
996  * Get the greatest (modulus, remainder) pair contained in
997  * boundinfo->datums that is less than or equal to the
998  * (spec->modulus, spec->remainder) pair.
999  */
1000  offset = partition_hash_bsearch(boundinfo,
1001  spec->modulus,
1002  spec->remainder);
1003  if (offset < 0)
1004  {
1005  next_modulus = DatumGetInt32(datums[0][0]);
1006  valid_modulus = (next_modulus % spec->modulus) == 0;
1007  }
1008  else
1009  {
1010  prev_modulus = DatumGetInt32(datums[offset][0]);
1011  valid_modulus = (spec->modulus % prev_modulus) == 0;
1012 
1013  if (valid_modulus && (offset + 1) < ndatums)
1014  {
1015  next_modulus = DatumGetInt32(datums[offset + 1][0]);
1016  valid_modulus = (next_modulus % spec->modulus) == 0;
1017  }
1018  }
1019 
1020  if (!valid_modulus)
1021  ereport(ERROR,
1022  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1023  errmsg("every hash partition modulus must be a factor of the next larger modulus")));
1024 
1025  greatest_modulus = get_hash_partition_greatest_modulus(boundinfo);
1026  remainder = spec->remainder;
1027 
1028  /*
1029  * Normally, the lowest remainder that could conflict with
1030  * the new partition is equal to the remainder specified
1031  * for the new partition, but when the new partition has a
1032  * modulus higher than any used so far, we need to adjust.
1033  */
1034  if (remainder >= greatest_modulus)
1035  remainder = remainder % greatest_modulus;
1036 
1037  /* Check every potentially-conflicting remainder. */
1038  do
1039  {
1040  if (boundinfo->indexes[remainder] != -1)
1041  {
1042  overlap = true;
1043  with = boundinfo->indexes[remainder];
1044  break;
1045  }
1046  remainder += spec->modulus;
1047  } while (remainder < greatest_modulus);
1048  }
1049 
1050  break;
1051  }
1052 
1054  {
1056 
1057  if (partdesc->nparts > 0)
1058  {
1059  ListCell *cell;
1060 
1061  Assert(boundinfo &&
1062  boundinfo->strategy == PARTITION_STRATEGY_LIST &&
1063  (boundinfo->ndatums > 0 ||
1064  partition_bound_accepts_nulls(boundinfo) ||
1065  partition_bound_has_default(boundinfo)));
1066 
1067  foreach(cell, spec->listdatums)
1068  {
1069  Const *val = castNode(Const, lfirst(cell));
1070 
1071  if (!val->constisnull)
1072  {
1073  int offset;
1074  bool equal;
1075 
1076  offset = partition_list_bsearch(&key->partsupfunc[0],
1077  key->partcollation,
1078  boundinfo,
1079  val->constvalue,
1080  &equal);
1081  if (offset >= 0 && equal)
1082  {
1083  overlap = true;
1084  with = boundinfo->indexes[offset];
1085  break;
1086  }
1087  }
1088  else if (partition_bound_accepts_nulls(boundinfo))
1089  {
1090  overlap = true;
1091  with = boundinfo->null_index;
1092  break;
1093  }
1094  }
1095  }
1096 
1097  break;
1098  }
1099 
1101  {
1103  *upper;
1104 
1106  lower = make_one_partition_rbound(key, -1, spec->lowerdatums, true);
1107  upper = make_one_partition_rbound(key, -1, spec->upperdatums, false);
1108 
1109  /*
1110  * First check if the resulting range would be empty with
1111  * specified lower and upper bounds
1112  */
1114  key->partcollation, lower->datums,
1115  lower->kind, true, upper) >= 0)
1116  {
1117  ereport(ERROR,
1118  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1119  errmsg("empty range bound specified for partition \"%s\"",
1120  relname),
1121  errdetail("Specified lower bound %s is greater than or equal to upper bound %s.",
1124  parser_errposition(pstate, spec->location)));
1125  }
1126 
1127  if (partdesc->nparts > 0)
1128  {
1129  int offset;
1130  bool equal;
1131 
1132  Assert(boundinfo &&
1133  boundinfo->strategy == PARTITION_STRATEGY_RANGE &&
1134  (boundinfo->ndatums > 0 ||
1135  partition_bound_has_default(boundinfo)));
1136 
1137  /*
1138  * Test whether the new lower bound (which is treated
1139  * inclusively as part of the new partition) lies inside
1140  * an existing partition, or in a gap.
1141  *
1142  * If it's inside an existing partition, the bound at
1143  * offset + 1 will be the upper bound of that partition,
1144  * and its index will be >= 0.
1145  *
1146  * If it's in a gap, the bound at offset + 1 will be the
1147  * lower bound of the next partition, and its index will
1148  * be -1. This is also true if there is no next partition,
1149  * since the index array is initialised with an extra -1
1150  * at the end.
1151  */
1152  offset = partition_range_bsearch(key->partnatts,
1153  key->partsupfunc,
1154  key->partcollation,
1155  boundinfo, lower,
1156  &equal);
1157 
1158  if (boundinfo->indexes[offset + 1] < 0)
1159  {
1160  /*
1161  * Check that the new partition will fit in the gap.
1162  * For it to fit, the new upper bound must be less
1163  * than or equal to the lower bound of the next
1164  * partition, if there is one.
1165  */
1166  if (offset + 1 < boundinfo->ndatums)
1167  {
1168  int32 cmpval;
1169  Datum *datums;
1171  bool is_lower;
1172 
1173  datums = boundinfo->datums[offset + 1];
1174  kind = boundinfo->kind[offset + 1];
1175  is_lower = (boundinfo->indexes[offset + 1] == -1);
1176 
1177  cmpval = partition_rbound_cmp(key->partnatts,
1178  key->partsupfunc,
1179  key->partcollation,
1180  datums, kind,
1181  is_lower, upper);
1182  if (cmpval < 0)
1183  {
1184  /*
1185  * The new partition overlaps with the
1186  * existing partition between offset + 1 and
1187  * offset + 2.
1188  */
1189  overlap = true;
1190  with = boundinfo->indexes[offset + 2];
1191  }
1192  }
1193  }
1194  else
1195  {
1196  /*
1197  * The new partition overlaps with the existing
1198  * partition between offset and offset + 1.
1199  */
1200  overlap = true;
1201  with = boundinfo->indexes[offset + 1];
1202  }
1203  }
1204 
1205  break;
1206  }
1207 
1208  default:
1209  elog(ERROR, "unexpected partition strategy: %d",
1210  (int) key->strategy);
1211  }
1212 
1213  if (overlap)
1214  {
1215  Assert(with >= 0);
1216  ereport(ERROR,
1217  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1218  errmsg("partition \"%s\" would overlap partition \"%s\"",
1219  relname, get_rel_name(partdesc->oids[with])),
1220  parser_errposition(pstate, spec->location)));
1221  }
1222 }
1223 
1224 /*
1225  * check_default_partition_contents
1226  *
1227  * This function checks if there exists a row in the default partition that
1228  * would properly belong to the new partition being added. If it finds one,
1229  * it throws an error.
1230  */
1231 void
1233  PartitionBoundSpec *new_spec)
1234 {
1235  List *new_part_constraints;
1236  List *def_part_constraints;
1237  List *all_parts;
1238  ListCell *lc;
1239 
1240  new_part_constraints = (new_spec->strategy == PARTITION_STRATEGY_LIST)
1241  ? get_qual_for_list(parent, new_spec)
1242  : get_qual_for_range(parent, new_spec, false);
1243  def_part_constraints =
1244  get_proposed_default_constraint(new_part_constraints);
1245 
1246  /*
1247  * Map the Vars in the constraint expression from parent's attnos to
1248  * default_rel's.
1249  */
1250  def_part_constraints =
1251  map_partition_varattnos(def_part_constraints, 1, default_rel,
1252  parent);
1253 
1254  /*
1255  * If the existing constraints on the default partition imply that it will
1256  * not contain any row that would belong to the new partition, we can
1257  * avoid scanning the default partition.
1258  */
1259  if (PartConstraintImpliedByRelConstraint(default_rel, def_part_constraints))
1260  {
1261  ereport(DEBUG1,
1262  (errmsg("updated partition constraint for default partition \"%s\" is implied by existing constraints",
1263  RelationGetRelationName(default_rel))));
1264  return;
1265  }
1266 
1267  /*
1268  * Scan the default partition and its subpartitions, and check for rows
1269  * that do not satisfy the revised partition constraints.
1270  */
1271  if (default_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1272  all_parts = find_all_inheritors(RelationGetRelid(default_rel),
1273  AccessExclusiveLock, NULL);
1274  else
1275  all_parts = list_make1_oid(RelationGetRelid(default_rel));
1276 
1277  foreach(lc, all_parts)
1278  {
1279  Oid part_relid = lfirst_oid(lc);
1280  Relation part_rel;
1281  Expr *partition_constraint;
1282  EState *estate;
1283  ExprState *partqualstate = NULL;
1284  Snapshot snapshot;
1285  ExprContext *econtext;
1286  TableScanDesc scan;
1287  MemoryContext oldCxt;
1288  TupleTableSlot *tupslot;
1289 
1290  /* Lock already taken above. */
1291  if (part_relid != RelationGetRelid(default_rel))
1292  {
1293  part_rel = table_open(part_relid, NoLock);
1294 
1295  /*
1296  * Map the Vars in the constraint expression from default_rel's
1297  * the sub-partition's.
1298  */
1299  partition_constraint = make_ands_explicit(def_part_constraints);
1300  partition_constraint = (Expr *)
1301  map_partition_varattnos((List *) partition_constraint, 1,
1302  part_rel, default_rel);
1303 
1304  /*
1305  * If the partition constraints on default partition child imply
1306  * that it will not contain any row that would belong to the new
1307  * partition, we can avoid scanning the child table.
1308  */
1310  def_part_constraints))
1311  {
1312  ereport(DEBUG1,
1313  (errmsg("updated partition constraint for default partition \"%s\" is implied by existing constraints",
1314  RelationGetRelationName(part_rel))));
1315 
1316  table_close(part_rel, NoLock);
1317  continue;
1318  }
1319  }
1320  else
1321  {
1322  part_rel = default_rel;
1323  partition_constraint = make_ands_explicit(def_part_constraints);
1324  }
1325 
1326  /*
1327  * Only RELKIND_RELATION relations (i.e. leaf partitions) need to be
1328  * scanned.
1329  */
1330  if (part_rel->rd_rel->relkind != RELKIND_RELATION)
1331  {
1332  if (part_rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
1333  ereport(WARNING,
1334  (errcode(ERRCODE_CHECK_VIOLATION),
1335  errmsg("skipped scanning foreign table \"%s\" which is a partition of default partition \"%s\"",
1336  RelationGetRelationName(part_rel),
1337  RelationGetRelationName(default_rel))));
1338 
1339  if (RelationGetRelid(default_rel) != RelationGetRelid(part_rel))
1340  table_close(part_rel, NoLock);
1341 
1342  continue;
1343  }
1344 
1345  estate = CreateExecutorState();
1346 
1347  /* Build expression execution states for partition check quals */
1348  partqualstate = ExecPrepareExpr(partition_constraint, estate);
1349 
1350  econtext = GetPerTupleExprContext(estate);
1351  snapshot = RegisterSnapshot(GetLatestSnapshot());
1352  tupslot = table_slot_create(part_rel, &estate->es_tupleTable);
1353  scan = table_beginscan(part_rel, snapshot, 0, NULL);
1354 
1355  /*
1356  * Switch to per-tuple memory context and reset it for each tuple
1357  * produced, so we don't leak memory.
1358  */
1360 
1361  while (table_scan_getnextslot(scan, ForwardScanDirection, tupslot))
1362  {
1363  econtext->ecxt_scantuple = tupslot;
1364 
1365  if (!ExecCheck(partqualstate, econtext))
1366  ereport(ERROR,
1367  (errcode(ERRCODE_CHECK_VIOLATION),
1368  errmsg("updated partition constraint for default partition \"%s\" would be violated by some row",
1369  RelationGetRelationName(default_rel)),
1370  errtable(default_rel)));
1371 
1372  ResetExprContext(econtext);
1374  }
1375 
1376  MemoryContextSwitchTo(oldCxt);
1377  table_endscan(scan);
1378  UnregisterSnapshot(snapshot);
1380  FreeExecutorState(estate);
1381 
1382  if (RelationGetRelid(default_rel) != RelationGetRelid(part_rel))
1383  table_close(part_rel, NoLock); /* keep the lock until commit */
1384  }
1385 }
1386 
1387 /*
1388  * get_hash_partition_greatest_modulus
1389  *
1390  * Returns the greatest modulus of the hash partition bound. The greatest
1391  * modulus will be at the end of the datums array because hash partitions are
1392  * arranged in the ascending order of their moduli and remainders.
1393  */
1394 int
1396 {
1397  Assert(bound && bound->strategy == PARTITION_STRATEGY_HASH);
1398  Assert(bound->datums && bound->ndatums > 0);
1399  Assert(DatumGetInt32(bound->datums[bound->ndatums - 1][0]) > 0);
1400 
1401  return DatumGetInt32(bound->datums[bound->ndatums - 1][0]);
1402 }
1403 
1404 /*
1405  * make_one_partition_rbound
1406  *
1407  * Return a PartitionRangeBound given a list of PartitionRangeDatum elements
1408  * and a flag telling whether the bound is lower or not. Made into a function
1409  * because there are multiple sites that want to use this facility.
1410  */
1411 static PartitionRangeBound *
1413 {
1414  PartitionRangeBound *bound;
1415  ListCell *lc;
1416  int i;
1417 
1418  Assert(datums != NIL);
1419 
1420  bound = (PartitionRangeBound *) palloc0(sizeof(PartitionRangeBound));
1421  bound->index = index;
1422  bound->datums = (Datum *) palloc0(key->partnatts * sizeof(Datum));
1423  bound->kind = (PartitionRangeDatumKind *) palloc0(key->partnatts *
1424  sizeof(PartitionRangeDatumKind));
1425  bound->lower = lower;
1426 
1427  i = 0;
1428  foreach(lc, datums)
1429  {
1431 
1432  /* What's contained in this range datum? */
1433  bound->kind[i] = datum->kind;
1434 
1435  if (datum->kind == PARTITION_RANGE_DATUM_VALUE)
1436  {
1437  Const *val = castNode(Const, datum->value);
1438 
1439  if (val->constisnull)
1440  elog(ERROR, "invalid range bound datum");
1441  bound->datums[i] = val->constvalue;
1442  }
1443 
1444  i++;
1445  }
1446 
1447  return bound;
1448 }
1449 
1450 /*
1451  * partition_rbound_cmp
1452  *
1453  * Return for two range bounds whether the 1st one (specified in datums1,
1454  * kind1, and lower1) is <, =, or > the bound specified in *b2.
1455  *
1456  * partnatts, partsupfunc and partcollation give the number of attributes in the
1457  * bounds to be compared, comparison function to be used and the collations of
1458  * attributes, respectively.
1459  *
1460  * Note that if the values of the two range bounds compare equal, then we take
1461  * into account whether they are upper or lower bounds, and an upper bound is
1462  * considered to be smaller than a lower bound. This is important to the way
1463  * that RelationBuildPartitionDesc() builds the PartitionBoundInfoData
1464  * structure, which only stores the upper bound of a common boundary between
1465  * two contiguous partitions.
1466  */
1467 static int32
1468 partition_rbound_cmp(int partnatts, FmgrInfo *partsupfunc,
1469  Oid *partcollation,
1470  Datum *datums1, PartitionRangeDatumKind *kind1,
1471  bool lower1, PartitionRangeBound *b2)
1472 {
1473  int32 cmpval = 0; /* placate compiler */
1474  int i;
1475  Datum *datums2 = b2->datums;
1476  PartitionRangeDatumKind *kind2 = b2->kind;
1477  bool lower2 = b2->lower;
1478 
1479  for (i = 0; i < partnatts; i++)
1480  {
1481  /*
1482  * First, handle cases where the column is unbounded, which should not
1483  * invoke the comparison procedure, and should not consider any later
1484  * columns. Note that the PartitionRangeDatumKind enum elements
1485  * compare the same way as the values they represent.
1486  */
1487  if (kind1[i] < kind2[i])
1488  return -1;
1489  else if (kind1[i] > kind2[i])
1490  return 1;
1491  else if (kind1[i] != PARTITION_RANGE_DATUM_VALUE)
1492 
1493  /*
1494  * The column bounds are both MINVALUE or both MAXVALUE. No later
1495  * columns should be considered, but we still need to compare
1496  * whether they are upper or lower bounds.
1497  */
1498  break;
1499 
1500  cmpval = DatumGetInt32(FunctionCall2Coll(&partsupfunc[i],
1501  partcollation[i],
1502  datums1[i],
1503  datums2[i]));
1504  if (cmpval != 0)
1505  break;
1506  }
1507 
1508  /*
1509  * If the comparison is anything other than equal, we're done. If they
1510  * compare equal though, we still have to consider whether the boundaries
1511  * are inclusive or exclusive. Exclusive one is considered smaller of the
1512  * two.
1513  */
1514  if (cmpval == 0 && lower1 != lower2)
1515  cmpval = lower1 ? 1 : -1;
1516 
1517  return cmpval;
1518 }
1519 
1520 /*
1521  * partition_rbound_datum_cmp
1522  *
1523  * Return whether range bound (specified in rb_datums and rb_kind)
1524  * is <, =, or > partition key of tuple (tuple_datums)
1525  *
1526  * n_tuple_datums, partsupfunc and partcollation give number of attributes in
1527  * the bounds to be compared, comparison function to be used and the collations
1528  * of attributes resp.
1529  *
1530  */
1531 int32
1532 partition_rbound_datum_cmp(FmgrInfo *partsupfunc, Oid *partcollation,
1533  Datum *rb_datums, PartitionRangeDatumKind *rb_kind,
1534  Datum *tuple_datums, int n_tuple_datums)
1535 {
1536  int i;
1537  int32 cmpval = -1;
1538 
1539  for (i = 0; i < n_tuple_datums; i++)
1540  {
1541  if (rb_kind[i] == PARTITION_RANGE_DATUM_MINVALUE)
1542  return -1;
1543  else if (rb_kind[i] == PARTITION_RANGE_DATUM_MAXVALUE)
1544  return 1;
1545 
1546  cmpval = DatumGetInt32(FunctionCall2Coll(&partsupfunc[i],
1547  partcollation[i],
1548  rb_datums[i],
1549  tuple_datums[i]));
1550  if (cmpval != 0)
1551  break;
1552  }
1553 
1554  return cmpval;
1555 }
1556 
1557 /*
1558  * partition_hbound_cmp
1559  *
1560  * Compares modulus first, then remainder if modulus is equal.
1561  */
1562 static int32
1563 partition_hbound_cmp(int modulus1, int remainder1, int modulus2, int remainder2)
1564 {
1565  if (modulus1 < modulus2)
1566  return -1;
1567  if (modulus1 > modulus2)
1568  return 1;
1569  if (modulus1 == modulus2 && remainder1 != remainder2)
1570  return (remainder1 > remainder2) ? 1 : -1;
1571  return 0;
1572 }
1573 
1574 /*
1575  * partition_list_bsearch
1576  * Returns the index of the greatest bound datum that is less than equal
1577  * to the given value or -1 if all of the bound datums are greater
1578  *
1579  * *is_equal is set to true if the bound datum at the returned index is equal
1580  * to the input value.
1581  */
1582 int
1583 partition_list_bsearch(FmgrInfo *partsupfunc, Oid *partcollation,
1584  PartitionBoundInfo boundinfo,
1585  Datum value, bool *is_equal)
1586 {
1587  int lo,
1588  hi,
1589  mid;
1590 
1591  lo = -1;
1592  hi = boundinfo->ndatums - 1;
1593  while (lo < hi)
1594  {
1595  int32 cmpval;
1596 
1597  mid = (lo + hi + 1) / 2;
1598  cmpval = DatumGetInt32(FunctionCall2Coll(&partsupfunc[0],
1599  partcollation[0],
1600  boundinfo->datums[mid][0],
1601  value));
1602  if (cmpval <= 0)
1603  {
1604  lo = mid;
1605  *is_equal = (cmpval == 0);
1606  if (*is_equal)
1607  break;
1608  }
1609  else
1610  hi = mid - 1;
1611  }
1612 
1613  return lo;
1614 }
1615 
1616 /*
1617  * partition_range_bsearch
1618  * Returns the index of the greatest range bound that is less than or
1619  * equal to the given range bound or -1 if all of the range bounds are
1620  * greater
1621  *
1622  * *is_equal is set to true if the range bound at the returned index is equal
1623  * to the input range bound
1624  */
1625 static int
1626 partition_range_bsearch(int partnatts, FmgrInfo *partsupfunc,
1627  Oid *partcollation,
1628  PartitionBoundInfo boundinfo,
1629  PartitionRangeBound *probe, bool *is_equal)
1630 {
1631  int lo,
1632  hi,
1633  mid;
1634 
1635  lo = -1;
1636  hi = boundinfo->ndatums - 1;
1637  while (lo < hi)
1638  {
1639  int32 cmpval;
1640 
1641  mid = (lo + hi + 1) / 2;
1642  cmpval = partition_rbound_cmp(partnatts, partsupfunc,
1643  partcollation,
1644  boundinfo->datums[mid],
1645  boundinfo->kind[mid],
1646  (boundinfo->indexes[mid] == -1),
1647  probe);
1648  if (cmpval <= 0)
1649  {
1650  lo = mid;
1651  *is_equal = (cmpval == 0);
1652 
1653  if (*is_equal)
1654  break;
1655  }
1656  else
1657  hi = mid - 1;
1658  }
1659 
1660  return lo;
1661 }
1662 
1663 /*
1664  * partition_range_bsearch
1665  * Returns the index of the greatest range bound that is less than or
1666  * equal to the given tuple or -1 if all of the range bounds are greater
1667  *
1668  * *is_equal is set to true if the range bound at the returned index is equal
1669  * to the input tuple.
1670  */
1671 int
1672 partition_range_datum_bsearch(FmgrInfo *partsupfunc, Oid *partcollation,
1673  PartitionBoundInfo boundinfo,
1674  int nvalues, Datum *values, bool *is_equal)
1675 {
1676  int lo,
1677  hi,
1678  mid;
1679 
1680  lo = -1;
1681  hi = boundinfo->ndatums - 1;
1682  while (lo < hi)
1683  {
1684  int32 cmpval;
1685 
1686  mid = (lo + hi + 1) / 2;
1687  cmpval = partition_rbound_datum_cmp(partsupfunc,
1688  partcollation,
1689  boundinfo->datums[mid],
1690  boundinfo->kind[mid],
1691  values,
1692  nvalues);
1693  if (cmpval <= 0)
1694  {
1695  lo = mid;
1696  *is_equal = (cmpval == 0);
1697 
1698  if (*is_equal)
1699  break;
1700  }
1701  else
1702  hi = mid - 1;
1703  }
1704 
1705  return lo;
1706 }
1707 
1708 /*
1709  * partition_hash_bsearch
1710  * Returns the index of the greatest (modulus, remainder) pair that is
1711  * less than or equal to the given (modulus, remainder) pair or -1 if
1712  * all of them are greater
1713  */
1714 int
1716  int modulus, int remainder)
1717 {
1718  int lo,
1719  hi,
1720  mid;
1721 
1722  lo = -1;
1723  hi = boundinfo->ndatums - 1;
1724  while (lo < hi)
1725  {
1726  int32 cmpval,
1727  bound_modulus,
1728  bound_remainder;
1729 
1730  mid = (lo + hi + 1) / 2;
1731  bound_modulus = DatumGetInt32(boundinfo->datums[mid][0]);
1732  bound_remainder = DatumGetInt32(boundinfo->datums[mid][1]);
1733  cmpval = partition_hbound_cmp(bound_modulus, bound_remainder,
1734  modulus, remainder);
1735  if (cmpval <= 0)
1736  {
1737  lo = mid;
1738 
1739  if (cmpval == 0)
1740  break;
1741  }
1742  else
1743  hi = mid - 1;
1744  }
1745 
1746  return lo;
1747 }
1748 
1749 /*
1750  * qsort_partition_hbound_cmp
1751  *
1752  * Hash bounds are sorted by modulus, then by remainder.
1753  */
1754 static int32
1755 qsort_partition_hbound_cmp(const void *a, const void *b)
1756 {
1757  PartitionHashBound *h1 = (*(PartitionHashBound *const *) a);
1758  PartitionHashBound *h2 = (*(PartitionHashBound *const *) b);
1759 
1760  return partition_hbound_cmp(h1->modulus, h1->remainder,
1761  h2->modulus, h2->remainder);
1762 }
1763 
1764 /*
1765  * qsort_partition_list_value_cmp
1766  *
1767  * Compare two list partition bound datums.
1768  */
1769 static int32
1770 qsort_partition_list_value_cmp(const void *a, const void *b, void *arg)
1771 {
1772  Datum val1 = (*(PartitionListValue *const *) a)->value,
1773  val2 = (*(PartitionListValue *const *) b)->value;
1774  PartitionKey key = (PartitionKey) arg;
1775 
1777  key->partcollation[0],
1778  val1, val2));
1779 }
1780 
1781 /*
1782  * qsort_partition_rbound_cmp
1783  *
1784  * Used when sorting range bounds across all range partitions.
1785  */
1786 static int32
1787 qsort_partition_rbound_cmp(const void *a, const void *b, void *arg)
1788 {
1789  PartitionRangeBound *b1 = (*(PartitionRangeBound *const *) a);
1790  PartitionRangeBound *b2 = (*(PartitionRangeBound *const *) b);
1791  PartitionKey key = (PartitionKey) arg;
1792 
1793  return partition_rbound_cmp(key->partnatts, key->partsupfunc,
1794  key->partcollation, b1->datums, b1->kind,
1795  b1->lower, b2);
1796 }
1797 
1798 /*
1799  * get_partition_bound_num_indexes
1800  *
1801  * Returns the number of the entries in the partition bound indexes array.
1802  */
1803 static int
1805 {
1806  int num_indexes;
1807 
1808  Assert(bound);
1809 
1810  switch (bound->strategy)
1811  {
1813 
1814  /*
1815  * The number of the entries in the indexes array is same as the
1816  * greatest modulus.
1817  */
1818  num_indexes = get_hash_partition_greatest_modulus(bound);
1819  break;
1820 
1822  num_indexes = bound->ndatums;
1823  break;
1824 
1826  /* Range partitioned table has an extra index. */
1827  num_indexes = bound->ndatums + 1;
1828  break;
1829 
1830  default:
1831  elog(ERROR, "unexpected partition strategy: %d",
1832  (int) bound->strategy);
1833  }
1834 
1835  return num_indexes;
1836 }
1837 
1838 /*
1839  * get_partition_operator
1840  *
1841  * Return oid of the operator of the given strategy for the given partition
1842  * key column. It is assumed that the partitioning key is of the same type as
1843  * the chosen partitioning opclass, or at least binary-compatible. In the
1844  * latter case, *need_relabel is set to true if the opclass is not of a
1845  * polymorphic type (indicating a RelabelType node needed on top), otherwise
1846  * false.
1847  */
1848 static Oid
1850  bool *need_relabel)
1851 {
1852  Oid operoid;
1853 
1854  /*
1855  * Get the operator in the partitioning opfamily using the opclass'
1856  * declared input type as both left- and righttype.
1857  */
1858  operoid = get_opfamily_member(key->partopfamily[col],
1859  key->partopcintype[col],
1860  key->partopcintype[col],
1861  strategy);
1862  if (!OidIsValid(operoid))
1863  elog(ERROR, "missing operator %d(%u,%u) in partition opfamily %u",
1864  strategy, key->partopcintype[col], key->partopcintype[col],
1865  key->partopfamily[col]);
1866 
1867  /*
1868  * If the partition key column is not of the same type as the operator
1869  * class and not polymorphic, tell caller to wrap the non-Const expression
1870  * in a RelabelType. This matches what parse_coerce.c does.
1871  */
1872  *need_relabel = (key->parttypid[col] != key->partopcintype[col] &&
1873  key->partopcintype[col] != RECORDOID &&
1874  !IsPolymorphicType(key->partopcintype[col]));
1875 
1876  return operoid;
1877 }
1878 
1879 /*
1880  * make_partition_op_expr
1881  * Returns an Expr for the given partition key column with arg1 and
1882  * arg2 as its leftop and rightop, respectively
1883  */
1884 static Expr *
1886  uint16 strategy, Expr *arg1, Expr *arg2)
1887 {
1888  Oid operoid;
1889  bool need_relabel = false;
1890  Expr *result = NULL;
1891 
1892  /* Get the correct btree operator for this partitioning column */
1893  operoid = get_partition_operator(key, keynum, strategy, &need_relabel);
1894 
1895  /*
1896  * Chosen operator may be such that the non-Const operand needs to be
1897  * coerced, so apply the same; see the comment in
1898  * get_partition_operator().
1899  */
1900  if (!IsA(arg1, Const) &&
1901  (need_relabel ||
1902  key->partcollation[keynum] != key->parttypcoll[keynum]))
1903  arg1 = (Expr *) makeRelabelType(arg1,
1904  key->partopcintype[keynum],
1905  -1,
1906  key->partcollation[keynum],
1908 
1909  /* Generate the actual expression */
1910  switch (key->strategy)
1911  {
1913  {
1914  List *elems = (List *) arg2;
1915  int nelems = list_length(elems);
1916 
1917  Assert(nelems >= 1);
1918  Assert(keynum == 0);
1919 
1920  if (nelems > 1 &&
1921  !type_is_array(key->parttypid[keynum]))
1922  {
1923  ArrayExpr *arrexpr;
1924  ScalarArrayOpExpr *saopexpr;
1925 
1926  /* Construct an ArrayExpr for the right-hand inputs */
1927  arrexpr = makeNode(ArrayExpr);
1928  arrexpr->array_typeid =
1929  get_array_type(key->parttypid[keynum]);
1930  arrexpr->array_collid = key->parttypcoll[keynum];
1931  arrexpr->element_typeid = key->parttypid[keynum];
1932  arrexpr->elements = elems;
1933  arrexpr->multidims = false;
1934  arrexpr->location = -1;
1935 
1936  /* Build leftop = ANY (rightop) */
1937  saopexpr = makeNode(ScalarArrayOpExpr);
1938  saopexpr->opno = operoid;
1939  saopexpr->opfuncid = get_opcode(operoid);
1940  saopexpr->useOr = true;
1941  saopexpr->inputcollid = key->partcollation[keynum];
1942  saopexpr->args = list_make2(arg1, arrexpr);
1943  saopexpr->location = -1;
1944 
1945  result = (Expr *) saopexpr;
1946  }
1947  else
1948  {
1949  List *elemops = NIL;
1950  ListCell *lc;
1951 
1952  foreach(lc, elems)
1953  {
1954  Expr *elem = lfirst(lc),
1955  *elemop;
1956 
1957  elemop = make_opclause(operoid,
1958  BOOLOID,
1959  false,
1960  arg1, elem,
1961  InvalidOid,
1962  key->partcollation[keynum]);
1963  elemops = lappend(elemops, elemop);
1964  }
1965 
1966  result = nelems > 1 ? makeBoolExpr(OR_EXPR, elemops, -1) : linitial(elemops);
1967  }
1968  break;
1969  }
1970 
1972  result = make_opclause(operoid,
1973  BOOLOID,
1974  false,
1975  arg1, arg2,
1976  InvalidOid,
1977  key->partcollation[keynum]);
1978  break;
1979 
1980  default:
1981  elog(ERROR, "invalid partitioning strategy");
1982  break;
1983  }
1984 
1985  return result;
1986 }
1987 
1988 /*
1989  * get_qual_for_hash
1990  *
1991  * Returns a CHECK constraint expression to use as a hash partition's
1992  * constraint, given the parent relation and partition bound structure.
1993  *
1994  * The partition constraint for a hash partition is always a call to the
1995  * built-in function satisfies_hash_partition().
1996  */
1997 static List *
1999 {
2001  FuncExpr *fexpr;
2002  Node *relidConst;
2003  Node *modulusConst;
2004  Node *remainderConst;
2005  List *args;
2006  ListCell *partexprs_item;
2007  int i;
2008 
2009  /* Fixed arguments. */
2010  relidConst = (Node *) makeConst(OIDOID,
2011  -1,
2012  InvalidOid,
2013  sizeof(Oid),
2015  false,
2016  true);
2017 
2018  modulusConst = (Node *) makeConst(INT4OID,
2019  -1,
2020  InvalidOid,
2021  sizeof(int32),
2022  Int32GetDatum(spec->modulus),
2023  false,
2024  true);
2025 
2026  remainderConst = (Node *) makeConst(INT4OID,
2027  -1,
2028  InvalidOid,
2029  sizeof(int32),
2030  Int32GetDatum(spec->remainder),
2031  false,
2032  true);
2033 
2034  args = list_make3(relidConst, modulusConst, remainderConst);
2035  partexprs_item = list_head(key->partexprs);
2036 
2037  /* Add an argument for each key column. */
2038  for (i = 0; i < key->partnatts; i++)
2039  {
2040  Node *keyCol;
2041 
2042  /* Left operand */
2043  if (key->partattrs[i] != 0)
2044  {
2045  keyCol = (Node *) makeVar(1,
2046  key->partattrs[i],
2047  key->parttypid[i],
2048  key->parttypmod[i],
2049  key->parttypcoll[i],
2050  0);
2051  }
2052  else
2053  {
2054  keyCol = (Node *) copyObject(lfirst(partexprs_item));
2055  partexprs_item = lnext(key->partexprs, partexprs_item);
2056  }
2057 
2058  args = lappend(args, keyCol);
2059  }
2060 
2061  fexpr = makeFuncExpr(F_SATISFIES_HASH_PARTITION,
2062  BOOLOID,
2063  args,
2064  InvalidOid,
2065  InvalidOid,
2067 
2068  return list_make1(fexpr);
2069 }
2070 
2071 /*
2072  * get_qual_for_list
2073  *
2074  * Returns an implicit-AND list of expressions to use as a list partition's
2075  * constraint, given the parent relation and partition bound structure.
2076  *
2077  * The function returns NIL for a default partition when it's the only
2078  * partition since in that case there is no constraint.
2079  */
2080 static List *
2082 {
2084  List *result;
2085  Expr *keyCol;
2086  Expr *opexpr;
2087  NullTest *nulltest;
2088  ListCell *cell;
2089  List *elems = NIL;
2090  bool list_has_null = false;
2091 
2092  /*
2093  * Only single-column list partitioning is supported, so we are worried
2094  * only about the partition key with index 0.
2095  */
2096  Assert(key->partnatts == 1);
2097 
2098  /* Construct Var or expression representing the partition column */
2099  if (key->partattrs[0] != 0)
2100  keyCol = (Expr *) makeVar(1,
2101  key->partattrs[0],
2102  key->parttypid[0],
2103  key->parttypmod[0],
2104  key->parttypcoll[0],
2105  0);
2106  else
2107  keyCol = (Expr *) copyObject(linitial(key->partexprs));
2108 
2109  /*
2110  * For default list partition, collect datums for all the partitions. The
2111  * default partition constraint should check that the partition key is
2112  * equal to none of those.
2113  */
2114  if (spec->is_default)
2115  {
2116  int i;
2117  int ndatums = 0;
2118  PartitionDesc pdesc = RelationGetPartitionDesc(parent);
2119  PartitionBoundInfo boundinfo = pdesc->boundinfo;
2120 
2121  if (boundinfo)
2122  {
2123  ndatums = boundinfo->ndatums;
2124 
2125  if (partition_bound_accepts_nulls(boundinfo))
2126  list_has_null = true;
2127  }
2128 
2129  /*
2130  * If default is the only partition, there need not be any partition
2131  * constraint on it.
2132  */
2133  if (ndatums == 0 && !list_has_null)
2134  return NIL;
2135 
2136  for (i = 0; i < ndatums; i++)
2137  {
2138  Const *val;
2139 
2140  /*
2141  * Construct Const from known-not-null datum. We must be careful
2142  * to copy the value, because our result has to be able to outlive
2143  * the relcache entry we're copying from.
2144  */
2145  val = makeConst(key->parttypid[0],
2146  key->parttypmod[0],
2147  key->parttypcoll[0],
2148  key->parttyplen[0],
2149  datumCopy(*boundinfo->datums[i],
2150  key->parttypbyval[0],
2151  key->parttyplen[0]),
2152  false, /* isnull */
2153  key->parttypbyval[0]);
2154 
2155  elems = lappend(elems, val);
2156  }
2157  }
2158  else
2159  {
2160  /*
2161  * Create list of Consts for the allowed values, excluding any nulls.
2162  */
2163  foreach(cell, spec->listdatums)
2164  {
2165  Const *val = castNode(Const, lfirst(cell));
2166 
2167  if (val->constisnull)
2168  list_has_null = true;
2169  else
2170  elems = lappend(elems, copyObject(val));
2171  }
2172  }
2173 
2174  if (elems)
2175  {
2176  /*
2177  * Generate the operator expression from the non-null partition
2178  * values.
2179  */
2181  keyCol, (Expr *) elems);
2182  }
2183  else
2184  {
2185  /*
2186  * If there are no partition values, we don't need an operator
2187  * expression.
2188  */
2189  opexpr = NULL;
2190  }
2191 
2192  if (!list_has_null)
2193  {
2194  /*
2195  * Gin up a "col IS NOT NULL" test that will be AND'd with the main
2196  * expression. This might seem redundant, but the partition routing
2197  * machinery needs it.
2198  */
2199  nulltest = makeNode(NullTest);
2200  nulltest->arg = keyCol;
2201  nulltest->nulltesttype = IS_NOT_NULL;
2202  nulltest->argisrow = false;
2203  nulltest->location = -1;
2204 
2205  result = opexpr ? list_make2(nulltest, opexpr) : list_make1(nulltest);
2206  }
2207  else
2208  {
2209  /*
2210  * Gin up a "col IS NULL" test that will be OR'd with the main
2211  * expression.
2212  */
2213  nulltest = makeNode(NullTest);
2214  nulltest->arg = keyCol;
2215  nulltest->nulltesttype = IS_NULL;
2216  nulltest->argisrow = false;
2217  nulltest->location = -1;
2218 
2219  if (opexpr)
2220  {
2221  Expr *or;
2222 
2223  or = makeBoolExpr(OR_EXPR, list_make2(nulltest, opexpr), -1);
2224  result = list_make1(or);
2225  }
2226  else
2227  result = list_make1(nulltest);
2228  }
2229 
2230  /*
2231  * Note that, in general, applying NOT to a constraint expression doesn't
2232  * necessarily invert the set of rows it accepts, because NOT (NULL) is
2233  * NULL. However, the partition constraints we construct here never
2234  * evaluate to NULL, so applying NOT works as intended.
2235  */
2236  if (spec->is_default)
2237  {
2238  result = list_make1(make_ands_explicit(result));
2239  result = list_make1(makeBoolExpr(NOT_EXPR, result, -1));
2240  }
2241 
2242  return result;
2243 }
2244 
2245 /*
2246  * get_qual_for_range
2247  *
2248  * Returns an implicit-AND list of expressions to use as a range partition's
2249  * constraint, given the parent relation and partition bound structure.
2250  *
2251  * For a multi-column range partition key, say (a, b, c), with (al, bl, cl)
2252  * as the lower bound tuple and (au, bu, cu) as the upper bound tuple, we
2253  * generate an expression tree of the following form:
2254  *
2255  * (a IS NOT NULL) and (b IS NOT NULL) and (c IS NOT NULL)
2256  * AND
2257  * (a > al OR (a = al AND b > bl) OR (a = al AND b = bl AND c >= cl))
2258  * AND
2259  * (a < au OR (a = au AND b < bu) OR (a = au AND b = bu AND c < cu))
2260  *
2261  * It is often the case that a prefix of lower and upper bound tuples contains
2262  * the same values, for example, (al = au), in which case, we will emit an
2263  * expression tree of the following form:
2264  *
2265  * (a IS NOT NULL) and (b IS NOT NULL) and (c IS NOT NULL)
2266  * AND
2267  * (a = al)
2268  * AND
2269  * (b > bl OR (b = bl AND c >= cl))
2270  * AND
2271  * (b < bu OR (b = bu AND c < cu))
2272  *
2273  * If a bound datum is either MINVALUE or MAXVALUE, these expressions are
2274  * simplified using the fact that any value is greater than MINVALUE and less
2275  * than MAXVALUE. So, for example, if cu = MAXVALUE, c < cu is automatically
2276  * true, and we need not emit any expression for it, and the last line becomes
2277  *
2278  * (b < bu) OR (b = bu), which is simplified to (b <= bu)
2279  *
2280  * In most common cases with only one partition column, say a, the following
2281  * expression tree will be generated: a IS NOT NULL AND a >= al AND a < au
2282  *
2283  * For default partition, it returns the negation of the constraints of all
2284  * the other partitions.
2285  *
2286  * External callers should pass for_default as false; we set it to true only
2287  * when recursing.
2288  */
2289 static List *
2291  bool for_default)
2292 {
2293  List *result = NIL;
2294  ListCell *cell1,
2295  *cell2,
2296  *partexprs_item,
2297  *partexprs_item_saved;
2298  int i,
2299  j;
2300  PartitionRangeDatum *ldatum,
2301  *udatum;
2303  Expr *keyCol;
2304  Const *lower_val,
2305  *upper_val;
2306  List *lower_or_arms,
2307  *upper_or_arms;
2308  int num_or_arms,
2309  current_or_arm;
2310  ListCell *lower_or_start_datum,
2311  *upper_or_start_datum;
2312  bool need_next_lower_arm,
2313  need_next_upper_arm;
2314 
2315  if (spec->is_default)
2316  {
2317  List *or_expr_args = NIL;
2318  PartitionDesc pdesc = RelationGetPartitionDesc(parent);
2319  Oid *inhoids = pdesc->oids;
2320  int nparts = pdesc->nparts,
2321  i;
2322 
2323  for (i = 0; i < nparts; i++)
2324  {
2325  Oid inhrelid = inhoids[i];
2326  HeapTuple tuple;
2327  Datum datum;
2328  bool isnull;
2329  PartitionBoundSpec *bspec;
2330 
2331  tuple = SearchSysCache1(RELOID, inhrelid);
2332  if (!HeapTupleIsValid(tuple))
2333  elog(ERROR, "cache lookup failed for relation %u", inhrelid);
2334 
2335  datum = SysCacheGetAttr(RELOID, tuple,
2336  Anum_pg_class_relpartbound,
2337  &isnull);
2338  if (isnull)
2339  elog(ERROR, "null relpartbound for relation %u", inhrelid);
2340 
2341  bspec = (PartitionBoundSpec *)
2343  if (!IsA(bspec, PartitionBoundSpec))
2344  elog(ERROR, "expected PartitionBoundSpec");
2345 
2346  if (!bspec->is_default)
2347  {
2348  List *part_qual;
2349 
2350  part_qual = get_qual_for_range(parent, bspec, true);
2351 
2352  /*
2353  * AND the constraints of the partition and add to
2354  * or_expr_args
2355  */
2356  or_expr_args = lappend(or_expr_args, list_length(part_qual) > 1
2357  ? makeBoolExpr(AND_EXPR, part_qual, -1)
2358  : linitial(part_qual));
2359  }
2360  ReleaseSysCache(tuple);
2361  }
2362 
2363  if (or_expr_args != NIL)
2364  {
2365  Expr *other_parts_constr;
2366 
2367  /*
2368  * Combine the constraints obtained for non-default partitions
2369  * using OR. As requested, each of the OR's args doesn't include
2370  * the NOT NULL test for partition keys (which is to avoid its
2371  * useless repetition). Add the same now.
2372  */
2373  other_parts_constr =
2376  list_length(or_expr_args) > 1
2377  ? makeBoolExpr(OR_EXPR, or_expr_args,
2378  -1)
2379  : linitial(or_expr_args)),
2380  -1);
2381 
2382  /*
2383  * Finally, the default partition contains everything *NOT*
2384  * contained in the non-default partitions.
2385  */
2386  result = list_make1(makeBoolExpr(NOT_EXPR,
2387  list_make1(other_parts_constr), -1));
2388  }
2389 
2390  return result;
2391  }
2392 
2393  lower_or_start_datum = list_head(spec->lowerdatums);
2394  upper_or_start_datum = list_head(spec->upperdatums);
2395  num_or_arms = key->partnatts;
2396 
2397  /*
2398  * If it is the recursive call for default, we skip the get_range_nulltest
2399  * to avoid accumulating the NullTest on the same keys for each partition.
2400  */
2401  if (!for_default)
2402  result = get_range_nulltest(key);
2403 
2404  /*
2405  * Iterate over the key columns and check if the corresponding lower and
2406  * upper datums are equal using the btree equality operator for the
2407  * column's type. If equal, we emit single keyCol = common_value
2408  * expression. Starting from the first column for which the corresponding
2409  * lower and upper bound datums are not equal, we generate OR expressions
2410  * as shown in the function's header comment.
2411  */
2412  i = 0;
2413  partexprs_item = list_head(key->partexprs);
2414  partexprs_item_saved = partexprs_item; /* placate compiler */
2415  forboth(cell1, spec->lowerdatums, cell2, spec->upperdatums)
2416  {
2417  EState *estate;
2418  MemoryContext oldcxt;
2419  Expr *test_expr;
2420  ExprState *test_exprstate;
2421  Datum test_result;
2422  bool isNull;
2423 
2424  ldatum = castNode(PartitionRangeDatum, lfirst(cell1));
2425  udatum = castNode(PartitionRangeDatum, lfirst(cell2));
2426 
2427  /*
2428  * Since get_range_key_properties() modifies partexprs_item, and we
2429  * might need to start over from the previous expression in the later
2430  * part of this function, save away the current value.
2431  */
2432  partexprs_item_saved = partexprs_item;
2433 
2434  get_range_key_properties(key, i, ldatum, udatum,
2435  &partexprs_item,
2436  &keyCol,
2437  &lower_val, &upper_val);
2438 
2439  /*
2440  * If either value is NULL, the corresponding partition bound is
2441  * either MINVALUE or MAXVALUE, and we treat them as unequal, because
2442  * even if they're the same, there is no common value to equate the
2443  * key column with.
2444  */
2445  if (!lower_val || !upper_val)
2446  break;
2447 
2448  /* Create the test expression */
2449  estate = CreateExecutorState();
2450  oldcxt = MemoryContextSwitchTo(estate->es_query_cxt);
2451  test_expr = make_partition_op_expr(key, i, BTEqualStrategyNumber,
2452  (Expr *) lower_val,
2453  (Expr *) upper_val);
2454  fix_opfuncids((Node *) test_expr);
2455  test_exprstate = ExecInitExpr(test_expr, NULL);
2456  test_result = ExecEvalExprSwitchContext(test_exprstate,
2457  GetPerTupleExprContext(estate),
2458  &isNull);
2459  MemoryContextSwitchTo(oldcxt);
2460  FreeExecutorState(estate);
2461 
2462  /* If not equal, go generate the OR expressions */
2463  if (!DatumGetBool(test_result))
2464  break;
2465 
2466  /*
2467  * The bounds for the last key column can't be equal, because such a
2468  * range partition would never be allowed to be defined (it would have
2469  * an empty range otherwise).
2470  */
2471  if (i == key->partnatts - 1)
2472  elog(ERROR, "invalid range bound specification");
2473 
2474  /* Equal, so generate keyCol = lower_val expression */
2475  result = lappend(result,
2477  keyCol, (Expr *) lower_val));
2478 
2479  i++;
2480  }
2481 
2482  /* First pair of lower_val and upper_val that are not equal. */
2483  lower_or_start_datum = cell1;
2484  upper_or_start_datum = cell2;
2485 
2486  /* OR will have as many arms as there are key columns left. */
2487  num_or_arms = key->partnatts - i;
2488  current_or_arm = 0;
2489  lower_or_arms = upper_or_arms = NIL;
2490  need_next_lower_arm = need_next_upper_arm = true;
2491  while (current_or_arm < num_or_arms)
2492  {
2493  List *lower_or_arm_args = NIL,
2494  *upper_or_arm_args = NIL;
2495 
2496  /* Restart scan of columns from the i'th one */
2497  j = i;
2498  partexprs_item = partexprs_item_saved;
2499 
2500  for_both_cell(cell1, spec->lowerdatums, lower_or_start_datum,
2501  cell2, spec->upperdatums, upper_or_start_datum)
2502  {
2503  PartitionRangeDatum *ldatum_next = NULL,
2504  *udatum_next = NULL;
2505 
2506  ldatum = castNode(PartitionRangeDatum, lfirst(cell1));
2507  if (lnext(spec->lowerdatums, cell1))
2508  ldatum_next = castNode(PartitionRangeDatum,
2509  lfirst(lnext(spec->lowerdatums, cell1)));
2510  udatum = castNode(PartitionRangeDatum, lfirst(cell2));
2511  if (lnext(spec->upperdatums, cell2))
2512  udatum_next = castNode(PartitionRangeDatum,
2513  lfirst(lnext(spec->upperdatums, cell2)));
2514  get_range_key_properties(key, j, ldatum, udatum,
2515  &partexprs_item,
2516  &keyCol,
2517  &lower_val, &upper_val);
2518 
2519  if (need_next_lower_arm && lower_val)
2520  {
2521  uint16 strategy;
2522 
2523  /*
2524  * For the non-last columns of this arm, use the EQ operator.
2525  * For the last column of this arm, use GT, unless this is the
2526  * last column of the whole bound check, or the next bound
2527  * datum is MINVALUE, in which case use GE.
2528  */
2529  if (j - i < current_or_arm)
2530  strategy = BTEqualStrategyNumber;
2531  else if (j == key->partnatts - 1 ||
2532  (ldatum_next &&
2533  ldatum_next->kind == PARTITION_RANGE_DATUM_MINVALUE))
2534  strategy = BTGreaterEqualStrategyNumber;
2535  else
2536  strategy = BTGreaterStrategyNumber;
2537 
2538  lower_or_arm_args = lappend(lower_or_arm_args,
2539  make_partition_op_expr(key, j,
2540  strategy,
2541  keyCol,
2542  (Expr *) lower_val));
2543  }
2544 
2545  if (need_next_upper_arm && upper_val)
2546  {
2547  uint16 strategy;
2548 
2549  /*
2550  * For the non-last columns of this arm, use the EQ operator.
2551  * For the last column of this arm, use LT, unless the next
2552  * bound datum is MAXVALUE, in which case use LE.
2553  */
2554  if (j - i < current_or_arm)
2555  strategy = BTEqualStrategyNumber;
2556  else if (udatum_next &&
2557  udatum_next->kind == PARTITION_RANGE_DATUM_MAXVALUE)
2558  strategy = BTLessEqualStrategyNumber;
2559  else
2560  strategy = BTLessStrategyNumber;
2561 
2562  upper_or_arm_args = lappend(upper_or_arm_args,
2563  make_partition_op_expr(key, j,
2564  strategy,
2565  keyCol,
2566  (Expr *) upper_val));
2567  }
2568 
2569  /*
2570  * Did we generate enough of OR's arguments? First arm considers
2571  * the first of the remaining columns, second arm considers first
2572  * two of the remaining columns, and so on.
2573  */
2574  ++j;
2575  if (j - i > current_or_arm)
2576  {
2577  /*
2578  * We must not emit any more arms if the new column that will
2579  * be considered is unbounded, or this one was.
2580  */
2581  if (!lower_val || !ldatum_next ||
2582  ldatum_next->kind != PARTITION_RANGE_DATUM_VALUE)
2583  need_next_lower_arm = false;
2584  if (!upper_val || !udatum_next ||
2585  udatum_next->kind != PARTITION_RANGE_DATUM_VALUE)
2586  need_next_upper_arm = false;
2587  break;
2588  }
2589  }
2590 
2591  if (lower_or_arm_args != NIL)
2592  lower_or_arms = lappend(lower_or_arms,
2593  list_length(lower_or_arm_args) > 1
2594  ? makeBoolExpr(AND_EXPR, lower_or_arm_args, -1)
2595  : linitial(lower_or_arm_args));
2596 
2597  if (upper_or_arm_args != NIL)
2598  upper_or_arms = lappend(upper_or_arms,
2599  list_length(upper_or_arm_args) > 1
2600  ? makeBoolExpr(AND_EXPR, upper_or_arm_args, -1)
2601  : linitial(upper_or_arm_args));
2602 
2603  /* If no work to do in the next iteration, break away. */
2604  if (!need_next_lower_arm && !need_next_upper_arm)
2605  break;
2606 
2607  ++current_or_arm;
2608  }
2609 
2610  /*
2611  * Generate the OR expressions for each of lower and upper bounds (if
2612  * required), and append to the list of implicitly ANDed list of
2613  * expressions.
2614  */
2615  if (lower_or_arms != NIL)
2616  result = lappend(result,
2617  list_length(lower_or_arms) > 1
2618  ? makeBoolExpr(OR_EXPR, lower_or_arms, -1)
2619  : linitial(lower_or_arms));
2620  if (upper_or_arms != NIL)
2621  result = lappend(result,
2622  list_length(upper_or_arms) > 1
2623  ? makeBoolExpr(OR_EXPR, upper_or_arms, -1)
2624  : linitial(upper_or_arms));
2625 
2626  /*
2627  * As noted above, for non-default, we return list with constant TRUE. If
2628  * the result is NIL during the recursive call for default, it implies
2629  * this is the only other partition which can hold every value of the key
2630  * except NULL. Hence we return the NullTest result skipped earlier.
2631  */
2632  if (result == NIL)
2633  result = for_default
2634  ? get_range_nulltest(key)
2635  : list_make1(makeBoolConst(true, false));
2636 
2637  return result;
2638 }
2639 
2640 /*
2641  * get_range_key_properties
2642  * Returns range partition key information for a given column
2643  *
2644  * This is a subroutine for get_qual_for_range, and its API is pretty
2645  * specialized to that caller.
2646  *
2647  * Constructs an Expr for the key column (returned in *keyCol) and Consts
2648  * for the lower and upper range limits (returned in *lower_val and
2649  * *upper_val). For MINVALUE/MAXVALUE limits, NULL is returned instead of
2650  * a Const. All of these structures are freshly palloc'd.
2651  *
2652  * *partexprs_item points to the cell containing the next expression in
2653  * the key->partexprs list, or NULL. It may be advanced upon return.
2654  */
2655 static void
2657  PartitionRangeDatum *ldatum,
2658  PartitionRangeDatum *udatum,
2659  ListCell **partexprs_item,
2660  Expr **keyCol,
2661  Const **lower_val, Const **upper_val)
2662 {
2663  /* Get partition key expression for this column */
2664  if (key->partattrs[keynum] != 0)
2665  {
2666  *keyCol = (Expr *) makeVar(1,
2667  key->partattrs[keynum],
2668  key->parttypid[keynum],
2669  key->parttypmod[keynum],
2670  key->parttypcoll[keynum],
2671  0);
2672  }
2673  else
2674  {
2675  if (*partexprs_item == NULL)
2676  elog(ERROR, "wrong number of partition key expressions");
2677  *keyCol = copyObject(lfirst(*partexprs_item));
2678  *partexprs_item = lnext(key->partexprs, *partexprs_item);
2679  }
2680 
2681  /* Get appropriate Const nodes for the bounds */
2682  if (ldatum->kind == PARTITION_RANGE_DATUM_VALUE)
2683  *lower_val = castNode(Const, copyObject(ldatum->value));
2684  else
2685  *lower_val = NULL;
2686 
2687  if (udatum->kind == PARTITION_RANGE_DATUM_VALUE)
2688  *upper_val = castNode(Const, copyObject(udatum->value));
2689  else
2690  *upper_val = NULL;
2691 }
2692 
2693 /*
2694  * get_range_nulltest
2695  *
2696  * A non-default range partition table does not currently allow partition
2697  * keys to be null, so emit an IS NOT NULL expression for each key column.
2698  */
2699 static List *
2701 {
2702  List *result = NIL;
2703  NullTest *nulltest;
2704  ListCell *partexprs_item;
2705  int i;
2706 
2707  partexprs_item = list_head(key->partexprs);
2708  for (i = 0; i < key->partnatts; i++)
2709  {
2710  Expr *keyCol;
2711 
2712  if (key->partattrs[i] != 0)
2713  {
2714  keyCol = (Expr *) makeVar(1,
2715  key->partattrs[i],
2716  key->parttypid[i],
2717  key->parttypmod[i],
2718  key->parttypcoll[i],
2719  0);
2720  }
2721  else
2722  {
2723  if (partexprs_item == NULL)
2724  elog(ERROR, "wrong number of partition key expressions");
2725  keyCol = copyObject(lfirst(partexprs_item));
2726  partexprs_item = lnext(key->partexprs, partexprs_item);
2727  }
2728 
2729  nulltest = makeNode(NullTest);
2730  nulltest->arg = keyCol;
2731  nulltest->nulltesttype = IS_NOT_NULL;
2732  nulltest->argisrow = false;
2733  nulltest->location = -1;
2734  result = lappend(result, nulltest);
2735  }
2736 
2737  return result;
2738 }
2739 
2740 /*
2741  * compute_partition_hash_value
2742  *
2743  * Compute the hash value for given partition key values.
2744  */
2745 uint64
2746 compute_partition_hash_value(int partnatts, FmgrInfo *partsupfunc, Oid *partcollation,
2747  Datum *values, bool *isnull)
2748 {
2749  int i;
2750  uint64 rowHash = 0;
2752 
2753  for (i = 0; i < partnatts; i++)
2754  {
2755  /* Nulls are just ignored */
2756  if (!isnull[i])
2757  {
2758  Datum hash;
2759 
2760  Assert(OidIsValid(partsupfunc[i].fn_oid));
2761 
2762  /*
2763  * Compute hash for each datum value by calling respective
2764  * datatype-specific hash functions of each partition key
2765  * attribute.
2766  */
2767  hash = FunctionCall2Coll(&partsupfunc[i], partcollation[i],
2768  values[i], seed);
2769 
2770  /* Form a single 64-bit hash value */
2771  rowHash = hash_combine64(rowHash, DatumGetUInt64(hash));
2772  }
2773  }
2774 
2775  return rowHash;
2776 }
2777 
2778 /*
2779  * satisfies_hash_partition
2780  *
2781  * This is an SQL-callable function for use in hash partition constraints.
2782  * The first three arguments are the parent table OID, modulus, and remainder.
2783  * The remaining arguments are the value of the partitioning columns (or
2784  * expressions); these are hashed and the results are combined into a single
2785  * hash value by calling hash_combine64.
2786  *
2787  * Returns true if remainder produced when this computed single hash value is
2788  * divided by the given modulus is equal to given remainder, otherwise false.
2789  *
2790  * See get_qual_for_hash() for usage.
2791  */
2792 Datum
2794 {
2795  typedef struct ColumnsHashData
2796  {
2797  Oid relid;
2798  int nkeys;
2799  Oid variadic_type;
2800  int16 variadic_typlen;
2801  bool variadic_typbyval;
2802  char variadic_typalign;
2803  Oid partcollid[PARTITION_MAX_KEYS];
2804  FmgrInfo partsupfunc[FLEXIBLE_ARRAY_MEMBER];
2805  } ColumnsHashData;
2806  Oid parentId;
2807  int modulus;
2808  int remainder;
2810  ColumnsHashData *my_extra;
2811  uint64 rowHash = 0;
2812 
2813  /* Return null if the parent OID, modulus, or remainder is NULL. */
2814  if (PG_ARGISNULL(0) || PG_ARGISNULL(1) || PG_ARGISNULL(2))
2815  PG_RETURN_NULL();
2816  parentId = PG_GETARG_OID(0);
2817  modulus = PG_GETARG_INT32(1);
2818  remainder = PG_GETARG_INT32(2);
2819 
2820  /* Sanity check modulus and remainder. */
2821  if (modulus <= 0)
2822  ereport(ERROR,
2823  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2824  errmsg("modulus for hash partition must be a positive integer")));
2825  if (remainder < 0)
2826  ereport(ERROR,
2827  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2828  errmsg("remainder for hash partition must be a non-negative integer")));
2829  if (remainder >= modulus)
2830  ereport(ERROR,
2831  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2832  errmsg("remainder for hash partition must be less than modulus")));
2833 
2834  /*
2835  * Cache hash function information.
2836  */
2837  my_extra = (ColumnsHashData *) fcinfo->flinfo->fn_extra;
2838  if (my_extra == NULL || my_extra->relid != parentId)
2839  {
2840  Relation parent;
2841  PartitionKey key;
2842  int j;
2843 
2844  /* Open parent relation and fetch partition key info */
2845  parent = try_relation_open(parentId, AccessShareLock);
2846  if (parent == NULL)
2847  PG_RETURN_NULL();
2848  key = RelationGetPartitionKey(parent);
2849 
2850  /* Reject parent table that is not hash-partitioned. */
2851  if (parent->rd_rel->relkind != RELKIND_PARTITIONED_TABLE ||
2853  ereport(ERROR,
2854  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2855  errmsg("\"%s\" is not a hash partitioned table",
2856  get_rel_name(parentId))));
2857 
2858  if (!get_fn_expr_variadic(fcinfo->flinfo))
2859  {
2860  int nargs = PG_NARGS() - 3;
2861 
2862  /* complain if wrong number of column values */
2863  if (key->partnatts != nargs)
2864  ereport(ERROR,
2865  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2866  errmsg("number of partitioning columns (%d) does not match number of partition keys provided (%d)",
2867  key->partnatts, nargs)));
2868 
2869  /* allocate space for our cache */
2870  fcinfo->flinfo->fn_extra =
2871  MemoryContextAllocZero(fcinfo->flinfo->fn_mcxt,
2872  offsetof(ColumnsHashData, partsupfunc) +
2873  sizeof(FmgrInfo) * nargs);
2874  my_extra = (ColumnsHashData *) fcinfo->flinfo->fn_extra;
2875  my_extra->relid = parentId;
2876  my_extra->nkeys = key->partnatts;
2877  memcpy(my_extra->partcollid, key->partcollation,
2878  key->partnatts * sizeof(Oid));
2879 
2880  /* check argument types and save fmgr_infos */
2881  for (j = 0; j < key->partnatts; ++j)
2882  {
2883  Oid argtype = get_fn_expr_argtype(fcinfo->flinfo, j + 3);
2884 
2885  if (argtype != key->parttypid[j] && !IsBinaryCoercible(argtype, key->parttypid[j]))
2886  ereport(ERROR,
2887  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2888  errmsg("column %d of the partition key has type \"%s\", but supplied value is of type \"%s\"",
2889  j + 1, format_type_be(key->parttypid[j]), format_type_be(argtype))));
2890 
2891  fmgr_info_copy(&my_extra->partsupfunc[j],
2892  &key->partsupfunc[j],
2893  fcinfo->flinfo->fn_mcxt);
2894  }
2895  }
2896  else
2897  {
2898  ArrayType *variadic_array = PG_GETARG_ARRAYTYPE_P(3);
2899 
2900  /* allocate space for our cache -- just one FmgrInfo in this case */
2901  fcinfo->flinfo->fn_extra =
2902  MemoryContextAllocZero(fcinfo->flinfo->fn_mcxt,
2903  offsetof(ColumnsHashData, partsupfunc) +
2904  sizeof(FmgrInfo));
2905  my_extra = (ColumnsHashData *) fcinfo->flinfo->fn_extra;
2906  my_extra->relid = parentId;
2907  my_extra->nkeys = key->partnatts;
2908  my_extra->variadic_type = ARR_ELEMTYPE(variadic_array);
2909  get_typlenbyvalalign(my_extra->variadic_type,
2910  &my_extra->variadic_typlen,
2911  &my_extra->variadic_typbyval,
2912  &my_extra->variadic_typalign);
2913  my_extra->partcollid[0] = key->partcollation[0];
2914 
2915  /* check argument types */
2916  for (j = 0; j < key->partnatts; ++j)
2917  if (key->parttypid[j] != my_extra->variadic_type)
2918  ereport(ERROR,
2919  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2920  errmsg("column %d of the partition key has type \"%s\", but supplied value is of type \"%s\"",
2921  j + 1,
2922  format_type_be(key->parttypid[j]),
2923  format_type_be(my_extra->variadic_type))));
2924 
2925  fmgr_info_copy(&my_extra->partsupfunc[0],
2926  &key->partsupfunc[0],
2927  fcinfo->flinfo->fn_mcxt);
2928  }
2929 
2930  /* Hold lock until commit */
2931  relation_close(parent, NoLock);
2932  }
2933 
2934  if (!OidIsValid(my_extra->variadic_type))
2935  {
2936  int nkeys = my_extra->nkeys;
2937  int i;
2938 
2939  /*
2940  * For a non-variadic call, neither the number of arguments nor their
2941  * types can change across calls, so avoid the expense of rechecking
2942  * here.
2943  */
2944 
2945  for (i = 0; i < nkeys; i++)
2946  {
2947  Datum hash;
2948 
2949  /* keys start from fourth argument of function. */
2950  int argno = i + 3;
2951 
2952  if (PG_ARGISNULL(argno))
2953  continue;
2954 
2955  hash = FunctionCall2Coll(&my_extra->partsupfunc[i],
2956  my_extra->partcollid[i],
2957  PG_GETARG_DATUM(argno),
2958  seed);
2959 
2960  /* Form a single 64-bit hash value */
2961  rowHash = hash_combine64(rowHash, DatumGetUInt64(hash));
2962  }
2963  }
2964  else
2965  {
2966  ArrayType *variadic_array = PG_GETARG_ARRAYTYPE_P(3);
2967  int i;
2968  int nelems;
2969  Datum *datum;
2970  bool *isnull;
2971 
2972  deconstruct_array(variadic_array,
2973  my_extra->variadic_type,
2974  my_extra->variadic_typlen,
2975  my_extra->variadic_typbyval,
2976  my_extra->variadic_typalign,
2977  &datum, &isnull, &nelems);
2978 
2979  /* complain if wrong number of column values */
2980  if (nelems != my_extra->nkeys)
2981  ereport(ERROR,
2982  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2983  errmsg("number of partitioning columns (%d) does not match number of partition keys provided (%d)",
2984  my_extra->nkeys, nelems)));
2985 
2986  for (i = 0; i < nelems; i++)
2987  {
2988  Datum hash;
2989 
2990  if (isnull[i])
2991  continue;
2992 
2993  hash = FunctionCall2Coll(&my_extra->partsupfunc[0],
2994  my_extra->partcollid[0],
2995  datum[i],
2996  seed);
2997 
2998  /* Form a single 64-bit hash value */
2999  rowHash = hash_combine64(rowHash, DatumGetUInt64(hash));
3000  }
3001  }
3002 
3003  PG_RETURN_BOOL(rowHash % modulus == remainder);
3004 }
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:354
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:577
static int partition_range_bsearch(int partnatts, FmgrInfo *partsupfunc, Oid *partcollation, PartitionBoundInfo boundinfo, PartitionRangeBound *probe, bool *is_equal)
Definition: partbounds.c:1626
PartitionRangeDatumKind * kind
Definition: partbounds.c:67
static Datum ExecEvalExprSwitchContext(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:305
#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:1755
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:940
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:3028
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:595
static List * get_qual_for_hash(Relation parent, PartitionBoundSpec *spec)
Definition: partbounds.c:1998
PartitionRangeDatumKind
Definition: parsenodes.h:835
void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, char *typalign)
Definition: lsyscache.c:2110
#define PG_GETARG_DATUM(n)
Definition: fmgr.h:263
Oid get_array_type(Oid typid)
Definition: lsyscache.c:2615
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:222
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:846
#define AccessShareLock
Definition: lockdefs.h:36
#define FLEXIBLE_ARRAY_MEMBER
Definition: c.h:276
Definition: nodes.h:526
struct cursor * cur
Definition: ecpg.c:28
bool get_fn_expr_variadic(FmgrInfo *flinfo)
Definition: fmgr.c:1938
uint16 StrategyNumber
Definition: stratnum.h:22
int errcode(int sqlerrcode)
Definition: elog.c:610
static List * get_range_nulltest(PartitionKey key)
Definition: partbounds.c:2700
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:1787
#define PARTITION_MAX_KEYS
Oid array_typeid
Definition: primnodes.h:988
char * format_type_be(Oid type_oid)
Definition: format_type.c:327
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:1152
static bool table_scan_getnextslot(TableScanDesc sscan, ScanDirection direction, TupleTableSlot *slot)
Definition: tableam.h:904
PartitionKey RelationGetPartitionKey(Relation rel)
Definition: partcache.c:54
struct PartitionRangeBound PartitionRangeBound
Form_pg_class rd_rel
Definition: rel.h:89
NameData relname
Definition: pg_class.h:38
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
static uint64 hash_combine64(uint64 a, uint64 b)
Definition: hashfn.h:80
#define OidIsValid(objectId)
Definition: c.h:644
ExprState * ExecPrepareExpr(Expr *node, EState *estate)
Definition: execExpr.c:492
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:355
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:1885
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:2656
#define GetPerTupleExprContext(estate)
Definition: executor.h:506
static PartitionRangeBound * make_one_partition_rbound(PartitionKey key, int index, List *datums, bool lower)
Definition: partbounds.c:1412
#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:1672
unsigned short uint16
Definition: c.h:366
void pfree(void *pointer)
Definition: mcxt.c:1056
MemoryContext es_query_cxt
Definition: execnodes.h:555
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:755
Oid get_fn_expr_argtype(FmgrInfo *flinfo, int argnum)
Definition: fmgr.c:1804
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:1232
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:612
int get_hash_partition_greatest_modulus(PartitionBoundInfo bound)
Definition: partbounds.c:1395
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:1532
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:957
Oid get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype, int16 strategy)
Definition: lsyscache.c:164
#define DatumGetBool(X)
Definition: postgres.h:393
static int32 partition_hbound_cmp(int modulus1, int remainder1, int modulus2, int remainder2)
Definition: partbounds.c:1563
PartitionDesc RelationGetPartitionDesc(Relation rel)
Definition: partdesc.c:65
#define RelationGetRelationName(relation)
Definition: rel.h:470
#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:1715
List * elements
Definition: primnodes.h:991
static int get_partition_bound_num_indexes(PartitionBoundInfo b)
Definition: partbounds.c:1804
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:131
EState * CreateExecutorState(void)
Definition: execUtils.c:88
char * get_range_partbound_string(List *bound_datums)
Definition: ruleutils.c:11374
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
Oid * partcollation
Definition: partcache.h:38
#define TextDatumGetCString(d)
Definition: builtins.h:88
PartitionBoundInfo partition_bounds_copy(PartitionBoundInfo src, PartitionKey key)
Definition: partbounds.c:784
List * es_tupleTable
Definition: execnodes.h:557
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:353
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:1849
#define PARTITION_STRATEGY_HASH
Definition: parsenodes.h:799
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:1583
uint64 compute_partition_hash_value(int partnatts, FmgrInfo *partsupfunc, Oid *partcollation, Datum *values, bool *isnull)
Definition: partbounds.c:2746
#define InvalidOid
Definition: postgres_ext.h:36
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1153
static struct @143 value
#define ereport(elevel,...)
Definition: elog.h:144
static int32 partition_rbound_cmp(int partnatts, FmgrInfo *partsupfunc, Oid *partcollation, Datum *datums1, PartitionRangeDatumKind *kind1, bool lower1, PartitionRangeBound *b2)
Definition: partbounds.c:1468
static List * get_qual_for_range(Relation parent, PartitionBoundSpec *spec, bool for_default)
Definition: partbounds.c:2290
#define DatumGetUInt64(X)
Definition: postgres.h:634
#define makeNode(_type_)
Definition: nodes.h:574
bool partitions_are_ordered(PartitionBoundInfo boundinfo, int nparts)
Definition: partbounds.c:881
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:738
#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:226
#define type_is_array(typid)
Definition: lsyscache.h:189
#define PG_NARGS()
Definition: fmgr.h:198
#define HASH_PARTITION_SEED
Definition: partition.h:20
#define PARTITION_STRATEGY_LIST
Definition: parsenodes.h:800
Snapshot GetLatestSnapshot(void)
Definition: snapmgr.c:381
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:511
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:863
static Datum values[MAXATTR]
Definition: bootstrap.c:167
#define PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:801
#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:824
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:214
int i
void * arg
bool ExecCheck(ExprState *state, ExprContext *econtext)
Definition: execExpr.c:599
bool argisrow
Definition: primnodes.h:1221
Datum satisfies_hash_partition(PG_FUNCTION_ARGS)
Definition: partbounds.c:2793
#define PG_FUNCTION_ARGS
Definition: fmgr.h:188
ExprState * ExecInitExpr(Expr *node, PlanState *parent)
Definition: execExpr.c:123
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:99
struct PartitionBoundInfoData * PartitionBoundInfo
Definition: partdefs.h:16
#define qsort(a, b, c, d)
Definition: port.h:478
#define copyObject(obj)
Definition: nodes.h:642
#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:1770
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:1791
int errtable(Relation rel)
Definition: relcache.c:5302
#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:436
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:339
static List * get_qual_for_list(Relation parent, PartitionBoundSpec *spec)
Definition: partbounds.c:2081
bool constisnull
Definition: primnodes.h:215
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define offsetof(type, field)
Definition: c.h:661
#define BTGreaterEqualStrategyNumber
Definition: stratnum.h:32
#define ResetExprContext(econtext)
Definition: executor.h:500
#define lfirst_oid(lc)
Definition: pg_list.h:192
bool PartConstraintImpliedByRelConstraint(Relation scanrel, List *partConstraint)
Definition: tablecmds.c:15856
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