PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
partition.h File Reference
#include "fmgr.h"
#include "executor/tuptable.h"
#include "nodes/execnodes.h"
#include "parser/parse_node.h"
#include "utils/rel.h"
Include dependency graph for partition.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  PartitionDescData
 
struct  PartitionDispatchData
 

Typedefs

typedef struct
PartitionBoundInfoData
PartitionBoundInfo
 
typedef struct PartitionDescData PartitionDescData
 
typedef struct PartitionDescDataPartitionDesc
 
typedef struct
PartitionDispatchData 
PartitionDispatchData
 
typedef struct
PartitionDispatchData
PartitionDispatch
 

Functions

void RelationBuildPartitionDesc (Relation relation)
 
bool partition_bounds_equal (PartitionKey key, PartitionBoundInfo p1, PartitionBoundInfo p2)
 
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)
 

Typedef Documentation

Definition at line 28 of file partition.h.

Definition at line 40 of file partition.h.

Definition at line 71 of file partition.h.

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:2137
static int partition_bound_bsearch(PartitionKey key, PartitionBoundInfo boundinfo, void *probe, bool probe_is_bound, bool *is_equal)
Definition: partition.c:2285
#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:2080
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 1858 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().

1863 {
1864  ListCell *partexpr_item;
1865  int i;
1866 
1867  if (pd->key->partexprs != NIL && pd->keystate == NIL)
1868  {
1869  /* Check caller has set up context correctly */
1870  Assert(estate != NULL &&
1871  GetPerTupleExprContext(estate)->ecxt_scantuple == slot);
1872 
1873  /* First time through, set up expression evaluation state */
1874  pd->keystate = ExecPrepareExprList(pd->key->partexprs, estate);
1875  }
1876 
1877  partexpr_item = list_head(pd->keystate);
1878  for (i = 0; i < pd->key->partnatts; i++)
1879  {
1880  AttrNumber keycol = pd->key->partattrs[i];
1881  Datum datum;
1882  bool isNull;
1883 
1884  if (keycol != 0)
1885  {
1886  /* Plain column; get the value directly from the heap tuple */
1887  datum = slot_getattr(slot, keycol, &isNull);
1888  }
1889  else
1890  {
1891  /* Expression; need to evaluate it */
1892  if (partexpr_item == NULL)
1893  elog(ERROR, "wrong number of partition key expressions");
1894  datum = ExecEvalExprSwitchContext((ExprState *) lfirst(partexpr_item),
1895  GetPerTupleExprContext(estate),
1896  &isNull);
1897  partexpr_item = lnext(partexpr_item);
1898  }
1899  values[i] = datum;
1900  isnull[i] = isNull;
1901  }
1902 
1903  if (partexpr_item != NULL)
1904  elog(ERROR, "wrong number of partition key expressions");
1905 }
#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
int get_partition_for_tuple ( PartitionDispatch pd,
TupleTableSlot slot,
EState estate,
PartitionDispatchData **  failed_at,
TupleTableSlot **  failed_slot 
)

Definition at line 1917 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().

