PostgreSQL Source Code  git master
execPartition.h File Reference
Include dependency graph for execPartition.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  PartitionRoutingInfo
 
struct  PartitionedRelPruningData
 
struct  PartitionPruningData
 
struct  PartitionPruneState
 

Typedefs

typedef struct PartitionDispatchDataPartitionDispatch
 
typedef struct PartitionTupleRouting PartitionTupleRouting
 
typedef struct PartitionRoutingInfo PartitionRoutingInfo
 
typedef struct PartitionedRelPruningData PartitionedRelPruningData
 
typedef struct PartitionPruningData PartitionPruningData
 
typedef struct PartitionPruneState PartitionPruneState
 

Functions

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)
 
BitmapsetExecFindMatchingSubPlans (PartitionPruneState *prunestate)
 
BitmapsetExecFindInitialMatchingSubPlans (PartitionPruneState *prunestate, int nsubplans)
 

Typedef Documentation

◆ PartitionDispatch

Definition at line 22 of file execPartition.h.

◆ PartitionedRelPruningData

◆ PartitionPruneState

◆ PartitionPruningData

◆ PartitionRoutingInfo

◆ PartitionTupleRouting

Definition at line 23 of file execPartition.h.

Function Documentation

◆ ExecCleanupTupleRouting()

void ExecCleanupTupleRouting ( ModifyTableState mtstate,
PartitionTupleRouting proute 
)

Definition at line 1096 of file execPartition.c.

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

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

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

◆ ExecCreatePartitionPruneState()

PartitionPruneState* ExecCreatePartitionPruneState ( PlanState planstate,
PartitionPruneInfo partitionpruneinfo 
)

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

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

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

◆ ExecFindMatchingSubPlans()

Bitmapset* ExecFindMatchingSubPlans ( PartitionPruneState prunestate)

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

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

◆ ExecFindPartition()

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

Definition at line 271 of file execPartition.c.

References Assert, CHECK_FOR_INTERRUPTS, CheckValidResultRel(), CMD_INSERT, ExprContext::ecxt_scantuple, ereport, errcode(), errdetail(), errmsg(), ERROR, errtable(), ExecBuildSlotPartitionKeyDescription(), ExecClearTuple(), ExecInitPartitionDispatchInfo(), ExecInitPartitionInfo(), ExecInitRoutingInfo(), ExecPartitionCheck(), execute_attr_map_slot(), FormPartitionKeyDatum(), get_partition_for_tuple(), GetPerTupleExprContext, GetPerTupleMemoryContext, HASH_FIND, hash_search(), PartitionDispatchData::indexes, PartitionDescData::is_leaf, likely, MemoryContextSwitchTo(), 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 apply_handle_tuple_routing(), CopyFrom(), and ExecPrepareTupleRouting().

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

◆ ExecSetupPartitionTupleRouting()

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

Definition at line 211 of file execPartition.c.

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

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

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