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, ResultRelInfo *rootResultRelInfo)
 
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 1516 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().

1517 {
1518  List *new_tlist = NIL;
1519  TupleDesc tupdesc = map->outdesc;
1520  AttrMap *attrMap = map->attrMap;
1521  AttrNumber attrno;
1522 
1523  Assert(tupdesc->natts == attrMap->maplen);
1524  for (attrno = 1; attrno <= tupdesc->natts; attrno++)
1525  {
1526  Form_pg_attribute att_tup = TupleDescAttr(tupdesc, attrno - 1);
1527  TargetEntry *tle;
1528 
1529  if (attrMap->attnums[attrno - 1] != InvalidAttrNumber)
1530  {
1531  Assert(!att_tup->attisdropped);
1532 
1533  /*
1534  * Use the corresponding entry from the parent's tlist, adjusting
1535  * the resno the match the partition's attno.
1536  */
1537  tle = (TargetEntry *) list_nth(tlist, attrMap->attnums[attrno - 1] - 1);
1538  tle->resno = attrno;
1539  }
1540  else
1541  {
1542  Const *expr;
1543 
1544  /*
1545  * For a dropped attribute in the partition, generate a dummy
1546  * entry with resno matching the partition's attno.
1547  */
1548  Assert(att_tup->attisdropped);
1549  expr = makeConst(INT4OID,
1550  -1,
1551  InvalidOid,
1552  sizeof(int32),
1553  (Datum) 0,
1554  true, /* isnull */
1555  true /* byval */ );
1556  tle = makeTargetEntry((Expr *) expr,
1557  attrno,
1558  pstrdup(NameStr(att_tup->attname)),
1559  false);
1560  }
1561 
1562  new_tlist = lappend(new_tlist, tle);
1563  }
1564 
1565  return new_tlist;
1566 }
#define NIL
Definition: pg_list.h:65
TupleDesc outdesc
Definition: tupconvert.h:27
#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:429
Definition: attmap.h:34
static void * list_nth(const List *list, int n)
Definition: pg_list.h:278
AttrNumber resno
Definition: primnodes.h:1432
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:197
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:238
AttrMap * attrMap
Definition: tupconvert.h:28
List * lappend(List *list, void *datum)
Definition: list.c:336
uintptr_t Datum
Definition: postgres.h:367
#define InvalidOid
Definition: postgres_ext.h:36
#define Assert(condition)
Definition: c.h:804
AttrNumber * attnums
Definition: attmap.h:36
#define InvalidAttrNumber
Definition: attnum.h:23
#define NameStr(name)
Definition: c.h:681
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 1420 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().

1424 {
1427  int partnatts = get_partition_natts(key);
1428  int i;
1429  Oid relid = RelationGetRelid(rel);
1430  AclResult aclresult;
1431 
1432  if (check_enable_rls(relid, InvalidOid, true) == RLS_ENABLED)
1433  return NULL;
1434 
1435  /* If the user has table-level access, just go build the description. */
1436  aclresult = pg_class_aclcheck(relid, GetUserId(), ACL_SELECT);
1437  if (aclresult != ACLCHECK_OK)
1438  {
1439  /*
1440  * Step through the columns of the partition key and make sure the
1441  * user has SELECT rights on all of them.
1442  */
1443  for (i = 0; i < partnatts; i++)
1444  {
1446 
1447  /*
1448  * If this partition key column is an expression, we return no
1449  * detail rather than try to figure out what column(s) the
1450  * expression includes and if the user has SELECT rights on them.
1451  */
1452  if (attnum == InvalidAttrNumber ||
1453  pg_attribute_aclcheck(relid, attnum, GetUserId(),
1454  ACL_SELECT) != ACLCHECK_OK)
1455  return NULL;
1456  }
1457  }
1458 
1459  initStringInfo(&buf);
1460  appendStringInfo(&buf, "(%s) = (",
1461  pg_get_partkeydef_columns(relid, true));
1462 
1463  for (i = 0; i < partnatts; i++)
1464  {
1465  char *val;
1466  int vallen;
1467 
1468  if (isnull[i])
1469  val = "null";
1470  else
1471  {
1472  Oid foutoid;
1473  bool typisvarlena;
1474 
1476  &foutoid, &typisvarlena);
1477  val = OidOutputFunctionCall(foutoid, values[i]);
1478  }
1479 
1480  if (i > 0)
1481  appendStringInfoString(&buf, ", ");
1482 
1483  /* truncate if needed */
1484  vallen = strlen(val);
1485  if (vallen <= maxfieldlen)
1486  appendBinaryStringInfo(&buf, val, vallen);
1487  else
1488  {
1489  vallen = pg_mbcliplen(val, vallen, maxfieldlen);
1490  appendBinaryStringInfo(&buf, val, vallen);
1491  appendStringInfoString(&buf, "...");
1492  }
1493  }
1494 
1495  appendStringInfoChar(&buf, ')');
1496 
1497  return buf.data;
1498 }
char * pg_get_partkeydef_columns(Oid relid, bool pretty)
Definition: ruleutils.c:1660
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
Definition: lsyscache.c:2854
AclResult pg_attribute_aclcheck(Oid table_oid, AttrNumber attnum, Oid roleid, AclMode mode)
Definition: aclchk.c:4468
Oid GetUserId(void)
Definition: miscinit.c:478
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:83
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:4582
static Datum values[MAXATTR]
Definition: bootstrap.c:165
char * OidOutputFunctionCall(Oid functionId, Datum val)
Definition: fmgr.c:1656
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 1186 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().

