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

1096 {
1097  HTAB *htab = proute->subplan_resultrel_htab;
1098  int i;
1099 
1100  /*
1101  * Remember, proute->partition_dispatch_info[0] corresponds to the root
1102  * partitioned table, which we must not try to close, because it is the
1103  * main target table of the query that will be closed by callers such as
1104  * ExecEndPlan() or DoCopy(). Also, tupslot is NULL for the root
1105  * partitioned table.
1106  */
1107  for (i = 1; i < proute->num_dispatch; i++)
1108  {
1110 
1111  table_close(pd->reldesc, NoLock);
1112 
1113  if (pd->tupslot)
1115  }
1116 
1117  for (i = 0; i < proute->num_partitions; i++)
1118  {
1119  ResultRelInfo *resultRelInfo = proute->partitions[i];
1120 
1121  /* Allow any FDWs to shut down */
1122  if (resultRelInfo->ri_FdwRoutine != NULL &&
1123  resultRelInfo->ri_FdwRoutine->EndForeignInsert != NULL)
1124  resultRelInfo->ri_FdwRoutine->EndForeignInsert(mtstate->ps.state,
1125  resultRelInfo);
1126 
1127  /*
1128  * Check if this result rel is one belonging to the node's subplans,
1129  * if so, let ExecEndPlan() clean it up.
1130  */
1131  if (htab)
1132  {
1133  Oid partoid;
1134  bool found;
1135 
1136  partoid = RelationGetRelid(resultRelInfo->ri_RelationDesc);
1137 
1138  (void) hash_search(htab, &partoid, HASH_FIND, &found);
1139  if (found)
1140  continue;
1141  }
1142 
1143  ExecCloseIndices(resultRelInfo);
1144  table_close(resultRelInfo->ri_RelationDesc, NoLock);
1145  }
1146 }
Relation ri_RelationDesc
Definition: execnodes.h:411
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:906
EState * state
Definition: execnodes.h:945
unsigned int Oid
Definition: postgres_ext.h:31
ResultRelInfo ** partitions
Definition: execPartition.c:93
Definition: dynahash.c:208
PlanState ps
Definition: execnodes.h:1163
#define NoLock
Definition: lockdefs.h:34
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:1224
struct FdwRoutine * ri_FdwRoutine
Definition: execnodes.h:440
PartitionDispatch * partition_dispatch_info
Definition: execPartition.c:90
TupleTableSlot * tupslot
int i
#define RelationGetRelid(relation)
Definition: rel.h:428
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 1549 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, 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, 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().

