PostgreSQL Source Code  git master
execPartition.c File Reference
#include "postgres.h"
#include "access/table.h"
#include "access/tableam.h"
#include "catalog/partition.h"
#include "catalog/pg_inherits.h"
#include "catalog/pg_type.h"
#include "executor/execPartition.h"
#include "executor/executor.h"
#include "foreign/fdwapi.h"
#include "mb/pg_wchar.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "partitioning/partbounds.h"
#include "partitioning/partdesc.h"
#include "partitioning/partprune.h"
#include "rewrite/rewriteManip.h"
#include "utils/acl.h"
#include "utils/lsyscache.h"
#include "utils/partcache.h"
#include "utils/rls.h"
#include "utils/ruleutils.h"
Include dependency graph for execPartition.c:

Go to the source code of this file.

Data Structures

struct  PartitionTupleRouting
 
struct  PartitionDispatchData
 
struct  SubplanResultRelHashElem
 

Typedefs

typedef struct PartitionDispatchData PartitionDispatchData
 
typedef struct SubplanResultRelHashElem SubplanResultRelHashElem
 

Functions

static void ExecHashSubPlanResultRelsByOid (ModifyTableState *mtstate, PartitionTupleRouting *proute)
 
static ResultRelInfoExecInitPartitionInfo (ModifyTableState *mtstate, EState *estate, PartitionTupleRouting *proute, PartitionDispatch dispatch, ResultRelInfo *rootResultRelInfo, int partidx)
 
static void ExecInitRoutingInfo (ModifyTableState *mtstate, EState *estate, PartitionTupleRouting *proute, PartitionDispatch dispatch, ResultRelInfo *partRelInfo, int partidx)
 
static PartitionDispatch ExecInitPartitionDispatchInfo (EState *estate, PartitionTupleRouting *proute, Oid partoid, PartitionDispatch parent_pd, int partidx)
 
static void FormPartitionKeyDatum (PartitionDispatch pd, TupleTableSlot *slot, EState *estate, Datum *values, bool *isnull)
 
static int get_partition_for_tuple (PartitionDispatch pd, Datum *values, bool *isnull)
 
static char * ExecBuildSlotPartitionKeyDescription (Relation rel, Datum *values, bool *isnull, int maxfieldlen)
 
static Listadjust_partition_tlist (List *tlist, TupleConversionMap *map)
 
static void ExecInitPruningContext (PartitionPruneContext *context, List *pruning_steps, PartitionDesc partdesc, PartitionKey partkey, PlanState *planstate)
 
static void find_matching_subplans_recurse (PartitionPruningData *prunedata, PartitionedRelPruningData *pprune, bool initial_prune, Bitmapset **validsubplans)
 
PartitionTupleRoutingExecSetupPartitionTupleRouting (EState *estate, ModifyTableState *mtstate, Relation rel)
 
ResultRelInfoExecFindPartition (ModifyTableState *mtstate, ResultRelInfo *rootResultRelInfo, PartitionTupleRouting *proute, TupleTableSlot *slot, EState *estate)
 
void ExecCleanupTupleRouting (ModifyTableState *mtstate, PartitionTupleRouting *proute)
 
PartitionPruneStateExecCreatePartitionPruneState (PlanState *planstate, PartitionPruneInfo *partitionpruneinfo)
 
BitmapsetExecFindInitialMatchingSubPlans (PartitionPruneState *prunestate, int nsubplans)
 
BitmapsetExecFindMatchingSubPlans (PartitionPruneState *prunestate)
 

Typedef Documentation

◆ PartitionDispatchData

◆ SubplanResultRelHashElem

Function Documentation

◆ adjust_partition_tlist()

static List * adjust_partition_tlist ( List tlist,
TupleConversionMap map 
)
static

Definition at line 1500 of file execPartition.c.

References Assert, AttrMap::attnums, TupleConversionMap::attrMap, InvalidAttrNumber, InvalidOid, lappend(), list_nth(), makeConst(), makeTargetEntry(), AttrMap::maplen, NameStr, TupleDescData::natts, NIL, TupleConversionMap::outdesc, pstrdup(), TargetEntry::resno, and TupleDescAttr.

Referenced by ExecInitPartitionInfo().

1501 {
1502  List *new_tlist = NIL;
1503  TupleDesc tupdesc = map->outdesc;
1504  AttrMap *attrMap = map->attrMap;
1505  AttrNumber attrno;
1506 
1507  Assert(tupdesc->natts == attrMap->maplen);
1508  for (attrno = 1; attrno <= tupdesc->natts; attrno++)
1509  {
1510  Form_pg_attribute att_tup = TupleDescAttr(tupdesc, attrno - 1);
1511  TargetEntry *tle;
1512 
1513  if (attrMap->attnums[attrno - 1] != InvalidAttrNumber)
1514  {
1515  Assert(!att_tup->attisdropped);
1516 
1517  /*
1518  * Use the corresponding entry from the parent's tlist, adjusting
1519  * the resno the match the partition's attno.
1520  */
1521  tle = (TargetEntry *) list_nth(tlist, attrMap->attnums[attrno - 1] - 1);
1522  tle->resno = attrno;
1523  }
1524  else
1525  {
1526  Const *expr;
1527 
1528  /*
1529  * For a dropped attribute in the partition, generate a dummy
1530  * entry with resno matching the partition's attno.
1531  */
1532  Assert(att_tup->attisdropped);
1533  expr = makeConst(INT4OID,
1534  -1,
1535  InvalidOid,
1536  sizeof(int32),
1537  (Datum) 0,
1538  true, /* isnull */
1539  true /* byval */ );
1540  tle = makeTargetEntry((Expr *) expr,
1541  attrno,
1542  pstrdup(NameStr(att_tup->attname)),
1543  false);
1544  }
1545 
1546  new_tlist = lappend(new_tlist, tle);
1547  }
1548 
1549  return new_tlist;
1550 }
#define NIL
Definition: pg_list.h:65
TupleDesc outdesc
Definition: tupconvert.h:26
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
char * pstrdup(const char *in)
Definition: mcxt.c:1187
int maplen
Definition: attmap.h:37
Const * makeConst(Oid consttype, int32 consttypmod, Oid constcollid, int constlen, Datum constvalue, bool constisnull, bool constbyval)
Definition: makefuncs.c:299
signed int int32
Definition: c.h:417
Definition: attmap.h:34
static void * list_nth(const List *list, int n)
Definition: pg_list.h:266
AttrNumber resno
Definition: primnodes.h:1423
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:193
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:238
AttrMap * attrMap
Definition: tupconvert.h:27
List * lappend(List *list, void *datum)
Definition: list.c:321
uintptr_t Datum
Definition: postgres.h:367
#define InvalidOid
Definition: postgres_ext.h:36
#define Assert(condition)
Definition: c.h:800
AttrNumber * attnums
Definition: attmap.h:36
#define InvalidAttrNumber
Definition: attnum.h:23
#define NameStr(name)
Definition: c.h:677
Definition: pg_list.h:50
int16 AttrNumber
Definition: attnum.h:21

◆ ExecBuildSlotPartitionKeyDescription()

static char * ExecBuildSlotPartitionKeyDescription ( Relation  rel,
Datum values,
bool isnull,
int  maxfieldlen 
)
static

Definition at line 1404 of file execPartition.c.

References ACL_SELECT, ACLCHECK_OK, appendBinaryStringInfo(), appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), attnum, buf, check_enable_rls(), StringInfoData::data, get_partition_col_attnum(), get_partition_col_typid(), get_partition_natts(), getTypeOutputInfo(), GetUserId(), i, initStringInfo(), InvalidAttrNumber, InvalidOid, sort-test::key, OidOutputFunctionCall(), pg_attribute_aclcheck(), pg_class_aclcheck(), pg_get_partkeydef_columns(), pg_mbcliplen(), RelationGetPartitionKey(), RelationGetRelid, RLS_ENABLED, and val.

Referenced by ExecFindPartition().

1408 {
1411  int partnatts = get_partition_natts(key);
1412  int i;
1413  Oid relid = RelationGetRelid(rel);
1414  AclResult aclresult;
1415 
1416  if (check_enable_rls(relid, InvalidOid, true) == RLS_ENABLED)
1417  return NULL;
1418 
1419  /* If the user has table-level access, just go build the description. */
1420  aclresult = pg_class_aclcheck(relid, GetUserId(), ACL_SELECT);
1421  if (aclresult != ACLCHECK_OK)
1422  {
1423  /*
1424  * Step through the columns of the partition key and make sure the
1425  * user has SELECT rights on all of them.
1426  */
1427  for (i = 0; i < partnatts; i++)
1428  {
1430 
1431  /*
1432  * If this partition key column is an expression, we return no
1433  * detail rather than try to figure out what column(s) the
1434  * expression includes and if the user has SELECT rights on them.
1435  */
1436  if (attnum == InvalidAttrNumber ||
1437  pg_attribute_aclcheck(relid, attnum, GetUserId(),
1438  ACL_SELECT) != ACLCHECK_OK)
1439  return NULL;
1440  }
1441  }
1442 
1443  initStringInfo(&buf);
1444  appendStringInfo(&buf, "(%s) = (",
1445  pg_get_partkeydef_columns(relid, true));
1446 
1447  for (i = 0; i < partnatts; i++)
1448  {
1449  char *val;
1450  int vallen;
1451 
1452  if (isnull[i])
1453  val = "null";
1454  else
1455  {
1456  Oid foutoid;
1457  bool typisvarlena;
1458 
1460  &foutoid, &typisvarlena);
1461  val = OidOutputFunctionCall(foutoid, values[i]);
1462  }
1463 
1464  if (i > 0)
1465  appendStringInfoString(&buf, ", ");
1466 
1467  /* truncate if needed */
1468  vallen = strlen(val);
1469  if (vallen <= maxfieldlen)
1470  appendBinaryStringInfo(&buf, val, vallen);
1471  else
1472  {
1473  vallen = pg_mbcliplen(val, vallen, maxfieldlen);
1474  appendBinaryStringInfo(&buf, val, vallen);
1475  appendStringInfoString(&buf, "...");
1476  }
1477  }
1478 
1479  appendStringInfoChar(&buf, ')');
1480 
1481  return buf.data;
1482 }
char * pg_get_partkeydef_columns(Oid relid, bool pretty)
Definition: ruleutils.c:1661
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
Definition: lsyscache.c:2789
AclResult pg_attribute_aclcheck(Oid table_oid, AttrNumber attnum, Oid roleid, AclMode mode)
Definition: aclchk.c:4449
Oid GetUserId(void)
Definition: miscinit.c:476
static Oid get_partition_col_typid(PartitionKey key, int col)
Definition: partcache.h:85
static int get_partition_natts(PartitionKey key)
Definition: partcache.h:64
PartitionKey RelationGetPartitionKey(Relation rel)
Definition: partcache.c:54
unsigned int Oid
Definition: postgres_ext.h:31
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:91
int pg_mbcliplen(const char *mbstr, int len, int limit)
Definition: mbutils.c:967
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:176
static char * buf
Definition: pg_test_fsync.c:68
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:188
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59
static int16 get_partition_col_attnum(PartitionKey key, int col)
Definition: partcache.h:79
AclResult
Definition: acl.h:177
#define ACL_SELECT
Definition: parsenodes.h:75
#define InvalidOid
Definition: postgres_ext.h:36
int16 attnum
Definition: pg_attribute.h:79
int check_enable_rls(Oid relid, Oid checkAsUser, bool noError)
Definition: rls.c:52
#define InvalidAttrNumber
Definition: attnum.h:23
AclResult pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4563
static Datum values[MAXATTR]
Definition: bootstrap.c:165
char * OidOutputFunctionCall(Oid functionId, Datum val)
Definition: fmgr.c:1657
int i
int16 AttrNumber
Definition: attnum.h:21
#define RelationGetRelid(relation)
Definition: rel.h:457
void appendBinaryStringInfo(StringInfo str, const char *data, int datalen)
Definition: stringinfo.c:227
long val
Definition: informix.c:664

◆ ExecCleanupTupleRouting()

void ExecCleanupTupleRouting ( ModifyTableState mtstate,
PartitionTupleRouting proute 
)

Definition at line 1168 of file execPartition.c.

References FdwRoutine::EndForeignInsert, ExecCloseIndices(), ExecDropSingleTupleTableSlot(), HASH_FIND, hash_search(), i, NoLock, PartitionTupleRouting::num_dispatch, PartitionTupleRouting::num_partitions, PartitionTupleRouting::partition_dispatch_info, PartitionTupleRouting::partitions, ModifyTableState::ps, RelationGetRelid, PartitionDispatchData::reldesc, ResultRelInfo::ri_FdwRoutine, ResultRelInfo::ri_RelationDesc, PlanState::state, PartitionTupleRouting::subplan_resultrel_htab, table_close(), and PartitionDispatchData::tupslot.

Referenced by apply_handle_tuple_routing(), CopyFrom(), and ExecEndModifyTable().