1188 {
1189  HTAB *htab = proute->subplan_resultrel_htab;
1190  int i;
1191 
1192  /*
1193  * Remember, proute->partition_dispatch_info[0] corresponds to the root
1194  * partitioned table, which we must not try to close, because it is the
1195  * main target table of the query that will be closed by callers such as
1196  * ExecEndPlan() or DoCopy(). Also, tupslot is NULL for the root
1197  * partitioned table.
1198  */
1199  for (i = 1; i < proute->num_dispatch; i++)
1200  {
1202 
1203  table_close(pd->reldesc, NoLock);
1204 
1205  if (pd->tupslot)
1207  }
1208 
1209  for (i = 0; i < proute->num_partitions; i++)
1210  {
1211  ResultRelInfo *resultRelInfo = proute->partitions[i];
1212 
1213  /* Allow any FDWs to shut down */
1214  if (resultRelInfo->ri_FdwRoutine != NULL &&
1215  resultRelInfo->ri_FdwRoutine->EndForeignInsert != NULL)
1216  resultRelInfo->ri_FdwRoutine->EndForeignInsert(mtstate->ps.state,
1217  resultRelInfo);
1218 
1219  /*
1220  * Check if this result rel is one belonging to the node's subplans,
1221  * if so, let ExecEndPlan() clean it up.
1222  */
1223  if (htab)
1224  {
1225  Oid partoid;
1226  bool found;
1227 
1228  partoid = RelationGetRelid(resultRelInfo->ri_RelationDesc);
1229 
1230  (void) hash_search(htab, &partoid, HASH_FIND, &found);
1231  if (found)
1232  continue;
1233  }
1234 
1235  ExecCloseIndices(resultRelInfo);
1236  table_close(resultRelInfo->ri_RelationDesc, NoLock);
1237  }
1238 }
Relation ri_RelationDesc
Definition: execnodes.h:415
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:954
EState * state
Definition: execnodes.h:943
unsigned int Oid
Definition: postgres_ext.h:31
ResultRelInfo ** partitions
Definition: dynahash.c:219
PlanState ps
Definition: execnodes.h:1161
#define NoLock
Definition: lockdefs.h:34
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:1224
struct FdwRoutine * ri_FdwRoutine
Definition: execnodes.h:444
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:231
EndForeignInsert_function EndForeignInsert
Definition: fdwapi.h:226

◆ ExecCreatePartitionPruneState()

PartitionPruneState* ExecCreatePartitionPruneState ( PlanState planstate,
PartitionPruneInfo partitionpruneinfo 
)

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

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

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

2095 {
2096  Bitmapset *result = NULL;
2097  MemoryContext oldcontext;
2098  int i;
2099 
2100  /*
2101  * If !do_exec_prune, we've got problems because
2102  * ExecFindInitialMatchingSubPlans will not have bothered to update
2103  * prunestate for whatever pruning it did.
2104  */
2105  Assert(prunestate->do_exec_prune);
2106 
2107  /*
2108  * Switch to a temp context to avoid leaking memory in the executor's
2109  * query-lifespan memory context.
2110  */
2111  oldcontext = MemoryContextSwitchTo(prunestate->prune_context);
2112 
2113  /*
2114  * For each hierarchy, do the pruning tests, and add nondeletable
2115  * subplans' indexes to "result".
2116  */
2117  for (i = 0; i < prunestate->num_partprunedata; i++)
2118  {
2119  PartitionPruningData *prunedata;
2120  PartitionedRelPruningData *pprune;
2121 
2122  prunedata = prunestate->partprunedata[i];
2123  pprune = &prunedata->partrelprunedata[0];
2124 
2125  find_matching_subplans_recurse(prunedata, pprune, false, &result);
2126 
2127  /* Expression eval may have used space in node's ps_ExprContext too */
2128  if (pprune->exec_pruning_steps)
2130  }
2131 
2132  /* Add in any subplans that partition pruning didn't account for */
2133  result = bms_add_members(result, prunestate->other_subplans);
2134 
2135  MemoryContextSwitchTo(oldcontext);
2136 
2137  /* Copy result out of the temp context before we reset it */
2138  result = bms_copy(result);
2139 
2140  MemoryContextReset(prunestate->prune_context);
2141 
2142  return result;
2143 }
MemoryContext prune_context
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:74
ExprContext * ps_ExprContext
Definition: execnodes.h:980
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:804
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 278 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, RelationData::rd_rel, RelationGetRelationName, RelationGetRelid, PartitionDispatchData::reldesc, ResultRelInfo::ri_PartitionTupleSlot, ResultRelInfo::ri_RelationDesc, ResultRelInfo::ri_RootToPartitionMap, ModifyTableState::rootResultRelInfo, SubplanResultRelHashElem::rri, PartitionTupleRouting::subplan_resultrel_htab, PartitionDispatchData::tupmap, PartitionDispatchData::tupslot, and values.

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

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

Referenced by ExecSetupPartitionTupleRouting().

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

◆ ExecInitPartitionDispatchInfo()

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

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

