PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
partition.c File Reference
#include "postgres.h"
#include "access/heapam.h"
#include "access/htup_details.h"
#include "access/nbtree.h"
#include "access/sysattr.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/objectaddress.h"
#include "catalog/partition.h"
#include "catalog/pg_collation.h"
#include "catalog/pg_inherits.h"
#include "catalog/pg_inherits_fn.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_type.h"
#include "executor/executor.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "nodes/parsenodes.h"
#include "optimizer/clauses.h"
#include "optimizer/planmain.h"
#include "optimizer/var.h"
#include "rewrite/rewriteManip.h"
#include "storage/lmgr.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/datum.h"
#include "utils/memutils.h"
#include "utils/fmgroids.h"
#include "utils/inval.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
#include "utils/ruleutils.h"
#include "utils/syscache.h"
Include dependency graph for partition.c:

Go to the source code of this file.

Data Structures

struct  PartitionBoundInfoData
 
struct  PartitionListValue
 
struct  PartitionRangeBound
 

Macros

#define partition_bound_accepts_nulls(bi)   ((bi)->null_index != -1)
 
#define APPEND_REL_PARTITION_OIDS(rel, partoids, parents)
 

Typedefs

typedef enum RangeDatumContent RangeDatumContent
 
typedef struct
PartitionBoundInfoData 
PartitionBoundInfoData
 
typedef struct PartitionListValue PartitionListValue
 
typedef struct PartitionRangeBound PartitionRangeBound
 

Enumerations

enum  RangeDatumContent { RANGE_DATUM_FINITE = 0, RANGE_DATUM_NEG_INF, RANGE_DATUM_POS_INF }
 

Functions

static int32 qsort_partition_list_value_cmp (const void *a, const void *b, void *arg)
 
static int32 qsort_partition_rbound_cmp (const void *a, const void *b, void *arg)
 
static Oid get_partition_operator (PartitionKey key, int col, StrategyNumber strategy, bool *need_relabel)
 
static Exprmake_partition_op_expr (PartitionKey key, int keynum, uint16 strategy, Expr *arg1, Expr *arg2)
 
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)
 
static Listget_qual_for_list (PartitionKey key, PartitionBoundSpec *spec)
 
static Listget_qual_for_range (PartitionKey key, PartitionBoundSpec *spec)
 
static Listgenerate_partition_qual (Relation rel)
 
static PartitionRangeBoundmake_one_range_bound (PartitionKey key, int index, List *datums, bool lower)
 
static int32 partition_rbound_cmp (PartitionKey key, Datum *datums1, RangeDatumContent *content1, bool lower1, PartitionRangeBound *b2)
 
static int32 partition_rbound_datum_cmp (PartitionKey key, Datum *rb_datums, RangeDatumContent *rb_content, Datum *tuple_datums)
 
static int32 partition_bound_cmp (PartitionKey key, PartitionBoundInfo boundinfo, int offset, void *probe, bool probe_is_bound)
 
static int partition_bound_bsearch (PartitionKey key, PartitionBoundInfo boundinfo, void *probe, bool probe_is_bound, bool *is_equal)
 
void RelationBuildPartitionDesc (Relation rel)
 
bool partition_bounds_equal (PartitionKey key, PartitionBoundInfo b1, PartitionBoundInfo b2)
 
void check_new_partition_bound (char *relname, Relation parent, PartitionBoundSpec *spec)
 
Oid get_partition_parent (Oid relid)
 
Listget_qual_from_partbound (Relation rel, Relation parent, PartitionBoundSpec *spec)
 
Listmap_partition_varattnos (List *expr, int target_varno, Relation partrel, Relation parent)
 
ListRelationGetPartitionQual (Relation rel)
 
Exprget_partition_qual_relid (Oid relid)
 
PartitionDispatchRelationGetPartitionDispatchInfo (Relation rel, int lockmode, int *num_parted, List **leaf_part_oids)
 
void FormPartitionKeyDatum (PartitionDispatch pd, TupleTableSlot *slot, EState *estate, Datum *values, bool *isnull)
 
int get_partition_for_tuple (PartitionDispatch *pd, TupleTableSlot *slot, EState *estate, PartitionDispatchData **failed_at, TupleTableSlot **failed_slot)
 

Macro Definition Documentation

#define APPEND_REL_PARTITION_OIDS (   rel,
  partoids,
  parents 
)
Value:
do\
{\
int i;\
for (i = 0; i < (rel)->rd_partdesc->nparts; i++)\
{\
(partoids) = lappend_oid((partoids), (rel)->rd_partdesc->oids[i]);\
(parents) = lappend((parents), (rel));\
}\
} while(0)
List * lappend_oid(List *list, Oid datum)
Definition: list.c:164
List * lappend(List *list, void *datum)
Definition: list.c:128
int i

Definition at line 1006 of file partition.c.

Referenced by RelationGetPartitionDispatchInfo().

#define partition_bound_accepts_nulls (   bi)    ((bi)->null_index != -1)

Definition at line 93 of file partition.c.

Referenced by check_new_partition_bound(), and get_partition_for_tuple().

Typedef Documentation

Enumeration Type Documentation

Enumerator
RANGE_DATUM_FINITE 
RANGE_DATUM_NEG_INF 
RANGE_DATUM_POS_INF 

Definition at line 70 of file partition.c.

71 {
72  RANGE_DATUM_FINITE = 0, /* actual datum stored elsewhere */
73  RANGE_DATUM_NEG_INF, /* negative infinity */
74  RANGE_DATUM_POS_INF /* positive infinity */
RangeDatumContent
Definition: partition.c:70

Function Documentation

void check_new_partition_bound ( char *  relname,
Relation  parent,
PartitionBoundSpec spec 
)

Definition at line 669 of file partition.c.

References Assert, PartitionDescData::boundinfo, castNode, Const::constisnull, Const::constvalue, PartitionRangeBound::content, PartitionRangeBound::datums, elog, equal(), ereport, errcode(), errmsg(), ERROR, get_rel_name(), PartitionBoundInfoData::indexes, lfirst, PartitionBoundSpec::listdatums, PartitionBoundSpec::location, lower(), PartitionBoundSpec::lowerdatums, make_one_range_bound(), make_parsestate(), PartitionBoundInfoData::ndatums, PartitionDescData::nparts, NULL, PartitionBoundInfoData::null_index, PartitionDescData::oids, parser_errposition(), partition_bound_accepts_nulls, partition_bound_bsearch(), partition_rbound_cmp(), PARTITION_STRATEGY_LIST, PARTITION_STRATEGY_RANGE, RelationGetPartitionDesc, RelationGetPartitionKey, PartitionKeyData::strategy, PartitionBoundInfoData::strategy, PartitionBoundSpec::strategy, upper(), PartitionBoundSpec::upperdatums, and val.

Referenced by ATExecAttachPartition(), and DefineRelation().

671 {
673  PartitionDesc partdesc = RelationGetPartitionDesc(parent);
674  ParseState *pstate = make_parsestate(NULL);
675  int with = -1;
676  bool overlap = false;
677 
678  switch (key->strategy)
679  {
681  {
683 
684  if (partdesc->nparts > 0)
685  {
686  PartitionBoundInfo boundinfo = partdesc->boundinfo;
687  ListCell *cell;
688 
689  Assert(boundinfo &&
690  boundinfo->strategy == PARTITION_STRATEGY_LIST &&
691  (boundinfo->ndatums > 0 ||
692  partition_bound_accepts_nulls(boundinfo)));
693 
694  foreach(cell, spec->listdatums)
695  {
696  Const *val = castNode(Const, lfirst(cell));
697 
698  if (!val->constisnull)
699  {
700  int offset;
701  bool equal;
702 
703  offset = partition_bound_bsearch(key, boundinfo,
704  &val->constvalue,
705  true, &equal);
706  if (offset >= 0 && equal)
707  {
708  overlap = true;
709  with = boundinfo->indexes[offset];
710  break;
711  }
712  }
713  else if (partition_bound_accepts_nulls(boundinfo))
714  {
715  overlap = true;
716  with = boundinfo->null_index;
717  break;
718  }
719  }
720  }
721 
722  break;
723  }
724 
726  {
728  *upper;
729 
731  lower = make_one_range_bound(key, -1, spec->lowerdatums, true);
732  upper = make_one_range_bound(key, -1, spec->upperdatums, false);
733 
734  /*
735  * First check if the resulting range would be empty with
736  * specified lower and upper bounds
737  */
738  if (partition_rbound_cmp(key, lower->datums, lower->content, true,
739  upper) >= 0)
740  ereport(ERROR,
741  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
742  errmsg("cannot create range partition with empty range"),
743  parser_errposition(pstate, spec->location)));
744 
745  if (partdesc->nparts > 0)
746  {
747  PartitionBoundInfo boundinfo = partdesc->boundinfo;
748  int off1,
749  off2;
750  bool equal = false;
751 
752  Assert(boundinfo && boundinfo->ndatums > 0 &&
753  boundinfo->strategy == PARTITION_STRATEGY_RANGE);
754 
755  /*
756  * Firstly, find the greatest range bound that is less
757  * than or equal to the new lower bound.
758  */
759  off1 = partition_bound_bsearch(key, boundinfo, lower, true,
760  &equal);
761 
762  /*
763  * off1 == -1 means that all existing bounds are greater
764  * than the new lower bound. In that case and the case
765  * where no partition is defined between the bounds at
766  * off1 and off1 + 1, we have a "gap" in the range that
767  * could be occupied by the new partition. We confirm if
768  * so by checking whether the new upper bound is confined
769  * within the gap.
770  */
771  if (!equal && boundinfo->indexes[off1 + 1] < 0)
772  {
773  off2 = partition_bound_bsearch(key, boundinfo, upper,
774  true, &equal);
775 
776  /*
777  * If the new upper bound is returned to be equal to
778  * the bound at off2, the latter must be the upper
779  * bound of some partition with which the new
780  * partition clearly overlaps.
781  *
782  * Also, if bound at off2 is not same as the one
783  * returned for the new lower bound (IOW, off1 !=
784  * off2), then the new partition overlaps at least one
785  * partition.
786  */
787  if (equal || off1 != off2)
788  {
789  overlap = true;
790 
791  /*
792  * The bound at off2 could be the lower bound of
793  * the partition with which the new partition
794  * overlaps. In that case, use the upper bound
795  * (that is, the bound at off2 + 1) to get the
796  * index of that partition.
797  */
798  if (boundinfo->indexes[off2] < 0)
799  with = boundinfo->indexes[off2 + 1];
800  else
801  with = boundinfo->indexes[off2];
802  }
803  }
804  else
805  {
806  /*
807  * Equal has been set to true and there is no "gap"
808  * between the bound at off1 and that at off1 + 1, so
809  * the new partition will overlap some partition. In
810  * the former case, the new lower bound is found to be
811  * equal to the bound at off1, which could only ever
812  * be true if the latter is the lower bound of some
813  * partition. It's clear in such a case that the new
814  * partition overlaps that partition, whose index we
815  * get using its upper bound (that is, using the bound
816  * at off1 + 1).
817  */
818  overlap = true;
819  with = boundinfo->indexes[off1 + 1];
820  }
821  }
822 
823  break;
824  }
825 
826  default:
827  elog(ERROR, "unexpected partition strategy: %d",
828  (int) key->strategy);
829  }
830 
831  if (overlap)
832  {
833  Assert(with >= 0);
834  ereport(ERROR,
835  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
836  errmsg("partition \"%s\" would overlap partition \"%s\"",
837  relname, get_rel_name(partdesc->oids[with])),
838  parser_errposition(pstate, spec->location)));
839  }
840 }
Datum constvalue
Definition: primnodes.h:196
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:2962
Datum lower(PG_FUNCTION_ARGS)
Definition: oracle_compat.c:43
#define castNode(_type_, nodeptr)
Definition: nodes.h:578
#define partition_bound_accepts_nulls(bi)
Definition: partition.c:93
int errcode(int sqlerrcode)
Definition: elog.c:575
Datum upper(PG_FUNCTION_ARGS)
Definition: oracle_compat.c:74
char strategy
Definition: rel.h:54
PartitionBoundInfo boundinfo
Definition: partition.h:37
ParseState * make_parsestate(ParseState *parentParseState)
Definition: parse_node.c:44
#define ERROR
Definition: elog.h:43
static int32 partition_rbound_cmp(PartitionKey key, Datum *datums1, RangeDatumContent *content1, bool lower1, PartitionRangeBound *b2)
Definition: partition.c:2156
static int partition_bound_bsearch(PartitionKey key, PartitionBoundInfo boundinfo, void *probe, bool probe_is_bound, bool *is_equal)
Definition: partition.c:2304
#define ereport(elevel, rest)
Definition: elog.h:122
static PartitionRangeBound * make_one_range_bound(PartitionKey key, int index, List *datums, bool lower)
Definition: partition.c:2099
RangeDatumContent * content
Definition: partition.c:112
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
#define lfirst(lc)
Definition: pg_list.h:106
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:111
#define PARTITION_STRATEGY_LIST
Definition: parsenodes.h:786
#define RelationGetPartitionKey(relation)
Definition: rel.h:584
#define PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:787
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define elog
Definition: elog.h:219
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1726
long val
Definition: informix.c:689
bool constisnull
Definition: primnodes.h:197
#define RelationGetPartitionDesc(relation)
Definition: rel.h:632
void FormPartitionKeyDatum ( PartitionDispatch  pd,
TupleTableSlot slot,
EState estate,
Datum values,
bool isnull 
)

Definition at line 1877 of file partition.c.

