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)
 
int get_partition_for_tuple (PartitionDispatch *pd, TupleTableSlot *slot, EState *estate, Oid *failed_at)
 

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 676 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().

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

Definition at line 1672 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, RelationGetRelid, PartitionDispatchData::reldesc, PartitionKeyData::strategy, PartitionDispatchData::tupmap, PartitionDispatchData::tupslot, and values.

Referenced by ExecFindPartition().

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

Definition at line 858 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, ScanKeyInit(), systable_beginscan(), systable_endscan(), and systable_getnext().

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

859 {
860  Form_pg_inherits form;
861  Relation catalogRelation;
862  SysScanDesc scan;
863  ScanKeyData key[2];
864  HeapTuple tuple;
865  Oid result;
866 
867  catalogRelation = heap_open(InheritsRelationId, AccessShareLock);
868 
869  ScanKeyInit(&key[0],
871  BTEqualStrategyNumber, F_OIDEQ,
872  ObjectIdGetDatum(relid));
873  ScanKeyInit(&key[1],
875  BTEqualStrategyNumber, F_INT4EQ,
876  Int32GetDatum(1));
877 
878  scan = systable_beginscan(catalogRelation, InheritsRelidSeqnoIndexId, true,
879  NULL, 2, key);
880 
881  tuple = systable_getnext(scan);
882  Assert(HeapTupleIsValid(tuple));
883 
884  form = (Form_pg_inherits) GETSTRUCT(tuple);
885  result = form->inhparent;
886 
887  systable_endscan(scan);
888  heap_close(catalogRelation, AccessShareLock);
889 
890  return result;
891 }
#define Anum_pg_inherits_inhrelid
Definition: pg_inherits.h:50
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:493
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
#define AccessShareLock
Definition: lockdefs.h:36
#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:322
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:410
#define ObjectIdGetDatum(X)
Definition: postgres.h:515
#define Anum_pg_inherits_inhseqno
Definition: pg_inherits.h:52
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1287
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:670
#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:487
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 899 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().

900 {
901  PartitionBoundSpec *spec = (PartitionBoundSpec *) bound;
903  List *my_qual = NIL;
904 
905  Assert(key != NULL);
906 
907  switch (key->strategy)
908  {
911  my_qual = get_qual_for_list(key, spec);
912  break;
913 
916  my_qual = get_qual_for_range(key, spec);
917  break;
918 
919  default:
920  elog(ERROR, "unexpected partition strategy: %d",
921  (int) key->strategy);
922  }
923 
924  return my_qual;
925 }
#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:1279
#define ERROR
Definition: elog.h:43
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:670
static List * get_qual_for_list(PartitionKey key, PartitionBoundSpec *spec)
Definition: partition.c:1157
#define PARTITION_STRATEGY_LIST
Definition: parsenodes.h:736
#define RelationGetPartitionKey(relation)
Definition: rel.h:581
#define PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:737
#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 935 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().

937 {
938  AttrNumber *part_attnos;
939  bool found_whole_row;
940 
941  if (expr == NIL)
942  return NIL;
943 
944  part_attnos = convert_tuples_by_name_map(RelationGetDescr(partrel),
945  RelationGetDescr(parent),
946  gettext_noop("could not convert row type"));
947  expr = (List *) map_variable_attnos((Node *) expr,
948  target_varno, 0,
949  part_attnos,
950  RelationGetDescr(parent)->natts,
951  &found_whole_row);
952  /* There can never be a whole-row reference here */
953  if (found_whole_row)
954  elog(ERROR, "unexpected whole-row reference found in partition key");
955 
956  return expr;
957 }
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:425
#define gettext_noop(x)
Definition: c.h:139
Definition: nodes.h:508
#define ERROR
Definition: elog.h:43
AttrNumber * convert_tuples_by_name_map(TupleDesc indesc, TupleDesc outdesc, const char *msg)
Definition: tupconvert.c:281
#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 602 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().

604 {
605  int i;
606 
607  if (b1->strategy != b2->strategy)
608  return false;
609 
610  if (b1->ndatums != b2->ndatums)
611  return false;
612 
613  if (b1->has_null != b2->has_null)
614  return false;
615 
616  if (b1->null_index != b2->null_index)
617  return false;
618 
619  for (i = 0; i < b1->ndatums; i++)
620  {
621  int j;
622 
623  for (j = 0; j < key->partnatts; j++)
624  {
625  /* For range partitions, the bounds might not be finite. */
626  if (b1->content != NULL)
627  {
628  /*
629  * A finite bound always differs from an infinite bound, and
630  * different kinds of infinities differ from each other.
631  */
632  if (b1->content[i][j] != b2->content[i][j])
633  return false;
634 
635  /* Non-finite bounds are equal without further examination. */
636  if (b1->content[i][j] != RANGE_DATUM_FINITE)
637  continue;
638  }
639 
640  /*
641  * Compare the actual values. Note that it would be both incorrect
642  * and unsafe to invoke the comparison operator derived from the
643  * partitioning specification here. It would be incorrect because
644  * we want the relcache entry to be updated for ANY change to the
645  * partition bounds, not just those that the partitioning operator
646  * thinks are significant. It would be unsafe because we might
647  * reach this code in the context of an aborted transaction, and
648  * an arbitrary partitioning operator might not be safe in that
649  * context. datumIsEqual() should be simple enough to be safe.
650  */
651  if (!datumIsEqual(b1->datums[i][j], b2->datums[i][j],
652  key->parttypbyval[j],
653  key->parttyplen[j]))
654  return false;
655  }
656 
657  if (b1->indexes[i] != b2->indexes[i])
658  return false;
659  }
660 
661  /* There are ndatums+1 indexes in case of range partitions */
662  if (key->strategy == PARTITION_STRATEGY_RANGE &&
663  b1->indexes[i] != b2->indexes[i])
664  return false;
665 
666  return true;
667 }
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:226
int16 * parttyplen
Definition: rel.h:71
#define PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:737
int i
void RelationBuildPartitionDesc ( Relation  relation)

Definition at line 158 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, SearchSysCache1, PartitionKeyData::strategy, PartitionBoundInfoData::strategy, PartitionBoundSpec::strategy, stringToNode(), SysCacheGetAttr(), TextDatumGetCString, upper(), PartitionBoundSpec::upperdatums, val, PartitionListValue::value, and value.

Referenced by RelationBuildDesc(), and RelationCacheInitializePhase3().

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

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

Definition at line 965 of file partition.c.

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

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

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