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, 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

◆ PartitionTupleRouting

Definition at line 23 of file execPartition.h.

Function Documentation

◆ ExecCleanupTupleRouting()

void ExecCleanupTupleRouting ( ModifyTableState mtstate,
PartitionTupleRouting proute 
)

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

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

◆ ExecCreatePartitionPruneState()

PartitionPruneState* ExecCreatePartitionPruneState ( PlanState planstate,
PartitionPruneInfo partitionpruneinfo 
)

Definition at line 1639 of file execPartition.c.

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

Referenced by ExecInitAppend(), and ExecInitMergeAppend().

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

◆ ExecFindInitialMatchingSubPlans()

Bitmapset* ExecFindInitialMatchingSubPlans ( PartitionPruneState prunestate,
int  nsubplans 
)

Definition at line 1927 of file execPartition.c.

References Assert, bms_add_member(), bms_add_members(), bms_copy(), bms_free(), bms_is_empty(), bms_next_member(), bms_num_members(), PartitionPruneState::do_exec_prune, PartitionPruneState::do_initial_prune, find_matching_subplans_recurse(), i, PartitionedRelPruningData::initial_context, PartitionedRelPruningData::initial_pruning_steps, MemoryContextReset(), MemoryContextSwitchTo(), PartitionedRelPruningData::nparts, PartitionPruneState::num_partprunedata, PartitionPruningData::num_partrelprunedata, PartitionPruneState::other_subplans, palloc0(), PartitionPruneState::partprunedata, PartitionPruningData::partrelprunedata, pfree(), PartitionPruneContext::planstate, PartitionedRelPruningData::present_parts, PartitionPruneState::prune_context, PlanState::ps_ExprContext, ResetExprContext, PartitionedRelPruningData::subpart_map, and PartitionedRelPruningData::subplan_map.

Referenced by ExecInitAppend(), and ExecInitMergeAppend().

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

◆ ExecFindMatchingSubPlans()

Bitmapset* ExecFindMatchingSubPlans ( PartitionPruneState prunestate)

Definition at line 2094 of file execPartition.c.

References Assert, bms_add_members(), bms_copy(), PartitionPruneState::do_exec_prune, PartitionedRelPruningData::exec_context, PartitionedRelPruningData::exec_pruning_steps, find_matching_subplans_recurse(), i, MemoryContextReset(), MemoryContextSwitchTo(), PartitionPruneState::num_partprunedata, PartitionPruneState::other_subplans, PartitionPruneState::partprunedata, PartitionPruningData::partrelprunedata, PartitionPruneContext::planstate, PartitionPruneState::prune_context, PlanState::ps_ExprContext, and ResetExprContext.

Referenced by choose_next_subplan_for_leader(), choose_next_subplan_for_worker(), choose_next_subplan_locally(), and ExecMergeAppend().

2095 {
2096  Bitmapset *result = NULL;
2097  MemoryContext oldcontext;
2098  int i;
2099 
2100  /*
2101  * If !do_exec_prune, we've got problems because
2102  * ExecFindInitialMatchingSubPlans will not have bothered to update
2103  * prunestate for whatever pruning it did.
2104  */
2105  Assert(prunestate->do_exec_prune);
2106 
2107  /*
2108  * Switch to a temp context to avoid leaking memory in the executor's
2109  * query-lifespan memory context.
2110  */
2111  oldcontext = MemoryContextSwitchTo(prunestate->prune_context);
2112 
2113  /*
2114  * For each hierarchy, do the pruning tests, and add nondeletable
2115  * subplans' indexes to "result".
2116  */
2117  for (i = 0; i < prunestate->num_partprunedata; i++)
2118  {
2119  PartitionPruningData *prunedata;
2120  PartitionedRelPruningData *pprune;
2121 
2122  prunedata = prunestate->partprunedata[i];
2123  pprune = &prunedata->partrelprunedata[0];
2124 
2125  find_matching_subplans_recurse(prunedata, pprune, false, &result);
2126 
2127  /* Expression eval may have used space in node's ps_ExprContext too */
2128  if (pprune->exec_pruning_steps)
2130  }
2131 
2132  /* Add in any subplans that partition pruning didn't account for */
2133  result = bms_add_members(result, prunestate->other_subplans);
2134 
2135  MemoryContextSwitchTo(oldcontext);
2136 
2137  /* Copy result out of the temp context before we reset it */
2138  result = bms_copy(result);
2139 
2140  MemoryContextReset(prunestate->prune_context);
2141 
2142  return result;
2143 }
MemoryContext prune_context
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:74
ExprContext * ps_ExprContext
Definition: execnodes.h:973
PartitionPruningData * partprunedata[FLEXIBLE_ARRAY_MEMBER]
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:137
static void find_matching_subplans_recurse(PartitionPruningData *prunedata, PartitionedRelPruningData *pprune, bool initial_prune, Bitmapset **validsubplans)
PartitionPruneContext exec_context
Definition: execPartition.h:57
#define Assert(condition)
Definition: c.h:792
PartitionedRelPruningData partrelprunedata[FLEXIBLE_ARRAY_MEMBER]
Definition: execPartition.h:70
int i
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:793
#define ResetExprContext(econtext)
Definition: executor.h:503
Bitmapset * other_subplans
PlanState * planstate
Definition: partprune.h:58

