PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
partition.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * partition.c
4  * Partitioning related data structures and functions.
5  *
6  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  * src/backend/catalog/partition.c
12  *
13  *-------------------------------------------------------------------------
14 */
15 
16 #include "postgres.h"
17 
18 #include "access/heapam.h"
19 #include "access/htup_details.h"
20 #include "access/nbtree.h"
21 #include "access/sysattr.h"
22 #include "catalog/dependency.h"
23 #include "catalog/indexing.h"
24 #include "catalog/objectaddress.h"
25 #include "catalog/partition.h"
26 #include "catalog/pg_collation.h"
27 #include "catalog/pg_inherits.h"
28 #include "catalog/pg_inherits_fn.h"
29 #include "catalog/pg_opclass.h"
30 #include "catalog/pg_type.h"
31 #include "executor/executor.h"
32 #include "miscadmin.h"
33 #include "nodes/makefuncs.h"
34 #include "nodes/nodeFuncs.h"
35 #include "nodes/parsenodes.h"
36 #include "optimizer/clauses.h"
37 #include "optimizer/planmain.h"
38 #include "optimizer/var.h"
39 #include "rewrite/rewriteManip.h"
40 #include "storage/lmgr.h"
41 #include "utils/array.h"
42 #include "utils/builtins.h"
43 #include "utils/datum.h"
44 #include "utils/memutils.h"
45 #include "utils/fmgroids.h"
46 #include "utils/inval.h"
47 #include "utils/lsyscache.h"
48 #include "utils/rel.h"
49 #include "utils/ruleutils.h"
50 #include "utils/syscache.h"
51 
52 /*
53  * Information about bounds of a partitioned relation
54  *
55  * A list partition datum that is known to be NULL is never put into the
56  * datums array. Instead, it is tracked using the null_index field.
57  *
58  * In the case of range partitioning, ndatums will typically be far less than
59  * 2 * nparts, because a partition's upper bound and the next partition's lower
60  * bound are the same in most common cases, and we only store one of them.
61  *
62  * In the case of list partitioning, the indexes array stores one entry for
63  * every datum, which is the index of the partition that accepts a given datum.
64  * In case of range partitioning, it stores one entry per distinct range
65  * datum, which is the index of the partition for which a given datum
66  * is an upper bound.
67  */
68 
69 /* Ternary value to represent what's contained in a range bound datum */
70 typedef enum RangeDatumContent
71 {
72  RANGE_DATUM_FINITE = 0, /* actual datum stored elsewhere */
73  RANGE_DATUM_NEG_INF, /* negative infinity */
74  RANGE_DATUM_POS_INF /* positive infinity */
76 
77 typedef struct PartitionBoundInfoData
78 {
79  char strategy; /* list or range bounds? */
80  int ndatums; /* Length of the datums following array */
81  Datum **datums; /* Array of datum-tuples with key->partnatts
82  * datums each */
83  RangeDatumContent **content;/* what's contained in each range bound datum?
84  * (see the above enum); NULL for list
85  * partitioned tables */
86  int *indexes; /* Partition indexes; one entry per member of
87  * the datums array (plus one if range
88  * partitioned table) */
89  int null_index; /* Index of the null-accepting partition; -1
90  * if there isn't one */
92 
93 #define partition_bound_accepts_nulls(bi) ((bi)->null_index != -1)
94 
95 /*
96  * When qsort'ing partition bounds after reading from the catalog, each bound
97  * is represented with one of the following structs.
98  */
99 
100 /* One value coming from some (index'th) list partition */
101 typedef struct PartitionListValue
102 {
103  int index;
106 
107 /* One bound of a range partition */
108 typedef struct PartitionRangeBound
109 {
110  int index;
111  Datum *datums; /* range bound datums */
112  RangeDatumContent *content; /* what's contained in each datum? */
113  bool lower; /* this is the lower (vs upper) bound */
115 
116 static int32 qsort_partition_list_value_cmp(const void *a, const void *b,
117  void *arg);
118 static int32 qsort_partition_rbound_cmp(const void *a, const void *b,
119  void *arg);
120 
121 static Oid get_partition_operator(PartitionKey key, int col,
122  StrategyNumber strategy, bool *need_relabel);
123 static Expr *make_partition_op_expr(PartitionKey key, int keynum,
124  uint16 strategy, Expr *arg1, Expr *arg2);
125 static void get_range_key_properties(PartitionKey key, int keynum,
126  PartitionRangeDatum *ldatum,
127  PartitionRangeDatum *udatum,
128  ListCell **partexprs_item,
129  Expr **keyCol,
130  Const **lower_val, Const **upper_val);
134 
136  List *datums, bool lower);
138  Datum *datums1, RangeDatumContent *content1, bool lower1,
139  PartitionRangeBound *b2);
141  Datum *rb_datums, RangeDatumContent *rb_content,
142  Datum *tuple_datums);
143 
145  PartitionBoundInfo boundinfo,
146  int offset, void *probe, bool probe_is_bound);
148  PartitionBoundInfo boundinfo,
149  void *probe, bool probe_is_bound, bool *is_equal);
150 
151 /*
152  * RelationBuildPartitionDesc
153  * Form rel's partition descriptor
154  *
155  * Not flushed from the cache by RelationClearRelation() unless changed because
156  * of addition or removal of partition.
157  */
158 void
160 {
161  List *inhoids,
162  *partoids;
163  Oid *oids = NULL;
164  List *boundspecs = NIL;
165  ListCell *cell;
166  int i,
167  nparts;
170  MemoryContext oldcxt;
171 
172  int ndatums = 0;
173 
174  /* List partitioning specific */
175  PartitionListValue **all_values = NULL;
176  int null_index = -1;
177 
178  /* Range partitioning specific */
179  PartitionRangeBound **rbounds = NULL;
180 
181  /*
182  * The following could happen in situations where rel has a pg_class entry
183  * but not the pg_partitioned_table entry yet.
184  */
185  if (key == NULL)
186  return;
187 
188  /* Get partition oids from pg_inherits */
190 
191  /* Collect bound spec nodes in a list */
192  i = 0;
193  partoids = NIL;
194  foreach(cell, inhoids)
195  {
196  Oid inhrelid = lfirst_oid(cell);
197  HeapTuple tuple;
198  Datum datum;
199  bool isnull;
200  Node *boundspec;
201 
202  tuple = SearchSysCache1(RELOID, inhrelid);
203  if (!HeapTupleIsValid(tuple))
204  elog(ERROR, "cache lookup failed for relation %u", inhrelid);
205 
206  /*
207  * It is possible that the pg_class tuple of a partition has not been
208  * updated yet to set its relpartbound field. The only case where
209  * this happens is when we open the parent relation to check using its
210  * partition descriptor that a new partition's bound does not overlap
211  * some existing partition.
212  */
213  if (!((Form_pg_class) GETSTRUCT(tuple))->relispartition)
214  {
215  ReleaseSysCache(tuple);
216  continue;
217  }
218 
219  datum = SysCacheGetAttr(RELOID, tuple,
221  &isnull);
222  Assert(!isnull);
223  boundspec = (Node *) stringToNode(TextDatumGetCString(datum));
224  boundspecs = lappend(boundspecs, boundspec);
225  partoids = lappend_oid(partoids, inhrelid);
226  ReleaseSysCache(tuple);
227  }
228 
229  nparts = list_length(partoids);
230 
231  if (nparts > 0)
232  {
233  oids = (Oid *) palloc(nparts * sizeof(Oid));
234  i = 0;
235  foreach(cell, partoids)
236  oids[i++] = lfirst_oid(cell);
237 
238  /* Convert from node to the internal representation */
239  if (key->strategy == PARTITION_STRATEGY_LIST)
240  {
241  List *non_null_values = NIL;
242 
243  /*
244  * Create a unified list of non-null values across all partitions.
245  */
246  i = 0;
247  null_index = -1;
248  foreach(cell, boundspecs)
249  {
250  ListCell *c;
251  PartitionBoundSpec *spec = lfirst(cell);
252 
253  if (spec->strategy != PARTITION_STRATEGY_LIST)
254  elog(ERROR, "invalid strategy in partition bound spec");
255 
256  foreach(c, spec->listdatums)
257  {
258  Const *val = lfirst(c);
259  PartitionListValue *list_value = NULL;
260 
261  if (!val->constisnull)
262  {
263  list_value = (PartitionListValue *)
264  palloc0(sizeof(PartitionListValue));
265  list_value->index = i;
266  list_value->value = val->constvalue;
267  }
268  else
269  {
270  /*
271  * Never put a null into the values array, flag
272  * instead for the code further down below where we
273  * construct the actual relcache struct.
274  */
275  if (null_index != -1)
276  elog(ERROR, "found null more than once");
277  null_index = i;
278  }
279 
280  if (list_value)
281  non_null_values = lappend(non_null_values,
282  list_value);
283  }
284 
285  i++;
286  }
287 
288  ndatums = list_length(non_null_values);
289 
290  /*
291  * Collect all list values in one array. Alongside the value, we
292  * also save the index of partition the value comes from.
293  */
294  all_values = (PartitionListValue **) palloc(ndatums *
295  sizeof(PartitionListValue *));
296  i = 0;
297  foreach(cell, non_null_values)
298  {
299  PartitionListValue *src = lfirst(cell);
300 
301  all_values[i] = (PartitionListValue *)
302  palloc(sizeof(PartitionListValue));
303  all_values[i]->value = src->value;
304  all_values[i]->index = src->index;
305  i++;
306  }
307 
308  qsort_arg(all_values, ndatums, sizeof(PartitionListValue *),
309  qsort_partition_list_value_cmp, (void *) key);
310  }
311  else if (key->strategy == PARTITION_STRATEGY_RANGE)
312  {
313  int j,
314  k;
315  PartitionRangeBound **all_bounds,
316  *prev;
317  bool *distinct_indexes;
318 
319  all_bounds = (PartitionRangeBound **) palloc0(2 * nparts *
320  sizeof(PartitionRangeBound *));
321  distinct_indexes = (bool *) palloc(2 * nparts * sizeof(bool));
322 
323  /*
324  * Create a unified list of range bounds across all the
325  * partitions.
326  */
327  i = j = 0;
328  foreach(cell, boundspecs)
329  {
330  PartitionBoundSpec *spec = lfirst(cell);
332  *upper;
333 
334  if (spec->strategy != PARTITION_STRATEGY_RANGE)
335  elog(ERROR, "invalid strategy in partition bound spec");
336 
337  lower = make_one_range_bound(key, i, spec->lowerdatums,
338  true);
339  upper = make_one_range_bound(key, i, spec->upperdatums,
340  false);
341  all_bounds[j] = lower;
342  all_bounds[j + 1] = upper;
343  j += 2;
344  i++;
345  }
346  Assert(j == 2 * nparts);
347 
348  /* Sort all the bounds in ascending order */
349  qsort_arg(all_bounds, 2 * nparts,
350  sizeof(PartitionRangeBound *),
352  (void *) key);
353 
354  /*
355  * Count the number of distinct bounds to allocate an array of
356  * that size.
357  */
358  ndatums = 0;
359  prev = NULL;
360  for (i = 0; i < 2 * nparts; i++)
361  {
362  PartitionRangeBound *cur = all_bounds[i];
363  bool is_distinct = false;
364  int j;
365 
366  /* Is current bound is distinct from the previous? */
367  for (j = 0; j < key->partnatts; j++)
368  {
369  Datum cmpval;
370 
371  if (prev == NULL)
372  {
373  is_distinct = true;
374  break;
375  }
376 
377  /*
378  * If either of them has infinite element, we can't equate
379  * them. Even when both are infinite, they'd have
380  * opposite signs, because only one of cur and prev is a
381  * lower bound).
382  */
383  if (cur->content[j] != RANGE_DATUM_FINITE ||
384  prev->content[j] != RANGE_DATUM_FINITE)
385  {
386  is_distinct = true;
387  break;
388  }
389  cmpval = FunctionCall2Coll(&key->partsupfunc[j],
390  key->partcollation[j],
391  cur->datums[j],
392  prev->datums[j]);
393  if (DatumGetInt32(cmpval) != 0)
394  {
395  is_distinct = true;
396  break;
397  }
398  }
399 
400  /*
401  * Count the current bound if it is distinct from the previous
402  * one. Also, store if the index i contains a distinct bound
403  * that we'd like put in the relcache array.
404  */
405  if (is_distinct)
406  {
407  distinct_indexes[i] = true;
408  ndatums++;
409  }
410  else
411  distinct_indexes[i] = false;
412 
413  prev = cur;
414  }
415 
416  /*
417  * Finally save them in an array from where they will be copied
418  * into the relcache.
419  */
420  rbounds = (PartitionRangeBound **) palloc(ndatums *
421  sizeof(PartitionRangeBound *));
422  k = 0;
423  for (i = 0; i < 2 * nparts; i++)
424  {
425  if (distinct_indexes[i])
426  rbounds[k++] = all_bounds[i];
427  }
428  Assert(k == ndatums);
429  }
430  else
431  elog(ERROR, "unexpected partition strategy: %d",
432  (int) key->strategy);
433  }
434 
435  /* Now build the actual relcache partition descriptor */
439  oldcxt = MemoryContextSwitchTo(rel->rd_pdcxt);
440 
441  result = (PartitionDescData *) palloc0(sizeof(PartitionDescData));
442  result->nparts = nparts;
443  if (nparts > 0)
444  {
445  PartitionBoundInfo boundinfo;
446  int *mapping;
447  int next_index = 0;
448 
449  result->oids = (Oid *) palloc0(nparts * sizeof(Oid));
450 
451  boundinfo = (PartitionBoundInfoData *)
453  boundinfo->strategy = key->strategy;
454  boundinfo->ndatums = ndatums;
455  boundinfo->datums = (Datum **) palloc0(ndatums * sizeof(Datum *));
456 
457  /* Initialize mapping array with invalid values */
458  mapping = (int *) palloc(sizeof(int) * nparts);
459  for (i = 0; i < nparts; i++)
460  mapping[i] = -1;
461 
462  switch (key->strategy)
463  {
465  {
466  boundinfo->indexes = (int *) palloc(ndatums * sizeof(int));
467 
468  /*
469  * Copy values. Indexes of individual values are mapped
470  * to canonical values so that they match for any two list
471  * partitioned tables with same number of partitions and
472  * same lists per partition. One way to canonicalize is
473  * to assign the index in all_values[] of the smallest
474  * value of each partition, as the index of all of the
475  * partition's values.
476  */
477  for (i = 0; i < ndatums; i++)
478  {
479  boundinfo->datums[i] = (Datum *) palloc(sizeof(Datum));
480  boundinfo->datums[i][0] = datumCopy(all_values[i]->value,
481  key->parttypbyval[0],
482  key->parttyplen[0]);
483 
484  /* If the old index has no mapping, assign one */
485  if (mapping[all_values[i]->index] == -1)
486  mapping[all_values[i]->index] = next_index++;
487 
488  boundinfo->indexes[i] = mapping[all_values[i]->index];
489  }
490 
491  /*
492  * If null-accepting partition has no mapped index yet,
493  * assign one. This could happen if such partition
494  * accepts only null and hence not covered in the above
495  * loop which only handled non-null values.
496  */
497  if (null_index != -1)
498  {
499  Assert(null_index >= 0);
500  if (mapping[null_index] == -1)
501  mapping[null_index] = next_index++;
502  boundinfo->null_index = mapping[null_index];
503  }
504  else
505  boundinfo->null_index = -1;
506 
507  /* All partition must now have a valid mapping */
508  Assert(next_index == nparts);
509  break;
510  }
511 
513  {
514  boundinfo->content = (RangeDatumContent **) palloc(ndatums *
515  sizeof(RangeDatumContent *));
516  boundinfo->indexes = (int *) palloc((ndatums + 1) *
517  sizeof(int));
518 
519  for (i = 0; i < ndatums; i++)
520  {
521  int j;
522 
523  boundinfo->datums[i] = (Datum *) palloc(key->partnatts *
524  sizeof(Datum));
525  boundinfo->content[i] = (RangeDatumContent *)
526  palloc(key->partnatts *
527  sizeof(RangeDatumContent));
528  for (j = 0; j < key->partnatts; j++)
529  {
530  if (rbounds[i]->content[j] == RANGE_DATUM_FINITE)
531  boundinfo->datums[i][j] =
532  datumCopy(rbounds[i]->datums[j],
533  key->parttypbyval[j],
534  key->parttyplen[j]);
535  /* Remember, we are storing the tri-state value. */
536  boundinfo->content[i][j] = rbounds[i]->content[j];
537  }
538 
539  /*
540  * There is no mapping for invalid indexes.
541  *
542  * Any lower bounds in the rbounds array have invalid
543  * indexes assigned, because the values between the
544  * previous bound (if there is one) and this (lower)
545  * bound are not part of the range of any existing
546  * partition.
547  */
548  if (rbounds[i]->lower)
549  boundinfo->indexes[i] = -1;
550  else
551  {
552  int orig_index = rbounds[i]->index;
553 
554  /* If the old index has no mapping, assign one */
555  if (mapping[orig_index] == -1)
556  mapping[orig_index] = next_index++;
557 
558  boundinfo->indexes[i] = mapping[orig_index];
559  }
560  }
561  boundinfo->indexes[i] = -1;
562  break;
563  }
564 
565  default:
566  elog(ERROR, "unexpected partition strategy: %d",
567  (int) key->strategy);
568  }
569 
570  result->boundinfo = boundinfo;
571 
572  /*
573  * Now assign OIDs from the original array into mapped indexes of the
574  * result array. Order of OIDs in the former is defined by the
575  * catalog scan that retrived them, whereas that in the latter is
576  * defined by canonicalized representation of the list values or the
577  * range bounds.
578  */
579  for (i = 0; i < nparts; i++)
580  result->oids[mapping[i]] = oids[i];
581  pfree(mapping);
582  }
583 
584  MemoryContextSwitchTo(oldcxt);
585  rel->rd_partdesc = result;
586 }
587 
588 /*
589  * Are two partition bound collections logically equal?
590  *
591  * Used in the keep logic of relcache.c (ie, in RelationClearRelation()).
592  * This is also useful when b1 and b2 are bound collections of two separate
593  * relations, respectively, because PartitionBoundInfo is a canonical
594  * representation of partition bounds.
595  */
596 bool
599 {
600  int i;
601 
602  if (b1->strategy != b2->strategy)
603  return false;
604 
605  if (b1->ndatums != b2->ndatums)
606  return false;
607 
608  if (b1->null_index != b2->null_index)
609  return false;
610 
611  for (i = 0; i < b1->ndatums; i++)
612  {
613  int j;
614 
615  for (j = 0; j < key->partnatts; j++)
616  {
617  /* For range partitions, the bounds might not be finite. */
618  if (b1->content != NULL)
619  {
620  /*
621  * A finite bound always differs from an infinite bound, and
622  * different kinds of infinities differ from each other.
623  */
624  if (b1->content[i][j] != b2->content[i][j])
625  return false;
626 
627  /* Non-finite bounds are equal without further examination. */
628  if (b1->content[i][j] != RANGE_DATUM_FINITE)
629  continue;
630  }
631 
632  /*
633  * Compare the actual values. Note that it would be both incorrect
634  * and unsafe to invoke the comparison operator derived from the
635  * partitioning specification here. It would be incorrect because
636  * we want the relcache entry to be updated for ANY change to the
637  * partition bounds, not just those that the partitioning operator
638  * thinks are significant. It would be unsafe because we might
639  * reach this code in the context of an aborted transaction, and
640  * an arbitrary partitioning operator might not be safe in that
641  * context. datumIsEqual() should be simple enough to be safe.
642  */
643  if (!datumIsEqual(b1->datums[i][j], b2->datums[i][j],
644  key->parttypbyval[j],
645  key->parttyplen[j]))
646  return false;
647  }
648 
649  if (b1->indexes[i] != b2->indexes[i])
650  return false;
651  }
652 
653  /* There are ndatums+1 indexes in case of range partitions */
654  if (key->strategy == PARTITION_STRATEGY_RANGE &&
655  b1->indexes[i] != b2->indexes[i])
656  return false;
657 
658  return true;
659 }
660 
661 /*
662  * check_new_partition_bound
663  *
664  * Checks if the new partition's bound overlaps any of the existing partitions
665  * of parent. Also performs additional checks as necessary per strategy.
666  */
667 void
668 check_new_partition_bound(char *relname, Relation parent, Node *bound)
669 {
670  PartitionBoundSpec *spec = (PartitionBoundSpec *) bound;
672  PartitionDesc partdesc = RelationGetPartitionDesc(parent);
673  ParseState *pstate = make_parsestate(NULL);
674  int with = -1;
675  bool overlap = false;
676 
677  switch (key->strategy)
678  {
680  {
682 
683  if (partdesc->nparts > 0)
684  {
685  PartitionBoundInfo boundinfo = partdesc->boundinfo;
686  ListCell *cell;
687 
688  Assert(boundinfo &&
689  boundinfo->strategy == PARTITION_STRATEGY_LIST &&
690  (boundinfo->ndatums > 0 ||
691  partition_bound_accepts_nulls(boundinfo)));
692 
693  foreach(cell, spec->listdatums)
694  {
695  Const *val = lfirst(cell);
696 
697  if (!val->constisnull)
698  {
699  int offset;
700  bool equal;
701 
702  offset = partition_bound_bsearch(key, boundinfo,
703  &val->constvalue,
704  true, &equal);
705  if (offset >= 0 && equal)
706  {
707  overlap = true;
708  with = boundinfo->indexes[offset];
709  break;
710  }
711  }
712  else if (partition_bound_accepts_nulls(boundinfo))
713  {
714  overlap = true;
715  with = boundinfo->null_index;
716  break;
717  }
718  }
719  }
720 
721  break;
722  }
723 
725  {
727  *upper;
728 
730  lower = make_one_range_bound(key, -1, spec->lowerdatums, true);
731  upper = make_one_range_bound(key, -1, spec->upperdatums, false);
732 
733  /*
734  * First check if the resulting range would be empty with
735  * specified lower and upper bounds
736  */
737  if (partition_rbound_cmp(key, lower->datums, lower->content, true,
738  upper) >= 0)
739  ereport(ERROR,
740  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
741  errmsg("cannot create range partition with empty range"),
742  parser_errposition(pstate, spec->location)));
743 
744  if (partdesc->nparts > 0)
745  {
746  PartitionBoundInfo boundinfo = partdesc->boundinfo;
747  int off1,
748  off2;
749  bool equal = false;
750 
751  Assert(boundinfo && boundinfo->ndatums > 0 &&
752  boundinfo->strategy == PARTITION_STRATEGY_RANGE);
753 
754  /*
755  * Firstly, find the greatest range bound that is less
756  * than or equal to the new lower bound.
757  */
758  off1 = partition_bound_bsearch(key, boundinfo, lower, true,
759  &equal);
760 
761  /*
762  * off1 == -1 means that all existing bounds are greater
763  * than the new lower bound. In that case and the case
764  * where no partition is defined between the bounds at
765  * off1 and off1 + 1, we have a "gap" in the range that
766  * could be occupied by the new partition. We confirm if
767  * so by checking whether the new upper bound is confined
768  * within the gap.
769  */
770  if (!equal && boundinfo->indexes[off1 + 1] < 0)
771  {
772  off2 = partition_bound_bsearch(key, boundinfo, upper,
773  true, &equal);
774 
775  /*
776  * If the new upper bound is returned to be equal to
777  * the bound at off2, the latter must be the upper
778  * bound of some partition with which the new
779  * partition clearly overlaps.
780  *
781  * Also, if bound at off2 is not same as the one
782  * returned for the new lower bound (IOW, off1 !=
783  * off2), then the new partition overlaps at least one
784  * partition.
785  */
786  if (equal || off1 != off2)
787  {
788  overlap = true;
789 
790  /*
791  * The bound at off2 could be the lower bound of
792  * the partition with which the new partition
793  * overlaps. In that case, use the upper bound
794  * (that is, the bound at off2 + 1) to get the
795  * index of that partition.
796  */
797  if (boundinfo->indexes[off2] < 0)
798  with = boundinfo->indexes[off2 + 1];
799  else
800  with = boundinfo->indexes[off2];
801  }
802  }
803  else
804  {
805  /*
806  * Equal has been set to true and there is no "gap"
807  * between the bound at off1 and that at off1 + 1, so
808  * the new partition will overlap some partition. In
809  * the former case, the new lower bound is found to be
810  * equal to the bound at off1, which could only ever
811  * be true if the latter is the lower bound of some
812  * partition. It's clear in such a case that the new
813  * partition overlaps that partition, whose index we
814  * get using its upper bound (that is, using the bound
815  * at off1 + 1).
816  */
817  overlap = true;
818  with = boundinfo->indexes[off1 + 1];
819  }
820  }
821 
822  break;
823  }
824 
825  default:
826  elog(ERROR, "unexpected partition strategy: %d",
827  (int) key->strategy);
828  }
829 
830  if (overlap)
831  {
832  Assert(with >= 0);
833  ereport(ERROR,
834  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
835  errmsg("partition \"%s\" would overlap partition \"%s\"",
836  relname, get_rel_name(partdesc->oids[with])),
837  parser_errposition(pstate, spec->location)));
838  }
839 }
840 
841 /*
842  * get_partition_parent
843  *
844  * Returns inheritance parent of a partition by scanning pg_inherits
845  *
846  * Note: Because this function assumes that the relation whose OID is passed
847  * as an argument will have precisely one parent, it should only be called
848  * when it is known that the relation is a partition.
849  */
850 Oid
852 {
853  Form_pg_inherits form;
854  Relation catalogRelation;
855  SysScanDesc scan;
856  ScanKeyData key[2];
857  HeapTuple tuple;
858  Oid result;
859 
860  catalogRelation = heap_open(InheritsRelationId, AccessShareLock);
861 
862  ScanKeyInit(&key[0],
864  BTEqualStrategyNumber, F_OIDEQ,
865  ObjectIdGetDatum(relid));
866  ScanKeyInit(&key[1],
868  BTEqualStrategyNumber, F_INT4EQ,
869  Int32GetDatum(1));
870 
871  scan = systable_beginscan(catalogRelation, InheritsRelidSeqnoIndexId, true,
872  NULL, 2, key);
873 
874  tuple = systable_getnext(scan);
875  Assert(HeapTupleIsValid(tuple));
876 
877  form = (Form_pg_inherits) GETSTRUCT(tuple);
878  result = form->inhparent;
879 
880  systable_endscan(scan);
881  heap_close(catalogRelation, AccessShareLock);
882 
883  return result;
884 }
885 
886 /*
887  * get_qual_from_partbound
888  * Given a parser node for partition bound, return the list of executable
889  * expressions as partition constraint
890  */
891 List *
893 {
894  PartitionBoundSpec *spec = (PartitionBoundSpec *) bound;
896  List *my_qual = NIL;
897 
898  Assert(key != NULL);
899 
900  switch (key->strategy)
901  {
904  my_qual = get_qual_for_list(key, spec);
905  break;
906 
909  my_qual = get_qual_for_range(key, spec);
910  break;
911 
912  default:
913  elog(ERROR, "unexpected partition strategy: %d",
914  (int) key->strategy);
915  }
916 
917  return my_qual;
918 }
919 
920 /*
921  * map_partition_varattnos - maps varattno of any Vars in expr from the
922  * parent attno to partition attno.
923  *
924  * We must allow for cases where physical attnos of a partition can be
925  * different from the parent's.
926  *
927  * Note: this will work on any node tree, so really the argument and result
928  * should be declared "Node *". But a substantial majority of the callers
929  * are working on Lists, so it's less messy to do the casts internally.
930  */
931 List *
932 map_partition_varattnos(List *expr, int target_varno,
933  Relation partrel, Relation parent)
934 {
935  AttrNumber *part_attnos;
936  bool found_whole_row;
937 
938  if (expr == NIL)
939  return NIL;
940 
941  part_attnos = convert_tuples_by_name_map(RelationGetDescr(partrel),
942  RelationGetDescr(parent),
943  gettext_noop("could not convert row type"));
944  expr = (List *) map_variable_attnos((Node *) expr,
945  target_varno, 0,
946  part_attnos,
947  RelationGetDescr(parent)->natts,
948  &found_whole_row);
949  /* There can never be a whole-row reference here */
950  if (found_whole_row)
951  elog(ERROR, "unexpected whole-row reference found in partition key");
952 
953  return expr;
954 }
955 
956 /*
957  * RelationGetPartitionQual
958  *
959  * Returns a list of partition quals
960  */
961 List *
963 {
964  /* Quick exit */
965  if (!rel->rd_rel->relispartition)
966  return NIL;
967 
968  return generate_partition_qual(rel);
969 }
970 
971 /*
972  * get_partition_qual_relid
973  *
974  * Returns an expression tree describing the passed-in relation's partition
975  * constraint.
976  */
977 Expr *
979 {
980  Relation rel = heap_open(relid, AccessShareLock);
981  Expr *result = NULL;
982  List *and_args;
983 
984  /* Do the work only if this relation is a partition. */
985  if (rel->rd_rel->relispartition)
986  {
987  and_args = generate_partition_qual(rel);
988  if (list_length(and_args) > 1)
989  result = makeBoolExpr(AND_EXPR, and_args, -1);
990  else
991  result = linitial(and_args);
992  }
993 
994  /* Keep the lock. */
995  heap_close(rel, NoLock);
996 
997  return result;
998 }
999 
1000 /*
1001  * Append OIDs of rel's partitions to the list 'partoids' and for each OID,
1002  * append pointer rel to the list 'parents'.
1003  */
1004 #define APPEND_REL_PARTITION_OIDS(rel, partoids, parents) \
1005  do\
1006  {\
1007  int i;\
1008  for (i = 0; i < (rel)->rd_partdesc->nparts; i++)\
1009  {\
1010  (partoids) = lappend_oid((partoids), (rel)->rd_partdesc->oids[i]);\
1011  (parents) = lappend((parents), (rel));\
1012  }\
1013  } while(0)
1014 
1015 /*
1016  * RelationGetPartitionDispatchInfo
1017  * Returns information necessary to route tuples down a partition tree
1018  *
1019  * All the partitions will be locked with lockmode, unless it is NoLock.
1020  * A list of the OIDs of all the leaf partitions of rel is returned in
1021  * *leaf_part_oids.
1022  */
1025  int *num_parted, List **leaf_part_oids)
1026 {
1027  PartitionDispatchData **pd;
1028  List *all_parts = NIL,
1029  *all_parents = NIL,
1030  *parted_rels,
1031  *parted_rel_parents;
1032  ListCell *lc1,
1033  *lc2;
1034  int i,
1035  k,
1036  offset;
1037 
1038  /*
1039  * Lock partitions and make a list of the partitioned ones to prepare
1040  * their PartitionDispatch objects below.
1041  *
1042  * Cannot use find_all_inheritors() here, because then the order of OIDs
1043  * in parted_rels list would be unknown, which does not help, because we
1044  * assign indexes within individual PartitionDispatch in an order that is
1045  * predetermined (determined by the order of OIDs in individual partition
1046  * descriptors).
1047  */
1048  *num_parted = 1;
1049  parted_rels = list_make1(rel);
1050  /* Root partitioned table has no parent, so NULL for parent */
1051  parted_rel_parents = list_make1(NULL);
1052  APPEND_REL_PARTITION_OIDS(rel, all_parts, all_parents);
1053  forboth(lc1, all_parts, lc2, all_parents)
1054  {
1055  Relation partrel = heap_open(lfirst_oid(lc1), lockmode);
1056  Relation parent = lfirst(lc2);
1057  PartitionDesc partdesc = RelationGetPartitionDesc(partrel);
1058 
1059  /*
1060  * If this partition is a partitioned table, add its children to the
1061  * end of the list, so that they are processed as well.
1062  */
1063  if (partdesc)
1064  {
1065  (*num_parted)++;
1066  parted_rels = lappend(parted_rels, partrel);
1067  parted_rel_parents = lappend(parted_rel_parents, parent);
1068  APPEND_REL_PARTITION_OIDS(partrel, all_parts, all_parents);
1069  }
1070  else
1071  heap_close(partrel, NoLock);
1072 
1073  /*
1074  * We keep the partitioned ones open until we're done using the
1075  * information being collected here (for example, see
1076  * ExecEndModifyTable).
1077  */
1078  }
1079 
1080  /*
1081  * We want to create two arrays - one for leaf partitions and another for
1082  * partitioned tables (including the root table and internal partitions).
1083  * While we only create the latter here, leaf partition array of suitable
1084  * objects (such as, ResultRelInfo) is created by the caller using the
1085  * list of OIDs we return. Indexes into these arrays get assigned in a
1086  * breadth-first manner, whereby partitions of any given level are placed
1087  * consecutively in the respective arrays.
1088  */
1089  pd = (PartitionDispatchData **) palloc(*num_parted *
1090  sizeof(PartitionDispatchData *));
1091  *leaf_part_oids = NIL;
1092  i = k = offset = 0;
1093  forboth(lc1, parted_rels, lc2, parted_rel_parents)
1094  {
1095  Relation partrel = lfirst(lc1);
1096  Relation parent = lfirst(lc2);
1097  PartitionKey partkey = RelationGetPartitionKey(partrel);
1098  TupleDesc tupdesc = RelationGetDescr(partrel);
1099  PartitionDesc partdesc = RelationGetPartitionDesc(partrel);
1100  int j,
1101  m;
1102 
1104  pd[i]->reldesc = partrel;
1105  pd[i]->key = partkey;
1106  pd[i]->keystate = NIL;
1107  pd[i]->partdesc = partdesc;
1108  if (parent != NULL)
1109  {
1110  /*
1111  * For every partitioned table other than root, we must store a
1112  * tuple table slot initialized with its tuple descriptor and a
1113  * tuple conversion map to convert a tuple from its parent's
1114  * rowtype to its own. That is to make sure that we are looking at
1115  * the correct row using the correct tuple descriptor when
1116  * computing its partition key for tuple routing.
1117  */
1118  pd[i]->tupslot = MakeSingleTupleTableSlot(tupdesc);
1120  tupdesc,
1121  gettext_noop("could not convert row type"));
1122  }
1123  else
1124  {
1125  /* Not required for the root partitioned table */
1126  pd[i]->tupslot = NULL;
1127  pd[i]->tupmap = NULL;
1128  }
1129  pd[i]->indexes = (int *) palloc(partdesc->nparts * sizeof(int));
1130 
1131  /*
1132  * Indexes corresponding to the internal partitions are multiplied by
1133  * -1 to distinguish them from those of leaf partitions. Encountering
1134  * an index >= 0 means we found a leaf partition, which is immediately
1135  * returned as the partition we are looking for. A negative index
1136  * means we found a partitioned table, whose PartitionDispatch object
1137  * is located at the above index multiplied back by -1. Using the
1138  * PartitionDispatch object, search is continued further down the
1139  * partition tree.
1140  */
1141  m = 0;
1142  for (j = 0; j < partdesc->nparts; j++)
1143  {
1144  Oid partrelid = partdesc->oids[j];
1145 
1146  if (get_rel_relkind(partrelid) != RELKIND_PARTITIONED_TABLE)
1147  {
1148  *leaf_part_oids = lappend_oid(*leaf_part_oids, partrelid);
1149  pd[i]->indexes[j] = k++;
1150  }
1151  else
1152  {
1153  /*
1154  * offset denotes the number of partitioned tables of upper
1155  * levels including those of the current level. Any partition
1156  * of this table must belong to the next level and hence will
1157  * be placed after the last partitioned table of this level.
1158  */
1159  pd[i]->indexes[j] = -(1 + offset + m);
1160  m++;
1161  }
1162  }
1163  i++;
1164 
1165  /*
1166  * This counts the number of partitioned tables at upper levels
1167  * including those of the current level.
1168  */
1169  offset += m;
1170  }
1171 
1172  return pd;
1173 }
1174 
1175 /* Module-local functions */
1176 
1177 /*
1178  * get_partition_operator
1179  *
1180  * Return oid of the operator of given strategy for a given partition key
1181  * column.
1182  */
1183 static Oid
1185  bool *need_relabel)
1186 {
1187  Oid operoid;
1188 
1189  /*
1190  * First check if there exists an operator of the given strategy, with
1191  * this column's type as both its lefttype and righttype, in the
1192  * partitioning operator family specified for the column.
1193  */
1194  operoid = get_opfamily_member(key->partopfamily[col],
1195  key->parttypid[col],
1196  key->parttypid[col],
1197  strategy);
1198 
1199  /*
1200  * If one doesn't exist, we must resort to using an operator in the same
1201  * opreator family but with the operator class declared input type. It is
1202  * OK to do so, because the column's type is known to be binary-coercible
1203  * with the operator class input type (otherwise, the operator class in
1204  * question would not have been accepted as the partitioning operator
1205  * class). We must however inform the caller to wrap the non-Const
1206  * expression with a RelabelType node to denote the implicit coercion. It
1207  * ensures that the resulting expression structurally matches similarly
1208  * processed expressions within the optimizer.
1209  */
1210  if (!OidIsValid(operoid))
1211  {
1212  operoid = get_opfamily_member(key->partopfamily[col],
1213  key->partopcintype[col],
1214  key->partopcintype[col],
1215  strategy);
1216  *need_relabel = true;
1217  }
1218  else
1219  *need_relabel = false;
1220 
1221  if (!OidIsValid(operoid))
1222  elog(ERROR, "could not find operator for partitioning");
1223 
1224  return operoid;
1225 }
1226 
1227 /*
1228  * make_partition_op_expr
1229  * Returns an Expr for the given partition key column with arg1 and
1230  * arg2 as its leftop and rightop, respectively
1231  */
1232 static Expr *
1234  uint16 strategy, Expr *arg1, Expr *arg2)
1235 {
1236  Oid operoid;
1237  bool need_relabel = false;
1238  Expr *result = NULL;
1239 
1240  /* Get the correct btree operator for this partitioning column */
1241  operoid = get_partition_operator(key, keynum, strategy, &need_relabel);
1242 
1243  /*
1244  * Chosen operator may be such that the non-Const operand needs to be
1245  * coerced, so apply the same; see the comment in
1246  * get_partition_operator().
1247  */
1248  if (!IsA(arg1, Const) &&
1249  (need_relabel ||
1250  key->partcollation[keynum] != key->parttypcoll[keynum]))
1251  arg1 = (Expr *) makeRelabelType(arg1,
1252  key->partopcintype[keynum],
1253  -1,
1254  key->partcollation[keynum],
1256 
1257  /* Generate the actual expression */
1258  switch (key->strategy)
1259  {
1261  {
1262  ScalarArrayOpExpr *saopexpr;
1263 
1264  /* Build leftop = ANY (rightop) */
1265  saopexpr = makeNode(ScalarArrayOpExpr);
1266  saopexpr->opno = operoid;
1267  saopexpr->opfuncid = get_opcode(operoid);
1268  saopexpr->useOr = true;
1269  saopexpr->inputcollid = key->partcollation[keynum];
1270  saopexpr->args = list_make2(arg1, arg2);
1271  saopexpr->location = -1;
1272 
1273  result = (Expr *) saopexpr;
1274  break;
1275  }
1276 
1278  result = make_opclause(operoid,
1279  BOOLOID,
1280  false,
1281  arg1, arg2,
1282  InvalidOid,
1283  key->partcollation[keynum]);
1284  break;
1285 
1286  default:
1287  elog(ERROR, "invalid partitioning strategy");
1288  break;
1289  }
1290 
1291  return result;
1292 }
1293 
1294 /*
1295  * get_qual_for_list
1296  *
1297  * Returns a list of expressions to use as a list partition's constraint.
1298  */
1299 static List *
1301 {
1302  List *result;
1303  ArrayExpr *arr;
1304  Expr *opexpr;
1305  ListCell *cell,
1306  *prev,
1307  *next;
1308  Expr *keyCol;
1309  bool list_has_null = false;
1310  NullTest *nulltest1 = NULL,
1311  *nulltest2 = NULL;
1312 
1313  /* Left operand is either a simple Var or arbitrary expression */
1314  if (key->partattrs[0] != 0)
1315  keyCol = (Expr *) makeVar(1,
1316  key->partattrs[0],
1317  key->parttypid[0],
1318  key->parttypmod[0],
1319  key->parttypcoll[0],
1320  0);
1321  else
1322  keyCol = (Expr *) copyObject(linitial(key->partexprs));
1323 
1324  /*
1325  * We must remove any NULL value in the list; we handle it separately
1326  * below.
1327  */
1328  prev = NULL;
1329  for (cell = list_head(spec->listdatums); cell; cell = next)
1330  {
1331  Const *val = (Const *) lfirst(cell);
1332 
1333  next = lnext(cell);
1334 
1335  if (val->constisnull)
1336  {
1337  list_has_null = true;
1338  spec->listdatums = list_delete_cell(spec->listdatums,
1339  cell, prev);
1340  }
1341  else
1342  prev = cell;
1343  }
1344 
1345  if (!list_has_null)
1346  {
1347  /*
1348  * Gin up a col IS NOT NULL test that will be AND'd with other
1349  * expressions
1350  */
1351  nulltest1 = makeNode(NullTest);
1352  nulltest1->arg = keyCol;
1353  nulltest1->nulltesttype = IS_NOT_NULL;
1354  nulltest1->argisrow = false;
1355  nulltest1->location = -1;
1356  }
1357  else
1358  {
1359  /*
1360  * Gin up a col IS NULL test that will be OR'd with other expressions
1361  */
1362  nulltest2 = makeNode(NullTest);
1363  nulltest2->arg = keyCol;
1364  nulltest2->nulltesttype = IS_NULL;
1365  nulltest2->argisrow = false;
1366  nulltest2->location = -1;
1367  }
1368 
1369  /* Right operand is an ArrayExpr containing this partition's values */
1370  arr = makeNode(ArrayExpr);
1371  arr->array_typeid = !type_is_array(key->parttypid[0])
1372  ? get_array_type(key->parttypid[0])
1373  : key->parttypid[0];
1374  arr->array_collid = key->parttypcoll[0];
1375  arr->element_typeid = key->parttypid[0];
1376  arr->elements = spec->listdatums;
1377  arr->multidims = false;
1378  arr->location = -1;
1379 
1380  /* Generate the main expression, i.e., keyCol = ANY (arr) */
1382  keyCol, (Expr *) arr);
1383 
1384  if (nulltest1)
1385  result = list_make2(nulltest1, opexpr);
1386  else
1387  {
1388  Expr *or;
1389 
1390  Assert(nulltest2 != NULL);
1391  or = makeBoolExpr(OR_EXPR, list_make2(nulltest2, opexpr), -1);
1392  result = list_make1(or);
1393  }
1394 
1395  return result;
1396 }
1397 
1398 /*
1399  * get_range_key_properties
1400  * Returns range partition key information for a given column
1401  *
1402  * On return, *partexprs_item points to the cell containing the next
1403  * expression in the key->partexprs list, or NULL.
1404  */
1405 static void
1407  PartitionRangeDatum *ldatum,
1408  PartitionRangeDatum *udatum,
1409  ListCell **partexprs_item,
1410  Expr **keyCol,
1411  Const **lower_val, Const **upper_val)
1412 {
1413  /* Partition key expression for this column */
1414  if (key->partattrs[keynum] != 0)
1415  {
1416  *keyCol = (Expr *) makeVar(1,
1417  key->partattrs[keynum],
1418  key->parttypid[keynum],
1419  key->parttypmod[keynum],
1420  key->parttypcoll[keynum],
1421  0);
1422  }
1423  else
1424  {
1425  *keyCol = copyObject(lfirst(*partexprs_item));
1426  *partexprs_item = lnext(*partexprs_item);
1427  }
1428 
1429  if (!ldatum->infinite)
1430  *lower_val = (Const *) ldatum->value;
1431  else
1432  *lower_val = NULL;
1433 
1434  if (!udatum->infinite)
1435  *upper_val = (Const *) udatum->value;
1436  else
1437  *upper_val = NULL;
1438 }
1439 
1440 /*
1441  * get_qual_for_range
1442  *
1443  * Get a list of expressions to use as a range partition's constraint.
1444  * If there are multiple expressions, they are to be considered implicitly
1445  * ANDed.
1446  *
1447  * For a multi-column range partition key, say (a, b, c), with (al, bl, cl)
1448  * as the lower bound tuple and (au, bu, cu) as the upper bound tuple, we
1449  * generate an expression tree of the following form:
1450  *
1451  * (a IS NOT NULL) and (b IS NOT NULL) and (c IS NOT NULL)
1452  * AND
1453  * (a > al OR (a = al AND b > bl) OR (a = al AND b = bl AND c >= cl))
1454  * AND
1455  * (a < au OR (a = au AND b < bu) OR (a = au AND b = bu AND c < cu))
1456  *
1457  * It is often the case that a prefix of lower and upper bound tuples contains
1458  * the same values, for example, (al = au), in which case, we will emit an
1459  * expression tree of the following form:
1460  *
1461  * (a IS NOT NULL) and (b IS NOT NULL) and (c IS NOT NULL)
1462  * AND
1463  * (a = al)
1464  * AND
1465  * (b > bl OR (b = bl AND c >= cl))
1466  * AND
1467  * (b < bu) OR (b = bu AND c < cu))
1468  *
1469  * If cu happens to be UNBOUNDED, we need not emit any expression for it, so
1470  * the last line would be:
1471  *
1472  * (b < bu) OR (b = bu), which is simplified to (b <= bu)
1473  *
1474  * In most common cases with only one partition column, say a, the following
1475  * expression tree will be generated: a IS NOT NULL AND a >= al AND a < au
1476  *
1477  * If all values of both lower and upper bounds are UNBOUNDED, the partition
1478  * does not really have a constraint, except the IS NOT NULL constraint for
1479  * partition keys.
1480  *
1481  * If we end up with an empty result list, we append return a single-member
1482  * list containing a constant-true expression in that case, because callers
1483  * expect a non-empty list.
1484  */
1485 static List *
1487 {
1488  List *result = NIL;
1489  ListCell *cell1,
1490  *cell2,
1491  *partexprs_item,
1492  *partexprs_item_saved;
1493  int i,
1494  j;
1495  PartitionRangeDatum *ldatum,
1496  *udatum;
1497  Expr *keyCol;
1498  Const *lower_val,
1499  *upper_val;
1500  NullTest *nulltest;
1501  List *lower_or_arms,
1502  *upper_or_arms;
1503  int num_or_arms,
1504  current_or_arm;
1505  ListCell *lower_or_start_datum,
1506  *upper_or_start_datum;
1507  bool need_next_lower_arm,
1508  need_next_upper_arm;
1509 
1510  lower_or_start_datum = list_head(spec->lowerdatums);
1511  upper_or_start_datum = list_head(spec->upperdatums);
1512  num_or_arms = key->partnatts;
1513 
1514  /*
1515  * A range-partitioned table does not currently allow partition keys to
1516  * be null, so emit an IS NOT NULL expression for each key column.
1517  */
1518  partexprs_item = list_head(key->partexprs);
1519  for (i = 0; i < key->partnatts; i++)
1520  {
1521  Expr *keyCol;
1522 
1523  if (key->partattrs[i] != 0)
1524  {
1525  keyCol = (Expr *) makeVar(1,
1526  key->partattrs[i],
1527  key->parttypid[i],
1528  key->parttypmod[i],
1529  key->parttypcoll[i],
1530  0);
1531  }
1532  else
1533  {
1534  if (partexprs_item == NULL)
1535  elog(ERROR, "wrong number of partition key expressions");
1536  keyCol = copyObject(lfirst(partexprs_item));
1537  partexprs_item = lnext(partexprs_item);
1538  }
1539 
1540  nulltest = makeNode(NullTest);
1541  nulltest->arg = keyCol;
1542  nulltest->nulltesttype = IS_NOT_NULL;
1543  nulltest->argisrow = false;
1544  nulltest->location = -1;
1545  result = lappend(result, nulltest);
1546  }
1547 
1548  /*
1549  * Iterate over the key columns and check if the corresponding lower and
1550  * upper datums are equal using the btree equality operator for the
1551  * column's type. If equal, we emit single keyCol = common_value
1552  * expression. Starting from the first column for which the corresponding
1553  * lower and upper bound datums are not equal, we generate OR expressions
1554  * as shown in the function's header comment.
1555  */
1556  i = 0;
1557  partexprs_item = list_head(key->partexprs);
1558  partexprs_item_saved = partexprs_item; /* placate compiler */
1559  forboth(cell1, spec->lowerdatums, cell2, spec->upperdatums)
1560  {
1561  EState *estate;
1562  MemoryContext oldcxt;
1563  Expr *test_expr;
1564  ExprState *test_exprstate;
1565  Datum test_result;
1566  bool isNull;
1567 
1568  ldatum = lfirst(cell1);
1569  udatum = lfirst(cell2);
1570 
1571  /*
1572  * Since get_range_key_properties() modifies partexprs_item, and we
1573  * might need to start over from the previous expression in the later
1574  * part of this functiom, save away the current value.
1575  */
1576  partexprs_item_saved = partexprs_item;
1577 
1578  get_range_key_properties(key, i, ldatum, udatum,
1579  &partexprs_item,
1580  &keyCol,
1581  &lower_val, &upper_val);
1582 
1583  /*
1584  * If either or both of lower_val and upper_val is NULL, they are
1585  * unequal, because being NULL means the column is unbounded in the
1586  * respective direction.
1587  */
1588  if (!lower_val || !upper_val)
1589  break;
1590 
1591  /* Create the test expression */
1592  estate = CreateExecutorState();
1593  oldcxt = MemoryContextSwitchTo(estate->es_query_cxt);
1594  test_expr = make_partition_op_expr(key, i, BTEqualStrategyNumber,
1595  (Expr *) lower_val,
1596  (Expr *) upper_val);
1597  fix_opfuncids((Node *) test_expr);
1598  test_exprstate = ExecInitExpr(test_expr, NULL);
1599  test_result = ExecEvalExprSwitchContext(test_exprstate,
1600  GetPerTupleExprContext(estate),
1601  &isNull);
1602  MemoryContextSwitchTo(oldcxt);
1603  FreeExecutorState(estate);
1604 
1605  /* If not equal, go generate the OR expressions */
1606  if (!DatumGetBool(test_result))
1607  break;
1608 
1609  /*
1610  * The bounds for the last key column can't be equal, because such a
1611  * range partition would never be allowed to be defined (it would have
1612  * an empty range otherwise).
1613  */
1614  if (i == key->partnatts - 1)
1615  elog(ERROR, "invalid range bound specification");
1616 
1617  /* Equal, so generate keyCol = lower_val expression */
1618  result = lappend(result,
1620  keyCol, (Expr *) lower_val));
1621 
1622  i++;
1623  }
1624 
1625  /* First pair of lower_val and upper_val that are not equal. */
1626  lower_or_start_datum = cell1;
1627  upper_or_start_datum = cell2;
1628 
1629  /* OR will have as many arms as there are key columns left. */
1630  num_or_arms = key->partnatts - i;
1631  current_or_arm = 0;
1632  lower_or_arms = upper_or_arms = NIL;
1633  need_next_lower_arm = need_next_upper_arm = true;
1634  while (current_or_arm < num_or_arms)
1635  {
1636  List *lower_or_arm_args = NIL,
1637  *upper_or_arm_args = NIL;
1638 
1639  j = i;
1640  partexprs_item = partexprs_item_saved;
1641 
1642  for_both_cell(cell1, lower_or_start_datum, cell2, upper_or_start_datum)
1643  {
1644  PartitionRangeDatum *ldatum_next = NULL,
1645  *udatum_next = NULL;
1646 
1647  ldatum = lfirst(cell1);
1648  if (lnext(cell1))
1649  ldatum_next = lfirst(lnext(cell1));
1650  udatum = lfirst(cell2);
1651  if (lnext(cell2))
1652  udatum_next = lfirst(lnext(cell2));
1653  get_range_key_properties(key, j, ldatum, udatum,
1654  &partexprs_item,
1655  &keyCol,
1656  &lower_val, &upper_val);
1657 
1658  if (need_next_lower_arm && lower_val)
1659  {
1660  uint16 strategy;
1661 
1662  /*
1663  * For the non-last columns of this arm, use the EQ operator.
1664  * For the last or the last finite-valued column, use GE.
1665  */
1666  if (j - i < current_or_arm)
1667  strategy = BTEqualStrategyNumber;
1668  else if ((ldatum_next && ldatum_next->infinite) ||
1669  j == key->partnatts - 1)
1670  strategy = BTGreaterEqualStrategyNumber;
1671  else
1672  strategy = BTGreaterStrategyNumber;
1673 
1674  lower_or_arm_args = lappend(lower_or_arm_args,
1675  make_partition_op_expr(key, j,
1676  strategy,
1677  keyCol,
1678  (Expr *) lower_val));
1679  }
1680 
1681  if (need_next_upper_arm && upper_val)
1682  {
1683  uint16 strategy;
1684 
1685  /*
1686  * For the non-last columns of this arm, use the EQ operator.
1687  * For the last finite-valued column, use LE.
1688  */
1689  if (j - i < current_or_arm)
1690  strategy = BTEqualStrategyNumber;
1691  else if (udatum_next && udatum_next->infinite)
1692  strategy = BTLessEqualStrategyNumber;
1693  else
1694  strategy = BTLessStrategyNumber;
1695 
1696  upper_or_arm_args = lappend(upper_or_arm_args,
1697  make_partition_op_expr(key, j,
1698  strategy,
1699  keyCol,
1700  (Expr *) upper_val));
1701 
1702  }
1703 
1704  /*
1705  * Did we generate enough of OR's arguments? First arm considers
1706  * the first of the remaining columns, second arm considers first
1707  * two of the remaining columns, and so on.
1708  */
1709  ++j;
1710  if (j - i > current_or_arm)
1711  {
1712  /*
1713  * We need not emit the next arm if the new column that will
1714  * be considered is unbounded.
1715  */
1716  need_next_lower_arm = ldatum_next && !ldatum_next->infinite;
1717  need_next_upper_arm = udatum_next && !udatum_next->infinite;
1718  break;
1719  }
1720  }
1721 
1722  if (lower_or_arm_args != NIL)
1723  lower_or_arms = lappend(lower_or_arms,
1724  list_length(lower_or_arm_args) > 1
1725  ? makeBoolExpr(AND_EXPR, lower_or_arm_args, -1)
1726  : linitial(lower_or_arm_args));
1727 
1728  if (upper_or_arm_args != NIL)
1729  upper_or_arms = lappend(upper_or_arms,
1730  list_length(upper_or_arm_args) > 1
1731  ? makeBoolExpr(AND_EXPR, upper_or_arm_args, -1)
1732  : linitial(upper_or_arm_args));
1733 
1734  /* If no work to do in the next iteration, break away. */
1735  if (!need_next_lower_arm && !need_next_upper_arm)
1736  break;
1737 
1738  ++current_or_arm;
1739  }
1740 
1741  /*
1742  * Generate the OR expressions for each of lower and upper bounds (if
1743  * required), and append to the list of implicitly ANDed list of
1744  * expressions.
1745  */
1746  if (lower_or_arms != NIL)
1747  result = lappend(result,
1748  list_length(lower_or_arms) > 1
1749  ? makeBoolExpr(OR_EXPR, lower_or_arms, -1)
1750  : linitial(lower_or_arms));
1751  if (upper_or_arms != NIL)
1752  result = lappend(result,
1753  list_length(upper_or_arms) > 1
1754  ? makeBoolExpr(OR_EXPR, upper_or_arms, -1)
1755  : linitial(upper_or_arms));
1756 
1757  /* As noted above, caller expects the list to be non-empty. */
1758  if (result == NULL)
1759  result = list_make1(makeBoolConst(true, false));
1760 
1761  return result;
1762 }
1763 
1764 /*
1765  * generate_partition_qual
1766  *
1767  * Generate partition predicate from rel's partition bound expression
1768  *
1769  * Result expression tree is stored CacheMemoryContext to ensure it survives
1770  * as long as the relcache entry. But we should be running in a less long-lived
1771  * working context. To avoid leaking cache memory if this routine fails partway
1772  * through, we build in working memory and then copy the completed structure
1773  * into cache memory.
1774  */
1775 static List *
1777 {
1778  HeapTuple tuple;
1779  MemoryContext oldcxt;
1780  Datum boundDatum;
1781  bool isnull;
1782  Node *bound;
1783  List *my_qual = NIL,
1784  *result = NIL;
1785  Relation parent;
1786 
1787  /* Guard against stack overflow due to overly deep partition tree */
1789 
1790  /* Quick copy */
1791  if (rel->rd_partcheck != NIL)
1792  return copyObject(rel->rd_partcheck);
1793 
1794  /* Grab at least an AccessShareLock on the parent table */
1796  AccessShareLock);
1797 
1798  /* Get pg_class.relpartbound */
1799  tuple = SearchSysCache1(RELOID, RelationGetRelid(rel));
1800  if (!HeapTupleIsValid(tuple))
1801  elog(ERROR, "cache lookup failed for relation %u",
1802  RelationGetRelid(rel));
1803 
1804  boundDatum = SysCacheGetAttr(RELOID, tuple,
1806  &isnull);
1807  if (isnull) /* should not happen */
1808  elog(ERROR, "relation \"%s\" has relpartbound = null",
1810  bound = stringToNode(TextDatumGetCString(boundDatum));
1811  ReleaseSysCache(tuple);
1812 
1813  my_qual = get_qual_from_partbound(rel, parent, bound);
1814 
1815  /* Add the parent's quals to the list (if any) */
1816  if (parent->rd_rel->relispartition)
1817  result = list_concat(generate_partition_qual(parent), my_qual);
1818  else
1819  result = my_qual;
1820 
1821  /*
1822  * Change Vars to have partition's attnos instead of the parent's. We do
1823  * this after we concatenate the parent's quals, because we want every Var
1824  * in it to bear this relation's attnos. It's safe to assume varno = 1
1825  * here.
1826  */
1827  result = map_partition_varattnos(result, 1, rel, parent);
1828 
1829  /* Save a copy in the relcache */
1831  rel->rd_partcheck = copyObject(result);
1832  MemoryContextSwitchTo(oldcxt);
1833 
1834  /* Keep the parent locked until commit */
1835  heap_close(parent, NoLock);
1836 
1837  return result;
1838 }
1839 
1840 /* ----------------
1841  * FormPartitionKeyDatum
1842  * Construct values[] and isnull[] arrays for the partition key
1843  * of a tuple.
1844  *
1845  * pd Partition dispatch object of the partitioned table
1846  * slot Heap tuple from which to extract partition key
1847  * estate executor state for evaluating any partition key
1848  * expressions (must be non-NULL)
1849  * values Array of partition key Datums (output area)
1850  * isnull Array of is-null indicators (output area)
1851  *
1852  * the ecxt_scantuple slot of estate's per-tuple expr context must point to
1853  * the heap tuple passed in.
1854  * ----------------
1855  */
1856 void
1858  TupleTableSlot *slot,
1859  EState *estate,
1860  Datum *values,
1861  bool *isnull)
1862 {
1863  ListCell *partexpr_item;
1864  int i;
1865 
1866  if (pd->key->partexprs != NIL && pd->keystate == NIL)
1867  {
1868  /* Check caller has set up context correctly */
1869  Assert(estate != NULL &&
1870  GetPerTupleExprContext(estate)->ecxt_scantuple == slot);
1871 
1872  /* First time through, set up expression evaluation state */
1873  pd->keystate = ExecPrepareExprList(pd->key->partexprs, estate);
1874  }
1875 
1876  partexpr_item = list_head(pd->keystate);
1877  for (i = 0; i < pd->key->partnatts; i++)
1878  {
1879  AttrNumber keycol = pd->key->partattrs[i];
1880  Datum datum;
1881  bool isNull;
1882 
1883  if (keycol != 0)
1884  {
1885  /* Plain column; get the value directly from the heap tuple */
1886  datum = slot_getattr(slot, keycol, &isNull);
1887  }
1888  else
1889  {
1890  /* Expression; need to evaluate it */
1891  if (partexpr_item == NULL)
1892  elog(ERROR, "wrong number of partition key expressions");
1893  datum = ExecEvalExprSwitchContext((ExprState *) lfirst(partexpr_item),
1894  GetPerTupleExprContext(estate),
1895  &isNull);
1896  partexpr_item = lnext(partexpr_item);
1897  }
1898  values[i] = datum;
1899  isnull[i] = isNull;
1900  }
1901 
1902  if (partexpr_item != NULL)
1903  elog(ERROR, "wrong number of partition key expressions");
1904 }
1905 
1906 /*
1907  * get_partition_for_tuple
1908  * Finds a leaf partition for tuple contained in *slot
1909  *
1910  * Returned value is the sequence number of the leaf partition thus found,
1911  * or -1 if no leaf partition is found for the tuple. *failed_at is set
1912  * to the OID of the partitioned table whose partition was not found in
1913  * the latter case.
1914  */
1915 int
1917  TupleTableSlot *slot,
1918  EState *estate,
1919  PartitionDispatchData **failed_at,
1920  TupleTableSlot **failed_slot)
1921 {
1922  PartitionDispatch parent;
1924  bool isnull[PARTITION_MAX_KEYS];
1925  int cur_offset,
1926  cur_index;
1927  int i,
1928  result;
1929  ExprContext *ecxt = GetPerTupleExprContext(estate);
1930  TupleTableSlot *ecxt_scantuple_old = ecxt->ecxt_scantuple;
1931 
1932  /* start with the root partitioned table */
1933  parent = pd[0];
1934  while (true)
1935  {
1936  PartitionKey key = parent->key;
1937  PartitionDesc partdesc = parent->partdesc;
1938  TupleTableSlot *myslot = parent->tupslot;
1939  TupleConversionMap *map = parent->tupmap;
1940 
1941  if (myslot != NULL && map != NULL)
1942  {
1943  HeapTuple tuple = ExecFetchSlotTuple(slot);
1944 
1945  ExecClearTuple(myslot);
1946  tuple = do_convert_tuple(tuple, map);
1947  ExecStoreTuple(tuple, myslot, InvalidBuffer, true);
1948  slot = myslot;
1949  }
1950 
1951  /* Quick exit */
1952  if (partdesc->nparts == 0)
1953  {
1954  *failed_at = parent;
1955  *failed_slot = slot;
1956  result = -1;
1957  goto error_exit;
1958  }
1959 
1960  /*
1961  * Extract partition key from tuple. Expression evaluation machinery
1962  * that FormPartitionKeyDatum() invokes expects ecxt_scantuple to
1963  * point to the correct tuple slot. The slot might have changed from
1964  * what was used for the parent table if the table of the current
1965  * partitioning level has different tuple descriptor from the parent.
1966  * So update ecxt_scantuple accordingly.
1967  */
1968  ecxt->ecxt_scantuple = slot;
1969  FormPartitionKeyDatum(parent, slot, estate, values, isnull);
1970 
1971  if (key->strategy == PARTITION_STRATEGY_RANGE)
1972  {
1973  /*
1974  * Since we cannot route tuples with NULL partition keys through
1975  * a range-partitioned table, simply return that no partition
1976  * exists
1977  */
1978  for (i = 0; i < key->partnatts; i++)
1979  {
1980  if (isnull[i])
1981  {
1982  *failed_at = parent;
1983  *failed_slot = slot;
1984  result = -1;
1985  goto error_exit;
1986  }
1987  }
1988  }
1989 
1990  /*
1991  * A null partition key is only acceptable if null-accepting list
1992  * partition exists.
1993  */
1994  cur_index = -1;
1995  if (isnull[0] && partition_bound_accepts_nulls(partdesc->boundinfo))
1996  cur_index = partdesc->boundinfo->null_index;
1997  else if (!isnull[0])
1998  {
1999  /* Else bsearch in partdesc->boundinfo */
2000  bool equal = false;
2001 
2002  cur_offset = partition_bound_bsearch(key, partdesc->boundinfo,
2003  values, false, &equal);
2004  switch (key->strategy)
2005  {
2007  if (cur_offset >= 0 && equal)
2008  cur_index = partdesc->boundinfo->indexes[cur_offset];
2009  else
2010  cur_index = -1;
2011  break;
2012 
2014 
2015  /*
2016  * Offset returned is such that the bound at offset is
2017  * found to be less or equal with the tuple. So, the bound
2018  * at offset+1 would be the upper bound.
2019  */
2020  cur_index = partdesc->boundinfo->indexes[cur_offset + 1];
2021  break;
2022 
2023  default:
2024  elog(ERROR, "unexpected partition strategy: %d",
2025  (int) key->strategy);
2026  }
2027  }
2028 
2029  /*
2030  * cur_index < 0 means we failed to find a partition of this parent.
2031  * cur_index >= 0 means we either found the leaf partition, or the
2032  * next parent to find a partition of.
2033  */
2034  if (cur_index < 0)
2035  {
2036  result = -1;
2037  *failed_at = parent;
2038  *failed_slot = slot;
2039  break;
2040  }
2041  else if (parent->indexes[cur_index] >= 0)
2042  {
2043  result = parent->indexes[cur_index];
2044  break;
2045  }
2046  else
2047  parent = pd[-parent->indexes[cur_index]];
2048  }
2049 
2050 error_exit:
2051  ecxt->ecxt_scantuple = ecxt_scantuple_old;
2052  return result;
2053 }
2054 
2055 /*
2056  * qsort_partition_list_value_cmp
2057  *
2058  * Compare two list partition bound datums
2059  */
2060 static int32
2061 qsort_partition_list_value_cmp(const void *a, const void *b, void *arg)
2062 {
2063  Datum val1 = (*(const PartitionListValue **) a)->value,
2064  val2 = (*(const PartitionListValue **) b)->value;
2065  PartitionKey key = (PartitionKey) arg;
2066 
2068  key->partcollation[0],
2069  val1, val2));
2070 }
2071 
2072 /*
2073  * make_one_range_bound
2074  *
2075  * Return a PartitionRangeBound given a list of PartitionRangeDatum elements
2076  * and a flag telling whether the bound is lower or not. Made into a function
2077  * because there are multiple sites that want to use this facility.
2078  */
2079 static PartitionRangeBound *
2081 {
2082  PartitionRangeBound *bound;
2083  ListCell *cell;
2084  int i;
2085 
2086  bound = (PartitionRangeBound *) palloc0(sizeof(PartitionRangeBound));
2087  bound->index = index;
2088  bound->datums = (Datum *) palloc0(key->partnatts * sizeof(Datum));
2089  bound->content = (RangeDatumContent *) palloc0(key->partnatts *
2090  sizeof(RangeDatumContent));
2091  bound->lower = lower;
2092 
2093  i = 0;
2094  foreach(cell, datums)
2095  {
2096  PartitionRangeDatum *datum = lfirst(cell);
2097 
2098  /* What's contained in this range datum? */
2099  bound->content[i] = !datum->infinite
2101  : (lower ? RANGE_DATUM_NEG_INF
2103 
2104  if (bound->content[i] == RANGE_DATUM_FINITE)
2105  {
2106  Const *val = (Const *) datum->value;
2107 
2108  if (val->constisnull)
2109  elog(ERROR, "invalid range bound datum");
2110  bound->datums[i] = val->constvalue;
2111  }
2112 
2113  i++;
2114  }
2115 
2116  return bound;
2117 }
2118 
2119 /* Used when sorting range bounds across all range partitions */
2120 static int32
2121 qsort_partition_rbound_cmp(const void *a, const void *b, void *arg)
2122 {
2123  PartitionRangeBound *b1 = (*(PartitionRangeBound *const *) a);
2124  PartitionRangeBound *b2 = (*(PartitionRangeBound *const *) b);
2125  PartitionKey key = (PartitionKey) arg;
2126 
2127  return partition_rbound_cmp(key, b1->datums, b1->content, b1->lower, b2);
2128 }
2129 
2130 /*
2131  * partition_rbound_cmp
2132  *
2133  * Return for two range bounds whether the 1st one (specified in datum1,
2134  * content1, and lower1) is <=, =, >= the bound specified in *b2
2135  */
2136 static int32
2138  Datum *datums1, RangeDatumContent *content1, bool lower1,
2139  PartitionRangeBound *b2)
2140 {
2141  int32 cmpval = 0; /* placate compiler */
2142  int i;
2143  Datum *datums2 = b2->datums;
2144  RangeDatumContent *content2 = b2->content;
2145  bool lower2 = b2->lower;
2146 
2147  for (i = 0; i < key->partnatts; i++)
2148  {
2149  /*
2150  * First, handle cases involving infinity, which don't require
2151  * invoking the comparison proc.
2152  */
2153  if (content1[i] != RANGE_DATUM_FINITE &&
2154  content2[i] != RANGE_DATUM_FINITE)
2155 
2156  /*
2157  * Both are infinity, so they are equal unless one is negative
2158  * infinity and other positive (or vice versa)
2159  */
2160  return content1[i] == content2[i] ? 0
2161  : (content1[i] < content2[i] ? -1 : 1);
2162  else if (content1[i] != RANGE_DATUM_FINITE)
2163  return content1[i] == RANGE_DATUM_NEG_INF ? -1 : 1;
2164  else if (content2[i] != RANGE_DATUM_FINITE)
2165  return content2[i] == RANGE_DATUM_NEG_INF ? 1 : -1;
2166 
2167  cmpval = DatumGetInt32(FunctionCall2Coll(&key->partsupfunc[i],
2168  key->partcollation[i],
2169  datums1[i],
2170  datums2[i]));
2171  if (cmpval != 0)
2172  break;
2173  }
2174 
2175  /*
2176  * If the comparison is anything other than equal, we're done. If they
2177  * compare equal though, we still have to consider whether the boundaries
2178  * are inclusive or exclusive. Exclusive one is considered smaller of the
2179  * two.
2180  */
2181  if (cmpval == 0 && lower1 != lower2)
2182  cmpval = lower1 ? 1 : -1;
2183 
2184  return cmpval;
2185 }
2186 
2187 /*
2188  * partition_rbound_datum_cmp
2189  *
2190  * Return whether range bound (specified in rb_datums, rb_content, and
2191  * rb_lower) <=, =, >= partition key of tuple (tuple_datums)
2192  */
2193 static int32
2195  Datum *rb_datums, RangeDatumContent *rb_content,
2196  Datum *tuple_datums)
2197 {
2198  int i;
2199  int32 cmpval = -1;
2200 
2201  for (i = 0; i < key->partnatts; i++)
2202  {
2203  if (rb_content[i] != RANGE_DATUM_FINITE)
2204  return rb_content[i] == RANGE_DATUM_NEG_INF ? -1 : 1;
2205 
2206  cmpval = DatumGetInt32(FunctionCall2Coll(&key->partsupfunc[i],
2207  key->partcollation[i],
2208  rb_datums[i],
2209  tuple_datums[i]));
2210  if (cmpval != 0)
2211  break;
2212  }
2213 
2214  return cmpval;
2215 }
2216 
2217 /*
2218  * partition_bound_cmp
2219  *
2220  * Return whether the bound at offset in boundinfo is <=, =, >= the argument
2221  * specified in *probe.
2222  */
2223 static int32
2225  int offset, void *probe, bool probe_is_bound)
2226 {
2227  Datum *bound_datums = boundinfo->datums[offset];
2228  int32 cmpval = -1;
2229 
2230  switch (key->strategy)
2231  {
2233  cmpval = DatumGetInt32(FunctionCall2Coll(&key->partsupfunc[0],
2234  key->partcollation[0],
2235  bound_datums[0],
2236  *(Datum *) probe));
2237  break;
2238 
2240  {
2241  RangeDatumContent *content = boundinfo->content[offset];
2242 
2243  if (probe_is_bound)
2244  {
2245  /*
2246  * We need to pass whether the existing bound is a lower
2247  * bound, so that two equal-valued lower and upper bounds
2248  * are not regarded equal.
2249  */
2250  bool lower = boundinfo->indexes[offset] < 0;
2251 
2252  cmpval = partition_rbound_cmp(key,
2253  bound_datums, content, lower,
2254  (PartitionRangeBound *) probe);
2255  }
2256  else
2257  cmpval = partition_rbound_datum_cmp(key,
2258  bound_datums, content,
2259  (Datum *) probe);
2260  break;
2261  }
2262 
2263  default:
2264  elog(ERROR, "unexpected partition strategy: %d",
2265  (int) key->strategy);
2266  }
2267 
2268  return cmpval;
2269 }
2270 
2271 /*
2272  * Binary search on a collection of partition bounds. Returns greatest
2273  * bound in array boundinfo->datums which is less than or equal to *probe
2274  * If all bounds in the array are greater than *probe, -1 is returned.
2275  *
2276  * *probe could either be a partition bound or a Datum array representing
2277  * the partition key of a tuple being routed; probe_is_bound tells which.
2278  * We pass that down to the comparison function so that it can interpret the
2279  * contents of *probe accordingly.
2280  *
2281  * *is_equal is set to whether the bound at the returned index is equal with
2282  * *probe.
2283  */
2284 static int
2286  void *probe, bool probe_is_bound, bool *is_equal)
2287 {
2288  int lo,
2289  hi,
2290  mid;
2291 
2292  lo = -1;
2293  hi = boundinfo->ndatums - 1;
2294  while (lo < hi)
2295  {
2296  int32 cmpval;
2297 
2298  mid = (lo + hi + 1) / 2;
2299  cmpval = partition_bound_cmp(key, boundinfo, mid, probe,
2300  probe_is_bound);
2301  if (cmpval <= 0)
2302  {
2303  lo = mid;
2304  *is_equal = (cmpval == 0);
2305 
2306  if (*is_equal)
2307  break;
2308  }
2309  else
2310  hi = mid - 1;
2311  }
2312 
2313  return lo;
2314 }
Datum constvalue
Definition: primnodes.h:196
#define list_make2(x1, x2)
Definition: pg_list.h:140
Node * map_variable_attnos(Node *node, int target_varno, int sublevels_up, const AttrNumber *attno_map, int map_length, bool *found_whole_row)
bool multidims
Definition: primnodes.h:955
#define NIL
Definition: pg_list.h:69
TupleTableSlot * ExecStoreTuple(HeapTuple tuple, TupleTableSlot *slot, Buffer buffer, bool shouldFree)
Definition: execTuples.c:320
static int32 partition_rbound_datum_cmp(PartitionKey key, Datum *rb_datums, RangeDatumContent *rb_content, Datum *tuple_datums)
Definition: partition.c:2194
struct PartitionDescData * rd_partdesc
Definition: rel.h:131
#define Anum_pg_inherits_inhrelid
Definition: pg_inherits.h:50
void * stringToNode(char *str)
Definition: read.c:38
#define IsA(nodeptr, _type_)
Definition: nodes.h:560
struct PartitionDispatchData * PartitionDispatch
Definition: partition.h:71
static Expr * make_partition_op_expr(PartitionKey key, int keynum, uint16 strategy, Expr *arg1, Expr *arg2)
Definition: partition.c:1233
PartitionDesc partdesc
Definition: partition.h:65
static Datum ExecEvalExprSwitchContext(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:281
#define BTGreaterStrategyNumber
Definition: stratnum.h:33
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:180
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:499
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
static int32 next
Definition: blutils.c:210
#define DatumGetInt32(X)
Definition: postgres.h:478
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:2962
#define RelationGetDescr(relation)
Definition: rel.h:429
Oid * partopfamily
Definition: rel.h:61
Datum lower(PG_FUNCTION_ARGS)
Definition: oracle_compat.c:43
FmgrInfo * partsupfunc
Definition: rel.h:63
Oid get_array_type(Oid typid)
Definition: lsyscache.c:2512
void fix_opfuncids(Node *node)
Definition: nodeFuncs.c:1604
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1801
static Oid get_partition_operator(PartitionKey key, int col, StrategyNumber strategy, bool *need_relabel)
Definition: partition.c:1184
bool datumIsEqual(Datum value1, Datum value2, bool typByVal, int typLen)
Definition: datum.c:219
TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: execTuples.c:439
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
static int32 qsort_partition_rbound_cmp(const void *a, const void *b, void *arg)
Definition: partition.c:2121
TupleConversionMap * tupmap
Definition: partition.h:67
#define AccessShareLock
Definition: lockdefs.h:36
#define InvalidBuffer
Definition: buf.h:25
#define gettext_noop(x)
Definition: c.h:139
Definition: nodes.h:509
#define partition_bound_accepts_nulls(bi)
Definition: partition.c:93
struct cursor * cur
Definition: ecpg.c:28
uint16 StrategyNumber
Definition: stratnum.h:22
int errcode(int sqlerrcode)
Definition: elog.c:575
#define PARTITION_MAX_KEYS
Oid array_typeid
Definition: primnodes.h:951
int get_partition_for_tuple(PartitionDispatch *pd, TupleTableSlot *slot, EState *estate, PartitionDispatchData **failed_at, TupleTableSlot **failed_slot)
Definition: partition.c:1916
List * list_concat(List *list1, List *list2)
Definition: list.c:321
return result
Definition: formatting.c:1632
struct PartitionListValue PartitionListValue
Expr * make_opclause(Oid opno, Oid opresulttype, bool opretset, Expr *leftop, Expr *rightop, Oid opcollid, Oid inputcollid)
Definition: clauses.c:172
#define heap_close(r, l)
Definition: heapam.h:97
Datum upper(PG_FUNCTION_ARGS)
Definition: oracle_compat.c:74
List * partexprs
Definition: rel.h:58
char strategy
Definition: rel.h:54
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1047
Form_pg_class rd_rel
Definition: rel.h:114
unsigned int Oid
Definition: postgres_ext.h:31
List * lappend_oid(List *list, Oid datum)
Definition: list.c:164
#define OidIsValid(objectId)
Definition: c.h:538
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:328
void RelationBuildPartitionDesc(Relation rel)
Definition: partition.c:159
#define SearchSysCache1(cacheId, key1)
Definition: syscache.h:156
signed int int32
Definition: c.h:256
Expr * makeBoolExpr(BoolExprType boolop, List *args, int location)
Definition: makefuncs.c:366
PartitionBoundInfo boundinfo
Definition: partition.h:37
#define BTLessEqualStrategyNumber
Definition: stratnum.h:30
ParseState * make_parsestate(ParseState *parentParseState)
Definition: parse_node.c:44
Definition: type.h:90
#define list_make1(x1)
Definition: pg_list.h:139
void FreeExecutorState(EState *estate)
Definition: execUtils.c:178
#define GetPerTupleExprContext(estate)
Definition: executor.h:456
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:416
unsigned short uint16
Definition: c.h:267
void pfree(void *pointer)
Definition: mcxt.c:950
MemoryContext es_query_cxt
Definition: execnodes.h:448
Oid * parttypcoll
Definition: rel.h:74
#define linitial(l)
Definition: pg_list.h:111
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
static List * get_qual_for_range(PartitionKey key, PartitionBoundSpec *spec)
Definition: partition.c:1486
#define ERROR
Definition: elog.h:43
static int32 partition_rbound_cmp(PartitionKey key, Datum *datums1, RangeDatumContent *content1, bool lower1, PartitionRangeBound *b2)
Definition: partition.c:2137
Oid get_partition_parent(Oid relid)
Definition: partition.c:851
Node * makeBoolConst(bool value, bool isnull)
Definition: makefuncs.c:354
Expr * arg
Definition: primnodes.h:1179
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:165
static int32 qsort_partition_list_value_cmp(const void *a, const void *b, void *arg)
Definition: partition.c:2061
static int partition_bound_bsearch(PartitionKey key, PartitionBoundInfo boundinfo, void *probe, bool probe_is_bound, bool *is_equal)
Definition: partition.c:2285
char * c
void FormPartitionKeyDatum(PartitionDispatch pd, TupleTableSlot *slot, EState *estate, Datum *values, bool *isnull)
Definition: partition.c:1857
#define NoLock
Definition: lockdefs.h:34
RelabelType * makeRelabelType(Expr *arg, Oid rtype, int32 rtypmod, Oid rcollid, CoercionForm rformat)
Definition: makefuncs.c:399
void check_stack_depth(void)
Definition: postgres.c:3102
void check_new_partition_bound(char *relname, Relation parent, Node *bound)
Definition: partition.c:668
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: partition.c:1406
Oid get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype, int16 strategy)
Definition: lsyscache.c:163
#define DatumGetBool(X)
Definition: postgres.h:399
#define RelationGetRelationName(relation)
Definition: rel.h:437
static ListCell * list_head(const List *l)
Definition: pg_list.h:77
List * elements
Definition: primnodes.h:954
TupleTableSlot * MakeSingleTupleTableSlot(TupleDesc tupdesc)
Definition: execTuples.c:199
RangeDatumContent
Definition: partition.c:70
#define lnext(lc)
Definition: pg_list.h:105
#define ereport(elevel, rest)
Definition: elog.h:122
Var * makeVar(Index varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:67
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:128
Oid * parttypid
Definition: rel.h:69
EState * CreateExecutorState(void)
Definition: execUtils.c:80
TupleConversionMap * convert_tuples_by_name(TupleDesc indesc, TupleDesc outdesc, const char *msg)
Definition: tupconvert.c:205
List * ExecPrepareExprList(List *nodes, EState *estate)
Definition: execExpr.c:511
List * lappend(List *list, void *datum)
Definition: list.c:128
void qsort_arg(void *base, size_t nel, size_t elsize, qsort_arg_comparator cmp, void *arg)
Definition: qsort_arg.c:113
AttrNumber * convert_tuples_by_name_map(TupleDesc indesc, TupleDesc outdesc, const char *msg)
Definition: tupconvert.c:283
List * list_delete_cell(List *list, ListCell *cell, ListCell *prev)
Definition: list.c:528
#define RELKIND_PARTITIONED_TABLE
Definition: pg_class.h:168
Oid * partcollation
Definition: rel.h:66
#define TextDatumGetCString(d)
Definition: builtins.h:92
List * RelationGetPartitionQual(Relation rel)
Definition: partition.c:962
static PartitionRangeBound * make_one_range_bound(PartitionKey key, int index, List *datums, bool lower)
Definition: partition.c:2080
MemoryContext AllocSetContextCreate(MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
Definition: aset.c:322
void * palloc0(Size size)
Definition: mcxt.c:878
int location
Definition: primnodes.h:956
AttrNumber * partattrs
Definition: rel.h:56
uintptr_t Datum
Definition: postgres.h:372
int16 partnatts
Definition: rel.h:55
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1117
List * get_qual_from_partbound(Relation rel, Relation parent, Node *bound)
Definition: partition.c:892
TupleTableSlot * tupslot
Definition: partition.h:66
#define Anum_pg_inherits_inhseqno
Definition: pg_inherits.h:52
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1279
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1284
NullTestType nulltesttype
Definition: primnodes.h:1180
int32 * parttypmod
Definition: rel.h:70
struct PartitionBoundInfoData PartitionBoundInfoData
#define InvalidOid
Definition: postgres_ext.h:36
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1094
List * find_inheritance_children(Oid parentrelId, LOCKMODE lockmode)
Definition: pg_inherits.c:57
RangeDatumContent * content
Definition: partition.c:112
#define for_both_cell(cell1, initcell1, cell2, initcell2)
Definition: pg_list.h:194
#define Anum_pg_class_relpartbound
Definition: pg_class.h:135
#define makeNode(_type_)
Definition: nodes.h:557
bool * parttypbyval
Definition: rel.h:72
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:229
MemoryContext rd_pdcxt
Definition: rel.h:130
#define Assert(condition)
Definition: c.h:675
#define lfirst(lc)
Definition: pg_list.h:106
int16 * parttyplen
Definition: rel.h:71
static List * get_qual_for_list(PartitionKey key, PartitionBoundSpec *spec)
Definition: partition.c:1300
Oid array_collid
Definition: primnodes.h:952
#define InheritsRelidSeqnoIndexId
Definition: indexing.h:167
int location
Definition: primnodes.h:1182
FormData_pg_inherits * Form_pg_inherits
Definition: pg_inherits.h:43
static int list_length(const List *l)
Definition: pg_list.h:89
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:111
TupleTableSlot * ecxt_scantuple
Definition: execnodes.h:197
#define type_is_array(typid)
Definition: lsyscache.h:180
#define BOOLOID
Definition: pg_type.h:288
static List * generate_partition_qual(Relation rel)
Definition: partition.c:1776
#define PARTITION_STRATEGY_LIST
Definition: parsenodes.h:781
#define RelationGetPartitionKey(relation)
Definition: rel.h:585
HeapTuple do_convert_tuple(HeapTuple tuple, TupleConversionMap *map)
Definition: tupconvert.c:343
HeapTuple ExecFetchSlotTuple(TupleTableSlot *slot)
Definition: execTuples.c:618
Oid element_typeid
Definition: primnodes.h:953
#define InheritsRelationId
Definition: pg_inherits.h:29
Expr * get_partition_qual_relid(Oid relid)
Definition: partition.c:978
PartitionDispatch * RelationGetPartitionDispatchInfo(Relation rel, int lockmode, int *num_parted, List **leaf_part_oids)
Definition: partition.c:1024
static Datum values[MAXATTR]
Definition: bootstrap.c:163
FormData_pg_class * Form_pg_class
Definition: pg_class.h:95
#define PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:782
#define Int32GetDatum(X)
Definition: postgres.h:485
void * palloc(Size size)
Definition: mcxt.c:849
struct PartitionKeyData * PartitionKey
Definition: rel.h:77
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define APPEND_REL_PARTITION_OIDS(rel, partoids, parents)
Definition: partition.c:1004
Oid * partopcintype
Definition: rel.h:62
int i
Datum slot_getattr(TupleTableSlot *slot, int attnum, bool *isnull)
Definition: heaptuple.c:1141
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
void * arg
bool partition_bounds_equal(PartitionKey key, PartitionBoundInfo b1, PartitionBoundInfo b2)
Definition: partition.c:597
bool argisrow
Definition: primnodes.h:1181
struct PartitionRangeBound PartitionRangeBound
ExprState * ExecInitExpr(Expr *node, PlanState *parent)
Definition: execExpr.c:113
#define elog
Definition: elog.h:219
static struct @121 value
#define copyObject(obj)
Definition: nodes.h:621
#define BTLessStrategyNumber
Definition: stratnum.h:29
Definition: pg_list.h:45
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1726
int16 AttrNumber
Definition: attnum.h:21
#define RelationGetRelid(relation)
Definition: rel.h:417
List * rd_partcheck
Definition: rel.h:132
long val
Definition: informix.c:689
static int32 partition_bound_cmp(PartitionKey key, PartitionBoundInfo boundinfo, int offset, void *probe, bool probe_is_bound)
Definition: partition.c:2224
bool constisnull
Definition: primnodes.h:197
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define BTGreaterEqualStrategyNumber
Definition: stratnum.h:32
#define lfirst_oid(lc)
Definition: pg_list.h:108
#define RelationGetPartitionDesc(relation)
Definition: rel.h:633
List * map_partition_varattnos(List *expr, int target_varno, Relation partrel, Relation parent)
Definition: partition.c:932
MemoryContext CacheMemoryContext
Definition: mcxt.c:46
PartitionKey key
Definition: partition.h:63
RangeDatumContent ** content
Definition: partition.c:83