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/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 1426 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().

1427 {
1428  List *new_tlist = NIL;
1429  TupleDesc tupdesc = map->outdesc;
1430  AttrMap *attrMap = map->attrMap;
1431  AttrNumber attrno;
1432 
1433  Assert(tupdesc->natts == attrMap->maplen);
1434  for (attrno = 1; attrno <= tupdesc->natts; attrno++)
1435  {
1436  Form_pg_attribute att_tup = TupleDescAttr(tupdesc, attrno - 1);
1437  TargetEntry *tle;
1438 
1439  if (attrMap->attnums[attrno - 1] != InvalidAttrNumber)
1440  {
1441  Assert(!att_tup->attisdropped);
1442 
1443  /*
1444  * Use the corresponding entry from the parent's tlist, adjusting
1445  * the resno the match the partition's attno.
1446  */
1447  tle = (TargetEntry *) list_nth(tlist, attrMap->attnums[attrno - 1] - 1);
1448  tle->resno = attrno;
1449  }
1450  else
1451  {
1452  Const *expr;
1453 
1454  /*
1455  * For a dropped attribute in the partition, generate a dummy
1456  * entry with resno matching the partition's attno.
1457  */
1458  Assert(att_tup->attisdropped);
1459  expr = makeConst(INT4OID,
1460  -1,
1461  InvalidOid,
1462  sizeof(int32),
1463  (Datum) 0,
1464  true, /* isnull */
1465  true /* byval */ );
1466  tle = makeTargetEntry((Expr *) expr,
1467  attrno,
1468  pstrdup(NameStr(att_tup->attname)),
1469  false);
1470  }
1471 
1472  new_tlist = lappend(new_tlist, tle);
1473  }
1474 
1475  return new_tlist;
1476 }
#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:1186
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:297
signed int int32
Definition: c.h:347
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:200
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:236
AttrMap * attrMap
Definition: tupconvert.h:27
List * lappend(List *list, void *datum)
Definition: list.c:322
uintptr_t Datum
Definition: postgres.h:367
#define InvalidOid
Definition: postgres_ext.h:36
#define Assert(condition)
Definition: c.h:739
AttrNumber * attnums
Definition: attmap.h:36
#define InvalidAttrNumber
Definition: attnum.h:23
#define NameStr(name)
Definition: c.h:616
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 1330 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().

1334 {
1337  int partnatts = get_partition_natts(key);
1338  int i;
1339  Oid relid = RelationGetRelid(rel);
1340  AclResult aclresult;
1341 
1342  if (check_enable_rls(relid, InvalidOid, true) == RLS_ENABLED)
1343  return NULL;
1344 
1345  /* If the user has table-level access, just go build the description. */
1346  aclresult = pg_class_aclcheck(relid, GetUserId(), ACL_SELECT);
1347  if (aclresult != ACLCHECK_OK)
1348  {
1349  /*
1350  * Step through the columns of the partition key and make sure the
1351  * user has SELECT rights on all of them.
1352  */
1353  for (i = 0; i < partnatts; i++)
1354  {
1356 
1357  /*
1358  * If this partition key column is an expression, we return no
1359  * detail rather than try to figure out what column(s) the
1360  * expression includes and if the user has SELECT rights on them.
1361  */
1362  if (attnum == InvalidAttrNumber ||
1363  pg_attribute_aclcheck(relid, attnum, GetUserId(),
1364  ACL_SELECT) != ACLCHECK_OK)
1365  return NULL;
1366  }
1367  }
1368 
1369  initStringInfo(&buf);
1370  appendStringInfo(&buf, "(%s) = (",
1371  pg_get_partkeydef_columns(relid, true));
1372 
1373  for (i = 0; i < partnatts; i++)
1374  {
1375  char *val;
1376  int vallen;
1377 
1378  if (isnull[i])
1379  val = "null";
1380  else
1381  {
1382  Oid foutoid;
1383  bool typisvarlena;
1384 
1386  &foutoid, &typisvarlena);
1387  val = OidOutputFunctionCall(foutoid, values[i]);
1388  }
1389 
1390  if (i > 0)
1391  appendStringInfoString(&buf, ", ");
1392 
1393  /* truncate if needed */
1394  vallen = strlen(val);
1395  if (vallen <= maxfieldlen)
1396  appendBinaryStringInfo(&buf, val, vallen);
1397  else
1398  {
1399  vallen = pg_mbcliplen(val, vallen, maxfieldlen);
1400  appendBinaryStringInfo(&buf, val, vallen);
1401  appendStringInfoString(&buf, "...");
1402  }
1403  }
1404 
1405  appendStringInfoChar(&buf, ')');
1406 
1407  return buf.data;
1408 }
char * pg_get_partkeydef_columns(Oid relid, bool pretty)
Definition: ruleutils.c:1650
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
Definition: lsyscache.c:2674
AclResult pg_attribute_aclcheck(Oid table_oid, AttrNumber attnum, Oid roleid, AclMode mode)
Definition: aclchk.c:4515
Oid GetUserId(void)
Definition: miscinit.c:380
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:862
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:4629
static Datum values[MAXATTR]
Definition: bootstrap.c:167
char * OidOutputFunctionCall(Oid functionId, Datum val)
Definition: fmgr.c:1655
int i
int16 AttrNumber
Definition: attnum.h:21
#define RelationGetRelid(relation)
Definition: rel.h:428
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 1094 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 CopyFrom(), and ExecEndModifyTable().

1096 {
1097  HTAB *htab = proute->subplan_resultrel_htab;
1098  int i;
1099 
1100  /*
1101  * Remember, proute->partition_dispatch_info[0] corresponds to the root
1102  * partitioned table, which we must not try to close, because it is the
1103  * main target table of the query that will be closed by callers such as
1104  * ExecEndPlan() or DoCopy(). Also, tupslot is NULL for the root
1105  * partitioned table.
1106  */
1107  for (i = 1; i < proute->num_dispatch; i++)
1108  {
1110 
1111  table_close(pd->reldesc, NoLock);
1112 
1113  if (pd->tupslot)
1115  }
1116 
1117  for (i = 0; i < proute->num_partitions; i++)
1118  {
1119  ResultRelInfo *resultRelInfo = proute->partitions[i];
1120 
1121  /* Allow any FDWs to shut down */
1122  if (resultRelInfo->ri_FdwRoutine != NULL &&
1123  resultRelInfo->ri_FdwRoutine->EndForeignInsert != NULL)
1124  resultRelInfo->ri_FdwRoutine->EndForeignInsert(mtstate->ps.state,
1125  resultRelInfo);
1126 
1127  /*
1128  * Check if this result rel is one belonging to the node's subplans,
1129  * if so, let ExecEndPlan() clean it up.
1130  */
1131  if (htab)
1132  {
1133  Oid partoid;
1134  bool found;
1135 
1136  partoid = RelationGetRelid(resultRelInfo->ri_RelationDesc);
1137 
1138  (void) hash_search(htab, &partoid, HASH_FIND, &found);
1139  if (found)
1140  continue;
1141  }
1142 
1143  ExecCloseIndices(resultRelInfo);
1144  table_close(resultRelInfo->ri_RelationDesc, NoLock);
1145  }
1146 }
Relation ri_RelationDesc
Definition: execnodes.h:410
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:906
EState * state
Definition: execnodes.h:941
unsigned int Oid
Definition: postgres_ext.h:31
ResultRelInfo ** partitions
Definition: execPartition.c:93
Definition: dynahash.c:208
PlanState ps
Definition: execnodes.h:1159
#define NoLock
Definition: lockdefs.h:34
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:1224
struct FdwRoutine * ri_FdwRoutine
Definition: execnodes.h:439
PartitionDispatch * partition_dispatch_info
Definition: execPartition.c:90
TupleTableSlot * tupslot
int i
#define RelationGetRelid(relation)
Definition: rel.h:428
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 1549 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, 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, 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().

