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 (int partnatts, int16 *parttyplen, bool *parttypbyval, 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, bool *found_whole_row)
 
ListRelationGetPartitionQual (Relation rel)
 
Exprget_partition_qual_relid (Oid relid)
 
PartitionDispatchRelationGetPartitionDispatchInfo (Relation rel, 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 653 of file partition.c.

References Assert, PartitionDescData::boundinfo, castNode, Const::constisnull, Const::constvalue, PartitionRangeBound::datums, elog, equal(), ereport, errcode(), errdetail(), errmsg(), ERROR, get_range_partbound_string(), get_rel_name(), PartitionBoundInfoData::indexes, PartitionRangeBound::kind, 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_bound_cmp(), 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().

655 {
657  PartitionDesc partdesc = RelationGetPartitionDesc(parent);
658  ParseState *pstate = make_parsestate(NULL);
659  int with = -1;
660  bool overlap = false;
661 
662  switch (key->strategy)
663  {
665  {
667 
668  if (partdesc->nparts > 0)
669  {
670  PartitionBoundInfo boundinfo = partdesc->boundinfo;
671  ListCell *cell;
672 
673  Assert(boundinfo &&
674  boundinfo->strategy == PARTITION_STRATEGY_LIST &&
675  (boundinfo->ndatums > 0 ||
676  partition_bound_accepts_nulls(boundinfo)));
677 
678  foreach(cell, spec->listdatums)
679  {
680  Const *val = castNode(Const, lfirst(cell));
681 
682  if (!val->constisnull)
683  {
684  int offset;
685  bool equal;
686 
687  offset = partition_bound_bsearch(key, boundinfo,
688  &val->constvalue,
689  true, &equal);
690  if (offset >= 0 && equal)
691  {
692  overlap = true;
693  with = boundinfo->indexes[offset];
694  break;
695  }
696  }
697  else if (partition_bound_accepts_nulls(boundinfo))
698  {
699  overlap = true;
700  with = boundinfo->null_index;
701  break;
702  }
703  }
704  }
705 
706  break;
707  }
708 
710  {
712  *upper;
713 
715  lower = make_one_range_bound(key, -1, spec->lowerdatums, true);
716  upper = make_one_range_bound(key, -1, spec->upperdatums, false);
717 
718  /*
719  * First check if the resulting range would be empty with
720  * specified lower and upper bounds
721  */
722  if (partition_rbound_cmp(key, lower->datums, lower->kind, true,
723  upper) >= 0)
724  {
725  ereport(ERROR,
726  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
727  errmsg("empty range bound specified for partition \"%s\"",
728  relname),
729  errdetail("Specified lower bound %s is greater than or equal to upper bound %s.",
732  parser_errposition(pstate, spec->location)));
733  }
734 
735  if (partdesc->nparts > 0)
736  {
737  PartitionBoundInfo boundinfo = partdesc->boundinfo;
738  int offset;
739  bool equal;
740 
741  Assert(boundinfo && boundinfo->ndatums > 0 &&
742  boundinfo->strategy == PARTITION_STRATEGY_RANGE);
743 
744  /*
745  * Test whether the new lower bound (which is treated
746  * inclusively as part of the new partition) lies inside
747  * an existing partition, or in a gap.
748  *
749  * If it's inside an existing partition, the bound at
750  * offset + 1 will be the upper bound of that partition,
751  * and its index will be >= 0.
752  *
753  * If it's in a gap, the bound at offset + 1 will be the
754  * lower bound of the next partition, and its index will
755  * be -1. This is also true if there is no next partition,
756  * since the index array is initialised with an extra -1
757  * at the end.
758  */
759  offset = partition_bound_bsearch(key, boundinfo, lower,
760  true, &equal);
761 
762  if (boundinfo->indexes[offset + 1] < 0)
763  {
764  /*
765  * Check that the new partition will fit in the gap.
766  * For it to fit, the new upper bound must be less
767  * than or equal to the lower bound of the next
768  * partition, if there is one.
769  */
770  if (offset + 1 < boundinfo->ndatums)
771  {
772  int32 cmpval;
773 
774  cmpval = partition_bound_cmp(key, boundinfo,
775  offset + 1, upper,
776  true);
777  if (cmpval < 0)
778  {
779  /*
780  * The new partition overlaps with the
781  * existing partition between offset + 1 and
782  * offset + 2.
783  */
784  overlap = true;
785  with = boundinfo->indexes[offset + 2];
786  }
787  }
788  }
789  else
790  {
791  /*
792  * The new partition overlaps with the existing
793  * partition between offset and offset + 1.
794  */
795  overlap = true;
796  with = boundinfo->indexes[offset + 1];
797  }
798  }
799 
800  break;
801  }
802 
803  default:
804  elog(ERROR, "unexpected partition strategy: %d",
805  (int) key->strategy);
806  }
807 
808  if (overlap)
809  {
810  Assert(with >= 0);
811  ereport(ERROR,
812  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
813  errmsg("partition \"%s\" would overlap partition \"%s\"",
814  relname, get_rel_name(partdesc->oids[with])),
815  parser_errposition(pstate, spec->location)));
816  }
817 }
Datum constvalue
Definition: primnodes.h:196
PartitionRangeDatumKind * kind
Definition: partition.c:104
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:85
int errcode(int sqlerrcode)
Definition: elog.c:575
Datum upper(PG_FUNCTION_ARGS)
Definition: oracle_compat.c:74
char strategy
Definition: rel.h:54
signed int int32
Definition: c.h:256
PartitionBoundInfo boundinfo
Definition: partition.h:37
ParseState * make_parsestate(ParseState *parentParseState)
Definition: parse_node.c:44
#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:2309
static int32 partition_rbound_cmp(PartitionKey key, Datum *datums1, PartitionRangeDatumKind *kind1, bool lower1, PartitionRangeBound *b2)
Definition: partition.c:2158
int errdetail(const char *fmt,...)
Definition: elog.c:873
#define ereport(elevel, rest)
Definition: elog.h:122
char * get_range_partbound_string(List *bound_datums)
Definition: ruleutils.c:10914
static PartitionRangeBound * make_one_range_bound(PartitionKey key, int index, List *datums, bool lower)
Definition: partition.c:2097
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:676
#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
static int32 partition_bound_cmp(PartitionKey key, PartitionBoundInfo boundinfo, int offset, void *probe, bool probe_is_bound)
Definition: partition.c:2248
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 1875 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().

