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  PartitionedRelPruningData
 
struct  PartitionPruningData
 
struct  PartitionPruneState
 

Typedefs

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

Functions

PartitionTupleRoutingExecSetupPartitionTupleRouting (EState *estate, 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

◆ PartitionTupleRouting

Definition at line 23 of file execPartition.h.

Function Documentation

◆ ExecCleanupTupleRouting()

void ExecCleanupTupleRouting ( ModifyTableState mtstate,
PartitionTupleRouting proute 
)

Definition at line 1122 of file execPartition.c.

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

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

1124 {
1125  int i;
1126 
1127  /*
1128  * Remember, proute->partition_dispatch_info[0] corresponds to the root
1129  * partitioned table, which we must not try to close, because it is the
1130  * main target table of the query that will be closed by callers such as
1131  * ExecEndPlan() or DoCopy(). Also, tupslot is NULL for the root
1132  * partitioned table.
1133  */
1134  for (i = 1; i < proute->num_dispatch; i++)
1135  {
1137 
1138  table_close(pd->reldesc, NoLock);
1139 
1140  if (pd->tupslot)
1142  }
1143 
1144  for (i = 0; i < proute->num_partitions; i++)
1145  {
1146  ResultRelInfo *resultRelInfo = proute->partitions[i];
1147 
1148  /* Allow any FDWs to shut down */
1149  if (resultRelInfo->ri_FdwRoutine != NULL &&
1150  resultRelInfo->ri_FdwRoutine->EndForeignInsert != NULL)
1151  resultRelInfo->ri_FdwRoutine->EndForeignInsert(mtstate->ps.state,
1152  resultRelInfo);
1153 
1154  /*
1155  * Close it if it's not one of the result relations borrowed from the
1156  * owning ModifyTableState; those will be closed by ExecEndPlan().
1157  */
1158  if (proute->is_borrowed_rel[i])
1159  continue;
1160 
1161  ExecCloseIndices(resultRelInfo);
1162  table_close(resultRelInfo->ri_RelationDesc, NoLock);
1163  }
1164 }
Relation ri_RelationDesc
Definition: execnodes.h:411
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
EState * state
Definition: execnodes.h:966
ResultRelInfo ** partitions
PlanState ps
Definition: execnodes.h:1183
#define NoLock
Definition: lockdefs.h:34
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:1224
struct FdwRoutine * ri_FdwRoutine
Definition: execnodes.h:455
PartitionDispatch * partition_dispatch_info
Definition: execPartition.c:96
TupleTableSlot * tupslot
int i
void ExecCloseIndices(ResultRelInfo *resultRelInfo)
Definition: execIndexing.c:231
EndForeignInsert_function EndForeignInsert
Definition: fdwapi.h:240

◆ ExecCreatePartitionPruneState()

PartitionPruneState* ExecCreatePartitionPruneState ( PlanState planstate,
PartitionPruneInfo partitionpruneinfo 
)

Definition at line 1565 of file execPartition.c.

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

Referenced by ExecInitAppend(), and ExecInitMergeAppend().

1567 {
1568  EState *estate = planstate->state;
1569  PartitionPruneState *prunestate;
1570  int n_part_hierarchies;
1571  ListCell *lc;
1572  int i;
1573 
1574  /* Executor must always include detached partitions */
1575  if (estate->es_partition_directory == NULL)
1576  estate->es_partition_directory =
1577  CreatePartitionDirectory(estate->es_query_cxt, true);
1578 
1579  n_part_hierarchies = list_length(partitionpruneinfo->prune_infos);
1580  Assert(n_part_hierarchies > 0);
1581 
1582  /*
1583  * Allocate the data structure
1584  */
1585  prunestate = (PartitionPruneState *)
1586  palloc(offsetof(PartitionPruneState, partprunedata) +
1587  sizeof(PartitionPruningData *) * n_part_hierarchies);
1588 
1589  prunestate->execparamids = NULL;
1590  /* other_subplans can change at runtime, so we need our own copy */
1591  prunestate->other_subplans = bms_copy(partitionpruneinfo->other_subplans);
1592  prunestate->do_initial_prune = false; /* may be set below */
1593  prunestate->do_exec_prune = false; /* may be set below */
1594  prunestate->num_partprunedata = n_part_hierarchies;
1595 
1596  /*
1597  * Create a short-term memory context which we'll use when making calls to
1598  * the partition pruning functions. This avoids possible memory leaks,
1599  * since the pruning functions call comparison functions that aren't under
1600  * our control.
1601  */
1602  prunestate->prune_context =
1604  "Partition Prune",
1606 
1607  i = 0;
1608  foreach(lc, partitionpruneinfo->prune_infos)
1609  {
1610  List *partrelpruneinfos = lfirst_node(List, lc);
1611  int npartrelpruneinfos = list_length(partrelpruneinfos);
1612  PartitionPruningData *prunedata;
1613  ListCell *lc2;
1614  int j;
1615 
1616  prunedata = (PartitionPruningData *)
1617  palloc(offsetof(PartitionPruningData, partrelprunedata) +
1618  npartrelpruneinfos * sizeof(PartitionedRelPruningData));
1619  prunestate->partprunedata[i] = prunedata;
1620  prunedata->num_partrelprunedata = npartrelpruneinfos;
1621 
1622  j = 0;
1623  foreach(lc2, partrelpruneinfos)
1624  {
1626  PartitionedRelPruningData *pprune = &prunedata->partrelprunedata[j];
1627  Relation partrel;
1628  PartitionDesc partdesc;
1629  PartitionKey partkey;
1630 
1631  /*
1632  * We can rely on the copies of the partitioned table's partition
1633  * key and partition descriptor appearing in its relcache entry,
1634  * because that entry will be held open and locked for the
1635  * duration of this executor run.
1636  */
1637  partrel = ExecGetRangeTableRelation(estate, pinfo->rtindex);
1638  partkey = RelationGetPartitionKey(partrel);
1640  partrel);
1641 
1642  /*
1643  * Initialize the subplan_map and subpart_map.
1644  *
1645  * Because we request detached partitions to be included, and
1646  * detaching waits for old transactions, it is safe to assume that
1647  * no partitions have disappeared since this query was planned.
1648  *
1649  * However, new partitions may have been added.
1650  */
1651  Assert(partdesc->nparts >= pinfo->nparts);
1652  pprune->nparts = partdesc->nparts;
1653  pprune->subplan_map = palloc(sizeof(int) * partdesc->nparts);
1654  if (partdesc->nparts == pinfo->nparts)
1655  {
1656  /*
1657  * There are no new partitions, so this is simple. We can
1658  * simply point to the subpart_map from the plan, but we must
1659  * copy the subplan_map since we may change it later.
1660  */
1661  pprune->subpart_map = pinfo->subpart_map;
1662  memcpy(pprune->subplan_map, pinfo->subplan_map,
1663  sizeof(int) * pinfo->nparts);
1664 
1665  /*
1666  * Double-check that the list of unpruned relations has not
1667  * changed. (Pruned partitions are not in relid_map[].)
1668  */
1669 #ifdef USE_ASSERT_CHECKING
1670  for (int k = 0; k < pinfo->nparts; k++)
1671  {
1672  Assert(partdesc->oids[k] == pinfo->relid_map[k] ||
1673  pinfo->subplan_map[k] == -1);
1674  }
1675 #endif
1676  }
1677  else
1678  {
1679  int pd_idx = 0;
1680  int pp_idx;
1681 
1682  /*
1683  * Some new partitions have appeared since plan time, and
1684  * those are reflected in our PartitionDesc but were not
1685  * present in the one used to construct subplan_map and
1686  * subpart_map. So we must construct new and longer arrays
1687  * where the partitions that were originally present map to
1688  * the same sub-structures, and any added partitions map to
1689  * -1, as if the new partitions had been pruned.
1690  *
1691  * Note: pinfo->relid_map[] may contain InvalidOid entries for
1692  * partitions pruned by the planner. We cannot tell exactly
1693  * which of the partdesc entries these correspond to, but we
1694  * don't have to; just skip over them. The non-pruned
1695  * relid_map entries, however, had better be a subset of the
1696  * partdesc entries and in the same order.
1697  */
1698  pprune->subpart_map = palloc(sizeof(int) * partdesc->nparts);
1699  for (pp_idx = 0; pp_idx < partdesc->nparts; pp_idx++)
1700  {
1701  /* Skip any InvalidOid relid_map entries */
1702  while (pd_idx < pinfo->nparts &&
1703  !OidIsValid(pinfo->relid_map[pd_idx]))
1704  pd_idx++;
1705 
1706  if (pd_idx < pinfo->nparts &&
1707  pinfo->relid_map[pd_idx] == partdesc->oids[pp_idx])
1708  {
1709  /* match... */
1710  pprune->subplan_map[pp_idx] =
1711  pinfo->subplan_map[pd_idx];
1712  pprune->subpart_map[pp_idx] =
1713  pinfo->subpart_map[pd_idx];
1714  pd_idx++;
1715  }
1716  else
1717  {
1718  /* this partdesc entry is not in the plan */
1719  pprune->subplan_map[pp_idx] = -1;
1720  pprune->subpart_map[pp_idx] = -1;
1721  }
1722  }
1723 
1724  /*
1725  * It might seem that we need to skip any trailing InvalidOid
1726  * entries in pinfo->relid_map before checking that we scanned
1727  * all of the relid_map. But we will have skipped them above,
1728  * because they must correspond to some partdesc->oids
1729  * entries; we just couldn't tell which.
1730  */
1731  if (pd_idx != pinfo->nparts)
1732  elog(ERROR, "could not match partition child tables to plan elements");
1733  }
1734 
1735  /* present_parts is also subject to later modification */
1736  pprune->present_parts = bms_copy(pinfo->present_parts);
1737 
1738  /*
1739  * Initialize pruning contexts as needed.
1740  */
1742  if (pinfo->initial_pruning_steps)
1743  {
1745  pinfo->initial_pruning_steps,
1746  partdesc, partkey, planstate);
1747  /* Record whether initial pruning is needed at any level */
1748  prunestate->do_initial_prune = true;
1749  }
1750  pprune->exec_pruning_steps = pinfo->exec_pruning_steps;
1751  if (pinfo->exec_pruning_steps)
1752  {
1754  pinfo->exec_pruning_steps,
1755  partdesc, partkey, planstate);
1756  /* Record whether exec pruning is needed at any level */
1757  prunestate->do_exec_prune = true;
1758  }
1759 
1760  /*
1761  * Accumulate the IDs of all PARAM_EXEC Params affecting the
1762  * partitioning decisions at this plan node.
1763  */
1764  prunestate->execparamids = bms_add_members(prunestate->execparamids,
1765  pinfo->execparamids);
1766 
1767  j++;
1768  }
1769  i++;
1770  }
1771 
1772  return prunestate;
1773 }
Bitmapset * execparamids
Definition: plannodes.h:1201
MemoryContext prune_context
#define AllocSetContextCreate
Definition: memutils.h:173
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]
EState * state
Definition: execnodes.h:966
PartitionKey RelationGetPartitionKey(Relation rel)
Definition: partcache.c:54
#define OidIsValid(objectId)
Definition: c.h:710
MemoryContext es_query_cxt
Definition: execnodes.h:598
#define ERROR
Definition: elog.h:46
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:195
#define lfirst_node(type, lc)
Definition: pg_list.h:172
Bitmapset * present_parts
Definition: plannodes.h:1186
MemoryContext CurrentMemoryContext
Definition: mcxt.c:42
Bitmapset * execparamids
PartitionDirectory CreatePartitionDirectory(MemoryContext mcxt, bool include_detached)
Definition: partdesc.c:287
PartitionPruneContext exec_context
Definition: execPartition.h:57
Relation ExecGetRangeTableRelation(EState *estate, Index rti)
Definition: execUtils.c:782
Bitmapset * other_subplans
Definition: plannodes.h:1162
#define Assert(condition)
Definition: c.h:804
static int list_length(const List *l)
Definition: pg_list.h:149
PartitionDirectory es_partition_directory
Definition: execnodes.h:580
PartitionedRelPruningData partrelprunedata[FLEXIBLE_ARRAY_MEMBER]
Definition: execPartition.h:70
void * palloc(Size size)
Definition: mcxt.c:1062
#define elog(elevel,...)
Definition: elog.h:232
int i
PartitionDesc PartitionDirectoryLookup(PartitionDirectory pdir, Relation rel)
Definition: partdesc.c:320
Definition: pg_list.h:50
PartitionPruneContext initial_context
Definition: execPartition.h:56
#define offsetof(type, field)
Definition: c.h:727
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:793
Bitmapset * other_subplans
struct PartitionedRelPruningData PartitionedRelPruningData