1551 {
1552  EState *estate = planstate->state;
1553  PartitionPruneState *prunestate;
1554  int n_part_hierarchies;
1555  ListCell *lc;
1556  int i;
1557 
1558  if (estate->es_partition_directory == NULL)
1559  estate->es_partition_directory =
1561 
1562  n_part_hierarchies = list_length(partitionpruneinfo->prune_infos);
1563  Assert(n_part_hierarchies > 0);
1564 
1565  /*
1566  * Allocate the data structure
1567  */
1568  prunestate = (PartitionPruneState *)
1569  palloc(offsetof(PartitionPruneState, partprunedata) +
1570  sizeof(PartitionPruningData *) * n_part_hierarchies);
1571 
1572  prunestate->execparamids = NULL;
1573  /* other_subplans can change at runtime, so we need our own copy */
1574  prunestate->other_subplans = bms_copy(partitionpruneinfo->other_subplans);
1575  prunestate->do_initial_prune = false; /* may be set below */
1576  prunestate->do_exec_prune = false; /* may be set below */
1577  prunestate->num_partprunedata = n_part_hierarchies;
1578 
1579  /*
1580  * Create a short-term memory context which we'll use when making calls to
1581  * the partition pruning functions. This avoids possible memory leaks,
1582  * since the pruning functions call comparison functions that aren't under
1583  * our control.
1584  */
1585  prunestate->prune_context =
1587  "Partition Prune",
1589 
1590  i = 0;
1591  foreach(lc, partitionpruneinfo->prune_infos)
1592  {
1593  List *partrelpruneinfos = lfirst_node(List, lc);
1594  int npartrelpruneinfos = list_length(partrelpruneinfos);
1595  PartitionPruningData *prunedata;
1596  ListCell *lc2;
1597  int j;
1598 
1599  prunedata = (PartitionPruningData *)
1600  palloc(offsetof(PartitionPruningData, partrelprunedata) +
1601  npartrelpruneinfos * sizeof(PartitionedRelPruningData));
1602  prunestate->partprunedata[i] = prunedata;
1603  prunedata->num_partrelprunedata = npartrelpruneinfos;
1604 
1605  j = 0;
1606  foreach(lc2, partrelpruneinfos)
1607  {
1609  PartitionedRelPruningData *pprune = &prunedata->partrelprunedata[j];
1610  Relation partrel;
1611  PartitionDesc partdesc;
1612  PartitionKey partkey;
1613 
1614  /*
1615  * We can rely on the copies of the partitioned table's partition
1616  * key and partition descriptor appearing in its relcache entry,
1617  * because that entry will be held open and locked for the
1618  * duration of this executor run.
1619  */
1620  partrel = ExecGetRangeTableRelation(estate, pinfo->rtindex);
1621  partkey = RelationGetPartitionKey(partrel);
1623  partrel);
1624 
1625  /*
1626  * Initialize the subplan_map and subpart_map. Since detaching a
1627  * partition requires AccessExclusiveLock, no partitions can have
1628  * disappeared, nor can the bounds for any partition have changed.
1629  * However, new partitions may have been added.
1630  */
1631  Assert(partdesc->nparts >= pinfo->nparts);
1632  pprune->nparts = partdesc->nparts;
1633  pprune->subplan_map = palloc(sizeof(int) * partdesc->nparts);
1634  if (partdesc->nparts == pinfo->nparts)
1635  {
1636  /*
1637  * There are no new partitions, so this is simple. We can
1638  * simply point to the subpart_map from the plan, but we must
1639  * copy the subplan_map since we may change it later.
1640  */
1641  pprune->subpart_map = pinfo->subpart_map;
1642  memcpy(pprune->subplan_map, pinfo->subplan_map,
1643  sizeof(int) * pinfo->nparts);
1644 
1645  /*
1646  * Double-check that the list of unpruned relations has not
1647  * changed. (Pruned partitions are not in relid_map[].)
1648  */
1649 #ifdef USE_ASSERT_CHECKING
1650  for (int k = 0; k < pinfo->nparts; k++)
1651  {
1652  Assert(partdesc->oids[k] == pinfo->relid_map[k] ||
1653  pinfo->subplan_map[k] == -1);
1654  }
1655 #endif
1656  }
1657  else
1658  {
1659  int pd_idx = 0;
1660  int pp_idx;
1661 
1662  /*
1663  * Some new partitions have appeared since plan time, and
1664  * those are reflected in our PartitionDesc but were not
1665  * present in the one used to construct subplan_map and
1666  * subpart_map. So we must construct new and longer arrays
1667  * where the partitions that were originally present map to
1668  * the same place, and any added indexes map to -1, as if the
1669  * new partitions had been pruned.
1670  */
1671  pprune->subpart_map = palloc(sizeof(int) * partdesc->nparts);
1672  for (pp_idx = 0; pp_idx < partdesc->nparts; ++pp_idx)
1673  {
1674  if (pinfo->relid_map[pd_idx] != partdesc->oids[pp_idx])
1675  {
1676  pprune->subplan_map[pp_idx] = -1;
1677  pprune->subpart_map[pp_idx] = -1;
1678  }
1679  else
1680  {
1681  pprune->subplan_map[pp_idx] =
1682  pinfo->subplan_map[pd_idx];
1683  pprune->subpart_map[pp_idx] =
1684  pinfo->subpart_map[pd_idx++];
1685  }
1686  }
1687  Assert(pd_idx == pinfo->nparts);
1688  }
1689 
1690  /* present_parts is also subject to later modification */
1691  pprune->present_parts = bms_copy(pinfo->present_parts);
1692 
1693  /*
1694  * Initialize pruning contexts as needed.
1695  */
1697  if (pinfo->initial_pruning_steps)
1698  {
1700  pinfo->initial_pruning_steps,
1701  partdesc, partkey, planstate);
1702  /* Record whether initial pruning is needed at any level */
1703  prunestate->do_initial_prune = true;
1704  }
1705  pprune->exec_pruning_steps = pinfo->exec_pruning_steps;
1706  if (pinfo->exec_pruning_steps)
1707  {
1709  pinfo->exec_pruning_steps,
1710  partdesc, partkey, planstate);
1711  /* Record whether exec pruning is needed at any level */
1712  prunestate->do_exec_prune = true;
1713  }
1714 
1715  /*
1716  * Accumulate the IDs of all PARAM_EXEC Params affecting the
1717  * partitioning decisions at this plan node.
1718  */
1719  prunestate->execparamids = bms_add_members(prunestate->execparamids,
1720  pinfo->execparamids);
1721 
1722  j++;
1723  }
1724  i++;
1725  }
1726 
1727  return prunestate;
1728 }
Bitmapset * execparamids
Definition: plannodes.h:1145
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:945
PartitionKey RelationGetPartitionKey(Relation rel)
Definition: partcache.c:54
MemoryContext es_query_cxt
Definition: execnodes.h:553
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:192
#define lfirst_node(type, lc)
Definition: pg_list.h:193
Bitmapset * present_parts
Definition: plannodes.h:1130
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
Bitmapset * execparamids
PartitionPruneContext exec_context
Definition: execPartition.h:84
Relation ExecGetRangeTableRelation(EState *estate, Index rti)
Definition: execUtils.c:754
Bitmapset * other_subplans
Definition: plannodes.h:1106
#define Assert(condition)
Definition: c.h:738
static int list_length(const List *l)
Definition: pg_list.h:169
PartitionDirectory es_partition_directory
Definition: execnodes.h:535
PartitionedRelPruningData partrelprunedata[FLEXIBLE_ARRAY_MEMBER]
Definition: execPartition.h:97
void * palloc(Size size)
Definition: mcxt.c:949
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:661
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 1812 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().

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

