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"
31 #include "catalog/pg_type.h"
32 #include "commands/tablecmds.h"
33 #include "executor/executor.h"
34 #include "miscadmin.h"
35 #include "nodes/makefuncs.h"
36 #include "nodes/nodeFuncs.h"
37 #include "nodes/parsenodes.h"
38 #include "optimizer/clauses.h"
39 #include "optimizer/planmain.h"
40 #include "optimizer/prep.h"
41 #include "optimizer/var.h"
42 #include "rewrite/rewriteManip.h"
43 #include "storage/lmgr.h"
44 #include "utils/array.h"
45 #include "utils/builtins.h"
46 #include "utils/datum.h"
47 #include "utils/memutils.h"
48 #include "utils/fmgroids.h"
49 #include "utils/inval.h"
50 #include "utils/lsyscache.h"
51 #include "utils/rel.h"
52 #include "utils/ruleutils.h"
53 #include "utils/syscache.h"
54 
55 /*
56  * Information about bounds of a partitioned relation
57  *
58  * A list partition datum that is known to be NULL is never put into the
59  * datums array. Instead, it is tracked using the null_index field.
60  *
61  * In the case of range partitioning, ndatums will typically be far less than
62  * 2 * nparts, because a partition's upper bound and the next partition's lower
63  * bound are the same in most common cases, and we only store one of them (the
64  * upper bound).
65  *
66  * In the case of list partitioning, the indexes array stores one entry for
67  * every datum, which is the index of the partition that accepts a given datum.
68  * In case of range partitioning, it stores one entry per distinct range
69  * datum, which is the index of the partition for which a given datum
70  * is an upper bound.
71  */
72 
73 typedef struct PartitionBoundInfoData
74 {
75  char strategy; /* list or range bounds? */
76  int ndatums; /* Length of the datums following array */
77  Datum **datums; /* Array of datum-tuples with key->partnatts
78  * datums each */
79  PartitionRangeDatumKind **kind; /* The kind of each range bound datum;
80  * NULL for list partitioned tables */
81  int *indexes; /* Partition indexes; one entry per member of
82  * the datums array (plus one if range
83  * partitioned table) */
84  int null_index; /* Index of the null-accepting partition; -1
85  * if there isn't one */
86  int default_index; /* Index of the default partition; -1 if there
87  * isn't one */
89 
90 #define partition_bound_accepts_nulls(bi) ((bi)->null_index != -1)
91 #define partition_bound_has_default(bi) ((bi)->default_index != -1)
92 
93 /*
94  * When qsort'ing partition bounds after reading from the catalog, each bound
95  * is represented with one of the following structs.
96  */
97 
98 /* One value coming from some (index'th) list partition */
99 typedef struct PartitionListValue
100 {
101  int index;
104 
105 /* One bound of a range partition */
106 typedef struct PartitionRangeBound
107 {
108  int index;
109  Datum *datums; /* range bound datums */
110  PartitionRangeDatumKind *kind; /* the kind of each datum */
111  bool lower; /* this is the lower (vs upper) bound */
113 
114 static int32 qsort_partition_list_value_cmp(const void *a, const void *b,
115  void *arg);
116 static int32 qsort_partition_rbound_cmp(const void *a, const void *b,
117  void *arg);
118 
119 static Oid get_partition_operator(PartitionKey key, int col,
120  StrategyNumber strategy, bool *need_relabel);
121 static Expr *make_partition_op_expr(PartitionKey key, int keynum,
122  uint16 strategy, Expr *arg1, Expr *arg2);
123 static void get_range_key_properties(PartitionKey key, int keynum,
124  PartitionRangeDatum *ldatum,
125  PartitionRangeDatum *udatum,
126  ListCell **partexprs_item,
127  Expr **keyCol,
128  Const **lower_val, Const **upper_val);
129 static List *get_qual_for_list(Relation parent, PartitionBoundSpec *spec);
130 static List *get_qual_for_range(Relation parent, PartitionBoundSpec *spec,
131  bool for_default);
134 
136  List *datums, bool lower);
138  Datum *datums1, PartitionRangeDatumKind *kind1,
139  bool lower1, PartitionRangeBound *b2);
141  Datum *rb_datums, PartitionRangeDatumKind *rb_kind,
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 static void get_partition_dispatch_recurse(Relation rel, Relation parent,
151  List **pds, List **leaf_part_oids);
152 
153 /*
154  * RelationBuildPartitionDesc
155  * Form rel's partition descriptor
156  *
157  * Not flushed from the cache by RelationClearRelation() unless changed because
158  * of addition or removal of partition.
159  */
160 void
162 {
163  List *inhoids,
164  *partoids;
165  Oid *oids = NULL;
166  List *boundspecs = NIL;
167  ListCell *cell;
168  int i,
169  nparts;
172  MemoryContext oldcxt;
173 
174  int ndatums = 0;
175  int default_index = -1;
176 
177  /* List partitioning specific */
178  PartitionListValue **all_values = NULL;
179  int null_index = -1;
180 
181  /* Range partitioning specific */
182  PartitionRangeBound **rbounds = NULL;
183 
184  /*
185  * The following could happen in situations where rel has a pg_class entry
186  * but not the pg_partitioned_table entry yet.
187  */
188  if (key == NULL)
189  return;
190 
191  /* Get partition oids from pg_inherits */
193 
194  /* Collect bound spec nodes in a list */
195  i = 0;
196  partoids = NIL;
197  foreach(cell, inhoids)
198  {
199  Oid inhrelid = lfirst_oid(cell);
200  HeapTuple tuple;
201  Datum datum;
202  bool isnull;
203  Node *boundspec;
204 
205  tuple = SearchSysCache1(RELOID, inhrelid);
206  if (!HeapTupleIsValid(tuple))
207  elog(ERROR, "cache lookup failed for relation %u", inhrelid);
208 
209  /*
210  * It is possible that the pg_class tuple of a partition has not been
211  * updated yet to set its relpartbound field. The only case where
212  * this happens is when we open the parent relation to check using its
213  * partition descriptor that a new partition's bound does not overlap
214  * some existing partition.
215  */
216  if (!((Form_pg_class) GETSTRUCT(tuple))->relispartition)
217  {
218  ReleaseSysCache(tuple);
219  continue;
220  }
221 
222  datum = SysCacheGetAttr(RELOID, tuple,
224  &isnull);
225  Assert(!isnull);
226  boundspec = (Node *) stringToNode(TextDatumGetCString(datum));
227 
228  /*
229  * Sanity check: If the PartitionBoundSpec says this is the default
230  * partition, its OID should correspond to whatever's stored in
231  * pg_partitioned_table.partdefid; if not, the catalog is corrupt.
232  */
233  if (castNode(PartitionBoundSpec, boundspec)->is_default)
234  {
235  Oid partdefid;
236 
238  if (partdefid != inhrelid)
239  elog(ERROR, "expected partdefid %u, but got %u",
240  inhrelid, partdefid);
241  }
242 
243  boundspecs = lappend(boundspecs, boundspec);
244  partoids = lappend_oid(partoids, inhrelid);
245  ReleaseSysCache(tuple);
246  }
247 
248  nparts = list_length(partoids);
249 
250  if (nparts > 0)
251  {
252  oids = (Oid *) palloc(nparts * sizeof(Oid));
253  i = 0;
254  foreach(cell, partoids)
255  oids[i++] = lfirst_oid(cell);
256 
257  /* Convert from node to the internal representation */
258  if (key->strategy == PARTITION_STRATEGY_LIST)
259  {
260  List *non_null_values = NIL;
261 
262  /*
263  * Create a unified list of non-null values across all partitions.
264  */
265  i = 0;
266  null_index = -1;
267  foreach(cell, boundspecs)
268  {
270  lfirst(cell));
271  ListCell *c;
272 
273  if (spec->strategy != PARTITION_STRATEGY_LIST)
274  elog(ERROR, "invalid strategy in partition bound spec");
275 
276  /*
277  * Note the index of the partition bound spec for the default
278  * partition. There's no datum to add to the list of non-null
279  * datums for this partition.
280  */
281  if (spec->is_default)
282  {
283  default_index = i;
284  i++;
285  continue;
286  }
287 
288  foreach(c, spec->listdatums)
289  {
290  Const *val = castNode(Const, lfirst(c));
291  PartitionListValue *list_value = NULL;
292 
293  if (!val->constisnull)
294  {
295  list_value = (PartitionListValue *)
296  palloc0(sizeof(PartitionListValue));
297  list_value->index = i;
298  list_value->value = val->constvalue;
299  }
300  else
301  {
302  /*
303  * Never put a null into the values array, flag
304  * instead for the code further down below where we
305  * construct the actual relcache struct.
306  */
307  if (null_index != -1)
308  elog(ERROR, "found null more than once");
309  null_index = i;
310  }
311 
312  if (list_value)
313  non_null_values = lappend(non_null_values,
314  list_value);
315  }
316 
317  i++;
318  }
319 
320  ndatums = list_length(non_null_values);
321 
322  /*
323  * Collect all list values in one array. Alongside the value, we
324  * also save the index of partition the value comes from.
325  */
326  all_values = (PartitionListValue **) palloc(ndatums *
327  sizeof(PartitionListValue *));
328  i = 0;
329  foreach(cell, non_null_values)
330  {
331  PartitionListValue *src = lfirst(cell);
332 
333  all_values[i] = (PartitionListValue *)
334  palloc(sizeof(PartitionListValue));
335  all_values[i]->value = src->value;
336  all_values[i]->index = src->index;
337  i++;
338  }
339 
340  qsort_arg(all_values, ndatums, sizeof(PartitionListValue *),
341  qsort_partition_list_value_cmp, (void *) key);
342  }
343  else if (key->strategy == PARTITION_STRATEGY_RANGE)
344  {
345  int k;
346  PartitionRangeBound **all_bounds,
347  *prev;
348 
349  all_bounds = (PartitionRangeBound **) palloc0(2 * nparts *
350  sizeof(PartitionRangeBound *));
351 
352  /*
353  * Create a unified list of range bounds across all the
354  * partitions.
355  */
356  i = ndatums = 0;
357  foreach(cell, boundspecs)
358  {
360  lfirst(cell));
362  *upper;
363 
364  if (spec->strategy != PARTITION_STRATEGY_RANGE)
365  elog(ERROR, "invalid strategy in partition bound spec");
366 
367  /*
368  * Note the index of the partition bound spec for the default
369  * partition. There's no datum to add to the allbounds array
370  * for this partition.
371  */
372  if (spec->is_default)
373  {
374  default_index = i++;
375  continue;
376  }
377 
378  lower = make_one_range_bound(key, i, spec->lowerdatums,
379  true);
380  upper = make_one_range_bound(key, i, spec->upperdatums,
381  false);
382  all_bounds[ndatums++] = lower;
383  all_bounds[ndatums++] = upper;
384  i++;
385  }
386 
387  Assert(ndatums == nparts * 2 ||
388  (default_index != -1 && ndatums == (nparts - 1) * 2));
389 
390  /* Sort all the bounds in ascending order */
391  qsort_arg(all_bounds, ndatums,
392  sizeof(PartitionRangeBound *),
394  (void *) key);
395 
396  /* Save distinct bounds from all_bounds into rbounds. */
397  rbounds = (PartitionRangeBound **)
398  palloc(ndatums * sizeof(PartitionRangeBound *));
399  k = 0;
400  prev = NULL;
401  for (i = 0; i < ndatums; i++)
402  {
403  PartitionRangeBound *cur = all_bounds[i];
404  bool is_distinct = false;
405  int j;
406 
407  /* Is the current bound distinct from the previous one? */
408  for (j = 0; j < key->partnatts; j++)
409  {
410  Datum cmpval;
411 
412  if (prev == NULL || cur->kind[j] != prev->kind[j])
413  {
414  is_distinct = true;
415  break;
416  }
417 
418  /*
419  * If the bounds are both MINVALUE or MAXVALUE, stop now
420  * and treat them as equal, since any values after this
421  * point must be ignored.
422  */
423  if (cur->kind[j] != PARTITION_RANGE_DATUM_VALUE)
424  break;
425 
426  cmpval = FunctionCall2Coll(&key->partsupfunc[j],
427  key->partcollation[j],
428  cur->datums[j],
429  prev->datums[j]);
430  if (DatumGetInt32(cmpval) != 0)
431  {
432  is_distinct = true;
433  break;
434  }
435  }
436 
437  /*
438  * Only if the bound is distinct save it into a temporary
439  * array i.e. rbounds which is later copied into boundinfo
440  * datums array.
441  */
442  if (is_distinct)
443  rbounds[k++] = all_bounds[i];
444 
445  prev = cur;
446  }
447 
448  /* Update ndatums to hold the count of distinct datums. */
449  ndatums = k;
450  }
451  else
452  elog(ERROR, "unexpected partition strategy: %d",
453  (int) key->strategy);
454  }
455 
456  /* Now build the actual relcache partition descriptor */
460  oldcxt = MemoryContextSwitchTo(rel->rd_pdcxt);
461 
462  result = (PartitionDescData *) palloc0(sizeof(PartitionDescData));
463  result->nparts = nparts;
464  if (nparts > 0)
465  {
466  PartitionBoundInfo boundinfo;
467  int *mapping;
468  int next_index = 0;
469 
470  result->oids = (Oid *) palloc0(nparts * sizeof(Oid));
471 
472  boundinfo = (PartitionBoundInfoData *)
474  boundinfo->strategy = key->strategy;
475  boundinfo->default_index = -1;
476  boundinfo->ndatums = ndatums;
477  boundinfo->null_index = -1;
478  boundinfo->datums = (Datum **) palloc0(ndatums * sizeof(Datum *));
479 
480  /* Initialize mapping array with invalid values */
481  mapping = (int *) palloc(sizeof(int) * nparts);
482  for (i = 0; i < nparts; i++)
483  mapping[i] = -1;
484 
485  switch (key->strategy)
486  {
488  {
489  boundinfo->indexes = (int *) palloc(ndatums * sizeof(int));
490 
491  /*
492  * Copy values. Indexes of individual values are mapped
493  * to canonical values so that they match for any two list
494  * partitioned tables with same number of partitions and
495  * same lists per partition. One way to canonicalize is
496  * to assign the index in all_values[] of the smallest
497  * value of each partition, as the index of all of the
498  * partition's values.
499  */
500  for (i = 0; i < ndatums; i++)
501  {
502  boundinfo->datums[i] = (Datum *) palloc(sizeof(Datum));
503  boundinfo->datums[i][0] = datumCopy(all_values[i]->value,
504  key->parttypbyval[0],
505  key->parttyplen[0]);
506 
507  /* If the old index has no mapping, assign one */
508  if (mapping[all_values[i]->index] == -1)
509  mapping[all_values[i]->index] = next_index++;
510 
511  boundinfo->indexes[i] = mapping[all_values[i]->index];
512  }
513 
514  /*
515  * If null-accepting partition has no mapped index yet,
516  * assign one. This could happen if such partition
517  * accepts only null and hence not covered in the above
518  * loop which only handled non-null values.
519  */
520  if (null_index != -1)
521  {
522  Assert(null_index >= 0);
523  if (mapping[null_index] == -1)
524  mapping[null_index] = next_index++;
525  boundinfo->null_index = mapping[null_index];
526  }
527 
528  /* Assign mapped index for the default partition. */
529  if (default_index != -1)
530  {
531  /*
532  * The default partition accepts any value not
533  * specified in the lists of other partitions, hence
534  * it should not get mapped index while assigning
535  * those for non-null datums.
536  */
537  Assert(default_index >= 0 &&
538  mapping[default_index] == -1);
539  mapping[default_index] = next_index++;
540  boundinfo->default_index = mapping[default_index];
541  }
542 
543  /* All partition must now have a valid mapping */
544  Assert(next_index == nparts);
545  break;
546  }
547 
549  {
550  boundinfo->kind = (PartitionRangeDatumKind **)
551  palloc(ndatums *
552  sizeof(PartitionRangeDatumKind *));
553  boundinfo->indexes = (int *) palloc((ndatums + 1) *
554  sizeof(int));
555 
556  for (i = 0; i < ndatums; i++)
557  {
558  int j;
559 
560  boundinfo->datums[i] = (Datum *) palloc(key->partnatts *
561  sizeof(Datum));
562  boundinfo->kind[i] = (PartitionRangeDatumKind *)
563  palloc(key->partnatts *
564  sizeof(PartitionRangeDatumKind));
565  for (j = 0; j < key->partnatts; j++)
566  {
567  if (rbounds[i]->kind[j] == PARTITION_RANGE_DATUM_VALUE)
568  boundinfo->datums[i][j] =
569  datumCopy(rbounds[i]->datums[j],
570  key->parttypbyval[j],
571  key->parttyplen[j]);
572  boundinfo->kind[i][j] = rbounds[i]->kind[j];
573  }
574 
575  /*
576  * There is no mapping for invalid indexes.
577  *
578  * Any lower bounds in the rbounds array have invalid
579  * indexes assigned, because the values between the
580  * previous bound (if there is one) and this (lower)
581  * bound are not part of the range of any existing
582  * partition.
583  */
584  if (rbounds[i]->lower)
585  boundinfo->indexes[i] = -1;
586  else
587  {
588  int orig_index = rbounds[i]->index;
589 
590  /* If the old index has no mapping, assign one */
591  if (mapping[orig_index] == -1)
592  mapping[orig_index] = next_index++;
593 
594  boundinfo->indexes[i] = mapping[orig_index];
595  }
596  }
597 
598  /* Assign mapped index for the default partition. */
599  if (default_index != -1)
600  {
601  Assert(default_index >= 0 && mapping[default_index] == -1);
602  mapping[default_index] = next_index++;
603  boundinfo->default_index = mapping[default_index];
604  }
605  boundinfo->indexes[i] = -1;
606  break;
607  }
608 
609  default:
610  elog(ERROR, "unexpected partition strategy: %d",
611  (int) key->strategy);
612  }
613 
614  result->boundinfo = boundinfo;
615 
616  /*
617  * Now assign OIDs from the original array into mapped indexes of the
618  * result array. Order of OIDs in the former is defined by the
619  * catalog scan that retrieved them, whereas that in the latter is
620  * defined by canonicalized representation of the list values or the
621  * range bounds.
622  */
623  for (i = 0; i < nparts; i++)
624  result->oids[mapping[i]] = oids[i];
625  pfree(mapping);
626  }
627 
628  MemoryContextSwitchTo(oldcxt);
629  rel->rd_partdesc = result;
630 }
631 
632 /*
633  * Are two partition bound collections logically equal?
634  *
635  * Used in the keep logic of relcache.c (ie, in RelationClearRelation()).
636  * This is also useful when b1 and b2 are bound collections of two separate
637  * relations, respectively, because PartitionBoundInfo is a canonical
638  * representation of partition bounds.
639  */
640 bool
641 partition_bounds_equal(int partnatts, int16 *parttyplen, bool *parttypbyval,
643 {
644  int i;
645 
646  if (b1->strategy != b2->strategy)
647  return false;
648 
649  if (b1->ndatums != b2->ndatums)
650  return false;
651 
652  if (b1->null_index != b2->null_index)
653  return false;
654 
655  if (b1->default_index != b2->default_index)
656  return false;
657 
658  for (i = 0; i < b1->ndatums; i++)
659  {
660  int j;
661 
662  for (j = 0; j < partnatts; j++)
663  {
664  /* For range partitions, the bounds might not be finite. */
665  if (b1->kind != NULL)
666  {
667  /* The different kinds of bound all differ from each other */
668  if (b1->kind[i][j] != b2->kind[i][j])
669  return false;
670 
671  /* Non-finite bounds are equal without further examination. */
672  if (b1->kind[i][j] != PARTITION_RANGE_DATUM_VALUE)
673  continue;
674  }
675 
676  /*
677  * Compare the actual values. Note that it would be both incorrect
678  * and unsafe to invoke the comparison operator derived from the
679  * partitioning specification here. It would be incorrect because
680  * we want the relcache entry to be updated for ANY change to the
681  * partition bounds, not just those that the partitioning operator
682  * thinks are significant. It would be unsafe because we might
683  * reach this code in the context of an aborted transaction, and
684  * an arbitrary partitioning operator might not be safe in that
685  * context. datumIsEqual() should be simple enough to be safe.
686  */
687  if (!datumIsEqual(b1->datums[i][j], b2->datums[i][j],
688  parttypbyval[j], parttyplen[j]))
689  return false;
690  }
691 
692  if (b1->indexes[i] != b2->indexes[i])
693  return false;
694  }
695 
696  /* There are ndatums+1 indexes in case of range partitions */
697  if (b1->strategy == PARTITION_STRATEGY_RANGE &&
698  b1->indexes[i] != b2->indexes[i])
699  return false;
700 
701  return true;
702 }
703 
704 /*
705  * check_new_partition_bound
706  *
707  * Checks if the new partition's bound overlaps any of the existing partitions
708  * of parent. Also performs additional checks as necessary per strategy.
709  */
710 void
711 check_new_partition_bound(char *relname, Relation parent,
712  PartitionBoundSpec *spec)
713 {
715  PartitionDesc partdesc = RelationGetPartitionDesc(parent);
716  PartitionBoundInfo boundinfo = partdesc->boundinfo;
717  ParseState *pstate = make_parsestate(NULL);
718  int with = -1;
719  bool overlap = false;
720 
721  if (spec->is_default)
722  {
723  if (boundinfo == NULL || !partition_bound_has_default(boundinfo))
724  return;
725 
726  /* Default partition already exists, error out. */
727  ereport(ERROR,
728  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
729  errmsg("partition \"%s\" conflicts with existing default partition \"%s\"",
730  relname, get_rel_name(partdesc->oids[boundinfo->default_index])),
731  parser_errposition(pstate, spec->location)));
732  }
733 
734  switch (key->strategy)
735  {
737  {
739 
740  if (partdesc->nparts > 0)
741  {
742  ListCell *cell;
743 
744  Assert(boundinfo &&
745  boundinfo->strategy == PARTITION_STRATEGY_LIST &&
746  (boundinfo->ndatums > 0 ||
747  partition_bound_accepts_nulls(boundinfo) ||
748  partition_bound_has_default(boundinfo)));
749 
750  foreach(cell, spec->listdatums)
751  {
752  Const *val = castNode(Const, lfirst(cell));
753 
754  if (!val->constisnull)
755  {
756  int offset;
757  bool equal;
758 
759  offset = partition_bound_bsearch(key, boundinfo,
760  &val->constvalue,
761  true, &equal);
762  if (offset >= 0 && equal)
763  {
764  overlap = true;
765  with = boundinfo->indexes[offset];
766  break;
767  }
768  }
769  else if (partition_bound_accepts_nulls(boundinfo))
770  {
771  overlap = true;
772  with = boundinfo->null_index;
773  break;
774  }
775  }
776  }
777 
778  break;
779  }
780 
782  {
784  *upper;
785 
787  lower = make_one_range_bound(key, -1, spec->lowerdatums, true);
788  upper = make_one_range_bound(key, -1, spec->upperdatums, false);
789 
790  /*
791  * First check if the resulting range would be empty with
792  * specified lower and upper bounds
793  */
794  if (partition_rbound_cmp(key, lower->datums, lower->kind, true,
795  upper) >= 0)
796  {
797  ereport(ERROR,
798  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
799  errmsg("empty range bound specified for partition \"%s\"",
800  relname),
801  errdetail("Specified lower bound %s is greater than or equal to upper bound %s.",
804  parser_errposition(pstate, spec->location)));
805  }
806 
807  if (partdesc->nparts > 0)
808  {
809  PartitionBoundInfo boundinfo = partdesc->boundinfo;
810  int offset;
811  bool equal;
812 
813  Assert(boundinfo &&
814  boundinfo->strategy == PARTITION_STRATEGY_RANGE &&
815  (boundinfo->ndatums > 0 ||
816  partition_bound_has_default(boundinfo)));
817 
818  /*
819  * Test whether the new lower bound (which is treated
820  * inclusively as part of the new partition) lies inside
821  * an existing partition, or in a gap.
822  *
823  * If it's inside an existing partition, the bound at
824  * offset + 1 will be the upper bound of that partition,
825  * and its index will be >= 0.
826  *
827  * If it's in a gap, the bound at offset + 1 will be the
828  * lower bound of the next partition, and its index will
829  * be -1. This is also true if there is no next partition,
830  * since the index array is initialised with an extra -1
831  * at the end.
832  */
833  offset = partition_bound_bsearch(key, boundinfo, lower,
834  true, &equal);
835 
836  if (boundinfo->indexes[offset + 1] < 0)
837  {
838  /*
839  * Check that the new partition will fit in the gap.
840  * For it to fit, the new upper bound must be less
841  * than or equal to the lower bound of the next
842  * partition, if there is one.
843  */
844  if (offset + 1 < boundinfo->ndatums)
845  {
846  int32 cmpval;
847 
848  cmpval = partition_bound_cmp(key, boundinfo,
849  offset + 1, upper,
850  true);
851  if (cmpval < 0)
852  {
853  /*
854  * The new partition overlaps with the
855  * existing partition between offset + 1 and
856  * offset + 2.
857  */
858  overlap = true;
859  with = boundinfo->indexes[offset + 2];
860  }
861  }
862  }
863  else
864  {
865  /*
866  * The new partition overlaps with the existing
867  * partition between offset and offset + 1.
868  */
869  overlap = true;
870  with = boundinfo->indexes[offset + 1];
871  }
872  }
873 
874  break;
875  }
876 
877  default:
878  elog(ERROR, "unexpected partition strategy: %d",
879  (int) key->strategy);
880  }
881 
882  if (overlap)
883  {
884  Assert(with >= 0);
885  ereport(ERROR,
886  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
887  errmsg("partition \"%s\" would overlap partition \"%s\"",
888  relname, get_rel_name(partdesc->oids[with])),
889  parser_errposition(pstate, spec->location)));
890  }
891 }
892 
893 /*
894  * check_default_allows_bound
895  *
896  * This function checks if there exists a row in the default partition that
897  * would properly belong to the new partition being added. If it finds one,
898  * it throws an error.
899  */
900 void
902  PartitionBoundSpec *new_spec)
903 {
904  List *new_part_constraints;
905  List *def_part_constraints;
906  List *all_parts;
907  ListCell *lc;
908 
909  new_part_constraints = (new_spec->strategy == PARTITION_STRATEGY_LIST)
910  ? get_qual_for_list(parent, new_spec)
911  : get_qual_for_range(parent, new_spec, false);
912  def_part_constraints =
913  get_proposed_default_constraint(new_part_constraints);
914 
915  /*
916  * If the existing constraints on the default partition imply that it will
917  * not contain any row that would belong to the new partition, we can
918  * avoid scanning the default partition.
919  */
920  if (PartConstraintImpliedByRelConstraint(default_rel, def_part_constraints))
921  {
922  ereport(INFO,
923  (errmsg("partition constraint for table \"%s\" is implied by existing constraints",
924  RelationGetRelationName(default_rel))));
925  return;
926  }
927 
928  /*
929  * Scan the default partition and its subpartitions, and check for rows
930  * that do not satisfy the revised partition constraints.
931  */
932  if (default_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
933  all_parts = find_all_inheritors(RelationGetRelid(default_rel),
934  AccessExclusiveLock, NULL);
935  else
936  all_parts = list_make1_oid(RelationGetRelid(default_rel));
937 
938  foreach(lc, all_parts)
939  {
940  Oid part_relid = lfirst_oid(lc);
941  Relation part_rel;
942  Expr *constr;
943  Expr *partition_constraint;
944  EState *estate;
945  HeapTuple tuple;
946  ExprState *partqualstate = NULL;
947  Snapshot snapshot;
948  TupleDesc tupdesc;
949  ExprContext *econtext;
950  HeapScanDesc scan;
951  MemoryContext oldCxt;
952  TupleTableSlot *tupslot;
953 
954  /* Lock already taken above. */
955  if (part_relid != RelationGetRelid(default_rel))
956  part_rel = heap_open(part_relid, NoLock);
957  else
958  part_rel = default_rel;
959 
960  /*
961  * Only RELKIND_RELATION relations (i.e. leaf partitions) need to be
962  * scanned.
963  */
964  if (part_rel->rd_rel->relkind != RELKIND_RELATION)
965  {
966  if (part_rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
968  (errcode(ERRCODE_CHECK_VIOLATION),
969  errmsg("skipped scanning foreign table \"%s\" which is a partition of default partition \"%s\"",
970  RelationGetRelationName(part_rel),
971  RelationGetRelationName(default_rel))));
972 
973  if (RelationGetRelid(default_rel) != RelationGetRelid(part_rel))
974  heap_close(part_rel, NoLock);
975 
976  continue;
977  }
978 
979  tupdesc = CreateTupleDescCopy(RelationGetDescr(part_rel));
980  constr = linitial(def_part_constraints);
981  partition_constraint = (Expr *)
982  map_partition_varattnos((List *) constr,
983  1, part_rel, parent, NULL);
984  estate = CreateExecutorState();
985 
986  /* Build expression execution states for partition check quals */
987  partqualstate = ExecPrepareExpr(partition_constraint, estate);
988 
989  econtext = GetPerTupleExprContext(estate);
990  snapshot = RegisterSnapshot(GetLatestSnapshot());
991  scan = heap_beginscan(part_rel, snapshot, 0, NULL);
992  tupslot = MakeSingleTupleTableSlot(tupdesc);
993 
994  /*
995  * Switch to per-tuple memory context and reset it for each tuple
996  * produced, so we don't leak memory.
997  */
999 
1000  while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
1001  {
1002  ExecStoreTuple(tuple, tupslot, InvalidBuffer, false);
1003  econtext->ecxt_scantuple = tupslot;
1004 
1005  if (!ExecCheck(partqualstate, econtext))
1006  ereport(ERROR,
1007  (errcode(ERRCODE_CHECK_VIOLATION),
1008  errmsg("updated partition constraint for default partition \"%s\" would be violated by some row",
1009  RelationGetRelationName(default_rel))));
1010 
1011  ResetExprContext(econtext);
1013  }
1014 
1015  MemoryContextSwitchTo(oldCxt);
1016  heap_endscan(scan);
1017  UnregisterSnapshot(snapshot);
1019  FreeExecutorState(estate);
1020 
1021  if (RelationGetRelid(default_rel) != RelationGetRelid(part_rel))
1022  heap_close(part_rel, NoLock); /* keep the lock until commit */
1023  }
1024 }
1025 
1026 /*
1027  * get_partition_parent
1028  *
1029  * Returns inheritance parent of a partition by scanning pg_inherits
1030  *
1031  * Note: Because this function assumes that the relation whose OID is passed
1032  * as an argument will have precisely one parent, it should only be called
1033  * when it is known that the relation is a partition.
1034  */
1035 Oid
1037 {
1038  Form_pg_inherits form;
1039  Relation catalogRelation;
1040  SysScanDesc scan;
1041  ScanKeyData key[2];
1042  HeapTuple tuple;
1043  Oid result;
1044 
1045  catalogRelation = heap_open(InheritsRelationId, AccessShareLock);
1046 
1047  ScanKeyInit(&key[0],
1049  BTEqualStrategyNumber, F_OIDEQ,
1050  ObjectIdGetDatum(relid));
1051  ScanKeyInit(&key[1],
1053  BTEqualStrategyNumber, F_INT4EQ,
1054  Int32GetDatum(1));
1055 
1056  scan = systable_beginscan(catalogRelation, InheritsRelidSeqnoIndexId, true,
1057  NULL, 2, key);
1058 
1059  tuple = systable_getnext(scan);
1060  if (!HeapTupleIsValid(tuple))
1061  elog(ERROR, "could not find tuple for parent of relation %u", relid);
1062 
1063  form = (Form_pg_inherits) GETSTRUCT(tuple);
1064  result = form->inhparent;
1065 
1066  systable_endscan(scan);
1067  heap_close(catalogRelation, AccessShareLock);
1068 
1069  return result;
1070 }
1071 
1072 /*
1073  * get_qual_from_partbound
1074  * Given a parser node for partition bound, return the list of executable
1075  * expressions as partition constraint
1076  */
1077 List *
1079  PartitionBoundSpec *spec)
1080 {
1081  PartitionKey key = RelationGetPartitionKey(parent);
1082  List *my_qual = NIL;
1083 
1084  Assert(key != NULL);
1085 
1086  switch (key->strategy)
1087  {
1090  my_qual = get_qual_for_list(parent, spec);
1091  break;
1092 
1095  my_qual = get_qual_for_range(parent, spec, false);
1096  break;
1097 
1098  default:
1099  elog(ERROR, "unexpected partition strategy: %d",
1100  (int) key->strategy);
1101  }
1102 
1103  return my_qual;
1104 }
1105 
1106 /*
1107  * map_partition_varattnos - maps varattno of any Vars in expr from the
1108  * parent attno to partition attno.
1109  *
1110  * We must allow for cases where physical attnos of a partition can be
1111  * different from the parent's.
1112  *
1113  * If found_whole_row is not NULL, *found_whole_row returns whether a
1114  * whole-row variable was found in the input expression.
1115  *
1116  * Note: this will work on any node tree, so really the argument and result
1117  * should be declared "Node *". But a substantial majority of the callers
1118  * are working on Lists, so it's less messy to do the casts internally.
1119  */
1120 List *
1121 map_partition_varattnos(List *expr, int target_varno,
1122  Relation partrel, Relation parent,
1123  bool *found_whole_row)
1124 {
1125  bool my_found_whole_row = false;
1126 
1127  if (expr != NIL)
1128  {
1129  AttrNumber *part_attnos;
1130 
1131  part_attnos = convert_tuples_by_name_map(RelationGetDescr(partrel),
1132  RelationGetDescr(parent),
1133  gettext_noop("could not convert row type"));
1134  expr = (List *) map_variable_attnos((Node *) expr,
1135  target_varno, 0,
1136  part_attnos,
1137  RelationGetDescr(parent)->natts,
1138  RelationGetForm(partrel)->reltype,
1139  &my_found_whole_row);
1140  }
1141 
1142  if (found_whole_row)
1143  *found_whole_row = my_found_whole_row;
1144 
1145  return expr;
1146 }
1147 
1148 /*
1149  * RelationGetPartitionQual
1150  *
1151  * Returns a list of partition quals
1152  */
1153 List *
1155 {
1156  /* Quick exit */
1157  if (!rel->rd_rel->relispartition)
1158  return NIL;
1159 
1160  return generate_partition_qual(rel);
1161 }
1162 
1163 /*
1164  * get_partition_qual_relid
1165  *
1166  * Returns an expression tree describing the passed-in relation's partition
1167  * constraint. If there is no partition constraint returns NULL; this can
1168  * happen if the default partition is the only partition.
1169  */
1170 Expr *
1172 {
1173  Relation rel = heap_open(relid, AccessShareLock);
1174  Expr *result = NULL;
1175  List *and_args;
1176 
1177  /* Do the work only if this relation is a partition. */
1178  if (rel->rd_rel->relispartition)
1179  {
1180  and_args = generate_partition_qual(rel);
1181 
1182  if (and_args == NIL)
1183  result = NULL;
1184  else if (list_length(and_args) > 1)
1185  result = makeBoolExpr(AND_EXPR, and_args, -1);
1186  else
1187  result = linitial(and_args);
1188  }
1189 
1190  /* Keep the lock. */
1191  heap_close(rel, NoLock);
1192 
1193  return result;
1194 }
1195 
1196 /*
1197  * RelationGetPartitionDispatchInfo
1198  * Returns information necessary to route tuples down a partition tree
1199  *
1200  * The number of elements in the returned array (that is, the number of
1201  * PartitionDispatch objects for the partitioned tables in the partition tree)
1202  * is returned in *num_parted and a list of the OIDs of all the leaf
1203  * partitions of rel is returned in *leaf_part_oids.
1204  *
1205  * All the relations in the partition tree (including 'rel') must have been
1206  * locked (using at least the AccessShareLock) by the caller.
1207  */
1210  int *num_parted, List **leaf_part_oids)
1211 {
1212  List *pdlist = NIL;
1213  PartitionDispatchData **pd;
1214  ListCell *lc;
1215  int i;
1216 
1217  Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
1218 
1219  *num_parted = 0;
1220  *leaf_part_oids = NIL;
1221 
1222  get_partition_dispatch_recurse(rel, NULL, &pdlist, leaf_part_oids);
1223  *num_parted = list_length(pdlist);
1224  pd = (PartitionDispatchData **) palloc(*num_parted *
1225  sizeof(PartitionDispatchData *));
1226  i = 0;
1227  foreach(lc, pdlist)
1228  {
1229  pd[i++] = lfirst(lc);
1230  }
1231 
1232  return pd;
1233 }
1234 
1235 /*
1236  * get_partition_dispatch_recurse
1237  * Recursively expand partition tree rooted at rel
1238  *
1239  * As the partition tree is expanded in a depth-first manner, we mantain two
1240  * global lists: of PartitionDispatch objects corresponding to partitioned
1241  * tables in *pds and of the leaf partition OIDs in *leaf_part_oids.
1242  *
1243  * Note that the order of OIDs of leaf partitions in leaf_part_oids matches
1244  * the order in which the planner's expand_partitioned_rtentry() processes
1245  * them. It's not necessarily the case that the offsets match up exactly,
1246  * because constraint exclusion might prune away some partitions on the
1247  * planner side, whereas we'll always have the complete list; but unpruned
1248  * partitions will appear in the same order in the plan as they are returned
1249  * here.
1250  */
1251 static void
1253  List **pds, List **leaf_part_oids)
1254 {
1255  TupleDesc tupdesc = RelationGetDescr(rel);
1256  PartitionDesc partdesc = RelationGetPartitionDesc(rel);
1257  PartitionKey partkey = RelationGetPartitionKey(rel);
1258  PartitionDispatch pd;
1259  int i;
1260 
1262 
1263  /* Build a PartitionDispatch for this table and add it to *pds. */
1265  *pds = lappend(*pds, pd);
1266  pd->reldesc = rel;
1267  pd->key = partkey;
1268  pd->keystate = NIL;
1269  pd->partdesc = partdesc;
1270  if (parent != NULL)
1271  {
1272  /*
1273  * For every partitioned table other than the root, we must store a
1274  * tuple table slot initialized with its tuple descriptor and a tuple
1275  * conversion map to convert a tuple from its parent's rowtype to its
1276  * own. That is to make sure that we are looking at the correct row
1277  * using the correct tuple descriptor when computing its partition key
1278  * for tuple routing.
1279  */
1280  pd->tupslot = MakeSingleTupleTableSlot(tupdesc);
1282  tupdesc,
1283  gettext_noop("could not convert row type"));
1284  }
1285  else
1286  {
1287  /* Not required for the root partitioned table */
1288  pd->tupslot = NULL;
1289  pd->tupmap = NULL;
1290  }
1291 
1292  /*
1293  * Go look at each partition of this table. If it's a leaf partition,
1294  * simply add its OID to *leaf_part_oids. If it's a partitioned table,
1295  * recursively call get_partition_dispatch_recurse(), so that its
1296  * partitions are processed as well and a corresponding PartitionDispatch
1297  * object gets added to *pds.
1298  *
1299  * About the values in pd->indexes: for a leaf partition, it contains the
1300  * leaf partition's position in the global list *leaf_part_oids minus 1,
1301  * whereas for a partitioned table partition, it contains the partition's
1302  * position in the global list *pds multiplied by -1. The latter is
1303  * multiplied by -1 to distinguish partitioned tables from leaf partitions
1304  * when going through the values in pd->indexes. So, for example, when
1305  * using it during tuple-routing, encountering a value >= 0 means we found
1306  * a leaf partition. It is immediately returned as the index in the array
1307  * of ResultRelInfos of all the leaf partitions, using which we insert the
1308  * tuple into that leaf partition. A negative value means we found a
1309  * partitioned table. The value multiplied by -1 is returned as the index
1310  * in the array of PartitionDispatch objects of all partitioned tables in
1311  * the tree. This value is used to continue the search in the next level
1312  * of the partition tree.
1313  */
1314  pd->indexes = (int *) palloc(partdesc->nparts * sizeof(int));
1315  for (i = 0; i < partdesc->nparts; i++)
1316  {
1317  Oid partrelid = partdesc->oids[i];
1318 
1319  if (get_rel_relkind(partrelid) != RELKIND_PARTITIONED_TABLE)
1320  {
1321  *leaf_part_oids = lappend_oid(*leaf_part_oids, partrelid);
1322  pd->indexes[i] = list_length(*leaf_part_oids) - 1;
1323  }
1324  else
1325  {
1326  /*
1327  * We assume all tables in the partition tree were already locked
1328  * by the caller.
1329  */
1330  Relation partrel = heap_open(partrelid, NoLock);
1331 
1332  pd->indexes[i] = -list_length(*pds);
1333  get_partition_dispatch_recurse(partrel, rel, pds, leaf_part_oids);
1334  }
1335  }
1336 }
1337 
1338 /* Module-local functions */
1339 
1340 /*
1341  * get_partition_operator
1342  *
1343  * Return oid of the operator of given strategy for a given partition key
1344  * column.
1345  */
1346 static Oid
1348  bool *need_relabel)
1349 {
1350  Oid operoid;
1351 
1352  /*
1353  * First check if there exists an operator of the given strategy, with
1354  * this column's type as both its lefttype and righttype, in the
1355  * partitioning operator family specified for the column.
1356  */
1357  operoid = get_opfamily_member(key->partopfamily[col],
1358  key->parttypid[col],
1359  key->parttypid[col],
1360  strategy);
1361 
1362  /*
1363  * If one doesn't exist, we must resort to using an operator in the same
1364  * operator family but with the operator class declared input type. It is
1365  * OK to do so, because the column's type is known to be binary-coercible
1366  * with the operator class input type (otherwise, the operator class in
1367  * question would not have been accepted as the partitioning operator
1368  * class). We must however inform the caller to wrap the non-Const
1369  * expression with a RelabelType node to denote the implicit coercion. It
1370  * ensures that the resulting expression structurally matches similarly
1371  * processed expressions within the optimizer.
1372  */
1373  if (!OidIsValid(operoid))
1374  {
1375  operoid = get_opfamily_member(key->partopfamily[col],
1376  key->partopcintype[col],
1377  key->partopcintype[col],
1378  strategy);
1379  if (!OidIsValid(operoid))
1380  elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
1381  strategy, key->partopcintype[col], key->partopcintype[col],
1382  key->partopfamily[col]);
1383  *need_relabel = true;
1384  }
1385  else
1386  *need_relabel = false;
1387 
1388  return operoid;
1389 }
1390 
1391 /*
1392  * make_partition_op_expr
1393  * Returns an Expr for the given partition key column with arg1 and
1394  * arg2 as its leftop and rightop, respectively
1395  */
1396 static Expr *
1398  uint16 strategy, Expr *arg1, Expr *arg2)
1399 {
1400  Oid operoid;
1401  bool need_relabel = false;
1402  Expr *result = NULL;
1403 
1404  /* Get the correct btree operator for this partitioning column */
1405  operoid = get_partition_operator(key, keynum, strategy, &need_relabel);
1406 
1407  /*
1408  * Chosen operator may be such that the non-Const operand needs to be
1409  * coerced, so apply the same; see the comment in
1410  * get_partition_operator().
1411  */
1412  if (!IsA(arg1, Const) &&
1413  (need_relabel ||
1414  key->partcollation[keynum] != key->parttypcoll[keynum]))
1415  arg1 = (Expr *) makeRelabelType(arg1,
1416  key->partopcintype[keynum],
1417  -1,
1418  key->partcollation[keynum],
1420 
1421  /* Generate the actual expression */
1422  switch (key->strategy)
1423  {
1425  {
1426  ScalarArrayOpExpr *saopexpr;
1427 
1428  /* Build leftop = ANY (rightop) */
1429  saopexpr = makeNode(ScalarArrayOpExpr);
1430  saopexpr->opno = operoid;
1431  saopexpr->opfuncid = get_opcode(operoid);
1432  saopexpr->useOr = true;
1433  saopexpr->inputcollid = key->partcollation[keynum];
1434  saopexpr->args = list_make2(arg1, arg2);
1435  saopexpr->location = -1;
1436 
1437  result = (Expr *) saopexpr;
1438  break;
1439  }
1440 
1442  result = make_opclause(operoid,
1443  BOOLOID,
1444  false,
1445  arg1, arg2,
1446  InvalidOid,
1447  key->partcollation[keynum]);
1448  break;
1449 
1450  default:
1451  elog(ERROR, "invalid partitioning strategy");
1452  break;
1453  }
1454 
1455  return result;
1456 }
1457 
1458 /*
1459  * get_qual_for_list
1460  *
1461  * Returns an implicit-AND list of expressions to use as a list partition's
1462  * constraint, given the partition key and bound structures.
1463  *
1464  * The function returns NIL for a default partition when it's the only
1465  * partition since in that case there is no constraint.
1466  */
1467 static List *
1469 {
1470  PartitionKey key = RelationGetPartitionKey(parent);
1471  List *result;
1472  Expr *keyCol;
1473  ArrayExpr *arr;
1474  Expr *opexpr;
1475  NullTest *nulltest;
1476  ListCell *cell;
1477  List *arrelems = NIL;
1478  bool list_has_null = false;
1479 
1480  /*
1481  * Only single-column list partitioning is supported, so we are worried
1482  * only about the partition key with index 0.
1483  */
1484  Assert(key->partnatts == 1);
1485 
1486  /* Construct Var or expression representing the partition column */
1487  if (key->partattrs[0] != 0)
1488  keyCol = (Expr *) makeVar(1,
1489  key->partattrs[0],
1490  key->parttypid[0],
1491  key->parttypmod[0],
1492  key->parttypcoll[0],
1493  0);
1494  else
1495  keyCol = (Expr *) copyObject(linitial(key->partexprs));
1496 
1497  /*
1498  * For default list partition, collect datums for all the partitions. The
1499  * default partition constraint should check that the partition key is
1500  * equal to none of those.
1501  */
1502  if (spec->is_default)
1503  {
1504  int i;
1505  int ndatums = 0;
1506  PartitionDesc pdesc = RelationGetPartitionDesc(parent);
1507  PartitionBoundInfo boundinfo = pdesc->boundinfo;
1508 
1509  if (boundinfo)
1510  {
1511  ndatums = boundinfo->ndatums;
1512 
1513  if (partition_bound_accepts_nulls(boundinfo))
1514  list_has_null = true;
1515  }
1516 
1517  /*
1518  * If default is the only partition, there need not be any partition
1519  * constraint on it.
1520  */
1521  if (ndatums == 0 && !list_has_null)
1522  return NIL;
1523 
1524  for (i = 0; i < ndatums; i++)
1525  {
1526  Const *val;
1527 
1528  /*
1529  * Construct Const from known-not-null datum. We must be careful
1530  * to copy the value, because our result has to be able to outlive
1531  * the relcache entry we're copying from.
1532  */
1533  val = makeConst(key->parttypid[0],
1534  key->parttypmod[0],
1535  key->parttypcoll[0],
1536  key->parttyplen[0],
1537  datumCopy(*boundinfo->datums[i],
1538  key->parttypbyval[0],
1539  key->parttyplen[0]),
1540  false, /* isnull */
1541  key->parttypbyval[0]);
1542 
1543  arrelems = lappend(arrelems, val);
1544  }
1545  }
1546  else
1547  {
1548  /*
1549  * Create list of Consts for the allowed values, excluding any nulls.
1550  */
1551  foreach(cell, spec->listdatums)
1552  {
1553  Const *val = castNode(Const, lfirst(cell));
1554 
1555  if (val->constisnull)
1556  list_has_null = true;
1557  else
1558  arrelems = lappend(arrelems, copyObject(val));
1559  }
1560  }
1561 
1562  if (arrelems)
1563  {
1564  /* Construct an ArrayExpr for the non-null partition values */
1565  arr = makeNode(ArrayExpr);
1566  arr->array_typeid = !type_is_array(key->parttypid[0])
1567  ? get_array_type(key->parttypid[0])
1568  : key->parttypid[0];
1569  arr->array_collid = key->parttypcoll[0];
1570  arr->element_typeid = key->parttypid[0];
1571  arr->elements = arrelems;
1572  arr->multidims = false;
1573  arr->location = -1;
1574 
1575  /* Generate the main expression, i.e., keyCol = ANY (arr) */
1577  keyCol, (Expr *) arr);
1578  }
1579  else
1580  {
1581  /* If there are no partition values, we don't need an = ANY expr */
1582  opexpr = NULL;
1583  }
1584 
1585  if (!list_has_null)
1586  {
1587  /*
1588  * Gin up a "col IS NOT NULL" test that will be AND'd with the main
1589  * expression. This might seem redundant, but the partition routing
1590  * machinery needs it.
1591  */
1592  nulltest = makeNode(NullTest);
1593  nulltest->arg = keyCol;
1594  nulltest->nulltesttype = IS_NOT_NULL;
1595  nulltest->argisrow = false;
1596  nulltest->location = -1;
1597 
1598  result = opexpr ? list_make2(nulltest, opexpr) : list_make1(nulltest);
1599  }
1600  else
1601  {
1602  /*
1603  * Gin up a "col IS NULL" test that will be OR'd with the main
1604  * expression.
1605  */
1606  nulltest = makeNode(NullTest);
1607  nulltest->arg = keyCol;
1608  nulltest->nulltesttype = IS_NULL;
1609  nulltest->argisrow = false;
1610  nulltest->location = -1;
1611 
1612  if (opexpr)
1613  {
1614  Expr *or;
1615 
1616  or = makeBoolExpr(OR_EXPR, list_make2(nulltest, opexpr), -1);
1617  result = list_make1(or);
1618  }
1619  else
1620  result = list_make1(nulltest);
1621  }
1622 
1623  /*
1624  * Note that, in general, applying NOT to a constraint expression doesn't
1625  * necessarily invert the set of rows it accepts, because NOT (NULL) is
1626  * NULL. However, the partition constraints we construct here never
1627  * evaluate to NULL, so applying NOT works as intended.
1628  */
1629  if (spec->is_default)
1630  {
1631  result = list_make1(make_ands_explicit(result));
1632  result = list_make1(makeBoolExpr(NOT_EXPR, result, -1));
1633  }
1634 
1635  return result;
1636 }
1637 
1638 /*
1639  * get_range_key_properties
1640  * Returns range partition key information for a given column
1641  *
1642  * This is a subroutine for get_qual_for_range, and its API is pretty
1643  * specialized to that caller.
1644  *
1645  * Constructs an Expr for the key column (returned in *keyCol) and Consts
1646  * for the lower and upper range limits (returned in *lower_val and
1647  * *upper_val). For MINVALUE/MAXVALUE limits, NULL is returned instead of
1648  * a Const. All of these structures are freshly palloc'd.
1649  *
1650  * *partexprs_item points to the cell containing the next expression in
1651  * the key->partexprs list, or NULL. It may be advanced upon return.
1652  */
1653 static void
1655  PartitionRangeDatum *ldatum,
1656  PartitionRangeDatum *udatum,
1657  ListCell **partexprs_item,
1658  Expr **keyCol,
1659  Const **lower_val, Const **upper_val)
1660 {
1661  /* Get partition key expression for this column */
1662  if (key->partattrs[keynum] != 0)
1663  {
1664  *keyCol = (Expr *) makeVar(1,
1665  key->partattrs[keynum],
1666  key->parttypid[keynum],
1667  key->parttypmod[keynum],
1668  key->parttypcoll[keynum],
1669  0);
1670  }
1671  else
1672  {
1673  if (*partexprs_item == NULL)
1674  elog(ERROR, "wrong number of partition key expressions");
1675  *keyCol = copyObject(lfirst(*partexprs_item));
1676  *partexprs_item = lnext(*partexprs_item);
1677  }
1678 
1679  /* Get appropriate Const nodes for the bounds */
1680  if (ldatum->kind == PARTITION_RANGE_DATUM_VALUE)
1681  *lower_val = castNode(Const, copyObject(ldatum->value));
1682  else
1683  *lower_val = NULL;
1684 
1685  if (udatum->kind == PARTITION_RANGE_DATUM_VALUE)
1686  *upper_val = castNode(Const, copyObject(udatum->value));
1687  else
1688  *upper_val = NULL;
1689 }
1690 
1691  /*
1692  * get_range_nulltest
1693  *
1694  * A non-default range partition table does not currently allow partition
1695  * keys to be null, so emit an IS NOT NULL expression for each key column.
1696  */
1697 static List *
1699 {
1700  List *result = NIL;
1701  NullTest *nulltest;
1702  ListCell *partexprs_item;
1703  int i;
1704 
1705  partexprs_item = list_head(key->partexprs);
1706  for (i = 0; i < key->partnatts; i++)
1707  {
1708  Expr *keyCol;
1709 
1710  if (key->partattrs[i] != 0)
1711  {
1712  keyCol = (Expr *) makeVar(1,
1713  key->partattrs[i],
1714  key->parttypid[i],
1715  key->parttypmod[i],
1716  key->parttypcoll[i],
1717  0);
1718  }
1719  else
1720  {
1721  if (partexprs_item == NULL)
1722  elog(ERROR, "wrong number of partition key expressions");
1723  keyCol = copyObject(lfirst(partexprs_item));
1724  partexprs_item = lnext(partexprs_item);
1725  }
1726 
1727  nulltest = makeNode(NullTest);
1728  nulltest->arg = keyCol;
1729  nulltest->nulltesttype = IS_NOT_NULL;
1730  nulltest->argisrow = false;
1731  nulltest->location = -1;
1732  result = lappend(result, nulltest);
1733  }
1734 
1735  return result;
1736 }
1737 
1738 /*
1739  * get_qual_for_range
1740  *
1741  * Returns an implicit-AND list of expressions to use as a range partition's
1742  * constraint, given the partition key and bound structures.
1743  *
1744  * For a multi-column range partition key, say (a, b, c), with (al, bl, cl)
1745  * as the lower bound tuple and (au, bu, cu) as the upper bound tuple, we
1746  * generate an expression tree of the following form:
1747  *
1748  * (a IS NOT NULL) and (b IS NOT NULL) and (c IS NOT NULL)
1749  * AND
1750  * (a > al OR (a = al AND b > bl) OR (a = al AND b = bl AND c >= cl))
1751  * AND
1752  * (a < au OR (a = au AND b < bu) OR (a = au AND b = bu AND c < cu))
1753  *
1754  * It is often the case that a prefix of lower and upper bound tuples contains
1755  * the same values, for example, (al = au), in which case, we will emit an
1756  * expression tree of the following form:
1757  *
1758  * (a IS NOT NULL) and (b IS NOT NULL) and (c IS NOT NULL)
1759  * AND
1760  * (a = al)
1761  * AND
1762  * (b > bl OR (b = bl AND c >= cl))
1763  * AND
1764  * (b < bu) OR (b = bu AND c < cu))
1765  *
1766  * If a bound datum is either MINVALUE or MAXVALUE, these expressions are
1767  * simplified using the fact that any value is greater than MINVALUE and less
1768  * than MAXVALUE. So, for example, if cu = MAXVALUE, c < cu is automatically
1769  * true, and we need not emit any expression for it, and the last line becomes
1770  *
1771  * (b < bu) OR (b = bu), which is simplified to (b <= bu)
1772  *
1773  * In most common cases with only one partition column, say a, the following
1774  * expression tree will be generated: a IS NOT NULL AND a >= al AND a < au
1775  *
1776  * For default partition, it returns the negation of the constraints of all
1777  * the other partitions.
1778  *
1779  * External callers should pass for_default as false; we set it to true only
1780  * when recursing.
1781  */
1782 static List *
1784  bool for_default)
1785 {
1786  List *result = NIL;
1787  ListCell *cell1,
1788  *cell2,
1789  *partexprs_item,
1790  *partexprs_item_saved;
1791  int i,
1792  j;
1793  PartitionRangeDatum *ldatum,
1794  *udatum;
1795  PartitionKey key = RelationGetPartitionKey(parent);
1796  Expr *keyCol;
1797  Const *lower_val,
1798  *upper_val;
1799  List *lower_or_arms,
1800  *upper_or_arms;
1801  int num_or_arms,
1802  current_or_arm;
1803  ListCell *lower_or_start_datum,
1804  *upper_or_start_datum;
1805  bool need_next_lower_arm,
1806  need_next_upper_arm;
1807 
1808  if (spec->is_default)
1809  {
1810  List *or_expr_args = NIL;
1811  PartitionDesc pdesc = RelationGetPartitionDesc(parent);
1812  Oid *inhoids = pdesc->oids;
1813  int nparts = pdesc->nparts,
1814  i;
1815 
1816  for (i = 0; i < nparts; i++)
1817  {
1818  Oid inhrelid = inhoids[i];
1819  HeapTuple tuple;
1820  Datum datum;
1821  bool isnull;
1822  PartitionBoundSpec *bspec;
1823 
1824  tuple = SearchSysCache1(RELOID, inhrelid);
1825  if (!HeapTupleIsValid(tuple))
1826  elog(ERROR, "cache lookup failed for relation %u", inhrelid);
1827 
1828  datum = SysCacheGetAttr(RELOID, tuple,
1830  &isnull);
1831 
1832  Assert(!isnull);
1833  bspec = (PartitionBoundSpec *)
1835  if (!IsA(bspec, PartitionBoundSpec))
1836  elog(ERROR, "expected PartitionBoundSpec");
1837 
1838  if (!bspec->is_default)
1839  {
1840  List *part_qual;
1841 
1842  part_qual = get_qual_for_range(parent, bspec, true);
1843 
1844  /*
1845  * AND the constraints of the partition and add to
1846  * or_expr_args
1847  */
1848  or_expr_args = lappend(or_expr_args, list_length(part_qual) > 1
1849  ? makeBoolExpr(AND_EXPR, part_qual, -1)
1850  : linitial(part_qual));
1851  }
1852  ReleaseSysCache(tuple);
1853  }
1854 
1855  if (or_expr_args != NIL)
1856  {
1857  /* OR all the non-default partition constraints; then negate it */
1858  result = lappend(result,
1859  list_length(or_expr_args) > 1
1860  ? makeBoolExpr(OR_EXPR, or_expr_args, -1)
1861  : linitial(or_expr_args));
1862  result = list_make1(makeBoolExpr(NOT_EXPR, result, -1));
1863  }
1864 
1865  return result;
1866  }
1867 
1868  lower_or_start_datum = list_head(spec->lowerdatums);
1869  upper_or_start_datum = list_head(spec->upperdatums);
1870  num_or_arms = key->partnatts;
1871 
1872  /*
1873  * If it is the recursive call for default, we skip the get_range_nulltest
1874  * to avoid accumulating the NullTest on the same keys for each partition.
1875  */
1876  if (!for_default)
1877  result = get_range_nulltest(key);
1878 
1879  /*
1880  * Iterate over the key columns and check if the corresponding lower and
1881  * upper datums are equal using the btree equality operator for the
1882  * column's type. If equal, we emit single keyCol = common_value
1883  * expression. Starting from the first column for which the corresponding
1884  * lower and upper bound datums are not equal, we generate OR expressions
1885  * as shown in the function's header comment.
1886  */
1887  i = 0;
1888  partexprs_item = list_head(key->partexprs);
1889  partexprs_item_saved = partexprs_item; /* placate compiler */
1890  forboth(cell1, spec->lowerdatums, cell2, spec->upperdatums)
1891  {
1892  EState *estate;
1893  MemoryContext oldcxt;
1894  Expr *test_expr;
1895  ExprState *test_exprstate;
1896  Datum test_result;
1897  bool isNull;
1898 
1899  ldatum = castNode(PartitionRangeDatum, lfirst(cell1));
1900  udatum = castNode(PartitionRangeDatum, lfirst(cell2));
1901 
1902  /*
1903  * Since get_range_key_properties() modifies partexprs_item, and we
1904  * might need to start over from the previous expression in the later
1905  * part of this function, save away the current value.
1906  */
1907  partexprs_item_saved = partexprs_item;
1908 
1909  get_range_key_properties(key, i, ldatum, udatum,
1910  &partexprs_item,
1911  &keyCol,
1912  &lower_val, &upper_val);
1913 
1914  /*
1915  * If either value is NULL, the corresponding partition bound is
1916  * either MINVALUE or MAXVALUE, and we treat them as unequal, because
1917  * even if they're the same, there is no common value to equate the
1918  * key column with.
1919  */
1920  if (!lower_val || !upper_val)
1921  break;
1922 
1923  /* Create the test expression */
1924  estate = CreateExecutorState();
1925  oldcxt = MemoryContextSwitchTo(estate->es_query_cxt);
1926  test_expr = make_partition_op_expr(key, i, BTEqualStrategyNumber,
1927  (Expr *) lower_val,
1928  (Expr *) upper_val);
1929  fix_opfuncids((Node *) test_expr);
1930  test_exprstate = ExecInitExpr(test_expr, NULL);
1931  test_result = ExecEvalExprSwitchContext(test_exprstate,
1932  GetPerTupleExprContext(estate),
1933  &isNull);
1934  MemoryContextSwitchTo(oldcxt);
1935  FreeExecutorState(estate);
1936 
1937  /* If not equal, go generate the OR expressions */
1938  if (!DatumGetBool(test_result))
1939  break;
1940 
1941  /*
1942  * The bounds for the last key column can't be equal, because such a
1943  * range partition would never be allowed to be defined (it would have
1944  * an empty range otherwise).
1945  */
1946  if (i == key->partnatts - 1)
1947  elog(ERROR, "invalid range bound specification");
1948 
1949  /* Equal, so generate keyCol = lower_val expression */
1950  result = lappend(result,
1952  keyCol, (Expr *) lower_val));
1953 
1954  i++;
1955  }
1956 
1957  /* First pair of lower_val and upper_val that are not equal. */
1958  lower_or_start_datum = cell1;
1959  upper_or_start_datum = cell2;
1960 
1961  /* OR will have as many arms as there are key columns left. */
1962  num_or_arms = key->partnatts - i;
1963  current_or_arm = 0;
1964  lower_or_arms = upper_or_arms = NIL;
1965  need_next_lower_arm = need_next_upper_arm = true;
1966  while (current_or_arm < num_or_arms)
1967  {
1968  List *lower_or_arm_args = NIL,
1969  *upper_or_arm_args = NIL;
1970 
1971  /* Restart scan of columns from the i'th one */
1972  j = i;
1973  partexprs_item = partexprs_item_saved;
1974 
1975  for_both_cell(cell1, lower_or_start_datum, cell2, upper_or_start_datum)
1976  {
1977  PartitionRangeDatum *ldatum_next = NULL,
1978  *udatum_next = NULL;
1979 
1980  ldatum = castNode(PartitionRangeDatum, lfirst(cell1));
1981  if (lnext(cell1))
1982  ldatum_next = castNode(PartitionRangeDatum,
1983  lfirst(lnext(cell1)));
1984  udatum = castNode(PartitionRangeDatum, lfirst(cell2));
1985  if (lnext(cell2))
1986  udatum_next = castNode(PartitionRangeDatum,
1987  lfirst(lnext(cell2)));
1988  get_range_key_properties(key, j, ldatum, udatum,
1989  &partexprs_item,
1990  &keyCol,
1991  &lower_val, &upper_val);
1992 
1993  if (need_next_lower_arm && lower_val)
1994  {
1995  uint16 strategy;
1996 
1997  /*
1998  * For the non-last columns of this arm, use the EQ operator.
1999  * For the last column of this arm, use GT, unless this is the
2000  * last column of the whole bound check, or the next bound
2001  * datum is MINVALUE, in which case use GE.
2002  */
2003  if (j - i < current_or_arm)
2004  strategy = BTEqualStrategyNumber;
2005  else if (j == key->partnatts - 1 ||
2006  (ldatum_next &&
2007  ldatum_next->kind == PARTITION_RANGE_DATUM_MINVALUE))
2008  strategy = BTGreaterEqualStrategyNumber;
2009  else
2010  strategy = BTGreaterStrategyNumber;
2011 
2012  lower_or_arm_args = lappend(lower_or_arm_args,
2013  make_partition_op_expr(key, j,
2014  strategy,
2015  keyCol,
2016  (Expr *) lower_val));
2017  }
2018 
2019  if (need_next_upper_arm && upper_val)
2020  {
2021  uint16 strategy;
2022 
2023  /*
2024  * For the non-last columns of this arm, use the EQ operator.
2025  * For the last column of this arm, use LT, unless the next
2026  * bound datum is MAXVALUE, in which case use LE.
2027  */
2028  if (j - i < current_or_arm)
2029  strategy = BTEqualStrategyNumber;
2030  else if (udatum_next &&
2031  udatum_next->kind == PARTITION_RANGE_DATUM_MAXVALUE)
2032  strategy = BTLessEqualStrategyNumber;
2033  else
2034  strategy = BTLessStrategyNumber;
2035 
2036  upper_or_arm_args = lappend(upper_or_arm_args,
2037  make_partition_op_expr(key, j,
2038  strategy,
2039  keyCol,
2040  (Expr *) upper_val));
2041  }
2042 
2043  /*
2044  * Did we generate enough of OR's arguments? First arm considers
2045  * the first of the remaining columns, second arm considers first
2046  * two of the remaining columns, and so on.
2047  */
2048  ++j;
2049  if (j - i > current_or_arm)
2050  {
2051  /*
2052  * We must not emit any more arms if the new column that will
2053  * be considered is unbounded, or this one was.
2054  */
2055  if (!lower_val || !ldatum_next ||
2056  ldatum_next->kind != PARTITION_RANGE_DATUM_VALUE)
2057  need_next_lower_arm = false;
2058  if (!upper_val || !udatum_next ||
2059  udatum_next->kind != PARTITION_RANGE_DATUM_VALUE)
2060  need_next_upper_arm = false;
2061  break;
2062  }
2063  }
2064 
2065  if (lower_or_arm_args != NIL)
2066  lower_or_arms = lappend(lower_or_arms,
2067  list_length(lower_or_arm_args) > 1
2068  ? makeBoolExpr(AND_EXPR, lower_or_arm_args, -1)
2069  : linitial(lower_or_arm_args));
2070 
2071  if (upper_or_arm_args != NIL)
2072  upper_or_arms = lappend(upper_or_arms,
2073  list_length(upper_or_arm_args) > 1
2074  ? makeBoolExpr(AND_EXPR, upper_or_arm_args, -1)
2075  : linitial(upper_or_arm_args));
2076 
2077  /* If no work to do in the next iteration, break away. */
2078  if (!need_next_lower_arm && !need_next_upper_arm)
2079  break;
2080 
2081  ++current_or_arm;
2082  }
2083 
2084  /*
2085  * Generate the OR expressions for each of lower and upper bounds (if
2086  * required), and append to the list of implicitly ANDed list of
2087  * expressions.
2088  */
2089  if (lower_or_arms != NIL)
2090  result = lappend(result,
2091  list_length(lower_or_arms) > 1
2092  ? makeBoolExpr(OR_EXPR, lower_or_arms, -1)
2093  : linitial(lower_or_arms));
2094  if (upper_or_arms != NIL)
2095  result = lappend(result,
2096  list_length(upper_or_arms) > 1
2097  ? makeBoolExpr(OR_EXPR, upper_or_arms, -1)
2098  : linitial(upper_or_arms));
2099 
2100  /*
2101  * As noted above, for non-default, we return list with constant TRUE. If
2102  * the result is NIL during the recursive call for default, it implies
2103  * this is the only other partition which can hold every value of the key
2104  * except NULL. Hence we return the NullTest result skipped earlier.
2105  */
2106  if (result == NIL)
2107  result = for_default
2108  ? get_range_nulltest(key)
2109  : list_make1(makeBoolConst(true, false));
2110 
2111  return result;
2112 }
2113 
2114 /*
2115  * generate_partition_qual
2116  *
2117  * Generate partition predicate from rel's partition bound expression. The
2118  * function returns a NIL list if there is no predicate.
2119  *
2120  * Result expression tree is stored CacheMemoryContext to ensure it survives
2121  * as long as the relcache entry. But we should be running in a less long-lived
2122  * working context. To avoid leaking cache memory if this routine fails partway
2123  * through, we build in working memory and then copy the completed structure
2124  * into cache memory.
2125  */
2126 static List *
2128 {
2129  HeapTuple tuple;
2130  MemoryContext oldcxt;
2131  Datum boundDatum;
2132  bool isnull;
2133  PartitionBoundSpec *bound;
2134  List *my_qual = NIL,
2135  *result = NIL;
2136  Relation parent;
2137  bool found_whole_row;
2138 
2139  /* Guard against stack overflow due to overly deep partition tree */
2141 
2142  /* Quick copy */
2143  if (rel->rd_partcheck != NIL)
2144  return copyObject(rel->rd_partcheck);
2145 
2146  /* Grab at least an AccessShareLock on the parent table */
2148  AccessShareLock);
2149 
2150  /* Get pg_class.relpartbound */
2151  tuple = SearchSysCache1(RELOID, RelationGetRelid(rel));
2152  if (!HeapTupleIsValid(tuple))
2153  elog(ERROR, "cache lookup failed for relation %u",
2154  RelationGetRelid(rel));
2155 
2156  boundDatum = SysCacheGetAttr(RELOID, tuple,
2158  &isnull);
2159  if (isnull) /* should not happen */
2160  elog(ERROR, "relation \"%s\" has relpartbound = null",
2162  bound = castNode(PartitionBoundSpec,
2163  stringToNode(TextDatumGetCString(boundDatum)));
2164  ReleaseSysCache(tuple);
2165 
2166  my_qual = get_qual_from_partbound(rel, parent, bound);
2167 
2168  /* Add the parent's quals to the list (if any) */
2169  if (parent->rd_rel->relispartition)
2170  result = list_concat(generate_partition_qual(parent), my_qual);
2171  else
2172  result = my_qual;
2173 
2174  /*
2175  * Change Vars to have partition's attnos instead of the parent's. We do
2176  * this after we concatenate the parent's quals, because we want every Var
2177  * in it to bear this relation's attnos. It's safe to assume varno = 1
2178  * here.
2179  */
2180  result = map_partition_varattnos(result, 1, rel, parent,
2181  &found_whole_row);
2182  /* There can never be a whole-row reference here */
2183  if (found_whole_row)
2184  elog(ERROR, "unexpected whole-row reference found in partition key");
2185 
2186  /* Save a copy in the relcache */
2188  rel->rd_partcheck = copyObject(result);
2189  MemoryContextSwitchTo(oldcxt);
2190 
2191  /* Keep the parent locked until commit */
2192  heap_close(parent, NoLock);
2193 
2194  return result;
2195 }
2196 
2197 /* ----------------
2198  * FormPartitionKeyDatum
2199  * Construct values[] and isnull[] arrays for the partition key
2200  * of a tuple.
2201  *
2202  * pd Partition dispatch object of the partitioned table
2203  * slot Heap tuple from which to extract partition key
2204  * estate executor state for evaluating any partition key
2205  * expressions (must be non-NULL)
2206  * values Array of partition key Datums (output area)
2207  * isnull Array of is-null indicators (output area)
2208  *
2209  * the ecxt_scantuple slot of estate's per-tuple expr context must point to
2210  * the heap tuple passed in.
2211  * ----------------
2212  */
2213 void
2215  TupleTableSlot *slot,
2216  EState *estate,
2217  Datum *values,
2218  bool *isnull)
2219 {
2220  ListCell *partexpr_item;
2221  int i;
2222 
2223  if (pd->key->partexprs != NIL && pd->keystate == NIL)
2224  {
2225  /* Check caller has set up context correctly */
2226  Assert(estate != NULL &&
2227  GetPerTupleExprContext(estate)->ecxt_scantuple == slot);
2228 
2229  /* First time through, set up expression evaluation state */
2230  pd->keystate = ExecPrepareExprList(pd->key->partexprs, estate);
2231  }
2232 
2233  partexpr_item = list_head(pd->keystate);
2234  for (i = 0; i < pd->key->partnatts; i++)
2235  {
2236  AttrNumber keycol = pd->key->partattrs[i];
2237  Datum datum;
2238  bool isNull;
2239 
2240  if (keycol != 0)
2241  {
2242  /* Plain column; get the value directly from the heap tuple */
2243  datum = slot_getattr(slot, keycol, &isNull);
2244  }
2245  else
2246  {
2247  /* Expression; need to evaluate it */
2248  if (partexpr_item == NULL)
2249  elog(ERROR, "wrong number of partition key expressions");
2250  datum = ExecEvalExprSwitchContext((ExprState *) lfirst(partexpr_item),
2251  GetPerTupleExprContext(estate),
2252  &isNull);
2253  partexpr_item = lnext(partexpr_item);
2254  }
2255  values[i] = datum;
2256  isnull[i] = isNull;
2257  }
2258 
2259  if (partexpr_item != NULL)
2260  elog(ERROR, "wrong number of partition key expressions");
2261 }
2262 
2263 /*
2264  * get_partition_for_tuple
2265  * Finds a leaf partition for tuple contained in *slot
2266  *
2267  * Returned value is the sequence number of the leaf partition thus found,
2268  * or -1 if no leaf partition is found for the tuple. *failed_at is set
2269  * to the OID of the partitioned table whose partition was not found in
2270  * the latter case.
2271  */
2272 int
2274  TupleTableSlot *slot,
2275  EState *estate,
2276  PartitionDispatchData **failed_at,
2277  TupleTableSlot **failed_slot)
2278 {
2279  PartitionDispatch parent;
2281  bool isnull[PARTITION_MAX_KEYS];
2282  int result;
2283  ExprContext *ecxt = GetPerTupleExprContext(estate);
2284  TupleTableSlot *ecxt_scantuple_old = ecxt->ecxt_scantuple;
2285 
2286  /* start with the root partitioned table */
2287  parent = pd[0];
2288  while (true)
2289  {
2290  PartitionKey key = parent->key;
2291  PartitionDesc partdesc = parent->partdesc;
2292  TupleTableSlot *myslot = parent->tupslot;
2293  TupleConversionMap *map = parent->tupmap;
2294  int cur_index = -1;
2295 
2296  if (myslot != NULL && map != NULL)
2297  {
2298  HeapTuple tuple = ExecFetchSlotTuple(slot);
2299 
2300  ExecClearTuple(myslot);
2301  tuple = do_convert_tuple(tuple, map);
2302  ExecStoreTuple(tuple, myslot, InvalidBuffer, true);
2303  slot = myslot;
2304  }
2305 
2306  /* Quick exit */
2307  if (partdesc->nparts == 0)
2308  {
2309  *failed_at = parent;
2310  *failed_slot = slot;
2311  result = -1;
2312  goto error_exit;
2313  }
2314 
2315  /*
2316  * Extract partition key from tuple. Expression evaluation machinery
2317  * that FormPartitionKeyDatum() invokes expects ecxt_scantuple to
2318  * point to the correct tuple slot. The slot might have changed from
2319  * what was used for the parent table if the table of the current
2320  * partitioning level has different tuple descriptor from the parent.
2321  * So update ecxt_scantuple accordingly.
2322  */
2323  ecxt->ecxt_scantuple = slot;
2324  FormPartitionKeyDatum(parent, slot, estate, values, isnull);
2325 
2326  /* Route as appropriate based on partitioning strategy. */
2327  switch (key->strategy)
2328  {
2330 
2331  if (isnull[0])
2332  {
2334  cur_index = partdesc->boundinfo->null_index;
2335  }
2336  else
2337  {
2338  bool equal = false;
2339  int cur_offset;
2340 
2341  cur_offset = partition_bound_bsearch(key,
2342  partdesc->boundinfo,
2343  values,
2344  false,
2345  &equal);
2346  if (cur_offset >= 0 && equal)
2347  cur_index = partdesc->boundinfo->indexes[cur_offset];
2348  }
2349  break;
2350 
2352  {
2353  bool equal = false,
2354  range_partkey_has_null = false;
2355  int cur_offset;
2356  int i;
2357 
2358  /*
2359  * No range includes NULL, so this will be accepted by the
2360  * default partition if there is one, and otherwise
2361  * rejected.
2362  */
2363  for (i = 0; i < key->partnatts; i++)
2364  {
2365  if (isnull[i] &&
2367  {
2368  range_partkey_has_null = true;
2369  break;
2370  }
2371  else if (isnull[i])
2372  {
2373  *failed_at = parent;
2374  *failed_slot = slot;
2375  result = -1;
2376  goto error_exit;
2377  }
2378  }
2379 
2380  /*
2381  * No need to search for partition, as the null key will
2382  * be routed to the default partition.
2383  */
2384  if (range_partkey_has_null)
2385  break;
2386 
2387  cur_offset = partition_bound_bsearch(key,
2388  partdesc->boundinfo,
2389  values,
2390  false,
2391  &equal);
2392 
2393  /*
2394  * The offset returned is such that the bound at
2395  * cur_offset is less than or equal to the tuple value, so
2396  * the bound at offset+1 is the upper bound.
2397  */
2398  cur_index = partdesc->boundinfo->indexes[cur_offset + 1];
2399  }
2400  break;
2401 
2402  default:
2403  elog(ERROR, "unexpected partition strategy: %d",
2404  (int) key->strategy);
2405  }
2406 
2407  /*
2408  * cur_index < 0 means we failed to find a partition of this parent.
2409  * Use the default partition, if there is one.
2410  */
2411  if (cur_index < 0)
2412  cur_index = partdesc->boundinfo->default_index;
2413 
2414  /*
2415  * If cur_index is still less than 0 at this point, there's no
2416  * partition for this tuple. Otherwise, we either found the leaf
2417  * partition, or a child partitioned table through which we have to
2418  * route the tuple.
2419  */
2420  if (cur_index < 0)
2421  {
2422  result = -1;
2423  *failed_at = parent;
2424  *failed_slot = slot;
2425  break;
2426  }
2427  else if (parent->indexes[cur_index] >= 0)
2428  {
2429  result = parent->indexes[cur_index];
2430  break;
2431  }
2432  else
2433  parent = pd[-parent->indexes[cur_index]];
2434  }
2435 
2436 error_exit:
2437  ecxt->ecxt_scantuple = ecxt_scantuple_old;
2438  return result;
2439 }
2440 
2441 /*
2442  * qsort_partition_list_value_cmp
2443  *
2444  * Compare two list partition bound datums
2445  */
2446 static int32
2447 qsort_partition_list_value_cmp(const void *a, const void *b, void *arg)
2448 {
2449  Datum val1 = (*(const PartitionListValue **) a)->value,
2450  val2 = (*(const PartitionListValue **) b)->value;
2451  PartitionKey key = (PartitionKey) arg;
2452 
2454  key->partcollation[0],
2455  val1, val2));
2456 }
2457 
2458 /*
2459  * make_one_range_bound
2460  *
2461  * Return a PartitionRangeBound given a list of PartitionRangeDatum elements
2462  * and a flag telling whether the bound is lower or not. Made into a function
2463  * because there are multiple sites that want to use this facility.
2464  */
2465 static PartitionRangeBound *
2467 {
2468  PartitionRangeBound *bound;
2469  ListCell *lc;
2470  int i;
2471 
2472  Assert(datums != NIL);
2473 
2474  bound = (PartitionRangeBound *) palloc0(sizeof(PartitionRangeBound));
2475  bound->index = index;
2476  bound->datums = (Datum *) palloc0(key->partnatts * sizeof(Datum));
2477  bound->kind = (PartitionRangeDatumKind *) palloc0(key->partnatts *
2478  sizeof(PartitionRangeDatumKind));
2479  bound->lower = lower;
2480 
2481  i = 0;
2482  foreach(lc, datums)
2483  {
2485 
2486  /* What's contained in this range datum? */
2487  bound->kind[i] = datum->kind;
2488 
2489  if (datum->kind == PARTITION_RANGE_DATUM_VALUE)
2490  {
2491  Const *val = castNode(Const, datum->value);
2492 
2493  if (val->constisnull)
2494  elog(ERROR, "invalid range bound datum");
2495  bound->datums[i] = val->constvalue;
2496  }
2497 
2498  i++;
2499  }
2500 
2501  return bound;
2502 }
2503 
2504 /* Used when sorting range bounds across all range partitions */
2505 static int32
2506 qsort_partition_rbound_cmp(const void *a, const void *b, void *arg)
2507 {
2508  PartitionRangeBound *b1 = (*(PartitionRangeBound *const *) a);
2509  PartitionRangeBound *b2 = (*(PartitionRangeBound *const *) b);
2510  PartitionKey key = (PartitionKey) arg;
2511 
2512  return partition_rbound_cmp(key, b1->datums, b1->kind, b1->lower, b2);
2513 }
2514 
2515 /*
2516  * partition_rbound_cmp
2517  *
2518  * Return for two range bounds whether the 1st one (specified in datum1,
2519  * kind1, and lower1) is <, =, or > the bound specified in *b2.
2520  *
2521  * Note that if the values of the two range bounds compare equal, then we take
2522  * into account whether they are upper or lower bounds, and an upper bound is
2523  * considered to be smaller than a lower bound. This is important to the way
2524  * that RelationBuildPartitionDesc() builds the PartitionBoundInfoData
2525  * structure, which only stores the upper bound of a common boundary between
2526  * two contiguous partitions.
2527  */
2528 static int32
2530  Datum *datums1, PartitionRangeDatumKind *kind1,
2531  bool lower1, PartitionRangeBound *b2)
2532 {
2533  int32 cmpval = 0; /* placate compiler */
2534  int i;
2535  Datum *datums2 = b2->datums;
2536  PartitionRangeDatumKind *kind2 = b2->kind;
2537  bool lower2 = b2->lower;
2538 
2539  for (i = 0; i < key->partnatts; i++)
2540  {
2541  /*
2542  * First, handle cases where the column is unbounded, which should not
2543  * invoke the comparison procedure, and should not consider any later
2544  * columns. Note that the PartitionRangeDatumKind enum elements
2545  * compare the same way as the values they represent.
2546  */
2547  if (kind1[i] < kind2[i])
2548  return -1;
2549  else if (kind1[i] > kind2[i])
2550  return 1;
2551  else if (kind1[i] != PARTITION_RANGE_DATUM_VALUE)
2552 
2553  /*
2554  * The column bounds are both MINVALUE or both MAXVALUE. No later
2555  * columns should be considered, but we still need to compare
2556  * whether they are upper or lower bounds.
2557  */
2558  break;
2559 
2560  cmpval = DatumGetInt32(FunctionCall2Coll(&key->partsupfunc[i],
2561  key->partcollation[i],
2562  datums1[i],
2563  datums2[i]));
2564  if (cmpval != 0)
2565  break;
2566  }
2567 
2568  /*
2569  * If the comparison is anything other than equal, we're done. If they
2570  * compare equal though, we still have to consider whether the boundaries
2571  * are inclusive or exclusive. Exclusive one is considered smaller of the
2572  * two.
2573  */
2574  if (cmpval == 0 && lower1 != lower2)
2575  cmpval = lower1 ? 1 : -1;
2576 
2577  return cmpval;
2578 }
2579 
2580 /*
2581  * partition_rbound_datum_cmp
2582  *
2583  * Return whether range bound (specified in rb_datums, rb_kind, and rb_lower)
2584  * is <, =, or > partition key of tuple (tuple_datums)
2585  */
2586 static int32
2588  Datum *rb_datums, PartitionRangeDatumKind *rb_kind,
2589  Datum *tuple_datums)
2590 {
2591  int i;
2592  int32 cmpval = -1;
2593 
2594  for (i = 0; i < key->partnatts; i++)
2595  {
2596  if (rb_kind[i] == PARTITION_RANGE_DATUM_MINVALUE)
2597  return -1;
2598  else if (rb_kind[i] == PARTITION_RANGE_DATUM_MAXVALUE)
2599  return 1;
2600 
2601  cmpval = DatumGetInt32(FunctionCall2Coll(&key->partsupfunc[i],
2602  key->partcollation[i],
2603  rb_datums[i],
2604  tuple_datums[i]));
2605  if (cmpval != 0)
2606  break;
2607  }
2608 
2609  return cmpval;
2610 }
2611 
2612 /*
2613  * partition_bound_cmp
2614  *
2615  * Return whether the bound at offset in boundinfo is <, =, or > the argument
2616  * specified in *probe.
2617  */
2618 static int32
2620  int offset, void *probe, bool probe_is_bound)
2621 {
2622  Datum *bound_datums = boundinfo->datums[offset];
2623  int32 cmpval = -1;
2624 
2625  switch (key->strategy)
2626  {
2628  cmpval = DatumGetInt32(FunctionCall2Coll(&key->partsupfunc[0],
2629  key->partcollation[0],
2630  bound_datums[0],
2631  *(Datum *) probe));
2632  break;
2633 
2635  {
2636  PartitionRangeDatumKind *kind = boundinfo->kind[offset];
2637 
2638  if (probe_is_bound)
2639  {
2640  /*
2641  * We need to pass whether the existing bound is a lower
2642  * bound, so that two equal-valued lower and upper bounds
2643  * are not regarded equal.
2644  */
2645  bool lower = boundinfo->indexes[offset] < 0;
2646 
2647  cmpval = partition_rbound_cmp(key,
2648  bound_datums, kind, lower,
2649  (PartitionRangeBound *) probe);
2650  }
2651  else
2652  cmpval = partition_rbound_datum_cmp(key,
2653  bound_datums, kind,
2654  (Datum *) probe);
2655  break;
2656  }
2657 
2658  default:
2659  elog(ERROR, "unexpected partition strategy: %d",
2660  (int) key->strategy);
2661  }
2662 
2663  return cmpval;
2664 }
2665 
2666 /*
2667  * Binary search on a collection of partition bounds. Returns greatest
2668  * bound in array boundinfo->datums which is less than or equal to *probe.
2669  * If all bounds in the array are greater than *probe, -1 is returned.
2670  *
2671  * *probe could either be a partition bound or a Datum array representing
2672  * the partition key of a tuple being routed; probe_is_bound tells which.
2673  * We pass that down to the comparison function so that it can interpret the
2674  * contents of *probe accordingly.
2675  *
2676  * *is_equal is set to whether the bound at the returned index is equal with
2677  * *probe.
2678  */
2679 static int
2681  void *probe, bool probe_is_bound, bool *is_equal)
2682 {
2683  int lo,
2684  hi,
2685  mid;
2686 
2687  lo = -1;
2688  hi = boundinfo->ndatums - 1;
2689  while (lo < hi)
2690  {
2691  int32 cmpval;
2692 
2693  mid = (lo + hi + 1) / 2;
2694  cmpval = partition_bound_cmp(key, boundinfo, mid, probe,
2695  probe_is_bound);
2696  if (cmpval <= 0)
2697  {
2698  lo = mid;
2699  *is_equal = (cmpval == 0);
2700 
2701  if (*is_equal)
2702  break;
2703  }
2704  else
2705  hi = mid - 1;
2706  }
2707 
2708  return lo;
2709 }
2710 
2711 /*
2712  * get_default_oid_from_partdesc
2713  *
2714  * Given a partition descriptor, return the OID of the default partition, if
2715  * one exists; else, return InvalidOid.
2716  */
2717 Oid
2719 {
2720  if (partdesc && partdesc->boundinfo &&
2722  return partdesc->oids[partdesc->boundinfo->default_index];
2723 
2724  return InvalidOid;
2725 }
2726 
2727 /*
2728  * get_default_partition_oid
2729  *
2730  * Given a relation OID, return the OID of the default partition, if one
2731  * exists. Use get_default_oid_from_partdesc where possible, for
2732  * efficiency.
2733  */
2734 Oid
2736 {
2737  HeapTuple tuple;
2738  Oid defaultPartId = InvalidOid;
2739 
2740  tuple = SearchSysCache1(PARTRELID, ObjectIdGetDatum(parentId));
2741 
2742  if (HeapTupleIsValid(tuple))
2743  {
2744  Form_pg_partitioned_table part_table_form;
2745 
2746  part_table_form = (Form_pg_partitioned_table) GETSTRUCT(tuple);
2747  defaultPartId = part_table_form->partdefid;
2748  }
2749 
2750  ReleaseSysCache(tuple);
2751  return defaultPartId;
2752 }
2753 
2754 /*
2755  * update_default_partition_oid
2756  *
2757  * Update pg_partition_table.partdefid with a new default partition OID.
2758  */
2759 void
2760 update_default_partition_oid(Oid parentId, Oid defaultPartId)
2761 {
2762  HeapTuple tuple;
2763  Relation pg_partitioned_table;
2764  Form_pg_partitioned_table part_table_form;
2765 
2766  pg_partitioned_table = heap_open(PartitionedRelationId, RowExclusiveLock);
2767 
2768  tuple = SearchSysCacheCopy1(PARTRELID, ObjectIdGetDatum(parentId));
2769 
2770  if (!HeapTupleIsValid(tuple))
2771  elog(ERROR, "cache lookup failed for partition key of relation %u",
2772  parentId);
2773 
2774  part_table_form = (Form_pg_partitioned_table) GETSTRUCT(tuple);
2775  part_table_form->partdefid = defaultPartId;
2776  CatalogTupleUpdate(pg_partitioned_table, &tuple->t_self, tuple);
2777 
2778  heap_freetuple(tuple);
2779  heap_close(pg_partitioned_table, RowExclusiveLock);
2780 }
2781 
2782 /*
2783  * get_proposed_default_constraint
2784  *
2785  * This function returns the negation of new_part_constraints, which
2786  * would be an integral part of the default partition constraints after
2787  * addition of the partition to which the new_part_constraints belongs.
2788  */
2789 List *
2791 {
2792  Expr *defPartConstraint;
2793 
2794  defPartConstraint = make_ands_explicit(new_part_constraints);
2795 
2796  /*
2797  * Derive the partition constraints of default partition by negating the
2798  * given partition constraints. The partition constraint never evaluates
2799  * to NULL, so negating it like this is safe.
2800  */
2801  defPartConstraint = makeBoolExpr(NOT_EXPR,
2802  list_make1(defPartConstraint),
2803  -1);
2804  defPartConstraint =
2805  (Expr *) eval_const_expressions(NULL,
2806  (Node *) defPartConstraint);
2807  defPartConstraint = canonicalize_qual(defPartConstraint);
2808 
2809  return list_make1(defPartConstraint);
2810 }
Datum constvalue
Definition: primnodes.h:196
#define list_make2(x1, x2)
Definition: pg_list.h:140
signed short int16
Definition: c.h:245
bool multidims
Definition: primnodes.h:956
#define NIL
Definition: pg_list.h:69
TupleTableSlot * ExecStoreTuple(HeapTuple tuple, TupleTableSlot *slot, Buffer buffer, bool shouldFree)
Definition: execTuples.c:320
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
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition: tupdesc.c:102
PartitionRangeDatumKind ** kind
Definition: partition.c:79
#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:1397
PartitionRangeDatumKind * kind
Definition: partition.c:110
PartitionDesc partdesc
Definition: partition.h:65
static Datum ExecEvalExprSwitchContext(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:301
#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
void heap_endscan(HeapScanDesc scan)
Definition: heapam.c:1565
Snapshot RegisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:863
#define DatumGetInt32(X)
Definition: postgres.h:478
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:2964
#define RelationGetDescr(relation)
Definition: rel.h:428
Oid * partopfamily
Definition: rel.h:61
Datum lower(PG_FUNCTION_ARGS)
Definition: oracle_compat.c:43
FmgrInfo * partsupfunc
Definition: rel.h:63
#define castNode(_type_, nodeptr)
Definition: nodes.h:578
PartitionRangeDatumKind
Definition: parsenodes.h:817
Oid get_array_type(Oid typid)
Definition: lsyscache.c:2512
void fix_opfuncids(Node *node)
Definition: nodeFuncs.c:1582
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1801
#define RelationGetForm(relation)
Definition: rel.h:410
static Oid get_partition_operator(PartitionKey key, int col, StrategyNumber strategy, bool *need_relabel)
Definition: partition.c:1347
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:2506
TupleConversionMap * tupmap
Definition: partition.h:67
void update_default_partition_oid(Oid parentId, Oid defaultPartId)
Definition: partition.c:2760
PartitionRangeDatumKind kind
Definition: parsenodes.h:828
#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:90
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
Node * eval_const_expressions(PlannerInfo *root, Node *node)
Definition: clauses.c:2421
Oid array_typeid
Definition: primnodes.h:952
#define INFO
Definition: elog.h:33
int get_partition_for_tuple(PartitionDispatch *pd, TupleTableSlot *slot, EState *estate, PartitionDispatchData **failed_at, TupleTableSlot **failed_slot)
Definition: partition.c:2273
List * list_concat(List *list1, List *list2)
Definition: list.c:321
return result
Definition: formatting.c:1633
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
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1373
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:296
FormData_pg_partitioned_table * Form_pg_partitioned_table
List * lappend_oid(List *list, Oid datum)
Definition: list.c:164
#define OidIsValid(objectId)
Definition: c.h:532
void check_default_allows_bound(Relation parent, Relation default_rel, PartitionBoundSpec *new_spec)
Definition: partition.c:901
ExprState * ExecPrepareExpr(Expr *node, EState *estate)
Definition: execExpr.c:437
List * get_qual_from_partbound(Relation rel, Relation parent, PartitionBoundSpec *spec)
Definition: partition.c:1078
void check_new_partition_bound(char *relname, Relation parent, PartitionBoundSpec *spec)
Definition: partition.c:711
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:161
#define SearchSysCache1(cacheId, key1)
Definition: syscache.h:159
List * map_partition_varattnos(List *expr, int target_varno, Relation partrel, Relation parent, bool *found_whole_row)
Definition: partition.c:1121
bool partition_bounds_equal(int partnatts, int16 *parttyplen, bool *parttypbyval, PartitionBoundInfo b1, PartitionBoundInfo b2)
Definition: partition.c:641
signed int int32
Definition: c.h:246
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:89
Expr * make_ands_explicit(List *andclauses)
Definition: clauses.c:367
#define list_make1(x1)
Definition: pg_list.h:139
void FreeExecutorState(EState *estate)
Definition: execUtils.c:183
#define GetPerTupleExprContext(estate)
Definition: executor.h:476
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:416
unsigned short uint16
Definition: c.h:257
void pfree(void *pointer)
Definition: mcxt.c:949
MemoryContext es_query_cxt
Definition: execnodes.h:471
Oid * parttypcoll
Definition: rel.h:74
#define linitial(l)
Definition: pg_list.h:111
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
#define partition_bound_has_default(bi)
Definition: partition.c:91
static List * get_qual_for_list(Relation parent, PartitionBoundSpec *spec)
Definition: partition.c:1468
Oid get_partition_parent(Oid relid)
Definition: partition.c:1036
Node * makeBoolConst(bool value, bool isnull)
Definition: makefuncs.c:354
Expr * arg
Definition: primnodes.h:1180
static struct @121 value
ItemPointerData t_self
Definition: htup.h:65
#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:2447
static int partition_bound_bsearch(PartitionKey key, PartitionBoundInfo boundinfo, void *probe, bool probe_is_bound, bool *is_equal)
Definition: partition.c:2680
char * c
void FormPartitionKeyDatum(PartitionDispatch pd, TupleTableSlot *slot, EState *estate, Datum *values, bool *isnull)
Definition: partition.c:2214
#define NoLock
Definition: lockdefs.h:34
List * get_proposed_default_constraint(List *new_part_constraints)
Definition: partition.c:2790
static int32 partition_rbound_cmp(PartitionKey key, Datum *datums1, PartitionRangeDatumKind *kind1, bool lower1, PartitionRangeBound *b2)
Definition: partition.c:2529
RelabelType * makeRelabelType(Expr *arg, Oid rtype, int32 rtypmod, Oid rcollid, CoercionForm rformat)
Definition: makefuncs.c:399
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:216
#define PartitionedRelationId
void check_stack_depth(void)
Definition: postgres.c:3144
#define RowExclusiveLock
Definition: lockdefs.h:38
int errdetail(const char *fmt,...)
Definition: elog.c:873
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:1654
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:436
static ListCell * list_head(const List *l)
Definition: pg_list.h:77
#define RELKIND_FOREIGN_TABLE
Definition: pg_class.h:167
List * elements
Definition: primnodes.h:955
TupleTableSlot * MakeSingleTupleTableSlot(TupleDesc tupdesc)
Definition: execTuples.c:199
#define lnext(lc)
Definition: pg_list.h:105
#define ereport(elevel, rest)
Definition: elog.h:122
Node * map_variable_attnos(Node *node, int target_varno, int sublevels_up, const AttrNumber *attno_map, int map_length, Oid to_rowtype, bool *found_whole_row)
static int32 partition_rbound_datum_cmp(PartitionKey key, Datum *rb_datums, PartitionRangeDatumKind *rb_kind, Datum *tuple_datums)
Definition: partition.c:2587
static List * get_qual_for_range(Relation parent, PartitionBoundSpec *spec, bool for_default)
Definition: partition.c:1783
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
Oid get_default_partition_oid(Oid parentId)
Definition: partition.c:2735
EState * CreateExecutorState(void)
Definition: execUtils.c:80
char * get_range_partbound_string(List *bound_datums)
Definition: ruleutils.c:10923
TupleConversionMap * convert_tuples_by_name(TupleDesc indesc, TupleDesc outdesc, const char *msg)
Definition: tupconvert.c:210
List * ExecPrepareExprList(List *nodes, EState *estate)
Definition: execExpr.c:511
void UnregisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:905
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
#define WARNING
Definition: elog.h:40
AttrNumber * convert_tuples_by_name_map(TupleDesc indesc, TupleDesc outdesc, const char *msg)
Definition: tupconvert.c:293
#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:1154
static PartitionRangeBound * make_one_range_bound(PartitionKey key, int index, List *datums, bool lower)
Definition: partition.c:2466
MemoryContext AllocSetContextCreate(MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
Definition: aset.c:322
void * palloc0(Size size)
Definition: mcxt.c:877
int location
Definition: primnodes.h:957
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
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:1325
Expr * canonicalize_qual(Expr *qual)
Definition: prepqual.c:286
#define list_make1_oid(x1)
Definition: pg_list.h:151
HeapTuple heap_getnext(HeapScanDesc scan, ScanDirection direction)
Definition: heapam.c:1808
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
NullTestType nulltesttype
Definition: primnodes.h:1181
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
#define for_both_cell(cell1, initcell1, cell2, initcell2)
Definition: pg_list.h:194
#define Anum_pg_class_relpartbound
Definition: pg_class.h:135
static void get_partition_dispatch_recurse(Relation rel, Relation parent, List **pds, List **leaf_part_oids)
Definition: partition.c:1252
#define makeNode(_type_)
Definition: nodes.h:557
bool * parttypbyval
Definition: rel.h:72
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
MemoryContext rd_pdcxt
Definition: rel.h:130
#define Assert(condition)
Definition: c.h:664
#define lfirst(lc)
Definition: pg_list.h:106
int16 * parttyplen
Definition: rel.h:71
Oid array_collid
Definition: primnodes.h:953
#define InheritsRelidSeqnoIndexId
Definition: indexing.h:167
int location
Definition: primnodes.h:1183
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:210
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:2127
#define PARTITION_STRATEGY_LIST
Definition: parsenodes.h:786
Snapshot GetLatestSnapshot(void)
Definition: snapmgr.c:379
#define RelationGetPartitionKey(relation)
Definition: rel.h:584
HeapTuple do_convert_tuple(HeapTuple tuple, TupleConversionMap *map)
Definition: tupconvert.c:354
HeapTuple ExecFetchSlotTuple(TupleTableSlot *slot)
Definition: execTuples.c:618
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:481
Oid element_typeid
Definition: primnodes.h:954
#define InheritsRelationId
Definition: pg_inherits.h:29
Expr * get_partition_qual_relid(Oid relid)
Definition: partition.c:1171
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:787
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:168
#define AccessExclusiveLock
Definition: lockdefs.h:45
List * find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents)
Definition: pg_inherits.c:167
#define Int32GetDatum(X)
Definition: postgres.h:485
void * palloc(Size size)
Definition: mcxt.c:848
struct PartitionKeyData * PartitionKey
Definition: rel.h:77
int errmsg(const char *fmt,...)
Definition: elog.c:797
Oid * partopcintype
Definition: rel.h:62
int i
Datum slot_getattr(TupleTableSlot *slot, int attnum, bool *isnull)
Definition: heaptuple.c:1142
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
void * arg
bool ExecCheck(ExprState *state, ExprContext *econtext)
Definition: execExpr.c:544
bool argisrow
Definition: primnodes.h:1182
struct PartitionRangeBound PartitionRangeBound
ExprState * ExecInitExpr(Expr *node, PlanState *parent)
Definition: execExpr.c:113
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:98
#define elog
Definition: elog.h:219
#define copyObject(obj)
Definition: nodes.h:622
static List * get_range_nulltest(PartitionKey key)
Definition: partition.c:1698
#define BTLessStrategyNumber
Definition: stratnum.h:29
#define RELKIND_RELATION
Definition: pg_class.h:160
Definition: pg_list.h:45
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1726
HeapScanDesc heap_beginscan(Relation relation, Snapshot snapshot, int nkeys, ScanKey key)
Definition: heapam.c:1397
int16 AttrNumber
Definition: attnum.h:21
#define RelationGetRelid(relation)
Definition: rel.h:416
List * rd_partcheck
Definition: rel.h:132
Oid get_default_oid_from_partdesc(PartitionDesc partdesc)
Definition: partition.c:2718
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:2619
bool constisnull
Definition: primnodes.h:197
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define BTGreaterEqualStrategyNumber
Definition: stratnum.h:32
PartitionDispatch * RelationGetPartitionDispatchInfo(Relation rel, int *num_parted, List **leaf_part_oids)
Definition: partition.c:1209
#define ResetExprContext(econtext)
Definition: executor.h:470
#define lfirst_oid(lc)
Definition: pg_list.h:108
bool PartConstraintImpliedByRelConstraint(Relation scanrel, List *partConstraint)
Definition: tablecmds.c:13537
#define RelationGetPartitionDesc(relation)
Definition: rel.h:632
MemoryContext CacheMemoryContext
Definition: mcxt.c:46
PartitionKey key
Definition: partition.h:63