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, Node *bound)
 
Oid get_partition_parent (Oid relid)
 
Listget_qual_from_partbound (Relation rel, Relation parent, Node *bound)
 
Listmap_partition_varattnos (List *expr, int target_varno, Relation partrel, Relation parent)
 
ListRelationGetPartitionQual (Relation rel)
 
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,
Node bound 
)

Definition at line 669 of file partition.c.

References Assert, PartitionDescData::boundinfo, Const::constisnull, Const::constvalue, PartitionRangeBound::content, PartitionRangeBound::datums, elog, equal(), ereport, errcode(), errmsg(), ERROR, get_rel_name(), PartitionBoundInfoData::has_null, 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_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().

670 {
671  PartitionBoundSpec *spec = (PartitionBoundSpec *) bound;
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 || boundinfo->has_null));
692 
693  foreach(cell, spec->listdatums)
694  {
695  Const *val = lfirst(cell);
696 
697  if (!val->constisnull)
698  {
699  int offset;
700  bool equal;
701 
702  offset = partition_bound_bsearch(key, boundinfo,
703  &val->constvalue,
704  true, &equal);
705  if (offset >= 0 && equal)
706  {
707  overlap = true;
708  with = boundinfo->indexes[offset];
709  break;
710  }
711  }
712  else if (boundinfo->has_null)
713  {
714  overlap = true;
715  with = boundinfo->null_index;
716  break;
717  }
718  }
719  }
720 
721  break;
722  }
723 
725  {
727  *upper;
728 
730  lower = make_one_range_bound(key, -1, spec->lowerdatums, true);
731  upper = make_one_range_bound(key, -1, spec->upperdatums, false);
732 
733  /*
734  * First check if the resulting range would be empty with
735  * specified lower and upper bounds
736  */
737  if (partition_rbound_cmp(key, lower->datums, lower->content, true,
738  upper) >= 0)
739  ereport(ERROR,
740  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
741  errmsg("cannot create range partition with empty range"),
742  parser_errposition(pstate, spec->location)));
743 
744  if (partdesc->nparts > 0)
745  {
746  PartitionBoundInfo boundinfo = partdesc->boundinfo;
747  int off1,
748  off2;
749  bool equal = false;
750 
751  Assert(boundinfo && boundinfo->ndatums > 0 &&
752  boundinfo->strategy == PARTITION_STRATEGY_RANGE);
753 
754  /*
755  * Firstly, find the greatest range bound that is less
756  * than or equal to the new lower bound.
757  */
758  off1 = partition_bound_bsearch(key, boundinfo, lower, true,
759  &equal);
760 
761  /*
762  * off1 == -1 means that all existing bounds are greater
763  * than the new lower bound. In that case and the case
764  * where no partition is defined between the bounds at
765  * off1 and off1 + 1, we have a "gap" in the range that
766  * could be occupied by the new partition. We confirm if
767  * so by checking whether the new upper bound is confined
768  * within the gap.
769  */
770  if (!equal && boundinfo->indexes[off1 + 1] < 0)
771  {
772  off2 = partition_bound_bsearch(key, boundinfo, upper,
773  true, &equal);
774 
775  /*
776  * If the new upper bound is returned to be equal to
777  * the bound at off2, the latter must be the upper
778  * bound of some partition with which the new
779  * partition clearly overlaps.
780  *
781  * Also, if bound at off2 is not same as the one
782  * returned for the new lower bound (IOW, off1 !=
783  * off2), then the new partition overlaps at least one
784  * partition.
785  */
786  if (equal || off1 != off2)
787  {
788  overlap = true;
789 
790  /*
791  * The bound at off2 could be the lower bound of
792  * the partition with which the new partition
793  * overlaps. In that case, use the upper bound
794  * (that is, the bound at off2 + 1) to get the
795  * index of that partition.
796  */
797  if (boundinfo->indexes[off2] < 0)
798  with = boundinfo->indexes[off2 + 1];
799  else
800  with = boundinfo->indexes[off2];
801  }
802  }
803  else
804  {
805  /*
806  * Equal has been set to true and there is no "gap"
807  * between the bound at off1 and that at off1 + 1, so
808  * the new partition will overlap some partition. In
809  * the former case, the new lower bound is found to be
810  * equal to the bound at off1, which could only ever
811  * be true if the latter is the lower bound of some
812  * partition. It's clear in such a case that the new
813  * partition overlaps that partition, whose index we
814  * get using its upper bound (that is, using the bound
815  * at off1 + 1).
816  */
817  overlap = true;
818  with = boundinfo->indexes[off1 + 1];
819  }
820  }
821 
822  break;
823  }
824 
825  default:
826  elog(ERROR, "unexpected partition strategy: %d",
827  (int) key->strategy);
828  }
829 
830  if (overlap)
831  {
832  Assert(with >= 0);
833  ereport(ERROR,
834  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
835  errmsg("partition \"%s\" would overlap partition \"%s\"",
836  relname, get_rel_name(partdesc->oids[with])),
837  parser_errposition(pstate, spec->location)));
838  }
839 }
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
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:1878
static int partition_bound_bsearch(PartitionKey key, PartitionBoundInfo boundinfo, void *probe, bool probe_is_bound, bool *is_equal)
Definition: partition.c:2026
#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:1821
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:781
#define RelationGetPartitionKey(relation)
Definition: rel.h:585
#define PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:782
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:633
void FormPartitionKeyDatum ( PartitionDispatch  pd,
TupleTableSlot slot,
EState estate,
Datum values,
bool isnull 
)

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