1170 {
1171  HTAB *htab = proute->subplan_resultrel_htab;
1172  int i;
1173 
1174  /*
1175  * Remember, proute->partition_dispatch_info[0] corresponds to the root
1176  * partitioned table, which we must not try to close, because it is the
1177  * main target table of the query that will be closed by callers such as
1178  * ExecEndPlan() or DoCopy(). Also, tupslot is NULL for the root
1179  * partitioned table.
1180  */
1181  for (i = 1; i < proute->num_dispatch; i++)
1182  {
1184 
1185  table_close(pd->reldesc, NoLock);
1186 
1187  if (pd->tupslot)
1189  }
1190 
1191  for (i = 0; i < proute->num_partitions; i++)
1192  {
1193  ResultRelInfo *resultRelInfo = proute->partitions[i];
1194 
1195  /* Allow any FDWs to shut down */
1196  if (resultRelInfo->ri_FdwRoutine != NULL &&
1197  resultRelInfo->ri_FdwRoutine->EndForeignInsert != NULL)
1198  resultRelInfo->ri_FdwRoutine->EndForeignInsert(mtstate->ps.state,
1199  resultRelInfo);
1200 
1201  /*
1202  * Check if this result rel is one belonging to the node's subplans,
1203  * if so, let ExecEndPlan() clean it up.
1204  */
1205  if (htab)
1206  {
1207  Oid partoid;
1208  bool found;
1209 
1210  partoid = RelationGetRelid(resultRelInfo->ri_RelationDesc);
1211 
1212  (void) hash_search(htab, &partoid, HASH_FIND, &found);
1213  if (found)
1214  continue;
1215  }
1216 
1217  ExecCloseIndices(resultRelInfo);
1218  table_close(resultRelInfo->ri_RelationDesc, NoLock);
1219  }
1220 }
Relation ri_RelationDesc
Definition: execnodes.h:412
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:919
EState * state
Definition: execnodes.h:930
unsigned int Oid
Definition: postgres_ext.h:31
ResultRelInfo ** partitions
Definition: dynahash.c:218
PlanState ps
Definition: execnodes.h:1148
#define NoLock
Definition: lockdefs.h:34
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:1224
struct FdwRoutine * ri_FdwRoutine
Definition: execnodes.h:441
PartitionDispatch * partition_dispatch_info
Definition: execPartition.c:96
TupleTableSlot * tupslot
int i
#define RelationGetRelid(relation)
Definition: rel.h:457
void ExecCloseIndices(ResultRelInfo *resultRelInfo)
Definition: execIndexing.c:226
EndForeignInsert_function EndForeignInsert
Definition: fdwapi.h:216

◆ ExecCreatePartitionPruneState()

PartitionPruneState* ExecCreatePartitionPruneState ( PlanState planstate,
PartitionPruneInfo partitionpruneinfo 
)

Definition at line 1623 of file execPartition.c.

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, Assert, bms_add_members(), bms_copy(), CreatePartitionDirectory(), CurrentMemoryContext, PartitionPruneState::do_exec_prune, PartitionPruneState::do_initial_prune, elog, ERROR, EState::es_partition_directory, EState::es_query_cxt, PartitionedRelPruningData::exec_context, PartitionedRelPruningData::exec_pruning_steps, PartitionedRelPruneInfo::exec_pruning_steps, ExecGetRangeTableRelation(), ExecInitPruningContext(), PartitionPruneState::execparamids, PartitionedRelPruneInfo::execparamids, i, PartitionedRelPruningData::initial_context, PartitionedRelPruningData::initial_pruning_steps, PartitionedRelPruneInfo::initial_pruning_steps, lfirst_node, list_length(), PartitionDescData::nparts, PartitionedRelPruningData::nparts, PartitionedRelPruneInfo::nparts, PartitionPruneState::num_partprunedata, PartitionPruningData::num_partrelprunedata, offsetof, OidIsValid, PartitionDescData::oids, PartitionPruneState::other_subplans, PartitionPruneInfo::other_subplans, palloc(), PartitionDirectoryLookup(), PartitionPruneState::partprunedata, PartitionPruningData::partrelprunedata, PartitionedRelPruningData::present_parts, PartitionedRelPruneInfo::present_parts, PartitionPruneState::prune_context, PartitionPruneInfo::prune_infos, RelationGetPartitionKey(), PartitionedRelPruneInfo::relid_map, PartitionedRelPruneInfo::rtindex, PlanState::state, PartitionedRelPruningData::subpart_map, PartitionedRelPruneInfo::subpart_map, PartitionedRelPruningData::subplan_map, and PartitionedRelPruneInfo::subplan_map.

Referenced by ExecInitAppend(), and ExecInitMergeAppend().

1625 {
1626  EState *estate = planstate->state;
1627  PartitionPruneState *prunestate;
1628  int n_part_hierarchies;
1629  ListCell *lc;
1630  int i;
1631 
1632  if (estate->es_partition_directory == NULL)
1633  estate->es_partition_directory =
1635 
1636  n_part_hierarchies = list_length(partitionpruneinfo->prune_infos);
1637  Assert(n_part_hierarchies > 0);
1638 
1639  /*
1640  * Allocate the data structure
1641  */
1642  prunestate = (PartitionPruneState *)
1643  palloc(offsetof(PartitionPruneState, partprunedata) +
1644  sizeof(PartitionPruningData *) * n_part_hierarchies);
1645 
1646  prunestate->execparamids = NULL;
1647  /* other_subplans can change at runtime, so we need our own copy */
1648  prunestate->other_subplans = bms_copy(partitionpruneinfo->other_subplans);
1649  prunestate->do_initial_prune = false; /* may be set below */
1650  prunestate->do_exec_prune = false; /* may be set below */
1651  prunestate->num_partprunedata = n_part_hierarchies;
1652 
1653  /*
1654  * Create a short-term memory context which we'll use when making calls to
1655  * the partition pruning functions. This avoids possible memory leaks,
1656  * since the pruning functions call comparison functions that aren't under
1657  * our control.
1658  */
1659  prunestate->prune_context =
1661  "Partition Prune",
1663 
1664  i = 0;
1665  foreach(lc, partitionpruneinfo->prune_infos)
1666  {
1667  List *partrelpruneinfos = lfirst_node(List, lc);
1668  int npartrelpruneinfos = list_length(partrelpruneinfos);
1669  PartitionPruningData *prunedata;
1670  ListCell *lc2;
1671  int j;
1672 
1673  prunedata = (PartitionPruningData *)
1674  palloc(offsetof(PartitionPruningData, partrelprunedata) +
1675  npartrelpruneinfos * sizeof(PartitionedRelPruningData));
1676  prunestate->partprunedata[i] = prunedata;
1677  prunedata->num_partrelprunedata = npartrelpruneinfos;
1678 
1679  j = 0;
1680  foreach(lc2, partrelpruneinfos)
1681  {
1683  PartitionedRelPruningData *pprune = &prunedata->partrelprunedata[j];
1684  Relation partrel;
1685  PartitionDesc partdesc;
1686  PartitionKey partkey;
1687 
1688  /*
1689  * We can rely on the copies of the partitioned table's partition
1690  * key and partition descriptor appearing in its relcache entry,
1691  * because that entry will be held open and locked for the
1692  * duration of this executor run.
1693  */
1694  partrel = ExecGetRangeTableRelation(estate, pinfo->rtindex);
1695  partkey = RelationGetPartitionKey(partrel);
1697  partrel);
1698 
1699  /*
1700  * Initialize the subplan_map and subpart_map. Since detaching a
1701  * partition requires AccessExclusiveLock, no partitions can have
1702  * disappeared, nor can the bounds for any partition have changed.
1703  * However, new partitions may have been added.
1704  */
1705  Assert(partdesc->nparts >= pinfo->nparts);
1706  pprune->nparts = partdesc->nparts;
1707  pprune->subplan_map = palloc(sizeof(int) * partdesc->nparts);
1708  if (partdesc->nparts == pinfo->nparts)
1709  {
1710  /*
1711  * There are no new partitions, so this is simple. We can
1712  * simply point to the subpart_map from the plan, but we must
1713  * copy the subplan_map since we may change it later.
1714  */
1715  pprune->subpart_map = pinfo->subpart_map;
1716  memcpy(pprune->subplan_map, pinfo->subplan_map,
1717  sizeof(int) * pinfo->nparts);
1718 
1719  /*
1720  * Double-check that the list of unpruned relations has not
1721  * changed. (Pruned partitions are not in relid_map[].)
1722  */
1723 #ifdef USE_ASSERT_CHECKING
1724  for (int k = 0; k < pinfo->nparts; k++)
1725  {
1726  Assert(partdesc->oids[k] == pinfo->relid_map[k] ||
1727  pinfo->subplan_map[k] == -1);
1728  }
1729 #endif
1730  }
1731  else
1732  {
1733  int pd_idx = 0;
1734  int pp_idx;
1735 
1736  /*
1737  * Some new partitions have appeared since plan time, and
1738  * those are reflected in our PartitionDesc but were not
1739  * present in the one used to construct subplan_map and
1740  * subpart_map. So we must construct new and longer arrays
1741  * where the partitions that were originally present map to
1742  * the same sub-structures, and any added partitions map to
1743  * -1, as if the new partitions had been pruned.
1744  *
1745  * Note: pinfo->relid_map[] may contain InvalidOid entries for
1746  * partitions pruned by the planner. We cannot tell exactly
1747  * which of the partdesc entries these correspond to, but we
1748  * don't have to; just skip over them. The non-pruned
1749  * relid_map entries, however, had better be a subset of the
1750  * partdesc entries and in the same order.
1751  */
1752  pprune->subpart_map = palloc(sizeof(int) * partdesc->nparts);
1753  for (pp_idx = 0; pp_idx < partdesc->nparts; pp_idx++)
1754  {
1755  /* Skip any InvalidOid relid_map entries */
1756  while (pd_idx < pinfo->nparts &&
1757  !OidIsValid(pinfo->relid_map[pd_idx]))
1758  pd_idx++;
1759 
1760  if (pd_idx < pinfo->nparts &&
1761  pinfo->relid_map[pd_idx] == partdesc->oids[pp_idx])
1762  {
1763  /* match... */
1764  pprune->subplan_map[pp_idx] =
1765  pinfo->subplan_map[pd_idx];
1766  pprune->subpart_map[pp_idx] =
1767  pinfo->subpart_map[pd_idx];
1768  pd_idx++;
1769  }
1770  else
1771  {
1772  /* this partdesc entry is not in the plan */
1773  pprune->subplan_map[pp_idx] = -1;
1774  pprune->subpart_map[pp_idx] = -1;
1775  }
1776  }
1777 
1778  /*
1779  * It might seem that we need to skip any trailing InvalidOid
1780  * entries in pinfo->relid_map before checking that we scanned
1781  * all of the relid_map. But we will have skipped them above,
1782  * because they must correspond to some partdesc->oids
1783  * entries; we just couldn't tell which.
1784  */
1785  if (pd_idx != pinfo->nparts)
1786  elog(ERROR, "could not match partition child tables to plan elements");
1787  }
1788 
1789  /* present_parts is also subject to later modification */
1790  pprune->present_parts = bms_copy(pinfo->present_parts);
1791 
1792  /*
1793  * Initialize pruning contexts as needed.
1794  */
1796  if (pinfo->initial_pruning_steps)
1797  {
1799  pinfo->initial_pruning_steps,
1800  partdesc, partkey, planstate);
1801  /* Record whether initial pruning is needed at any level */
1802  prunestate->do_initial_prune = true;
1803  }
1804  pprune->exec_pruning_steps = pinfo->exec_pruning_steps;
1805  if (pinfo->exec_pruning_steps)
1806  {
1808  pinfo->exec_pruning_steps,
1809  partdesc, partkey, planstate);
1810  /* Record whether exec pruning is needed at any level */
1811  prunestate->do_exec_prune = true;
1812  }
1813 
1814  /*
1815  * Accumulate the IDs of all PARAM_EXEC Params affecting the
1816  * partitioning decisions at this plan node.
1817  */
1818  prunestate->execparamids = bms_add_members(prunestate->execparamids,
1819  pinfo->execparamids);
1820 
1821  j++;
1822  }
1823  i++;
1824  }
1825 
1826  return prunestate;
1827 }
Bitmapset * execparamids
Definition: plannodes.h:1161
MemoryContext prune_context
#define AllocSetContextCreate
Definition: memutils.h:170
static void ExecInitPruningContext(PartitionPruneContext *context, List *pruning_steps, PartitionDesc partdesc, PartitionKey partkey, PlanState *planstate)
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:74
PartitionPruningData * partprunedata[FLEXIBLE_ARRAY_MEMBER]
PartitionDirectory CreatePartitionDirectory(MemoryContext mcxt)
Definition: partdesc.c:283
EState * state
Definition: execnodes.h:930
PartitionKey RelationGetPartitionKey(Relation rel)
Definition: partcache.c:54
#define OidIsValid(objectId)
Definition: c.h:706
MemoryContext es_query_cxt
Definition: execnodes.h:559
#define ERROR
Definition: elog.h:43
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:192
#define lfirst_node(type, lc)
Definition: pg_list.h:172
Bitmapset * present_parts
Definition: plannodes.h:1146
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
Bitmapset * execparamids
PartitionPruneContext exec_context
Definition: execPartition.h:57
Relation ExecGetRangeTableRelation(EState *estate, Index rti)
Definition: execUtils.c:781
Bitmapset * other_subplans
Definition: plannodes.h:1122
#define Assert(condition)
Definition: c.h:800
static int list_length(const List *l)
Definition: pg_list.h:149
PartitionDirectory es_partition_directory
Definition: execnodes.h:541
PartitionedRelPruningData partrelprunedata[FLEXIBLE_ARRAY_MEMBER]
Definition: execPartition.h:70
void * palloc(Size size)
Definition: mcxt.c:950
#define elog(elevel,...)
Definition: elog.h:228
int i
PartitionDesc PartitionDirectoryLookup(PartitionDirectory pdir, Relation rel)
Definition: partdesc.c:315
Definition: pg_list.h:50
PartitionPruneContext initial_context
Definition: execPartition.h:56
#define offsetof(type, field)
Definition: c.h:723
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:793
Bitmapset * other_subplans
struct PartitionedRelPruningData PartitionedRelPruningData