1551 {
1552  EState *estate = planstate->state;
1553  PartitionPruneState *prunestate;
1554  int n_part_hierarchies;
1555  ListCell *lc;
1556  int i;
1557 
1558  if (estate->es_partition_directory == NULL)
1559  estate->es_partition_directory =
1561 
1562  n_part_hierarchies = list_length(partitionpruneinfo->prune_infos);
1563  Assert(n_part_hierarchies > 0);
1564 
1565  /*
1566  * Allocate the data structure
1567  */
1568  prunestate = (PartitionPruneState *)
1569  palloc(offsetof(PartitionPruneState, partprunedata) +
1570  sizeof(PartitionPruningData *) * n_part_hierarchies);
1571 
1572  prunestate->execparamids = NULL;
1573  /* other_subplans can change at runtime, so we need our own copy */
1574  prunestate->other_subplans = bms_copy(partitionpruneinfo->other_subplans);
1575  prunestate->do_initial_prune = false; /* may be set below */
1576  prunestate->do_exec_prune = false; /* may be set below */
1577  prunestate->num_partprunedata = n_part_hierarchies;
1578 
1579  /*
1580  * Create a short-term memory context which we'll use when making calls to
1581  * the partition pruning functions. This avoids possible memory leaks,
1582  * since the pruning functions call comparison functions that aren't under
1583  * our control.
1584  */
1585  prunestate->prune_context =
1587  "Partition Prune",
1589 
1590  i = 0;
1591  foreach(lc, partitionpruneinfo->prune_infos)
1592  {
1593  List *partrelpruneinfos = lfirst_node(List, lc);
1594  int npartrelpruneinfos = list_length(partrelpruneinfos);
1595  PartitionPruningData *prunedata;
1596  ListCell *lc2;
1597  int j;
1598 
1599  prunedata = (PartitionPruningData *)
1600  palloc(offsetof(PartitionPruningData, partrelprunedata) +
1601  npartrelpruneinfos * sizeof(PartitionedRelPruningData));
1602  prunestate->partprunedata[i] = prunedata;
1603  prunedata->num_partrelprunedata = npartrelpruneinfos;
1604 
1605  j = 0;
1606  foreach(lc2, partrelpruneinfos)
1607  {
1609  PartitionedRelPruningData *pprune = &prunedata->partrelprunedata[j];
1610  Relation partrel;
1611  PartitionDesc partdesc;
1612  PartitionKey partkey;
1613 
1614  /*
1615  * We can rely on the copies of the partitioned table's partition
1616  * key and partition descriptor appearing in its relcache entry,
1617  * because that entry will be held open and locked for the
1618  * duration of this executor run.
1619  */
1620  partrel = ExecGetRangeTableRelation(estate, pinfo->rtindex);
1621  partkey = RelationGetPartitionKey(partrel);
1623  partrel);
1624 
1625  /*
1626  * Initialize the subplan_map and subpart_map. Since detaching a
1627  * partition requires AccessExclusiveLock, no partitions can have
1628  * disappeared, nor can the bounds for any partition have changed.
1629  * However, new partitions may have been added.
1630  */
1631  Assert(partdesc->nparts >= pinfo->nparts);
1632  pprune->nparts = partdesc->nparts;
1633  pprune->subplan_map = palloc(sizeof(int) * partdesc->nparts);
1634  if (partdesc->nparts == pinfo->nparts)
1635  {
1636  /*
1637  * There are no new partitions, so this is simple. We can
1638  * simply point to the subpart_map from the plan, but we must
1639  * copy the subplan_map since we may change it later.
1640  */
1641  pprune->subpart_map = pinfo->subpart_map;
1642  memcpy(pprune->subplan_map, pinfo->subplan_map,
1643  sizeof(int) * pinfo->nparts);
1644 
1645  /*
1646  * Double-check that the list of unpruned relations has not
1647  * changed. (Pruned partitions are not in relid_map[].)
1648  */
1649 #ifdef USE_ASSERT_CHECKING
1650  for (int k = 0; k < pinfo->nparts; k++)
1651  {
1652  Assert(partdesc->oids[k] == pinfo->relid_map[k] ||
1653  pinfo->subplan_map[k] == -1);
1654  }
1655 #endif
1656  }
1657  else
1658  {
1659  int pd_idx = 0;
1660  int pp_idx;
1661 
1662  /*
1663  * Some new partitions have appeared since plan time, and
1664  * those are reflected in our PartitionDesc but were not
1665  * present in the one used to construct subplan_map and
1666  * subpart_map. So we must construct new and longer arrays
1667  * where the partitions that were originally present map to
1668  * the same place, and any added indexes map to -1, as if the
1669  * new partitions had been pruned.
1670  */
1671  pprune->subpart_map = palloc(sizeof(int) * partdesc->nparts);
1672  for (pp_idx = 0; pp_idx < partdesc->nparts; ++pp_idx)
1673  {
1674  if (pinfo->relid_map[pd_idx] != partdesc->oids[pp_idx])
1675  {
1676  pprune->subplan_map[pp_idx] = -1;
1677  pprune->subpart_map[pp_idx] = -1;
1678  }
1679  else
1680  {
1681  pprune->subplan_map[pp_idx] =
1682  pinfo->subplan_map[pd_idx];
1683  pprune->subpart_map[pp_idx] =
1684  pinfo->subpart_map[pd_idx++];
1685  }
1686  }
1687  Assert(pd_idx == pinfo->nparts);
1688  }
1689 
1690  /* present_parts is also subject to later modification */
1691  pprune->present_parts = bms_copy(pinfo->present_parts);
1692 
1693  /*
1694  * Initialize pruning contexts as needed.
1695  */
1697  if (pinfo->initial_pruning_steps)
1698  {
1700  pinfo->initial_pruning_steps,
1701  partdesc, partkey, planstate);
1702  /* Record whether initial pruning is needed at any level */
1703  prunestate->do_initial_prune = true;
1704  }
1705  pprune->exec_pruning_steps = pinfo->exec_pruning_steps;
1706  if (pinfo->exec_pruning_steps)
1707  {
1709  pinfo->exec_pruning_steps,
1710  partdesc, partkey, planstate);
1711  /* Record whether exec pruning is needed at any level */
1712  prunestate->do_exec_prune = true;
1713  }
1714 
1715  /*
1716  * Accumulate the IDs of all PARAM_EXEC Params affecting the
1717  * partitioning decisions at this plan node.
1718  */
1719  prunestate->execparamids = bms_add_members(prunestate->execparamids,
1720  pinfo->execparamids);
1721 
1722  j++;
1723  }
1724  i++;
1725  }
1726 
1727  return prunestate;
1728 }
Bitmapset * execparamids
Definition: plannodes.h:1145
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:941
PartitionKey RelationGetPartitionKey(Relation rel)
Definition: partcache.c:54
MemoryContext es_query_cxt
Definition: execnodes.h:549
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:192
#define lfirst_node(type, lc)
Definition: pg_list.h:193
Bitmapset * present_parts
Definition: plannodes.h:1130
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
Bitmapset * execparamids
PartitionPruneContext exec_context
Definition: execPartition.h:84
Relation ExecGetRangeTableRelation(EState *estate, Index rti)
Definition: execUtils.c:754
Bitmapset * other_subplans
Definition: plannodes.h:1106
#define Assert(condition)
Definition: c.h:739
static int list_length(const List *l)
Definition: pg_list.h:169
PartitionDirectory es_partition_directory
Definition: execnodes.h:531
PartitionedRelPruningData partrelprunedata[FLEXIBLE_ARRAY_MEMBER]
Definition: execPartition.h:97
void * palloc(Size size)
Definition: mcxt.c:949
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:662
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 1812 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().

