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

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

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

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

◆ ExecFindMatchingSubPlans()

Bitmapset* ExecFindMatchingSubPlans ( PartitionPruneState prunestate)

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

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

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  AttrNumber *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  }
351 
352  if (partdesc->is_leaf[partidx])
353  {
354  ResultRelInfo *rri;
355 
356  /*
357  * Look to see if we've already got a ResultRelInfo for this
358  * partition.
359  */
360  if (likely(dispatch->indexes[partidx] >= 0))
361  {
362  /* ResultRelInfo already built */
363  Assert(dispatch->indexes[partidx] < proute->num_partitions);
364  rri = proute->partitions[dispatch->indexes[partidx]];
365  }
366  else
367  {
368  bool found = false;
369 
370  /*
371  * We have not yet set up a ResultRelInfo for this partition,
372  * but if we have a subplan hash table, we might have one
373  * there. If not, we'll have to create one.
374  */
375  if (proute->subplan_resultrel_htab)
376  {
377  Oid partoid = partdesc->oids[partidx];
379 
380  elem = hash_search(proute->subplan_resultrel_htab,
381  &partoid, HASH_FIND, NULL);
382  if (elem)
383  {
384  found = true;
385  rri = elem->rri;
386 
387  /* Verify this ResultRelInfo allows INSERTs */
389 
390  /* Set up the PartitionRoutingInfo for it */
391  ExecInitRoutingInfo(mtstate, estate, proute, dispatch,
392  rri, partidx);
393  }
394  }
395 
396  /* We need to create a new one. */
397  if (!found)
398  rri = ExecInitPartitionInfo(mtstate, estate, proute,
399  dispatch,
400  rootResultRelInfo, partidx);
401  }
402 
403  /* Release the tuple in the lowest parent's dedicated slot. */
404  if (slot == myslot)
405  ExecClearTuple(myslot);
406 
407  MemoryContextSwitchTo(oldcxt);
408  ecxt->ecxt_scantuple = ecxt_scantuple_old;
409  return rri;
410  }
411  else
412  {
413  /*
414  * Partition is a sub-partitioned table; get the PartitionDispatch
415  */
416  if (likely(dispatch->indexes[partidx] >= 0))
417  {
418  /* Already built. */
419  Assert(dispatch->indexes[partidx] < proute->num_dispatch);
420 
421  /*
422  * Move down to the next partition level and search again
423  * until we find a leaf partition that matches this tuple
424  */
425  dispatch = pd[dispatch->indexes[partidx]];
426  }
427  else
428  {
429  /* Not yet built. Do that now. */
430  PartitionDispatch subdispatch;
431 
432  /*
433  * Create the new PartitionDispatch. We pass the current one
434  * in as the parent PartitionDispatch
435  */
436  subdispatch = ExecInitPartitionDispatchInfo(mtstate->ps.state,
437  proute,
438  partdesc->oids[partidx],
439  dispatch, partidx);
440  Assert(dispatch->indexes[partidx] >= 0 &&
441  dispatch->indexes[partidx] < proute->num_dispatch);
442  dispatch = subdispatch;
443  }
444  }
445  }
446 }
static int get_partition_for_tuple(PartitionDispatch pd, Datum *values, bool *isnull)
PartitionDesc partdesc
#define likely(x)
Definition: c.h:207
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:426
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
int errcode(int sqlerrcode)
Definition: elog.c:570
#define PARTITION_MAX_KEYS
TupleTableSlot * execute_attr_map_slot(AttrNumber *attrMap, TupleTableSlot *in_slot, TupleTableSlot *out_slot)
Definition: tupconvert.c:425
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:942
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:638
ResultRelInfo ** partitions
Definition: execPartition.c:94
#define GetPerTupleExprContext(estate)
Definition: executor.h:501
#define ERROR
Definition: elog.h:43
PlanState ps
Definition: execnodes.h:1160
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:860
#define RelationGetRelationName(relation)
Definition: rel.h:453
PartitionDispatch * partition_dispatch_info
Definition: execPartition.c:91
#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:476
static ResultRelInfo * ExecInitPartitionInfo(ModifyTableState *mtstate, EState *estate, PartitionTupleRouting *proute, PartitionDispatch dispatch, ResultRelInfo *rootResultRelInfo, int partidx)
#define Assert(condition)
Definition: c.h:732
TupleTableSlot * ecxt_scantuple
Definition: execnodes.h:224
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:506
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:784
bool ExecPartitionCheck(ResultRelInfo *resultRelInfo, TupleTableSlot *slot, EState *estate, bool emitError)
Definition: execMain.c:1792
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:99
int16 AttrNumber
Definition: attnum.h:21
static void ExecInitRoutingInfo(ModifyTableState *mtstate, EState *estate, PartitionTupleRouting *proute, PartitionDispatch dispatch, ResultRelInfo *partRelInfo, int partidx)
#define RelationGetRelid(relation)
Definition: rel.h:419
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 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:1160
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:940
CmdType operation
Definition: plannodes.h:219
MemoryContext memcxt
Definition: execPartition.c:98
#define RelationGetRelid(relation)
Definition: rel.h:419