◆ ExecFindInitialMatchingSubPlans()

Bitmapset* ExecFindInitialMatchingSubPlans ( PartitionPruneState prunestate,
int  nsubplans 
)

Definition at line 1911 of file execPartition.c.

References Assert, bms_add_member(), bms_add_members(), bms_copy(), bms_free(), bms_is_empty(), bms_next_member(), bms_num_members(), PartitionPruneState::do_exec_prune, PartitionPruneState::do_initial_prune, find_matching_subplans_recurse(), i, PartitionedRelPruningData::initial_context, PartitionedRelPruningData::initial_pruning_steps, MemoryContextReset(), MemoryContextSwitchTo(), PartitionedRelPruningData::nparts, PartitionPruneState::num_partprunedata, PartitionPruningData::num_partrelprunedata, PartitionPruneState::other_subplans, palloc0(), PartitionPruneState::partprunedata, PartitionPruningData::partrelprunedata, pfree(), PartitionPruneContext::planstate, PartitionedRelPruningData::present_parts, PartitionPruneState::prune_context, PlanState::ps_ExprContext, ResetExprContext, PartitionedRelPruningData::subpart_map, and PartitionedRelPruningData::subplan_map.

Referenced by ExecInitAppend(), and ExecInitMergeAppend().

1912 {
1913  Bitmapset *result = NULL;
1914  MemoryContext oldcontext;
1915  int i;
1916 
1917  /* Caller error if we get here without do_initial_prune */
1918  Assert(prunestate->do_initial_prune);
1919 
1920  /*
1921  * Switch to a temp context to avoid leaking memory in the executor's
1922  * query-lifespan memory context.
1923  */
1924  oldcontext = MemoryContextSwitchTo(prunestate->prune_context);
1925 
1926  /*
1927  * For each hierarchy, do the pruning tests, and add nondeletable
1928  * subplans' indexes to "result".
1929  */
1930  for (i = 0; i < prunestate->num_partprunedata; i++)
1931  {
1932  PartitionPruningData *prunedata;
1933  PartitionedRelPruningData *pprune;
1934 
1935  prunedata = prunestate->partprunedata[i];
1936  pprune = &prunedata->partrelprunedata[0];
1937 
1938  /* Perform pruning without using PARAM_EXEC Params */
1939  find_matching_subplans_recurse(prunedata, pprune, true, &result);
1940 
1941  /* Expression eval may have used space in node's ps_ExprContext too */
1942  if (pprune->initial_pruning_steps)
1944  }
1945 
1946  /* Add in any subplans that partition pruning didn't account for */
1947  result = bms_add_members(result, prunestate->other_subplans);
1948 
1949  MemoryContextSwitchTo(oldcontext);
1950 
1951  /* Copy result out of the temp context before we reset it */
1952  result = bms_copy(result);
1953 
1954  MemoryContextReset(prunestate->prune_context);
1955 
1956  /*
1957  * If exec-time pruning is required and we pruned subplans above, then we
1958  * must re-sequence the subplan indexes so that ExecFindMatchingSubPlans
1959  * properly returns the indexes from the subplans which will remain after
1960  * execution of this function.
1961  *
1962  * We can safely skip this when !do_exec_prune, even though that leaves
1963  * invalid data in prunestate, because that data won't be consulted again
1964  * (cf initial Assert in ExecFindMatchingSubPlans).
1965  */
1966  if (prunestate->do_exec_prune && bms_num_members(result) < nsubplans)
1967  {
1968  int *new_subplan_indexes;
1969  Bitmapset *new_other_subplans;
1970  int i;
1971  int newidx;
1972 
1973  /*
1974  * First we must build a temporary array which maps old subplan
1975  * indexes to new ones. For convenience of initialization, we use
1976  * 1-based indexes in this array and leave pruned items as 0.
1977  */
1978  new_subplan_indexes = (int *) palloc0(sizeof(int) * nsubplans);
1979  newidx = 1;
1980  i = -1;
1981  while ((i = bms_next_member(result, i)) >= 0)
1982  {
1983  Assert(i < nsubplans);
1984  new_subplan_indexes[i] = newidx++;
1985  }
1986 
1987  /*
1988  * Now we can update each PartitionedRelPruneInfo's subplan_map with
1989  * new subplan indexes. We must also recompute its present_parts
1990  * bitmap.
1991  */
1992  for (i = 0; i < prunestate->num_partprunedata; i++)
1993  {
1994  PartitionPruningData *prunedata = prunestate->partprunedata[i];
1995  int j;
1996 
1997  /*
1998  * Within each hierarchy, we perform this loop in back-to-front
1999  * order so that we determine present_parts for the lowest-level
2000  * partitioned tables first. This way we can tell whether a
2001  * sub-partitioned table's partitions were entirely pruned so we
2002  * can exclude it from the current level's present_parts.
2003  */
2004  for (j = prunedata->num_partrelprunedata - 1; j >= 0; j--)
2005  {
2006  PartitionedRelPruningData *pprune = &prunedata->partrelprunedata[j];
2007  int nparts = pprune->nparts;
2008  int k;
2009 
2010  /* We just rebuild present_parts from scratch */
2011  bms_free(pprune->present_parts);
2012  pprune->present_parts = NULL;
2013 
2014  for (k = 0; k < nparts; k++)
2015  {
2016  int oldidx = pprune->subplan_map[k];
2017  int subidx;
2018 
2019  /*
2020  * If this partition existed as a subplan then change the
2021  * old subplan index to the new subplan index. The new
2022  * index may become -1 if the partition was pruned above,
2023  * or it may just come earlier in the subplan list due to
2024  * some subplans being removed earlier in the list. If
2025  * it's a subpartition, add it to present_parts unless
2026  * it's entirely pruned.
2027  */
2028  if (oldidx >= 0)
2029  {
2030  Assert(oldidx < nsubplans);
2031  pprune->subplan_map[k] = new_subplan_indexes[oldidx] - 1;
2032 
2033  if (new_subplan_indexes[oldidx] > 0)
2034  pprune->present_parts =
2035  bms_add_member(pprune->present_parts, k);
2036  }
2037  else if ((subidx = pprune->subpart_map[k]) >= 0)
2038  {
2039  PartitionedRelPruningData *subprune;
2040 
2041  subprune = &prunedata->partrelprunedata[subidx];
2042 
2043  if (!bms_is_empty(subprune->present_parts))
2044  pprune->present_parts =
2045  bms_add_member(pprune->present_parts, k);
2046  }
2047  }
2048  }
2049  }
2050 
2051  /*
2052  * We must also recompute the other_subplans set, since indexes in it
2053  * may change.
2054  */
2055  new_other_subplans = NULL;
2056  i = -1;
2057  while ((i = bms_next_member(prunestate->other_subplans, i)) >= 0)
2058  new_other_subplans = bms_add_member(new_other_subplans,
2059  new_subplan_indexes[i] - 1);
2060 
2061  bms_free(prunestate->other_subplans);
2062  prunestate->other_subplans = new_other_subplans;
2063 
2064  pfree(new_subplan_indexes);
2065  }
2066 
2067  return result;
2068 }
MemoryContext prune_context
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:74
ExprContext * ps_ExprContext
Definition: execnodes.h:967
PartitionPruningData * partprunedata[FLEXIBLE_ARRAY_MEMBER]
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1043
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:137
void pfree(void *pointer)
Definition: mcxt.c:1057
static void find_matching_subplans_recurse(PartitionPruningData *prunedata, PartitionedRelPruningData *pprune, bool initial_prune, Bitmapset **validsubplans)
int bms_num_members(const Bitmapset *a)
Definition: bitmapset.c:646
bool bms_is_empty(const Bitmapset *a)
Definition: bitmapset.c:701
void * palloc0(Size size)
Definition: mcxt.c:981
void bms_free(Bitmapset *a)
Definition: bitmapset.c:208
#define Assert(condition)
Definition: c.h:800
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:736
PartitionedRelPruningData partrelprunedata[FLEXIBLE_ARRAY_MEMBER]
Definition: execPartition.h:70
int i
PartitionPruneContext initial_context
Definition: execPartition.h:56
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:793
#define ResetExprContext(econtext)
Definition: executor.h:503
Bitmapset * other_subplans
PlanState * planstate
Definition: partprune.h:58

◆ ExecFindMatchingSubPlans()

Bitmapset* ExecFindMatchingSubPlans ( PartitionPruneState prunestate)

Definition at line 2078 of file execPartition.c.

References Assert, bms_add_members(), bms_copy(), PartitionPruneState::do_exec_prune, PartitionedRelPruningData::exec_context, PartitionedRelPruningData::exec_pruning_steps, find_matching_subplans_recurse(), i, MemoryContextReset(), MemoryContextSwitchTo(), PartitionPruneState::num_partprunedata, PartitionPruneState::other_subplans, PartitionPruneState::partprunedata, PartitionPruningData::partrelprunedata, PartitionPruneContext::planstate, PartitionPruneState::prune_context, PlanState::ps_ExprContext, and ResetExprContext.

Referenced by choose_next_subplan_for_leader(), choose_next_subplan_for_worker(), choose_next_subplan_locally(), and ExecMergeAppend().

2079 {
2080  Bitmapset *result = NULL;
2081  MemoryContext oldcontext;
2082  int i;
2083 
2084  /*
2085  * If !do_exec_prune, we've got problems because
2086  * ExecFindInitialMatchingSubPlans will not have bothered to update
2087  * prunestate for whatever pruning it did.
2088  */
2089  Assert(prunestate->do_exec_prune);
2090 
2091  /*
2092  * Switch to a temp context to avoid leaking memory in the executor's
2093  * query-lifespan memory context.
2094  */
2095  oldcontext = MemoryContextSwitchTo(prunestate->prune_context);
2096 
2097  /*
2098  * For each hierarchy, do the pruning tests, and add nondeletable
2099  * subplans' indexes to "result".
2100  */
2101  for (i = 0; i < prunestate->num_partprunedata; i++)
2102  {
2103  PartitionPruningData *prunedata;
2104  PartitionedRelPruningData *pprune;
2105 
2106  prunedata = prunestate->partprunedata[i];
2107  pprune = &prunedata->partrelprunedata[0];
2108 
2109  find_matching_subplans_recurse(prunedata, pprune, false, &result);
2110 
2111  /* Expression eval may have used space in node's ps_ExprContext too */
2112  if (pprune->exec_pruning_steps)
2114  }
2115 
2116  /* Add in any subplans that partition pruning didn't account for */
2117  result = bms_add_members(result, prunestate->other_subplans);
2118 
2119  MemoryContextSwitchTo(oldcontext);
2120 
2121  /* Copy result out of the temp context before we reset it */
2122  result = bms_copy(result);
2123 
2124  MemoryContextReset(prunestate->prune_context);
2125 
2126  return result;
2127 }
MemoryContext prune_context
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:74
ExprContext * ps_ExprContext
Definition: execnodes.h:967
PartitionPruningData * partprunedata[FLEXIBLE_ARRAY_MEMBER]
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:137
static void find_matching_subplans_recurse(PartitionPruningData *prunedata, PartitionedRelPruningData *pprune, bool initial_prune, Bitmapset **validsubplans)
PartitionPruneContext exec_context
Definition: execPartition.h:57
#define Assert(condition)
Definition: c.h:800
PartitionedRelPruningData partrelprunedata[FLEXIBLE_ARRAY_MEMBER]
Definition: execPartition.h:70
int i
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:793
#define ResetExprContext(econtext)
Definition: executor.h:503
Bitmapset * other_subplans
PlanState * planstate
Definition: partprune.h:58

◆ ExecFindPartition()

ResultRelInfo* ExecFindPartition ( ModifyTableState mtstate,
ResultRelInfo rootResultRelInfo,
PartitionTupleRouting proute,
TupleTableSlot slot,
EState estate 
)

Definition at line 277 of file execPartition.c.