◆ ExecFindMatchingSubPlans()

Bitmapset* ExecFindMatchingSubPlans ( PartitionPruneState prunestate)

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

1980 {
1981  Bitmapset *result = NULL;
1982  MemoryContext oldcontext;
1983  int i;
1984 
1985  /*
1986  * If !do_exec_prune, we've got problems because
1987  * ExecFindInitialMatchingSubPlans will not have bothered to update
1988  * prunestate for whatever pruning it did.
1989  */
1990  Assert(prunestate->do_exec_prune);
1991 
1992  /*
1993  * Switch to a temp context to avoid leaking memory in the executor's
1994  * query-lifespan memory context.
1995  */
1996  oldcontext = MemoryContextSwitchTo(prunestate->prune_context);
1997 
1998  /*
1999  * For each hierarchy, do the pruning tests, and add nondeletable
2000  * subplans' indexes to "result".
2001  */
2002  for (i = 0; i < prunestate->num_partprunedata; i++)
2003  {
2004  PartitionPruningData *prunedata;
2005  PartitionedRelPruningData *pprune;
2006 
2007  prunedata = prunestate->partprunedata[i];
2008  pprune = &prunedata->partrelprunedata[0];
2009 
2010  find_matching_subplans_recurse(prunedata, pprune, false, &result);
2011 
2012  /* Expression eval may have used space in node's ps_ExprContext too */
2013  if (pprune->exec_pruning_steps)
2015  }
2016 
2017  /* Add in any subplans that partition pruning didn't account for */
2018  result = bms_add_members(result, prunestate->other_subplans);
2019 
2020  MemoryContextSwitchTo(oldcontext);
2021 
2022  /* Copy result out of the temp context before we reset it */
2023  result = bms_copy(result);
2024 
2025  MemoryContextReset(prunestate->prune_context);
2026 
2027  return result;
2028 }
MemoryContext prune_context
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:74
ExprContext * ps_ExprContext
Definition: execnodes.h:982
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:738
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: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 270 of file execPartition.c.

References Assert, CHECK_FOR_INTERRUPTS, CheckValidResultRel(), CMD_INSERT, ExprContext::ecxt_scantuple, ereport, errcode(), errdetail(), errmsg(), ERROR, 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 CopyFrom(), and ExecPrepareTupleRouting().

