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 1124 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 CopyFrom(), ExecEndModifyTable(), and finish_edata().

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

◆ ExecCreatePartitionPruneState()

PartitionPruneState* ExecCreatePartitionPruneState ( PlanState planstate,
PartitionPruneInfo partitionpruneinfo 
)

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

1533 {
1534  EState *estate = planstate->state;
1535  PartitionPruneState *prunestate;
1536  int n_part_hierarchies;
1537  ListCell *lc;
1538  int i;
1539 
1540  /* For data reading, executor always omits detached partitions */
1541  if (estate->es_partition_directory == NULL)
1542  estate->es_partition_directory =
1543  CreatePartitionDirectory(estate->es_query_cxt, false);
1544 
1545  n_part_hierarchies = list_length(partitionpruneinfo->prune_infos);
1546  Assert(n_part_hierarchies > 0);
1547 
1548  /*
1549  * Allocate the data structure
1550  */
1551  prunestate = (PartitionPruneState *)
1552  palloc(offsetof(PartitionPruneState, partprunedata) +
1553  sizeof(PartitionPruningData *) * n_part_hierarchies);
1554 
1555  prunestate->execparamids = NULL;
1556  /* other_subplans can change at runtime, so we need our own copy */
1557  prunestate->other_subplans = bms_copy(partitionpruneinfo->other_subplans);
1558  prunestate->do_initial_prune = false; /* may be set below */
1559  prunestate->do_exec_prune = false; /* may be set below */
1560  prunestate->num_partprunedata = n_part_hierarchies;
1561 
1562  /*
1563  * Create a short-term memory context which we'll use when making calls to
1564  * the partition pruning functions. This avoids possible memory leaks,
1565  * since the pruning functions call comparison functions that aren't under
1566  * our control.
1567  */
1568  prunestate->prune_context =
1570  "Partition Prune",
1572 
1573  i = 0;
1574  foreach(lc, partitionpruneinfo->prune_infos)
1575  {
1576  List *partrelpruneinfos = lfirst_node(List, lc);
1577  int npartrelpruneinfos = list_length(partrelpruneinfos);
1578  PartitionPruningData *prunedata;
1579  ListCell *lc2;
1580  int j;
1581 
1582  prunedata = (PartitionPruningData *)
1583  palloc(offsetof(PartitionPruningData, partrelprunedata) +
1584  npartrelpruneinfos * sizeof(PartitionedRelPruningData));
1585  prunestate->partprunedata[i] = prunedata;
1586  prunedata->num_partrelprunedata = npartrelpruneinfos;
1587 
1588  j = 0;
1589  foreach(lc2, partrelpruneinfos)
1590  {
1592  PartitionedRelPruningData *pprune = &prunedata->partrelprunedata[j];
1593  Relation partrel;
1594  PartitionDesc partdesc;
1595  PartitionKey partkey;
1596 
1597  /*
1598  * We can rely on the copies of the partitioned table's partition
1599  * key and partition descriptor appearing in its relcache entry,
1600  * because that entry will be held open and locked for the
1601  * duration of this executor run.
1602  */
1603  partrel = ExecGetRangeTableRelation(estate, pinfo->rtindex);
1604  partkey = RelationGetPartitionKey(partrel);
1606  partrel);
1607 
1608  /*
1609  * Initialize the subplan_map and subpart_map.
1610  *
1611  * Because we request detached partitions to be included, and
1612  * detaching waits for old transactions, it is safe to assume that
1613  * no partitions have disappeared since this query was planned.
1614  *
1615  * However, new partitions may have been added.
1616  */
1617  Assert(partdesc->nparts >= pinfo->nparts);
1618  pprune->nparts = partdesc->nparts;
1619  pprune->subplan_map = palloc(sizeof(int) * partdesc->nparts);
1620  if (partdesc->nparts == pinfo->nparts)
1621  {
1622  /*
1623  * There are no new partitions, so this is simple. We can
1624  * simply point to the subpart_map from the plan, but we must
1625  * copy the subplan_map since we may change it later.
1626  */
1627  pprune->subpart_map = pinfo->subpart_map;
1628  memcpy(pprune->subplan_map, pinfo->subplan_map,
1629  sizeof(int) * pinfo->nparts);
1630 
1631  /*
1632  * Double-check that the list of unpruned relations has not
1633  * changed. (Pruned partitions are not in relid_map[].)
1634  */
1635 #ifdef USE_ASSERT_CHECKING
1636  for (int k = 0; k < pinfo->nparts; k++)
1637  {
1638  Assert(partdesc->oids[k] == pinfo->relid_map[k] ||
1639  pinfo->subplan_map[k] == -1);
1640  }
1641 #endif
1642  }
1643  else
1644  {
1645  int pd_idx = 0;
1646  int pp_idx;
1647 
1648  /*
1649  * Some new partitions have appeared since plan time, and
1650  * those are reflected in our PartitionDesc but were not
1651  * present in the one used to construct subplan_map and
1652  * subpart_map. So we must construct new and longer arrays
1653  * where the partitions that were originally present map to
1654  * the same sub-structures, and any added partitions map to
1655  * -1, as if the new partitions had been pruned.
1656  *
1657  * Note: pinfo->relid_map[] may contain InvalidOid entries for
1658  * partitions pruned by the planner. We cannot tell exactly
1659  * which of the partdesc entries these correspond to, but we
1660  * don't have to; just skip over them. The non-pruned
1661  * relid_map entries, however, had better be a subset of the
1662  * partdesc entries and in the same order.
1663  */
1664  pprune->subpart_map = palloc(sizeof(int) * partdesc->nparts);
1665  for (pp_idx = 0; pp_idx < partdesc->nparts; pp_idx++)
1666  {
1667  /* Skip any InvalidOid relid_map entries */
1668  while (pd_idx < pinfo->nparts &&
1669  !OidIsValid(pinfo->relid_map[pd_idx]))
1670  pd_idx++;
1671 
1672  if (pd_idx < pinfo->nparts &&
1673  pinfo->relid_map[pd_idx] == partdesc->oids[pp_idx])
1674  {
1675  /* match... */
1676  pprune->subplan_map[pp_idx] =
1677  pinfo->subplan_map[pd_idx];
1678  pprune->subpart_map[pp_idx] =
1679  pinfo->subpart_map[pd_idx];
1680  pd_idx++;
1681  }
1682  else
1683  {
1684  /* this partdesc entry is not in the plan */
1685  pprune->subplan_map[pp_idx] = -1;
1686  pprune->subpart_map[pp_idx] = -1;
1687  }
1688  }
1689 
1690  /*
1691  * It might seem that we need to skip any trailing InvalidOid
1692  * entries in pinfo->relid_map before checking that we scanned
1693  * all of the relid_map. But we will have skipped them above,
1694  * because they must correspond to some partdesc->oids
1695  * entries; we just couldn't tell which.
1696  */
1697  if (pd_idx != pinfo->nparts)
1698  elog(ERROR, "could not match partition child tables to plan elements");
1699  }
1700 
1701  /* present_parts is also subject to later modification */
1702  pprune->present_parts = bms_copy(pinfo->present_parts);
1703 
1704  /*
1705  * Initialize pruning contexts as needed.
1706  */
1708  if (pinfo->initial_pruning_steps)
1709  {
1711  pinfo->initial_pruning_steps,
1712  partdesc, partkey, planstate);
1713  /* Record whether initial pruning is needed at any level */
1714  prunestate->do_initial_prune = true;
1715  }
1716  pprune->exec_pruning_steps = pinfo->exec_pruning_steps;
1717  if (pinfo->exec_pruning_steps)
1718  {
1720  pinfo->exec_pruning_steps,
1721  partdesc, partkey, planstate);
1722  /* Record whether exec pruning is needed at any level */
1723  prunestate->do_exec_prune = true;
1724  }
1725 
1726  /*
1727  * Accumulate the IDs of all PARAM_EXEC Params affecting the
1728  * partitioning decisions at this plan node.
1729  */
1730  prunestate->execparamids = bms_add_members(prunestate->execparamids,
1731  pinfo->execparamids);
1732 
1733  j++;
1734  }
1735  i++;
1736  }
1737 
1738  return prunestate;
1739 }
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
PartitionDirectory CreatePartitionDirectory(MemoryContext mcxt, bool omit_detached)
Definition: partdesc.c:377
PartitionPruningData * partprunedata[FLEXIBLE_ARRAY_MEMBER]
EState * state
Definition: execnodes.h:968
PartitionKey RelationGetPartitionKey(Relation rel)
Definition: partcache.c:54
#define OidIsValid(objectId)
Definition: c.h:710
MemoryContext es_query_cxt
Definition: execnodes.h:600
#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
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:582
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:410
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 1823 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().

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