References Assert, elog, ERROR, ExecEvalExprSwitchContext(), ExecPrepareExprList(), GetPerTupleExprContext, i, PartitionDispatchData::key, PartitionDispatchData::keystate, lfirst, list_head(), lnext, NIL, NULL, PartitionKeyData::partattrs, PartitionKeyData::partexprs, PartitionKeyData::partnatts, and slot_getattr().

Referenced by ExecFindPartition(), and get_partition_for_tuple().

1882 {
1883  ListCell *partexpr_item;
1884  int i;
1885 
1886  if (pd->key->partexprs != NIL && pd->keystate == NIL)
1887  {
1888  /* Check caller has set up context correctly */
1889  Assert(estate != NULL &&
1890  GetPerTupleExprContext(estate)->ecxt_scantuple == slot);
1891 
1892  /* First time through, set up expression evaluation state */
1893  pd->keystate = ExecPrepareExprList(pd->key->partexprs, estate);
1894  }
1895 
1896  partexpr_item = list_head(pd->keystate);
1897  for (i = 0; i < pd->key->partnatts; i++)
1898  {
1899  AttrNumber keycol = pd->key->partattrs[i];
1900  Datum datum;
1901  bool isNull;
1902 
1903  if (keycol != 0)
1904  {
1905  /* Plain column; get the value directly from the heap tuple */
1906  datum = slot_getattr(slot, keycol, &isNull);
1907  }
1908  else
1909  {
1910  /* Expression; need to evaluate it */
1911  if (partexpr_item == NULL)
1912  elog(ERROR, "wrong number of partition key expressions");
1913  datum = ExecEvalExprSwitchContext((ExprState *) lfirst(partexpr_item),
1914  GetPerTupleExprContext(estate),
1915  &isNull);
1916  partexpr_item = lnext(partexpr_item);
1917  }
1918  values[i] = datum;
1919  isnull[i] = isNull;
1920  }
1921 
1922  if (partexpr_item != NULL)
1923  elog(ERROR, "wrong number of partition key expressions");
1924 }
#define NIL
Definition: pg_list.h:69
static Datum ExecEvalExprSwitchContext(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:281
List * partexprs
Definition: rel.h:58
#define GetPerTupleExprContext(estate)
Definition: executor.h:456
#define ERROR
Definition: elog.h:43
static ListCell * list_head(const List *l)
Definition: pg_list.h:77
#define lnext(lc)
Definition: pg_list.h:105
List * ExecPrepareExprList(List *nodes, EState *estate)
Definition: execExpr.c:511
AttrNumber * partattrs
Definition: rel.h:56
uintptr_t Datum
Definition: postgres.h:372
int16 partnatts
Definition: rel.h:55
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
#define lfirst(lc)
Definition: pg_list.h:106
static Datum values[MAXATTR]
Definition: bootstrap.c:163
int i
Datum slot_getattr(TupleTableSlot *slot, int attnum, bool *isnull)
Definition: heaptuple.c:1141
#define elog
Definition: elog.h:219
int16 AttrNumber
Definition: attnum.h:21
PartitionKey key
Definition: partition.h:63
static List * generate_partition_qual ( Relation  rel)
static

Definition at line 1795 of file partition.c.

References AccessShareLock, Anum_pg_class_relpartbound, CacheMemoryContext, castNode, check_stack_depth(), copyObject, elog, ERROR, get_partition_parent(), get_qual_from_partbound(), heap_close, heap_open(), HeapTupleIsValid, list_concat(), map_partition_varattnos(), MemoryContextSwitchTo(), NIL, NoLock, RelationData::rd_partcheck, RelationData::rd_rel, RelationGetRelationName, RelationGetRelid, ReleaseSysCache(), RELOID, result, SearchSysCache1, stringToNode(), SysCacheGetAttr(), and TextDatumGetCString.

Referenced by get_partition_qual_relid(), and RelationGetPartitionQual().

1796 {
1797  HeapTuple tuple;
1798  MemoryContext oldcxt;
1799  Datum boundDatum;
1800  bool isnull;
1801  PartitionBoundSpec *bound;
1802  List *my_qual = NIL,
1803  *result = NIL;
1804  Relation parent;
1805 
1806  /* Guard against stack overflow due to overly deep partition tree */
1808 
1809  /* Quick copy */
1810  if (rel->rd_partcheck != NIL)
1811  return copyObject(rel->rd_partcheck);
1812 
1813  /* Grab at least an AccessShareLock on the parent table */
1815  AccessShareLock);
1816 
1817  /* Get pg_class.relpartbound */
1818  tuple = SearchSysCache1(RELOID, RelationGetRelid(rel));
1819  if (!HeapTupleIsValid(tuple))
1820  elog(ERROR, "cache lookup failed for relation %u",
1821  RelationGetRelid(rel));
1822 
1823  boundDatum = SysCacheGetAttr(RELOID, tuple,
1825  &isnull);
1826  if (isnull) /* should not happen */
1827  elog(ERROR, "relation \"%s\" has relpartbound = null",
1829  bound = castNode(PartitionBoundSpec,
1830  stringToNode(TextDatumGetCString(boundDatum)));
1831  ReleaseSysCache(tuple);
1832 
1833  my_qual = get_qual_from_partbound(rel, parent, bound);
1834 
1835  /* Add the parent's quals to the list (if any) */
1836  if (parent->rd_rel->relispartition)
1837  result = list_concat(generate_partition_qual(parent), my_qual);
1838  else
1839  result = my_qual;
1840 
1841  /*
1842  * Change Vars to have partition's attnos instead of the parent's. We do
1843  * this after we concatenate the parent's quals, because we want every Var
1844  * in it to bear this relation's attnos. It's safe to assume varno = 1
1845  * here.
1846  */
1847  result = map_partition_varattnos(result, 1, rel, parent);
1848 
1849  /* Save a copy in the relcache */
1851  rel->rd_partcheck = copyObject(result);
1852  MemoryContextSwitchTo(oldcxt);
1853 
1854  /* Keep the parent locked until commit */
1855  heap_close(parent, NoLock);
1856 
1857  return result;
1858 }
#define NIL
Definition: pg_list.h:69
void * stringToNode(char *str)
Definition: read.c:38
#define castNode(_type_, nodeptr)
Definition: nodes.h:578
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define AccessShareLock
Definition: lockdefs.h:36
List * list_concat(List *list1, List *list2)
Definition: list.c:321
return result
Definition: formatting.c:1633
#define heap_close(r, l)
Definition: heapam.h:97
Form_pg_class rd_rel
Definition: rel.h:114
List * get_qual_from_partbound(Relation rel, Relation parent, PartitionBoundSpec *spec)
Definition: partition.c:894
#define SearchSysCache1(cacheId, key1)
Definition: syscache.h:156
#define ERROR
Definition: elog.h:43
Oid get_partition_parent(Oid relid)
Definition: partition.c:852
#define NoLock
Definition: lockdefs.h:34
void check_stack_depth(void)
Definition: postgres.c:3117
#define RelationGetRelationName(relation)
Definition: rel.h:436
#define TextDatumGetCString(d)
Definition: builtins.h:92
uintptr_t Datum
Definition: postgres.h:372
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1117
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1279
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1284
#define Anum_pg_class_relpartbound
Definition: pg_class.h:135
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
static List * generate_partition_qual(Relation rel)
Definition: partition.c:1795
#define elog
Definition: elog.h:219
#define copyObject(obj)
Definition: nodes.h:622
Definition: pg_list.h:45
#define RelationGetRelid(relation)
Definition: rel.h:416
List * rd_partcheck
Definition: rel.h:132
List * map_partition_varattnos(List *expr, int target_varno, Relation partrel, Relation parent)
Definition: partition.c:934
MemoryContext CacheMemoryContext
Definition: mcxt.c:46
int get_partition_for_tuple ( PartitionDispatch pd,
TupleTableSlot slot,
EState estate,
PartitionDispatchData **  failed_at,
TupleTableSlot **  failed_slot 
)

Definition at line 1936 of file partition.c.

References PartitionDescData::boundinfo, do_convert_tuple(), ExprContext::ecxt_scantuple, elog, equal(), ERROR, ExecClearTuple(), ExecFetchSlotTuple(), ExecStoreTuple(), FormPartitionKeyDatum(), GetPerTupleExprContext, i, PartitionDispatchData::indexes, PartitionBoundInfoData::indexes, InvalidBuffer, PartitionDispatchData::key, PartitionDescData::nparts, NULL, PartitionBoundInfoData::null_index, PartitionDispatchData::partdesc, partition_bound_accepts_nulls, partition_bound_bsearch(), PARTITION_MAX_KEYS, PARTITION_STRATEGY_LIST, PARTITION_STRATEGY_RANGE, PartitionKeyData::partnatts, result, PartitionKeyData::strategy, PartitionDispatchData::tupmap, PartitionDispatchData::tupslot, and values.

Referenced by ExecFindPartition().

1941 {
1942  PartitionDispatch parent;
1944  bool isnull[PARTITION_MAX_KEYS];
1945  int cur_offset,
1946  cur_index;
1947  int i,
1948  result;
1949  ExprContext *ecxt = GetPerTupleExprContext(estate);
1950  TupleTableSlot *ecxt_scantuple_old = ecxt->ecxt_scantuple;
1951 
1952  /* start with the root partitioned table */
1953  parent = pd[0];
1954  while (true)
1955  {
1956  PartitionKey key = parent->key;
1957  PartitionDesc partdesc = parent->partdesc;
1958  TupleTableSlot *myslot = parent->tupslot;
1959  TupleConversionMap *map = parent->tupmap;
1960 
1961  if (myslot != NULL && map != NULL)
1962  {
1963  HeapTuple tuple = ExecFetchSlotTuple(slot);
1964 
1965  ExecClearTuple(myslot);
1966  tuple = do_convert_tuple(tuple, map);
1967  ExecStoreTuple(tuple, myslot, InvalidBuffer, true);
1968  slot = myslot;
1969  }
1970 
1971  /* Quick exit */
1972  if (partdesc->nparts == 0)
1973  {
1974  *failed_at = parent;
1975  *failed_slot = slot;
1976  result = -1;
1977  goto error_exit;
1978  }
1979 
1980  /*
1981  * Extract partition key from tuple. Expression evaluation machinery
1982  * that FormPartitionKeyDatum() invokes expects ecxt_scantuple to
1983  * point to the correct tuple slot. The slot might have changed from
1984  * what was used for the parent table if the table of the current
1985  * partitioning level has different tuple descriptor from the parent.
1986  * So update ecxt_scantuple accordingly.
1987  */
1988  ecxt->ecxt_scantuple = slot;
1989  FormPartitionKeyDatum(parent, slot, estate, values, isnull);
1990 
1991  if (key->strategy == PARTITION_STRATEGY_RANGE)
1992  {
1993  /*
1994  * Since we cannot route tuples with NULL partition keys through a
1995  * range-partitioned table, simply return that no partition exists
1996  */
1997  for (i = 0; i < key->partnatts; i++)
1998  {
1999  if (isnull[i])
2000  {
2001  *failed_at = parent;
2002  *failed_slot = slot;
2003  result = -1;
2004  goto error_exit;
2005  }
2006  }
2007  }
2008 
2009  /*
2010  * A null partition key is only acceptable if null-accepting list
2011  * partition exists.
2012  */
2013  cur_index = -1;
2014  if (isnull[0] && partition_bound_accepts_nulls(partdesc->boundinfo))
2015  cur_index = partdesc->boundinfo->null_index;
2016  else if (!isnull[0])
2017  {
2018  /* Else bsearch in partdesc->boundinfo */
2019  bool equal = false;
2020 
2021  cur_offset = partition_bound_bsearch(key, partdesc->boundinfo,
2022  values, false, &equal);
2023  switch (key->strategy)
2024  {
2026  if (cur_offset >= 0 && equal)
2027  cur_index = partdesc->boundinfo->indexes[cur_offset];
2028  else
2029  cur_index = -1;
2030  break;
2031 
2033 
2034  /*
2035  * Offset returned is such that the bound at offset is
2036  * found to be less or equal with the tuple. So, the bound
2037  * at offset+1 would be the upper bound.
2038  */
2039  cur_index = partdesc->boundinfo->indexes[cur_offset + 1];
2040  break;
2041 
2042  default:
2043  elog(ERROR, "unexpected partition strategy: %d",
2044  (int) key->strategy);
2045  }
2046  }
2047 
2048  /*
2049  * cur_index < 0 means we failed to find a partition of this parent.
2050  * cur_index >= 0 means we either found the leaf partition, or the
2051  * next parent to find a partition of.
2052  */
2053  if (cur_index < 0)
2054  {
2055  result = -1;
2056  *failed_at = parent;
2057  *failed_slot = slot;
2058  break;
2059  }
2060  else if (parent->indexes[cur_index] >= 0)
2061  {
2062  result = parent->indexes[cur_index];
2063  break;
2064  }
2065  else
2066  parent = pd[-parent->indexes[cur_index]];
2067  }
2068 
2069 error_exit:
2070  ecxt->ecxt_scantuple = ecxt_scantuple_old;
2071  return result;
2072 }
TupleTableSlot * ExecStoreTuple(HeapTuple tuple, TupleTableSlot *slot, Buffer buffer, bool shouldFree)
Definition: execTuples.c:320
PartitionDesc partdesc
Definition: partition.h:65
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:2962
TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: execTuples.c:439
TupleConversionMap * tupmap
Definition: partition.h:67
#define InvalidBuffer
Definition: buf.h:25
#define partition_bound_accepts_nulls(bi)
Definition: partition.c:93
#define PARTITION_MAX_KEYS
return result
Definition: formatting.c:1633
char strategy
Definition: rel.h:54
PartitionBoundInfo boundinfo
Definition: partition.h:37
#define GetPerTupleExprContext(estate)
Definition: executor.h:456
#define ERROR
Definition: elog.h:43
static int partition_bound_bsearch(PartitionKey key, PartitionBoundInfo boundinfo, void *probe, bool probe_is_bound, bool *is_equal)
Definition: partition.c:2304
void FormPartitionKeyDatum(PartitionDispatch pd, TupleTableSlot *slot, EState *estate, Datum *values, bool *isnull)
Definition: partition.c:1877
uintptr_t Datum
Definition: postgres.h:372
int16 partnatts
Definition: rel.h:55
TupleTableSlot * tupslot
Definition: partition.h:66
#define NULL
Definition: c.h:229
TupleTableSlot * ecxt_scantuple
Definition: execnodes.h:197
#define PARTITION_STRATEGY_LIST
Definition: parsenodes.h:786
HeapTuple do_convert_tuple(HeapTuple tuple, TupleConversionMap *map)
Definition: tupconvert.c:343
HeapTuple ExecFetchSlotTuple(TupleTableSlot *slot)
Definition: execTuples.c:618
static Datum values[MAXATTR]
Definition: bootstrap.c:163
#define PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:787
int i
#define elog
Definition: elog.h:219
PartitionKey key
Definition: partition.h:63
static Oid get_partition_operator ( PartitionKey  key,
int  col,
StrategyNumber  strategy,
bool need_relabel 
)
static

Definition at line 1186 of file partition.c.

References elog, ERROR, get_opfamily_member(), OidIsValid, PartitionKeyData::partopcintype, PartitionKeyData::partopfamily, and PartitionKeyData::parttypid.

Referenced by make_partition_op_expr().

1188 {
1189  Oid operoid;
1190 
1191  /*
1192  * First check if there exists an operator of the given strategy, with
1193  * this column's type as both its lefttype and righttype, in the
1194  * partitioning operator family specified for the column.
1195  */
1196  operoid = get_opfamily_member(key->partopfamily[col],
1197  key->parttypid[col],
1198  key->parttypid[col],
1199  strategy);
1200 
1201  /*
1202  * If one doesn't exist, we must resort to using an operator in the same
1203  * operator family but with the operator class declared input type. It is
1204  * OK to do so, because the column's type is known to be binary-coercible
1205  * with the operator class input type (otherwise, the operator class in
1206  * question would not have been accepted as the partitioning operator
1207  * class). We must however inform the caller to wrap the non-Const
1208  * expression with a RelabelType node to denote the implicit coercion. It
1209  * ensures that the resulting expression structurally matches similarly
1210  * processed expressions within the optimizer.
1211  */
1212  if (!OidIsValid(operoid))
1213  {
1214  operoid = get_opfamily_member(key->partopfamily[col],
1215  key->partopcintype[col],
1216  key->partopcintype[col],
1217  strategy);
1218  *need_relabel = true;
1219  }
1220  else
1221  *need_relabel = false;
1222 
1223  if (!OidIsValid(operoid))
1224  elog(ERROR, "could not find operator for partitioning");
1225 
1226  return operoid;
1227 }
Oid * partopfamily
Definition: rel.h:61
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:538
#define ERROR
Definition: elog.h:43
Oid get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype, int16 strategy)
Definition: lsyscache.c:163
Oid * parttypid
Definition: rel.h:69
Oid * partopcintype
Definition: rel.h:62
#define elog
Definition: elog.h:219
Oid get_partition_parent ( Oid  relid)