1614 {
1615  ListCell *partexpr_item;
1616  int i;
1617 
1618  if (pd->key->partexprs != NIL && pd->keystate == NIL)
1619  {
1620  /* Check caller has set up context correctly */
1621  Assert(estate != NULL &&
1622  GetPerTupleExprContext(estate)->ecxt_scantuple == slot);
1623 
1624  /* First time through, set up expression evaluation state */
1625  pd->keystate = ExecPrepareExprList(pd->key->partexprs, estate);
1626  }
1627 
1628  partexpr_item = list_head(pd->keystate);
1629  for (i = 0; i < pd->key->partnatts; i++)
1630  {
1631  AttrNumber keycol = pd->key->partattrs[i];
1632  Datum datum;
1633  bool isNull;
1634 
1635  if (keycol != 0)
1636  {
1637  /* Plain column; get the value directly from the heap tuple */
1638  datum = slot_getattr(slot, keycol, &isNull);
1639  }
1640  else
1641  {
1642  /* Expression; need to evaluate it */
1643  if (partexpr_item == NULL)
1644  elog(ERROR, "wrong number of partition key expressions");
1645  datum = ExecEvalExprSwitchContext((ExprState *) lfirst(partexpr_item),
1646  GetPerTupleExprContext(estate),
1647  &isNull);
1648  partexpr_item = lnext(partexpr_item);
1649  }
1650  values[i] = datum;
1651  isnull[i] = isNull;
1652  }
1653 
1654  if (partexpr_item != NULL)
1655  elog(ERROR, "wrong number of partition key expressions");
1656 }
#define NIL
Definition: pg_list.h:69
static Datum ExecEvalExprSwitchContext(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:280
List * partexprs
Definition: rel.h:58
#define GetPerTupleExprContext(estate)
Definition: executor.h:455
#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:1143
#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 1668 of file partition.c.

References PartitionDescData::boundinfo, do_convert_tuple(), ExprContext::ecxt_scantuple, elog, equal(), ereport, errcode(), errmsg(), ERROR, ExecClearTuple(), ExecFetchSlotTuple(), ExecStoreTuple(), FormPartitionKeyDatum(), GetPerTupleExprContext, PartitionBoundInfoData::has_null, i, PartitionDispatchData::indexes, PartitionBoundInfoData::indexes, InvalidBuffer, PartitionDispatchData::key, PartitionDescData::nparts, NULL, PartitionBoundInfoData::null_index, PartitionDispatchData::partdesc, 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().

1673 {
1674  PartitionDispatch parent;
1676  bool isnull[PARTITION_MAX_KEYS];
1677  int cur_offset,
1678  cur_index;
1679  int i,
1680  result;
1681  ExprContext *ecxt = GetPerTupleExprContext(estate);
1682  TupleTableSlot *ecxt_scantuple_old = ecxt->ecxt_scantuple;
1683 
1684  /* start with the root partitioned table */
1685  parent = pd[0];
1686  while (true)
1687  {
1688  PartitionKey key = parent->key;
1689  PartitionDesc partdesc = parent->partdesc;
1690  TupleTableSlot *myslot = parent->tupslot;
1691  TupleConversionMap *map = parent->tupmap;
1692 
1693  if (myslot != NULL && map != NULL)
1694  {
1695  HeapTuple tuple = ExecFetchSlotTuple(slot);
1696 
1697  ExecClearTuple(myslot);
1698  tuple = do_convert_tuple(tuple, map);
1699  ExecStoreTuple(tuple, myslot, InvalidBuffer, true);
1700  slot = myslot;
1701  }
1702 
1703  /* Quick exit */
1704  if (partdesc->nparts == 0)
1705  {
1706  *failed_at = parent;
1707  *failed_slot = slot;
1708  return -1;
1709  }
1710 
1711  /*
1712  * Extract partition key from tuple. Expression evaluation machinery
1713  * that FormPartitionKeyDatum() invokes expects ecxt_scantuple to
1714  * point to the correct tuple slot. The slot might have changed from
1715  * what was used for the parent table if the table of the current
1716  * partitioning level has different tuple descriptor from the parent.
1717  * So update ecxt_scantuple accordingly.
1718  */
1719  ecxt->ecxt_scantuple = slot;
1720  FormPartitionKeyDatum(parent, slot, estate, values, isnull);
1721 
1722  if (key->strategy == PARTITION_STRATEGY_RANGE)
1723  {
1724  /* Disallow nulls in the range partition key of the tuple */
1725  for (i = 0; i < key->partnatts; i++)
1726  if (isnull[i])
1727  ereport(ERROR,
1728  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
1729  errmsg("range partition key of row contains null")));
1730  }
1731 
1732  /*
1733  * A null partition key is only acceptable if null-accepting list
1734  * partition exists.
1735  */
1736  cur_index = -1;
1737  if (isnull[0] && partdesc->boundinfo->has_null)
1738  cur_index = partdesc->boundinfo->null_index;
1739  else if (!isnull[0])
1740  {
1741  /* Else bsearch in partdesc->boundinfo */
1742  bool equal = false;
1743 
1744  cur_offset = partition_bound_bsearch(key, partdesc->boundinfo,
1745  values, false, &equal);
1746  switch (key->strategy)
1747  {
1749  if (cur_offset >= 0 && equal)
1750  cur_index = partdesc->boundinfo->indexes[cur_offset];
1751  else
1752  cur_index = -1;
1753  break;
1754 
1756 
1757  /*
1758  * Offset returned is such that the bound at offset is
1759  * found to be less or equal with the tuple. So, the bound
1760  * at offset+1 would be the upper bound.
1761  */
1762  cur_index = partdesc->boundinfo->indexes[cur_offset + 1];
1763  break;
1764 
1765  default:
1766  elog(ERROR, "unexpected partition strategy: %d",
1767  (int) key->strategy);
1768  }
1769  }
1770 
1771  /*
1772  * cur_index < 0 means we failed to find a partition of this parent.
1773  * cur_index >= 0 means we either found the leaf partition, or the
1774  * next parent to find a partition of.
1775  */
1776  if (cur_index < 0)
1777  {
1778  result = -1;
1779  *failed_at = parent;
1780  *failed_slot = slot;
1781  break;
1782  }
1783  else if (parent->indexes[cur_index] >= 0)
1784  {
1785  result = parent->indexes[cur_index];
1786  break;
1787  }
1788  else
1789  parent = pd[-parent->indexes[cur_index]];
1790  }
1791 
1792  ecxt->ecxt_scantuple = ecxt_scantuple_old;
1793  return result;
1794 }
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
int errcode(int sqlerrcode)
Definition: elog.c:575
#define PARTITION_MAX_KEYS
return result
Definition: formatting.c:1618
char strategy
Definition: rel.h:54
PartitionBoundInfo boundinfo
Definition: partition.h:37
#define GetPerTupleExprContext(estate)
Definition: executor.h:455
#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:2026
void FormPartitionKeyDatum(PartitionDispatch pd, TupleTableSlot *slot, EState *estate, Datum *values, bool *isnull)
Definition: partition.c:1609
#define ereport(elevel, rest)
Definition: elog.h:122
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:781
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:782
int errmsg(const char *fmt,...)
Definition: elog.c:797
int i
#define elog
Definition: elog.h:219
PartitionKey key
Definition: partition.h:63
Oid get_partition_parent ( Oid  relid)

