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

Go to the source code of this file.

Data Structures

struct  PartitionRoutingInfo
 
struct  PartitionedRelPruningData
 
struct  PartitionPruningData
 
struct  PartitionPruneState
 

Typedefs

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

Functions

PartitionTupleRoutingExecSetupPartitionTupleRouting (EState *estate, ModifyTableState *mtstate, Relation rel)
 
ResultRelInfoExecFindPartition (ModifyTableState *mtstate, ResultRelInfo *rootResultRelInfo, PartitionTupleRouting *proute, TupleTableSlot *slot, EState *estate)
 
void ExecCleanupTupleRouting (ModifyTableState *mtstate, PartitionTupleRouting *proute)
 
PartitionPruneStateExecCreatePartitionPruneState (PlanState *planstate, PartitionPruneInfo *partitionpruneinfo)
 
BitmapsetExecFindMatchingSubPlans (PartitionPruneState *prunestate)
 
BitmapsetExecFindInitialMatchingSubPlans (PartitionPruneState *prunestate, int nsubplans)
 

Typedef Documentation

◆ PartitionDispatch

Definition at line 22 of file execPartition.h.

◆ PartitionedRelPruningData

◆ PartitionPruneState

◆ PartitionPruningData

◆ PartitionRoutingInfo

◆ PartitionTupleRouting

Definition at line 23 of file execPartition.h.

Function Documentation

◆ ExecCleanupTupleRouting()

void ExecCleanupTupleRouting ( ModifyTableState mtstate,
PartitionTupleRouting proute 
)

Definition at line 1096 of file execPartition.c.

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

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

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

◆ ExecCreatePartitionPruneState()

PartitionPruneState* ExecCreatePartitionPruneState ( PlanState planstate,
PartitionPruneInfo partitionpruneinfo 
)

Definition at line 1551 of file execPartition.c.

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, Assert, bms_add_members(), bms_copy(), CreatePartitionDirectory(), CurrentMemoryContext, PartitionPruneState::do_exec_prune, PartitionPruneState::do_initial_prune, 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().

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

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

◆ ExecFindMatchingSubPlans()

Bitmapset* ExecFindMatchingSubPlans ( PartitionPruneState prunestate)

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

2007 {
2008  Bitmapset *result = NULL;
2009  MemoryContext oldcontext;
2010  int i;
2011 
2012  /*
2013  * If !do_exec_prune, we've got problems because
2014  * ExecFindInitialMatchingSubPlans will not have bothered to update
2015  * prunestate for whatever pruning it did.
2016  */
2017  Assert(prunestate->do_exec_prune);
2018 
2019  /*
2020  * Switch to a temp context to avoid leaking memory in the executor's
2021  * query-lifespan memory context.
2022  */
2023  oldcontext = MemoryContextSwitchTo(prunestate->prune_context);
2024 
2025  /*
2026  * For each hierarchy, do the pruning tests, and add nondeletable
2027  * subplans' indexes to "result".
2028  */
2029  for (i = 0; i < prunestate->num_partprunedata; i++)
2030  {
2031  PartitionPruningData *prunedata;
2032  PartitionedRelPruningData *pprune;
2033 
2034  prunedata = prunestate->partprunedata[i];
2035  pprune = &prunedata->partrelprunedata[0];
2036 
2037  find_matching_subplans_recurse(prunedata, pprune, false, &result);
2038 
2039  /* Expression eval may have used space in node's ps_ExprContext too */
2040  if (pprune->exec_pruning_steps)
2042  }
2043 
2044  /* Add in any subplans that partition pruning didn't account for */
2045  result = bms_add_members(result, prunestate->other_subplans);
2046 
2047  MemoryContextSwitchTo(oldcontext);
2048 
2049  /* Copy result out of the temp context before we reset it */
2050  result = bms_copy(result);
2051 
2052  MemoryContextReset(prunestate->prune_context);
2053 
2054  return result;
2055 }
MemoryContext prune_context
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:74
ExprContext * ps_ExprContext
Definition: execnodes.h:984
PartitionPruningData * partprunedata[FLEXIBLE_ARRAY_MEMBER]
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:136
static void find_matching_subplans_recurse(PartitionPruningData *prunedata, PartitionedRelPruningData *pprune, bool initial_prune, Bitmapset **validsubplans)
PartitionPruneContext exec_context
Definition: execPartition.h:84
#define Assert(condition)
Definition: c.h:745
PartitionedRelPruningData partrelprunedata[FLEXIBLE_ARRAY_MEMBER]
Definition: execPartition.h:97
int i
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:793
#define ResetExprContext(econtext)
Definition: executor.h:501
Bitmapset * other_subplans
PlanState * planstate
Definition: partprune.h:58

◆ ExecFindPartition()

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

Definition at line 271 of file execPartition.c.

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

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

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

◆ ExecSetupPartitionTupleRouting()

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

Definition at line 211 of file execPartition.c.

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

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

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