Definition at line 852 of file partition.c.

References AccessShareLock, Anum_pg_inherits_inhrelid, Anum_pg_inherits_inhseqno, BTEqualStrategyNumber, elog, ERROR, GETSTRUCT, heap_close, heap_open(), HeapTupleIsValid, InheritsRelationId, InheritsRelidSeqnoIndexId, Int32GetDatum, NULL, ObjectIdGetDatum, result, ScanKeyInit(), systable_beginscan(), systable_endscan(), and systable_getnext().

Referenced by ATExecDropNotNull(), generate_partition_qual(), heap_drop_with_catalog(), and RangeVarCallbackForDropRelation().

853 {
854  Form_pg_inherits form;
855  Relation catalogRelation;
856  SysScanDesc scan;
857  ScanKeyData key[2];
858  HeapTuple tuple;
859  Oid result;
860 
861  catalogRelation = heap_open(InheritsRelationId, AccessShareLock);
862 
863  ScanKeyInit(&key[0],
865  BTEqualStrategyNumber, F_OIDEQ,
866  ObjectIdGetDatum(relid));
867  ScanKeyInit(&key[1],
869  BTEqualStrategyNumber, F_INT4EQ,
870  Int32GetDatum(1));
871 
872  scan = systable_beginscan(catalogRelation, InheritsRelidSeqnoIndexId, true,
873  NULL, 2, key);
874 
875  tuple = systable_getnext(scan);
876  if (!HeapTupleIsValid(tuple))
877  elog(ERROR, "could not find tuple for parent of relation %u", relid);
878 
879  form = (Form_pg_inherits) GETSTRUCT(tuple);
880  result = form->inhparent;
881 
882  systable_endscan(scan);
883  heap_close(catalogRelation, AccessShareLock);
884 
885  return result;
886 }
#define Anum_pg_inherits_inhrelid
Definition: pg_inherits.h:50
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:499
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
#define AccessShareLock
Definition: lockdefs.h:36
return result
Definition: formatting.c:1633
#define heap_close(r, l)
Definition: heapam.h:97
unsigned int Oid
Definition: postgres_ext.h:31
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:328
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:416
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
#define Anum_pg_inherits_inhseqno
Definition: pg_inherits.h:52
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1284
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:229
#define InheritsRelidSeqnoIndexId
Definition: indexing.h:167
FormData_pg_inherits * Form_pg_inherits
Definition: pg_inherits.h:43
#define InheritsRelationId
Definition: pg_inherits.h:29
#define Int32GetDatum(X)
Definition: postgres.h:485
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define elog
Definition: elog.h:219
#define BTEqualStrategyNumber
Definition: stratnum.h:31
Expr* get_partition_qual_relid ( Oid  relid)

Definition at line 980 of file partition.c.

References AccessShareLock, AND_EXPR, generate_partition_qual(), heap_close, heap_open(), linitial, list_length(), makeBoolExpr(), NoLock, NULL, RelationData::rd_rel, and result.

Referenced by pg_get_partition_constraintdef().

981 {
982  Relation rel = heap_open(relid, AccessShareLock);
983  Expr *result = NULL;
984  List *and_args;
985 
986  /* Do the work only if this relation is a partition. */
987  if (rel->rd_rel->relispartition)
988  {
989  and_args = generate_partition_qual(rel);
990  if (list_length(and_args) > 1)
991  result = makeBoolExpr(AND_EXPR, and_args, -1);
992  else
993  result = linitial(and_args);
994  }
995 
996  /* Keep the lock. */
997  heap_close(rel, NoLock);
998 
999  return result;
1000 }
#define AccessShareLock
Definition: lockdefs.h:36
return result
Definition: formatting.c:1633
#define heap_close(r, l)
Definition: heapam.h:97
Form_pg_class rd_rel
Definition: rel.h:114
Expr * makeBoolExpr(BoolExprType boolop, List *args, int location)
Definition: makefuncs.c:366
#define linitial(l)
Definition: pg_list.h:111
#define NoLock
Definition: lockdefs.h:34
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1284
#define NULL
Definition: c.h:229
static int list_length(const List *l)
Definition: pg_list.h:89
static List * generate_partition_qual(Relation rel)
Definition: partition.c:1795
Definition: pg_list.h:45
static List * get_qual_for_list ( PartitionKey  key,
PartitionBoundSpec spec 
)
static

Definition at line 1303 of file partition.c.

References NullTest::arg, NullTest::argisrow, ArrayExpr::array_collid, ArrayExpr::array_typeid, Assert, BTEqualStrategyNumber, castNode, Const::constisnull, copyObject, ArrayExpr::element_typeid, ArrayExpr::elements, get_array_type(), IS_NOT_NULL, IS_NULL, lappend(), lfirst, linitial, list_make1, list_make2, PartitionBoundSpec::listdatums, ArrayExpr::location, NullTest::location, make_partition_op_expr(), makeBoolExpr(), makeNode, makeVar(), ArrayExpr::multidims, NIL, NULL, NullTest::nulltesttype, OR_EXPR, PartitionKeyData::partattrs, PartitionKeyData::partexprs, PartitionKeyData::partnatts, PartitionKeyData::parttypcoll, PartitionKeyData::parttypid, PartitionKeyData::parttypmod, result, type_is_array, and val.

Referenced by get_qual_from_partbound().

