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