◆ ExecFindPartition()

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

Definition at line 277 of file execPartition.c.

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

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

281 {
284  bool isnull[PARTITION_MAX_KEYS];
285  Relation rel;
286  PartitionDispatch dispatch;
287  PartitionDesc partdesc;
288  ExprContext *ecxt = GetPerTupleExprContext(estate);
289  TupleTableSlot *ecxt_scantuple_saved = ecxt->ecxt_scantuple;
290  TupleTableSlot *rootslot = slot;
291  TupleTableSlot *myslot = NULL;
292  MemoryContext oldcxt;
293  ResultRelInfo *rri = NULL;
294 
295  /* use per-tuple context here to avoid leaking memory */
297 
298  /*
299  * First check the root table's partition constraint, if any. No point in
300  * routing the tuple if it doesn't belong in the root table itself.
301  */
302  if (rootResultRelInfo->ri_RelationDesc->rd_rel->relispartition)
303  ExecPartitionCheck(rootResultRelInfo, slot, estate, true);
304 
305  /* start with the root partitioned table */
306  dispatch = pd[0];
307  while (dispatch != NULL)
308  {
309  int partidx = -1;
310  bool is_leaf;
311 
313 
314  rel = dispatch->reldesc;
315  partdesc = dispatch->partdesc;
316 
317  /*
318  * Extract partition key from tuple. Expression evaluation machinery
319  * that FormPartitionKeyDatum() invokes expects ecxt_scantuple to
320  * point to the correct tuple slot. The slot might have changed from
321  * what was used for the parent table if the table of the current
322  * partitioning level has different tuple descriptor from the parent.
323  * So update ecxt_scantuple accordingly.
324  */
325  ecxt->ecxt_scantuple = slot;
326  FormPartitionKeyDatum(dispatch, slot, estate, values, isnull);
327 
328  /*
329  * If this partitioned table has no partitions or no partition for
330  * these values, error out.
331  */
332  if (partdesc->nparts == 0 ||
333  (partidx = get_partition_for_tuple(dispatch, values, isnull)) < 0)
334  {
335  char *val_desc;
336 
338  values, isnull, 64);
340  ereport(ERROR,
341  (errcode(ERRCODE_CHECK_VIOLATION),
342  errmsg("no partition of relation \"%s\" found for row",
344  val_desc ?
345  errdetail("Partition key of the failing row contains %s.",
346  val_desc) : 0,
347  errtable(rel)));
348  }
349 
350  is_leaf = partdesc->is_leaf[partidx];
351  if (is_leaf)
352  {
353 
354  /*
355  * We've reached the leaf -- hurray, we're done. Look to see if
356  * we've already got a ResultRelInfo for this partition.
357  */
358  if (likely(dispatch->indexes[partidx] >= 0))
359  {
360  /* ResultRelInfo already built */
361  Assert(dispatch->indexes[partidx] < proute->num_partitions);
362  rri = proute->partitions[dispatch->indexes[partidx]];
363  }
364  else
365  {
366  bool found = false;
367 
368  /*
369  * We have not yet set up a ResultRelInfo for this partition,
370  * but if we have a subplan hash table, we might have one
371  * there. If not, we'll have to create one.
372  */
373  if (proute->subplan_resultrel_htab)
374  {
375  Oid partoid = partdesc->oids[partidx];
377 
378  elem = hash_search(proute->subplan_resultrel_htab,
379  &partoid, HASH_FIND, NULL);
380  if (elem)
381  {
382  found = true;
383  rri = elem->rri;
384 
385  /* Verify this ResultRelInfo allows INSERTs */
387 
388  /*
389  * Initialize information needed to insert this and
390  * subsequent tuples routed to this partition.
391  */
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  Assert(rri != NULL);
404 
405  /* Signal to terminate the loop */
406  dispatch = NULL;
407  }
408  else
409  {
410  /*
411  * Partition is a sub-partitioned table; get the PartitionDispatch
412  */
413  if (likely(dispatch->indexes[partidx] >= 0))
414  {
415  /* Already built. */
416  Assert(dispatch->indexes[partidx] < proute->num_dispatch);
417 
418  rri = proute->nonleaf_partitions[dispatch->indexes[partidx]];
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 
442  rri = proute->nonleaf_partitions[dispatch->indexes[partidx]];
443  dispatch = subdispatch;
444  }
445 
446  /*
447  * Convert the tuple to the new parent's layout, if different from
448  * the previous parent.
449  */
450  if (dispatch->tupslot)
451  {
452  AttrMap *map = dispatch->tupmap;
453  TupleTableSlot *tempslot = myslot;
454 
455  myslot = dispatch->tupslot;
456  slot = execute_attr_map_slot(map, slot, myslot);
457 
458  if (tempslot != NULL)
459  ExecClearTuple(tempslot);
460  }
461  }
462 
463  /*
464  * If this partition is the default one, we must check its partition
465  * constraint now, which may have changed concurrently due to
466  * partitions being added to the parent.
467  *
468  * (We do this here, and do not rely on ExecInsert doing it, because
469  * we don't want to miss doing it for non-leaf partitions.)
470  */
471  if (partidx == partdesc->boundinfo->default_index)
472  {
473  /*
474  * The tuple must match the partition's layout for the constraint
475  * expression to be evaluated successfully. If the partition is
476  * sub-partitioned, that would already be the case due to the code
477  * above, but for a leaf partition the tuple still matches the
478  * parent's layout.
479  *
480  * Note that we have a map to convert from root to current
481  * partition, but not from immediate parent to current partition.
482  * So if we have to convert, do it from the root slot; if not, use
483  * the root slot as-is.
484  */
485  if (is_leaf)
486  {
488 
489  if (map)
490  slot = execute_attr_map_slot(map->attrMap, rootslot,
491  rri->ri_PartitionTupleSlot);
492  else
493  slot = rootslot;
494  }
495 
496  ExecPartitionCheck(rri, slot, estate, true);
497  }
498  }
499 
500  /* Release the tuple in the lowest parent's dedicated slot. */
501  if (myslot != NULL)
502  ExecClearTuple(myslot);
503  /* and restore ecxt's scantuple */
504  ecxt->ecxt_scantuple = ecxt_scantuple_saved;
505  MemoryContextSwitchTo(oldcxt);
506 
507  return rri;
508 }
static int get_partition_for_tuple(PartitionDispatch pd, Datum *values, bool *isnull)
Relation ri_RelationDesc
Definition: execnodes.h:412
PartitionDesc partdesc
#define likely(x)
Definition: c.h:260
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:704
#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:954
EState * state
Definition: execnodes.h:936
Form_pg_class rd_rel
Definition: rel.h:110
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:698
ResultRelInfo ** partitions
Definition: attmap.h:34
PartitionBoundInfo boundinfo
Definition: partdesc.h:29
#define GetPerTupleExprContext(estate)
Definition: executor.h:509
#define ERROR
Definition: elog.h:45
PlanState ps
Definition: execnodes.h:1154
TupleTableSlot * ri_PartitionTupleSlot
Definition: execnodes.h:498
static void FormPartitionKeyDatum(PartitionDispatch pd, TupleTableSlot *slot, EState *estate, Datum *values, bool *isnull)
void CheckValidResultRel(ResultRelInfo *resultRelInfo, CmdType operation)
Definition: execMain.c:995
int errdetail(const char *fmt,...)
Definition: elog.c:1048
#define RelationGetRelationName(relation)
Definition: rel.h:491
PartitionDispatch * partition_dispatch_info
Definition: execPartition.c:96
AttrMap * attrMap
Definition: tupconvert.h:27
ResultRelInfo ** nonleaf_partitions
Definition: execPartition.c:97
static PartitionDispatch ExecInitPartitionDispatchInfo(EState *estate, PartitionTupleRouting *proute, Oid partoid, PartitionDispatch parent_pd, int partidx)
uintptr_t Datum
Definition: postgres.h:367
TupleTableSlot * tupslot
#define ereport(elevel,...)
Definition: elog.h:155
static ResultRelInfo * ExecInitPartitionInfo(ModifyTableState *mtstate, EState *estate, PartitionTupleRouting *proute, PartitionDispatch dispatch, ResultRelInfo *rootResultRelInfo, int partidx)
TupleTableSlot * execute_attr_map_slot(AttrMap *attrMap, TupleTableSlot *in_slot, TupleTableSlot *out_slot)
Definition: tupconvert.c:177
#define Assert(condition)
Definition: c.h:792
TupleTableSlot * ecxt_scantuple
Definition: execnodes.h:225
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:514
static Datum values[MAXATTR]
Definition: bootstrap.c:165
static char * ExecBuildSlotPartitionKeyDescription(Relation rel, Datum *values, bool *isnull, int maxfieldlen)
TupleConversionMap * ri_RootToPartitionMap
Definition: execnodes.h:497
int errmsg(const char *fmt,...)
Definition: elog.c:915
bool ExecPartitionCheck(ResultRelInfo *resultRelInfo, TupleTableSlot *slot, EState *estate, bool emitError)
Definition: execMain.c:1679
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:100
int errtable(Relation rel)
Definition: relcache.c:5509
static void ExecInitRoutingInfo(ModifyTableState *mtstate, EState *estate, PartitionTupleRouting *proute, PartitionDispatch dispatch, ResultRelInfo *partRelInfo, int partidx)
#define RelationGetRelid(relation)
Definition: rel.h:457
int indexes[FLEXIBLE_ARRAY_MEMBER]

◆ ExecSetupPartitionTupleRouting()

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

Definition at line 217 of file execPartition.c.

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

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

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