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

Go to the source code of this file.

Data Structures

struct  PartitionBoundInfoData
 
struct  PartitionListValue
 
struct  PartitionRangeBound
 

Macros

#define APPEND_REL_PARTITION_OIDS(rel, partoids, parents)
 

Typedefs

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

Enumerations

enum  RangeDatumContent { RANGE_DATUM_FINITE = 0, RANGE_DATUM_NEG_INF, RANGE_DATUM_POS_INF }
 

Functions

static int32 qsort_partition_list_value_cmp (const void *a, const void *b, void *arg)
 
static int32 qsort_partition_rbound_cmp (const void *a, const void *b, void *arg)
 
static Listget_qual_for_list (PartitionKey key, PartitionBoundSpec *spec)
 
static Listget_qual_for_range (PartitionKey key, PartitionBoundSpec *spec)
 
static Oid get_partition_operator (PartitionKey key, int col, StrategyNumber strategy, bool *need_relabel)
 
static Listgenerate_partition_qual (Relation rel)
 
static PartitionRangeBoundmake_one_range_bound (PartitionKey key, int index, List *datums, bool lower)
 
static int32 partition_rbound_cmp (PartitionKey key, Datum *datums1, RangeDatumContent *content1, bool lower1, PartitionRangeBound *b2)
 
static int32 partition_rbound_datum_cmp (PartitionKey key, Datum *rb_datums, RangeDatumContent *rb_content, Datum *tuple_datums)
 
static int32 partition_bound_cmp (PartitionKey key, PartitionBoundInfo boundinfo, int offset, void *probe, bool probe_is_bound)
 
static int partition_bound_bsearch (PartitionKey key, PartitionBoundInfo boundinfo, void *probe, bool probe_is_bound, bool *is_equal)
 
static void FormPartitionKeyDatum (PartitionDispatch pd, TupleTableSlot *slot, EState *estate, Datum *values, bool *isnull)
 
void RelationBuildPartitionDesc (Relation rel)
 
bool partition_bounds_equal (PartitionKey key, PartitionBoundInfo b1, PartitionBoundInfo b2)
 
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)
 

Macro Definition Documentation

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

Definition at line 978 of file partition.c.

Referenced by RelationGetPartitionDispatchInfo().

Typedef Documentation

Enumeration Type Documentation

Enumerator
RANGE_DATUM_FINITE 
RANGE_DATUM_NEG_INF 
RANGE_DATUM_POS_INF 

Definition at line 70 of file partition.c.

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

Function Documentation