1922 {
1923  PartitionDispatch parent;
1925  bool isnull[PARTITION_MAX_KEYS];
1926  int cur_offset,
1927  cur_index;
1928  int i,
1929  result;
1930  ExprContext *ecxt = GetPerTupleExprContext(estate);
1931  TupleTableSlot *ecxt_scantuple_old = ecxt->ecxt_scantuple;
1932 
1933  /* start with the root partitioned table */
1934  parent = pd[0];
1935  while (true)
1936  {
1937  PartitionKey key = parent->key;
1938  PartitionDesc partdesc = parent->partdesc;
1939  TupleTableSlot *myslot = parent->tupslot;
1940  TupleConversionMap *map = parent->tupmap;
1941 
1942  if (myslot != NULL && map != NULL)
1943  {
1944  HeapTuple tuple = ExecFetchSlotTuple(slot);
1945 
1946  ExecClearTuple(myslot);
1947  tuple = do_convert_tuple(tuple, map);
1948  ExecStoreTuple(tuple, myslot, InvalidBuffer, true);
1949  slot = myslot;
1950  }
1951 
1952  /* Quick exit */
1953  if (partdesc->nparts == 0)
1954  {
1955  *failed_at = parent;
1956  *failed_slot = slot;
1957  result = -1;
1958  goto error_exit;
1959  }
1960 
1961  /*
1962  * Extract partition key from tuple. Expression evaluation machinery
1963  * that FormPartitionKeyDatum() invokes expects ecxt_scantuple to
1964  * point to the correct tuple slot. The slot might have changed from
1965  * what was used for the parent table if the table of the current
1966  * partitioning level has different tuple descriptor from the parent.
1967  * So update ecxt_scantuple accordingly.
1968  */
1969  ecxt->ecxt_scantuple = slot;
1970  FormPartitionKeyDatum(parent, slot, estate, values, isnull);
1971 
1972  if (key->strategy == PARTITION_STRATEGY_RANGE)
1973  {
1974  /*
1975  * Since we cannot route tuples with NULL partition keys through a
1976  * range-partitioned table, simply return that no partition exists
1977  */
1978  for (i = 0; i < key->partnatts; i++)
1979  {
1980  if (isnull[i])
1981  {
1982  *failed_at = parent;
1983  *failed_slot = slot;
1984  result = -1;
1985  goto error_exit;
1986  }
1987  }
1988  }
1989 
1990  /*
1991  * A null partition key is only acceptable if null-accepting list
1992  * partition exists.
1993  */
1994  cur_index = -1;
1995  if (isnull[0] && partition_bound_accepts_nulls(partdesc->boundinfo))
1996  cur_index = partdesc->boundinfo->null_index;
1997  else if (!isnull[0])
1998  {
1999  /* Else bsearch in partdesc->boundinfo */
2000  bool equal = false;
2001 
2002  cur_offset = partition_bound_bsearch(key, partdesc->boundinfo,
2003  values, false, &equal);
2004  switch (key->strategy)
2005  {
2007  if (cur_offset >= 0 && equal)
2008  cur_index = partdesc->boundinfo->indexes[cur_offset];
2009  else
2010  cur_index = -1;
2011  break;
2012 
2014 
2015  /*
2016  * Offset returned is such that the bound at offset is
2017  * found to be less or equal with the tuple. So, the bound
2018  * at offset+1 would be the upper bound.
2019  */
2020  cur_index = partdesc->boundinfo->indexes[cur_offset + 1];
2021  break;
2022 
2023  default:
2024  elog(ERROR, "unexpected partition strategy: %d",
2025  (int) key->strategy);
2026  }
2027  }
2028 
2029  /*
2030  * cur_index < 0 means we failed to find a partition of this parent.
2031  * cur_index >= 0 means we either found the leaf partition, or the
2032  * next parent to find a partition of.
2033  */
2034  if (cur_index < 0)
2035  {
2036  result = -1;
2037  *failed_at = parent;
2038  *failed_slot = slot;
2039  break;
2040  }
2041  else if (parent->indexes[cur_index] >= 0)
2042  {
2043  result = parent->indexes[cur_index];
2044  break;
2045  }
2046  else
2047  parent = pd[-parent->indexes[cur_index]];
2048  }
2049 
2050 error_exit:
2051  ecxt->ecxt_scantuple = ecxt_scantuple_old;
2052  return result;
2053 }
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:2285
void FormPartitionKeyDatum(PartitionDispatch pd, TupleTableSlot *slot, EState *estate, Datum *values, bool *isnull)
Definition: partition.c:1858
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
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:1776
Definition: pg_list.h:45
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:1484
#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
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
bool partition_bounds_equal ( PartitionKey  key,
PartitionBoundInfo  p1,
PartitionBoundInfo  p2 
)

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
void RelationBuildPartitionDesc ( Relation  relation)

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
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:2121
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:2061
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:2080
MemoryContext AllocSetContextCreate(MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
Definition: aset.c:322
void * palloc0(Size size)
Definition: mcxt.c:878
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
#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:1776