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 1168 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().

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

◆ ExecCreatePartitionPruneState()

PartitionPruneState* ExecCreatePartitionPruneState ( PlanState planstate,
PartitionPruneInfo partitionpruneinfo 
)

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

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

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

◆ ExecFindMatchingSubPlans()

Bitmapset* ExecFindMatchingSubPlans ( PartitionPruneState prunestate)

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

2079 {
2080  Bitmapset *result = NULL;
2081  MemoryContext oldcontext;
2082  int i;
2083 
2084  /*
2085  * If !do_exec_prune, we've got problems because
2086  * ExecFindInitialMatchingSubPlans will not have bothered to update
2087  * prunestate for whatever pruning it did.
2088  */
2089  Assert(prunestate->do_exec_prune);
2090 
2091  /*
2092  * Switch to a temp context to avoid leaking memory in the executor's
2093  * query-lifespan memory context.
2094  */
2095  oldcontext = MemoryContextSwitchTo(prunestate->prune_context);
2096 
2097  /*
2098  * For each hierarchy, do the pruning tests, and add nondeletable
2099  * subplans' indexes to "result".
2100  */
2101  for (i = 0; i < prunestate->num_partprunedata; i++)
2102  {
2103  PartitionPruningData *prunedata;
2104  PartitionedRelPruningData *pprune;
2105 
2106  prunedata = prunestate->partprunedata[i];
2107  pprune = &prunedata->partrelprunedata[0];
2108 
2109  find_matching_subplans_recurse(prunedata, pprune, false, &result);
2110 
2111  /* Expression eval may have used space in node's ps_ExprContext too */
2112  if (pprune->exec_pruning_steps)
2114  }
2115 
2116  /* Add in any subplans that partition pruning didn't account for */
2117  result = bms_add_members(result, prunestate->other_subplans);
2118 
2119  MemoryContextSwitchTo(oldcontext);
2120 
2121  /* Copy result out of the temp context before we reset it */
2122  result = bms_copy(result);
2123 
2124  MemoryContextReset(prunestate->prune_context);
2125 
2126  return result;
2127 }
MemoryContext prune_context
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:74
ExprContext * ps_ExprContext
Definition: execnodes.h:978
PartitionPruningData * partprunedata[FLEXIBLE_ARRAY_MEMBER]
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c: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:746
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:500
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:206
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:919
EState * state
Definition: execnodes.h:941
Form_pg_class rd_rel
Definition: rel.h:109
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:652
ResultRelInfo ** partitions
Definition: attmap.h:34
PartitionBoundInfo boundinfo
Definition: partdesc.h:29
#define GetPerTupleExprContext(estate)
Definition: executor.h:506
#define ERROR
Definition: elog.h:43
PlanState ps
Definition: execnodes.h:1159
TupleTableSlot * ri_PartitionTupleSlot
Definition: execnodes.h:492
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:954
#define RelationGetRelationName(relation)
Definition: rel.h:490
PartitionDispatch * partition_dispatch_info
Definition: execPartition.c:96
AttrMap * attrMap
Definition: tupconvert.h:27
ResultRelInfo ** nonleaf_partitions
Definition: execPartition.c:97
static PartitionDispatch ExecInitPartitionDispatchInfo(EState *estate, PartitionTupleRouting *proute, Oid partoid, PartitionDispatch parent_pd, int partidx)
uintptr_t Datum
Definition: postgres.h:367
TupleTableSlot * tupslot
#define ereport(elevel,...)
Definition: elog.h:144
static ResultRelInfo * ExecInitPartitionInfo(ModifyTableState *mtstate, EState *estate, PartitionTupleRouting *proute, PartitionDispatch dispatch, ResultRelInfo *rootResultRelInfo, int partidx)
TupleTableSlot * execute_attr_map_slot(AttrMap *attrMap, TupleTableSlot *in_slot, TupleTableSlot *out_slot)
Definition: tupconvert.c:177
#define Assert(condition)
Definition: c.h:746
TupleTableSlot * ecxt_scantuple
Definition: execnodes.h:225
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:511
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:491
int errmsg(const char *fmt,...)
Definition: elog.c:821
bool ExecPartitionCheck(ResultRelInfo *resultRelInfo, TupleTableSlot *slot, EState *estate, bool emitError)
Definition: execMain.c:1679
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:99
int errtable(Relation rel)
Definition: relcache.c:5497
static void ExecInitRoutingInfo(ModifyTableState *mtstate, EState *estate, PartitionTupleRouting *proute, PartitionDispatch dispatch, ResultRelInfo *partRelInfo, int partidx)
#define RelationGetRelid(relation)
Definition: rel.h:456
int indexes[FLEXIBLE_ARRAY_MEMBER]

◆ 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:1159
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:939
CmdType operation
Definition: plannodes.h:215
MemoryContext memcxt
#define RelationGetRelid(relation)
Definition: rel.h:456