Definition at line 851 of file partition.c.

References AccessShareLock, Anum_pg_inherits_inhrelid, Anum_pg_inherits_inhseqno, Assert, BTEqualStrategyNumber, 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().

852 {
853  Form_pg_inherits form;
854  Relation catalogRelation;
855  SysScanDesc scan;
856  ScanKeyData key[2];
857  HeapTuple tuple;
858  Oid result;
859 
860  catalogRelation = heap_open(InheritsRelationId, AccessShareLock);
861 
862  ScanKeyInit(&key[0],
864  BTEqualStrategyNumber, F_OIDEQ,
865  ObjectIdGetDatum(relid));
866  ScanKeyInit(&key[1],
868  BTEqualStrategyNumber, F_INT4EQ,
869  Int32GetDatum(1));
870 
871  scan = systable_beginscan(catalogRelation, InheritsRelidSeqnoIndexId, true,
872  NULL, 2, key);
873 
874  tuple = systable_getnext(scan);
875  Assert(HeapTupleIsValid(tuple));
876 
877  form = (Form_pg_inherits) GETSTRUCT(tuple);
878  result = form->inhparent;
879 
880  systable_endscan(scan);
881  heap_close(catalogRelation, AccessShareLock);
882 
883  return result;
884 }
#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:1618
#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 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 Assert(condition)
Definition: c.h:675
#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 BTEqualStrategyNumber
Definition: stratnum.h:31
List* get_qual_from_partbound ( Relation  rel,
Relation  parent,
Node bound 
)

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