◆ ExecFindInitialMatchingSubPlans()

Bitmapset* ExecFindInitialMatchingSubPlans ( PartitionPruneState prunestate,
int  nsubplans 
)

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

1858 {
1859  Bitmapset *result = NULL;
1860  MemoryContext oldcontext;
1861  int i;
1862 
1863  /* Caller error if we get here without do_initial_prune */
1864  Assert(prunestate->do_initial_prune);
1865 
1866  /*
1867  * Switch to a temp context to avoid leaking memory in the executor's
1868  * query-lifespan memory context.
1869  */
1870  oldcontext = MemoryContextSwitchTo(prunestate->prune_context);
1871 
1872  /*
1873  * For each hierarchy, do the pruning tests, and add nondeletable
1874  * subplans' indexes to "result".
1875  */
1876  for (i = 0; i < prunestate->num_partprunedata; i++)
1877  {
1878  PartitionPruningData *prunedata;
1879  PartitionedRelPruningData *pprune;
1880 
1881  prunedata = prunestate->partprunedata[i];
1882  pprune = &prunedata->partrelprunedata[0];
1883 
1884  /* Perform pruning without using PARAM_EXEC Params */
1885  find_matching_subplans_recurse(prunedata, pprune, true, &result);
1886 
1887  /* Expression eval may have used space in node's ps_ExprContext too */
1888  if (pprune->initial_pruning_steps)
1890  }
1891 
1892  /* Add in any subplans that partition pruning didn't account for */
1893  result = bms_add_members(result, prunestate->other_subplans);
1894 
1895  MemoryContextSwitchTo(oldcontext);
1896 
1897  /* Copy result out of the temp context before we reset it */
1898  result = bms_copy(result);
1899 
1900  MemoryContextReset(prunestate->prune_context);
1901 
1902  /*
1903  * If exec-time pruning is required and we pruned subplans above, then we
1904  * must re-sequence the subplan indexes so that ExecFindMatchingSubPlans
1905  * properly returns the indexes from the subplans which will remain after
1906  * execution of this function.
1907  *
1908  * We can safely skip this when !do_exec_prune, even though that leaves
1909  * invalid data in prunestate, because that data won't be consulted again
1910  * (cf initial Assert in ExecFindMatchingSubPlans).
1911  */
1912  if (prunestate->do_exec_prune && bms_num_members(result) < nsubplans)
1913  {
1914  int *new_subplan_indexes;
1915  Bitmapset *new_other_subplans;
1916  int i;
1917  int newidx;
1918 
1919  /*
1920  * First we must build a temporary array which maps old subplan
1921  * indexes to new ones. For convenience of initialization, we use
1922  * 1-based indexes in this array and leave pruned items as 0.
1923  */
1924  new_subplan_indexes = (int *) palloc0(sizeof(int) * nsubplans);
1925  newidx = 1;
1926  i = -1;
1927  while ((i = bms_next_member(result, i)) >= 0)
1928  {
1929  Assert(i < nsubplans);
1930  new_subplan_indexes[i] = newidx++;
1931  }
1932 
1933  /*
1934  * Now we can update each PartitionedRelPruneInfo's subplan_map with
1935  * new subplan indexes. We must also recompute its present_parts
1936  * bitmap.
1937  */
1938  for (i = 0; i < prunestate->num_partprunedata; i++)
1939  {
1940  PartitionPruningData *prunedata = prunestate->partprunedata[i];
1941  int j;
1942 
1943  /*
1944  * Within each hierarchy, we perform this loop in back-to-front
1945  * order so that we determine present_parts for the lowest-level
1946  * partitioned tables first. This way we can tell whether a
1947  * sub-partitioned table's partitions were entirely pruned so we
1948  * can exclude it from the current level's present_parts.
1949  */
1950  for (j = prunedata->num_partrelprunedata - 1; j >= 0; j--)
1951  {
1952  PartitionedRelPruningData *pprune = &prunedata->partrelprunedata[j];
1953  int nparts = pprune->nparts;
1954  int k;
1955 
1956  /* We just rebuild present_parts from scratch */
1957  bms_free(pprune->present_parts);
1958  pprune->present_parts = NULL;
1959 
1960  for (k = 0; k < nparts; k++)
1961  {
1962  int oldidx = pprune->subplan_map[k];
1963  int subidx;
1964 
1965  /*
1966  * If this partition existed as a subplan then change the
1967  * old subplan index to the new subplan index. The new
1968  * index may become -1 if the partition was pruned above,
1969  * or it may just come earlier in the subplan list due to
1970  * some subplans being removed earlier in the list. If
1971  * it's a subpartition, add it to present_parts unless
1972  * it's entirely pruned.
1973  */
1974  if (oldidx >= 0)
1975  {
1976  Assert(oldidx < nsubplans);
1977  pprune->subplan_map[k] = new_subplan_indexes[oldidx] - 1;
1978 
1979  if (new_subplan_indexes[oldidx] > 0)
1980  pprune->present_parts =
1981  bms_add_member(pprune->present_parts, k);
1982  }
1983  else if ((subidx = pprune->subpart_map[k]) >= 0)
1984  {
1985  PartitionedRelPruningData *subprune;
1986 
1987  subprune = &prunedata->partrelprunedata[subidx];
1988 
1989  if (!bms_is_empty(subprune->present_parts))
1990  pprune->present_parts =
1991  bms_add_member(pprune->present_parts, k);
1992  }
1993  }
1994  }
1995  }
1996 
1997  /*
1998  * We must also recompute the other_subplans set, since indexes in it
1999  * may change.
2000  */
2001  new_other_subplans = NULL;
2002  i = -1;
2003  while ((i = bms_next_member(prunestate->other_subplans, i)) >= 0)
2004  new_other_subplans = bms_add_member(new_other_subplans,
2005  new_subplan_indexes[i] - 1);
2006 
2007  bms_free(prunestate->other_subplans);
2008  prunestate->other_subplans = new_other_subplans;
2009 
2010  pfree(new_subplan_indexes);
2011  }
2012 
2013  return result;
2014 }
MemoryContext prune_context
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:74
ExprContext * ps_ExprContext
Definition: execnodes.h:1003
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:143
void pfree(void *pointer)
Definition: mcxt.c:1169
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:1093
void bms_free(Bitmapset *a)
Definition: bitmapset.c:208
#define Assert(condition)
Definition: c.h:804
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:736
PartitionedRelPruningData partrelprunedata[FLEXIBLE_ARRAY_MEMBER]
Definition: execPartition.h:70
int i
PartitionPruneContext initial_context
Definition: execPartition.h:56
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:793
#define ResetExprContext(econtext)
Definition: executor.h:526
Bitmapset * other_subplans
PlanState * planstate
Definition: partprune.h:58