1813 {
1814  Bitmapset *result = NULL;
1815  MemoryContext oldcontext;
1816  int i;
1817 
1818  /* Caller error if we get here without do_initial_prune */
1819  Assert(prunestate->do_initial_prune);
1820 
1821  /*
1822  * Switch to a temp context to avoid leaking memory in the executor's
1823  * query-lifespan memory context.
1824  */
1825  oldcontext = MemoryContextSwitchTo(prunestate->prune_context);
1826 
1827  /*
1828  * For each hierarchy, do the pruning tests, and add nondeletable
1829  * subplans' indexes to "result".
1830  */
1831  for (i = 0; i < prunestate->num_partprunedata; i++)
1832  {
1833  PartitionPruningData *prunedata;
1834  PartitionedRelPruningData *pprune;
1835 
1836  prunedata = prunestate->partprunedata[i];
1837  pprune = &prunedata->partrelprunedata[0];
1838 
1839  /* Perform pruning without using PARAM_EXEC Params */
1840  find_matching_subplans_recurse(prunedata, pprune, true, &result);
1841 
1842  /* Expression eval may have used space in node's ps_ExprContext too */
1843  if (pprune->initial_pruning_steps)
1845  }
1846 
1847  /* Add in any subplans that partition pruning didn't account for */
1848  result = bms_add_members(result, prunestate->other_subplans);
1849 
1850  MemoryContextSwitchTo(oldcontext);
1851 
1852  /* Copy result out of the temp context before we reset it */
1853  result = bms_copy(result);
1854 
1855  MemoryContextReset(prunestate->prune_context);
1856 
1857  /*
1858  * If exec-time pruning is required and we pruned subplans above, then we
1859  * must re-sequence the subplan indexes so that ExecFindMatchingSubPlans
1860  * properly returns the indexes from the subplans which will remain after
1861  * execution of this function.
1862  *
1863  * We can safely skip this when !do_exec_prune, even though that leaves
1864  * invalid data in prunestate, because that data won't be consulted again
1865  * (cf initial Assert in ExecFindMatchingSubPlans).
1866  */
1867  if (prunestate->do_exec_prune && bms_num_members(result) < nsubplans)
1868  {
1869  int *new_subplan_indexes;
1870  Bitmapset *new_other_subplans;
1871  int i;
1872  int newidx;
1873 
1874  /*
1875  * First we must build a temporary array which maps old subplan
1876  * indexes to new ones. For convenience of initialization, we use
1877  * 1-based indexes in this array and leave pruned items as 0.
1878  */
1879  new_subplan_indexes = (int *) palloc0(sizeof(int) * nsubplans);
1880  newidx = 1;
1881  i = -1;
1882  while ((i = bms_next_member(result, i)) >= 0)
1883  {
1884  Assert(i < nsubplans);
1885  new_subplan_indexes[i] = newidx++;
1886  }
1887 
1888  /*
1889  * Now we can update each PartitionedRelPruneInfo's subplan_map with
1890  * new subplan indexes. We must also recompute its present_parts
1891  * bitmap.
1892  */
1893  for (i = 0; i < prunestate->num_partprunedata; i++)
1894  {
1895  PartitionPruningData *prunedata = prunestate->partprunedata[i];
1896  int j;
1897 
1898  /*
1899  * Within each hierarchy, we perform this loop in back-to-front
1900  * order so that we determine present_parts for the lowest-level
1901  * partitioned tables first. This way we can tell whether a
1902  * sub-partitioned table's partitions were entirely pruned so we
1903  * can exclude it from the current level's present_parts.
1904  */
1905  for (j = prunedata->num_partrelprunedata - 1; j >= 0; j--)
1906  {
1907  PartitionedRelPruningData *pprune = &prunedata->partrelprunedata[j];
1908  int nparts = pprune->nparts;
1909  int k;
1910 
1911  /* We just rebuild present_parts from scratch */
1912  bms_free(pprune->present_parts);
1913  pprune->present_parts = NULL;
1914 
1915  for (k = 0; k < nparts; k++)
1916  {
1917  int oldidx = pprune->subplan_map[k];
1918  int subidx;
1919 
1920  /*
1921  * If this partition existed as a subplan then change the
1922  * old subplan index to the new subplan index. The new
1923  * index may become -1 if the partition was pruned above,
1924  * or it may just come earlier in the subplan list due to
1925  * some subplans being removed earlier in the list. If
1926  * it's a subpartition, add it to present_parts unless
1927  * it's entirely pruned.
1928  */
1929  if (oldidx >= 0)
1930  {
1931  Assert(oldidx < nsubplans);
1932  pprune->subplan_map[k] = new_subplan_indexes[oldidx] - 1;
1933 
1934  if (new_subplan_indexes[oldidx] > 0)
1935  pprune->present_parts =
1936  bms_add_member(pprune->present_parts, k);
1937  }
1938  else if ((subidx = pprune->subpart_map[k]) >= 0)
1939  {
1940  PartitionedRelPruningData *subprune;
1941 
1942  subprune = &prunedata->partrelprunedata[subidx];
1943 
1944  if (!bms_is_empty(subprune->present_parts))
1945  pprune->present_parts =
1946  bms_add_member(pprune->present_parts, k);
1947  }
1948  }
1949  }
1950  }
1951 
1952  /*
1953  * We must also recompute the other_subplans set, since indexes in it
1954  * may change.
1955  */
1956  new_other_subplans = NULL;
1957  i = -1;
1958  while ((i = bms_next_member(prunestate->other_subplans, i)) >= 0)
1959  new_other_subplans = bms_add_member(new_other_subplans,
1960  new_subplan_indexes[i] - 1);
1961 
1962  bms_free(prunestate->other_subplans);
1963  prunestate->other_subplans = new_other_subplans;
1964 
1965  pfree(new_subplan_indexes);
1966  }
1967 
1968  return result;
1969 }
MemoryContext prune_context
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:74
ExprContext * ps_ExprContext
Definition: execnodes.h:978
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:136
void pfree(void *pointer)
Definition: mcxt.c:1056
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:980
void bms_free(Bitmapset *a)
Definition: bitmapset.c:208
#define Assert(condition)
Definition: c.h:739
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:495
Bitmapset * other_subplans
PlanState * planstate
Definition: partprune.h:58

◆ ExecFindMatchingSubPlans()

Bitmapset* ExecFindMatchingSubPlans ( PartitionPruneState prunestate)

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

1980 {
1981  Bitmapset *result = NULL;
1982  MemoryContext oldcontext;
1983  int i;
1984 
1985  /*
1986  * If !do_exec_prune, we've got problems because
1987  * ExecFindInitialMatchingSubPlans will not have bothered to update
1988  * prunestate for whatever pruning it did.
1989  */
1990  Assert(prunestate->do_exec_prune);
1991 
1992  /*
1993  * Switch to a temp context to avoid leaking memory in the executor's
1994  * query-lifespan memory context.
1995  */
1996  oldcontext = MemoryContextSwitchTo(prunestate->prune_context);
1997 
1998  /*
1999  * For each hierarchy, do the pruning tests, and add nondeletable
2000  * subplans' indexes to "result".
2001  */
2002  for (i = 0; i < prunestate->num_partprunedata; i++)
2003  {
2004  PartitionPruningData *prunedata;
2005  PartitionedRelPruningData *pprune;
2006 
2007  prunedata = prunestate->partprunedata[i];
2008  pprune = &prunedata->partrelprunedata[0];
2009 
2010  find_matching_subplans_recurse(prunedata, pprune, false, &result);
2011 
2012  /* Expression eval may have used space in node's ps_ExprContext too */
2013  if (pprune->exec_pruning_steps)
2015  }
2016 
2017  /* Add in any subplans that partition pruning didn't account for */
2018  result = bms_add_members(result, prunestate->other_subplans);
2019 
2020  MemoryContextSwitchTo(oldcontext);
2021 
2022  /* Copy result out of the temp context before we reset it */
2023  result = bms_copy(result);
2024 
2025  MemoryContextReset(prunestate->prune_context);
2026 
2027  return result;
2028 }
MemoryContext prune_context
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:74
ExprContext * ps_ExprContext
Definition: execnodes.h:978
PartitionPruningData * partprunedata[FLEXIBLE_ARRAY_MEMBER]
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:136
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:739
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:495
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 270 of file execPartition.c.

References Assert, CHECK_FOR_INTERRUPTS, CheckValidResultRel(), CMD_INSERT, ExprContext::ecxt_scantuple, ereport, errcode(), errdetail(), errmsg(), ERROR, 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(), PartitionDescData::nparts, PartitionTupleRouting::num_dispatch, PartitionTupleRouting::num_partitions, OidIsValid, PartitionDescData::oids, PartitionDispatchData::partdesc, PartitionTupleRouting::partition_dispatch_info, PARTITION_MAX_KEYS, PartitionTupleRouting::partitions, ModifyTableState::ps, RelationGetRelationName, RelationGetRelid, PartitionDispatchData::reldesc, ResultRelInfo::ri_PartitionCheck, SubplanResultRelHashElem::rri, PlanState::state, PartitionTupleRouting::subplan_resultrel_htab, PartitionDispatchData::tupmap, PartitionDispatchData::tupslot, and values.

Referenced by CopyFrom(), and ExecPrepareTupleRouting().