893 {
894  PartitionBoundSpec *spec = (PartitionBoundSpec *) bound;
896  List *my_qual = NIL;
897 
898  Assert(key != NULL);
899 
900  switch (key->strategy)
901  {
904  my_qual = get_qual_for_list(key, spec);
905  break;
906 
909  my_qual = get_qual_for_range(key, spec);
910  break;
911 
912  default:
913  elog(ERROR, "unexpected partition strategy: %d",
914  (int) key->strategy);
915  }
916 
917  return my_qual;
918 }
#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:1276
#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:1154
#define PARTITION_STRATEGY_LIST
Definition: parsenodes.h:781
#define RelationGetPartitionKey(relation)
Definition: rel.h:585
#define PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:782
#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 932 of file partition.c.

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

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

934 {
935  AttrNumber *part_attnos;
936  bool found_whole_row;
937 
938  if (expr == NIL)
939  return NIL;
940 
941  part_attnos = convert_tuples_by_name_map(RelationGetDescr(partrel),
942  RelationGetDescr(parent),
943  gettext_noop("could not convert row type"));
944  expr = (List *) map_variable_attnos((Node *) expr,
945  target_varno, 0,
946  part_attnos,
947  RelationGetDescr(parent)->natts,
948  &found_whole_row);
949  /* There can never be a whole-row reference here */
950  if (found_whole_row)
951  elog(ERROR, "unexpected whole-row reference found in partition key");
952 
953  return expr;
954 }
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:429
#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 595 of file partition.c.

References PartitionBoundInfoData::content, datumIsEqual(), PartitionBoundInfoData::datums, PartitionBoundInfoData::has_null, 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().