1880 {
1881  ListCell *partexpr_item;
1882  int i;
1883 
1884  if (pd->key->partexprs != NIL && pd->keystate == NIL)
1885  {
1886  /* Check caller has set up context correctly */
1887  Assert(estate != NULL &&
1888  GetPerTupleExprContext(estate)->ecxt_scantuple == slot);
1889 
1890  /* First time through, set up expression evaluation state */
1891  pd->keystate = ExecPrepareExprList(pd->key->partexprs, estate);
1892  }
1893 
1894  partexpr_item = list_head(pd->keystate);
1895  for (i = 0; i < pd->key->partnatts; i++)
1896  {
1897  AttrNumber keycol = pd->key->partattrs[i];
1898  Datum datum;
1899  bool isNull;
1900 
1901  if (keycol != 0)
1902  {
1903  /* Plain column; get the value directly from the heap tuple */
1904  datum = slot_getattr(slot, keycol, &isNull);
1905  }
1906  else
1907  {
1908  /* Expression; need to evaluate it */
1909  if (partexpr_item == NULL)
1910  elog(ERROR, "wrong number of partition key expressions");
1911  datum = ExecEvalExprSwitchContext((ExprState *) lfirst(partexpr_item),
1912  GetPerTupleExprContext(estate),
1913  &isNull);
1914  partexpr_item = lnext(partexpr_item);
1915  }
1916  values[i] = datum;
1917  isnull[i] = isNull;
1918  }
1919 
1920  if (partexpr_item != NULL)
1921  elog(ERROR, "wrong number of partition key expressions");
1922 }
#define NIL
Definition: pg_list.h:69
static Datum ExecEvalExprSwitchContext(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:299
List * partexprs
Definition: rel.h:58
#define GetPerTupleExprContext(estate)
Definition: executor.h:474
#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:676
#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 1934 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().

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

830 {
831  Form_pg_inherits form;
832  Relation catalogRelation;
833  SysScanDesc scan;
834  ScanKeyData key[2];
835  HeapTuple tuple;
836  Oid result;
837 
838  catalogRelation = heap_open(InheritsRelationId, AccessShareLock);
839 
840  ScanKeyInit(&key[0],
842  BTEqualStrategyNumber, F_OIDEQ,
843  ObjectIdGetDatum(relid));
844  ScanKeyInit(&key[1],
846  BTEqualStrategyNumber, F_INT4EQ,
847  Int32GetDatum(1));
848 
849  scan = systable_beginscan(catalogRelation, InheritsRelidSeqnoIndexId, true,
850  NULL, 2, key);
851 
852  tuple = systable_getnext(scan);
853  if (!HeapTupleIsValid(tuple))
854  elog(ERROR, "could not find tuple for parent of relation %u", relid);
855 
856  form = (Form_pg_inherits) GETSTRUCT(tuple);
857  result = form->inhparent;
858 
859  systable_endscan(scan);
860  heap_close(catalogRelation, AccessShareLock);
861 
862  return result;
863 }
#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:1290
#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 961 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().

962 {
963  Relation rel = heap_open(relid, AccessShareLock);
964  Expr *result = NULL;
965  List *and_args;
966 
967  /* Do the work only if this relation is a partition. */
968  if (rel->rd_rel->relispartition)
969  {
970  and_args = generate_partition_qual(rel);
971  if (list_length(and_args) > 1)
972  result = makeBoolExpr(AND_EXPR, and_args, -1);
973  else
974  result = linitial(and_args);
975  }
976 
977  /* Keep the lock. */
978  heap_close(rel, NoLock);
979 
980  return result;
981 }
#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:1290
#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:1788
Definition: pg_list.h:45
List* get_qual_from_partbound ( Relation  rel,
Relation  parent,
PartitionBoundSpec spec 
)

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

873 {
875  List *my_qual = NIL;
876 
877  Assert(key != NULL);
878 
879  switch (key->strategy)
880  {
883  my_qual = get_qual_for_list(key, spec);
884  break;
885 
888  my_qual = get_qual_for_range(key, spec);
889  break;
890 
891  default:
892  elog(ERROR, "unexpected partition strategy: %d",
893  (int) key->strategy);
894  }
895 
896  return my_qual;
897 }
#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:1486
#define ERROR
Definition: elog.h:43
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:676
static List * get_qual_for_list(PartitionKey key, PartitionBoundSpec *spec)
Definition: partition.c:1288
#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,
bool found_whole_row 
)