1061 {
1062  Relation rel;
1063  PartitionDesc partdesc;
1064  PartitionDispatch pd;
1065  int dispatchidx;
1066  MemoryContext oldcxt;
1067 
1068  if (estate->es_partition_directory == NULL)
1069  estate->es_partition_directory =
1071 
1072  oldcxt = MemoryContextSwitchTo(proute->memcxt);
1073 
1074  /*
1075  * Only sub-partitioned tables need to be locked here. The root
1076  * partitioned table will already have been locked as it's referenced in
1077  * the query's rtable.
1078  */
1079  if (partoid != RelationGetRelid(proute->partition_root))
1080  rel = table_open(partoid, RowExclusiveLock);
1081  else
1082  rel = proute->partition_root;
1083  partdesc = PartitionDirectoryLookup(estate->es_partition_directory, rel);
1084 
1086  partdesc->nparts * sizeof(int));
1087  pd->reldesc = rel;
1088  pd->key = RelationGetPartitionKey(rel);
1089  pd->keystate = NIL;
1090  pd->partdesc = partdesc;
1091  if (parent_pd != NULL)
1092  {
1093  TupleDesc tupdesc = RelationGetDescr(rel);
1094 
1095  /*
1096  * For sub-partitioned tables where the column order differs from its
1097  * direct parent partitioned table, we must store a tuple table slot
1098  * initialized with its tuple descriptor and a tuple conversion map to
1099  * convert a tuple from its parent's rowtype to its own. This is to
1100  * make sure that we are looking at the correct row using the correct
1101  * tuple descriptor when computing its partition key for tuple
1102  * routing.
1103  */
1105  tupdesc);
1106  pd->tupslot = pd->tupmap ?
1107  MakeSingleTupleTableSlot(tupdesc, &TTSOpsVirtual) : NULL;
1108  }
1109  else
1110  {
1111  /* Not required for the root partitioned table */
1112  pd->tupmap = NULL;
1113  pd->tupslot = NULL;
1114  }
1115 
1116  /*
1117  * Initialize with -1 to signify that the corresponding partition's
1118  * ResultRelInfo or PartitionDispatch has not been created yet.
1119  */
1120  memset(pd->indexes, -1, sizeof(int) * partdesc->nparts);
1121 
1122  /* Track in PartitionTupleRouting for later use */
1123  dispatchidx = proute->num_dispatch++;
1124 
1125  /* Allocate or enlarge the array, as needed */
1126  if (proute->num_dispatch >= proute->max_dispatch)
1127  {
1128  if (proute->max_dispatch == 0)
1129  {
1130  proute->max_dispatch = 4;
1132  palloc(sizeof(PartitionDispatch) * proute->max_dispatch);
1133  proute->nonleaf_partitions = (ResultRelInfo **)
1134  palloc(sizeof(ResultRelInfo *) * proute->max_dispatch);
1135  }
1136  else
1137  {
1138  proute->max_dispatch *= 2;
1141  sizeof(PartitionDispatch) * proute->max_dispatch);
1142  proute->nonleaf_partitions = (ResultRelInfo **)
1143  repalloc(proute->nonleaf_partitions,
1144  sizeof(ResultRelInfo *) * proute->max_dispatch);
1145  }
1146  }
1147  proute->partition_dispatch_info[dispatchidx] = pd;
1148 
1149  /*
1150  * If setting up a PartitionDispatch for a sub-partitioned table, we may
1151  * also need a minimally valid ResultRelInfo for checking the partition
1152  * constraint later; set that up now.
1153  */
1154  if (parent_pd)
1155  {
1157 
1158  InitResultRelInfo(rri, rel, 0, rootResultRelInfo, 0);
1159  proute->nonleaf_partitions[dispatchidx] = rri;
1160  }
1161  else
1162  proute->nonleaf_partitions[dispatchidx] = NULL;
1163 
1164  /*
1165  * Finally, if setting up a PartitionDispatch for a sub-partitioned table,
1166  * install a downlink in the parent to allow quick descent.
1167  */
1168  if (parent_pd)
1169  {
1170  Assert(parent_pd->indexes[partidx] == -1);
1171  parent_pd->indexes[partidx] = dispatchidx;
1172  }
1173 
1174  MemoryContextSwitchTo(oldcxt);
1175 
1176  return pd;
1177 }
#define NIL
Definition: pg_list.h:65
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:572
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
void InitResultRelInfo(ResultRelInfo *resultRelInfo, Relation resultRelationDesc, Index resultRelationIndex, ResultRelInfo *partition_root_rri, int instrument_options)
Definition: execMain.c:1182
TupleTableSlot * tupslot
#define makeNode(_type_)
Definition: nodes.h:581
#define Assert(condition)
Definition: c.h:804
PartitionDirectory es_partition_directory
Definition: execnodes.h:554
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:727
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 565 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, RowExclusiveLock, PlanState::state, table_open(), table_slot_create(), TTSOpsVirtual, and ModifyTable::withCheckOptionLists.

Referenced by ExecFindPartition().