274 {
277  bool isnull[PARTITION_MAX_KEYS];
278  Relation rel;
279  PartitionDispatch dispatch;
280  PartitionDesc partdesc;
281  ExprContext *ecxt = GetPerTupleExprContext(estate);
282  TupleTableSlot *ecxt_scantuple_old = ecxt->ecxt_scantuple;
283  TupleTableSlot *myslot = NULL;
284  MemoryContext oldcxt;
285 
286  /* use per-tuple context here to avoid leaking memory */
288 
289  /*
290  * First check the root table's partition constraint, if any. No point in
291  * routing the tuple if it doesn't belong in the root table itself.
292  */
293  if (rootResultRelInfo->ri_PartitionCheck)
294  ExecPartitionCheck(rootResultRelInfo, slot, estate, true);
295 
296  /* start with the root partitioned table */
297  dispatch = pd[0];
298  while (true)
299  {
300  AttrMap *map = dispatch->tupmap;
301  int partidx = -1;
302 
304 
305  rel = dispatch->reldesc;
306  partdesc = dispatch->partdesc;
307 
308  /*
309  * Convert the tuple to this parent's layout, if different from the
310  * current relation.
311  */
312  myslot = dispatch->tupslot;
313  if (myslot != NULL)
314  {
315  Assert(map != NULL);
316  slot = execute_attr_map_slot(map, slot, myslot);
317  }
318 
319  /*
320  * Extract partition key from tuple. Expression evaluation machinery
321  * that FormPartitionKeyDatum() invokes expects ecxt_scantuple to
322  * point to the correct tuple slot. The slot might have changed from
323  * what was used for the parent table if the table of the current
324  * partitioning level has different tuple descriptor from the parent.
325  * So update ecxt_scantuple accordingly.
326  */
327  ecxt->ecxt_scantuple = slot;
328  FormPartitionKeyDatum(dispatch, slot, estate, values, isnull);
329 
330  /*
331  * If this partitioned table has no partitions or no partition for
332  * these values, error out.
333  */
334  if (partdesc->nparts == 0 ||
335  (partidx = get_partition_for_tuple(dispatch, values, isnull)) < 0)
336  {
337  char *val_desc;
338 
340  values, isnull, 64);
342  ereport(ERROR,
343  (errcode(ERRCODE_CHECK_VIOLATION),
344  errmsg("no partition of relation \"%s\" found for row",
346  val_desc ?
347  errdetail("Partition key of the failing row contains %s.",
348  val_desc) : 0));
349  }
350 
351  if (partdesc->is_leaf[partidx])
352  {
353  ResultRelInfo *rri;
354 
355  /*
356  * Look to see if we've already got a ResultRelInfo for this
357  * partition.
358  */
359  if (likely(dispatch->indexes[partidx] >= 0))
360  {
361  /* ResultRelInfo already built */
362  Assert(dispatch->indexes[partidx] < proute->num_partitions);
363  rri = proute->partitions[dispatch->indexes[partidx]];
364  }
365  else
366  {
367  bool found = false;
368 
369  /*
370  * We have not yet set up a ResultRelInfo for this partition,
371  * but if we have a subplan hash table, we might have one
372  * there. If not, we'll have to create one.
373  */
374  if (proute->subplan_resultrel_htab)
375  {
376  Oid partoid = partdesc->oids[partidx];
378 
379  elem = hash_search(proute->subplan_resultrel_htab,
380  &partoid, HASH_FIND, NULL);
381  if (elem)
382  {
383  found = true;
384  rri = elem->rri;
385 
386  /* Verify this ResultRelInfo allows INSERTs */
388 
389  /* Set up the PartitionRoutingInfo for it */
390  ExecInitRoutingInfo(mtstate, estate, proute, dispatch,
391  rri, partidx);
392  }
393  }
394 
395  /* We need to create a new one. */
396  if (!found)
397  rri = ExecInitPartitionInfo(mtstate, estate, proute,
398  dispatch,
399  rootResultRelInfo, partidx);
400  }
401 
402  /* Release the tuple in the lowest parent's dedicated slot. */
403  if (slot == myslot)
404  ExecClearTuple(myslot);
405 
406  MemoryContextSwitchTo(oldcxt);
407  ecxt->ecxt_scantuple = ecxt_scantuple_old;
408  return rri;
409  }
410  else
411  {
412  /*
413  * Partition is a sub-partitioned table; get the PartitionDispatch
414  */
415  if (likely(dispatch->indexes[partidx] >= 0))
416  {
417  /* Already built. */
418  Assert(dispatch->indexes[partidx] < proute->num_dispatch);
419 
420  /*
421  * Move down to the next partition level and search again
422  * until we find a leaf partition that matches this tuple
423  */
424  dispatch = pd[dispatch->indexes[partidx]];
425  }
426  else
427  {
428  /* Not yet built. Do that now. */
429  PartitionDispatch subdispatch;
430 
431  /*
432  * Create the new PartitionDispatch. We pass the current one
433  * in as the parent PartitionDispatch
434  */
435  subdispatch = ExecInitPartitionDispatchInfo(mtstate->ps.state,
436  proute,
437  partdesc->oids[partidx],
438  dispatch, partidx);
439  Assert(dispatch->indexes[partidx] >= 0 &&
440  dispatch->indexes[partidx] < proute->num_dispatch);
441  dispatch = subdispatch;
442  }
443  }
444  }
445 }
static int get_partition_for_tuple(PartitionDispatch pd, Datum *values, bool *isnull)
PartitionDesc partdesc
#define likely(x)
Definition: c.h:207
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:425
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
int errcode(int sqlerrcode)
Definition: elog.c:608
#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:906
EState * state
Definition: execnodes.h:941
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:645
ResultRelInfo ** partitions
Definition: execPartition.c:93
Definition: attmap.h:34
#define GetPerTupleExprContext(estate)
Definition: executor.h:501
#define ERROR
Definition: elog.h:43
PlanState ps
Definition: execnodes.h:1159
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:955
#define RelationGetRelationName(relation)
Definition: rel.h:462
PartitionDispatch * partition_dispatch_info
Definition: execPartition.c:90
#define ereport(elevel, rest)
Definition: elog.h:141
static PartitionDispatch ExecInitPartitionDispatchInfo(EState *estate, PartitionTupleRouting *proute, Oid partoid, PartitionDispatch parent_pd, int partidx)
uintptr_t Datum
Definition: postgres.h:367
TupleTableSlot * tupslot
List * ri_PartitionCheck
Definition: execnodes.h:475
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:739
TupleTableSlot * ecxt_scantuple
Definition: execnodes.h:223
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:506
static Datum values[MAXATTR]
Definition: bootstrap.c:167
static char * ExecBuildSlotPartitionKeyDescription(Relation rel, Datum *values, bool *isnull, int maxfieldlen)
int errmsg(const char *fmt,...)
Definition: elog.c:822
bool ExecPartitionCheck(ResultRelInfo *resultRelInfo, TupleTableSlot *slot, EState *estate, bool emitError)
Definition: execMain.c:1783
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:99
static void ExecInitRoutingInfo(ModifyTableState *mtstate, EState *estate, PartitionTupleRouting *proute, PartitionDispatch dispatch, ResultRelInfo *partRelInfo, int partidx)
#define RelationGetRelid(relation)
Definition: rel.h:428
int indexes[FLEXIBLE_ARRAY_MEMBER]

◆ ExecHashSubPlanResultRelsByOid()

static void ExecHashSubPlanResultRelsByOid ( ModifyTableState mtstate,
PartitionTupleRouting proute 
)
static

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

456 {
457  HASHCTL ctl;
458  HTAB *htab;
459  int i;
460 
461  memset(&ctl, 0, sizeof(ctl));
462  ctl.keysize = sizeof(Oid);
463  ctl.entrysize = sizeof(SubplanResultRelHashElem);
465 
466  htab = hash_create("PartitionTupleRouting table", mtstate->mt_nplans,
467  &ctl, HASH_ELEM | HASH_BLOBS | HASH_CONTEXT);
468  proute->subplan_resultrel_htab = htab;
469 
470  /* Hash all subplans by their Oid */
471  for (i = 0; i < mtstate->mt_nplans; i++)
472  {
473  ResultRelInfo *rri = &mtstate->resultRelInfo[i];
474  bool found;
475  Oid partoid = RelationGetRelid(rri->ri_RelationDesc);
477 
478  elem = (SubplanResultRelHashElem *)
479  hash_search(htab, &partoid, HASH_ENTER, &found);
480  Assert(!found);
481  elem->rri = rri;
482 
483  /*
484  * This is required in order to convert the partition's tuple to be
485  * compatible with the root partitioned table's tuple descriptor. When
486  * generating the per-subplan result rels, this was not set.
487  */
488  rri->ri_PartitionRoot = proute->partition_root;
489  }
490 }
Relation ri_RelationDesc
Definition: execnodes.h:410
struct SubplanResultRelHashElem SubplanResultRelHashElem
#define HASH_CONTEXT
Definition: hsearch.h:93
#define HASH_ELEM
Definition: hsearch.h:87
MemoryContext hcxt
Definition: hsearch.h:78
ResultRelInfo * resultRelInfo
Definition: execnodes.h:1168
Relation ri_PartitionRoot
Definition: execnodes.h:481
Size entrysize
Definition: hsearch.h:73
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:906
unsigned int Oid
Definition: postgres_ext.h:31
Definition: dynahash.c:208
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
#define HASH_BLOBS
Definition: hsearch.h:88
HTAB * hash_create(const char *tabname, long nelem, HASHCTL *info, int flags)
Definition: dynahash.c:316
Size keysize
Definition: hsearch.h:72
#define Assert(condition)
Definition: c.h:739
int i
#define RelationGetRelid(relation)
Definition: rel.h:428

◆ ExecInitPartitionDispatchInfo()

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

Definition at line 986 of file execPartition.c.

References Assert, build_attrmap_by_name_if_req(), CreatePartitionDirectory(), EState::es_partition_directory, EState::es_query_cxt, PartitionDispatchData::indexes, PartitionDispatchData::key, PartitionDispatchData::keystate, MakeSingleTupleTableSlot(), PartitionTupleRouting::max_dispatch, PartitionTupleRouting::memcxt, MemoryContextSwitchTo(), NIL, 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().