References Assert, TupleConversionMap::attrMap, PartitionDescData::boundinfo, CHECK_FOR_INTERRUPTS, CheckValidResultRel(), CMD_INSERT, PartitionBoundInfoData::default_index, ExprContext::ecxt_scantuple, ereport, errcode(), errdetail(), errmsg(), ERROR, errtable(), ExecBuildSlotPartitionKeyDescription(), ExecClearTuple(), ExecInitPartitionDispatchInfo(), ExecInitPartitionInfo(), ExecInitRoutingInfo(), ExecPartitionCheck(), execute_attr_map_slot(), FormPartitionKeyDatum(), get_partition_for_tuple(), GetPerTupleExprContext, GetPerTupleMemoryContext, HASH_FIND, hash_search(), PartitionDispatchData::indexes, PartitionDescData::is_leaf, likely, MemoryContextSwitchTo(), PartitionTupleRouting::nonleaf_partitions, PartitionDescData::nparts, PartitionTupleRouting::num_dispatch, PartitionTupleRouting::num_partitions, OidIsValid, PartitionDescData::oids, PartitionDispatchData::partdesc, PartitionTupleRouting::partition_dispatch_info, PARTITION_MAX_KEYS, PartitionTupleRouting::partitions, ModifyTableState::ps, RelationData::rd_rel, RelationGetRelationName, RelationGetRelid, PartitionDispatchData::reldesc, ResultRelInfo::ri_PartitionTupleSlot, ResultRelInfo::ri_RelationDesc, ResultRelInfo::ri_RootToPartitionMap, SubplanResultRelHashElem::rri, PlanState::state, PartitionTupleRouting::subplan_resultrel_htab, PartitionDispatchData::tupmap, PartitionDispatchData::tupslot, and values.

Referenced by apply_handle_tuple_routing(), CopyFrom(), and ExecPrepareTupleRouting().

281 {
284  bool isnull[PARTITION_MAX_KEYS];
285  Relation rel;
286  PartitionDispatch dispatch;
287  PartitionDesc partdesc;
288  ExprContext *ecxt = GetPerTupleExprContext(estate);
289  TupleTableSlot *ecxt_scantuple_saved = ecxt->ecxt_scantuple;
290  TupleTableSlot *rootslot = slot;
291  TupleTableSlot *myslot = NULL;
292  MemoryContext oldcxt;
293  ResultRelInfo *rri = NULL;
294 
295  /* use per-tuple context here to avoid leaking memory */
297 
298  /*
299  * First check the root table's partition constraint, if any. No point in
300  * routing the tuple if it doesn't belong in the root table itself.
301  */
302  if (rootResultRelInfo->ri_RelationDesc->rd_rel->relispartition)
303  ExecPartitionCheck(rootResultRelInfo, slot, estate, true);
304 
305  /* start with the root partitioned table */
306  dispatch = pd[0];
307  while (dispatch != NULL)
308  {
309  int partidx = -1;
310  bool is_leaf;
311 
313 
314  rel = dispatch->reldesc;
315  partdesc = dispatch->partdesc;
316 
317  /*
318  * Extract partition key from tuple. Expression evaluation machinery
319  * that FormPartitionKeyDatum() invokes expects ecxt_scantuple to
320  * point to the correct tuple slot. The slot might have changed from
321  * what was used for the parent table if the table of the current
322  * partitioning level has different tuple descriptor from the parent.
323  * So update ecxt_scantuple accordingly.
324  */
325  ecxt->ecxt_scantuple = slot;
326  FormPartitionKeyDatum(dispatch, slot, estate, values, isnull);
327 
328  /*
329  * If this partitioned table has no partitions or no partition for
330  * these values, error out.
331  */
332  if (partdesc->nparts == 0 ||
333  (partidx = get_partition_for_tuple(dispatch, values, isnull)) < 0)
334  {
335  char *val_desc;
336 
338  values, isnull, 64);
340  ereport(ERROR,
341  (errcode(ERRCODE_CHECK_VIOLATION),
342  errmsg("no partition of relation \"%s\" found for row",
344  val_desc ?
345  errdetail("Partition key of the failing row contains %s.",
346  val_desc) : 0,
347  errtable(rel)));
348  }
349 
350  is_leaf = partdesc->is_leaf[partidx];
351  if (is_leaf)
352  {
353 
354  /*
355  * We've reached the leaf -- hurray, we're done. Look to see if
356  * we've already got a ResultRelInfo for this partition.
357  */
358  if (likely(dispatch->indexes[partidx] >= 0))
359  {
360  /* ResultRelInfo already built */
361  Assert(dispatch->indexes[partidx] < proute->num_partitions);
362  rri = proute->partitions[dispatch->indexes[partidx]];
363  }
364  else
365  {
366  bool found = false;
367 
368  /*
369  * We have not yet set up a ResultRelInfo for this partition,
370  * but if we have a subplan hash table, we might have one
371  * there. If not, we'll have to create one.
372  */
373  if (proute->subplan_resultrel_htab)
374  {
375  Oid partoid = partdesc->oids[partidx];
377 
378  elem = hash_search(proute->subplan_resultrel_htab,
379  &partoid, HASH_FIND, NULL);
380  if (elem)
381  {
382  found = true;
383  rri = elem->rri;
384 
385  /* Verify this ResultRelInfo allows INSERTs */
387 
388  /*
389  * Initialize information needed to insert this and
390  * subsequent tuples routed to this partition.
391  */
392  ExecInitRoutingInfo(mtstate, estate, proute, dispatch,
393  rri, partidx);
394  }
395  }
396 
397  /* We need to create a new one. */
398  if (!found)
399  rri = ExecInitPartitionInfo(mtstate, estate, proute,
400  dispatch,
401  rootResultRelInfo, partidx);
402  }
403  Assert(rri != NULL);
404 
405  /* Signal to terminate the loop */
406  dispatch = NULL;
407  }
408  else
409  {
410  /*
411  * Partition is a sub-partitioned table; get the PartitionDispatch
412  */
413  if (likely(dispatch->indexes[partidx] >= 0))
414  {
415  /* Already built. */
416  Assert(dispatch->indexes[partidx] < proute->num_dispatch);
417 
418  rri = proute->nonleaf_partitions[dispatch->indexes[partidx]];
419 
420  /*
421  * Move down to the next partition level and search again
422  * until we find a leaf partition that matches this tuple
423  */
424  dispatch = pd[dispatch->indexes[partidx]];
425  }
426  else
427  {
428  /* Not yet built. Do that now. */
429  PartitionDispatch subdispatch;
430 
431  /*
432  * Create the new PartitionDispatch. We pass the current one
433  * in as the parent PartitionDispatch
434  */
435  subdispatch = ExecInitPartitionDispatchInfo(mtstate->ps.state,
436  proute,
437  partdesc->oids[partidx],
438  dispatch, partidx);
439  Assert(dispatch->indexes[partidx] >= 0 &&
440  dispatch->indexes[partidx] < proute->num_dispatch);
441 
442  rri = proute->nonleaf_partitions[dispatch->indexes[partidx]];
443  dispatch = subdispatch;
444  }
445 
446  /*
447  * Convert the tuple to the new parent's layout, if different from
448  * the previous parent.
449  */
450  if (dispatch->tupslot)
451  {
452  AttrMap *map = dispatch->tupmap;
453  TupleTableSlot *tempslot = myslot;
454 
455  myslot = dispatch->tupslot;
456  slot = execute_attr_map_slot(map, slot, myslot);
457 
458  if (tempslot != NULL)
459  ExecClearTuple(tempslot);
460  }
461  }
462 
463  /*
464  * If this partition is the default one, we must check its partition
465  * constraint now, which may have changed concurrently due to
466  * partitions being added to the parent.
467  *
468  * (We do this here, and do not rely on ExecInsert doing it, because
469  * we don't want to miss doing it for non-leaf partitions.)
470  */
471  if (partidx == partdesc->boundinfo->default_index)
472  {
473  /*
474  * The tuple must match the partition's layout for the constraint
475  * expression to be evaluated successfully. If the partition is
476  * sub-partitioned, that would already be the case due to the code
477  * above, but for a leaf partition the tuple still matches the
478  * parent's layout.
479  *
480  * Note that we have a map to convert from root to current
481  * partition, but not from immediate parent to current partition.
482  * So if we have to convert, do it from the root slot; if not, use
483  * the root slot as-is.
484  */
485  if (is_leaf)
486  {
488 
489  if (map)
490  slot = execute_attr_map_slot(map->attrMap, rootslot,
491  rri->ri_PartitionTupleSlot);
492  else
493  slot = rootslot;
494  }
495 
496  ExecPartitionCheck(rri, slot, estate, true);
497  }
498  }
499 
500  /* Release the tuple in the lowest parent's dedicated slot. */
501  if (myslot != NULL)
502  ExecClearTuple(myslot);
503  /* and restore ecxt's scantuple */
504  ecxt->ecxt_scantuple = ecxt_scantuple_saved;
505  MemoryContextSwitchTo(oldcxt);
506 
507  return rri;
508 }
static int get_partition_for_tuple(PartitionDispatch pd, Datum *values, bool *isnull)
Relation ri_RelationDesc
Definition: execnodes.h:412
PartitionDesc partdesc
#define likely(x)
Definition: c.h:260
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:425
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
int errcode(int sqlerrcode)
Definition: elog.c:691
#define PARTITION_MAX_KEYS
bool * is_leaf
Definition: partdesc.h:26
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:919
EState * state
Definition: execnodes.h:930
Form_pg_class rd_rel
Definition: rel.h:110
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:706
ResultRelInfo ** partitions
Definition: attmap.h:34
PartitionBoundInfo boundinfo
Definition: partdesc.h:29
#define GetPerTupleExprContext(estate)
Definition: executor.h:509
#define ERROR
Definition: elog.h:43
PlanState ps
Definition: execnodes.h:1148
TupleTableSlot * ri_PartitionTupleSlot
Definition: execnodes.h:492
static void FormPartitionKeyDatum(PartitionDispatch pd, TupleTableSlot *slot, EState *estate, Datum *values, bool *isnull)
void CheckValidResultRel(ResultRelInfo *resultRelInfo, CmdType operation)
Definition: execMain.c:995
int errdetail(const char *fmt,...)
Definition: elog.c:1035
#define RelationGetRelationName(relation)
Definition: rel.h:491
PartitionDispatch * partition_dispatch_info
Definition: execPartition.c:96
AttrMap * attrMap
Definition: tupconvert.h:27
ResultRelInfo ** nonleaf_partitions
Definition: execPartition.c:97
static PartitionDispatch ExecInitPartitionDispatchInfo(EState *estate, PartitionTupleRouting *proute, Oid partoid, PartitionDispatch parent_pd, int partidx)
uintptr_t Datum
Definition: postgres.h:367
TupleTableSlot * tupslot
#define ereport(elevel,...)
Definition: elog.h:155
static ResultRelInfo * ExecInitPartitionInfo(ModifyTableState *mtstate, EState *estate, PartitionTupleRouting *proute, PartitionDispatch dispatch, ResultRelInfo *rootResultRelInfo, int partidx)
TupleTableSlot * execute_attr_map_slot(AttrMap *attrMap, TupleTableSlot *in_slot, TupleTableSlot *out_slot)
Definition: tupconvert.c:177
#define Assert(condition)
Definition: c.h:800
TupleTableSlot * ecxt_scantuple
Definition: execnodes.h:225
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:514
static Datum values[MAXATTR]
Definition: bootstrap.c:165
static char * ExecBuildSlotPartitionKeyDescription(Relation rel, Datum *values, bool *isnull, int maxfieldlen)
TupleConversionMap * ri_RootToPartitionMap
Definition: execnodes.h:491
int errmsg(const char *fmt,...)
Definition: elog.c:902
bool ExecPartitionCheck(ResultRelInfo *resultRelInfo, TupleTableSlot *slot, EState *estate, bool emitError)
Definition: execMain.c:1679
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:99
int errtable(Relation rel)
Definition: relcache.c:5498
static void ExecInitRoutingInfo(ModifyTableState *mtstate, EState *estate, PartitionTupleRouting *proute, PartitionDispatch dispatch, ResultRelInfo *partRelInfo, int partidx)
#define RelationGetRelid(relation)
Definition: rel.h:457
int indexes[FLEXIBLE_ARRAY_MEMBER]

◆ ExecHashSubPlanResultRelsByOid()

static void ExecHashSubPlanResultRelsByOid ( ModifyTableState mtstate,
PartitionTupleRouting proute 
)
static

Definition at line 517 of file execPartition.c.

References Assert, CurrentMemoryContext, HASHCTL::entrysize, HASH_BLOBS, HASH_CONTEXT, hash_create(), HASH_ELEM, HASH_ENTER, hash_search(), HASHCTL::hcxt, i, HASHCTL::keysize, ModifyTableState::mt_nplans, PartitionTupleRouting::partition_root, RelationGetRelid, ModifyTableState::resultRelInfo, ResultRelInfo::ri_PartitionRoot, ResultRelInfo::ri_RelationDesc, SubplanResultRelHashElem::rri, and PartitionTupleRouting::subplan_resultrel_htab.

Referenced by ExecSetupPartitionTupleRouting().