274 {
277  bool isnull[PARTITION_MAX_KEYS];
278  Relation rel;
279  PartitionDispatch dispatch;
280  PartitionDesc partdesc;
281  ExprContext *ecxt = GetPerTupleExprContext(estate);
282  TupleTableSlot *ecxt_scantuple_old = ecxt->ecxt_scantuple;
283  TupleTableSlot *myslot = NULL;
284  MemoryContext oldcxt;
285 
286  /* use per-tuple context here to avoid leaking memory */
288 
289  /*
290  * First check the root table's partition constraint, if any. No point in
291  * routing the tuple if it doesn't belong in the root table itself.
292  */
293  if (rootResultRelInfo->ri_PartitionCheck)
294  ExecPartitionCheck(rootResultRelInfo, slot, estate, true);
295 
296  /* start with the root partitioned table */
297  dispatch = pd[0];
298  while (true)
299  {
300  AttrMap *map = dispatch->tupmap;
301  int partidx = -1;
302 
304 
305  rel = dispatch->reldesc;
306  partdesc = dispatch->partdesc;
307 
308  /*
309  * Convert the tuple to this parent's layout, if different from the
310  * current relation.
311  */
312  myslot = dispatch->tupslot;
313  if (myslot != NULL)
314  {
315  Assert(map != NULL);
316  slot = execute_attr_map_slot(map, slot, myslot);
317  }
318 
319  /*
320  * Extract partition key from tuple. Expression evaluation machinery
321  * that FormPartitionKeyDatum() invokes expects ecxt_scantuple to
322  * point to the correct tuple slot. The slot might have changed from
323  * what was used for the parent table if the table of the current
324  * partitioning level has different tuple descriptor from the parent.
325  * So update ecxt_scantuple accordingly.
326  */
327  ecxt->ecxt_scantuple = slot;
328  FormPartitionKeyDatum(dispatch, slot, estate, values, isnull);
329 
330  /*
331  * If this partitioned table has no partitions or no partition for
332  * these values, error out.
333  */
334  if (partdesc->nparts == 0 ||
335  (partidx = get_partition_for_tuple(dispatch, values, isnull)) < 0)
336  {
337  char *val_desc;
338 
340  values, isnull, 64);
342  ereport(ERROR,
343  (errcode(ERRCODE_CHECK_VIOLATION),
344  errmsg("no partition of relation \"%s\" found for row",
346  val_desc ?
347  errdetail("Partition key of the failing row contains %s.",
348  val_desc) : 0));
349  }
350 
351  if (partdesc->is_leaf[partidx])
352  {
353  ResultRelInfo *rri;
354 
355  /*
356  * Look to see if we've already got a ResultRelInfo for this
357  * partition.
358  */
359  if (likely(dispatch->indexes[partidx] >= 0))
360  {
361  /* ResultRelInfo already built */
362  Assert(dispatch->indexes[partidx] < proute->num_partitions);
363  rri = proute->partitions[dispatch->indexes[partidx]];
364  }
365  else
366  {
367  bool found = false;
368 
369  /*
370  * We have not yet set up a ResultRelInfo for this partition,
371  * but if we have a subplan hash table, we might have one
372  * there. If not, we'll have to create one.
373  */
374  if (proute->subplan_resultrel_htab)
375  {
376  Oid partoid = partdesc->oids[partidx];
378 
379  elem = hash_search(proute->subplan_resultrel_htab,
380  &partoid, HASH_FIND, NULL);
381  if (elem)
382  {
383  found = true;
384  rri = elem->rri;
385 
386  /* Verify this ResultRelInfo allows INSERTs */
388 
389  /* Set up the PartitionRoutingInfo for it */
390  ExecInitRoutingInfo(mtstate, estate, proute, dispatch,
391  rri, partidx);
392  }
393  }
394 
395  /* We need to create a new one. */
396  if (!found)
397  rri = ExecInitPartitionInfo(mtstate, estate, proute,
398  dispatch,
399  rootResultRelInfo, partidx);
400  }
401 
402  /* Release the tuple in the lowest parent's dedicated slot. */
403  if (slot == myslot)
404  ExecClearTuple(myslot);
405 
406  MemoryContextSwitchTo(oldcxt);
407  ecxt->ecxt_scantuple = ecxt_scantuple_old;
408  return rri;
409  }
410  else
411  {
412  /*
413  * Partition is a sub-partitioned table; get the PartitionDispatch
414  */
415  if (likely(dispatch->indexes[partidx] >= 0))
416  {
417  /* Already built. */
418  Assert(dispatch->indexes[partidx] < proute->num_dispatch);
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  dispatch = subdispatch;
442  }
443  }
444  }
445 }
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:608
#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:906
EState * state
Definition: execnodes.h:945
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:644
ResultRelInfo ** partitions
Definition: execPartition.c:93
Definition: attmap.h:34
#define GetPerTupleExprContext(estate)
Definition: executor.h:506
#define ERROR
Definition: elog.h:43
PlanState ps
Definition: execnodes.h:1163
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:955
#define RelationGetRelationName(relation)
Definition: rel.h:462
PartitionDispatch * partition_dispatch_info
Definition: execPartition.c:90
#define ereport(elevel, rest)
Definition: elog.h:141
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:479
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:738
TupleTableSlot * ecxt_scantuple
Definition: execnodes.h:224
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:511
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:822
bool ExecPartitionCheck(ResultRelInfo *resultRelInfo, TupleTableSlot *slot, EState *estate, bool emitError)
Definition: execMain.c:1783
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:99
static void ExecInitRoutingInfo(ModifyTableState *mtstate, EState *estate, PartitionTupleRouting *proute, PartitionDispatch dispatch, ResultRelInfo *partRelInfo, int partidx)
#define RelationGetRelid(relation)
Definition: rel.h:428
int indexes[FLEXIBLE_ARRAY_MEMBER]

◆ ExecSetupPartitionTupleRouting()

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

Definition at line 210 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 CopyFrom(), and ExecInitModifyTable().

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