989 {
990  Relation rel;
991  PartitionDesc partdesc;
993  int dispatchidx;
994  MemoryContext oldcxt;
995 
996  if (estate->es_partition_directory == NULL)
997  estate->es_partition_directory =
999 
1000  oldcxt = MemoryContextSwitchTo(proute->memcxt);
1001 
1002  /*
1003  * Only sub-partitioned tables need to be locked here. The root
1004  * partitioned table will already have been locked as it's referenced in
1005  * the query's rtable.
1006  */
1007  if (partoid != RelationGetRelid(proute->partition_root))
1008  rel = table_open(partoid, RowExclusiveLock);
1009  else
1010  rel = proute->partition_root;
1011  partdesc = PartitionDirectoryLookup(estate->es_partition_directory, rel);
1012 
1014  partdesc->nparts * sizeof(int));
1015  pd->reldesc = rel;
1016  pd->key = RelationGetPartitionKey(rel);
1017  pd->keystate = NIL;
1018  pd->partdesc = partdesc;
1019  if (parent_pd != NULL)
1020  {
1021  TupleDesc tupdesc = RelationGetDescr(rel);
1022 
1023  /*
1024  * For sub-partitioned tables where the column order differs from its
1025  * direct parent partitioned table, we must store a tuple table slot
1026  * initialized with its tuple descriptor and a tuple conversion map to
1027  * convert a tuple from its parent's rowtype to its own. This is to
1028  * make sure that we are looking at the correct row using the correct
1029  * tuple descriptor when computing its partition key for tuple
1030  * routing.
1031  */
1033  tupdesc);
1034  pd->tupslot = pd->tupmap ?
1035  MakeSingleTupleTableSlot(tupdesc, &TTSOpsVirtual) : NULL;
1036  }
1037  else
1038  {
1039  /* Not required for the root partitioned table */
1040  pd->tupmap = NULL;
1041  pd->tupslot = NULL;
1042  }
1043 
1044  /*
1045  * Initialize with -1 to signify that the corresponding partition's
1046  * ResultRelInfo or PartitionDispatch has not been created yet.
1047  */
1048  memset(pd->indexes, -1, sizeof(int) * partdesc->nparts);
1049 
1050  /* Track in PartitionTupleRouting for later use */
1051  dispatchidx = proute->num_dispatch++;
1052 
1053  /* Allocate or enlarge the array, as needed */
1054  if (proute->num_dispatch >= proute->max_dispatch)
1055  {
1056  if (proute->max_dispatch == 0)
1057  {
1058  proute->max_dispatch = 4;
1060  palloc(sizeof(PartitionDispatch) * proute->max_dispatch);
1061  }
1062  else
1063  {
1064  proute->max_dispatch *= 2;
1067  sizeof(PartitionDispatch) * proute->max_dispatch);
1068  }
1069  }
1070  proute->partition_dispatch_info[dispatchidx] = pd;
1071 
1072  /*
1073  * Finally, if setting up a PartitionDispatch for a sub-partitioned table,
1074  * install a downlink in the parent to allow quick descent.
1075  */
1076  if (parent_pd)
1077  {
1078  Assert(parent_pd->indexes[partidx] == -1);
1079  parent_pd->indexes[partidx] = dispatchidx;
1080  }
1081 
1082  MemoryContextSwitchTo(oldcxt);
1083 
1084  return pd;
1085 }
#define NIL
Definition: pg_list.h:65
PartitionDesc partdesc
#define RelationGetDescr(relation)
Definition: rel.h:454
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:549
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:90
TupleTableSlot * tupslot
#define Assert(condition)
Definition: c.h:739
PartitionDirectory es_partition_directory
Definition: execnodes.h:531
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1069
void * palloc(Size size)
Definition: mcxt.c:949
PartitionDesc PartitionDirectoryLookup(PartitionDirectory pdir, Relation rel)
Definition: partdesc.c:316
MemoryContext memcxt
Definition: execPartition.c:97
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
struct PartitionDispatchData * PartitionDispatch
Definition: execPartition.h:22
#define RelationGetRelid(relation)
Definition: rel.h:428
#define offsetof(type, field)
Definition: c.h:662
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 501 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().