570 {
571  ModifyTable *node = (ModifyTable *) mtstate->ps.plan;
572  Relation partrel;
573  int firstVarno = mtstate->resultRelInfo[0].ri_RangeTableIndex;
574  Relation firstResultRel = mtstate->resultRelInfo[0].ri_RelationDesc;
575  ResultRelInfo *leaf_part_rri;
576  MemoryContext oldcxt;
577  AttrMap *part_attmap = NULL;
578  bool found_whole_row;
579 
580  oldcxt = MemoryContextSwitchTo(proute->memcxt);
581 
582  partrel = table_open(dispatch->partdesc->oids[partidx], RowExclusiveLock);
583 
584  leaf_part_rri = makeNode(ResultRelInfo);
585  InitResultRelInfo(leaf_part_rri,
586  partrel,
587  0,
588  rootResultRelInfo,
589  estate->es_instrument);
590 
591  /*
592  * Verify result relation is a valid target for an INSERT. An UPDATE of a
593  * partition-key becomes a DELETE+INSERT operation, so this check is still
594  * required when the operation is CMD_UPDATE.
595  */
596  CheckValidResultRel(leaf_part_rri, CMD_INSERT);
597 
598  /*
599  * Open partition indices. The user may have asked to check for conflicts
600  * within this leaf partition and do "nothing" instead of throwing an
601  * error. Be prepared in that case by initializing the index information
602  * needed by ExecInsert() to perform speculative insertions.
603  */
604  if (partrel->rd_rel->relhasindex &&
605  leaf_part_rri->ri_IndexRelationDescs == NULL)
606  ExecOpenIndices(leaf_part_rri,
607  (node != NULL &&
609 
610  /*
611  * Build WITH CHECK OPTION constraints for the partition. Note that we
612  * didn't build the withCheckOptionList for partitions within the planner,
613  * but simple translation of varattnos will suffice. This only occurs for
614  * the INSERT case or in the case of UPDATE tuple routing where we didn't
615  * find a result rel to reuse in ExecSetupPartitionTupleRouting().
616  */
617  if (node && node->withCheckOptionLists != NIL)
618  {
619  List *wcoList;
620  List *wcoExprs = NIL;
621  ListCell *ll;
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 
686  /* See the comment above for WCO lists. */
687  Assert((node->operation == CMD_INSERT &&
688  list_length(node->returningLists) == 1 &&
689  list_length(node->plans) == 1) ||
690  (node->operation == CMD_UPDATE &&
691  list_length(node->returningLists) ==
692  list_length(node->plans)));
693 
694  /*
695  * Use the RETURNING list of the first plan as a reference to
696  * calculate attno's for the RETURNING list of this partition. See
697  * the comment above for WCO lists for more details on why this is
698  * okay.
699  */
700  returningList = linitial(node->returningLists);
701 
702  /*
703  * Convert Vars in it to contain this partition's attribute numbers.
704  */
705  if (part_attmap == NULL)
706  part_attmap =
708  RelationGetDescr(firstResultRel));
709  returningList = (List *)
710  map_variable_attnos((Node *) returningList,
711  firstVarno, 0,
712  part_attmap,
713  RelationGetForm(partrel)->reltype,
714  &found_whole_row);
715  /* We ignore the value of found_whole_row. */
716 
717  leaf_part_rri->ri_returningList = returningList;
718 
719  /*
720  * Initialize the projection itself.
721  *
722  * Use the slot and the expression context that would have been set up
723  * in ExecInitModifyTable() for projection's output.
724  */
725  Assert(mtstate->ps.ps_ResultTupleSlot != NULL);
726  slot = mtstate->ps.ps_ResultTupleSlot;
727  Assert(mtstate->ps.ps_ExprContext != NULL);
728  econtext = mtstate->ps.ps_ExprContext;
729  leaf_part_rri->ri_projectReturning =
730  ExecBuildProjectionInfo(returningList, econtext, slot,
731  &mtstate->ps, RelationGetDescr(partrel));
732  }
733 
734  /* Set up information needed for routing tuples to the partition. */
735  ExecInitRoutingInfo(mtstate, estate, proute, dispatch,
736  leaf_part_rri, partidx);
737 
738  /*
739  * If there is an ON CONFLICT clause, initialize state for it.
740  */
741  if (node && node->onConflictAction != ONCONFLICT_NONE)
742  {
743  TupleDesc partrelDesc = RelationGetDescr(partrel);
744  ExprContext *econtext = mtstate->ps.ps_ExprContext;
745  ListCell *lc;
746  List *arbiterIndexes = NIL;
747 
748  /*
749  * If there is a list of arbiter indexes, map it to a list of indexes
750  * in the partition. We do that by scanning the partition's index
751  * list and searching for ancestry relationships to each index in the
752  * ancestor table.
753  */
754  if (list_length(rootResultRelInfo->ri_onConflictArbiterIndexes) > 0)
755  {
756  List *childIdxs;
757 
758  childIdxs = RelationGetIndexList(leaf_part_rri->ri_RelationDesc);
759 
760  foreach(lc, childIdxs)
761  {
762  Oid childIdx = lfirst_oid(lc);
763  List *ancestors;
764  ListCell *lc2;
765 
766  ancestors = get_partition_ancestors(childIdx);
767  foreach(lc2, rootResultRelInfo->ri_onConflictArbiterIndexes)
768  {
769  if (list_member_oid(ancestors, lfirst_oid(lc2)))
770  arbiterIndexes = lappend_oid(arbiterIndexes, childIdx);
771  }
772  list_free(ancestors);
773  }
774  }
775 
776  /*
777  * If the resulting lists are of inequal length, something is wrong.
778  * (This shouldn't happen, since arbiter index selection should not
779  * pick up an invalid index.)
780  */
781  if (list_length(rootResultRelInfo->ri_onConflictArbiterIndexes) !=
782  list_length(arbiterIndexes))
783  elog(ERROR, "invalid arbiter index list");
784  leaf_part_rri->ri_onConflictArbiterIndexes = arbiterIndexes;
785 
786  /*
787  * In the DO UPDATE case, we have some more state to initialize.
788  */
789  if (node->onConflictAction == ONCONFLICT_UPDATE)
790  {
791  TupleConversionMap *map;
792 
793  map = leaf_part_rri->ri_RootToPartitionMap;
794 
795  Assert(node->onConflictSet != NIL);
796  Assert(rootResultRelInfo->ri_onConflict != NULL);
797 
798  leaf_part_rri->ri_onConflict = makeNode(OnConflictSetState);
799 
800  /*
801  * Need a separate existing slot for each partition, as the
802  * partition could be of a different AM, even if the tuple
803  * descriptors match.
804  */
805  leaf_part_rri->ri_onConflict->oc_Existing =
806  table_slot_create(leaf_part_rri->ri_RelationDesc,
807  &mtstate->ps.state->es_tupleTable);
808 
809  /*
810  * If the partition's tuple descriptor matches exactly the root
811  * parent (the common case), we can re-use most of the parent's ON
812  * CONFLICT SET state, skipping a bunch of work. Otherwise, we
813  * need to create state specific to this partition.
814  */
815  if (map == NULL)
816  {
817  /*
818  * It's safe to reuse these from the partition root, as we
819  * only process one tuple at a time (therefore we won't
820  * overwrite needed data in slots), and the results of
821  * projections are independent of the underlying storage.
822  * Projections and where clauses themselves don't store state
823  * / are independent of the underlying storage.
824  */
825  leaf_part_rri->ri_onConflict->oc_ProjSlot =
826  rootResultRelInfo->ri_onConflict->oc_ProjSlot;
827  leaf_part_rri->ri_onConflict->oc_ProjInfo =
828  rootResultRelInfo->ri_onConflict->oc_ProjInfo;
829  leaf_part_rri->ri_onConflict->oc_WhereClause =
830  rootResultRelInfo->ri_onConflict->oc_WhereClause;
831  }
832  else
833  {
834  List *onconflset;
835  TupleDesc tupDesc;
836  bool found_whole_row;
837 
838  /*
839  * Translate expressions in onConflictSet to account for
840  * different attribute numbers. For that, map partition
841  * varattnos twice: first to catch the EXCLUDED
842  * pseudo-relation (INNER_VAR), and second to handle the main
843  * target relation (firstVarno).
844  */
845  onconflset = (List *) copyObject((Node *) node->onConflictSet);
846  if (part_attmap == NULL)
847  part_attmap =
849  RelationGetDescr(firstResultRel));
850  onconflset = (List *)
851  map_variable_attnos((Node *) onconflset,
852  INNER_VAR, 0,
853  part_attmap,
854  RelationGetForm(partrel)->reltype,
855  &found_whole_row);
856  /* We ignore the value of found_whole_row. */
857  onconflset = (List *)
858  map_variable_attnos((Node *) onconflset,
859  firstVarno, 0,
860  part_attmap,
861  RelationGetForm(partrel)->reltype,
862  &found_whole_row);
863  /* We ignore the value of found_whole_row. */
864 
865  /* Finally, adjust this tlist to match the partition. */
866  onconflset = adjust_partition_tlist(onconflset, map);
867 
868  /* create the tuple slot for the UPDATE SET projection */
869  tupDesc = ExecTypeFromTL(onconflset);
870  leaf_part_rri->ri_onConflict->oc_ProjSlot =
871  ExecInitExtraTupleSlot(mtstate->ps.state, tupDesc,
872  &TTSOpsVirtual);
873 
874  /* build UPDATE SET projection state */
875  leaf_part_rri->ri_onConflict->oc_ProjInfo =
876  ExecBuildProjectionInfo(onconflset, econtext,
877  leaf_part_rri->ri_onConflict->oc_ProjSlot,
878  &mtstate->ps, partrelDesc);
879 
880  /*
881  * If there is a WHERE clause, initialize state where it will
882  * be evaluated, mapping the attribute numbers appropriately.
883  * As with onConflictSet, we need to map partition varattnos
884  * to the partition's tupdesc.
885  */
886  if (node->onConflictWhere)
887  {
888  List *clause;
889 
890  clause = copyObject((List *) node->onConflictWhere);
891  clause = (List *)
892  map_variable_attnos((Node *) clause,
893  INNER_VAR, 0,
894  part_attmap,
895  RelationGetForm(partrel)->reltype,
896  &found_whole_row);
897  /* We ignore the value of found_whole_row. */
898  clause = (List *)
899  map_variable_attnos((Node *) clause,
900  firstVarno, 0,
901  part_attmap,
902  RelationGetForm(partrel)->reltype,
903  &found_whole_row);
904  /* We ignore the value of found_whole_row. */
905  leaf_part_rri->ri_onConflict->oc_WhereClause =
906  ExecInitQual((List *) clause, &mtstate->ps);
907  }
908  }
909  }
910  }
911 
912  /*
913  * Also, if transition capture is required, store a map to convert tuples
914  * from partition's rowtype to the root partition table's.
915  */
916  if (mtstate->mt_transition_capture || mtstate->mt_oc_transition_capture)
917  leaf_part_rri->ri_ChildToRootMap =
918  convert_tuples_by_name(RelationGetDescr(leaf_part_rri->ri_RelationDesc),
919  RelationGetDescr(rootResultRelInfo->ri_RelationDesc));
920 
921  /*
922  * Since we've just initialized this ResultRelInfo, it's not in any list
923  * attached to the estate as yet. Add it, so that it can be found later.
924  *
925  * Note that the entries in this list appear in no predetermined order,
926  * because partition result rels are initialized as and when they're
927  * needed.
928  */
932  leaf_part_rri);
933 
934  MemoryContextSwitchTo(oldcxt);
935 
936  return leaf_part_rri;
937 }
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:1195
Relation ri_RelationDesc
Definition: execnodes.h:415
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:602
ResultRelInfo * resultRelInfo
Definition: execnodes.h:1170
#define RelationGetForm(relation)
Definition: rel.h:451
ExprContext * ps_ExprContext
Definition: execnodes.h:980
const TupleTableSlotOps TTSOpsVirtual
Definition: execTuples.c:83
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
Definition: nodes.h:533
EState * state
Definition: execnodes.h:943
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:372
List * plans
Definition: plannodes.h:221
ExprState * ExecInitQual(List *qual, PlanState *parent)
Definition: execExpr.c:209
Index ri_RangeTableIndex
Definition: execnodes.h:412
List * onConflictSet
Definition: plannodes.h:230
Definition: attmap.h:34
void ExecOpenIndices(ResultRelInfo *resultRelInfo, bool speculative)
Definition: execIndexing.c:156
TupleTableSlot * ps_ResultTupleSlot
Definition: execnodes.h:979
MemoryContext es_query_cxt
Definition: execnodes.h:572
#define linitial(l)
Definition: pg_list.h:174
#define ERROR
Definition: elog.h:45
PlanState ps
Definition: execnodes.h:1161
ProjectionInfo * oc_ProjInfo
Definition: execnodes.h:386
void CheckValidResultRel(ResultRelInfo *resultRelInfo, CmdType operation)
Definition: execMain.c:981
TupleConversionMap * convert_tuples_by_name(TupleDesc indesc, TupleDesc outdesc)
Definition: tupconvert.c:102
struct TransitionCaptureState * mt_transition_capture
Definition: execnodes.h:1192
#define RowExclusiveLock
Definition: lockdefs.h:38
int es_instrument
Definition: execnodes.h:579
ExprState * oc_WhereClause
Definition: execnodes.h:387
List * lappend(List *list, void *datum)
Definition: list.c:336
OnConflictSetState * ri_onConflict
Definition: execnodes.h:486
List * es_tupleTable
Definition: execnodes.h:574
void InitResultRelInfo(ResultRelInfo *resultRelInfo, Relation resultRelationDesc, Index resultRelationIndex, ResultRelInfo *partition_root_rri, int instrument_options)
Definition: execMain.c:1182
Plan * plan
Definition: execnodes.h:941
List * es_tuple_routing_result_relations
Definition: execnodes.h:560
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:581
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:689
#define Assert(condition)
Definition: c.h:804
#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:4526
ProjectionInfo * ExecBuildProjectionInfo(List *targetList, ExprContext *econtext, TupleTableSlot *slot, PlanState *parent, TupleDesc inputDesc)
Definition: execExpr.c:353
CmdType operation
Definition: plannodes.h:215
void list_free(List *list)
Definition: list.c:1391
#define elog(elevel,...)
Definition: elog.h:227
List * returningLists
Definition: plannodes.h:223
MemoryContext memcxt
#define copyObject(obj)
Definition: nodes.h:649
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:483
#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 1849 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().