void check_new_partition_bound ( char *  relname,
Relation  parent,
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
static void FormPartitionKeyDatum ( PartitionDispatch  pd,
TupleTableSlot slot,
EState estate,
Datum values,
bool isnull 
)
static

Definition at line 1612 of file partition.c.

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

Referenced by get_partition_for_tuple().

1617 {
1618  ListCell *partexpr_item;
1619  int i;
1620 
1621  if (pd->key->partexprs != NIL && pd->keystate == NIL)
1622  {
1623  /* Check caller has set up context correctly */
1624  Assert(estate != NULL &&
1625  GetPerTupleExprContext(estate)->ecxt_scantuple == slot);
1626 
1627  /* First time through, set up expression evaluation state */
1628  pd->keystate = (List *) ExecPrepareExpr((Expr *) pd->key->partexprs,
1629  estate);
1630  }
1631 
1632  partexpr_item = list_head(pd->keystate);
1633  for (i = 0; i < pd->key->partnatts; i++)
1634  {
1635  AttrNumber keycol = pd->key->partattrs[i];
1636  Datum datum;
1637  bool isNull;
1638 
1639  if (keycol != 0)
1640  {
1641  /* Plain column; get the value directly from the heap tuple */
1642  datum = slot_getattr(slot, keycol, &isNull);
1643  }
1644  else
1645  {
1646  /* Expression; need to evaluate it */
1647  if (partexpr_item == NULL)
1648  elog(ERROR, "wrong number of partition key expressions");
1649  datum = ExecEvalExprSwitchContext((ExprState *) lfirst(partexpr_item),
1650  GetPerTupleExprContext(estate),
1651  &isNull);
1652  partexpr_item = lnext(partexpr_item);
1653  }
1654  values[i] = datum;
1655  isnull[i] = isNull;
1656  }
1657 
1658  if (partexpr_item != NULL)
1659  elog(ERROR, "wrong number of partition key expressions");
1660 }
#define NIL
Definition: pg_list.h:69
ExprState * ExecPrepareExpr(Expr *node, EState *estate)
Definition: execQual.c:5004
List * partexprs
Definition: rel.h:58
Datum ExecEvalExprSwitchContext(ExprState *expression, ExprContext *econtext, bool *isNull)
Definition: execQual.c:4219
#define GetPerTupleExprContext(estate)
Definition: executor.h:338
#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
AttrNumber * partattrs
Definition: rel.h:56
uintptr_t Datum
Definition: postgres.h:374
int16 partnatts
Definition: rel.h:55
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:670
#define lfirst(lc)
Definition: pg_list.h:106
static Datum values[MAXATTR]
Definition: bootstrap.c:162
int i
Datum slot_getattr(TupleTableSlot *slot, int attnum, bool *isnull)
Definition: heaptuple.c:1143
#define elog
Definition: elog.h:219
Definition: pg_list.h:45
int16 AttrNumber
Definition: attnum.h:21
PartitionKey key
Definition: partition.h:63
static List * generate_partition_qual ( Relation  rel)
static

Definition at line 1531 of file partition.c.

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

Referenced by RelationGetPartitionQual().

1532 {
1533  HeapTuple tuple;
1534  MemoryContext oldcxt;
1535  Datum boundDatum;
1536  bool isnull;
1537  Node *bound;
1538  List *my_qual = NIL,
1539  *result = NIL;
1540  Relation parent;
1541 
1542  /* Guard against stack overflow due to overly deep partition tree */
1544 
1545  /* Quick copy */
1546  if (rel->rd_partcheck != NIL)
1547  return copyObject(rel->rd_partcheck);
1548 
1549  /* Grab at least an AccessShareLock on the parent table */
1551  AccessShareLock);
1552 
1553  /* Get pg_class.relpartbound */
1554  tuple = SearchSysCache1(RELOID, RelationGetRelid(rel));
1555  if (!HeapTupleIsValid(tuple))
1556  elog(ERROR, "cache lookup failed for relation %u",
1557  RelationGetRelid(rel));
1558 
1559  boundDatum = SysCacheGetAttr(RELOID, tuple,
1561  &isnull);
1562  if (isnull) /* should not happen */
1563  elog(ERROR, "relation \"%s\" has relpartbound = null",
1565  bound = stringToNode(TextDatumGetCString(boundDatum));
1566  ReleaseSysCache(tuple);
1567 
1568  my_qual = get_qual_from_partbound(rel, parent, bound);
1569 
1570  /* Add the parent's quals to the list (if any) */
1571  if (parent->rd_rel->relispartition)
1572  result = list_concat(generate_partition_qual(parent), my_qual);
1573  else
1574  result = my_qual;
1575 
1576  /*
1577  * Change Vars to have partition's attnos instead of the parent's. We do
1578  * this after we concatenate the parent's quals, because we want every Var
1579  * in it to bear this relation's attnos. It's safe to assume varno = 1
1580  * here.
1581  */
1582  result = map_partition_varattnos(result, 1, rel, parent);
1583 
1584  /* Save a copy in the relcache */
1586  rel->rd_partcheck = copyObject(result);
1587  MemoryContextSwitchTo(oldcxt);
1588 
1589  /* Keep the parent locked until commit */
1590  heap_close(parent, NoLock);
1591 
1592  return result;
1593 }
#define NIL
Definition: pg_list.h:69
void * stringToNode(char *str)
Definition: read.c:38
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define AccessShareLock
Definition: lockdefs.h:36
Definition: nodes.h:508
List * list_concat(List *list1, List *list2)
Definition: list.c:321
#define heap_close(r, l)
Definition: heapam.h:97
Form_pg_class rd_rel
Definition: rel.h:113
#define SearchSysCache1(cacheId, key1)
Definition: syscache.h:149
void * copyObject(const void *from)
Definition: copyfuncs.c:4475
#define ERROR
Definition: elog.h:43
Oid get_partition_parent(Oid relid)
Definition: partition.c:858
#define NoLock
Definition: lockdefs.h:34
void check_stack_depth(void)
Definition: postgres.c:3096
#define RelationGetRelationName(relation)
Definition: rel.h:433
#define TextDatumGetCString(d)
Definition: builtins.h:91
uintptr_t Datum
Definition: postgres.h:374
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1083
List * get_qual_from_partbound(Relation rel, Relation parent, Node *bound)
Definition: partition.c:899
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1245
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1287
#define Anum_pg_class_relpartbound
Definition: pg_class.h:135
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
static List * generate_partition_qual(Relation rel)
Definition: partition.c:1531
#define elog
Definition: elog.h:219
Definition: pg_list.h:45
#define RelationGetRelid(relation)
Definition: rel.h:413
List * rd_partcheck
Definition: rel.h:131
List * map_partition_varattnos(List *expr, int target_varno, Relation partrel, Relation parent)
Definition: partition.c:935
MemoryContext CacheMemoryContext
Definition: mcxt.c:46
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
static Oid get_partition_operator ( PartitionKey  key,
int  col,
StrategyNumber  strategy,
bool need_relabel 
)
static

Definition at line 1476 of file partition.c.

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

Referenced by get_qual_for_list(), and get_qual_for_range().

1478 {
1479  Oid operoid;
1480 
1481  /*
1482  * First check if there exists an operator of the given strategy, with
1483  * this column's type as both its lefttype and righttype, in the
1484  * partitioning operator family specified for the column.
1485  */
1486  operoid = get_opfamily_member(key->partopfamily[col],
1487  key->parttypid[col],
1488  key->parttypid[col],
1489  strategy);
1490 
1491  /*
1492  * If one doesn't exist, we must resort to using an operator in the same
1493  * opreator family but with the operator class declared input type. It is
1494  * OK to do so, because the column's type is known to be binary-coercible
1495  * with the operator class input type (otherwise, the operator class in
1496  * question would not have been accepted as the partitioning operator
1497  * class). We must however inform the caller to wrap the non-Const
1498  * expression with a RelabelType node to denote the implicit coercion. It
1499  * ensures that the resulting expression structurally matches similarly
1500  * processed expressions within the optimizer.
1501  */
1502  if (!OidIsValid(operoid))
1503  {
1504  operoid = get_opfamily_member(key->partopfamily[col],
1505  key->partopcintype[col],
1506  key->partopcintype[col],
1507  strategy);
1508  *need_relabel = true;
1509  }
1510  else
1511  *need_relabel = false;
1512 
1513  if (!OidIsValid(operoid))
1514  elog(ERROR, "could not find operator for partitioning");
1515 
1516  return operoid;
1517 }
Oid * partopfamily
Definition: rel.h:61
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:533
#define ERROR
Definition: elog.h:43
Oid get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype, int16 strategy)
Definition: lsyscache.c:163
Oid * parttypid
Definition: rel.h:69
Oid * partopcintype
Definition: rel.h:62
#define elog
Definition: elog.h:219
Oid get_partition_parent ( Oid  relid)