Definition at line 914 of file partition.c.

References convert_tuples_by_name_map(), gettext_noop, map_variable_attnos(), NIL, RelationGetDescr, and RelationGetForm.

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

917 {
918  AttrNumber *part_attnos;
919  bool my_found_whole_row;
920 
921  if (expr == NIL)
922  return NIL;
923 
924  part_attnos = convert_tuples_by_name_map(RelationGetDescr(partrel),
925  RelationGetDescr(parent),
926  gettext_noop("could not convert row type"));
927  expr = (List *) map_variable_attnos((Node *) expr,
928  target_varno, 0,
929  part_attnos,
930  RelationGetDescr(parent)->natts,
931  RelationGetForm(partrel)->reltype,
932  &my_found_whole_row);
933  if (found_whole_row)
934  *found_whole_row = my_found_whole_row;
935 
936  return expr;
937 }
#define NIL
Definition: pg_list.h:69
#define RelationGetDescr(relation)
Definition: rel.h:428
#define RelationGetForm(relation)
Definition: rel.h:410
#define gettext_noop(x)
Definition: c.h:139
Definition: nodes.h:509
Node * map_variable_attnos(Node *node, int target_varno, int sublevels_up, const AttrNumber *attno_map, int map_length, Oid to_rowtype, bool *found_whole_row)
AttrNumber * convert_tuples_by_name_map(TupleDesc indesc, TupleDesc outdesc, const char *msg)
Definition: tupconvert.c:283
Definition: pg_list.h:45
int16 AttrNumber
Definition: attnum.h:21
bool partition_bounds_equal ( int  partnatts,
int16 parttyplen,
bool parttypbyval,
PartitionBoundInfo  b1,
PartitionBoundInfo  b2 
)

Definition at line 586 of file partition.c.

References datumIsEqual(), PartitionBoundInfoData::datums, i, PartitionBoundInfoData::indexes, PartitionBoundInfoData::kind, PartitionBoundInfoData::ndatums, NULL, PartitionBoundInfoData::null_index, PARTITION_RANGE_DATUM_VALUE, PARTITION_STRATEGY_RANGE, and PartitionBoundInfoData::strategy.

Referenced by equalPartitionDescs().