519 {
520  HASHCTL ctl;
521  HTAB *htab;
522  int i;
523 
524  memset(&ctl, 0, sizeof(ctl));
525  ctl.keysize = sizeof(Oid);
526  ctl.entrysize = sizeof(SubplanResultRelHashElem);
528 
529  htab = hash_create("PartitionTupleRouting table", mtstate->mt_nplans,
530  &ctl, HASH_ELEM | HASH_BLOBS | HASH_CONTEXT);
531  proute->subplan_resultrel_htab = htab;
532 
533  /* Hash all subplans by their Oid */
534  for (i = 0; i < mtstate->mt_nplans; i++)
535  {
536  ResultRelInfo *rri = &mtstate->resultRelInfo[i];
537  bool found;
538  Oid partoid = RelationGetRelid(rri->ri_RelationDesc);
540 
541  elem = (SubplanResultRelHashElem *)
542  hash_search(htab, &partoid, HASH_ENTER, &found);
543  Assert(!found);
544  elem->rri = rri;
545 
546  /*
547  * This is required in order to convert the partition's tuple to be
548  * compatible with the root partitioned table's tuple descriptor. When
549  * generating the per-subplan result rels, this was not set.
550  */
551  rri->ri_PartitionRoot = proute->partition_root;
552  }
553 }
Relation ri_RelationDesc
Definition: execnodes.h:412
struct SubplanResultRelHashElem SubplanResultRelHashElem
#define HASH_CONTEXT
Definition: hsearch.h:91
#define HASH_ELEM
Definition: hsearch.h:85
MemoryContext hcxt
Definition: hsearch.h:77
ResultRelInfo * resultRelInfo
Definition: execnodes.h:1157
Relation ri_PartitionRoot
Definition: execnodes.h:490
Size entrysize
Definition: hsearch.h:72
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:919
unsigned int Oid
Definition: postgres_ext.h:31
Definition: dynahash.c:218
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
#define HASH_BLOBS
Definition: hsearch.h:86
HTAB * hash_create(const char *tabname, long nelem, HASHCTL *info, int flags)
Definition: dynahash.c:326
Size keysize
Definition: hsearch.h:71
#define Assert(condition)
Definition: c.h:800
int i
#define RelationGetRelid(relation)
Definition: rel.h:457

◆ ExecInitPartitionDispatchInfo()

static PartitionDispatch ExecInitPartitionDispatchInfo ( EState estate,
PartitionTupleRouting proute,
Oid  partoid,
PartitionDispatch  parent_pd,
int  partidx 
)
static

Definition at line 1040 of file execPartition.c.

References Assert, build_attrmap_by_name_if_req(), CreatePartitionDirectory(), EState::es_partition_directory, EState::es_query_cxt, PartitionDispatchData::indexes, InitResultRelInfo(), PartitionDispatchData::key, PartitionDispatchData::keystate, makeNode, MakeSingleTupleTableSlot(), PartitionTupleRouting::max_dispatch, PartitionTupleRouting::memcxt, MemoryContextSwitchTo(), NIL, PartitionTupleRouting::nonleaf_partitions, PartitionDescData::nparts, PartitionTupleRouting::num_dispatch, offsetof, palloc(), PartitionDispatchData::partdesc, PartitionTupleRouting::partition_dispatch_info, PartitionTupleRouting::partition_root, PartitionDirectoryLookup(), RelationGetDescr, RelationGetPartitionKey(), RelationGetRelid, PartitionDispatchData::reldesc, repalloc(), RowExclusiveLock, table_open(), TTSOpsVirtual, PartitionDispatchData::tupmap, and PartitionDispatchData::tupslot.

Referenced by ExecFindPartition(), and ExecSetupPartitionTupleRouting().