◆ ExecFindMatchingSubPlans()

Bitmapset* ExecFindMatchingSubPlans ( PartitionPruneState prunestate)

Definition at line 2024 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(), ExecAppendAsyncBegin(), and ExecMergeAppend().

2025 {
2026  Bitmapset *result = NULL;
2027  MemoryContext oldcontext;
2028  int i;
2029 
2030  /*
2031  * If !do_exec_prune, we've got problems because
2032  * ExecFindInitialMatchingSubPlans will not have bothered to update
2033  * prunestate for whatever pruning it did.
2034  */
2035  Assert(prunestate->do_exec_prune);
2036 
2037  /*
2038  * Switch to a temp context to avoid leaking memory in the executor's
2039  * query-lifespan memory context.
2040  */
2041  oldcontext = MemoryContextSwitchTo(prunestate->prune_context);
2042 
2043  /*
2044  * For each hierarchy, do the pruning tests, and add nondeletable
2045  * subplans' indexes to "result".
2046  */
2047  for (i = 0; i < prunestate->num_partprunedata; i++)
2048  {
2049  PartitionPruningData *prunedata;
2050  PartitionedRelPruningData *pprune;
2051 
2052  prunedata = prunestate->partprunedata[i];
2053  pprune = &prunedata->partrelprunedata[0];
2054 
2055  find_matching_subplans_recurse(prunedata, pprune, false, &result);
2056 
2057  /* Expression eval may have used space in node's ps_ExprContext too */
2058  if (pprune->exec_pruning_steps)
2060  }
2061 
2062  /* Add in any subplans that partition pruning didn't account for */
2063  result = bms_add_members(result, prunestate->other_subplans);
2064 
2065  MemoryContextSwitchTo(oldcontext);
2066 
2067  /* Copy result out of the temp context before we reset it */
2068  result = bms_copy(result);
2069 
2070  MemoryContextReset(prunestate->prune_context);
2071 
2072  return result;
2073 }
MemoryContext prune_context
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:74
ExprContext * ps_ExprContext
Definition: execnodes.h:1003
PartitionPruningData * partprunedata[FLEXIBLE_ARRAY_MEMBER]
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:143
static void find_matching_subplans_recurse(PartitionPruningData *prunedata, PartitionedRelPruningData *pprune, bool initial_prune, Bitmapset **validsubplans)
PartitionPruneContext exec_context
Definition: execPartition.h:57
#define Assert(condition)
Definition: c.h:804
PartitionedRelPruningData partrelprunedata[FLEXIBLE_ARRAY_MEMBER]
Definition: execPartition.h:70
int i
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:793
#define ResetExprContext(econtext)
Definition: executor.h:526
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 257 of file execPartition.c.

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

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