1304 {
1305  List *result;
1306  Expr *keyCol;
1307  ArrayExpr *arr;
1308  Expr *opexpr;
1309  NullTest *nulltest;
1310  ListCell *cell;
1311  List *arrelems = NIL;
1312  bool list_has_null = false;
1313 
1314  /*
1315  * Only single-column list partitioning is supported, so we are worried
1316  * only about the partition key with index 0.
1317  */
1318  Assert(key->partnatts == 1);
1319 
1320  /* Construct Var or expression representing the partition column */
1321  if (key->partattrs[0] != 0)
1322  keyCol = (Expr *) makeVar(1,
1323  key->partattrs[0],
1324  key->parttypid[0],
1325  key->parttypmod[0],
1326  key->parttypcoll[0],
1327  0);
1328  else
1329  keyCol = (Expr *) copyObject(linitial(key->partexprs));
1330 
1331  /* Create list of Consts for the allowed values, excluding any nulls */
1332  foreach(cell, spec->listdatums)
1333  {
1334  Const *val = castNode(Const, lfirst(cell));
1335 
1336  if (val->constisnull)
1337  list_has_null = true;
1338  else
1339  arrelems = lappend(arrelems, copyObject(val));
1340  }
1341 
1342  if (arrelems)
1343  {
1344  /* Construct an ArrayExpr for the non-null partition values */
1345  arr = makeNode(ArrayExpr);
1346  arr->array_typeid = !type_is_array(key->parttypid[0])
1347  ? get_array_type(key->parttypid[0])
1348  : key->parttypid[0];
1349  arr->array_collid = key->parttypcoll[0];
1350  arr->element_typeid = key->parttypid[0];
1351  arr->elements = arrelems;
1352  arr->multidims = false;
1353  arr->location = -1;
1354 
1355  /* Generate the main expression, i.e., keyCol = ANY (arr) */
1357  keyCol, (Expr *) arr);
1358  }
1359  else
1360  {
1361  /* If there are no partition values, we don't need an = ANY expr */
1362  opexpr = NULL;
1363  }
1364 
1365  if (!list_has_null)
1366  {
1367  /*
1368  * Gin up a "col IS NOT NULL" test that will be AND'd with the main
1369  * expression. This might seem redundant, but the partition routing
1370  * machinery needs it.
1371  */
1372  nulltest = makeNode(NullTest);
1373  nulltest->arg = keyCol;
1374  nulltest->nulltesttype = IS_NOT_NULL;
1375  nulltest->argisrow = false;
1376  nulltest->location = -1;
1377 
1378  result = opexpr ? list_make2(nulltest, opexpr) : list_make1(nulltest);
1379  }
1380  else
1381  {
1382  /*
1383  * Gin up a "col IS NULL" test that will be OR'd with the main
1384  * expression.
1385  */
1386  nulltest = makeNode(NullTest);
1387  nulltest->arg = keyCol;
1388  nulltest->nulltesttype = IS_NULL;
1389  nulltest->argisrow = false;
1390  nulltest->location = -1;
1391 
1392  if (opexpr)
1393  {
1394  Expr *or;
1395 
1396  or = makeBoolExpr(OR_EXPR, list_make2(nulltest, opexpr), -1);
1397  result = list_make1(or);
1398  }
1399  else
1400  result = list_make1(nulltest);
1401  }
1402 
1403  return result;
1404 }
#define list_make2(x1, x2)
Definition: pg_list.h:140
bool multidims
Definition: primnodes.h:956
#define NIL
Definition: pg_list.h:69
static Expr * make_partition_op_expr(PartitionKey key, int keynum, uint16 strategy, Expr *arg1, Expr *arg2)
Definition: partition.c:1235
#define castNode(_type_, nodeptr)
Definition: nodes.h:578
Oid get_array_type(Oid typid)
Definition: lsyscache.c:2512
Oid array_typeid
Definition: primnodes.h:952
return result
Definition: formatting.c:1633
List * partexprs
Definition: rel.h:58
Expr * makeBoolExpr(BoolExprType boolop, List *args, int location)
Definition: makefuncs.c:366
#define list_make1(x1)
Definition: pg_list.h:139
Oid * parttypcoll
Definition: rel.h:74
#define linitial(l)
Definition: pg_list.h:111
Expr * arg
Definition: primnodes.h:1180
List * elements
Definition: primnodes.h:955
Var * makeVar(Index varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:67
Oid * parttypid
Definition: rel.h:69
List * lappend(List *list, void *datum)
Definition: list.c:128
int location
Definition: primnodes.h:957
AttrNumber * partattrs
Definition: rel.h:56
int16 partnatts
Definition: rel.h:55
NullTestType nulltesttype
Definition: primnodes.h:1181
int32 * parttypmod
Definition: rel.h:70
#define makeNode(_type_)
Definition: nodes.h:557
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
#define lfirst(lc)
Definition: pg_list.h:106
Oid array_collid
Definition: primnodes.h:953
int location
Definition: primnodes.h:1183
#define type_is_array(typid)
Definition: lsyscache.h:180
Oid element_typeid
Definition: primnodes.h:954
bool argisrow
Definition: primnodes.h:1182
#define copyObject(obj)
Definition: nodes.h:622
Definition: pg_list.h:45
long val
Definition: informix.c:689
bool constisnull
Definition: primnodes.h:197
#define BTEqualStrategyNumber
Definition: stratnum.h:31
static List * get_qual_for_range ( PartitionKey  key,
PartitionBoundSpec spec 
)
static

Definition at line 1503 of file partition.c.

References AND_EXPR, NullTest::arg, NullTest::argisrow, BTEqualStrategyNumber, BTGreaterEqualStrategyNumber, BTGreaterStrategyNumber, BTLessEqualStrategyNumber, BTLessStrategyNumber, castNode, copyObject, CreateExecutorState(), DatumGetBool, elog, ERROR, EState::es_query_cxt, ExecEvalExprSwitchContext(), ExecInitExpr(), fix_opfuncids(), for_both_cell, forboth, FreeExecutorState(), get_range_key_properties(), GetPerTupleExprContext, i, PartitionRangeDatum::infinite, IS_NOT_NULL, lappend(), lfirst, linitial, list_head(), list_length(), list_make1, lnext, NullTest::location, PartitionBoundSpec::lowerdatums, make_partition_op_expr(), makeBoolConst(), makeBoolExpr(), makeNode, makeVar(), MemoryContextSwitchTo(), NIL, NULL, NullTest::nulltesttype, OR_EXPR, PartitionKeyData::partattrs, PartitionKeyData::partexprs, PartitionKeyData::partnatts, PartitionKeyData::parttypcoll, PartitionKeyData::parttypid, PartitionKeyData::parttypmod, result, and PartitionBoundSpec::upperdatums.

Referenced by get_qual_from_partbound().

1504 {
1505  List *result = NIL;
1506  ListCell *cell1,
1507  *cell2,
1508  *partexprs_item,
1509  *partexprs_item_saved;
1510  int i,
1511  j;
1512  PartitionRangeDatum *ldatum,
1513  *udatum;
1514  Expr *keyCol;
1515  Const *lower_val,
1516  *upper_val;
1517  NullTest *nulltest;
1518  List *lower_or_arms,
1519  *upper_or_arms;
1520  int num_or_arms,
1521  current_or_arm;
1522  ListCell *lower_or_start_datum,
1523  *upper_or_start_datum;
1524  bool need_next_lower_arm,
1525  need_next_upper_arm;
1526 
1527  lower_or_start_datum = list_head(spec->lowerdatums);
1528  upper_or_start_datum = list_head(spec->upperdatums);
1529  num_or_arms = key->partnatts;
1530 
1531  /*
1532  * A range-partitioned table does not currently allow partition keys to be
1533  * null, so emit an IS NOT NULL expression for each key column.
1534  */
1535  partexprs_item = list_head(key->partexprs);
1536  for (i = 0; i < key->partnatts; i++)
1537  {
1538  Expr *keyCol;
1539 
1540  if (key->partattrs[i] != 0)
1541  {
1542  keyCol = (Expr *) makeVar(1,
1543  key->partattrs[i],
1544  key->parttypid[i],
1545  key->parttypmod[i],
1546  key->parttypcoll[i],
1547  0);
1548  }
1549  else
1550  {
1551  if (partexprs_item == NULL)
1552  elog(ERROR, "wrong number of partition key expressions");
1553  keyCol = copyObject(lfirst(partexprs_item));
1554  partexprs_item = lnext(partexprs_item);
1555  }
1556 
1557  nulltest = makeNode(NullTest);
1558  nulltest->arg = keyCol;
1559  nulltest->nulltesttype = IS_NOT_NULL;
1560  nulltest->argisrow = false;
1561  nulltest->location = -1;
1562  result = lappend(result, nulltest);
1563  }
1564 
1565  /*
1566  * Iterate over the key columns and check if the corresponding lower and
1567  * upper datums are equal using the btree equality operator for the
1568  * column's type. If equal, we emit single keyCol = common_value
1569  * expression. Starting from the first column for which the corresponding
1570  * lower and upper bound datums are not equal, we generate OR expressions
1571  * as shown in the function's header comment.
1572  */
1573  i = 0;
1574  partexprs_item = list_head(key->partexprs);
1575  partexprs_item_saved = partexprs_item; /* placate compiler */
1576  forboth(cell1, spec->lowerdatums, cell2, spec->upperdatums)
1577  {
1578  EState *estate;
1579  MemoryContext oldcxt;
1580  Expr *test_expr;
1581  ExprState *test_exprstate;
1582  Datum test_result;
1583  bool isNull;
1584 
1585  ldatum = castNode(PartitionRangeDatum, lfirst(cell1));
1586  udatum = castNode(PartitionRangeDatum, lfirst(cell2));
1587 
1588  /*
1589  * Since get_range_key_properties() modifies partexprs_item, and we
1590  * might need to start over from the previous expression in the later
1591  * part of this function, save away the current value.
1592  */
1593  partexprs_item_saved = partexprs_item;
1594 
1595  get_range_key_properties(key, i, ldatum, udatum,
1596  &partexprs_item,
1597  &keyCol,
1598  &lower_val, &upper_val);
1599 
1600  /*
1601  * If either or both of lower_val and upper_val is NULL, they are
1602  * unequal, because being NULL means the column is unbounded in the
1603  * respective direction.
1604  */
1605  if (!lower_val || !upper_val)
1606  break;
1607 
1608  /* Create the test expression */
1609  estate = CreateExecutorState();
1610  oldcxt = MemoryContextSwitchTo(estate->es_query_cxt);
1611  test_expr = make_partition_op_expr(key, i, BTEqualStrategyNumber,
1612  (Expr *) lower_val,
1613  (Expr *) upper_val);
1614  fix_opfuncids((Node *) test_expr);
1615  test_exprstate = ExecInitExpr(test_expr, NULL);
1616  test_result = ExecEvalExprSwitchContext(test_exprstate,
1617  GetPerTupleExprContext(estate),
1618  &isNull);
1619  MemoryContextSwitchTo(oldcxt);
1620  FreeExecutorState(estate);
1621 
1622  /* If not equal, go generate the OR expressions */
1623  if (!DatumGetBool(test_result))
1624  break;
1625 
1626  /*
1627  * The bounds for the last key column can't be equal, because such a
1628  * range partition would never be allowed to be defined (it would have
1629  * an empty range otherwise).
1630  */
1631  if (i == key->partnatts - 1)
1632  elog(ERROR, "invalid range bound specification");
1633 
1634  /* Equal, so generate keyCol = lower_val expression */
1635  result = lappend(result,
1637  keyCol, (Expr *) lower_val));
1638 
1639  i++;
1640  }
1641 
1642  /* First pair of lower_val and upper_val that are not equal. */
1643  lower_or_start_datum = cell1;
1644  upper_or_start_datum = cell2;
1645 
1646  /* OR will have as many arms as there are key columns left. */
1647  num_or_arms = key->partnatts - i;
1648  current_or_arm = 0;
1649  lower_or_arms = upper_or_arms = NIL;
1650  need_next_lower_arm = need_next_upper_arm = true;
1651  while (current_or_arm < num_or_arms)
1652  {
1653  List *lower_or_arm_args = NIL,
1654  *upper_or_arm_args = NIL;
1655 
1656  /* Restart scan of columns from the i'th one */
1657  j = i;
1658  partexprs_item = partexprs_item_saved;
1659 
1660  for_both_cell(cell1, lower_or_start_datum, cell2, upper_or_start_datum)
1661  {
1662  PartitionRangeDatum *ldatum_next = NULL,
1663  *udatum_next = NULL;
1664 
1665  ldatum = castNode(PartitionRangeDatum, lfirst(cell1));
1666  if (lnext(cell1))
1667  ldatum_next = castNode(PartitionRangeDatum,
1668  lfirst(lnext(cell1)));
1669  udatum = castNode(PartitionRangeDatum, lfirst(cell2));
1670  if (lnext(cell2))
1671  udatum_next = castNode(PartitionRangeDatum,
1672  lfirst(lnext(cell2)));
1673  get_range_key_properties(key, j, ldatum, udatum,
1674  &partexprs_item,
1675  &keyCol,
1676  &lower_val, &upper_val);
1677 
1678  if (need_next_lower_arm && lower_val)
1679  {
1680  uint16 strategy;
1681 
1682  /*
1683  * For the non-last columns of this arm, use the EQ operator.
1684  * For the last or the last finite-valued column, use GE.
1685  */
1686  if (j - i < current_or_arm)
1687  strategy = BTEqualStrategyNumber;
1688  else if ((ldatum_next && ldatum_next->infinite) ||
1689  j == key->partnatts - 1)
1690  strategy = BTGreaterEqualStrategyNumber;
1691  else
1692  strategy = BTGreaterStrategyNumber;
1693 
1694  lower_or_arm_args = lappend(lower_or_arm_args,
1695  make_partition_op_expr(key, j,
1696  strategy,
1697  keyCol,
1698  (Expr *) lower_val));
1699  }
1700 
1701  if (need_next_upper_arm && upper_val)
1702  {
1703  uint16 strategy;
1704 
1705  /*
1706  * For the non-last columns of this arm, use the EQ operator.
1707  * For the last finite-valued column, use LE.
1708  */
1709  if (j - i < current_or_arm)
1710  strategy = BTEqualStrategyNumber;
1711  else if (udatum_next && udatum_next->infinite)
1712  strategy = BTLessEqualStrategyNumber;
1713  else
1714  strategy = BTLessStrategyNumber;
1715 
1716  upper_or_arm_args = lappend(upper_or_arm_args,
1717  make_partition_op_expr(key, j,
1718  strategy,
1719  keyCol,
1720  (Expr *) upper_val));
1721  }
1722 
1723  /*
1724  * Did we generate enough of OR's arguments? First arm considers
1725  * the first of the remaining columns, second arm considers first
1726  * two of the remaining columns, and so on.
1727  */
1728  ++j;
1729  if (j - i > current_or_arm)
1730  {
1731  /*
1732  * We need not emit the next arm if the new column that will
1733  * be considered is unbounded.
1734  */
1735  need_next_lower_arm = ldatum_next && !ldatum_next->infinite;
1736  need_next_upper_arm = udatum_next && !udatum_next->infinite;
1737  break;
1738  }
1739  }
1740 
1741  if (lower_or_arm_args != NIL)
1742  lower_or_arms = lappend(lower_or_arms,
1743  list_length(lower_or_arm_args) > 1
1744  ? makeBoolExpr(AND_EXPR, lower_or_arm_args, -1)
1745  : linitial(lower_or_arm_args));
1746 
1747  if (upper_or_arm_args != NIL)
1748  upper_or_arms = lappend(upper_or_arms,
1749  list_length(upper_or_arm_args) > 1
1750  ? makeBoolExpr(AND_EXPR, upper_or_arm_args, -1)
1751  : linitial(upper_or_arm_args));
1752 
1753  /* If no work to do in the next iteration, break away. */
1754  if (!need_next_lower_arm && !need_next_upper_arm)
1755  break;
1756 
1757  ++current_or_arm;
1758  }
1759 
1760  /*
1761  * Generate the OR expressions for each of lower and upper bounds (if
1762  * required), and append to the list of implicitly ANDed list of
1763  * expressions.
1764  */
1765  if (lower_or_arms != NIL)
1766  result = lappend(result,
1767  list_length(lower_or_arms) > 1
1768  ? makeBoolExpr(OR_EXPR, lower_or_arms, -1)
1769  : linitial(lower_or_arms));
1770  if (upper_or_arms != NIL)
1771  result = lappend(result,
1772  list_length(upper_or_arms) > 1
1773  ? makeBoolExpr(OR_EXPR, upper_or_arms, -1)
1774  : linitial(upper_or_arms));
1775 
1776  /* As noted above, caller expects the list to be non-empty. */
1777  if (result == NIL)
1778  result = list_make1(makeBoolConst(true, false));
1779 
1780  return result;
1781 }
#define NIL
Definition: pg_list.h:69
static Expr * make_partition_op_expr(PartitionKey key, int keynum, uint16 strategy, Expr *arg1, Expr *arg2)
Definition: partition.c:1235
static Datum ExecEvalExprSwitchContext(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:281
#define BTGreaterStrategyNumber
Definition: stratnum.h:33
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:180
#define castNode(_type_, nodeptr)
Definition: nodes.h:578
void fix_opfuncids(Node *node)
Definition: nodeFuncs.c:1582
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
Definition: nodes.h:509
return result
Definition: formatting.c:1633
List * partexprs
Definition: rel.h:58
Expr * makeBoolExpr(BoolExprType boolop, List *args, int location)
Definition: makefuncs.c:366
#define BTLessEqualStrategyNumber
Definition: stratnum.h:30
#define list_make1(x1)
Definition: pg_list.h:139
void FreeExecutorState(EState *estate)
Definition: execUtils.c:178
#define GetPerTupleExprContext(estate)
Definition: executor.h:456
unsigned short uint16
Definition: c.h:267
MemoryContext es_query_cxt
Definition: execnodes.h:468
Oid * parttypcoll
Definition: rel.h:74
#define linitial(l)
Definition: pg_list.h:111
#define ERROR
Definition: elog.h:43
Node * makeBoolConst(bool value, bool isnull)
Definition: makefuncs.c:354
Expr * arg
Definition: primnodes.h:1180
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:1422
#define DatumGetBool(X)
Definition: postgres.h:399
static ListCell * list_head(const List *l)
Definition: pg_list.h:77
#define lnext(lc)
Definition: pg_list.h:105
Var * makeVar(Index varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:67
Oid * parttypid
Definition: rel.h:69
EState * CreateExecutorState(void)
Definition: execUtils.c:80
List * lappend(List *list, void *datum)
Definition: list.c:128
AttrNumber * partattrs
Definition: rel.h:56
uintptr_t Datum
Definition: postgres.h:372
int16 partnatts
Definition: rel.h:55
NullTestType nulltesttype
Definition: primnodes.h:1181
int32 * parttypmod
Definition: rel.h:70
#define for_both_cell(cell1, initcell1, cell2, initcell2)
Definition: pg_list.h:194
#define makeNode(_type_)
Definition: nodes.h:557
#define NULL
Definition: c.h:229
#define lfirst(lc)
Definition: pg_list.h:106
int location
Definition: primnodes.h:1183
static int list_length(const List *l)
Definition: pg_list.h:89
int i
bool argisrow
Definition: primnodes.h:1182
ExprState * ExecInitExpr(Expr *node, PlanState *parent)
Definition: execExpr.c:113
#define elog
Definition: elog.h:219
#define copyObject(obj)
Definition: nodes.h:622
#define BTLessStrategyNumber
Definition: stratnum.h:29
Definition: pg_list.h:45
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define BTGreaterEqualStrategyNumber
Definition: stratnum.h:32
List* get_qual_from_partbound ( Relation  rel,
Relation  parent,
PartitionBoundSpec spec 
)

Definition at line 894 of file partition.c.

References Assert, elog, ERROR, get_qual_for_list(), get_qual_for_range(), NIL, NULL, PARTITION_STRATEGY_LIST, PARTITION_STRATEGY_RANGE, RelationGetPartitionKey, PartitionKeyData::strategy, and PartitionBoundSpec::strategy.

Referenced by ATExecAttachPartition(), and generate_partition_qual().

896 {
898  List *my_qual = NIL;
899 
900  Assert(key != NULL);
901 
902  switch (key->strategy)
903  {
906  my_qual = get_qual_for_list(key, spec);
907  break;
908 
911  my_qual = get_qual_for_range(key, spec);
912  break;
913 
914  default:
915  elog(ERROR, "unexpected partition strategy: %d",
916  (int) key->strategy);
917  }
918 
919  return my_qual;
920 }
#define NIL
Definition: pg_list.h:69
char strategy
Definition: rel.h:54
static List * get_qual_for_range(PartitionKey key, PartitionBoundSpec *spec)
Definition: partition.c:1503
#define ERROR
Definition: elog.h:43
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
static List * get_qual_for_list(PartitionKey key, PartitionBoundSpec *spec)
Definition: partition.c:1303
#define PARTITION_STRATEGY_LIST
Definition: parsenodes.h:786
#define RelationGetPartitionKey(relation)
Definition: rel.h:584
#define PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:787
#define elog
Definition: elog.h:219
Definition: pg_list.h:45
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 
)
static

Definition at line 1422 of file partition.c.

References castNode, copyObject, elog, ERROR, PartitionRangeDatum::infinite, lfirst, lnext, makeVar(), NULL, PartitionKeyData::partattrs, PartitionKeyData::parttypcoll, PartitionKeyData::parttypid, PartitionKeyData::parttypmod, and PartitionRangeDatum::value.

Referenced by get_qual_for_range().

1428 {
1429  /* Get partition key expression for this column */
1430  if (key->partattrs[keynum] != 0)
1431  {
1432  *keyCol = (Expr *) makeVar(1,
1433  key->partattrs[keynum],
1434  key->parttypid[keynum],
1435  key->parttypmod[keynum],
1436  key->parttypcoll[keynum],
1437  0);
1438  }
1439  else
1440  {
1441  if (*partexprs_item == NULL)
1442  elog(ERROR, "wrong number of partition key expressions");
1443  *keyCol = copyObject(lfirst(*partexprs_item));
1444  *partexprs_item = lnext(*partexprs_item);
1445  }
1446 
1447  /* Get appropriate Const nodes for the bounds */
1448  if (!ldatum->infinite)
1449  *lower_val = castNode(Const, copyObject(ldatum->value));
1450  else
1451  *lower_val = NULL;
1452 
1453  if (!udatum->infinite)
1454  *upper_val = castNode(Const, copyObject(udatum->value));
1455  else
1456  *upper_val = NULL;
1457 }
#define castNode(_type_, nodeptr)
Definition: nodes.h:578
Oid * parttypcoll
Definition: rel.h:74
#define ERROR
Definition: elog.h:43
#define lnext(lc)
Definition: pg_list.h:105
Var * makeVar(Index varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:67
Oid * parttypid
Definition: rel.h:69
AttrNumber * partattrs
Definition: rel.h:56
int32 * parttypmod
Definition: rel.h:70
#define NULL
Definition: c.h:229
#define lfirst(lc)
Definition: pg_list.h:106
#define elog
Definition: elog.h:219
#define copyObject(obj)
Definition: nodes.h:622
static PartitionRangeBound * make_one_range_bound ( PartitionKey  key,
int  index,
List datums,
bool  lower 
)
static

Definition at line 2099 of file partition.c.

References castNode, Const::constisnull, Const::constvalue, PartitionRangeBound::content, PartitionRangeBound::datums, elog, ERROR, i, PartitionRangeBound::index, PartitionRangeDatum::infinite, lfirst, lower(), PartitionRangeBound::lower, palloc0(), PartitionKeyData::partnatts, RANGE_DATUM_FINITE, RANGE_DATUM_NEG_INF, RANGE_DATUM_POS_INF, val, and PartitionRangeDatum::value.

Referenced by check_new_partition_bound(), and RelationBuildPartitionDesc().

2100 {
2101  PartitionRangeBound *bound;
2102  ListCell *lc;
2103  int i;
2104 
2105  bound = (PartitionRangeBound *) palloc0(sizeof(PartitionRangeBound));
2106  bound->index = index;
2107  bound->datums = (Datum *) palloc0(key->partnatts * sizeof(Datum));
2108  bound->content = (RangeDatumContent *) palloc0(key->partnatts *
2109  sizeof(RangeDatumContent));
2110  bound->lower = lower;
2111 
2112  i = 0;
2113  foreach(lc, datums)
2114  {
2116 
2117  /* What's contained in this range datum? */
2118  bound->content[i] = !datum->infinite
2122 
2123  if (bound->content[i] == RANGE_DATUM_FINITE)
2124  {
2125  Const *val = castNode(Const, datum->value);
2126 
2127  if (val->constisnull)
2128  elog(ERROR, "invalid range bound datum");
2129  bound->datums[i] = val->constvalue;
2130  }
2131 
2132  i++;
2133  }
2134 
2135  return bound;
2136 }
Datum constvalue
Definition: primnodes.h:196
Datum lower(PG_FUNCTION_ARGS)
Definition: oracle_compat.c:43
#define castNode(_type_, nodeptr)
Definition: nodes.h:578
Definition: type.h:89
#define ERROR
Definition: elog.h:43
RangeDatumContent
Definition: partition.c:70
void * palloc0(Size size)
Definition: mcxt.c:878
uintptr_t Datum
Definition: postgres.h:372
int16 partnatts
Definition: rel.h:55
RangeDatumContent * content
Definition: partition.c:112
#define lfirst(lc)
Definition: pg_list.h:106
int i
#define elog
Definition: elog.h:219
long val
Definition: informix.c:689
bool constisnull
Definition: primnodes.h:197
static Expr * make_partition_op_expr ( PartitionKey  key,
int  keynum,
uint16  strategy,
Expr arg1,
Expr arg2 
)
static

Definition at line 1235 of file partition.c.

References ScalarArrayOpExpr::args, BOOLOID, COERCE_EXPLICIT_CAST, elog, ERROR, get_opcode(), get_partition_operator(), ScalarArrayOpExpr::inputcollid, InvalidOid, IsA, list_make2, ScalarArrayOpExpr::location, make_opclause(), makeNode, makeRelabelType(), NULL, ScalarArrayOpExpr::opfuncid, ScalarArrayOpExpr::opno, PartitionKeyData::partcollation, PARTITION_STRATEGY_LIST, PARTITION_STRATEGY_RANGE, PartitionKeyData::partopcintype, PartitionKeyData::parttypcoll, result, PartitionKeyData::strategy, and ScalarArrayOpExpr::useOr.

Referenced by get_qual_for_list(), and get_qual_for_range().

1237 {
1238  Oid operoid;
1239  bool need_relabel = false;
1240  Expr *result = NULL;
1241 
1242  /* Get the correct btree operator for this partitioning column */
1243  operoid = get_partition_operator(key, keynum, strategy, &need_relabel);
1244 
1245  /*
1246  * Chosen operator may be such that the non-Const operand needs to be
1247  * coerced, so apply the same; see the comment in
1248  * get_partition_operator().
1249  */
1250  if (!IsA(arg1, Const) &&
1251  (need_relabel ||
1252  key->partcollation[keynum] != key->parttypcoll[keynum]))
1253  arg1 = (Expr *) makeRelabelType(arg1,
1254  key->partopcintype[keynum],
1255  -1,
1256  key->partcollation[keynum],
1258 
1259  /* Generate the actual expression */
1260  switch (key->strategy)
1261  {
1263  {
1264  ScalarArrayOpExpr *saopexpr;
1265 
1266  /* Build leftop = ANY (rightop) */
1267  saopexpr = makeNode(ScalarArrayOpExpr);
1268  saopexpr->opno = operoid;
1269  saopexpr->opfuncid = get_opcode(operoid);
1270  saopexpr->useOr = true;
1271  saopexpr->inputcollid = key->partcollation[keynum];
1272  saopexpr->args = list_make2(arg1, arg2);
1273  saopexpr->location = -1;
1274 
1275  result = (Expr *) saopexpr;
1276  break;
1277  }
1278 
1280  result = make_opclause(operoid,
1281  BOOLOID,
1282  false,
1283  arg1, arg2,
1284  InvalidOid,
1285  key->partcollation[keynum]);
1286  break;
1287 
1288  default:
1289  elog(ERROR, "invalid partitioning strategy");
1290  break;
1291  }
1292 
1293  return result;
1294 }
#define list_make2(x1, x2)
Definition: pg_list.h:140
#define IsA(nodeptr, _type_)
Definition: nodes.h:560
static Oid get_partition_operator(PartitionKey key, int col, StrategyNumber strategy, bool *need_relabel)
Definition: partition.c:1186
return result
Definition: formatting.c:1633
Expr * make_opclause(Oid opno, Oid opresulttype, bool opretset, Expr *leftop, Expr *rightop, Oid opcollid, Oid inputcollid)
Definition: clauses.c:172
char strategy
Definition: rel.h:54
unsigned int Oid
Definition: postgres_ext.h:31
Oid * parttypcoll
Definition: rel.h:74
#define ERROR
Definition: elog.h:43
RelabelType * makeRelabelType(Expr *arg, Oid rtype, int32 rtypmod, Oid rcollid, CoercionForm rformat)
Definition: makefuncs.c:399
Oid * partcollation
Definition: rel.h:66
#define InvalidOid
Definition: postgres_ext.h:36
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1094
#define makeNode(_type_)
Definition: nodes.h:557
#define NULL
Definition: c.h:229
#define BOOLOID
Definition: pg_type.h:288
#define PARTITION_STRATEGY_LIST
Definition: parsenodes.h:786
#define PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:787
Oid * partopcintype
Definition: rel.h:62
#define elog
Definition: elog.h:219
List* map_partition_varattnos ( List expr,
int  target_varno,
Relation  partrel,
Relation  parent 
)

Definition at line 934 of file partition.c.

References convert_tuples_by_name_map(), elog, ERROR, gettext_noop, map_variable_attnos(), NIL, and RelationGetDescr.

Referenced by ATExecAttachPartition(), ExecInitModifyTable(), and generate_partition_qual().

936 {
937  AttrNumber *part_attnos;
938  bool found_whole_row;
939 
940  if (expr == NIL)
941  return NIL;
942 
943  part_attnos = convert_tuples_by_name_map(RelationGetDescr(partrel),
944  RelationGetDescr(parent),
945  gettext_noop("could not convert row type"));
946  expr = (List *) map_variable_attnos((Node *) expr,
947  target_varno, 0,
948  part_attnos,
949  RelationGetDescr(parent)->natts,
950  &found_whole_row);
951  /* There can never be a whole-row reference here */
952  if (found_whole_row)
953  elog(ERROR, "unexpected whole-row reference found in partition key");
954 
955  return expr;
956 }
Node * map_variable_attnos(Node *node, int target_varno, int sublevels_up, const AttrNumber *attno_map, int map_length, bool *found_whole_row)
#define NIL
Definition: pg_list.h:69
#define RelationGetDescr(relation)
Definition: rel.h:428
#define gettext_noop(x)
Definition: c.h:139
Definition: nodes.h:509
#define ERROR
Definition: elog.h:43
AttrNumber * convert_tuples_by_name_map(TupleDesc indesc, TupleDesc outdesc, const char *msg)
Definition: tupconvert.c:283
#define elog
Definition: elog.h:219
Definition: pg_list.h:45
int16 AttrNumber
Definition: attnum.h:21
static int partition_bound_bsearch ( PartitionKey  key,
PartitionBoundInfo  boundinfo,
void *  probe,
bool  probe_is_bound,
bool is_equal 
)
static

Definition at line 2304 of file partition.c.

References PartitionBoundInfoData::ndatums, and partition_bound_cmp().

Referenced by check_new_partition_bound(), and get_partition_for_tuple().

2306 {
2307  int lo,
2308  hi,
2309  mid;
2310 
2311  lo = -1;
2312  hi = boundinfo->ndatums - 1;
2313  while (lo < hi)
2314  {
2315  int32 cmpval;
2316 
2317  mid = (lo + hi + 1) / 2;
2318  cmpval = partition_bound_cmp(key, boundinfo, mid, probe,
2319  probe_is_bound);
2320  if (cmpval <= 0)
2321  {
2322  lo = mid;
2323  *is_equal = (cmpval == 0);
2324 
2325  if (*is_equal)
2326  break;
2327  }
2328  else
2329  hi = mid - 1;
2330  }
2331 
2332  return lo;
2333 }
signed int int32
Definition: c.h:256
static int32 partition_bound_cmp(PartitionKey key, PartitionBoundInfo boundinfo, int offset, void *probe, bool probe_is_bound)
Definition: partition.c:2243
static int32 partition_bound_cmp ( PartitionKey  key,
PartitionBoundInfo  boundinfo,
int  offset,
void *  probe,
bool  probe_is_bound 
)
static

Definition at line 2243 of file partition.c.

References PartitionBoundInfoData::content, DatumGetInt32, PartitionBoundInfoData::datums, elog, ERROR, FunctionCall2Coll(), PartitionBoundInfoData::indexes, lower(), PartitionKeyData::partcollation, partition_rbound_cmp(), partition_rbound_datum_cmp(), PARTITION_STRATEGY_LIST, PARTITION_STRATEGY_RANGE, PartitionKeyData::partsupfunc, and PartitionKeyData::strategy.

Referenced by partition_bound_bsearch().

2245 {
2246  Datum *bound_datums = boundinfo->datums[offset];
2247  int32 cmpval = -1;
2248 
2249  switch (key->strategy)
2250  {
2252  cmpval = DatumGetInt32(FunctionCall2Coll(&key->partsupfunc[0],
2253  key->partcollation[0],
2254  bound_datums[0],
2255  *(Datum *) probe));
2256  break;
2257 
2259  {
2260  RangeDatumContent *content = boundinfo->content[offset];
2261 
2262  if (probe_is_bound)
2263  {
2264  /*
2265  * We need to pass whether the existing bound is a lower
2266  * bound, so that two equal-valued lower and upper bounds
2267  * are not regarded equal.
2268  */
2269  bool lower = boundinfo->indexes[offset] < 0;
2270 
2271  cmpval = partition_rbound_cmp(key,
2272  bound_datums, content, lower,
2273  (PartitionRangeBound *) probe);
2274  }
2275  else
2276  cmpval = partition_rbound_datum_cmp(key,
2277  bound_datums, content,
2278  (Datum *) probe);
2279  break;
2280  }
2281 
2282  default:
2283  elog(ERROR, "unexpected partition strategy: %d",
2284  (int) key->strategy);
2285  }
2286 
2287  return cmpval;
2288 }
static int32 partition_rbound_datum_cmp(PartitionKey key, Datum *rb_datums, RangeDatumContent *rb_content, Datum *tuple_datums)
Definition: partition.c:2213
#define DatumGetInt32(X)
Definition: postgres.h:478
Datum lower(PG_FUNCTION_ARGS)
Definition: oracle_compat.c:43
FmgrInfo * partsupfunc
Definition: rel.h:63
char strategy
Definition: rel.h:54
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1047
signed int int32
Definition: c.h:256
#define ERROR
Definition: elog.h:43
static int32 partition_rbound_cmp(PartitionKey key, Datum *datums1, RangeDatumContent *content1, bool lower1, PartitionRangeBound *b2)
Definition: partition.c:2156
RangeDatumContent
Definition: partition.c:70
Oid * partcollation
Definition: rel.h:66
uintptr_t Datum
Definition: postgres.h:372
#define PARTITION_STRATEGY_LIST
Definition: parsenodes.h:786
#define PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:787
#define elog
Definition: elog.h:219
RangeDatumContent ** content
Definition: partition.c:83
bool partition_bounds_equal ( PartitionKey  key,
PartitionBoundInfo  b1,
PartitionBoundInfo  b2 
)

Definition at line 598 of file partition.c.

References PartitionBoundInfoData::content, datumIsEqual(), PartitionBoundInfoData::datums, i, PartitionBoundInfoData::indexes, PartitionBoundInfoData::ndatums, NULL, PartitionBoundInfoData::null_index, PARTITION_STRATEGY_RANGE, PartitionKeyData::partnatts, PartitionKeyData::parttypbyval, PartitionKeyData::parttyplen, RANGE_DATUM_FINITE, PartitionKeyData::strategy, and PartitionBoundInfoData::strategy.

Referenced by equalPartitionDescs().

600 {
601  int i;
602 
603  if (b1->strategy != b2->strategy)
604  return false;
605 
606  if (b1->ndatums != b2->ndatums)
607  return false;
608 
609  if (b1->null_index != b2->null_index)
610  return false;
611 
612  for (i = 0; i < b1->ndatums; i++)
613  {
614  int j;
615 
616  for (j = 0; j < key->partnatts; j++)
617  {
618  /* For range partitions, the bounds might not be finite. */
619  if (b1->content != NULL)
620  {
621  /*
622  * A finite bound always differs from an infinite bound, and
623  * different kinds of infinities differ from each other.
624  */
625  if (b1->content[i][j] != b2->content[i][j])
626  return false;
627 
628  /* Non-finite bounds are equal without further examination. */
629  if (b1->content[i][j] != RANGE_DATUM_FINITE)
630  continue;
631  }
632 
633  /*
634  * Compare the actual values. Note that it would be both incorrect
635  * and unsafe to invoke the comparison operator derived from the
636  * partitioning specification here. It would be incorrect because
637  * we want the relcache entry to be updated for ANY change to the
638  * partition bounds, not just those that the partitioning operator
639  * thinks are significant. It would be unsafe because we might
640  * reach this code in the context of an aborted transaction, and
641  * an arbitrary partitioning operator might not be safe in that
642  * context. datumIsEqual() should be simple enough to be safe.
643  */
644  if (!datumIsEqual(b1->datums[i][j], b2->datums[i][j],
645  key->parttypbyval[j],
646  key->parttyplen[j]))
647  return false;
648  }
649 
650  if (b1->indexes[i] != b2->indexes[i])
651  return false;
652  }
653 
654  /* There are ndatums+1 indexes in case of range partitions */
655  if (key->strategy == PARTITION_STRATEGY_RANGE &&
656  b1->indexes[i] != b2->indexes[i])
657  return false;
658 
659  return true;
660 }
bool datumIsEqual(Datum value1, Datum value2, bool typByVal, int typLen)
Definition: datum.c:219
char strategy
Definition: rel.h:54
int16 partnatts
Definition: rel.h:55
bool * parttypbyval
Definition: rel.h:72
#define NULL
Definition: c.h:229
int16 * parttyplen
Definition: rel.h:71
#define PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:787
int i
RangeDatumContent ** content
Definition: partition.c:83
static int32 partition_rbound_cmp ( PartitionKey  key,
Datum datums1,
RangeDatumContent content1,
bool  lower1,
PartitionRangeBound b2 
)
static

Definition at line 2156 of file partition.c.

References PartitionRangeBound::content, DatumGetInt32, PartitionRangeBound::datums, FunctionCall2Coll(), i, PartitionRangeBound::lower, PartitionKeyData::partcollation, PartitionKeyData::partnatts, PartitionKeyData::partsupfunc, RANGE_DATUM_FINITE, and RANGE_DATUM_NEG_INF.

Referenced by check_new_partition_bound(), partition_bound_cmp(), and qsort_partition_rbound_cmp().

2159 {
2160  int32 cmpval = 0; /* placate compiler */
2161  int i;
2162  Datum *datums2 = b2->datums;
2163  RangeDatumContent *content2 = b2->content;
2164  bool lower2 = b2->lower;
2165 
2166  for (i = 0; i < key->partnatts; i++)
2167  {
2168  /*
2169  * First, handle cases involving infinity, which don't require
2170  * invoking the comparison proc.
2171  */
2172  if (content1[i] != RANGE_DATUM_FINITE &&
2173  content2[i] != RANGE_DATUM_FINITE)
2174 
2175  /*
2176  * Both are infinity, so they are equal unless one is negative
2177  * infinity and other positive (or vice versa)
2178  */
2179  return content1[i] == content2[i] ? 0
2180  : (content1[i] < content2[i] ? -1 : 1);
2181  else if (content1[i] != RANGE_DATUM_FINITE)
2182  return content1[i] == RANGE_DATUM_NEG_INF ? -1 : 1;
2183  else if (content2[i] != RANGE_DATUM_FINITE)
2184  return content2[i] == RANGE_DATUM_NEG_INF ? 1 : -1;
2185 
2186  cmpval = DatumGetInt32(FunctionCall2Coll(&key->partsupfunc[i],
2187  key->partcollation[i],
2188  datums1[i],
2189  datums2[i]));
2190  if (cmpval != 0)
2191  break;
2192  }
2193 
2194  /*
2195  * If the comparison is anything other than equal, we're done. If they
2196  * compare equal though, we still have to consider whether the boundaries
2197  * are inclusive or exclusive. Exclusive one is considered smaller of the
2198  * two.
2199  */
2200  if (cmpval == 0 && lower1 != lower2)
2201  cmpval = lower1 ? 1 : -1;
2202 
2203  return cmpval;
2204 }
#define DatumGetInt32(X)
Definition: postgres.h:478
FmgrInfo * partsupfunc
Definition: rel.h:63
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1047
signed int int32
Definition: c.h:256
RangeDatumContent
Definition: partition.c:70
Oid * partcollation
Definition: rel.h:66
uintptr_t Datum
Definition: postgres.h:372
int16 partnatts
Definition: rel.h:55
RangeDatumContent * content
Definition: partition.c:112
int i
static int32 partition_rbound_datum_cmp ( PartitionKey  key,
Datum rb_datums,
RangeDatumContent rb_content,
Datum tuple_datums 
)
static

Definition at line 2213 of file partition.c.

References DatumGetInt32, FunctionCall2Coll(), i, PartitionKeyData::partcollation, PartitionKeyData::partnatts, PartitionKeyData::partsupfunc, RANGE_DATUM_FINITE, and RANGE_DATUM_NEG_INF.

Referenced by partition_bound_cmp().

2216 {
2217  int i;
2218  int32 cmpval = -1;
2219 
2220  for (i = 0; i < key->partnatts; i++)
2221  {
2222  if (rb_content[i] != RANGE_DATUM_FINITE)
2223  return rb_content[i] == RANGE_DATUM_NEG_INF ? -1 : 1;
2224 
2225  cmpval = DatumGetInt32(FunctionCall2Coll(&key->partsupfunc[i],
2226  key->partcollation[i],
2227  rb_datums[i],
2228  tuple_datums[i]));
2229  if (cmpval != 0)
2230  break;
2231  }
2232 
2233  return cmpval;
2234 }
#define DatumGetInt32(X)
Definition: postgres.h:478
FmgrInfo * partsupfunc
Definition: rel.h:63
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1047
signed int int32
Definition: c.h:256
Oid * partcollation
Definition: rel.h:66
int16 partnatts
Definition: rel.h:55
int i
static int32 qsort_partition_list_value_cmp ( const void *  a,
const void *  b,
void *  arg 
)
static

Definition at line 2080 of file partition.c.

References DatumGetInt32, FunctionCall2Coll(), PartitionKeyData::partcollation, and PartitionKeyData::partsupfunc.

Referenced by RelationBuildPartitionDesc().

2081 {
2082  Datum val1 = (*(const PartitionListValue **) a)->value,
2083  val2 = (*(const PartitionListValue **) b)->value;
2084  PartitionKey key = (PartitionKey) arg;
2085 
2087  key->partcollation[0],
2088  val1, val2));
2089 }
#define DatumGetInt32(X)
Definition: postgres.h:478
FmgrInfo * partsupfunc
Definition: rel.h:63
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1047
Oid * partcollation
Definition: rel.h:66
uintptr_t Datum
Definition: postgres.h:372
struct PartitionKeyData * PartitionKey
Definition: rel.h:77
void * arg
static int32 qsort_partition_rbound_cmp ( const void *  a,
const void *  b,
void *  arg 
)
static

Definition at line 2140 of file partition.c.

References PartitionRangeBound::content, PartitionRangeBound::datums, PartitionRangeBound::lower, and partition_rbound_cmp().

Referenced by RelationBuildPartitionDesc().

2141 {
2142  PartitionRangeBound *b1 = (*(PartitionRangeBound *const *) a);
2143  PartitionRangeBound *b2 = (*(PartitionRangeBound *const *) b);
2144  PartitionKey key = (PartitionKey) arg;
2145 
2146  return partition_rbound_cmp(key, b1->datums, b1->content, b1->lower, b2);
2147 }
static int32 partition_rbound_cmp(PartitionKey key, Datum *datums1, RangeDatumContent *content1, bool lower1, PartitionRangeBound *b2)
Definition: partition.c:2156
RangeDatumContent * content
Definition: partition.c:112
struct PartitionKeyData * PartitionKey
Definition: rel.h:77
void * arg
void RelationBuildPartitionDesc ( Relation  rel)

Definition at line 159 of file partition.c.

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate(), Anum_pg_class_relpartbound, Assert, PartitionDescData::boundinfo, CacheMemoryContext, castNode, Const::constisnull, Const::constvalue, PartitionBoundInfoData::content, PartitionRangeBound::content, cur, datumCopy(), DatumGetInt32, PartitionBoundInfoData::datums, PartitionRangeBound::datums, elog, ERROR, find_inheritance_children(), FunctionCall2Coll(), GETSTRUCT, HeapTupleIsValid, i, PartitionListValue::index, PartitionRangeBound::index, PartitionBoundInfoData::indexes, lappend(), lappend_oid(), lfirst, lfirst_oid, list_length(), PartitionBoundSpec::listdatums, lower(), PartitionBoundSpec::lowerdatums, make_one_range_bound(), MemoryContextSwitchTo(), PartitionBoundInfoData::ndatums, NIL, NoLock, PartitionDescData::nparts, NULL, PartitionBoundInfoData::null_index, PartitionDescData::oids, palloc(), palloc0(), PartitionKeyData::partcollation, PARTITION_STRATEGY_LIST, PARTITION_STRATEGY_RANGE, PartitionKeyData::partnatts, PartitionKeyData::partsupfunc, PartitionKeyData::parttypbyval, PartitionKeyData::parttyplen, pfree(), qsort_arg(), qsort_partition_list_value_cmp(), qsort_partition_rbound_cmp(), RANGE_DATUM_FINITE, RelationData::rd_partdesc, RelationData::rd_pdcxt, RelationGetPartitionKey, RelationGetRelationName, RelationGetRelid, ReleaseSysCache(), RELOID, result, SearchSysCache1, PartitionKeyData::strategy, PartitionBoundInfoData::strategy, PartitionBoundSpec::strategy, stringToNode(), SysCacheGetAttr(), TextDatumGetCString, upper(), PartitionBoundSpec::upperdatums, val, PartitionListValue::value, and value.

Referenced by RelationBuildDesc(), and RelationCacheInitializePhase3().

160 {
161  List *inhoids,
162  *partoids;
163  Oid *oids = NULL;
164  List *boundspecs = NIL;
165  ListCell *cell;
166  int i,
167  nparts;
170  MemoryContext oldcxt;
171 
172  int ndatums = 0;
173 
174  /* List partitioning specific */
175  PartitionListValue **all_values = NULL;
176  int null_index = -1;
177 
178  /* Range partitioning specific */
179  PartitionRangeBound **rbounds = NULL;
180 
181  /*
182  * The following could happen in situations where rel has a pg_class entry
183  * but not the pg_partitioned_table entry yet.
184  */
185  if (key == NULL)
186  return;
187 
188  /* Get partition oids from pg_inherits */
190 
191  /* Collect bound spec nodes in a list */
192  i = 0;
193  partoids = NIL;
194  foreach(cell, inhoids)
195  {
196  Oid inhrelid = lfirst_oid(cell);
197  HeapTuple tuple;
198  Datum datum;
199  bool isnull;
200  Node *boundspec;
201 
202  tuple = SearchSysCache1(RELOID, inhrelid);
203  if (!HeapTupleIsValid(tuple))
204  elog(ERROR, "cache lookup failed for relation %u", inhrelid);
205 
206  /*
207  * It is possible that the pg_class tuple of a partition has not been
208  * updated yet to set its relpartbound field. The only case where
209  * this happens is when we open the parent relation to check using its
210  * partition descriptor that a new partition's bound does not overlap
211  * some existing partition.
212  */
213  if (!((Form_pg_class) GETSTRUCT(tuple))->relispartition)
214  {
215  ReleaseSysCache(tuple);
216  continue;
217  }
218 
219  datum = SysCacheGetAttr(RELOID, tuple,
221  &isnull);
222  Assert(!isnull);
223  boundspec = (Node *) stringToNode(TextDatumGetCString(datum));
224  boundspecs = lappend(boundspecs, boundspec);
225  partoids = lappend_oid(partoids, inhrelid);
226  ReleaseSysCache(tuple);
227  }
228 
229  nparts = list_length(partoids);
230 
231  if (nparts > 0)
232  {
233  oids = (Oid *) palloc(nparts * sizeof(Oid));
234  i = 0;
235  foreach(cell, partoids)
236  oids[i++] = lfirst_oid(cell);
237 
238  /* Convert from node to the internal representation */
239  if (key->strategy == PARTITION_STRATEGY_LIST)
240  {
241  List *non_null_values = NIL;
242 
243  /*
244  * Create a unified list of non-null values across all partitions.
245  */
246  i = 0;
247  null_index = -1;
248  foreach(cell, boundspecs)
249  {
251  lfirst(cell));
252  ListCell *c;
253 
254  if (spec->strategy != PARTITION_STRATEGY_LIST)
255  elog(ERROR, "invalid strategy in partition bound spec");
256 
257  foreach(c, spec->listdatums)
258  {
259  Const *val = castNode(Const, lfirst(c));
260  PartitionListValue *list_value = NULL;
261 
262  if (!val->constisnull)
263  {
264  list_value = (PartitionListValue *)
265  palloc0(sizeof(PartitionListValue));
266  list_value->index = i;
267  list_value->value = val->constvalue;
268  }
269  else
270  {
271  /*
272  * Never put a null into the values array, flag
273  * instead for the code further down below where we
274  * construct the actual relcache struct.
275  */
276  if (null_index != -1)
277  elog(ERROR, "found null more than once");
278  null_index = i;
279  }
280 
281  if (list_value)
282  non_null_values = lappend(non_null_values,
283  list_value);
284  }
285 
286  i++;
287  }
288 
289  ndatums = list_length(non_null_values);
290 
291  /*
292  * Collect all list values in one array. Alongside the value, we
293  * also save the index of partition the value comes from.
294  */
295  all_values = (PartitionListValue **) palloc(ndatums *
296  sizeof(PartitionListValue *));
297  i = 0;
298  foreach(cell, non_null_values)
299  {
300  PartitionListValue *src = lfirst(cell);
301 
302  all_values[i] = (PartitionListValue *)
303  palloc(sizeof(PartitionListValue));
304  all_values[i]->value = src->value;
305  all_values[i]->index = src->index;
306  i++;
307  }
308 
309  qsort_arg(all_values, ndatums, sizeof(PartitionListValue *),
310  qsort_partition_list_value_cmp, (void *) key);
311  }
312  else if (key->strategy == PARTITION_STRATEGY_RANGE)
313  {
314  int j,
315  k;
316  PartitionRangeBound **all_bounds,
317  *prev;
318  bool *distinct_indexes;
319 
320  all_bounds = (PartitionRangeBound **) palloc0(2 * nparts *
321  sizeof(PartitionRangeBound *));
322  distinct_indexes = (bool *) palloc(2 * nparts * sizeof(bool));
323 
324  /*
325  * Create a unified list of range bounds across all the
326  * partitions.
327  */
328  i = j = 0;
329  foreach(cell, boundspecs)
330  {
332  lfirst(cell));
334  *upper;
335 
336  if (spec->strategy != PARTITION_STRATEGY_RANGE)
337  elog(ERROR, "invalid strategy in partition bound spec");
338 
339  lower = make_one_range_bound(key, i, spec->lowerdatums,
340  true);
341  upper = make_one_range_bound(key, i, spec->upperdatums,
342  false);
343  all_bounds[j] = lower;
344  all_bounds[j + 1] = upper;
345  j += 2;
346  i++;
347  }
348  Assert(j == 2 * nparts);
349 
350  /* Sort all the bounds in ascending order */
351  qsort_arg(all_bounds, 2 * nparts,
352  sizeof(PartitionRangeBound *),
354  (void *) key);
355 
356  /*
357  * Count the number of distinct bounds to allocate an array of
358  * that size.
359  */
360  ndatums = 0;
361  prev = NULL;
362  for (i = 0; i < 2 * nparts; i++)
363  {
364  PartitionRangeBound *cur = all_bounds[i];
365  bool is_distinct = false;
366  int j;
367 
368  /* Is current bound is distinct from the previous? */
369  for (j = 0; j < key->partnatts; j++)
370  {
371  Datum cmpval;
372 
373  if (prev == NULL)
374  {
375  is_distinct = true;
376  break;
377  }
378 
379  /*
380  * If either of them has infinite element, we can't equate
381  * them. Even when both are infinite, they'd have
382  * opposite signs, because only one of cur and prev is a
383  * lower bound).
384  */
385  if (cur->content[j] != RANGE_DATUM_FINITE ||
386  prev->content[j] != RANGE_DATUM_FINITE)
387  {
388  is_distinct = true;
389  break;
390  }
391  cmpval = FunctionCall2Coll(&key->partsupfunc[j],
392  key->partcollation[j],
393  cur->datums[j],
394  prev->datums[j]);
395  if (DatumGetInt32(cmpval) != 0)
396  {
397  is_distinct = true;
398  break;
399  }
400  }
401 
402  /*
403  * Count the current bound if it is distinct from the previous
404  * one. Also, store if the index i contains a distinct bound
405  * that we'd like put in the relcache array.
406  */
407  if (is_distinct)
408  {
409  distinct_indexes[i] = true;
410  ndatums++;
411  }
412  else
413  distinct_indexes[i] = false;
414 
415  prev = cur;
416  }
417 
418  /*
419  * Finally save them in an array from where they will be copied
420  * into the relcache.
421  */
422  rbounds = (PartitionRangeBound **) palloc(ndatums *
423  sizeof(PartitionRangeBound *));
424  k = 0;
425  for (i = 0; i < 2 * nparts; i++)
426  {
427  if (distinct_indexes[i])
428  rbounds[k++] = all_bounds[i];
429  }
430  Assert(k == ndatums);
431  }
432  else
433  elog(ERROR, "unexpected partition strategy: %d",
434  (int) key->strategy);
435  }
436 
437  /* Now build the actual relcache partition descriptor */
441  oldcxt = MemoryContextSwitchTo(rel->rd_pdcxt);
442 
443  result = (PartitionDescData *) palloc0(sizeof(PartitionDescData));
444  result->nparts = nparts;
445  if (nparts > 0)
446  {
447  PartitionBoundInfo boundinfo;
448  int *mapping;
449  int next_index = 0;
450 
451  result->oids = (Oid *) palloc0(nparts * sizeof(Oid));
452 
453  boundinfo = (PartitionBoundInfoData *)
455  boundinfo->strategy = key->strategy;
456  boundinfo->ndatums = ndatums;
457  boundinfo->null_index = -1;
458  boundinfo->datums = (Datum **) palloc0(ndatums * sizeof(Datum *));
459 
460  /* Initialize mapping array with invalid values */
461  mapping = (int *) palloc(sizeof(int) * nparts);
462  for (i = 0; i < nparts; i++)
463  mapping[i] = -1;
464 
465  switch (key->strategy)
466  {
468  {
469  boundinfo->indexes = (int *) palloc(ndatums * sizeof(int));
470 
471  /*
472  * Copy values. Indexes of individual values are mapped
473  * to canonical values so that they match for any two list
474  * partitioned tables with same number of partitions and
475  * same lists per partition. One way to canonicalize is
476  * to assign the index in all_values[] of the smallest
477  * value of each partition, as the index of all of the
478  * partition's values.
479  */
480  for (i = 0; i < ndatums; i++)
481  {
482  boundinfo->datums[i] = (Datum *) palloc(sizeof(Datum));
483  boundinfo->datums[i][0] = datumCopy(all_values[i]->value,
484  key->parttypbyval[0],
485  key->parttyplen[0]);
486 
487  /* If the old index has no mapping, assign one */
488  if (mapping[all_values[i]->index] == -1)
489  mapping[all_values[i]->index] = next_index++;
490 
491  boundinfo->indexes[i] = mapping[all_values[i]->index];
492  }
493 
494  /*
495  * If null-accepting partition has no mapped index yet,
496  * assign one. This could happen if such partition
497  * accepts only null and hence not covered in the above
498  * loop which only handled non-null values.
499  */
500  if (null_index != -1)
501  {
502  Assert(null_index >= 0);
503  if (mapping[null_index] == -1)
504  mapping[null_index] = next_index++;
505  boundinfo->null_index = mapping[null_index];
506  }
507 
508  /* All partition must now have a valid mapping */
509  Assert(next_index == nparts);
510  break;
511  }
512 
514  {
515  boundinfo->content = (RangeDatumContent **) palloc(ndatums *
516  sizeof(RangeDatumContent *));
517  boundinfo->indexes = (int *) palloc((ndatums + 1) *
518  sizeof(int));
519 
520  for (i = 0; i < ndatums; i++)
521  {
522  int j;
523 
524  boundinfo->datums[i] = (Datum *) palloc(key->partnatts *
525  sizeof(Datum));
526  boundinfo->content[i] = (RangeDatumContent *)
527  palloc(key->partnatts *
528  sizeof(RangeDatumContent));
529  for (j = 0; j < key->partnatts; j++)
530  {
531  if (rbounds[i]->content[j] == RANGE_DATUM_FINITE)
532  boundinfo->datums[i][j] =
533  datumCopy(rbounds[i]->datums[j],
534  key->parttypbyval[j],
535  key->parttyplen[j]);
536  /* Remember, we are storing the tri-state value. */
537  boundinfo->content[i][j] = rbounds[i]->content[j];
538  }
539 
540  /*
541  * There is no mapping for invalid indexes.
542  *
543  * Any lower bounds in the rbounds array have invalid
544  * indexes assigned, because the values between the
545  * previous bound (if there is one) and this (lower)
546  * bound are not part of the range of any existing
547  * partition.
548  */
549  if (rbounds[i]->lower)
550  boundinfo->indexes[i] = -1;
551  else
552  {
553  int orig_index = rbounds[i]->index;
554 
555  /* If the old index has no mapping, assign one */
556  if (mapping[orig_index] == -1)
557  mapping[orig_index] = next_index++;
558 
559  boundinfo->indexes[i] = mapping[orig_index];
560  }
561  }
562  boundinfo->indexes[i] = -1;
563  break;
564  }
565 
566  default:
567  elog(ERROR, "unexpected partition strategy: %d",
568  (int) key->strategy);
569  }
570 
571  result->boundinfo = boundinfo;
572 
573  /*
574  * Now assign OIDs from the original array into mapped indexes of the
575  * result array. Order of OIDs in the former is defined by the
576  * catalog scan that retrieved them, whereas that in the latter is
577  * defined by canonicalized representation of the list values or the
578  * range bounds.
579  */
580  for (i = 0; i < nparts; i++)
581  result->oids[mapping[i]] = oids[i];
582  pfree(mapping);
583  }
584 
585  MemoryContextSwitchTo(oldcxt);
586  rel->rd_partdesc = result;
587 }
Datum constvalue
Definition: primnodes.h:196
#define NIL
Definition: pg_list.h:69
struct PartitionDescData * rd_partdesc
Definition: rel.h:131
void * stringToNode(char *str)
Definition: read.c:38
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
#define DatumGetInt32(X)
Definition: postgres.h:478
Datum lower(PG_FUNCTION_ARGS)
Definition: oracle_compat.c:43
FmgrInfo * partsupfunc
Definition: rel.h:63
#define castNode(_type_, nodeptr)
Definition: nodes.h:578
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:2140
Definition: nodes.h:509
struct cursor * cur
Definition: ecpg.c:28
return result
Definition: formatting.c:1633
Datum upper(PG_FUNCTION_ARGS)
Definition: oracle_compat.c:74
char strategy
Definition: rel.h:54
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1047
unsigned int Oid
Definition: postgres_ext.h:31
List * lappend_oid(List *list, Oid datum)
Definition: list.c:164
#define SearchSysCache1(cacheId, key1)
Definition: syscache.h:156
PartitionBoundInfo boundinfo
Definition: partition.h:37
Definition: type.h:89
void pfree(void *pointer)
Definition: mcxt.c:950
#define ERROR
Definition: elog.h:43
static struct @121 value
#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:2080
char * c
#define NoLock
Definition: lockdefs.h:34
#define RelationGetRelationName(relation)
Definition: rel.h:436
RangeDatumContent
Definition: partition.c:70
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:128
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
Oid * partcollation
Definition: rel.h:66
#define TextDatumGetCString(d)
Definition: builtins.h:92
static PartitionRangeBound * make_one_range_bound(PartitionKey key, int index, List *datums, bool lower)
Definition: partition.c:2099
MemoryContext AllocSetContextCreate(MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
Definition: aset.c:322
void * palloc0(Size size)
Definition: mcxt.c:878
uintptr_t Datum
Definition: postgres.h:372
int16 partnatts
Definition: rel.h:55
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1117
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1279
List * find_inheritance_children(Oid parentrelId, LOCKMODE lockmode)
Definition: pg_inherits.c:57
RangeDatumContent * content
Definition: partition.c:112
#define Anum_pg_class_relpartbound
Definition: pg_class.h:135
bool * parttypbyval
Definition: rel.h:72
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:229
MemoryContext rd_pdcxt
Definition: rel.h:130
#define Assert(condition)
Definition: c.h:675
#define lfirst(lc)
Definition: pg_list.h:106
int16 * parttyplen
Definition: rel.h:71
static int list_length(const List *l)
Definition: pg_list.h:89
#define PARTITION_STRATEGY_LIST
Definition: parsenodes.h:786
#define RelationGetPartitionKey(relation)
Definition: rel.h:584
FormData_pg_class * Form_pg_class
Definition: pg_class.h:95
#define PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:787
void * palloc(Size size)
Definition: mcxt.c:849
int i
#define elog
Definition: elog.h:219
Definition: pg_list.h:45
#define RelationGetRelid(relation)
Definition: rel.h:416
long val
Definition: informix.c:689
bool constisnull
Definition: primnodes.h:197
#define lfirst_oid(lc)
Definition: pg_list.h:108
MemoryContext CacheMemoryContext
Definition: mcxt.c:46
RangeDatumContent ** content
Definition: partition.c:83
PartitionDispatch* RelationGetPartitionDispatchInfo ( Relation  rel,
int  lockmode,
int *  num_parted,
List **  leaf_part_oids 
)

Definition at line 1026 of file partition.c.

References APPEND_REL_PARTITION_OIDS, convert_tuples_by_name(), forboth, get_rel_relkind(), gettext_noop, heap_close, heap_open(), i, PartitionDispatchData::indexes, PartitionDispatchData::key, PartitionDispatchData::keystate, lappend(), lappend_oid(), lfirst, lfirst_oid, list_make1, MakeSingleTupleTableSlot(), NIL, NoLock, PartitionDescData::nparts, NULL, PartitionDescData::oids, palloc(), PartitionDispatchData::partdesc, RelationGetDescr, RelationGetPartitionDesc, RelationGetPartitionKey, PartitionDispatchData::reldesc, RELKIND_PARTITIONED_TABLE, PartitionDispatchData::tupmap, and PartitionDispatchData::tupslot.

Referenced by ExecSetupPartitionTupleRouting().

1028 {
1029  PartitionDispatchData **pd;
1030  List *all_parts = NIL,
1031  *all_parents = NIL,
1032  *parted_rels,
1033  *parted_rel_parents;
1034  ListCell *lc1,
1035  *lc2;
1036  int i,
1037  k,
1038  offset;
1039 
1040  /*
1041  * Lock partitions and make a list of the partitioned ones to prepare
1042  * their PartitionDispatch objects below.
1043  *
1044  * Cannot use find_all_inheritors() here, because then the order of OIDs
1045  * in parted_rels list would be unknown, which does not help, because we
1046  * assign indexes within individual PartitionDispatch in an order that is
1047  * predetermined (determined by the order of OIDs in individual partition
1048  * descriptors).
1049  */
1050  *num_parted = 1;
1051  parted_rels = list_make1(rel);
1052  /* Root partitioned table has no parent, so NULL for parent */
1053  parted_rel_parents = list_make1(NULL);
1054  APPEND_REL_PARTITION_OIDS(rel, all_parts, all_parents);
1055  forboth(lc1, all_parts, lc2, all_parents)
1056  {
1057  Relation partrel = heap_open(lfirst_oid(lc1), lockmode);
1058  Relation parent = lfirst(lc2);
1059  PartitionDesc partdesc = RelationGetPartitionDesc(partrel);
1060 
1061  /*
1062  * If this partition is a partitioned table, add its children to the
1063  * end of the list, so that they are processed as well.
1064  */
1065  if (partdesc)
1066  {
1067  (*num_parted)++;
1068  parted_rels = lappend(parted_rels, partrel);
1069  parted_rel_parents = lappend(parted_rel_parents, parent);
1070  APPEND_REL_PARTITION_OIDS(partrel, all_parts, all_parents);
1071  }
1072  else
1073  heap_close(partrel, NoLock);
1074 
1075  /*
1076  * We keep the partitioned ones open until we're done using the
1077  * information being collected here (for example, see
1078  * ExecEndModifyTable).
1079  */
1080  }
1081 
1082  /*
1083  * We want to create two arrays - one for leaf partitions and another for
1084  * partitioned tables (including the root table and internal partitions).
1085  * While we only create the latter here, leaf partition array of suitable
1086  * objects (such as, ResultRelInfo) is created by the caller using the
1087  * list of OIDs we return. Indexes into these arrays get assigned in a
1088  * breadth-first manner, whereby partitions of any given level are placed
1089  * consecutively in the respective arrays.
1090  */
1091  pd = (PartitionDispatchData **) palloc(*num_parted *
1092  sizeof(PartitionDispatchData *));
1093  *leaf_part_oids = NIL;
1094  i = k = offset = 0;
1095  forboth(lc1, parted_rels, lc2, parted_rel_parents)
1096  {
1097  Relation partrel = lfirst(lc1);
1098  Relation parent = lfirst(lc2);
1099  PartitionKey partkey = RelationGetPartitionKey(partrel);
1100  TupleDesc tupdesc = RelationGetDescr(partrel);
1101  PartitionDesc partdesc = RelationGetPartitionDesc(partrel);
1102  int j,
1103  m;
1104 
1106  pd[i]->reldesc = partrel;
1107  pd[i]->key = partkey;
1108  pd[i]->keystate = NIL;
1109  pd[i]->partdesc = partdesc;
1110  if (parent != NULL)
1111  {
1112  /*
1113  * For every partitioned table other than root, we must store a
1114  * tuple table slot initialized with its tuple descriptor and a
1115  * tuple conversion map to convert a tuple from its parent's
1116  * rowtype to its own. That is to make sure that we are looking at
1117  * the correct row using the correct tuple descriptor when
1118  * computing its partition key for tuple routing.
1119  */
1120  pd[i]->tupslot = MakeSingleTupleTableSlot(tupdesc);
1122  tupdesc,
1123  gettext_noop("could not convert row type"));
1124  }
1125  else
1126  {
1127  /* Not required for the root partitioned table */
1128  pd[i]->tupslot = NULL;
1129  pd[i]->tupmap = NULL;
1130  }
1131  pd[i]->indexes = (int *) palloc(partdesc->nparts * sizeof(int));
1132 
1133  /*
1134  * Indexes corresponding to the internal partitions are multiplied by
1135  * -1 to distinguish them from those of leaf partitions. Encountering
1136  * an index >= 0 means we found a leaf partition, which is immediately
1137  * returned as the partition we are looking for. A negative index
1138  * means we found a partitioned table, whose PartitionDispatch object
1139  * is located at the above index multiplied back by -1. Using the
1140  * PartitionDispatch object, search is continued further down the
1141  * partition tree.
1142  */
1143  m = 0;
1144  for (j = 0; j < partdesc->nparts; j++)
1145  {
1146  Oid partrelid = partdesc->oids[j];
1147 
1148  if (get_rel_relkind(partrelid) != RELKIND_PARTITIONED_TABLE)
1149  {
1150  *leaf_part_oids = lappend_oid(*leaf_part_oids, partrelid);
1151  pd[i]->indexes[j] = k++;
1152  }
1153  else
1154  {
1155  /*
1156  * offset denotes the number of partitioned tables of upper
1157  * levels including those of the current level. Any partition
1158  * of this table must belong to the next level and hence will
1159  * be placed after the last partitioned table of this level.
1160  */
1161  pd[i]->indexes[j] = -(1 + offset + m);
1162  m++;
1163  }
1164  }
1165  i++;
1166 
1167  /*
1168  * This counts the number of partitioned tables at upper levels
1169  * including those of the current level.
1170  */
1171  offset += m;
1172  }
1173 
1174  return pd;
1175 }
#define NIL
Definition: pg_list.h:69
struct PartitionDispatchData * PartitionDispatch
Definition: partition.h:71
PartitionDesc partdesc
Definition: partition.h:65
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:180
#define RelationGetDescr(relation)
Definition: rel.h:428
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1801
TupleConversionMap * tupmap
Definition: partition.h:67
#define gettext_noop(x)
Definition: c.h:139
#define heap_close(r, l)
Definition: heapam.h:97
unsigned int Oid
Definition: postgres_ext.h:31
List * lappend_oid(List *list, Oid datum)
Definition: list.c:164
#define list_make1(x1)
Definition: pg_list.h:139
#define NoLock
Definition: lockdefs.h:34
TupleTableSlot * MakeSingleTupleTableSlot(TupleDesc tupdesc)
Definition: execTuples.c:199
TupleConversionMap * convert_tuples_by_name(TupleDesc indesc, TupleDesc outdesc, const char *msg)
Definition: tupconvert.c:205
List * lappend(List *list, void *datum)
Definition: list.c:128
#define RELKIND_PARTITIONED_TABLE
Definition: pg_class.h:168
TupleTableSlot * tupslot
Definition: partition.h:66
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1284
#define NULL
Definition: c.h:229
#define lfirst(lc)
Definition: pg_list.h:106
#define RelationGetPartitionKey(relation)
Definition: rel.h:584
void * palloc(Size size)
Definition: mcxt.c:849
#define APPEND_REL_PARTITION_OIDS(rel, partoids, parents)
Definition: partition.c:1006
int i
Definition: pg_list.h:45
#define lfirst_oid(lc)
Definition: pg_list.h:108
#define RelationGetPartitionDesc(relation)
Definition: rel.h:632
PartitionKey key
Definition: partition.h:63
List* RelationGetPartitionQual ( Relation  rel)

Definition at line 964 of file partition.c.

References generate_partition_qual(), NIL, and RelationData::rd_rel.

Referenced by ATExecAttachPartition(), get_relation_constraints(), and InitResultRelInfo().

965 {
966  /* Quick exit */
967  if (!rel->rd_rel->relispartition)
968  return NIL;
969 
970  return generate_partition_qual(rel);
971 }
#define NIL
Definition: pg_list.h:69
Form_pg_class rd_rel
Definition: rel.h:114
static List * generate_partition_qual(Relation rel)
Definition: partition.c:1795