597 {
598  int i;
599 
600  if (b1->strategy != b2->strategy)
601  return false;
602 
603  if (b1->ndatums != b2->ndatums)
604  return false;
605 
606  if (b1->has_null != b2->has_null)
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:782
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, Const::constisnull, Const::constvalue, PartitionBoundInfoData::content, PartitionRangeBound::content, cur, datumCopy(), DatumGetInt32, PartitionBoundInfoData::datums, PartitionRangeBound::datums, elog, ERROR, find_inheritance_children(), FunctionCall2Coll(), GETSTRUCT, PartitionBoundInfoData::has_null, 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().

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

997 {
999  List *all_parts = NIL,
1000  *all_parents = NIL,
1001  *parted_rels,
1002  *parted_rel_parents;
1003  ListCell *lc1,
1004  *lc2;
1005  int i,
1006  k,
1007  offset;
1008 
1009  /*
1010  * Lock partitions and make a list of the partitioned ones to prepare
1011  * their PartitionDispatch objects below.
1012  *
1013  * Cannot use find_all_inheritors() here, because then the order of OIDs
1014  * in parted_rels list would be unknown, which does not help, because we
1015  * we assign indexes within individual PartitionDispatch in an order that
1016  * is predetermined (determined by the order of OIDs in individual
1017  * partition descriptors).
1018  */
1019  *num_parted = 1;
1020  parted_rels = list_make1(rel);
1021  /* Root partitioned table has no parent, so NULL for parent */
1022  parted_rel_parents = list_make1(NULL);
1023  APPEND_REL_PARTITION_OIDS(rel, all_parts, all_parents);
1024  forboth(lc1, all_parts, lc2, all_parents)
1025  {
1026  Relation partrel = heap_open(lfirst_oid(lc1), lockmode);
1027  Relation parent = lfirst(lc2);
1028  PartitionDesc partdesc = RelationGetPartitionDesc(partrel);
1029 
1030  /*
1031  * If this partition is a partitioned table, add its children to the
1032  * end of the list, so that they are processed as well.
1033  */
1034  if (partdesc)
1035  {
1036  (*num_parted)++;
1037  parted_rels = lappend(parted_rels, partrel);
1038  parted_rel_parents = lappend(parted_rel_parents, parent);
1039  APPEND_REL_PARTITION_OIDS(partrel, all_parts, all_parents);
1040  }
1041  else
1042  heap_close(partrel, NoLock);
1043 
1044  /*
1045  * We keep the partitioned ones open until we're done using the
1046  * information being collected here (for example, see
1047  * ExecEndModifyTable).
1048  */
1049  }
1050 
1051  /*
1052  * We want to create two arrays - one for leaf partitions and another for
1053  * partitioned tables (including the root table and internal partitions).
1054  * While we only create the latter here, leaf partition array of suitable
1055  * objects (such as, ResultRelInfo) is created by the caller using the
1056  * list of OIDs we return. Indexes into these arrays get assigned in a
1057  * breadth-first manner, whereby partitions of any given level are placed
1058  * consecutively in the respective arrays.
1059  */
1060  pd = (PartitionDispatchData **) palloc(*num_parted *
1061  sizeof(PartitionDispatchData *));
1062  *leaf_part_oids = NIL;
1063  i = k = offset = 0;
1064  forboth(lc1, parted_rels, lc2, parted_rel_parents)
1065  {
1066  Relation partrel = lfirst(lc1);
1067  Relation parent = lfirst(lc2);
1068  PartitionKey partkey = RelationGetPartitionKey(partrel);
1069  TupleDesc tupdesc = RelationGetDescr(partrel);
1070  PartitionDesc partdesc = RelationGetPartitionDesc(partrel);
1071  int j,
1072  m;
1073 
1075  pd[i]->reldesc = partrel;
1076  pd[i]->key = partkey;
1077  pd[i]->keystate = NIL;
1078  pd[i]->partdesc = partdesc;
1079  if (parent != NULL)
1080  {
1081  /*
1082  * For every partitioned table other than root, we must store a
1083  * tuple table slot initialized with its tuple descriptor and a
1084  * tuple conversion map to convert a tuple from its parent's
1085  * rowtype to its own. That is to make sure that we are looking at
1086  * the correct row using the correct tuple descriptor when
1087  * computing its partition key for tuple routing.
1088  */
1089  pd[i]->tupslot = MakeSingleTupleTableSlot(tupdesc);
1091  tupdesc,
1092  gettext_noop("could not convert row type"));
1093  }
1094  else
1095  {
1096  /* Not required for the root partitioned table */
1097  pd[i]->tupslot = NULL;
1098  pd[i]->tupmap = NULL;
1099  }
1100  pd[i]->indexes = (int *) palloc(partdesc->nparts * sizeof(int));
1101 
1102  /*
1103  * Indexes corresponding to the internal partitions are multiplied by
1104  * -1 to distinguish them from those of leaf partitions. Encountering
1105  * an index >= 0 means we found a leaf partition, which is immediately
1106  * returned as the partition we are looking for. A negative index
1107  * means we found a partitioned table, whose PartitionDispatch object
1108  * is located at the above index multiplied back by -1. Using the
1109  * PartitionDispatch object, search is continued further down the
1110  * partition tree.
1111  */
1112  m = 0;
1113  for (j = 0; j < partdesc->nparts; j++)
1114  {
1115  Oid partrelid = partdesc->oids[j];
1116 
1117  if (get_rel_relkind(partrelid) != RELKIND_PARTITIONED_TABLE)
1118  {
1119  *leaf_part_oids = lappend_oid(*leaf_part_oids, partrelid);
1120  pd[i]->indexes[j] = k++;
1121  }
1122  else
1123  {
1124  /*
1125  * offset denotes the number of partitioned tables of upper
1126  * levels including those of the current level. Any partition
1127  * of this table must belong to the next level and hence will
1128  * be placed after the last partitioned table of this level.
1129  */
1130  pd[i]->indexes[j] = -(1 + offset + m);
1131  m++;
1132  }
1133  }
1134  i++;
1135 
1136  /*
1137  * This counts the number of partitioned tables at upper levels
1138  * including those of the current level.
1139  */
1140  offset += m;
1141  }
1142 
1143  return pd;
1144 }
#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:429
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:585
void * palloc(Size size)
Definition: mcxt.c:849
#define APPEND_REL_PARTITION_OIDS(rel, partoids, parents)
Definition: partition.c:975
int i
Definition: pg_list.h:45
#define lfirst_oid(lc)
Definition: pg_list.h:108
#define RelationGetPartitionDesc(relation)
Definition: rel.h:633
PartitionKey key
Definition: partition.h:63
List* RelationGetPartitionQual ( Relation  rel)

Definition at line 962 of file partition.c.

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

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

963 {
964  /* Quick exit */
965  if (!rel->rd_rel->relispartition)
966  return NIL;
967 
968  return generate_partition_qual(rel);
969 }
#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:1528