1043 {
1044  Relation rel;
1045  PartitionDesc partdesc;
1046  PartitionDispatch pd;
1047  int dispatchidx;
1048  MemoryContext oldcxt;
1049 
1050  if (estate->es_partition_directory == NULL)
1051  estate->es_partition_directory =
1053 
1054  oldcxt = MemoryContextSwitchTo(proute->memcxt);
1055 
1056  /*
1057  * Only sub-partitioned tables need to be locked here. The root
1058  * partitioned table will already have been locked as it's referenced in
1059  * the query's rtable.
1060  */
1061  if (partoid != RelationGetRelid(proute->partition_root))
1062  rel = table_open(partoid, RowExclusiveLock);
1063  else
1064  rel = proute->partition_root;
1065  partdesc = PartitionDirectoryLookup(estate->es_partition_directory, rel);
1066 
1068  partdesc->nparts * sizeof(int));
1069  pd->reldesc = rel;
1070  pd->key = RelationGetPartitionKey(rel);
1071  pd->keystate = NIL;
1072  pd->partdesc = partdesc;
1073  if (parent_pd != NULL)
1074  {
1075  TupleDesc tupdesc = RelationGetDescr(rel);
1076 
1077  /*
1078  * For sub-partitioned tables where the column order differs from its
1079  * direct parent partitioned table, we must store a tuple table slot
1080  * initialized with its tuple descriptor and a tuple conversion map to
1081  * convert a tuple from its parent's rowtype to its own. This is to
1082  * make sure that we are looking at the correct row using the correct
1083  * tuple descriptor when computing its partition key for tuple
1084  * routing.
1085  */
1087  tupdesc);
1088  pd->tupslot = pd->tupmap ?
1089  MakeSingleTupleTableSlot(tupdesc, &TTSOpsVirtual) : NULL;
1090  }
1091  else
1092  {
1093  /* Not required for the root partitioned table */
1094  pd->tupmap = NULL;
1095  pd->tupslot = NULL;
1096  }
1097 
1098  /*
1099  * Initialize with -1 to signify that the corresponding partition's
1100  * ResultRelInfo or PartitionDispatch has not been created yet.
1101  */
1102  memset(pd->indexes, -1, sizeof(int) * partdesc->nparts);
1103 
1104  /* Track in PartitionTupleRouting for later use */
1105  dispatchidx = proute->num_dispatch++;
1106 
1107  /* Allocate or enlarge the array, as needed */
1108  if (proute->num_dispatch >= proute->max_dispatch)
1109  {
1110  if (proute->max_dispatch == 0)
1111  {
1112  proute->max_dispatch = 4;
1114  palloc(sizeof(PartitionDispatch) * proute->max_dispatch);
1115  proute->nonleaf_partitions = (ResultRelInfo **)
1116  palloc(sizeof(ResultRelInfo *) * proute->max_dispatch);
1117  }
1118  else
1119  {
1120  proute->max_dispatch *= 2;
1123  sizeof(PartitionDispatch) * proute->max_dispatch);
1124  proute->nonleaf_partitions = (ResultRelInfo **)
1125  repalloc(proute->nonleaf_partitions,
1126  sizeof(ResultRelInfo *) * proute->max_dispatch);
1127  }
1128  }
1129  proute->partition_dispatch_info[dispatchidx] = pd;
1130 
1131  /*
1132  * If setting up a PartitionDispatch for a sub-partitioned table, we may
1133  * also need a minimally valid ResultRelInfo for checking the partition
1134  * constraint later; set that up now.
1135  */
1136  if (parent_pd)
1137  {
1139 
1140  InitResultRelInfo(rri, rel, 1, proute->partition_root, 0);
1141  proute->nonleaf_partitions[dispatchidx] = rri;
1142  }
1143  else
1144  proute->nonleaf_partitions[dispatchidx] = NULL;
1145 
1146  /*
1147  * Finally, if setting up a PartitionDispatch for a sub-partitioned table,
1148  * install a downlink in the parent to allow quick descent.
1149  */
1150  if (parent_pd)
1151  {
1152  Assert(parent_pd->indexes[partidx] == -1);
1153  parent_pd->indexes[partidx] = dispatchidx;
1154  }
1155 
1156  MemoryContextSwitchTo(oldcxt);
1157 
1158  return pd;
1159 }
#define NIL
Definition: pg_list.h:65
void InitResultRelInfo(ResultRelInfo *resultRelInfo, Relation resultRelationDesc, Index resultRelationIndex, Relation partition_root, int instrument_options)
Definition: execMain.c:1196
PartitionDesc partdesc
#define RelationGetDescr(relation)
Definition: rel.h:483
TupleTableSlot * MakeSingleTupleTableSlot(TupleDesc tupdesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1208
const TupleTableSlotOps TTSOpsVirtual
Definition: execTuples.c:83
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
PartitionDirectory CreatePartitionDirectory(MemoryContext mcxt)
Definition: partdesc.c:283
PartitionKey RelationGetPartitionKey(Relation rel)
Definition: partcache.c:54
MemoryContext es_query_cxt
Definition: execnodes.h:559
AttrMap * build_attrmap_by_name_if_req(TupleDesc indesc, TupleDesc outdesc)
Definition: attmap.c:259
#define RowExclusiveLock
Definition: lockdefs.h:38
PartitionDispatch * partition_dispatch_info
Definition: execPartition.c:96
ResultRelInfo ** nonleaf_partitions
Definition: execPartition.c:97
TupleTableSlot * tupslot
#define makeNode(_type_)
Definition: nodes.h:575
#define Assert(condition)
Definition: c.h:800
PartitionDirectory es_partition_directory
Definition: execnodes.h:541
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1070
void * palloc(Size size)
Definition: mcxt.c:950
PartitionDesc PartitionDirectoryLookup(PartitionDirectory pdir, Relation rel)
Definition: partdesc.c:315
MemoryContext memcxt
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
struct PartitionDispatchData * PartitionDispatch
Definition: execPartition.h:22
#define RelationGetRelid(relation)
Definition: rel.h:457
#define offsetof(type, field)
Definition: c.h:723
int indexes[FLEXIBLE_ARRAY_MEMBER]

◆ ExecInitPartitionInfo()

static ResultRelInfo * ExecInitPartitionInfo ( ModifyTableState mtstate,
EState estate,
PartitionTupleRouting proute,
PartitionDispatch  dispatch,
ResultRelInfo rootResultRelInfo,
int  partidx 
)
static

Definition at line 564 of file execPartition.c.

References adjust_partition_tlist(), Assert, build_attrmap_by_name(), castNode, CheckValidResultRel(), CMD_INSERT, CMD_UPDATE, convert_tuples_by_name(), copyObject, elog, ERROR, EState::es_instrument, EState::es_query_cxt, EState::es_tuple_routing_result_relations, EState::es_tupleTable, ExecBuildProjectionInfo(), ExecInitExtraTupleSlot(), ExecInitQual(), ExecInitRoutingInfo(), ExecOpenIndices(), ExecTypeFromTL(), get_partition_ancestors(), InitResultRelInfo(), INNER_VAR, lappend(), lappend_oid(), lfirst, lfirst_oid, linitial, list_free(), list_length(), list_member_oid(), makeNode, map_variable_attnos(), PartitionTupleRouting::memcxt, MemoryContextSwitchTo(), ModifyTableState::mt_oc_transition_capture, ModifyTableState::mt_transition_capture, NIL, OnConflictSetState::oc_ProjInfo, OnConflictSetState::oc_ProjSlot, OnConflictSetState::oc_WhereClause, PartitionDescData::oids, ONCONFLICT_NONE, ONCONFLICT_UPDATE, ModifyTable::onConflictAction, ModifyTable::onConflictSet, ModifyTable::onConflictWhere, ModifyTable::operation, PartitionDispatchData::partdesc, PlanState::plan, ModifyTable::plans, ModifyTableState::ps, PlanState::ps_ExprContext, PlanState::ps_ResultTupleSlot, WithCheckOption::qual, RelationGetDescr, RelationGetForm, RelationGetIndexList(), ModifyTableState::resultRelInfo, ModifyTable::returningLists, ResultRelInfo::ri_onConflict, ResultRelInfo::ri_onConflictArbiterIndexes, ResultRelInfo::ri_RangeTableIndex, ResultRelInfo::ri_RelationDesc, ModifyTable::rootRelation, RowExclusiveLock, PlanState::state, table_open(), table_slot_create(), TTSOpsVirtual, and ModifyTable::withCheckOptionLists.

Referenced by ExecFindPartition().

569 {
570  ModifyTable *node = (ModifyTable *) mtstate->ps.plan;
571  Relation rootrel = rootResultRelInfo->ri_RelationDesc,
572  partrel;
573  Relation firstResultRel = mtstate->resultRelInfo[0].ri_RelationDesc;
574  ResultRelInfo *leaf_part_rri;
575  MemoryContext oldcxt;
576  AttrMap *part_attmap = NULL;
577  bool found_whole_row;
578 
579  oldcxt = MemoryContextSwitchTo(proute->memcxt);
580 
581  partrel = table_open(dispatch->partdesc->oids[partidx], RowExclusiveLock);
582 
583  leaf_part_rri = makeNode(ResultRelInfo);
584  InitResultRelInfo(leaf_part_rri,
585  partrel,
586  node ? node->rootRelation : 1,
587  rootrel,
588  estate->es_instrument);
589 
590  /*
591  * Verify result relation is a valid target for an INSERT. An UPDATE of a
592  * partition-key becomes a DELETE+INSERT operation, so this check is still
593  * required when the operation is CMD_UPDATE.
594  */
595  CheckValidResultRel(leaf_part_rri, CMD_INSERT);
596 
597  /*
598  * Open partition indices. The user may have asked to check for conflicts
599  * within this leaf partition and do "nothing" instead of throwing an
600  * error. Be prepared in that case by initializing the index information
601  * needed by ExecInsert() to perform speculative insertions.
602  */
603  if (partrel->rd_rel->relhasindex &&
604  leaf_part_rri->ri_IndexRelationDescs == NULL)
605  ExecOpenIndices(leaf_part_rri,
606  (node != NULL &&
608 
609  /*
610  * Build WITH CHECK OPTION constraints for the partition. Note that we
611  * didn't build the withCheckOptionList for partitions within the planner,
612  * but simple translation of varattnos will suffice. This only occurs for
613  * the INSERT case or in the case of UPDATE tuple routing where we didn't
614  * find a result rel to reuse in ExecSetupPartitionTupleRouting().
615  */
616  if (node && node->withCheckOptionLists != NIL)
617  {
618  List *wcoList;
619  List *wcoExprs = NIL;
620  ListCell *ll;
621  int firstVarno = mtstate->resultRelInfo[0].ri_RangeTableIndex;
622 
623  /*
624  * In the case of INSERT on a partitioned table, there is only one
625  * plan. Likewise, there is only one WCO list, not one per partition.
626  * For UPDATE, there are as many WCO lists as there are plans.
627  */
628  Assert((node->operation == CMD_INSERT &&
629  list_length(node->withCheckOptionLists) == 1 &&
630  list_length(node->plans) == 1) ||
631  (node->operation == CMD_UPDATE &&
633  list_length(node->plans)));
634 
635  /*
636  * Use the WCO list of the first plan as a reference to calculate
637  * attno's for the WCO list of this partition. In the INSERT case,
638  * that refers to the root partitioned table, whereas in the UPDATE
639  * tuple routing case, that refers to the first partition in the
640  * mtstate->resultRelInfo array. In any case, both that relation and
641  * this partition should have the same columns, so we should be able
642  * to map attributes successfully.
643  */
644  wcoList = linitial(node->withCheckOptionLists);
645 
646  /*
647  * Convert Vars in it to contain this partition's attribute numbers.
648  */
649  part_attmap =
651  RelationGetDescr(firstResultRel));
652  wcoList = (List *)
653  map_variable_attnos((Node *) wcoList,
654  firstVarno, 0,
655  part_attmap,
656  RelationGetForm(partrel)->reltype,
657  &found_whole_row);
658  /* We ignore the value of found_whole_row. */
659 
660  foreach(ll, wcoList)
661  {
663  ExprState *wcoExpr = ExecInitQual(castNode(List, wco->qual),
664  &mtstate->ps);
665 
666  wcoExprs = lappend(wcoExprs, wcoExpr);
667  }
668 
669  leaf_part_rri->ri_WithCheckOptions = wcoList;
670  leaf_part_rri->ri_WithCheckOptionExprs = wcoExprs;
671  }
672 
673  /*
674  * Build the RETURNING projection for the partition. Note that we didn't
675  * build the returningList for partitions within the planner, but simple
676  * translation of varattnos will suffice. This only occurs for the INSERT
677  * case or in the case of UPDATE tuple routing where we didn't find a
678  * result rel to reuse in ExecSetupPartitionTupleRouting().
679  */
680  if (node && node->returningLists != NIL)
681  {
682  TupleTableSlot *slot;
683  ExprContext *econtext;
684  List *returningList;
685  int firstVarno = mtstate->resultRelInfo[0].ri_RangeTableIndex;
686 
687  /* See the comment above for WCO lists. */
688  Assert((node->operation == CMD_INSERT &&
689  list_length(node->returningLists) == 1 &&
690  list_length(node->plans) == 1) ||
691  (node->operation == CMD_UPDATE &&
692  list_length(node->returningLists) ==
693  list_length(node->plans)));
694 
695  /*
696  * Use the RETURNING list of the first plan as a reference to
697  * calculate attno's for the RETURNING list of this partition. See
698  * the comment above for WCO lists for more details on why this is
699  * okay.
700  */
701  returningList = linitial(node->returningLists);
702 
703  /*
704  * Convert Vars in it to contain this partition's attribute numbers.
705  */
706  if (part_attmap == NULL)
707  part_attmap =
709  RelationGetDescr(firstResultRel));
710  returningList = (List *)
711  map_variable_attnos((Node *) returningList,
712  firstVarno, 0,
713  part_attmap,
714  RelationGetForm(partrel)->reltype,
715  &found_whole_row);
716  /* We ignore the value of found_whole_row. */
717 
718  leaf_part_rri->ri_returningList = returningList;
719 
720  /*
721  * Initialize the projection itself.
722  *
723  * Use the slot and the expression context that would have been set up
724  * in ExecInitModifyTable() for projection's output.
725  */
726  Assert(mtstate->ps.ps_ResultTupleSlot != NULL);
727  slot = mtstate->ps.ps_ResultTupleSlot;
728  Assert(mtstate->ps.ps_ExprContext != NULL);
729  econtext = mtstate->ps.ps_ExprContext;
730  leaf_part_rri->ri_projectReturning =
731  ExecBuildProjectionInfo(returningList, econtext, slot,
732  &mtstate->ps, RelationGetDescr(partrel));
733  }
734 
735  /* Set up information needed for routing tuples to the partition. */
736  ExecInitRoutingInfo(mtstate, estate, proute, dispatch,
737  leaf_part_rri, partidx);
738 
739  /*
740  * If there is an ON CONFLICT clause, initialize state for it.
741  */
742  if (node && node->onConflictAction != ONCONFLICT_NONE)
743  {
744  int firstVarno = mtstate->resultRelInfo[0].ri_RangeTableIndex;
745  TupleDesc partrelDesc = RelationGetDescr(partrel);
746  ExprContext *econtext = mtstate->ps.ps_ExprContext;
747  ListCell *lc;
748  List *arbiterIndexes = NIL;
749 
750  /*
751  * If there is a list of arbiter indexes, map it to a list of indexes
752  * in the partition. We do that by scanning the partition's index
753  * list and searching for ancestry relationships to each index in the
754  * ancestor table.
755  */
756  if (list_length(rootResultRelInfo->ri_onConflictArbiterIndexes) > 0)
757  {
758  List *childIdxs;
759 
760  childIdxs = RelationGetIndexList(leaf_part_rri->ri_RelationDesc);
761 
762  foreach(lc, childIdxs)
763  {
764  Oid childIdx = lfirst_oid(lc);
765  List *ancestors;
766  ListCell *lc2;
767 
768  ancestors = get_partition_ancestors(childIdx);
769  foreach(lc2, rootResultRelInfo->ri_onConflictArbiterIndexes)
770  {
771  if (list_member_oid(ancestors, lfirst_oid(lc2)))
772  arbiterIndexes = lappend_oid(arbiterIndexes, childIdx);
773  }
774  list_free(ancestors);
775  }
776  }
777 
778  /*
779  * If the resulting lists are of inequal length, something is wrong.
780  * (This shouldn't happen, since arbiter index selection should not
781  * pick up an invalid index.)
782  */
783  if (list_length(rootResultRelInfo->ri_onConflictArbiterIndexes) !=
784  list_length(arbiterIndexes))
785  elog(ERROR, "invalid arbiter index list");
786  leaf_part_rri->ri_onConflictArbiterIndexes = arbiterIndexes;
787 
788  /*
789  * In the DO UPDATE case, we have some more state to initialize.
790  */
791  if (node->onConflictAction == ONCONFLICT_UPDATE)
792  {
793  TupleConversionMap *map;
794 
795  map = leaf_part_rri->ri_RootToPartitionMap;
796 
797  Assert(node->onConflictSet != NIL);
798  Assert(rootResultRelInfo->ri_onConflict != NULL);
799 
800  leaf_part_rri->ri_onConflict = makeNode(OnConflictSetState);
801 
802  /*
803  * Need a separate existing slot for each partition, as the
804  * partition could be of a different AM, even if the tuple
805  * descriptors match.
806  */
807  leaf_part_rri->ri_onConflict->oc_Existing =
808  table_slot_create(leaf_part_rri->ri_RelationDesc,
809  &mtstate->ps.state->es_tupleTable);
810 
811  /*
812  * If the partition's tuple descriptor matches exactly the root
813  * parent (the common case), we can re-use most of the parent's ON
814  * CONFLICT SET state, skipping a bunch of work. Otherwise, we
815  * need to create state specific to this partition.
816  */
817  if (map == NULL)
818  {
819  /*
820  * It's safe to reuse these from the partition root, as we
821  * only process one tuple at a time (therefore we won't
822  * overwrite needed data in slots), and the results of
823  * projections are independent of the underlying storage.
824  * Projections and where clauses themselves don't store state
825  * / are independent of the underlying storage.
826  */
827  leaf_part_rri->ri_onConflict->oc_ProjSlot =
828  rootResultRelInfo->ri_onConflict->oc_ProjSlot;
829  leaf_part_rri->ri_onConflict->oc_ProjInfo =
830  rootResultRelInfo->ri_onConflict->oc_ProjInfo;
831  leaf_part_rri->ri_onConflict->oc_WhereClause =
832  rootResultRelInfo->ri_onConflict->oc_WhereClause;
833  }
834  else
835  {
836  List *onconflset;
837  TupleDesc tupDesc;
838  bool found_whole_row;
839 
840  /*
841  * Translate expressions in onConflictSet to account for
842  * different attribute numbers. For that, map partition
843  * varattnos twice: first to catch the EXCLUDED
844  * pseudo-relation (INNER_VAR), and second to handle the main
845  * target relation (firstVarno).
846  */
847  onconflset = (List *) copyObject((Node *) node->onConflictSet);
848  if (part_attmap == NULL)
849  part_attmap =
851  RelationGetDescr(firstResultRel));
852  onconflset = (List *)
853  map_variable_attnos((Node *) onconflset,
854  INNER_VAR, 0,
855  part_attmap,
856  RelationGetForm(partrel)->reltype,
857  &found_whole_row);
858  /* We ignore the value of found_whole_row. */
859  onconflset = (List *)
860  map_variable_attnos((Node *) onconflset,
861  firstVarno, 0,
862  part_attmap,
863  RelationGetForm(partrel)->reltype,
864  &found_whole_row);
865  /* We ignore the value of found_whole_row. */
866 
867  /* Finally, adjust this tlist to match the partition. */
868  onconflset = adjust_partition_tlist(onconflset, map);
869 
870  /* create the tuple slot for the UPDATE SET projection */
871  tupDesc = ExecTypeFromTL(onconflset);
872  leaf_part_rri->ri_onConflict->oc_ProjSlot =
873  ExecInitExtraTupleSlot(mtstate->ps.state, tupDesc,
874  &TTSOpsVirtual);
875 
876  /* build UPDATE SET projection state */
877  leaf_part_rri->ri_onConflict->oc_ProjInfo =
878  ExecBuildProjectionInfo(onconflset, econtext,
879  leaf_part_rri->ri_onConflict->oc_ProjSlot,
880  &mtstate->ps, partrelDesc);
881 
882  /*
883  * If there is a WHERE clause, initialize state where it will
884  * be evaluated, mapping the attribute numbers appropriately.
885  * As with onConflictSet, we need to map partition varattnos
886  * to the partition's tupdesc.
887  */
888  if (node->onConflictWhere)
889  {
890  List *clause;
891 
892  clause = copyObject((List *) node->onConflictWhere);
893  clause = (List *)
894  map_variable_attnos((Node *) clause,
895  INNER_VAR, 0,
896  part_attmap,
897  RelationGetForm(partrel)->reltype,
898  &found_whole_row);
899  /* We ignore the value of found_whole_row. */
900  clause = (List *)
901  map_variable_attnos((Node *) clause,
902  firstVarno, 0,
903  part_attmap,
904  RelationGetForm(partrel)->reltype,
905  &found_whole_row);
906  /* We ignore the value of found_whole_row. */
907  leaf_part_rri->ri_onConflict->oc_WhereClause =
908  ExecInitQual((List *) clause, &mtstate->ps);
909  }
910  }
911  }
912  }
913 
914  /*
915  * Also, if transition capture is required, store a map to convert tuples
916  * from partition's rowtype to the root partition table's.
917  */
918  if (mtstate->mt_transition_capture || mtstate->mt_oc_transition_capture)
919  leaf_part_rri->ri_ChildToRootMap =
920  convert_tuples_by_name(RelationGetDescr(leaf_part_rri->ri_RelationDesc),
921  RelationGetDescr(leaf_part_rri->ri_PartitionRoot));
922 
923  /*
924  * Since we've just initialized this ResultRelInfo, it's not in any list
925  * attached to the estate as yet. Add it, so that it can be found later.
926  *
927  * Note that the entries in this list appear in no predetermined order,
928  * because partition result rels are initialized as and when they're
929  * needed.
930  */
934  leaf_part_rri);
935 
936  MemoryContextSwitchTo(oldcxt);
937 
938  return leaf_part_rri;
939 }
TupleTableSlot * table_slot_create(Relation relation, List **reglist)
Definition: tableam.c:91
#define NIL
Definition: pg_list.h:65
struct TransitionCaptureState * mt_oc_transition_capture
Definition: execnodes.h:1182
void InitResultRelInfo(ResultRelInfo *resultRelInfo, Relation resultRelationDesc, Index resultRelationIndex, Relation partition_root, int instrument_options)
Definition: execMain.c:1196
Relation ri_RelationDesc
Definition: execnodes.h:412
PartitionDesc partdesc
TupleTableSlot * ExecInitExtraTupleSlot(EState *estate, TupleDesc tupledesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1801
#define RelationGetDescr(relation)
Definition: rel.h:483
List * withCheckOptionLists
Definition: plannodes.h:222
#define castNode(_type_, nodeptr)
Definition: nodes.h:596
ResultRelInfo * resultRelInfo
Definition: execnodes.h:1157
#define RelationGetForm(relation)
Definition: rel.h:451
ExprContext * ps_ExprContext
Definition: execnodes.h:967
const TupleTableSlotOps TTSOpsVirtual
Definition: execTuples.c:83
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
Definition: nodes.h:527
EState * state
Definition: execnodes.h:930
Node * map_variable_attnos(Node *node, int target_varno, int sublevels_up, const AttrMap *attno_map, Oid to_rowtype, bool *found_whole_row)
unsigned int Oid
Definition: postgres_ext.h:31
List * lappend_oid(List *list, Oid datum)
Definition: list.c:357
List * plans
Definition: plannodes.h:221
ExprState * ExecInitQual(List *qual, PlanState *parent)
Definition: execExpr.c:208
Index ri_RangeTableIndex
Definition: execnodes.h:409
List * onConflictSet
Definition: plannodes.h:230
Definition: attmap.h:34
Index rootRelation
Definition: plannodes.h:218
void ExecOpenIndices(ResultRelInfo *resultRelInfo, bool speculative)
Definition: execIndexing.c:151
TupleTableSlot * ps_ResultTupleSlot
Definition: execnodes.h:966
MemoryContext es_query_cxt
Definition: execnodes.h:559
#define linitial(l)
Definition: pg_list.h:174
#define ERROR
Definition: elog.h:43
PlanState ps
Definition: execnodes.h:1148
ProjectionInfo * oc_ProjInfo
Definition: execnodes.h:386
void CheckValidResultRel(ResultRelInfo *resultRelInfo, CmdType operation)
Definition: execMain.c:995
TupleConversionMap * convert_tuples_by_name(TupleDesc indesc, TupleDesc outdesc)
Definition: tupconvert.c:102
struct TransitionCaptureState * mt_transition_capture
Definition: execnodes.h:1179
#define RowExclusiveLock
Definition: lockdefs.h:38
int es_instrument
Definition: execnodes.h:566
ExprState * oc_WhereClause
Definition: execnodes.h:387
List * lappend(List *list, void *datum)
Definition: list.c:321
OnConflictSetState * ri_onConflict
Definition: execnodes.h:477
List * es_tupleTable
Definition: execnodes.h:561
Plan * plan
Definition: execnodes.h:928
List * es_tuple_routing_result_relations
Definition: execnodes.h:547
TupleTableSlot * oc_ProjSlot
Definition: execnodes.h:385
#define INNER_VAR
Definition: primnodes.h:171
AttrMap * build_attrmap_by_name(TupleDesc indesc, TupleDesc outdesc)
Definition: attmap.c:174
#define makeNode(_type_)
Definition: nodes.h:575
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:674
#define Assert(condition)
Definition: c.h:800
#define lfirst(lc)
Definition: pg_list.h:169
OnConflictAction onConflictAction
Definition: plannodes.h:228
static List * adjust_partition_tlist(List *tlist, TupleConversionMap *map)
static int list_length(const List *l)
Definition: pg_list.h:149
TupleDesc ExecTypeFromTL(List *targetList)
Definition: execTuples.c:1908
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4515
ProjectionInfo * ExecBuildProjectionInfo(List *targetList, ExprContext *econtext, TupleTableSlot *slot, PlanState *parent, TupleDesc inputDesc)
Definition: execExpr.c:352
CmdType operation
Definition: plannodes.h:215
void list_free(List *list)
Definition: list.c:1376
#define elog(elevel,...)
Definition: elog.h:228
List * returningLists
Definition: plannodes.h:223
MemoryContext memcxt
#define copyObject(obj)
Definition: nodes.h:643
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: pg_list.h:50
List * get_partition_ancestors(Oid relid)
Definition: partition.c:115
static void ExecInitRoutingInfo(ModifyTableState *mtstate, EState *estate, PartitionTupleRouting *proute, PartitionDispatch dispatch, ResultRelInfo *partRelInfo, int partidx)
List * ri_onConflictArbiterIndexes
Definition: execnodes.h:474
#define lfirst_oid(lc)
Definition: pg_list.h:171
Node * onConflictWhere
Definition: plannodes.h:231

◆ ExecInitPruningContext()

static void ExecInitPruningContext ( PartitionPruneContext context,
List pruning_steps,
PartitionDesc  partdesc,
PartitionKey  partkey,
PlanState planstate 
)
static

Definition at line 1833 of file execPartition.c.

References Assert, PartitionDescData::boundinfo, PartitionPruneContext::boundinfo, CurrentMemoryContext, ExecInitExpr(), PartitionPruneStepOp::exprs, PartitionPruneContext::exprstates, IsA, lfirst, list_length(), PartitionDescData::nparts, PartitionPruneContext::nparts, palloc0(), PartitionKeyData::partcollation, PartitionPruneContext::partcollation, PartitionKeyData::partnatts, PartitionPruneContext::partnatts, PartitionKeyData::partsupfunc, PartitionPruneContext::partsupfunc, PartitionPruneContext::planstate, PartitionPruneContext::ppccontext, PruneCxtStateIdx, PartitionPruneStepOp::step, PartitionPruneStep::step_id, PartitionPruneContext::stepcmpfuncs, PartitionKeyData::strategy, and PartitionPruneContext::strategy.

Referenced by ExecCreatePartitionPruneState().

1838 {
1839  int n_steps;
1840  int partnatts;
1841  ListCell *lc;
1842 
1843  n_steps = list_length(pruning_steps);
1844 
1845  context->strategy = partkey->strategy;
1846  context->partnatts = partnatts = partkey->partnatts;
1847  context->nparts = partdesc->nparts;
1848  context->boundinfo = partdesc->boundinfo;
1849  context->partcollation = partkey->partcollation;
1850  context->partsupfunc = partkey->partsupfunc;
1851 
1852  /* We'll look up type-specific support functions as needed */
1853  context->stepcmpfuncs = (FmgrInfo *)
1854  palloc0(sizeof(FmgrInfo) * n_steps * partnatts);
1855 
1856  context->ppccontext = CurrentMemoryContext;
1857  context->planstate = planstate;
1858 
1859  /* Initialize expression state for each expression we need */
1860  context->exprstates = (ExprState **)
1861  palloc0(sizeof(ExprState *) * n_steps * partnatts);
1862  foreach(lc, pruning_steps)
1863  {
1865  ListCell *lc2;
1866  int keyno;
1867 
1868  /* not needed for other step kinds */
1869  if (!IsA(step, PartitionPruneStepOp))
1870  continue;
1871 
1872  Assert(list_length(step->exprs) <= partnatts);
1873 
1874  keyno = 0;
1875  foreach(lc2, step->exprs)
1876  {
1877  Expr *expr = (Expr *) lfirst(lc2);
1878 
1879  /* not needed for Consts */
1880  if (!IsA(expr, Const))
1881  {
1882  int stateidx = PruneCxtStateIdx(partnatts,
1883  step->step.step_id,
1884  keyno);
1885 
1886  context->exprstates[stateidx] =
1887  ExecInitExpr(expr, context->planstate);
1888  }
1889  keyno++;
1890  }
1891  }
1892 }
Definition: fmgr.h:56
FmgrInfo * partsupfunc
Definition: partprune.h:55
#define IsA(nodeptr, _type_)
Definition: nodes.h:578
FmgrInfo * stepcmpfuncs
Definition: partprune.h:56
FmgrInfo * partsupfunc
Definition: partcache.h:35
MemoryContext ppccontext
Definition: partprune.h:57
PartitionBoundInfo boundinfo
Definition: partdesc.h:29
ExprState ** exprstates
Definition: partprune.h:59
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
PartitionPruneStep step
Definition: plannodes.h:1206
Oid * partcollation
Definition: partcache.h:38
void * palloc0(Size size)
Definition: mcxt.c:981
#define Assert(condition)
Definition: c.h:800
#define lfirst(lc)
Definition: pg_list.h:169
static int list_length(const List *l)
Definition: pg_list.h:149
PartitionBoundInfo boundinfo
Definition: partprune.h:53
ExprState * ExecInitExpr(Expr *node, PlanState *parent)
Definition: execExpr.c:122
#define PruneCxtStateIdx(partnatts, step_id, keyno)
Definition: partprune.h:68
PlanState * planstate
Definition: partprune.h:58

◆ ExecInitRoutingInfo()

static void ExecInitRoutingInfo ( ModifyTableState mtstate,
EState estate,
PartitionTupleRouting proute,
PartitionDispatch  dispatch,
ResultRelInfo partRelInfo,
int  partidx 
)
static

Definition at line 948 of file execPartition.c.

References Assert, FdwRoutine::BeginForeignInsert, convert_tuples_by_name(), EState::es_tupleTable, PartitionDispatchData::indexes, PartitionTupleRouting::max_partitions, PartitionTupleRouting::memcxt, MemoryContextSwitchTo(), PartitionTupleRouting::num_partitions, palloc(), PartitionTupleRouting::partitions, RelationGetDescr, repalloc(), ResultRelInfo::ri_CopyMultiInsertBuffer, ResultRelInfo::ri_FdwRoutine, ResultRelInfo::ri_PartitionRoot, ResultRelInfo::ri_PartitionTupleSlot, ResultRelInfo::ri_RelationDesc, ResultRelInfo::ri_RootToPartitionMap, and table_slot_create().

Referenced by ExecFindPartition(), and ExecInitPartitionInfo().

954 {
955  MemoryContext oldcxt;
956  int rri_index;
957 
958  oldcxt = MemoryContextSwitchTo(proute->memcxt);
959 
960  /*
961  * Set up a tuple conversion map to convert a tuple routed to the
962  * partition from the parent's type to the partition's.
963  */
964  partRelInfo->ri_RootToPartitionMap =
966  RelationGetDescr(partRelInfo->ri_RelationDesc));
967 
968  /*
969  * If a partition has a different rowtype than the root parent, initialize
970  * a slot dedicated to storing this partition's tuples. The slot is used
971  * for various operations that are applied to tuples after routing, such
972  * as checking constraints.
973  */
974  if (partRelInfo->ri_RootToPartitionMap != NULL)
975  {
976  Relation partrel = partRelInfo->ri_RelationDesc;
977 
978  /*
979  * Initialize the slot itself setting its descriptor to this
980  * partition's TupleDesc; TupleDesc reference will be released at the
981  * end of the command.
982  */
983  partRelInfo->ri_PartitionTupleSlot =
984  table_slot_create(partrel, &estate->es_tupleTable);
985  }
986  else
987  partRelInfo->ri_PartitionTupleSlot = NULL;
988 
989  /*
990  * If the partition is a foreign table, let the FDW init itself for
991  * routing tuples to the partition.
992  */
993  if (partRelInfo->ri_FdwRoutine != NULL &&
994  partRelInfo->ri_FdwRoutine->BeginForeignInsert != NULL)
995  partRelInfo->ri_FdwRoutine->BeginForeignInsert(mtstate, partRelInfo);
996 
997  partRelInfo->ri_CopyMultiInsertBuffer = NULL;
998 
999  /*
1000  * Keep track of it in the PartitionTupleRouting->partitions array.
1001  */
1002  Assert(dispatch->indexes[partidx] == -1);
1003 
1004  rri_index = proute->num_partitions++;
1005 
1006  /* Allocate or enlarge the array, as needed */
1007  if (proute->num_partitions >= proute->max_partitions)
1008  {
1009  if (proute->max_partitions == 0)
1010  {
1011  proute->max_partitions = 8;
1012  proute->partitions = (ResultRelInfo **)
1013  palloc(sizeof(ResultRelInfo *) * proute->max_partitions);
1014  }
1015  else
1016  {
1017  proute->max_partitions *= 2;
1018  proute->partitions = (ResultRelInfo **)
1019  repalloc(proute->partitions, sizeof(ResultRelInfo *) *
1020  proute->max_partitions);
1021  }
1022  }
1023 
1024  proute->partitions[rri_index] = partRelInfo;
1025  dispatch->indexes[partidx] = rri_index;
1026 
1027  MemoryContextSwitchTo(oldcxt);
1028 }
TupleTableSlot * table_slot_create(Relation relation, List **reglist)
Definition: tableam.c:91
Relation ri_RelationDesc
Definition: execnodes.h:412
struct CopyMultiInsertBuffer * ri_CopyMultiInsertBuffer
Definition: execnodes.h:502
#define RelationGetDescr(relation)
Definition: rel.h:483
BeginForeignInsert_function BeginForeignInsert
Definition: fdwapi.h:215
Relation ri_PartitionRoot
Definition: execnodes.h:490
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
ResultRelInfo ** partitions
TupleTableSlot * ri_PartitionTupleSlot
Definition: execnodes.h:492
TupleConversionMap * convert_tuples_by_name(TupleDesc indesc, TupleDesc outdesc)
Definition: tupconvert.c:102
struct FdwRoutine * ri_FdwRoutine
Definition: execnodes.h:441
List * es_tupleTable
Definition: execnodes.h:561
#define Assert(condition)
Definition: c.h:800
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1070
void * palloc(Size size)
Definition: mcxt.c:950
TupleConversionMap * ri_RootToPartitionMap
Definition: execnodes.h:491
MemoryContext memcxt
int indexes[FLEXIBLE_ARRAY_MEMBER]