1854 {
1855  int n_steps;
1856  int partnatts;
1857  ListCell *lc;
1858 
1859  n_steps = list_length(pruning_steps);
1860 
1861  context->strategy = partkey->strategy;
1862  context->partnatts = partnatts = partkey->partnatts;
1863  context->nparts = partdesc->nparts;
1864  context->boundinfo = partdesc->boundinfo;
1865  context->partcollation = partkey->partcollation;
1866  context->partsupfunc = partkey->partsupfunc;
1867 
1868  /* We'll look up type-specific support functions as needed */
1869  context->stepcmpfuncs = (FmgrInfo *)
1870  palloc0(sizeof(FmgrInfo) * n_steps * partnatts);
1871 
1872  context->ppccontext = CurrentMemoryContext;
1873  context->planstate = planstate;
1874 
1875  /* Initialize expression state for each expression we need */
1876  context->exprstates = (ExprState **)
1877  palloc0(sizeof(ExprState *) * n_steps * partnatts);
1878  foreach(lc, pruning_steps)
1879  {
1881  ListCell *lc2;
1882  int keyno;
1883 
1884  /* not needed for other step kinds */
1885  if (!IsA(step, PartitionPruneStepOp))
1886  continue;
1887 
1888  Assert(list_length(step->exprs) <= partnatts);
1889 
1890  keyno = 0;
1891  foreach(lc2, step->exprs)
1892  {
1893  Expr *expr = (Expr *) lfirst(lc2);
1894 
1895  /* not needed for Consts */
1896  if (!IsA(expr, Const))
1897  {
1898  int stateidx = PruneCxtStateIdx(partnatts,
1899  step->step.step_id,
1900  keyno);
1901 
1902  context->exprstates[stateidx] =
1903  ExecInitExpr(expr, context->planstate);
1904  }
1905  keyno++;
1906  }
1907  }
1908 }
Definition: fmgr.h:56
FmgrInfo * partsupfunc
Definition: partprune.h:55
#define IsA(nodeptr, _type_)
Definition: nodes.h:584
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:1219
Oid * partcollation
Definition: partcache.h:38
void * palloc0(Size size)
Definition: mcxt.c:981
#define Assert(condition)
Definition: c.h:804
#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:123
#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 946 of file execPartition.c.

