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

Go to the source code of this file.

Data Structures

struct  PartitionTupleRouting
 
struct  PartitionDispatchData
 
struct  SubplanResultRelHashElem
 

Typedefs

typedef struct PartitionDispatchData PartitionDispatchData
 
typedef struct SubplanResultRelHashElem SubplanResultRelHashElem
 

Functions

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

Typedef Documentation

◆ PartitionDispatchData

◆ SubplanResultRelHashElem

Function Documentation

◆ adjust_partition_tlist()

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

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

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

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

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

◆ ExecCreatePartitionPruneState()

PartitionPruneState* ExecCreatePartitionPruneState ( PlanState planstate,
PartitionPruneInfo partitionpruneinfo 
)

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

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

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

◆ ExecFindMatchingSubPlans()

Bitmapset* ExecFindMatchingSubPlans ( PartitionPruneState prunestate)

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

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

◆ ExecFindPartition()

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

Definition at line 277 of file execPartition.c.

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

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

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

◆ ExecHashSubPlanResultRelsByOid()

static void ExecHashSubPlanResultRelsByOid ( ModifyTableState mtstate,
PartitionTupleRouting proute 
)
static

Definition at line 513 of file execPartition.c.

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

Referenced by ExecSetupPartitionTupleRouting().

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

◆ ExecInitPartitionDispatchInfo()

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

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

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

References adjust_partition_tlist(), Assert, build_attrmap_by_name(), castNode, CheckValidResultRel(), CMD_INSERT, CMD_UPDATE, 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(), NIL, OnConflictSetState::oc_ProjInfo, OnConflictSetState::oc_ProjSlot, OnConflictSetState::oc_WhereClause, PartitionDescData::oids, ONCONFLICT_NONE, ONCONFLICT_UPDATE, ModifyTable::onConflictAction, ModifyTable::onConflictSet, ModifyTable::onConflictWhere, ModifyTable::operation, PartitionDispatchData::partdesc, PlanState::plan, ModifyTable::plans, ModifyTableState::ps, PlanState::ps_ExprContext, PlanState::ps_ResultTupleSlot, WithCheckOption::qual, RelationGetDescr, RelationGetForm, RelationGetIndexList(), ModifyTableState::resultRelInfo, ModifyTable::returningLists, ResultRelInfo::ri_onConflict, ResultRelInfo::ri_onConflictArbiterIndexes, ResultRelInfo::ri_RangeTableIndex, ResultRelInfo::ri_RelationDesc, ModifyTable::rootRelation, RowExclusiveLock, PlanState::state, table_open(), table_slot_create(), TTSOpsVirtual, and ModifyTable::withCheckOptionLists.

Referenced by ExecFindPartition().

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

◆ ExecInitPruningContext()

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

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

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

References Assert, FdwRoutine::BeginForeignInsert, convert_tuples_by_name(), EState::es_tupleTable, PartitionDispatchData::indexes, PartitionTupleRouting::max_partitions, PartitionTupleRouting::memcxt, MemoryContextSwitchTo(), ModifyTableState::mt_oc_transition_capture, ModifyTableState::mt_transition_capture, PartitionTupleRouting::num_partitions, palloc(), PartitionTupleRouting::partitions, PartitionRoutingInfo::pi_PartitionToRootMap, PartitionRoutingInfo::pi_PartitionTupleSlot, PartitionRoutingInfo::pi_RootToPartitionMap, RelationGetDescr, repalloc(), ResultRelInfo::ri_CopyMultiInsertBuffer, ResultRelInfo::ri_FdwRoutine, ResultRelInfo::ri_PartitionInfo, ResultRelInfo::ri_PartitionRoot, ResultRelInfo::ri_RelationDesc, and table_slot_create().

Referenced by ExecFindPartition(), and ExecInitPartitionInfo().

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

◆ ExecSetupPartitionTupleRouting()

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

Definition at line 217 of file execPartition.c.

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

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

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

◆ find_matching_subplans_recurse()

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

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

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

◆ FormPartitionKeyDatum()

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

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

1249 {
1250  ListCell *partexpr_item;
1251  int i;
1252 
1253  if (pd->key->partexprs != NIL && pd->keystate == NIL)
1254  {
1255  /* Check caller has set up context correctly */
1256  Assert(estate != NULL &&
1257  GetPerTupleExprContext(estate)->ecxt_scantuple == slot);
1258 
1259  /* First time through, set up expression evaluation state */
1260  pd->keystate = ExecPrepareExprList(pd->key->partexprs, estate);
1261  }
1262 
1263  partexpr_item = list_head(pd->keystate);
1264  for (i = 0; i < pd->key->partnatts; i++)
1265  {
1266  AttrNumber keycol = pd->key->partattrs[i];
1267  Datum datum;
1268  bool isNull;
1269 
1270  if (keycol != 0)
1271  {
1272  /* Plain column; get the value directly from the heap tuple */
1273  datum = slot_getattr(slot, keycol, &isNull);
1274  }
1275  else
1276  {
1277  /* Expression; need to evaluate it */
1278  if (partexpr_item == NULL)
1279  elog(ERROR, "wrong number of partition key expressions");
1280  datum = ExecEvalExprSwitchContext((ExprState *) lfirst(partexpr_item),
1281  GetPerTupleExprContext(estate),
1282  &isNull);
1283  partexpr_item = lnext(pd->keystate, partexpr_item);
1284  }
1285  values[i] = datum;
1286  isnull[i] = isNull;
1287  }
1288 
1289  if (partexpr_item != NULL)
1290  elog(ERROR, "wrong number of partition key expressions");
1291 }
#define NIL
Definition: pg_list.h:65
static Datum ExecEvalExprSwitchContext(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:305
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:321
List * partexprs
Definition: partcache.h:30
#define GetPerTupleExprContext(estate)
Definition: executor.h:507
#define ERROR
Definition: elog.h:43
static ListCell * list_head(const List *l)
Definition: pg_list.h:125
List * ExecPrepareExprList(List *nodes, EState *estate)
Definition: execExpr.c: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:745
#define lfirst(lc)
Definition: pg_list.h:190
static Datum values[MAXATTR]
Definition: bootstrap.c:165
#define elog(elevel,...)
Definition: elog.h:214
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 1302 of file execPartition.c.

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

Referenced by ExecFindPartition().

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