588 {
589  int i;
590 
591  if (b1->strategy != b2->strategy)
592  return false;
593 
594  if (b1->ndatums != b2->ndatums)
595  return false;
596 
597  if (b1->null_index != b2->null_index)
598  return false;
599 
600  for (i = 0; i < b1->ndatums; i++)
601  {
602  int j;
603 
604  for (j = 0; j < partnatts; j++)
605  {
606  /* For range partitions, the bounds might not be finite. */
607  if (b1->kind != NULL)
608  {
609  /* The different kinds of bound all differ from each other */
610  if (b1->kind[i][j] != b2->kind[i][j])
611  return false;
612 
613  /* Non-finite bounds are equal without further examination. */
614  if (b1->kind[i][j] != PARTITION_RANGE_DATUM_VALUE)
615  continue;
616  }
617 
618  /*
619  * Compare the actual values. Note that it would be both incorrect
620  * and unsafe to invoke the comparison operator derived from the
621  * partitioning specification here. It would be incorrect because
622  * we want the relcache entry to be updated for ANY change to the
623  * partition bounds, not just those that the partitioning operator
624  * thinks are significant. It would be unsafe because we might
625  * reach this code in the context of an aborted transaction, and
626  * an arbitrary partitioning operator might not be safe in that
627  * context. datumIsEqual() should be simple enough to be safe.
628  */
629  if (!datumIsEqual(b1->datums[i][j], b2->datums[i][j],
630  parttypbyval[j], parttyplen[j]))
631  return false;
632  }
633 
634  if (b1->indexes[i] != b2->indexes[i])
635  return false;
636  }
637 
638  /* There are ndatums+1 indexes in case of range partitions */
639  if (b1->strategy == PARTITION_STRATEGY_RANGE &&
640  b1->indexes[i] != b2->indexes[i])
641  return false;
642 
643  return true;
644 }
PartitionRangeDatumKind ** kind
Definition: partition.c:76
bool datumIsEqual(Datum value1, Datum value2, bool typByVal, int typLen)
Definition: datum.c:219
#define NULL
Definition: c.h:229
#define PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:787
int i
void RelationBuildPartitionDesc ( Relation  relation)

Definition at line 151 of file partition.c.

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate(), Anum_pg_class_relpartbound, Assert, PartitionDescData::boundinfo, CacheMemoryContext, castNode, Const::constisnull, Const::constvalue, cur, datumCopy(), DatumGetInt32, PartitionBoundInfoData::datums, PartitionRangeBound::datums, elog, ERROR, find_inheritance_children(), FunctionCall2Coll(), GETSTRUCT, HeapTupleIsValid, i, PartitionListValue::index, PartitionRangeBound::index, PartitionBoundInfoData::indexes, PartitionBoundInfoData::kind, PartitionRangeBound::kind, 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_RANGE_DATUM_VALUE, 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(), 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().

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

Definition at line 1011 of file partition.c.

References APPEND_REL_PARTITION_OIDS, convert_tuples_by_name(), forboth, get_rel_relkind(), gettext_noop, 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().