506 {
507  ModifyTable *node = (ModifyTable *) mtstate->ps.plan;
508  Relation rootrel = rootResultRelInfo->ri_RelationDesc,
509  partrel;
510  Relation firstResultRel = mtstate->resultRelInfo[0].ri_RelationDesc;
511  ResultRelInfo *leaf_part_rri;
512  MemoryContext oldcxt;
513  AttrMap *part_attmap = NULL;
514  bool found_whole_row;
515 
516  oldcxt = MemoryContextSwitchTo(proute->memcxt);
517 
518  partrel = table_open(dispatch->partdesc->oids[partidx], RowExclusiveLock);
519 
520  leaf_part_rri = makeNode(ResultRelInfo);
521  InitResultRelInfo(leaf_part_rri,
522  partrel,
523  node ? node->rootRelation : 1,
524  rootrel,
525  estate->es_instrument);
526 
527  /*
528  * Verify result relation is a valid target for an INSERT. An UPDATE of a
529  * partition-key becomes a DELETE+INSERT operation, so this check is still
530  * required when the operation is CMD_UPDATE.
531  */
532  CheckValidResultRel(leaf_part_rri, CMD_INSERT);
533 
534  /*
535  * Open partition indices. The user may have asked to check for conflicts
536  * within this leaf partition and do "nothing" instead of throwing an
537  * error. Be prepared in that case by initializing the index information
538  * needed by ExecInsert() to perform speculative insertions.
539  */
540  if (partrel->rd_rel->relhasindex &&
541  leaf_part_rri->ri_IndexRelationDescs == NULL)
542  ExecOpenIndices(leaf_part_rri,
543  (node != NULL &&
545 
546  /*
547  * Build WITH CHECK OPTION constraints for the partition. Note that we
548  * didn't build the withCheckOptionList for partitions within the planner,
549  * but simple translation of varattnos will suffice. This only occurs for
550  * the INSERT case or in the case of UPDATE tuple routing where we didn't
551  * find a result rel to reuse in ExecSetupPartitionTupleRouting().
552  */
553  if (node && node->withCheckOptionLists != NIL)
554  {
555  List *wcoList;
556  List *wcoExprs = NIL;
557  ListCell *ll;
558  int firstVarno = mtstate->resultRelInfo[0].ri_RangeTableIndex;
559 
560  /*
561  * In the case of INSERT on a partitioned table, there is only one
562  * plan. Likewise, there is only one WCO list, not one per partition.
563  * For UPDATE, there are as many WCO lists as there are plans.
564  */
565  Assert((node->operation == CMD_INSERT &&
566  list_length(node->withCheckOptionLists) == 1 &&
567  list_length(node->plans) == 1) ||
568  (node->operation == CMD_UPDATE &&
570  list_length(node->plans)));
571 
572  /*
573  * Use the WCO list of the first plan as a reference to calculate
574  * attno's for the WCO list of this partition. In the INSERT case,
575  * that refers to the root partitioned table, whereas in the UPDATE
576  * tuple routing case, that refers to the first partition in the
577  * mtstate->resultRelInfo array. In any case, both that relation and
578  * this partition should have the same columns, so we should be able
579  * to map attributes successfully.
580  */
581  wcoList = linitial(node->withCheckOptionLists);
582 
583  /*
584  * Convert Vars in it to contain this partition's attribute numbers.
585  */
586  part_attmap =
588  RelationGetDescr(firstResultRel));
589  wcoList = (List *)
590  map_variable_attnos((Node *) wcoList,
591  firstVarno, 0,
592  part_attmap,
593  RelationGetForm(partrel)->reltype,
594  &found_whole_row);
595  /* We ignore the value of found_whole_row. */
596 
597  foreach(ll, wcoList)
598  {
600  ExprState *wcoExpr = ExecInitQual(castNode(List, wco->qual),
601  &mtstate->ps);
602 
603  wcoExprs = lappend(wcoExprs, wcoExpr);
604  }
605 
606  leaf_part_rri->ri_WithCheckOptions = wcoList;
607  leaf_part_rri->ri_WithCheckOptionExprs = wcoExprs;
608  }
609 
610  /*
611  * Build the RETURNING projection for the partition. Note that we didn't
612  * build the returningList for partitions within the planner, but simple
613  * translation of varattnos will suffice. This only occurs for the INSERT
614  * case or in the case of UPDATE tuple routing where we didn't find a
615  * result rel to reuse in ExecSetupPartitionTupleRouting().
616  */
617  if (node && node->returningLists != NIL)
618  {
619  TupleTableSlot *slot;
620  ExprContext *econtext;
621  List *returningList;
622  int firstVarno = mtstate->resultRelInfo[0].ri_RangeTableIndex;
623 
624  /* See the comment above for WCO lists. */
625  Assert((node->operation == CMD_INSERT &&
626  list_length(node->returningLists) == 1 &&
627  list_length(node->plans) == 1) ||
628  (node->operation == CMD_UPDATE &&
629  list_length(node->returningLists) ==
630  list_length(node->plans)));
631 
632  /*
633  * Use the RETURNING list of the first plan as a reference to
634  * calculate attno's for the RETURNING list of this partition. See
635  * the comment above for WCO lists for more details on why this is
636  * okay.
637  */
638  returningList = linitial(node->returningLists);
639 
640  /*
641  * Convert Vars in it to contain this partition's attribute numbers.
642  */
643  if (part_attmap == NULL)
644  part_attmap =
646  RelationGetDescr(firstResultRel));
647  returningList = (List *)
648  map_variable_attnos((Node *) returningList,
649  firstVarno, 0,
650  part_attmap,
651  RelationGetForm(partrel)->reltype,
652  &found_whole_row);
653  /* We ignore the value of found_whole_row. */
654 
655  leaf_part_rri->ri_returningList = returningList;
656 
657  /*
658  * Initialize the projection itself.
659  *
660  * Use the slot and the expression context that would have been set up
661  * in ExecInitModifyTable() for projection's output.
662  */
663  Assert(mtstate->ps.ps_ResultTupleSlot != NULL);
664  slot = mtstate->ps.ps_ResultTupleSlot;
665  Assert(mtstate->ps.ps_ExprContext != NULL);
666  econtext = mtstate->ps.ps_ExprContext;
667  leaf_part_rri->ri_projectReturning =
668  ExecBuildProjectionInfo(returningList, econtext, slot,
669  &mtstate->ps, RelationGetDescr(partrel));
670  }
671 
672  /* Set up information needed for routing tuples to the partition. */
673  ExecInitRoutingInfo(mtstate, estate, proute, dispatch,
674  leaf_part_rri, partidx);
675 
676  /*
677  * If there is an ON CONFLICT clause, initialize state for it.
678  */
679  if (node && node->onConflictAction != ONCONFLICT_NONE)
680  {
681  int firstVarno = mtstate->resultRelInfo[0].ri_RangeTableIndex;
682  TupleDesc partrelDesc = RelationGetDescr(partrel);
683  ExprContext *econtext = mtstate->ps.ps_ExprContext;
684  ListCell *lc;
685  List *arbiterIndexes = NIL;
686 
687  /*
688  * If there is a list of arbiter indexes, map it to a list of indexes
689  * in the partition. We do that by scanning the partition's index
690  * list and searching for ancestry relationships to each index in the
691  * ancestor table.
692  */
693  if (list_length(rootResultRelInfo->ri_onConflictArbiterIndexes) > 0)
694  {
695  List *childIdxs;
696 
697  childIdxs = RelationGetIndexList(leaf_part_rri->ri_RelationDesc);
698 
699  foreach(lc, childIdxs)
700  {
701  Oid childIdx = lfirst_oid(lc);
702  List *ancestors;
703  ListCell *lc2;
704 
705  ancestors = get_partition_ancestors(childIdx);
706  foreach(lc2, rootResultRelInfo->ri_onConflictArbiterIndexes)
707  {
708  if (list_member_oid(ancestors, lfirst_oid(lc2)))
709  arbiterIndexes = lappend_oid(arbiterIndexes, childIdx);
710  }
711  list_free(ancestors);
712  }
713  }
714 
715  /*
716  * If the resulting lists are of inequal length, something is wrong.
717  * (This shouldn't happen, since arbiter index selection should not
718  * pick up an invalid index.)
719  */
720  if (list_length(rootResultRelInfo->ri_onConflictArbiterIndexes) !=
721  list_length(arbiterIndexes))
722  elog(ERROR, "invalid arbiter index list");
723  leaf_part_rri->ri_onConflictArbiterIndexes = arbiterIndexes;
724 
725  /*
726  * In the DO UPDATE case, we have some more state to initialize.
727  */
728  if (node->onConflictAction == ONCONFLICT_UPDATE)
729  {
730  TupleConversionMap *map;
731 
732  map = leaf_part_rri->ri_PartitionInfo->pi_RootToPartitionMap;
733 
734  Assert(node->onConflictSet != NIL);
735  Assert(rootResultRelInfo->ri_onConflict != NULL);
736 
737  leaf_part_rri->ri_onConflict = makeNode(OnConflictSetState);
738 
739  /*
740  * Need a separate existing slot for each partition, as the
741  * partition could be of a different AM, even if the tuple
742  * descriptors match.
743  */
744  leaf_part_rri->ri_onConflict->oc_Existing =
745  table_slot_create(leaf_part_rri->ri_RelationDesc,
746  &mtstate->ps.state->es_tupleTable);
747 
748  /*
749  * If the partition's tuple descriptor matches exactly the root
750  * parent (the common case), we can re-use most of the parent's ON
751  * CONFLICT SET state, skipping a bunch of work. Otherwise, we
752  * need to create state specific to this partition.
753  */
754  if (map == NULL)
755  {
756  /*
757  * It's safe to reuse these from the partition root, as we
758  * only process one tuple at a time (therefore we won't
759  * overwrite needed data in slots), and the results of
760  * projections are independent of the underlying storage.
761  * Projections and where clauses themselves don't store state
762  * / are independent of the underlying storage.
763  */
764  leaf_part_rri->ri_onConflict->oc_ProjSlot =
765  rootResultRelInfo->ri_onConflict->oc_ProjSlot;
766  leaf_part_rri->ri_onConflict->oc_ProjInfo =
767  rootResultRelInfo->ri_onConflict->oc_ProjInfo;
768  leaf_part_rri->ri_onConflict->oc_WhereClause =
769  rootResultRelInfo->ri_onConflict->oc_WhereClause;
770  }
771  else
772  {
773  List *onconflset;
774  TupleDesc tupDesc;
775  bool found_whole_row;
776 
777  /*
778  * Translate expressions in onConflictSet to account for
779  * different attribute numbers. For that, map partition
780  * varattnos twice: first to catch the EXCLUDED
781  * pseudo-relation (INNER_VAR), and second to handle the main
782  * target relation (firstVarno).
783  */
784  onconflset = (List *) copyObject((Node *) node->onConflictSet);
785  if (part_attmap == NULL)
786  part_attmap =
788  RelationGetDescr(firstResultRel));
789  onconflset = (List *)
790  map_variable_attnos((Node *) onconflset,
791  INNER_VAR, 0,
792  part_attmap,
793  RelationGetForm(partrel)->reltype,
794  &found_whole_row);
795  /* We ignore the value of found_whole_row. */
796  onconflset = (List *)
797  map_variable_attnos((Node *) onconflset,
798  firstVarno, 0,
799  part_attmap,
800  RelationGetForm(partrel)->reltype,
801  &found_whole_row);
802  /* We ignore the value of found_whole_row. */
803 
804  /* Finally, adjust this tlist to match the partition. */
805  onconflset = adjust_partition_tlist(onconflset, map);
806 
807  /* create the tuple slot for the UPDATE SET projection */
808  tupDesc = ExecTypeFromTL(onconflset);
809  leaf_part_rri->ri_onConflict->oc_ProjSlot =
810  ExecInitExtraTupleSlot(mtstate->ps.state, tupDesc,
811  &TTSOpsVirtual);
812 
813  /* build UPDATE SET projection state */
814  leaf_part_rri->ri_onConflict->oc_ProjInfo =
815  ExecBuildProjectionInfo(onconflset, econtext,
816  leaf_part_rri->ri_onConflict->oc_ProjSlot,
817  &mtstate->ps, partrelDesc);
818 
819  /*
820  * If there is a WHERE clause, initialize state where it will
821  * be evaluated, mapping the attribute numbers appropriately.
822  * As with onConflictSet, we need to map partition varattnos
823  * to the partition's tupdesc.
824  */
825  if (node->onConflictWhere)
826  {
827  List *clause;
828 
829  clause = copyObject((List *) node->onConflictWhere);
830  clause = (List *)
831  map_variable_attnos((Node *) clause,
832  INNER_VAR, 0,
833  part_attmap,
834  RelationGetForm(partrel)->reltype,
835  &found_whole_row);
836  /* We ignore the value of found_whole_row. */
837  clause = (List *)
838  map_variable_attnos((Node *) clause,
839  firstVarno, 0,
840  part_attmap,
841  RelationGetForm(partrel)->reltype,
842  &found_whole_row);
843  /* We ignore the value of found_whole_row. */
844  leaf_part_rri->ri_onConflict->oc_WhereClause =
845  ExecInitQual((List *) clause, &mtstate->ps);
846  }
847  }
848  }
849  }
850 
851  /*
852  * Since we've just initialized this ResultRelInfo, it's not in any list
853  * attached to the estate as yet. Add it, so that it can be found later.
854  *
855  * Note that the entries in this list appear in no predetermined order,
856  * because partition result rels are initialized as and when they're
857  * needed.
858  */
862  leaf_part_rri);
863 
864  MemoryContextSwitchTo(oldcxt);
865 
866  return leaf_part_rri;
867 }
TupleTableSlot * table_slot_create(Relation relation, List **reglist)
Definition: tableam.c:77
#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:410
PartitionDesc partdesc
TupleTableSlot * ExecInitExtraTupleSlot(EState *estate, TupleDesc tupledesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1801
#define RelationGetDescr(relation)
Definition: rel.h:454
List * withCheckOptionLists
Definition: plannodes.h:230
#define castNode(_type_, nodeptr)
Definition: nodes.h:594
ResultRelInfo * resultRelInfo
Definition: execnodes.h:1168
#define RelationGetForm(relation)
Definition: rel.h:422
ExprContext * ps_ExprContext
Definition: execnodes.h:978
const TupleTableSlotOps TTSOpsVirtual
Definition: execTuples.c:83
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
Definition: nodes.h:525
EState * state
Definition: execnodes.h:941
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:358
List * plans
Definition: plannodes.h:229
ExprState * ExecInitQual(List *qual, PlanState *parent)
Definition: execExpr.c:207
Index ri_RangeTableIndex
Definition: execnodes.h:407
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:977
MemoryContext es_query_cxt
Definition: execnodes.h:549
#define linitial(l)
Definition: pg_list.h:195
#define ERROR
Definition: elog.h:43
PlanState ps
Definition: execnodes.h:1159
ProjectionInfo * oc_ProjInfo
Definition: execnodes.h:384
void CheckValidResultRel(ResultRelInfo *resultRelInfo, CmdType operation)
Definition: execMain.c:1076
#define RowExclusiveLock
Definition: lockdefs.h:38
int es_instrument
Definition: execnodes.h:556
ExprState * oc_WhereClause
Definition: execnodes.h:385
List * lappend(List *list, void *datum)
Definition: list.c:322
OnConflictSetState * ri_onConflict
Definition: execnodes.h:472
List * es_tupleTable
Definition: execnodes.h:551
Plan * plan
Definition: execnodes.h:939
List * es_tuple_routing_result_relations
Definition: execnodes.h:537
TupleTableSlot * oc_ProjSlot
Definition: execnodes.h:383
#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:573
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:675
#define Assert(condition)
Definition: c.h:739
#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:4330
ProjectionInfo * ExecBuildProjectionInfo(List *targetList, ExprContext *econtext, TupleTableSlot *slot, PlanState *parent, TupleDesc inputDesc)
Definition: execExpr.c:351
CmdType operation
Definition: plannodes.h:221
void list_free(List *list)
Definition: list.c:1377
#define elog(elevel,...)
Definition: elog.h:228
List * returningLists
Definition: plannodes.h:231
MemoryContext memcxt
Definition: execPartition.c:97
#define copyObject(obj)
Definition: nodes.h:641
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:469
#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 1734 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().

1739 {
1740  int n_steps;
1741  int partnatts;
1742  ListCell *lc;
1743 
1744  n_steps = list_length(pruning_steps);
1745 
1746  context->strategy = partkey->strategy;
1747  context->partnatts = partnatts = partkey->partnatts;
1748  context->nparts = partdesc->nparts;
1749  context->boundinfo = partdesc->boundinfo;
1750  context->partcollation = partkey->partcollation;
1751  context->partsupfunc = partkey->partsupfunc;
1752 
1753  /* We'll look up type-specific support functions as needed */
1754  context->stepcmpfuncs = (FmgrInfo *)
1755  palloc0(sizeof(FmgrInfo) * n_steps * partnatts);
1756 
1757  context->ppccontext = CurrentMemoryContext;
1758  context->planstate = planstate;
1759 
1760  /* Initialize expression state for each expression we need */
1761  context->exprstates = (ExprState **)
1762  palloc0(sizeof(ExprState *) * n_steps * partnatts);
1763  foreach(lc, pruning_steps)
1764  {
1766  ListCell *lc2;
1767  int keyno;
1768 
1769  /* not needed for other step kinds */
1770  if (!IsA(step, PartitionPruneStepOp))
1771  continue;
1772 
1773  Assert(list_length(step->exprs) <= partnatts);
1774 
1775  keyno = 0;
1776  foreach(lc2, step->exprs)
1777  {
1778  Expr *expr = (Expr *) lfirst(lc2);
1779 
1780  /* not needed for Consts */
1781  if (!IsA(expr, Const))
1782  {
1783  int stateidx = PruneCxtStateIdx(partnatts,
1784  step->step.step_id,
1785  keyno);
1786 
1787  context->exprstates[stateidx] =
1788  ExecInitExpr(expr, context->planstate);
1789  }
1790  keyno++;
1791  }
1792  }
1793 }
Definition: fmgr.h:56
FmgrInfo * partsupfunc
Definition: partprune.h:55
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
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:1190
Oid * partcollation
Definition: partcache.h:38
void * palloc0(Size size)
Definition: mcxt.c:980
#define Assert(condition)
Definition: c.h:739
#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:121
#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 876 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().

882 {
883  MemoryContext oldcxt;
884  PartitionRoutingInfo *partrouteinfo;
885  int rri_index;
886 
887  oldcxt = MemoryContextSwitchTo(proute->memcxt);
888 
889  partrouteinfo = palloc(sizeof(PartitionRoutingInfo));
890 
891  /*
892  * Set up a tuple conversion map to convert a tuple routed to the
893  * partition from the parent's type to the partition's.
894  */
895  partrouteinfo->pi_RootToPartitionMap =
897  RelationGetDescr(partRelInfo->ri_RelationDesc));
898 
899  /*
900  * If a partition has a different rowtype than the root parent, initialize
901  * a slot dedicated to storing this partition's tuples. The slot is used
902  * for various operations that are applied to tuples after routing, such
903  * as checking constraints.
904  */
905  if (partrouteinfo->pi_RootToPartitionMap != NULL)
906  {
907  Relation partrel = partRelInfo->ri_RelationDesc;
908 
909  /*
910  * Initialize the slot itself setting its descriptor to this
911  * partition's TupleDesc; TupleDesc reference will be released at the
912  * end of the command.
913  */
914  partrouteinfo->pi_PartitionTupleSlot =
915  table_slot_create(partrel, &estate->es_tupleTable);
916  }
917  else
918  partrouteinfo->pi_PartitionTupleSlot = NULL;
919 
920  /*
921  * Also, if transition capture is required, store a map to convert tuples
922  * from partition's rowtype to the root partition table's.
923  */
924  if (mtstate &&
925  (mtstate->mt_transition_capture || mtstate->mt_oc_transition_capture))
926  {
927  partrouteinfo->pi_PartitionToRootMap =
929  RelationGetDescr(partRelInfo->ri_PartitionRoot));
930  }
931  else
932  partrouteinfo->pi_PartitionToRootMap = NULL;
933 
934  /*
935  * If the partition is a foreign table, let the FDW init itself for
936  * routing tuples to the partition.
937  */
938  if (partRelInfo->ri_FdwRoutine != NULL &&
939  partRelInfo->ri_FdwRoutine->BeginForeignInsert != NULL)
940  partRelInfo->ri_FdwRoutine->BeginForeignInsert(mtstate, partRelInfo);
941 
942  partRelInfo->ri_PartitionInfo = partrouteinfo;
943  partRelInfo->ri_CopyMultiInsertBuffer = NULL;
944 
945  /*
946  * Keep track of it in the PartitionTupleRouting->partitions array.
947  */
948  Assert(dispatch->indexes[partidx] == -1);
949 
950  rri_index = proute->num_partitions++;
951 
952  /* Allocate or enlarge the array, as needed */
953  if (proute->num_partitions >= proute->max_partitions)
954  {
955  if (proute->max_partitions == 0)
956  {
957  proute->max_partitions = 8;
958  proute->partitions = (ResultRelInfo **)
959  palloc(sizeof(ResultRelInfo *) * proute->max_partitions);
960  }
961  else
962  {
963  proute->max_partitions *= 2;
964  proute->partitions = (ResultRelInfo **)
965  repalloc(proute->partitions, sizeof(ResultRelInfo *) *
966  proute->max_partitions);
967  }
968  }
969 
970  proute->partitions[rri_index] = partRelInfo;
971  dispatch->indexes[partidx] = rri_index;
972 
973  MemoryContextSwitchTo(oldcxt);
974 }
TupleTableSlot * table_slot_create(Relation relation, List **reglist)
Definition: tableam.c:77
struct TransitionCaptureState * mt_oc_transition_capture
Definition: execnodes.h:1188
Relation ri_RelationDesc
Definition: execnodes.h:410
struct CopyMultiInsertBuffer * ri_CopyMultiInsertBuffer
Definition: execnodes.h:487
#define RelationGetDescr(relation)
Definition: rel.h:454
BeginForeignInsert_function BeginForeignInsert
Definition: fdwapi.h:215
struct PartitionRoutingInfo * ri_PartitionInfo
Definition: execnodes.h:484
Relation ri_PartitionRoot
Definition: execnodes.h:481
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
ResultRelInfo ** partitions
Definition: execPartition.c:93
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:1185
struct FdwRoutine * ri_FdwRoutine
Definition: execnodes.h:439
List * es_tupleTable
Definition: execnodes.h:551
TupleConversionMap * pi_PartitionToRootMap
Definition: execPartition.h:43
#define Assert(condition)
Definition: c.h:739
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1069
void * palloc(Size size)
Definition: mcxt.c:949
MemoryContext memcxt
Definition: execPartition.c:97
int indexes[FLEXIBLE_ARRAY_MEMBER]
TupleTableSlot * pi_PartitionTupleSlot
Definition: execPartition.h:49