Definition at line 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
static List * get_qual_for_list ( PartitionKey  key,
PartitionBoundSpec spec 
)
static

Definition at line 1157 of file partition.c.

References NullTest::arg, NullTest::argisrow, ScalarArrayOpExpr::args, ArrayExpr::array_collid, ArrayExpr::array_typeid, BTEqualStrategyNumber, COERCE_EXPLICIT_CAST, Const::constisnull, copyObject(), ArrayExpr::element_typeid, ArrayExpr::elements, get_array_type(), get_opcode(), get_partition_operator(), ScalarArrayOpExpr::inputcollid, IS_NOT_NULL, IS_NULL, lfirst, linitial, list_delete_cell(), list_head(), list_make1, list_make2, PartitionBoundSpec::listdatums, lnext, ScalarArrayOpExpr::location, ArrayExpr::location, NullTest::location, makeBoolExpr(), makeNode, makeRelabelType(), makeVar(), ArrayExpr::multidims, next, NULL, NullTest::nulltesttype, ScalarArrayOpExpr::opfuncid, ScalarArrayOpExpr::opno, OR_EXPR, PartitionKeyData::partattrs, PartitionKeyData::partcollation, PartitionKeyData::partexprs, PartitionKeyData::partopcintype, PartitionKeyData::parttypcoll, PartitionKeyData::parttypid, PartitionKeyData::parttypmod, type_is_array, ScalarArrayOpExpr::useOr, and val.

Referenced by get_qual_from_partbound().