1013 {
1014  PartitionDispatchData **pd;
1015  List *all_parts = NIL,
1016  *all_parents = NIL,
1017  *parted_rels,
1018  *parted_rel_parents;
1019  ListCell *lc1,
1020  *lc2;
1021  int i,
1022  k,
1023  offset;
1024 
1025  /*
1026  * We rely on the relcache to traverse the partition tree to build both
1027  * the leaf partition OIDs list and the array of PartitionDispatch objects
1028  * for the partitioned tables in the tree. That means every partitioned
1029  * table in the tree must be locked, which is fine since we require the
1030  * caller to lock all the partitions anyway.
1031  *
1032  * For every partitioned table in the tree, starting with the root
1033  * partitioned table, add its relcache entry to parted_rels, while also
1034  * queuing its partitions (in the order in which they appear in the
1035  * partition descriptor) to be looked at later in the same loop. This is
1036  * a bit tricky but works because the foreach() macro doesn't fetch the
1037  * next list element until the bottom of the loop.
1038  */
1039  *num_parted = 1;
1040  parted_rels = list_make1(rel);
1041  /* Root partitioned table has no parent, so NULL for parent */
1042  parted_rel_parents = list_make1(NULL);
1043  APPEND_REL_PARTITION_OIDS(rel, all_parts, all_parents);
1044  forboth(lc1, all_parts, lc2, all_parents)
1045  {
1046  Oid partrelid = lfirst_oid(lc1);
1047  Relation parent = lfirst(lc2);
1048 
1049  if (get_rel_relkind(partrelid) == RELKIND_PARTITIONED_TABLE)
1050  {
1051  /*
1052  * Already locked by the caller. Note that it is the
1053  * responsibility of the caller to close the below relcache entry,
1054  * once done using the information being collected here (for
1055  * example, in ExecEndModifyTable).
1056  */
1057  Relation partrel = heap_open(partrelid, NoLock);
1058 
1059  (*num_parted)++;
1060  parted_rels = lappend(parted_rels, partrel);
1061  parted_rel_parents = lappend(parted_rel_parents, parent);
1062  APPEND_REL_PARTITION_OIDS(partrel, all_parts, all_parents);
1063  }
1064  }
1065 
1066  /*
1067  * We want to create two arrays - one for leaf partitions and another for
1068  * partitioned tables (including the root table and internal partitions).
1069  * While we only create the latter here, leaf partition array of suitable
1070  * objects (such as, ResultRelInfo) is created by the caller using the
1071  * list of OIDs we return. Indexes into these arrays get assigned in a
1072  * breadth-first manner, whereby partitions of any given level are placed
1073  * consecutively in the respective arrays.
1074  */
1075  pd = (PartitionDispatchData **) palloc(*num_parted *
1076  sizeof(PartitionDispatchData *));
1077  *leaf_part_oids = NIL;
1078  i = k = offset = 0;
1079  forboth(lc1, parted_rels, lc2, parted_rel_parents)
1080  {
1081  Relation partrel = lfirst(lc1);
1082  Relation parent = lfirst(lc2);
1083  PartitionKey partkey = RelationGetPartitionKey(partrel);
1084  TupleDesc tupdesc = RelationGetDescr(partrel);
1085  PartitionDesc partdesc = RelationGetPartitionDesc(partrel);
1086  int j,
1087  m;
1088 
1090  pd[i]->reldesc = partrel;
1091  pd[i]->key = partkey;
1092  pd[i]->keystate = NIL;
1093  pd[i]->partdesc = partdesc;
1094  if (parent != NULL)
1095  {
1096  /*
1097  * For every partitioned table other than root, we must store a
1098  * tuple table slot initialized with its tuple descriptor and a
1099  * tuple conversion map to convert a tuple from its parent's
1100  * rowtype to its own. That is to make sure that we are looking at
1101  * the correct row using the correct tuple descriptor when
1102  * computing its partition key for tuple routing.
1103  */
1104  pd[i]->tupslot = MakeSingleTupleTableSlot(tupdesc);
1106  tupdesc,
1107  gettext_noop("could not convert row type"));
1108  }
1109  else
1110  {
1111  /* Not required for the root partitioned table */
1112  pd[i]->tupslot = NULL;
1113  pd[i]->tupmap = NULL;
1114  }
1115  pd[i]->indexes = (int *) palloc(partdesc->nparts * sizeof(int));
1116 
1117  /*
1118  * Indexes corresponding to the internal partitions are multiplied by
1119  * -1 to distinguish them from those of leaf partitions. Encountering
1120  * an index >= 0 means we found a leaf partition, which is immediately
1121  * returned as the partition we are looking for. A negative index
1122  * means we found a partitioned table, whose PartitionDispatch object
1123  * is located at the above index multiplied back by -1. Using the
1124  * PartitionDispatch object, search is continued further down the
1125  * partition tree.
1126  */
1127  m = 0;
1128  for (j = 0; j < partdesc->nparts; j++)
1129  {
1130  Oid partrelid = partdesc->oids[j];
1131 
1132  if (get_rel_relkind(partrelid) != RELKIND_PARTITIONED_TABLE)
1133  {
1134  *leaf_part_oids = lappend_oid(*leaf_part_oids, partrelid);
1135  pd[i]->indexes[j] = k++;
1136  }
1137  else
1138  {
1139  /*
1140  * offset denotes the number of partitioned tables of upper
1141  * levels including those of the current level. Any partition
1142  * of this table must belong to the next level and hence will
1143  * be placed after the last partitioned table of this level.
1144  */
1145  pd[i]->indexes[j] = -(1 + offset + m);
1146  m++;
1147  }
1148  }
1149  i++;
1150 
1151  /*
1152  * This counts the number of partitioned tables at upper levels
1153  * including those of the current level.
1154  */
1155  offset += m;
1156  }
1157 
1158  return pd;
1159 }
#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
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:1290
#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:987
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 945 of file partition.c.

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

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

946 {
947  /* Quick exit */
948  if (!rel->rd_rel->relispartition)
949  return NIL;
950 
951  return generate_partition_qual(rel);
952 }
#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:1788