References Assert, FdwRoutine::BeginForeignInsert, CMD_INSERT, convert_tuples_by_name(), EState::es_tupleTable, FdwRoutine::ExecForeignBatchInsert, FdwRoutine::GetForeignModifyBatchSize, PartitionDispatchData::indexes, PartitionTupleRouting::max_partitions, PartitionTupleRouting::memcxt, MemoryContextSwitchTo(), PartitionTupleRouting::num_partitions, ModifyTableState::operation, palloc(), PartitionTupleRouting::partitions, RelationGetDescr, repalloc(), ResultRelInfo::ri_BatchSize, ResultRelInfo::ri_CopyMultiInsertBuffer, ResultRelInfo::ri_FdwRoutine, ResultRelInfo::ri_PartitionTupleSlot, ResultRelInfo::ri_RelationDesc, ResultRelInfo::ri_RootResultRelInfo, ResultRelInfo::ri_RootToPartitionMap, and table_slot_create().

Referenced by ExecFindPartition(), and ExecInitPartitionInfo().

952 {
953  ResultRelInfo *rootRelInfo = partRelInfo->ri_RootResultRelInfo;
954  MemoryContext oldcxt;
955  int rri_index;
956 
957  oldcxt = MemoryContextSwitchTo(proute->memcxt);
958 
959  /*
960  * Set up a tuple conversion map to convert a tuple routed to the
961  * partition from the parent's type to the partition's.
962  */
963  partRelInfo->ri_RootToPartitionMap =
965  RelationGetDescr(partRelInfo->ri_RelationDesc));
966 
967  /*
968  * If a partition has a different rowtype than the root parent, initialize
969  * a slot dedicated to storing this partition's tuples. The slot is used
970  * for various operations that are applied to tuples after routing, such
971  * as checking constraints.
972  */
973  if (partRelInfo->ri_RootToPartitionMap != NULL)
974  {
975  Relation partrel = partRelInfo->ri_RelationDesc;
976 
977  /*
978  * Initialize the slot itself setting its descriptor to this
979  * partition's TupleDesc; TupleDesc reference will be released at the
980  * end of the command.
981  */
982  partRelInfo->ri_PartitionTupleSlot =
983  table_slot_create(partrel, &estate->es_tupleTable);
984  }
985  else
986  partRelInfo->ri_PartitionTupleSlot = NULL;
987 
988  /*
989  * If the partition is a foreign table, let the FDW init itself for
990  * routing tuples to the partition.
991  */
992  if (partRelInfo->ri_FdwRoutine != NULL &&
993  partRelInfo->ri_FdwRoutine->BeginForeignInsert != NULL)
994  partRelInfo->ri_FdwRoutine->BeginForeignInsert(mtstate, partRelInfo);
995 
996  /*
997  * Determine if the FDW supports batch insert and determine the batch
998  * size (a FDW may support batching, but it may be disabled for the
999  * server/table or for this particular query).
1000  *
1001  * If the FDW does not support batching, we set the batch size to 1.
1002  */
1003  if (mtstate->operation == CMD_INSERT &&
1004  partRelInfo->ri_FdwRoutine != NULL &&
1005  partRelInfo->ri_FdwRoutine->GetForeignModifyBatchSize &&
1006  partRelInfo->ri_FdwRoutine->ExecForeignBatchInsert)
1007  partRelInfo->ri_BatchSize =
1008  partRelInfo->ri_FdwRoutine->GetForeignModifyBatchSize(partRelInfo);
1009  else
1010  partRelInfo->ri_BatchSize = 1;
1011 
1012  Assert(partRelInfo->ri_BatchSize >= 1);
1013 
1014  partRelInfo->ri_CopyMultiInsertBuffer = NULL;
1015 
1016  /*
1017  * Keep track of it in the PartitionTupleRouting->partitions array.
1018  */
1019  Assert(dispatch->indexes[partidx] == -1);
1020 
1021  rri_index = proute->num_partitions++;
1022 
1023  /* Allocate or enlarge the array, as needed */
1024  if (proute->num_partitions >= proute->max_partitions)
1025  {
1026  if (proute->max_partitions == 0)
1027  {
1028  proute->max_partitions = 8;
1029  proute->partitions = (ResultRelInfo **)
1030  palloc(sizeof(ResultRelInfo *) * proute->max_partitions);
1031  }
1032  else
1033  {
1034  proute->max_partitions *= 2;
1035  proute->partitions = (ResultRelInfo **)
1036  repalloc(proute->partitions, sizeof(ResultRelInfo *) *
1037  proute->max_partitions);
1038  }
1039  }
1040 
1041  proute->partitions[rri_index] = partRelInfo;
1042  dispatch->indexes[partidx] = rri_index;
1043 
1044  MemoryContextSwitchTo(oldcxt);
1045 }
TupleTableSlot * table_slot_create(Relation relation, List **reglist)
Definition: tableam.c:91
Relation ri_RelationDesc
Definition: execnodes.h:415
struct CopyMultiInsertBuffer * ri_CopyMultiInsertBuffer
Definition: execnodes.h:515
#define RelationGetDescr(relation)
Definition: rel.h:483
BeginForeignInsert_function BeginForeignInsert
Definition: fdwapi.h:225
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
CmdType operation
Definition: execnodes.h:1162
ResultRelInfo ** partitions
TupleTableSlot * ri_PartitionTupleSlot
Definition: execnodes.h:505
struct ResultRelInfo * ri_RootResultRelInfo
Definition: execnodes.h:503
TupleConversionMap * convert_tuples_by_name(TupleDesc indesc, TupleDesc outdesc)
Definition: tupconvert.c:102
struct FdwRoutine * ri_FdwRoutine
Definition: execnodes.h:444
GetForeignModifyBatchSize_function GetForeignModifyBatchSize
Definition: fdwapi.h:221
List * es_tupleTable
Definition: execnodes.h:574
ExecForeignBatchInsert_function ExecForeignBatchInsert
Definition: fdwapi.h:220
int ri_BatchSize
Definition: execnodes.h:454
#define Assert(condition)
Definition: c.h:804
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1070
void * palloc(Size size)
Definition: mcxt.c:950
TupleConversionMap * ri_RootToPartitionMap
Definition: execnodes.h:504
MemoryContext memcxt
int indexes[FLEXIBLE_ARRAY_MEMBER]