261 {
264  bool isnull[PARTITION_MAX_KEYS];
265  Relation rel;
266  PartitionDispatch dispatch;
267  PartitionDesc partdesc;
268  ExprContext *ecxt = GetPerTupleExprContext(estate);
269  TupleTableSlot *ecxt_scantuple_saved = ecxt->ecxt_scantuple;
270  TupleTableSlot *rootslot = slot;
271  TupleTableSlot *myslot = NULL;
272  MemoryContext oldcxt;
273  ResultRelInfo *rri = NULL;
274 
275  /* use per-tuple context here to avoid leaking memory */
277 
278  /*
279  * First check the root table's partition constraint, if any. No point in
280  * routing the tuple if it doesn't belong in the root table itself.
281  */
282  if (rootResultRelInfo->ri_RelationDesc->rd_rel->relispartition)
283  ExecPartitionCheck(rootResultRelInfo, slot, estate, true);
284 
285  /* start with the root partitioned table */
286  dispatch = pd[0];
287  while (dispatch != NULL)
288  {
289  int partidx = -1;
290  bool is_leaf;
291 
293 
294  rel = dispatch->reldesc;
295  partdesc = dispatch->partdesc;
296 
297  /*
298  * Extract partition key from tuple. Expression evaluation machinery
299  * that FormPartitionKeyDatum() invokes expects ecxt_scantuple to
300  * point to the correct tuple slot. The slot might have changed from
301  * what was used for the parent table if the table of the current
302  * partitioning level has different tuple descriptor from the parent.
303  * So update ecxt_scantuple accordingly.
304  */
305  ecxt->ecxt_scantuple = slot;
306  FormPartitionKeyDatum(dispatch, slot, estate, values, isnull);
307 
308  /*
309  * If this partitioned table has no partitions or no partition for
310  * these values, error out.
311  */
312  if (partdesc->nparts == 0 ||
313  (partidx = get_partition_for_tuple(dispatch, values, isnull)) < 0)
314  {
315  char *val_desc;
316 
318  values, isnull, 64);
320  ereport(ERROR,
321  (errcode(ERRCODE_CHECK_VIOLATION),
322  errmsg("no partition of relation \"%s\" found for row",
324  val_desc ?
325  errdetail("Partition key of the failing row contains %s.",
326  val_desc) : 0,
327  errtable(rel)));
328  }
329 
330  is_leaf = partdesc->is_leaf[partidx];
331  if (is_leaf)
332  {
333  /*
334  * We've reached the leaf -- hurray, we're done. Look to see if
335  * we've already got a ResultRelInfo for this partition.
336  */
337  if (likely(dispatch->indexes[partidx] >= 0))
338  {
339  /* ResultRelInfo already built */
340  Assert(dispatch->indexes[partidx] < proute->num_partitions);
341  rri = proute->partitions[dispatch->indexes[partidx]];
342  }
343  else
344  {
345  /*
346  * If the partition is known in the owning ModifyTableState
347  * node, we can re-use that ResultRelInfo instead of creating
348  * a new one with ExecInitPartitionInfo().
349  */
350  rri = ExecLookupResultRelByOid(mtstate,
351  partdesc->oids[partidx],
352  true, false);
353  if (rri)
354  {
355  /* Verify this ResultRelInfo allows INSERTs */
357 
358  /*
359  * Initialize information needed to insert this and
360  * subsequent tuples routed to this partition.
361  */
362  ExecInitRoutingInfo(mtstate, estate, proute, dispatch,
363  rri, partidx, true);
364  }
365  else
366  {
367  /* We need to create a new one. */
368  rri = ExecInitPartitionInfo(mtstate, estate, proute,
369  dispatch,
370  rootResultRelInfo, partidx);
371  }
372  }
373  Assert(rri != NULL);
374 
375  /* Signal to terminate the loop */
376  dispatch = NULL;
377  }
378  else
379  {
380  /*
381  * Partition is a sub-partitioned table; get the PartitionDispatch
382  */
383  if (likely(dispatch->indexes[partidx] >= 0))
384  {
385  /* Already built. */
386  Assert(dispatch->indexes[partidx] < proute->num_dispatch);
387 
388  rri = proute->nonleaf_partitions[dispatch->indexes[partidx]];
389 
390  /*
391  * Move down to the next partition level and search again
392  * until we find a leaf partition that matches this tuple
393  */
394  dispatch = pd[dispatch->indexes[partidx]];
395  }
396  else
397  {
398  /* Not yet built. Do that now. */
399  PartitionDispatch subdispatch;
400 
401  /*
402  * Create the new PartitionDispatch. We pass the current one
403  * in as the parent PartitionDispatch
404  */
405  subdispatch = ExecInitPartitionDispatchInfo(estate,
406  proute,
407  partdesc->oids[partidx],
408  dispatch, partidx,
409  mtstate->rootResultRelInfo);
410  Assert(dispatch->indexes[partidx] >= 0 &&
411  dispatch->indexes[partidx] < proute->num_dispatch);
412 
413  rri = proute->nonleaf_partitions[dispatch->indexes[partidx]];
414  dispatch = subdispatch;
415  }
416 
417  /*
418  * Convert the tuple to the new parent's layout, if different from
419  * the previous parent.
420  */
421  if (dispatch->tupslot)
422  {
423  AttrMap *map = dispatch->tupmap;
424  TupleTableSlot *tempslot = myslot;
425 
426  myslot = dispatch->tupslot;
427  slot = execute_attr_map_slot(map, slot, myslot);
428 
429  if (tempslot != NULL)
430  ExecClearTuple(tempslot);
431  }
432  }
433 
434  /*
435  * If this partition is the default one, we must check its partition
436  * constraint now, which may have changed concurrently due to
437  * partitions being added to the parent.
438  *
439  * (We do this here, and do not rely on ExecInsert doing it, because
440  * we don't want to miss doing it for non-leaf partitions.)
441  */
442  if (partidx == partdesc->boundinfo->default_index)
443  {
444  /*
445  * The tuple must match the partition's layout for the constraint
446  * expression to be evaluated successfully. If the partition is
447  * sub-partitioned, that would already be the case due to the code
448  * above, but for a leaf partition the tuple still matches the
449  * parent's layout.
450  *
451  * Note that we have a map to convert from root to current
452  * partition, but not from immediate parent to current partition.
453  * So if we have to convert, do it from the root slot; if not, use
454  * the root slot as-is.
455  */
456  if (is_leaf)
457  {
459 
460  if (map)
461  slot = execute_attr_map_slot(map->attrMap, rootslot,
462  rri->ri_PartitionTupleSlot);
463  else
464  slot = rootslot;
465  }
466 
467  ExecPartitionCheck(rri, slot, estate, true);
468  }
469  }
470 
471  /* Release the tuple in the lowest parent's dedicated slot. */
472  if (myslot != NULL)
473  ExecClearTuple(myslot);
474  /* and restore ecxt's scantuple */
475  ecxt->ecxt_scantuple = ecxt_scantuple_saved;
476  MemoryContextSwitchTo(oldcxt);
477 
478  return rri;
479 }
static int get_partition_for_tuple(PartitionDispatch pd, Datum *values, bool *isnull)
Relation ri_RelationDesc
Definition: execnodes.h:411
PartitionDesc partdesc
#define likely(x)
Definition: c.h:272
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:425
static PartitionDispatch ExecInitPartitionDispatchInfo(EState *estate, PartitionTupleRouting *proute, Oid partoid, PartitionDispatch parent_pd, int partidx, ResultRelInfo *rootResultRelInfo)
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
int errcode(int sqlerrcode)
Definition: elog.c:698
#define PARTITION_MAX_KEYS
ResultRelInfo * rootResultRelInfo
Definition: execnodes.h:1196
bool * is_leaf
Definition: partdesc.h:27
Form_pg_class rd_rel
Definition: rel.h:110
#define OidIsValid(objectId)
Definition: c.h:710
ResultRelInfo ** partitions
Definition: attmap.h:34
PartitionBoundInfo boundinfo
Definition: partdesc.h:30
#define GetPerTupleExprContext(estate)
Definition: executor.h:532
#define ERROR
Definition: elog.h:46
TupleTableSlot * ri_PartitionTupleSlot
Definition: execnodes.h:513
static void FormPartitionKeyDatum(PartitionDispatch pd, TupleTableSlot *slot, EState *estate, Datum *values, bool *isnull)
void CheckValidResultRel(ResultRelInfo *resultRelInfo, CmdType operation)
Definition: execMain.c:990
int errdetail(const char *fmt,...)
Definition: elog.c:1042
#define RelationGetRelationName(relation)
Definition: rel.h:491
PartitionDispatch * partition_dispatch_info
Definition: execPartition.c:96
AttrMap * attrMap
Definition: tupconvert.h:28
ResultRelInfo * ExecLookupResultRelByOid(ModifyTableState *node, Oid resultoid, bool missing_ok, bool update_cache)
ResultRelInfo ** nonleaf_partitions
Definition: execPartition.c:97
uintptr_t Datum
Definition: postgres.h:411
TupleTableSlot * tupslot
#define ereport(elevel,...)
Definition: elog.h:157
static ResultRelInfo * ExecInitPartitionInfo(ModifyTableState *mtstate, EState *estate, PartitionTupleRouting *proute, PartitionDispatch dispatch, ResultRelInfo *rootResultRelInfo, int partidx)
TupleTableSlot * execute_attr_map_slot(AttrMap *attrMap, TupleTableSlot *in_slot, TupleTableSlot *out_slot)
Definition: tupconvert.c:177
#define Assert(condition)
Definition: c.h:804
TupleTableSlot * ecxt_scantuple
Definition: execnodes.h:226
static void ExecInitRoutingInfo(ModifyTableState *mtstate, EState *estate, PartitionTupleRouting *proute, PartitionDispatch dispatch, ResultRelInfo *partRelInfo, int partidx, bool is_borrowed_rel)
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:537
static Datum values[MAXATTR]
Definition: bootstrap.c:166
static char * ExecBuildSlotPartitionKeyDescription(Relation rel, Datum *values, bool *isnull, int maxfieldlen)
TupleConversionMap * ri_RootToPartitionMap
Definition: execnodes.h:512
int errmsg(const char *fmt,...)
Definition: elog.c:909
bool ExecPartitionCheck(ResultRelInfo *resultRelInfo, TupleTableSlot *slot, EState *estate, bool emitError)
Definition: execMain.c:1695
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:102
int errtable(Relation rel)
Definition: relcache.c:5534
#define RelationGetRelid(relation)
Definition: rel.h:457
int indexes[FLEXIBLE_ARRAY_MEMBER]