◆ ExecSetupPartitionTupleRouting()

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

Definition at line 210 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 CopyFrom(), and ExecInitModifyTable().

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

◆ find_matching_subplans_recurse()

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

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

2042 {
2043  Bitmapset *partset;
2044  int i;
2045 
2046  /* Guard against stack overflow due to overly deep partition hierarchy. */
2048 
2049  /* Only prune if pruning would be useful at this level. */
2050  if (initial_prune && pprune->initial_pruning_steps)
2051  {
2052  partset = get_matching_partitions(&pprune->initial_context,
2053  pprune->initial_pruning_steps);
2054  }
2055  else if (!initial_prune && pprune->exec_pruning_steps)
2056  {
2057  partset = get_matching_partitions(&pprune->exec_context,
2058  pprune->exec_pruning_steps);
2059  }
2060  else
2061  {
2062  /*
2063  * If no pruning is to be done, just include all partitions at this
2064  * level.
2065  */
2066  partset = pprune->present_parts;
2067  }
2068 
2069  /* Translate partset into subplan indexes */
2070  i = -1;
2071  while ((i = bms_next_member(partset, i)) >= 0)
2072  {
2073  if (pprune->subplan_map[i] >= 0)
2074  *validsubplans = bms_add_member(*validsubplans,
2075  pprune->subplan_map[i]);
2076  else
2077  {
2078  int partidx = pprune->subpart_map[i];
2079 
2080  if (partidx >= 0)
2082  &prunedata->partrelprunedata[partidx],
2083  initial_prune, validsubplans);
2084  else
2085  {
2086  /*
2087  * We get here if the planner already pruned all the sub-
2088  * partitions for this partition. Silently ignore this
2089  * partition in this case. The end result is the same: we
2090  * would have pruned all partitions just the same, but we
2091  * don't have any pruning steps to execute to verify this.
2092  */
2093  }
2094  }
2095  }
2096 }
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:3288
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 1165 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().