◆ ExecSetupPartitionTupleRouting()

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

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

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

2157 {
2158  Bitmapset *partset;
2159  int i;
2160 
2161  /* Guard against stack overflow due to overly deep partition hierarchy. */
2163 
2164  /* Only prune if pruning would be useful at this level. */
2165  if (initial_prune && pprune->initial_pruning_steps)
2166  {
2167  partset = get_matching_partitions(&pprune->initial_context,
2168  pprune->initial_pruning_steps);
2169  }
2170  else if (!initial_prune && pprune->exec_pruning_steps)
2171  {
2172  partset = get_matching_partitions(&pprune->exec_context,
2173  pprune->exec_pruning_steps);
2174  }
2175  else
2176  {
2177  /*
2178  * If no pruning is to be done, just include all partitions at this
2179  * level.
2180  */
2181  partset = pprune->present_parts;
2182  }
2183 
2184  /* Translate partset into subplan indexes */
2185  i = -1;
2186  while ((i = bms_next_member(partset, i)) >= 0)
2187  {
2188  if (pprune->subplan_map[i] >= 0)
2189  *validsubplans = bms_add_member(*validsubplans,
2190  pprune->subplan_map[i]);
2191  else
2192  {
2193  int partidx = pprune->subpart_map[i];
2194 
2195  if (partidx >= 0)
2197  &prunedata->partrelprunedata[partidx],
2198  initial_prune, validsubplans);
2199  else
2200  {
2201  /*
2202  * We get here if the planner already pruned all the sub-
2203  * partitions for this partition. Silently ignore this
2204  * partition in this case. The end result is the same: we
2205  * would have pruned all partitions just the same, but we
2206  * don't have any pruning steps to execute to verify this.
2207  */
2208  }
2209  }
2210  }
2211 }
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:3310
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:819
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 1257 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().