◆ ExecFindMatchingSubPlans()

Bitmapset* ExecFindMatchingSubPlans ( PartitionPruneState prunestate)

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

1991 {
1992  Bitmapset *result = NULL;
1993  MemoryContext oldcontext;
1994  int i;
1995 
1996  /*
1997  * If !do_exec_prune, we've got problems because
1998  * ExecFindInitialMatchingSubPlans will not have bothered to update
1999  * prunestate for whatever pruning it did.
2000  */
2001  Assert(prunestate->do_exec_prune);
2002 
2003  /*
2004  * Switch to a temp context to avoid leaking memory in the executor's
2005  * query-lifespan memory context.
2006  */
2007  oldcontext = MemoryContextSwitchTo(prunestate->prune_context);
2008 
2009  /*
2010  * For each hierarchy, do the pruning tests, and add nondeletable
2011  * subplans' indexes to "result".
2012  */
2013  for (i = 0; i < prunestate->num_partprunedata; i++)
2014  {
2015  PartitionPruningData *prunedata;
2016  PartitionedRelPruningData *pprune;
2017 
2018  prunedata = prunestate->partprunedata[i];
2019  pprune = &prunedata->partrelprunedata[0];
2020 
2021  find_matching_subplans_recurse(prunedata, pprune, false, &result);
2022 
2023  /* Expression eval may have used space in node's ps_ExprContext too */
2024  if (pprune->exec_pruning_steps)
2026  }
2027 
2028  /* Add in any subplans that partition pruning didn't account for */
2029  result = bms_add_members(result, prunestate->other_subplans);
2030 
2031  MemoryContextSwitchTo(oldcontext);
2032 
2033  /* Copy result out of the temp context before we reset it */
2034  result = bms_copy(result);
2035 
2036  MemoryContextReset(prunestate->prune_context);
2037 
2038  return result;
2039 }
MemoryContext prune_context
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:74
ExprContext * ps_ExprContext
Definition: execnodes.h:1005
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:527
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:1200
bool * is_leaf
Definition: partdesc.h:35
Form_pg_class rd_rel
Definition: rel.h:109
#define OidIsValid(objectId)
Definition: c.h:710
ResultRelInfo ** partitions
Definition: attmap.h:34
PartitionBoundInfo boundinfo
Definition: partdesc.h:38
#define GetPerTupleExprContext(estate)
Definition: executor.h:533
#define ERROR
Definition: elog.h:46
TupleTableSlot * ri_PartitionTupleSlot
Definition: execnodes.h:514
static void FormPartitionKeyDatum(PartitionDispatch pd, TupleTableSlot *slot, EState *estate, Datum *values, bool *isnull)
void CheckValidResultRel(ResultRelInfo *resultRelInfo, CmdType operation)
Definition: execMain.c:992
int errdetail(const char *fmt,...)
Definition: elog.c:1042
#define RelationGetRelationName(relation)
Definition: rel.h:511
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:538
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:513
int errmsg(const char *fmt,...)
Definition: elog.c:909
bool ExecPartitionCheck(ResultRelInfo *resultRelInfo, TupleTableSlot *slot, EState *estate, bool emitError)
Definition: execMain.c:1697
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:120
int errtable(Relation rel)
Definition: relcache.c:5636
#define RelationGetRelid(relation)
Definition: rel.h:477
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:477