1170 {
1171  ListCell *partexpr_item;
1172  int i;
1173 
1174  if (pd->key->partexprs != NIL && pd->keystate == NIL)
1175  {
1176  /* Check caller has set up context correctly */
1177  Assert(estate != NULL &&
1178  GetPerTupleExprContext(estate)->ecxt_scantuple == slot);
1179 
1180  /* First time through, set up expression evaluation state */
1181  pd->keystate = ExecPrepareExprList(pd->key->partexprs, estate);
1182  }
1183 
1184  partexpr_item = list_head(pd->keystate);
1185  for (i = 0; i < pd->key->partnatts; i++)
1186  {
1187  AttrNumber keycol = pd->key->partattrs[i];
1188  Datum datum;
1189  bool isNull;
1190 
1191  if (keycol != 0)
1192  {
1193  /* Plain column; get the value directly from the heap tuple */
1194  datum = slot_getattr(slot, keycol, &isNull);
1195  }
1196  else
1197  {
1198  /* Expression; need to evaluate it */
1199  if (partexpr_item == NULL)
1200  elog(ERROR, "wrong number of partition key expressions");
1201  datum = ExecEvalExprSwitchContext((ExprState *) lfirst(partexpr_item),
1202  GetPerTupleExprContext(estate),
1203  &isNull);
1204  partexpr_item = lnext(pd->keystate, partexpr_item);
1205  }
1206  values[i] = datum;
1207  isnull[i] = isNull;
1208  }
1209 
1210  if (partexpr_item != NULL)
1211  elog(ERROR, "wrong number of partition key expressions");
1212 }
#define NIL
Definition: pg_list.h:65
static Datum ExecEvalExprSwitchContext(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:300
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:501
#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:564
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:739
#define lfirst(lc)
Definition: pg_list.h:190
static Datum values[MAXATTR]
Definition: bootstrap.c:167
#define elog(elevel,...)
Definition: elog.h:228
int i
int16 AttrNumber
Definition: attnum.h:21

◆ get_partition_for_tuple()

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

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

1224 {
1225  int bound_offset;
1226  int part_index = -1;
1227  PartitionKey key = pd->key;
1228  PartitionDesc partdesc = pd->partdesc;
1229  PartitionBoundInfo boundinfo = partdesc->boundinfo;
1230 
1231  /* Route as appropriate based on partitioning strategy. */
1232  switch (key->strategy)
1233  {
1235  {
1236  int greatest_modulus;
1237  uint64 rowHash;
1238 
1239  greatest_modulus = get_hash_partition_greatest_modulus(boundinfo);
1240  rowHash = compute_partition_hash_value(key->partnatts,
1241  key->partsupfunc,
1242  key->partcollation,
1243  values, isnull);
1244 
1245  part_index = boundinfo->indexes[rowHash % greatest_modulus];
1246  }
1247  break;
1248 
1250  if (isnull[0])
1251  {
1252  if (partition_bound_accepts_nulls(boundinfo))
1253  part_index = boundinfo->null_index;
1254  }
1255  else
1256  {
1257  bool equal = false;
1258 
1259  bound_offset = partition_list_bsearch(key->partsupfunc,
1260  key->partcollation,
1261  boundinfo,
1262  values[0], &equal);
1263  if (bound_offset >= 0 && equal)
1264  part_index = boundinfo->indexes[bound_offset];
1265  }
1266  break;
1267 
1269  {
1270  bool equal = false,
1271  range_partkey_has_null = false;
1272  int i;
1273 
1274  /*
1275  * No range includes NULL, so this will be accepted by the
1276  * default partition if there is one, and otherwise rejected.
1277  */
1278  for (i = 0; i < key->partnatts; i++)
1279  {
1280  if (isnull[i])
1281  {
1282  range_partkey_has_null = true;
1283  break;
1284  }
1285  }
1286 
1287  if (!range_partkey_has_null)
1288  {
1289  bound_offset = partition_range_datum_bsearch(key->partsupfunc,
1290  key->partcollation,
1291  boundinfo,
1292  key->partnatts,
1293  values,
1294  &equal);
1295 
1296  /*
1297  * The bound at bound_offset is less than or equal to the
1298  * tuple value, so the bound at offset+1 is the upper
1299  * bound of the partition we're looking for, if there
1300  * actually exists one.
1301  */
1302  part_index = boundinfo->indexes[bound_offset + 1];
1303  }
1304  }
1305  break;
1306 
1307  default:
1308  elog(ERROR, "unexpected partition strategy: %d",
1309  (int) key->strategy);
1310  }
1311 
1312  /*
1313  * part_index < 0 means we failed to find a partition of this parent. Use
1314  * the default partition, if there is one.
1315  */
1316  if (part_index < 0)
1317  part_index = boundinfo->default_index;
1318 
1319  return part_index;
1320 }
PartitionDesc partdesc
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:3018
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:1669
#define ERROR
Definition: elog.h:43
int get_hash_partition_greatest_modulus(PartitionBoundInfo bound)
Definition: partbounds.c:1392
Oid * partcollation
Definition: partcache.h:38
#define PARTITION_STRATEGY_HASH
Definition: parsenodes.h:798
#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:1580
uint64 compute_partition_hash_value(int partnatts, FmgrInfo *partsupfunc, Oid *partcollation, Datum *values, bool *isnull)
Definition: partbounds.c:2743
#define PARTITION_STRATEGY_LIST
Definition: parsenodes.h:799
static Datum values[MAXATTR]
Definition: bootstrap.c:167
#define PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:800
#define elog(elevel,...)
Definition: elog.h:228
int i