◆ ExecSetupPartitionTupleRouting()

PartitionTupleRouting* ExecSetupPartitionTupleRouting ( EState estate,
Relation  rel 
)

Definition at line 210 of file execPartition.c.

References CurrentMemoryContext, ExecInitPartitionDispatchInfo(), PartitionTupleRouting::memcxt, palloc0(), PartitionTupleRouting::partition_root, and RelationGetRelid.

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

211 {
212  PartitionTupleRouting *proute;
213 
214  /*
215  * Here we attempt to expend as little effort as possible in setting up
216  * the PartitionTupleRouting. Each partition's ResultRelInfo is built on
217  * demand, only when we actually need to route a tuple to that partition.
218  * The reason for this is that a common case is for INSERT to insert a
219  * single tuple into a partitioned table and this must be fast.
220  */
222  proute->partition_root = rel;
223  proute->memcxt = CurrentMemoryContext;
224  /* Rest of members initialized by zeroing */
225 
226  /*
227  * Initialize this table's PartitionDispatch object. Here we pass in the
228  * parent as NULL as we don't need to care about any parent of the target
229  * partitioned table.
230  */
231  ExecInitPartitionDispatchInfo(estate, proute, RelationGetRelid(rel),
232  NULL, 0, NULL);
233 
234  return proute;
235 }
static PartitionDispatch ExecInitPartitionDispatchInfo(EState *estate, PartitionTupleRouting *proute, Oid partoid, PartitionDispatch parent_pd, int partidx, ResultRelInfo *rootResultRelInfo)
MemoryContext CurrentMemoryContext
Definition: mcxt.c:42
void * palloc0(Size size)
Definition: mcxt.c:1093
MemoryContext memcxt
#define RelationGetRelid(relation)
Definition: rel.h:457