◆ ExecSetupPartitionTupleRouting()

PartitionTupleRouting* ExecSetupPartitionTupleRouting ( EState estate,
ModifyTableState mtstate,
Relation  rel 
)

Definition at line 217 of file execPartition.c.

References CMD_UPDATE, CurrentMemoryContext, ExecHashSubPlanResultRelsByOid(), ExecInitPartitionDispatchInfo(), PartitionTupleRouting::memcxt, ModifyTable::operation, palloc0(), PartitionTupleRouting::partition_root, PlanState::plan, ModifyTableState::ps, and RelationGetRelid.

Referenced by apply_handle_tuple_routing(), CopyFrom(), and ExecInitModifyTable().

219 {
220  PartitionTupleRouting *proute;
221  ModifyTable *node = mtstate ? (ModifyTable *) mtstate->ps.plan : NULL;
222 
223  /*
224  * Here we attempt to expend as little effort as possible in setting up
225  * the PartitionTupleRouting. Each partition's ResultRelInfo is built on
226  * demand, only when we actually need to route a tuple to that partition.
227  * The reason for this is that a common case is for INSERT to insert a
228  * single tuple into a partitioned table and this must be fast.
229  */
231  proute->partition_root = rel;
232  proute->memcxt = CurrentMemoryContext;
233  /* Rest of members initialized by zeroing */
234 
235  /*
236  * Initialize this table's PartitionDispatch object. Here we pass in the
237  * parent as NULL as we don't need to care about any parent of the target
238  * partitioned table.
239  */
240  ExecInitPartitionDispatchInfo(estate, proute, RelationGetRelid(rel),
241  NULL, 0);
242 
243  /*
244  * If performing an UPDATE with tuple routing, we can reuse partition
245  * sub-plan result rels. We build a hash table to map the OIDs of
246  * partitions present in mtstate->resultRelInfo to their ResultRelInfos.
247  * Every time a tuple is routed to a partition that we've yet to set the
248  * ResultRelInfo for, before we go to the trouble of making one, we check
249  * for a pre-made one in the hash table.
250  */
251  if (node && node->operation == CMD_UPDATE)
252  ExecHashSubPlanResultRelsByOid(mtstate, proute);
253 
254  return proute;
255 }
static void ExecHashSubPlanResultRelsByOid(ModifyTableState *mtstate, PartitionTupleRouting *proute)
PlanState ps
Definition: execnodes.h:1148
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
void * palloc0(Size size)
Definition: mcxt.c:981
static PartitionDispatch ExecInitPartitionDispatchInfo(EState *estate, PartitionTupleRouting *proute, Oid partoid, PartitionDispatch parent_pd, int partidx)
Plan * plan
Definition: execnodes.h:928
CmdType operation
Definition: plannodes.h:215
MemoryContext memcxt
#define RelationGetRelid(relation)
Definition: rel.h:457