1158 {
1159  List *result;
1160  ArrayExpr *arr;
1161  ScalarArrayOpExpr *opexpr;
1162  ListCell *cell,
1163  *prev,
1164  *next;
1165  Node *keyCol;
1166  Oid operoid;
1167  bool need_relabel,
1168  list_has_null = false;
1169  NullTest *nulltest1 = NULL,
1170  *nulltest2 = NULL;
1171 
1172  /* Left operand is either a simple Var or arbitrary expression */
1173  if (key->partattrs[0] != 0)
1174  keyCol = (Node *) makeVar(1,
1175  key->partattrs[0],
1176  key->parttypid[0],
1177  key->parttypmod[0],
1178  key->parttypcoll[0],
1179  0);
1180  else
1181  keyCol = (Node *) copyObject(linitial(key->partexprs));
1182 
1183  /*
1184  * We must remove any NULL value in the list; we handle it separately
1185  * below.
1186  */
1187  prev = NULL;
1188  for (cell = list_head(spec->listdatums); cell; cell = next)
1189  {
1190  Const *val = (Const *) lfirst(cell);
1191 
1192  next = lnext(cell);
1193 
1194  if (val->constisnull)
1195  {
1196  list_has_null = true;
1197  spec->listdatums = list_delete_cell(spec->listdatums,
1198  cell, prev);
1199  }
1200  else
1201  prev = cell;
1202  }
1203 
1204  if (!list_has_null)
1205  {
1206  /*
1207  * Gin up a col IS NOT NULL test that will be AND'd with other
1208  * expressions
1209  */
1210  nulltest1 = makeNode(NullTest);
1211  nulltest1->arg = (Expr *) keyCol;
1212  nulltest1->nulltesttype = IS_NOT_NULL;
1213  nulltest1->argisrow = false;
1214  nulltest1->location = -1;
1215  }
1216  else
1217  {
1218  /*
1219  * Gin up a col IS NULL test that will be OR'd with other expressions
1220  */
1221  nulltest2 = makeNode(NullTest);
1222  nulltest2->arg = (Expr *) keyCol;
1223  nulltest2->nulltesttype = IS_NULL;
1224  nulltest2->argisrow = false;
1225  nulltest2->location = -1;
1226  }
1227 
1228  /* Right operand is an ArrayExpr containing this partition's values */
1229  arr = makeNode(ArrayExpr);
1230  arr->array_typeid = !type_is_array(key->parttypid[0])
1231  ? get_array_type(key->parttypid[0])
1232  : key->parttypid[0];
1233  arr->array_collid = key->parttypcoll[0];
1234  arr->element_typeid = key->parttypid[0];
1235  arr->elements = spec->listdatums;
1236  arr->multidims = false;
1237  arr->location = -1;
1238 
1239  /* Get the correct btree equality operator */
1241  &need_relabel);
1242  if (need_relabel || key->partcollation[0] != key->parttypcoll[0])
1243  keyCol = (Node *) makeRelabelType((Expr *) keyCol,
1244  key->partopcintype[0],
1245  -1,
1246  key->partcollation[0],
1248 
1249  /* Build leftop = ANY (rightop) */
1250  opexpr = makeNode(ScalarArrayOpExpr);
1251  opexpr->opno = operoid;
1252  opexpr->opfuncid = get_opcode(operoid);
1253  opexpr->useOr = true;
1254  opexpr->inputcollid = key->partcollation[0];
1255  opexpr->args = list_make2(keyCol, arr);
1256  opexpr->location = -1;
1257 
1258  if (nulltest1)
1259  result = list_make2(nulltest1, opexpr);
1260  else if (nulltest2)
1261  {
1262  Expr *or;
1263 
1264  or = makeBoolExpr(OR_EXPR, list_make2(nulltest2, opexpr), -1);
1265  result = list_make1(or);
1266  }
1267  else
1268  result = list_make1(opexpr);
1269 
1270  return result;
1271 }
#define list_make2(x1, x2)
Definition: pg_list.h:134
bool multidims
Definition: primnodes.h:932
static int32 next
Definition: blutils.c:210
Oid get_array_type(Oid typid)
Definition: lsyscache.c:2480
static Oid get_partition_operator(PartitionKey key, int col, StrategyNumber strategy, bool *need_relabel)
Definition: partition.c:1476
Definition: nodes.h:508
Oid array_typeid
Definition: primnodes.h:928
List * partexprs
Definition: rel.h:58
unsigned int Oid
Definition: postgres_ext.h:31
Expr * makeBoolExpr(BoolExprType boolop, List *args, int location)
Definition: makefuncs.c:366
void * copyObject(const void *from)
Definition: copyfuncs.c:4475
#define list_make1(x1)
Definition: pg_list.h:133
Oid * parttypcoll
Definition: rel.h:74
#define linitial(l)
Definition: pg_list.h:110
Expr * arg
Definition: primnodes.h:1156
RelabelType * makeRelabelType(Expr *arg, Oid rtype, int32 rtypmod, Oid rcollid, CoercionForm rformat)
Definition: makefuncs.c:399
static ListCell * list_head(const List *l)
Definition: pg_list.h:77
List * elements
Definition: primnodes.h:931
#define lnext(lc)
Definition: pg_list.h:105
Var * makeVar(Index varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:67
Oid * parttypid
Definition: rel.h:69
List * list_delete_cell(List *list, ListCell *cell, ListCell *prev)
Definition: list.c:528
Oid * partcollation
Definition: rel.h:66
int location
Definition: primnodes.h:933
AttrNumber * partattrs
Definition: rel.h:56
NullTestType nulltesttype
Definition: primnodes.h:1157
int32 * parttypmod
Definition: rel.h:70
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1062
#define makeNode(_type_)
Definition: nodes.h:556
#define NULL
Definition: c.h:226
#define lfirst(lc)
Definition: pg_list.h:106
Oid array_collid
Definition: primnodes.h:929
int location
Definition: primnodes.h:1159
#define type_is_array(typid)
Definition: lsyscache.h:163
Oid element_typeid
Definition: primnodes.h:930
Oid * partopcintype
Definition: rel.h:62
bool argisrow
Definition: primnodes.h:1158
Definition: pg_list.h:45
long val
Definition: informix.c:689
bool constisnull
Definition: primnodes.h:175
#define BTEqualStrategyNumber
Definition: stratnum.h:31
static List * get_qual_for_range ( PartitionKey  key,
PartitionBoundSpec spec 
)
static

Definition at line 1279 of file partition.c.

References NullTest::arg, NullTest::argisrow, BOOLOID, BTEqualStrategyNumber, BTGreaterEqualStrategyNumber, BTLessStrategyNumber, COERCE_EXPLICIT_CAST, copyObject(), CreateExecutorState(), DatumGetBool, elog, ERROR, EState::es_query_cxt, ExecEvalExprSwitchContext(), ExecInitExpr(), fix_opfuncids(), forboth, FreeExecutorState(), get_partition_operator(), GetPerTupleExprContext, i, PartitionRangeDatum::infinite, InvalidOid, IS_NOT_NULL, IsA, lappend(), lfirst, list_head(), lnext, NullTest::location, PartitionBoundSpec::lowerdatums, make_opclause(), makeNode, makeRelabelType(), makeVar(), MemoryContextSwitchTo(), NIL, NULL, NullTest::nulltesttype, PartitionKeyData::partattrs, PartitionKeyData::partcollation, PartitionKeyData::partexprs, PartitionKeyData::partnatts, PartitionKeyData::partopcintype, PartitionKeyData::parttypcoll, PartitionKeyData::parttypid, PartitionKeyData::parttypmod, PartitionBoundSpec::upperdatums, and PartitionRangeDatum::value.

Referenced by get_qual_from_partbound().

1280 {
1281  List *result = NIL;
1282  ListCell *cell1,
1283  *cell2,
1284  *partexprs_item;
1285  int i;
1286 
1287  /*
1288  * Iterate over columns of the key, emitting an OpExpr for each using the
1289  * corresponding lower and upper datums as constant operands.
1290  */
1291  i = 0;
1292  partexprs_item = list_head(key->partexprs);
1293  forboth(cell1, spec->lowerdatums, cell2, spec->upperdatums)
1294  {
1295  PartitionRangeDatum *ldatum = lfirst(cell1),
1296  *udatum = lfirst(cell2);
1297  Node *keyCol;
1298  Const *lower_val = NULL,
1299  *upper_val = NULL;
1300  EState *estate;
1301  MemoryContext oldcxt;
1302  Expr *test_expr;
1303  ExprState *test_exprstate;
1304  Datum test_result;
1305  bool isNull;
1306  bool need_relabel = false;
1307  Oid operoid;
1308  NullTest *nulltest;
1309 
1310  /* Left operand */
1311  if (key->partattrs[i] != 0)
1312  {
1313  keyCol = (Node *) makeVar(1,
1314  key->partattrs[i],
1315  key->parttypid[i],
1316  key->parttypmod[i],
1317  key->parttypcoll[i],
1318  0);
1319  }
1320  else
1321  {
1322  keyCol = (Node *) copyObject(lfirst(partexprs_item));
1323  partexprs_item = lnext(partexprs_item);
1324  }
1325 
1326  /*
1327  * Emit a IS NOT NULL expression for non-Var keys, because whereas
1328  * simple attributes are covered by NOT NULL constraints, expression
1329  * keys are still nullable which is not acceptable in case of range
1330  * partitioning.
1331  */
1332  if (!IsA(keyCol, Var))
1333  {
1334  nulltest = makeNode(NullTest);
1335  nulltest->arg = (Expr *) keyCol;
1336  nulltest->nulltesttype = IS_NOT_NULL;
1337  nulltest->argisrow = false;
1338  nulltest->location = -1;
1339  result = lappend(result, nulltest);
1340  }
1341 
1342  /*
1343  * Stop at this column if either of lower or upper datum is infinite,
1344  * but do emit an OpExpr for the non-infinite datum.
1345  */
1346  if (!ldatum->infinite)
1347  lower_val = (Const *) ldatum->value;
1348  if (!udatum->infinite)
1349  upper_val = (Const *) udatum->value;
1350 
1351  /*
1352  * If lower_val and upper_val are both finite and happen to be equal,
1353  * emit only (keyCol = lower_val) for this column, because all rows in
1354  * this partition could only ever contain this value (ie, lower_val)
1355  * in the current partitioning column. We must consider further
1356  * columns because the above condition does not fully constrain the
1357  * rows of this partition.
1358  */
1359  if (lower_val && upper_val)
1360  {
1361  /* Get the correct btree equality operator for the test */
1363  &need_relabel);
1364 
1365  /* Create the test expression */
1366  estate = CreateExecutorState();
1367  oldcxt = MemoryContextSwitchTo(estate->es_query_cxt);
1368  test_expr = make_opclause(operoid,
1369  BOOLOID,
1370  false,
1371  (Expr *) lower_val,
1372  (Expr *) upper_val,
1373  InvalidOid,
1374  key->partcollation[i]);
1375  fix_opfuncids((Node *) test_expr);
1376  test_exprstate = ExecInitExpr(test_expr, NULL);
1377  test_result = ExecEvalExprSwitchContext(test_exprstate,
1378  GetPerTupleExprContext(estate),
1379  &isNull);
1380  MemoryContextSwitchTo(oldcxt);
1381  FreeExecutorState(estate);
1382 
1383  if (DatumGetBool(test_result))
1384  {
1385  /* This can never be, but it's better to make sure */
1386  if (i == key->partnatts - 1)
1387  elog(ERROR, "invalid range bound specification");
1388 
1389  if (need_relabel || key->partcollation[i] != key->parttypcoll[i])
1390  keyCol = (Node *) makeRelabelType((Expr *) keyCol,
1391  key->partopcintype[i],
1392  -1,
1393  key->partcollation[i],
1395  result = lappend(result,
1396  make_opclause(operoid,
1397  BOOLOID,
1398  false,
1399  (Expr *) keyCol,
1400  (Expr *) lower_val,
1401  InvalidOid,
1402  key->partcollation[i]));
1403 
1404  /* Go over to consider the next column. */
1405  i++;
1406  continue;
1407  }
1408  }
1409 
1410  /*
1411  * We can say here that lower_val != upper_val. Emit expressions
1412  * (keyCol >= lower_val) and (keyCol < upper_val), then stop.
1413  */
1414  if (lower_val)
1415  {
1416  operoid = get_partition_operator(key, i,
1418  &need_relabel);
1419 
1420  if (need_relabel || key->partcollation[i] != key->parttypcoll[i])
1421  keyCol = (Node *) makeRelabelType((Expr *) keyCol,
1422  key->partopcintype[i],
1423  -1,
1424  key->partcollation[i],
1426  result = lappend(result,
1427  make_opclause(operoid,
1428  BOOLOID,
1429  false,
1430  (Expr *) keyCol,
1431  (Expr *) lower_val,
1432  InvalidOid,
1433  key->partcollation[i]));
1434  }
1435 
1436  if (upper_val)
1437  {
1438  operoid = get_partition_operator(key, i,
1440  &need_relabel);
1441 
1442  if (need_relabel || key->partcollation[i] != key->parttypcoll[i])
1443  keyCol = (Node *) makeRelabelType((Expr *) keyCol,
1444  key->partopcintype[i],
1445  -1,
1446  key->partcollation[i],
1448 
1449  result = lappend(result,
1450  make_opclause(operoid,
1451  BOOLOID,
1452  false,
1453  (Expr *) keyCol,
1454  (Expr *) upper_val,
1455  InvalidOid,
1456  key->partcollation[i]));
1457  }
1458 
1459  /*
1460  * We can stop at this column, because we would not have checked the
1461  * next column when routing a given row into this partition.
1462  */
1463  break;
1464  }
1465 
1466  return result;
1467 }
#define NIL
Definition: pg_list.h:69
#define IsA(nodeptr, _type_)
Definition: nodes.h:559
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:174
void fix_opfuncids(Node *node)
Definition: nodeFuncs.c:1596
static Oid get_partition_operator(PartitionKey key, int col, StrategyNumber strategy, bool *need_relabel)
Definition: partition.c:1476
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
Definition: nodes.h:508
Expr * make_opclause(Oid opno, Oid opresulttype, bool opretset, Expr *leftop, Expr *rightop, Oid opcollid, Oid inputcollid)
Definition: clauses.c:171
List * partexprs
Definition: rel.h:58
unsigned int Oid
Definition: postgres_ext.h:31
Definition: primnodes.h:141
Datum ExecEvalExprSwitchContext(ExprState *expression, ExprContext *econtext, bool *isNull)
Definition: execQual.c:4219
void * copyObject(const void *from)
Definition: copyfuncs.c:4475
void FreeExecutorState(EState *estate)
Definition: execUtils.c:167
#define GetPerTupleExprContext(estate)
Definition: executor.h:338
ExprState * ExecInitExpr(Expr *node, PlanState *parent)
Definition: execQual.c:4266
MemoryContext es_query_cxt
Definition: execnodes.h:396
Oid * parttypcoll
Definition: rel.h:74
#define ERROR
Definition: elog.h:43
Expr * arg
Definition: primnodes.h:1156
RelabelType * makeRelabelType(Expr *arg, Oid rtype, int32 rtypmod, Oid rcollid, CoercionForm rformat)
Definition: makefuncs.c:399
#define DatumGetBool(X)
Definition: postgres.h:401
static ListCell * list_head(const List *l)
Definition: pg_list.h:77
#define lnext(lc)
Definition: pg_list.h:105
Var * makeVar(Index varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:67
Oid * parttypid
Definition: rel.h:69
EState * CreateExecutorState(void)
Definition: execUtils.c:72
List * lappend(List *list, void *datum)
Definition: list.c:128
Oid * partcollation
Definition: rel.h:66
AttrNumber * partattrs
Definition: rel.h:56
uintptr_t Datum
Definition: postgres.h:374
int16 partnatts
Definition: rel.h:55
NullTestType nulltesttype
Definition: primnodes.h:1157
int32 * parttypmod
Definition: rel.h:70
#define InvalidOid
Definition: postgres_ext.h:36
#define makeNode(_type_)
Definition: nodes.h:556
#define NULL
Definition: c.h:226
#define lfirst(lc)
Definition: pg_list.h:106
int location
Definition: primnodes.h:1159
#define BOOLOID
Definition: pg_type.h:288
Oid * partopcintype
Definition: rel.h:62
int i
bool argisrow
Definition: primnodes.h:1158
#define elog
Definition: elog.h:219
#define BTLessStrategyNumber
Definition: stratnum.h:29
Definition: pg_list.h:45
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define BTGreaterEqualStrategyNumber
Definition: stratnum.h:32
List* get_qual_from_partbound ( Relation  rel,
Relation  parent,
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
static PartitionRangeBound * make_one_range_bound ( PartitionKey  key,
int  index,
List datums,
bool  lower 
)
static

Definition at line 1818 of file partition.c.

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

Referenced by check_new_partition_bound(), and RelationBuildPartitionDesc().

1819 {
1820  PartitionRangeBound *bound;
1821  ListCell *cell;
1822  int i;
1823 
1824  bound = (PartitionRangeBound *) palloc0(sizeof(PartitionRangeBound));
1825  bound->index = index;
1826  bound->datums = (Datum *) palloc0(key->partnatts * sizeof(Datum));
1827  bound->content = (RangeDatumContent *) palloc0(key->partnatts *
1828  sizeof(RangeDatumContent));
1829  bound->lower = lower;
1830 
1831  i = 0;
1832  foreach(cell, datums)
1833  {
1834  PartitionRangeDatum *datum = lfirst(cell);
1835 
1836  /* What's contained in this range datum? */
1837  bound->content[i] = !datum->infinite
1841 
1842  if (bound->content[i] == RANGE_DATUM_FINITE)
1843  {
1844  Const *val = (Const *) datum->value;
1845 
1846  if (val->constisnull)
1847  elog(ERROR, "invalid range bound datum");
1848  bound->datums[i] = val->constvalue;
1849  }
1850 
1851  i++;
1852  }
1853 
1854  return bound;
1855 }
Datum constvalue
Definition: primnodes.h:174
Datum lower(PG_FUNCTION_ARGS)
Definition: oracle_compat.c:43
Definition: type.h:90
#define ERROR
Definition: elog.h:43
RangeDatumContent
Definition: partition.c:70
void * palloc0(Size size)
Definition: mcxt.c:920
uintptr_t Datum
Definition: postgres.h:374
int16 partnatts
Definition: rel.h:55
RangeDatumContent * content
Definition: partition.c:112
#define lfirst(lc)
Definition: pg_list.h:106
int i
#define elog
Definition: elog.h:219
long val
Definition: informix.c:689
bool constisnull
Definition: primnodes.h:175
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
static int partition_bound_bsearch ( PartitionKey  key,
PartitionBoundInfo  boundinfo,
void *  probe,
bool  probe_is_bound,
bool is_equal 
)
static

Definition at line 2023 of file partition.c.

References PartitionBoundInfoData::ndatums, and partition_bound_cmp().

Referenced by check_new_partition_bound(), and get_partition_for_tuple().

2025 {
2026  int lo,
2027  hi,
2028  mid;
2029 
2030  lo = -1;
2031  hi = boundinfo->ndatums - 1;
2032  while (lo < hi)
2033  {
2034  int32 cmpval;
2035 
2036  mid = (lo + hi + 1) / 2;
2037  cmpval = partition_bound_cmp(key, boundinfo, mid, probe,
2038  probe_is_bound);
2039  if (cmpval <= 0)
2040  {
2041  lo = mid;
2042  *is_equal = (cmpval == 0);
2043 
2044  if (*is_equal)
2045  break;
2046  }
2047  else
2048  hi = mid - 1;
2049  }
2050 
2051  return lo;
2052 }
signed int int32
Definition: c.h:253
static int32 partition_bound_cmp(PartitionKey key, PartitionBoundInfo boundinfo, int offset, void *probe, bool probe_is_bound)
Definition: partition.c:1962
static int32 partition_bound_cmp ( PartitionKey  key,
PartitionBoundInfo  boundinfo,
int  offset,
void *  probe,
bool  probe_is_bound 
)
static

Definition at line 1962 of file partition.c.

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

Referenced by partition_bound_bsearch().

1964 {
1965  Datum *bound_datums = boundinfo->datums[offset];
1966  int32 cmpval = -1;
1967 
1968  switch (key->strategy)
1969  {
1971  cmpval = DatumGetInt32(FunctionCall2Coll(&key->partsupfunc[0],
1972  key->partcollation[0],
1973  bound_datums[0],
1974  *(Datum *) probe));
1975  break;
1976 
1978  {
1979  RangeDatumContent *content = boundinfo->content[offset];
1980 
1981  if (probe_is_bound)
1982  {
1983  /*
1984  * We need to pass whether the existing bound is a lower
1985  * bound, so that two equal-valued lower and upper bounds
1986  * are not regarded equal.
1987  */
1988  bool lower = boundinfo->indexes[offset] < 0;
1989 
1990  cmpval = partition_rbound_cmp(key,
1991  bound_datums, content, lower,
1992  (PartitionRangeBound *) probe);
1993  }
1994  else
1995  cmpval = partition_rbound_datum_cmp(key,
1996  bound_datums, content,
1997  (Datum *) probe);
1998  break;
1999  }
2000 
2001  default:
2002  elog(ERROR, "unexpected partition strategy: %d",
2003  (int) key->strategy);
2004  }
2005 
2006  return cmpval;
2007 }
static int32 partition_rbound_datum_cmp(PartitionKey key, Datum *rb_datums, RangeDatumContent *rb_content, Datum *tuple_datums)
Definition: partition.c:1932
#define DatumGetInt32(X)
Definition: postgres.h:480
Datum lower(PG_FUNCTION_ARGS)
Definition: oracle_compat.c:43
FmgrInfo * partsupfunc
Definition: rel.h:63
char strategy
Definition: rel.h:54
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1306
signed int int32
Definition: c.h:253
#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
RangeDatumContent
Definition: partition.c:70
Oid * partcollation
Definition: rel.h:66
uintptr_t Datum
Definition: postgres.h:374
#define PARTITION_STRATEGY_LIST
Definition: parsenodes.h:736
#define PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:737
#define elog
Definition: elog.h:219
RangeDatumContent ** content
Definition: partition.c:83
bool partition_bounds_equal ( PartitionKey  key,
PartitionBoundInfo  b1,
PartitionBoundInfo  b2 
)

Definition at line 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
RangeDatumContent ** content
Definition: partition.c:83
static int32 partition_rbound_cmp ( PartitionKey  key,
Datum datums1,
RangeDatumContent content1,
bool  lower1,
PartitionRangeBound b2 
)
static

Definition at line 1875 of file partition.c.

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

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

1878 {
1879  int32 cmpval = 0; /* placate compiler */
1880  int i;
1881  Datum *datums2 = b2->datums;
1882  RangeDatumContent *content2 = b2->content;
1883  bool lower2 = b2->lower;
1884 
1885  for (i = 0; i < key->partnatts; i++)
1886  {
1887  /*
1888  * First, handle cases involving infinity, which don't require
1889  * invoking the comparison proc.
1890  */
1891  if (content1[i] != RANGE_DATUM_FINITE &&
1892  content2[i] != RANGE_DATUM_FINITE)
1893 
1894  /*
1895  * Both are infinity, so they are equal unless one is negative
1896  * infinity and other positive (or vice versa)
1897  */
1898  return content1[i] == content2[i] ? 0
1899  : (content1[i] < content2[i] ? -1 : 1);
1900  else if (content1[i] != RANGE_DATUM_FINITE)
1901  return content1[i] == RANGE_DATUM_NEG_INF ? -1 : 1;
1902  else if (content2[i] != RANGE_DATUM_FINITE)
1903  return content2[i] == RANGE_DATUM_NEG_INF ? 1 : -1;
1904 
1905  cmpval = DatumGetInt32(FunctionCall2Coll(&key->partsupfunc[i],
1906  key->partcollation[i],
1907  datums1[i],
1908  datums2[i]));
1909  if (cmpval != 0)
1910  break;
1911  }
1912 
1913  /*
1914  * If the comparison is anything other than equal, we're done. If they
1915  * compare equal though, we still have to consider whether the boundaries
1916  * are inclusive or exclusive. Exclusive one is considered smaller of the
1917  * two.
1918  */
1919  if (cmpval == 0 && lower1 != lower2)
1920  cmpval = lower1 ? 1 : -1;
1921 
1922  return cmpval;
1923 }
#define DatumGetInt32(X)
Definition: postgres.h:480
FmgrInfo * partsupfunc
Definition: rel.h:63
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1306
signed int int32
Definition: c.h:253
RangeDatumContent
Definition: partition.c:70
Oid * partcollation
Definition: rel.h:66
uintptr_t Datum
Definition: postgres.h:374
int16 partnatts
Definition: rel.h:55
RangeDatumContent * content
Definition: partition.c:112
int i
static int32 partition_rbound_datum_cmp ( PartitionKey  key,
Datum rb_datums,
RangeDatumContent rb_content,
Datum tuple_datums 
)
static

Definition at line 1932 of file partition.c.

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

Referenced by partition_bound_cmp().

1935 {
1936  int i;
1937  int32 cmpval = -1;
1938 
1939  for (i = 0; i < key->partnatts; i++)
1940  {
1941  if (rb_content[i] != RANGE_DATUM_FINITE)
1942  return rb_content[i] == RANGE_DATUM_NEG_INF ? -1 : 1;
1943 
1944  cmpval = DatumGetInt32(FunctionCall2Coll(&key->partsupfunc[i],
1945  key->partcollation[i],
1946  rb_datums[i],
1947  tuple_datums[i]));
1948  if (cmpval != 0)
1949  break;
1950  }
1951 
1952  return cmpval;
1953 }
#define DatumGetInt32(X)
Definition: postgres.h:480
FmgrInfo * partsupfunc
Definition: rel.h:63
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1306
signed int int32
Definition: c.h:253
Oid * partcollation
Definition: rel.h:66
int16 partnatts
Definition: rel.h:55
int i
static int32 qsort_partition_list_value_cmp ( const void *  a,
const void *  b,
void *  arg 
)
static

Definition at line 1799 of file partition.c.

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

Referenced by RelationBuildPartitionDesc().

1800 {
1801  Datum val1 = (*(const PartitionListValue **) a)->value,
1802  val2 = (*(const PartitionListValue **) b)->value;
1803  PartitionKey key = (PartitionKey) arg;
1804 
1806  key->partcollation[0],
1807  val1, val2));
1808 }
#define DatumGetInt32(X)
Definition: postgres.h:480
FmgrInfo * partsupfunc
Definition: rel.h:63
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1306
Oid * partcollation
Definition: rel.h:66
uintptr_t Datum
Definition: postgres.h:374
struct PartitionKeyData * PartitionKey
Definition: rel.h:77
void * arg
static int32 qsort_partition_rbound_cmp ( const void *  a,
const void *  b,
void *  arg 
)
static

Definition at line 1859 of file partition.c.

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

Referenced by RelationBuildPartitionDesc().

1860 {
1861  PartitionRangeBound *b1 = (*(PartitionRangeBound *const *) a);
1862  PartitionRangeBound *b2 = (*(PartitionRangeBound *const *) b);
1863  PartitionKey key = (PartitionKey) arg;
1864 
1865  return partition_rbound_cmp(key, b1->datums, b1->content, b1->lower, b2);
1866 }
static int32 partition_rbound_cmp(PartitionKey key, Datum *datums1, RangeDatumContent *content1, bool lower1, PartitionRangeBound *b2)
Definition: partition.c:1875
RangeDatumContent * content
Definition: partition.c:112
struct PartitionKeyData * PartitionKey
Definition: rel.h:77
void * arg
void RelationBuildPartitionDesc ( Relation  rel)

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
struct PartitionDescData * rd_partdesc
Definition: rel.h:130
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
MemoryContext rd_pdcxt
Definition: rel.h:129
#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