1262 {
1263  ListCell *partexpr_item;
1264  int i;
1265 
1266  if (pd->key->partexprs != NIL && pd->keystate == NIL)
1267  {
1268  /* Check caller has set up context correctly */
1269  Assert(estate != NULL &&
1270  GetPerTupleExprContext(estate)->ecxt_scantuple == slot);
1271 
1272  /* First time through, set up expression evaluation state */
1273  pd->keystate = ExecPrepareExprList(pd->key->partexprs, estate);
1274  }
1275 
1276  partexpr_item = list_head(pd->keystate);
1277  for (i = 0; i < pd->key->partnatts; i++)
1278  {
1279  AttrNumber keycol = pd->key->partattrs[i];
1280  Datum datum;
1281  bool isNull;
1282 
1283  if (keycol != 0)
1284  {
1285  /* Plain column; get the value directly from the heap tuple */
1286  datum = slot_getattr(slot, keycol, &isNull);
1287  }
1288  else
1289  {
1290  /* Expression; need to evaluate it */
1291  if (partexpr_item == NULL)
1292  elog(ERROR, "wrong number of partition key expressions");
1293  datum = ExecEvalExprSwitchContext((ExprState *) lfirst(partexpr_item),
1294  GetPerTupleExprContext(estate),
1295  &isNull);
1296  partexpr_item = lnext(pd->keystate, partexpr_item);
1297  }
1298  values[i] = datum;
1299  isnull[i] = isNull;
1300  }
1301 
1302  if (partexpr_item != NULL)
1303  elog(ERROR, "wrong number of partition key expressions");
1304 }
#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:322
List * partexprs
Definition: partcache.h:30
#define GetPerTupleExprContext(estate)
Definition: executor.h:509
#define ERROR
Definition: elog.h:45
static ListCell * list_head(const List *l)
Definition: pg_list.h:125
List * ExecPrepareExprList(List *nodes, EState *estate)
Definition: execExpr.c:566
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:804
#define lfirst(lc)
Definition: pg_list.h:169
static Datum values[MAXATTR]
Definition: bootstrap.c:165
#define elog(elevel,...)
Definition: elog.h:227
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 1315 of file execPartition.c.

References PartitionDescData::boundinfo, compute_partition_hash_value(), PartitionBoundInfoData::default_index, elog, equal(), ERROR, i, PartitionBoundInfoData::indexes, sort-test::key, PartitionDispatchData::key, PartitionBoundInfoData::nindexes, 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().

1316 {
1317  int bound_offset;
1318  int part_index = -1;
1319  PartitionKey key = pd->key;
1320  PartitionDesc partdesc = pd->partdesc;
1321  PartitionBoundInfo boundinfo = partdesc->boundinfo;
1322 
1323  /* Route as appropriate based on partitioning strategy. */
1324  switch (key->strategy)
1325  {
1327  {
1328  uint64 rowHash;
1329 
1330  rowHash = compute_partition_hash_value(key->partnatts,
1331  key->partsupfunc,
1332  key->partcollation,
1333  values, isnull);
1334 
1335  part_index = boundinfo->indexes[rowHash % boundinfo->nindexes];
1336  }
1337  break;
1338 
1340  if (isnull[0])
1341  {
1342  if (partition_bound_accepts_nulls(boundinfo))
1343  part_index = boundinfo->null_index;
1344  }
1345  else
1346  {
1347  bool equal = false;
1348 
1349  bound_offset = partition_list_bsearch(key->partsupfunc,
1350  key->partcollation,
1351  boundinfo,
1352  values[0], &equal);
1353  if (bound_offset >= 0 && equal)
1354  part_index = boundinfo->indexes[bound_offset];
1355  }
1356  break;
1357 
1359  {
1360  bool equal = false,
1361  range_partkey_has_null = false;
1362  int i;
1363 
1364  /*
1365  * No range includes NULL, so this will be accepted by the
1366  * default partition if there is one, and otherwise rejected.
1367  */
1368  for (i = 0; i < key->partnatts; i++)
1369  {
1370  if (isnull[i])
1371  {
1372  range_partkey_has_null = true;
1373  break;
1374  }
1375  }
1376 
1377  if (!range_partkey_has_null)
1378  {
1379  bound_offset = partition_range_datum_bsearch(key->partsupfunc,
1380  key->partcollation,
1381  boundinfo,
1382  key->partnatts,
1383  values,
1384  &equal);
1385 
1386  /*
1387  * The bound at bound_offset is less than or equal to the
1388  * tuple value, so the bound at offset+1 is the upper
1389  * bound of the partition we're looking for, if there
1390  * actually exists one.
1391  */
1392  part_index = boundinfo->indexes[bound_offset + 1];
1393  }
1394  }
1395  break;
1396 
1397  default:
1398  elog(ERROR, "unexpected partition strategy: %d",
1399  (int) key->strategy);
1400  }
1401 
1402  /*
1403  * part_index < 0 means we failed to find a partition of this parent. Use
1404  * the default partition, if there is one.
1405  */
1406  if (part_index < 0)
1407  part_index = boundinfo->default_index;
1408 
1409  return part_index;
1410 }
PartitionDesc partdesc
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:3073
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:3587
#define ERROR
Definition: elog.h:45
Oid * partcollation
Definition: partcache.h:38
#define PARTITION_STRATEGY_HASH
Definition: parsenodes.h:801
#define partition_bound_accepts_nulls(bi)
Definition: partbounds.h:81
int partition_list_bsearch(FmgrInfo *partsupfunc, Oid *partcollation, PartitionBoundInfo boundinfo, Datum value, bool *is_equal)
Definition: partbounds.c:3499
uint64 compute_partition_hash_value(int partnatts, FmgrInfo *partsupfunc, Oid *partcollation, Datum *values, bool *isnull)
Definition: partbounds.c:4617
#define PARTITION_STRATEGY_LIST
Definition: parsenodes.h:802
static Datum values[MAXATTR]
Definition: bootstrap.c:165
#define PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:803
#define elog(elevel,...)
Definition: elog.h:227
int i