◆ find_matching_subplans_recurse()

static void find_matching_subplans_recurse ( PartitionPruningData prunedata,
PartitionedRelPruningData pprune,
bool  initial_prune,
Bitmapset **  validsubplans 
)
static

Definition at line 2137 of file execPartition.c.

References bms_add_member(), bms_next_member(), check_stack_depth(), PartitionedRelPruningData::exec_context, PartitionedRelPruningData::exec_pruning_steps, get_matching_partitions(), i, PartitionedRelPruningData::initial_context, PartitionedRelPruningData::initial_pruning_steps, PartitionPruningData::partrelprunedata, PartitionedRelPruningData::present_parts, PartitionedRelPruningData::subpart_map, and PartitionedRelPruningData::subplan_map.

Referenced by ExecFindInitialMatchingSubPlans(), and ExecFindMatchingSubPlans().

2141 {
2142  Bitmapset *partset;
2143  int i;
2144 
2145  /* Guard against stack overflow due to overly deep partition hierarchy. */
2147 
2148  /* Only prune if pruning would be useful at this level. */
2149  if (initial_prune && pprune->initial_pruning_steps)
2150  {
2151  partset = get_matching_partitions(&pprune->initial_context,
2152  pprune->initial_pruning_steps);
2153  }
2154  else if (!initial_prune && pprune->exec_pruning_steps)
2155  {
2156  partset = get_matching_partitions(&pprune->exec_context,
2157  pprune->exec_pruning_steps);
2158  }
2159  else
2160  {
2161  /*
2162  * If no pruning is to be done, just include all partitions at this
2163  * level.
2164  */
2165  partset = pprune->present_parts;
2166  }
2167 
2168  /* Translate partset into subplan indexes */
2169  i = -1;
2170  while ((i = bms_next_member(partset, i)) >= 0)
2171  {
2172  if (pprune->subplan_map[i] >= 0)
2173  *validsubplans = bms_add_member(*validsubplans,
2174  pprune->subplan_map[i]);
2175  else
2176  {
2177  int partidx = pprune->subpart_map[i];
2178 
2179  if (partidx >= 0)
2181  &prunedata->partrelprunedata[partidx],
2182  initial_prune, validsubplans);
2183  else
2184  {
2185  /*
2186  * We get here if the planner already pruned all the sub-
2187  * partitions for this partition. Silently ignore this
2188  * partition in this case. The end result is the same: we
2189  * would have pruned all partitions just the same, but we
2190  * don't have any pruning steps to execute to verify this.
2191  */
2192  }
2193  }
2194  }
2195 }
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1043
static void find_matching_subplans_recurse(PartitionPruningData *prunedata, PartitionedRelPruningData *pprune, bool initial_prune, Bitmapset **validsubplans)
void check_stack_depth(void)
Definition: postgres.c:3317
PartitionPruneContext exec_context
Definition: execPartition.h:57
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:736
PartitionedRelPruningData partrelprunedata[FLEXIBLE_ARRAY_MEMBER]
Definition: execPartition.h:70
Bitmapset * get_matching_partitions(PartitionPruneContext *context, List *pruning_steps)
Definition: partprune.c:721
int i
PartitionPruneContext initial_context
Definition: execPartition.h:56

◆ FormPartitionKeyDatum()

static void FormPartitionKeyDatum ( PartitionDispatch  pd,
TupleTableSlot slot,
EState estate,
Datum values,
bool isnull 
)
static

Definition at line 1239 of file execPartition.c.

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

Referenced by ExecFindPartition().

1244 {
1245  ListCell *partexpr_item;
1246  int i;
1247 
1248  if (pd->key->partexprs != NIL && pd->keystate == NIL)
1249  {
1250  /* Check caller has set up context correctly */
1251  Assert(estate != NULL &&
1252  GetPerTupleExprContext(estate)->ecxt_scantuple == slot);
1253 
1254  /* First time through, set up expression evaluation state */
1255  pd->keystate = ExecPrepareExprList(pd->key->partexprs, estate);
1256  }
1257 
1258  partexpr_item = list_head(pd->keystate);
1259  for (i = 0; i < pd->key->partnatts; i++)
1260  {
1261  AttrNumber keycol = pd->key->partattrs[i];
1262  Datum datum;
1263  bool isNull;
1264 
1265  if (keycol != 0)
1266  {
1267  /* Plain column; get the value directly from the heap tuple */
1268  datum = slot_getattr(slot, keycol, &isNull);
1269  }
1270  else
1271  {
1272  /* Expression; need to evaluate it */
1273  if (partexpr_item == NULL)
1274  elog(ERROR, "wrong number of partition key expressions");
1275  datum = ExecEvalExprSwitchContext((ExprState *) lfirst(partexpr_item),
1276  GetPerTupleExprContext(estate),
1277  &isNull);
1278  partexpr_item = lnext(pd->keystate, partexpr_item);
1279  }
1280  values[i] = datum;
1281  isnull[i] = isNull;
1282  }
1283 
1284  if (partexpr_item != NULL)
1285  elog(ERROR, "wrong number of partition key expressions");
1286 }
#define NIL
Definition: pg_list.h:65
static Datum ExecEvalExprSwitchContext(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:307
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:310
List * partexprs
Definition: partcache.h:30
#define GetPerTupleExprContext(estate)
Definition: executor.h:509
#define ERROR
Definition: elog.h:43
static ListCell * list_head(const List *l)
Definition: pg_list.h:125
List * ExecPrepareExprList(List *nodes, EState *estate)
Definition: execExpr.c:565
AttrNumber * partattrs
Definition: partcache.h:28
uintptr_t Datum
Definition: postgres.h:367
static Datum slot_getattr(TupleTableSlot *slot, int attnum, bool *isnull)
Definition: tuptable.h:381
#define Assert(condition)
Definition: c.h:800
#define lfirst(lc)
Definition: pg_list.h:169
static Datum values[MAXATTR]
Definition: bootstrap.c:165
#define elog(elevel,...)
Definition: elog.h:228
int i
int16 AttrNumber
Definition: attnum.h:21

◆ get_partition_for_tuple()

static int get_partition_for_tuple ( PartitionDispatch  pd,
Datum values,
bool isnull 
)
static

Definition at line 1297 of file execPartition.c.

References PartitionDescData::boundinfo, compute_partition_hash_value(), PartitionBoundInfoData::default_index, elog, equal(), ERROR, get_hash_partition_greatest_modulus(), i, PartitionBoundInfoData::indexes, sort-test::key, PartitionDispatchData::key, PartitionBoundInfoData::null_index, PartitionKeyData::partcollation, PartitionDispatchData::partdesc, partition_bound_accepts_nulls, partition_list_bsearch(), partition_range_datum_bsearch(), PARTITION_STRATEGY_HASH, PARTITION_STRATEGY_LIST, PARTITION_STRATEGY_RANGE, PartitionKeyData::partnatts, PartitionKeyData::partsupfunc, and PartitionKeyData::strategy.

Referenced by ExecFindPartition().

1298 {
1299  int bound_offset;
1300  int part_index = -1;
1301  PartitionKey key = pd->key;
1302  PartitionDesc partdesc = pd->partdesc;
1303  PartitionBoundInfo boundinfo = partdesc->boundinfo;
1304 
1305  /* Route as appropriate based on partitioning strategy. */
1306  switch (key->strategy)
1307  {
1309  {
1310  int greatest_modulus;
1311  uint64 rowHash;
1312 
1313  greatest_modulus = get_hash_partition_greatest_modulus(boundinfo);
1314  rowHash = compute_partition_hash_value(key->partnatts,
1315  key->partsupfunc,
1316  key->partcollation,
1317  values, isnull);
1318 
1319  part_index = boundinfo->indexes[rowHash % greatest_modulus];
1320  }
1321  break;
1322 
1324  if (isnull[0])
1325  {
1326  if (partition_bound_accepts_nulls(boundinfo))
1327  part_index = boundinfo->null_index;
1328  }
1329  else
1330  {
1331  bool equal = false;
1332 
1333  bound_offset = partition_list_bsearch(key->partsupfunc,
1334  key->partcollation,
1335  boundinfo,
1336  values[0], &equal);
1337  if (bound_offset >= 0 && equal)
1338  part_index = boundinfo->indexes[bound_offset];
1339  }
1340  break;
1341 
1343  {
1344  bool equal = false,
1345  range_partkey_has_null = false;
1346  int i;
1347 
1348  /*
1349  * No range includes NULL, so this will be accepted by the
1350  * default partition if there is one, and otherwise rejected.
1351  */
1352  for (i = 0; i < key->partnatts; i++)
1353  {
1354  if (isnull[i])
1355  {
1356  range_partkey_has_null = true;
1357  break;
1358  }
1359  }
1360 
1361  if (!range_partkey_has_null)
1362  {
1363  bound_offset = partition_range_datum_bsearch(key->partsupfunc,
1364  key->partcollation,
1365  boundinfo,
1366  key->partnatts,
1367  values,
1368  &equal);
1369 
1370  /*
1371  * The bound at bound_offset is less than or equal to the
1372  * tuple value, so the bound at offset+1 is the upper
1373  * bound of the partition we're looking for, if there
1374  * actually exists one.
1375  */
1376  part_index = boundinfo->indexes[bound_offset + 1];
1377  }
1378  }
1379  break;
1380 
1381  default:
1382  elog(ERROR, "unexpected partition strategy: %d",
1383  (int) key->strategy);
1384  }
1385 
1386  /*
1387  * part_index < 0 means we failed to find a partition of this parent. Use
1388  * the default partition, if there is one.
1389  */
1390  if (part_index < 0)
1391  part_index = boundinfo->default_index;
1392 
1393  return part_index;
1394 }
PartitionDesc partdesc
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:3029
FmgrInfo * partsupfunc
Definition: partcache.h:35
PartitionBoundInfo boundinfo
Definition: partdesc.h:29
int partition_range_datum_bsearch(FmgrInfo *partsupfunc, Oid *partcollation, PartitionBoundInfo boundinfo, int nvalues, Datum *values, bool *is_equal)
Definition: partbounds.c:3574
#define ERROR
Definition: elog.h:43
int get_hash_partition_greatest_modulus(PartitionBoundInfo bound)
Definition: partbounds.c:3290
Oid * partcollation
Definition: partcache.h:38
#define PARTITION_STRATEGY_HASH
Definition: parsenodes.h:802
#define partition_bound_accepts_nulls(bi)
Definition: partbounds.h:74
int partition_list_bsearch(FmgrInfo *partsupfunc, Oid *partcollation, PartitionBoundInfo boundinfo, Datum value, bool *is_equal)
Definition: partbounds.c:3486
uint64 compute_partition_hash_value(int partnatts, FmgrInfo *partsupfunc, Oid *partcollation, Datum *values, bool *isnull)
Definition: partbounds.c:4644
#define PARTITION_STRATEGY_LIST
Definition: parsenodes.h:803
static Datum values[MAXATTR]
Definition: bootstrap.c:165
#define PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:804
#define elog(elevel,...)
Definition: elog.h:228
int i