PostgreSQL Source Code  git master
execPartition.c File Reference
#include "postgres.h"
#include "access/table.h"
#include "access/tableam.h"
#include "catalog/partition.h"
#include "catalog/pg_inherits.h"
#include "catalog/pg_type.h"
#include "executor/execPartition.h"
#include "executor/executor.h"
#include "executor/nodeModifyTable.h"
#include "foreign/fdwapi.h"
#include "mb/pg_wchar.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "partitioning/partbounds.h"
#include "partitioning/partdesc.h"
#include "partitioning/partprune.h"
#include "rewrite/rewriteManip.h"
#include "utils/acl.h"
#include "utils/lsyscache.h"
#include "utils/partcache.h"
#include "utils/rls.h"
#include "utils/ruleutils.h"
Include dependency graph for execPartition.c:

Go to the source code of this file.

Data Structures

struct  PartitionTupleRouting
 
struct  PartitionDispatchData
 

Typedefs

typedef struct PartitionDispatchData PartitionDispatchData
 

Functions

static ResultRelInfoExecInitPartitionInfo (ModifyTableState *mtstate, EState *estate, PartitionTupleRouting *proute, PartitionDispatch dispatch, ResultRelInfo *rootResultRelInfo, int partidx)
 
static void ExecInitRoutingInfo (ModifyTableState *mtstate, EState *estate, PartitionTupleRouting *proute, PartitionDispatch dispatch, ResultRelInfo *partRelInfo, int partidx, bool is_borrowed_rel)
 
static PartitionDispatch ExecInitPartitionDispatchInfo (EState *estate, PartitionTupleRouting *proute, Oid partoid, PartitionDispatch parent_pd, int partidx, ResultRelInfo *rootResultRelInfo)
 
static void FormPartitionKeyDatum (PartitionDispatch pd, TupleTableSlot *slot, EState *estate, Datum *values, bool *isnull)
 
static int get_partition_for_tuple (PartitionDispatch pd, Datum *values, bool *isnull)
 
static char * ExecBuildSlotPartitionKeyDescription (Relation rel, Datum *values, bool *isnull, int maxfieldlen)
 
static Listadjust_partition_colnos (List *colnos, ResultRelInfo *leaf_part_rri)
 
static Listadjust_partition_colnos_using_map (List *colnos, AttrMap *attrMap)
 
static PartitionPruneStateCreatePartitionPruneState (PlanState *planstate, PartitionPruneInfo *pruneinfo)
 
static void InitPartitionPruneContext (PartitionPruneContext *context, List *pruning_steps, PartitionDesc partdesc, PartitionKey partkey, PlanState *planstate, ExprContext *econtext)
 
static void PartitionPruneFixSubPlanMap (PartitionPruneState *prunestate, Bitmapset *initially_valid_subplans, int n_total_subplans)
 
static void find_matching_subplans_recurse (PartitionPruningData *prunedata, PartitionedRelPruningData *pprune, bool initial_prune, Bitmapset **validsubplans)
 
PartitionTupleRoutingExecSetupPartitionTupleRouting (EState *estate, Relation rel)
 
ResultRelInfoExecFindPartition (ModifyTableState *mtstate, ResultRelInfo *rootResultRelInfo, PartitionTupleRouting *proute, TupleTableSlot *slot, EState *estate)
 
void ExecCleanupTupleRouting (ModifyTableState *mtstate, PartitionTupleRouting *proute)
 
PartitionPruneStateExecInitPartitionPruning (PlanState *planstate, int n_total_subplans, PartitionPruneInfo *pruneinfo, Bitmapset **initially_valid_subplans)
 
BitmapsetExecFindMatchingSubPlans (PartitionPruneState *prunestate, bool initial_prune)
 

Typedef Documentation

◆ PartitionDispatchData

Function Documentation

◆ adjust_partition_colnos()

static List * adjust_partition_colnos ( List colnos,
ResultRelInfo leaf_part_rri 
)
static

Definition at line 1537 of file execPartition.c.

1538 {
1539  TupleConversionMap *map = ExecGetChildToRootMap(leaf_part_rri);
1540 
1541  Assert(map != NULL);
1542 
1543  return adjust_partition_colnos_using_map(colnos, map->attrMap);
1544 }
static List * adjust_partition_colnos_using_map(List *colnos, AttrMap *attrMap)
TupleConversionMap * ExecGetChildToRootMap(ResultRelInfo *resultRelInfo)
Definition: execUtils.c:1234
Assert(fmt[strlen(fmt) - 1] !='\n')
AttrMap * attrMap
Definition: tupconvert.h:28

References adjust_partition_colnos_using_map(), Assert(), TupleConversionMap::attrMap, and ExecGetChildToRootMap().

Referenced by ExecInitPartitionInfo().

◆ adjust_partition_colnos_using_map()

static List * adjust_partition_colnos_using_map ( List colnos,
AttrMap attrMap 
)
static

Definition at line 1554 of file execPartition.c.

1555 {
1556  List *new_colnos = NIL;
1557  ListCell *lc;
1558 
1559  Assert(attrMap != NULL); /* else we shouldn't be here */
1560 
1561  foreach(lc, colnos)
1562  {
1563  AttrNumber parentattrno = lfirst_int(lc);
1564 
1565  if (parentattrno <= 0 ||
1566  parentattrno > attrMap->maplen ||
1567  attrMap->attnums[parentattrno - 1] == 0)
1568  elog(ERROR, "unexpected attno %d in target column list",
1569  parentattrno);
1570  new_colnos = lappend_int(new_colnos,
1571  attrMap->attnums[parentattrno - 1]);
1572  }
1573 
1574  return new_colnos;
1575 }
int16 AttrNumber
Definition: attnum.h:21
#define ERROR
Definition: elog.h:33
#define elog(elevel,...)
Definition: elog.h:218
List * lappend_int(List *list, int datum)
Definition: list.c:354
#define NIL
Definition: pg_list.h:65
#define lfirst_int(lc)
Definition: pg_list.h:170
int maplen
Definition: attmap.h:37
AttrNumber * attnums
Definition: attmap.h:36
Definition: pg_list.h:51

References Assert(), AttrMap::attnums, elog, ERROR, lappend_int(), lfirst_int, AttrMap::maplen, and NIL.

Referenced by adjust_partition_colnos(), and ExecInitPartitionInfo().

◆ CreatePartitionPruneState()

static PartitionPruneState * CreatePartitionPruneState ( PlanState planstate,
PartitionPruneInfo pruneinfo 
)
static

Definition at line 1705 of file execPartition.c.

1706 {
1707  EState *estate = planstate->state;
1708  PartitionPruneState *prunestate;
1709  int n_part_hierarchies;
1710  ListCell *lc;
1711  int i;
1712  ExprContext *econtext = planstate->ps_ExprContext;
1713 
1714  /* For data reading, executor always omits detached partitions */
1715  if (estate->es_partition_directory == NULL)
1716  estate->es_partition_directory =
1717  CreatePartitionDirectory(estate->es_query_cxt, false);
1718 
1719  n_part_hierarchies = list_length(pruneinfo->prune_infos);
1720  Assert(n_part_hierarchies > 0);
1721 
1722  /*
1723  * Allocate the data structure
1724  */
1725  prunestate = (PartitionPruneState *)
1726  palloc(offsetof(PartitionPruneState, partprunedata) +
1727  sizeof(PartitionPruningData *) * n_part_hierarchies);
1728 
1729  prunestate->execparamids = NULL;
1730  /* other_subplans can change at runtime, so we need our own copy */
1731  prunestate->other_subplans = bms_copy(pruneinfo->other_subplans);
1732  prunestate->do_initial_prune = false; /* may be set below */
1733  prunestate->do_exec_prune = false; /* may be set below */
1734  prunestate->num_partprunedata = n_part_hierarchies;
1735 
1736  /*
1737  * Create a short-term memory context which we'll use when making calls to
1738  * the partition pruning functions. This avoids possible memory leaks,
1739  * since the pruning functions call comparison functions that aren't under
1740  * our control.
1741  */
1742  prunestate->prune_context =
1744  "Partition Prune",
1746 
1747  i = 0;
1748  foreach(lc, pruneinfo->prune_infos)
1749  {
1750  List *partrelpruneinfos = lfirst_node(List, lc);
1751  int npartrelpruneinfos = list_length(partrelpruneinfos);
1752  PartitionPruningData *prunedata;
1753  ListCell *lc2;
1754  int j;
1755 
1756  prunedata = (PartitionPruningData *)
1757  palloc(offsetof(PartitionPruningData, partrelprunedata) +
1758  npartrelpruneinfos * sizeof(PartitionedRelPruningData));
1759  prunestate->partprunedata[i] = prunedata;
1760  prunedata->num_partrelprunedata = npartrelpruneinfos;
1761 
1762  j = 0;
1763  foreach(lc2, partrelpruneinfos)
1764  {
1766  PartitionedRelPruningData *pprune = &prunedata->partrelprunedata[j];
1767  Relation partrel;
1768  PartitionDesc partdesc;
1769  PartitionKey partkey;
1770 
1771  /*
1772  * We can rely on the copies of the partitioned table's partition
1773  * key and partition descriptor appearing in its relcache entry,
1774  * because that entry will be held open and locked for the
1775  * duration of this executor run.
1776  */
1777  partrel = ExecGetRangeTableRelation(estate, pinfo->rtindex);
1778  partkey = RelationGetPartitionKey(partrel);
1780  partrel);
1781 
1782  /*
1783  * Initialize the subplan_map and subpart_map.
1784  *
1785  * Because we request detached partitions to be included, and
1786  * detaching waits for old transactions, it is safe to assume that
1787  * no partitions have disappeared since this query was planned.
1788  *
1789  * However, new partitions may have been added.
1790  */
1791  Assert(partdesc->nparts >= pinfo->nparts);
1792  pprune->nparts = partdesc->nparts;
1793  pprune->subplan_map = palloc(sizeof(int) * partdesc->nparts);
1794  if (partdesc->nparts == pinfo->nparts)
1795  {
1796  /*
1797  * There are no new partitions, so this is simple. We can
1798  * simply point to the subpart_map from the plan, but we must
1799  * copy the subplan_map since we may change it later.
1800  */
1801  pprune->subpart_map = pinfo->subpart_map;
1802  memcpy(pprune->subplan_map, pinfo->subplan_map,
1803  sizeof(int) * pinfo->nparts);
1804 
1805  /*
1806  * Double-check that the list of unpruned relations has not
1807  * changed. (Pruned partitions are not in relid_map[].)
1808  */
1809 #ifdef USE_ASSERT_CHECKING
1810  for (int k = 0; k < pinfo->nparts; k++)
1811  {
1812  Assert(partdesc->oids[k] == pinfo->relid_map[k] ||
1813  pinfo->subplan_map[k] == -1);
1814  }
1815 #endif
1816  }
1817  else
1818  {
1819  int pd_idx = 0;
1820  int pp_idx;
1821 
1822  /*
1823  * Some new partitions have appeared since plan time, and
1824  * those are reflected in our PartitionDesc but were not
1825  * present in the one used to construct subplan_map and
1826  * subpart_map. So we must construct new and longer arrays
1827  * where the partitions that were originally present map to
1828  * the same sub-structures, and any added partitions map to
1829  * -1, as if the new partitions had been pruned.
1830  *
1831  * Note: pinfo->relid_map[] may contain InvalidOid entries for
1832  * partitions pruned by the planner. We cannot tell exactly
1833  * which of the partdesc entries these correspond to, but we
1834  * don't have to; just skip over them. The non-pruned
1835  * relid_map entries, however, had better be a subset of the
1836  * partdesc entries and in the same order.
1837  */
1838  pprune->subpart_map = palloc(sizeof(int) * partdesc->nparts);
1839  for (pp_idx = 0; pp_idx < partdesc->nparts; pp_idx++)
1840  {
1841  /* Skip any InvalidOid relid_map entries */
1842  while (pd_idx < pinfo->nparts &&
1843  !OidIsValid(pinfo->relid_map[pd_idx]))
1844  pd_idx++;
1845 
1846  if (pd_idx < pinfo->nparts &&
1847  pinfo->relid_map[pd_idx] == partdesc->oids[pp_idx])
1848  {
1849  /* match... */
1850  pprune->subplan_map[pp_idx] =
1851  pinfo->subplan_map[pd_idx];
1852  pprune->subpart_map[pp_idx] =
1853  pinfo->subpart_map[pd_idx];
1854  pd_idx++;
1855  }
1856  else
1857  {
1858  /* this partdesc entry is not in the plan */
1859  pprune->subplan_map[pp_idx] = -1;
1860  pprune->subpart_map[pp_idx] = -1;
1861  }
1862  }
1863 
1864  /*
1865  * It might seem that we need to skip any trailing InvalidOid
1866  * entries in pinfo->relid_map before checking that we scanned
1867  * all of the relid_map. But we will have skipped them above,
1868  * because they must correspond to some partdesc->oids
1869  * entries; we just couldn't tell which.
1870  */
1871  if (pd_idx != pinfo->nparts)
1872  elog(ERROR, "could not match partition child tables to plan elements");
1873  }
1874 
1875  /* present_parts is also subject to later modification */
1876  pprune->present_parts = bms_copy(pinfo->present_parts);
1877 
1878  /*
1879  * Initialize pruning contexts as needed.
1880  */
1882  if (pinfo->initial_pruning_steps)
1883  {
1885  pinfo->initial_pruning_steps,
1886  partdesc, partkey, planstate,
1887  econtext);
1888  /* Record whether initial pruning is needed at any level */
1889  prunestate->do_initial_prune = true;
1890  }
1891  pprune->exec_pruning_steps = pinfo->exec_pruning_steps;
1892  if (pinfo->exec_pruning_steps)
1893  {
1895  pinfo->exec_pruning_steps,
1896  partdesc, partkey, planstate,
1897  econtext);
1898  /* Record whether exec pruning is needed at any level */
1899  prunestate->do_exec_prune = true;
1900  }
1901 
1902  /*
1903  * Accumulate the IDs of all PARAM_EXEC Params affecting the
1904  * partitioning decisions at this plan node.
1905  */
1906  prunestate->execparamids = bms_add_members(prunestate->execparamids,
1907  pinfo->execparamids);
1908 
1909  j++;
1910  }
1911  i++;
1912  }
1913 
1914  return prunestate;
1915 }
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:795
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:74
#define offsetof(type, field)
Definition: c.h:727
#define OidIsValid(objectId)
Definition: c.h:710
static void InitPartitionPruneContext(PartitionPruneContext *context, List *pruning_steps, PartitionDesc partdesc, PartitionKey partkey, PlanState *planstate, ExprContext *econtext)
struct PartitionedRelPruningData PartitionedRelPruningData
Relation ExecGetRangeTableRelation(EState *estate, Index rti)
Definition: execUtils.c:782
int j
Definition: isn.c:74
int i
Definition: isn.c:73
MemoryContext CurrentMemoryContext
Definition: mcxt.c:42
void * palloc(Size size)
Definition: mcxt.c:1068
#define AllocSetContextCreate
Definition: memutils.h:173
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:197
PartitionKey RelationGetPartitionKey(Relation rel)
Definition: partcache.c:54
PartitionDirectory CreatePartitionDirectory(MemoryContext mcxt, bool omit_detached)
Definition: partdesc.c:377
PartitionDesc PartitionDirectoryLookup(PartitionDirectory pdir, Relation rel)
Definition: partdesc.c:410
#define lfirst_node(type, lc)
Definition: pg_list.h:172
static int list_length(const List *l)
Definition: pg_list.h:149
MemoryContext es_query_cxt
Definition: execnodes.h:632
PartitionDirectory es_partition_directory
Definition: execnodes.h:614
Bitmapset * other_subplans
Definition: plannodes.h:1203
PartitionPruningData * partprunedata[FLEXIBLE_ARRAY_MEMBER]
Bitmapset * execparamids
Bitmapset * other_subplans
MemoryContext prune_context
PartitionedRelPruningData partrelprunedata[FLEXIBLE_ARRAY_MEMBER]
Definition: execPartition.h:81
Bitmapset * present_parts
Definition: plannodes.h:1227
Bitmapset * execparamids
Definition: plannodes.h:1242
PartitionPruneContext exec_context
Definition: execPartition.h:68
PartitionPruneContext initial_context
Definition: execPartition.h:67
EState * state
Definition: execnodes.h:1000
ExprContext * ps_ExprContext
Definition: execnodes.h:1037

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(), PartitionPruneState::execparamids, PartitionedRelPruneInfo::execparamids, i, PartitionedRelPruningData::initial_context, PartitionedRelPruningData::initial_pruning_steps, PartitionedRelPruneInfo::initial_pruning_steps, InitPartitionPruneContext(), j, lfirst_node, list_length(), PartitionedRelPruningData::nparts, PartitionedRelPruneInfo::nparts, PartitionDescData::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, PlanState::ps_ExprContext, RelationGetPartitionKey(), PartitionedRelPruneInfo::relid_map, PartitionedRelPruneInfo::rtindex, PlanState::state, PartitionedRelPruningData::subpart_map, PartitionedRelPruneInfo::subpart_map, PartitionedRelPruningData::subplan_map, and PartitionedRelPruneInfo::subplan_map.

Referenced by ExecInitPartitionPruning().

◆ ExecBuildSlotPartitionKeyDescription()

static char * ExecBuildSlotPartitionKeyDescription ( Relation  rel,
Datum values,
bool isnull,
int  maxfieldlen 
)
static

Definition at line 1449 of file execPartition.c.

1453 {
1456  int partnatts = get_partition_natts(key);
1457  int i;
1458  Oid relid = RelationGetRelid(rel);
1459  AclResult aclresult;
1460 
1461  if (check_enable_rls(relid, InvalidOid, true) == RLS_ENABLED)
1462  return NULL;
1463 
1464  /* If the user has table-level access, just go build the description. */
1465  aclresult = pg_class_aclcheck(relid, GetUserId(), ACL_SELECT);
1466  if (aclresult != ACLCHECK_OK)
1467  {
1468  /*
1469  * Step through the columns of the partition key and make sure the
1470  * user has SELECT rights on all of them.
1471  */
1472  for (i = 0; i < partnatts; i++)
1473  {
1475 
1476  /*
1477  * If this partition key column is an expression, we return no
1478  * detail rather than try to figure out what column(s) the
1479  * expression includes and if the user has SELECT rights on them.
1480  */
1481  if (attnum == InvalidAttrNumber ||
1483  ACL_SELECT) != ACLCHECK_OK)
1484  return NULL;
1485  }
1486  }
1487 
1488  initStringInfo(&buf);
1489  appendStringInfo(&buf, "(%s) = (",
1490  pg_get_partkeydef_columns(relid, true));
1491 
1492  for (i = 0; i < partnatts; i++)
1493  {
1494  char *val;
1495  int vallen;
1496 
1497  if (isnull[i])
1498  val = "null";
1499  else
1500  {
1501  Oid foutoid;
1502  bool typisvarlena;
1503 
1505  &foutoid, &typisvarlena);
1506  val = OidOutputFunctionCall(foutoid, values[i]);
1507  }
1508 
1509  if (i > 0)
1510  appendStringInfoString(&buf, ", ");
1511 
1512  /* truncate if needed */
1513  vallen = strlen(val);
1514  if (vallen <= maxfieldlen)
1515  appendBinaryStringInfo(&buf, val, vallen);
1516  else
1517  {
1518  vallen = pg_mbcliplen(val, vallen, maxfieldlen);
1519  appendBinaryStringInfo(&buf, val, vallen);
1520  appendStringInfoString(&buf, "...");
1521  }
1522  }
1523 
1524  appendStringInfoChar(&buf, ')');
1525 
1526  return buf.data;
1527 }
AclResult
Definition: acl.h:181
@ ACLCHECK_OK
Definition: acl.h:182
AclResult pg_attribute_aclcheck(Oid table_oid, AttrNumber attnum, Oid roleid, AclMode mode)
Definition: aclchk.c:4878
AclResult pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:5007
#define InvalidAttrNumber
Definition: attnum.h:23
static Datum values[MAXATTR]
Definition: bootstrap.c:156
char * OidOutputFunctionCall(Oid functionId, Datum val)
Definition: fmgr.c:1639
long val
Definition: informix.c:664
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
Definition: lsyscache.c:2864
int pg_mbcliplen(const char *mbstr, int len, int limit)
Definition: mbutils.c:1026
Oid GetUserId(void)
Definition: miscinit.c:492
#define ACL_SELECT
Definition: parsenodes.h:83
static int16 get_partition_col_attnum(PartitionKey key, int col)
Definition: partcache.h:79
static int get_partition_natts(PartitionKey key)
Definition: partcache.h:64
static Oid get_partition_col_typid(PartitionKey key, int col)
Definition: partcache.h:85
int16 attnum
Definition: pg_attribute.h:83
static char * buf
Definition: pg_test_fsync.c:67
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31
#define RelationGetRelid(relation)
Definition: rel.h:489
int check_enable_rls(Oid relid, Oid checkAsUser, bool noError)
Definition: rls.c:52
@ RLS_ENABLED
Definition: rls.h:45
char * pg_get_partkeydef_columns(Oid relid, bool pretty)
Definition: ruleutils.c:1884
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:91
void appendBinaryStringInfo(StringInfo str, const char *data, int datalen)
Definition: stringinfo.c:227
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:176
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:188
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59

References ACL_SELECT, ACLCHECK_OK, appendBinaryStringInfo(), appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), attnum, buf, check_enable_rls(), get_partition_col_attnum(), get_partition_col_typid(), get_partition_natts(), getTypeOutputInfo(), GetUserId(), i, initStringInfo(), InvalidAttrNumber, InvalidOid, sort-test::key, OidOutputFunctionCall(), pg_attribute_aclcheck(), pg_class_aclcheck(), pg_get_partkeydef_columns(), pg_mbcliplen(), RelationGetPartitionKey(), RelationGetRelid, RLS_ENABLED, val, and values.

Referenced by ExecFindPartition().

◆ ExecCleanupTupleRouting()

void ExecCleanupTupleRouting ( ModifyTableState mtstate,
PartitionTupleRouting proute 
)

Definition at line 1225 of file execPartition.c.

1227 {
1228  int i;
1229 
1230  /*
1231  * Remember, proute->partition_dispatch_info[0] corresponds to the root
1232  * partitioned table, which we must not try to close, because it is the
1233  * main target table of the query that will be closed by callers such as
1234  * ExecEndPlan() or DoCopy(). Also, tupslot is NULL for the root
1235  * partitioned table.
1236  */
1237  for (i = 1; i < proute->num_dispatch; i++)
1238  {
1240 
1241  table_close(pd->reldesc, NoLock);
1242 
1243  if (pd->tupslot)
1245  }
1246 
1247  for (i = 0; i < proute->num_partitions; i++)
1248  {
1249  ResultRelInfo *resultRelInfo = proute->partitions[i];
1250 
1251  /* Allow any FDWs to shut down */
1252  if (resultRelInfo->ri_FdwRoutine != NULL &&
1253  resultRelInfo->ri_FdwRoutine->EndForeignInsert != NULL)
1254  resultRelInfo->ri_FdwRoutine->EndForeignInsert(mtstate->ps.state,
1255  resultRelInfo);
1256 
1257  /*
1258  * Close it if it's not one of the result relations borrowed from the
1259  * owning ModifyTableState; those will be closed by ExecEndPlan().
1260  */
1261  if (proute->is_borrowed_rel[i])
1262  continue;
1263 
1264  ExecCloseIndices(resultRelInfo);
1265  table_close(resultRelInfo->ri_RelationDesc, NoLock);
1266  }
1267 }
void ExecCloseIndices(ResultRelInfo *resultRelInfo)
Definition: execIndexing.c:231
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:1254
#define NoLock
Definition: lockdefs.h:34
EndForeignInsert_function EndForeignInsert
Definition: fdwapi.h:239
PlanState ps
Definition: execnodes.h:1225
TupleTableSlot * tupslot
PartitionDispatch * partition_dispatch_info
Definition: execPartition.c:97
ResultRelInfo ** partitions
Relation ri_RelationDesc
Definition: execnodes.h:433
struct FdwRoutine * ri_FdwRoutine
Definition: execnodes.h:477
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167

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

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

◆ ExecFindMatchingSubPlans()

Bitmapset* ExecFindMatchingSubPlans ( PartitionPruneState prunestate,
bool  initial_prune 
)

Definition at line 2122 of file execPartition.c.

2124 {
2125  Bitmapset *result = NULL;
2126  MemoryContext oldcontext;
2127  int i;
2128 
2129  /*
2130  * Either we're here on the initial prune done during pruning
2131  * initialization, or we're at a point where PARAM_EXEC Params can be
2132  * evaluated *and* there are steps in which to do so.
2133  */
2134  Assert(initial_prune || prunestate->do_exec_prune);
2135 
2136  /*
2137  * Switch to a temp context to avoid leaking memory in the executor's
2138  * query-lifespan memory context.
2139  */
2140  oldcontext = MemoryContextSwitchTo(prunestate->prune_context);
2141 
2142  /*
2143  * For each hierarchy, do the pruning tests, and add nondeletable
2144  * subplans' indexes to "result".
2145  */
2146  for (i = 0; i < prunestate->num_partprunedata; i++)
2147  {
2148  PartitionPruningData *prunedata = prunestate->partprunedata[i];
2149  PartitionedRelPruningData *pprune;
2150 
2151  /*
2152  * We pass the zeroth item, belonging to the root table of the
2153  * hierarchy, and find_matching_subplans_recurse() takes care of
2154  * recursing to other (lower-level) parents as needed.
2155  */
2156  pprune = &prunedata->partrelprunedata[0];
2157  find_matching_subplans_recurse(prunedata, pprune, initial_prune,
2158  &result);
2159 
2160  /* Expression eval may have used space in ExprContext too */
2161  if (pprune->exec_pruning_steps)
2163  }
2164 
2165  /* Add in any subplans that partition pruning didn't account for */
2166  result = bms_add_members(result, prunestate->other_subplans);
2167 
2168  MemoryContextSwitchTo(oldcontext);
2169 
2170  /* Copy result out of the temp context before we reset it */
2171  result = bms_copy(result);
2172 
2173  MemoryContextReset(prunestate->prune_context);
2174 
2175  return result;
2176 }
static void find_matching_subplans_recurse(PartitionPruningData *prunedata, PartitionedRelPruningData *pprune, bool initial_prune, Bitmapset **validsubplans)
#define ResetExprContext(econtext)
Definition: executor.h:531
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:143
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
ExprContext * exprcontext
Definition: partprune.h:60

References Assert(), bms_add_members(), bms_copy(), PartitionPruneState::do_exec_prune, PartitionedRelPruningData::exec_context, PartitionedRelPruningData::exec_pruning_steps, PartitionPruneContext::exprcontext, find_matching_subplans_recurse(), i, MemoryContextReset(), MemoryContextSwitchTo(), PartitionPruneState::num_partprunedata, PartitionPruneState::other_subplans, PartitionPruneState::partprunedata, PartitionPruningData::partrelprunedata, PartitionPruneState::prune_context, and ResetExprContext.

Referenced by choose_next_subplan_for_leader(), choose_next_subplan_for_worker(), choose_next_subplan_locally(), ExecAppendAsyncBegin(), ExecInitPartitionPruning(), and ExecMergeAppend().

◆ ExecFindPartition()

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

Definition at line 265 of file execPartition.c.

269 {
272  bool isnull[PARTITION_MAX_KEYS];
273  Relation rel;
274  PartitionDispatch dispatch;
275  PartitionDesc partdesc;
276  ExprContext *ecxt = GetPerTupleExprContext(estate);
277  TupleTableSlot *ecxt_scantuple_saved = ecxt->ecxt_scantuple;
278  TupleTableSlot *rootslot = slot;
279  TupleTableSlot *myslot = NULL;
280  MemoryContext oldcxt;
281  ResultRelInfo *rri = NULL;
282 
283  /* use per-tuple context here to avoid leaking memory */
285 
286  /*
287  * First check the root table's partition constraint, if any. No point in
288  * routing the tuple if it doesn't belong in the root table itself.
289  */
290  if (rootResultRelInfo->ri_RelationDesc->rd_rel->relispartition)
291  ExecPartitionCheck(rootResultRelInfo, slot, estate, true);
292 
293  /* start with the root partitioned table */
294  dispatch = pd[0];
295  while (dispatch != NULL)
296  {
297  int partidx = -1;
298  bool is_leaf;
299 
301 
302  rel = dispatch->reldesc;
303  partdesc = dispatch->partdesc;
304 
305  /*
306  * Extract partition key from tuple. Expression evaluation machinery
307  * that FormPartitionKeyDatum() invokes expects ecxt_scantuple to
308  * point to the correct tuple slot. The slot might have changed from
309  * what was used for the parent table if the table of the current
310  * partitioning level has different tuple descriptor from the parent.
311  * So update ecxt_scantuple accordingly.
312  */
313  ecxt->ecxt_scantuple = slot;
314  FormPartitionKeyDatum(dispatch, slot, estate, values, isnull);
315 
316  /*
317  * If this partitioned table has no partitions or no partition for
318  * these values, error out.
319  */
320  if (partdesc->nparts == 0 ||
321  (partidx = get_partition_for_tuple(dispatch, values, isnull)) < 0)
322  {
323  char *val_desc;
324 
326  values, isnull, 64);
328  ereport(ERROR,
329  (errcode(ERRCODE_CHECK_VIOLATION),
330  errmsg("no partition of relation \"%s\" found for row",
332  val_desc ?
333  errdetail("Partition key of the failing row contains %s.",
334  val_desc) : 0,
335  errtable(rel)));
336  }
337 
338  is_leaf = partdesc->is_leaf[partidx];
339  if (is_leaf)
340  {
341  /*
342  * We've reached the leaf -- hurray, we're done. Look to see if
343  * we've already got a ResultRelInfo for this partition.
344  */
345  if (likely(dispatch->indexes[partidx] >= 0))
346  {
347  /* ResultRelInfo already built */
348  Assert(dispatch->indexes[partidx] < proute->num_partitions);
349  rri = proute->partitions[dispatch->indexes[partidx]];
350  }
351  else
352  {
353  /*
354  * If the partition is known in the owning ModifyTableState
355  * node, we can re-use that ResultRelInfo instead of creating
356  * a new one with ExecInitPartitionInfo().
357  */
358  rri = ExecLookupResultRelByOid(mtstate,
359  partdesc->oids[partidx],
360  true, false);
361  if (rri)
362  {
363  /* Verify this ResultRelInfo allows INSERTs */
365 
366  /*
367  * Initialize information needed to insert this and
368  * subsequent tuples routed to this partition.
369  */
370  ExecInitRoutingInfo(mtstate, estate, proute, dispatch,
371  rri, partidx, true);
372  }
373  else
374  {
375  /* We need to create a new one. */
376  rri = ExecInitPartitionInfo(mtstate, estate, proute,
377  dispatch,
378  rootResultRelInfo, partidx);
379  }
380  }
381  Assert(rri != NULL);
382 
383  /* Signal to terminate the loop */
384  dispatch = NULL;
385  }
386  else
387  {
388  /*
389  * Partition is a sub-partitioned table; get the PartitionDispatch
390  */
391  if (likely(dispatch->indexes[partidx] >= 0))
392  {
393  /* Already built. */
394  Assert(dispatch->indexes[partidx] < proute->num_dispatch);
395 
396  rri = proute->nonleaf_partitions[dispatch->indexes[partidx]];
397 
398  /*
399  * Move down to the next partition level and search again
400  * until we find a leaf partition that matches this tuple
401  */
402  dispatch = pd[dispatch->indexes[partidx]];
403  }
404  else
405  {
406  /* Not yet built. Do that now. */
407  PartitionDispatch subdispatch;
408 
409  /*
410  * Create the new PartitionDispatch. We pass the current one
411  * in as the parent PartitionDispatch
412  */
413  subdispatch = ExecInitPartitionDispatchInfo(estate,
414  proute,
415  partdesc->oids[partidx],
416  dispatch, partidx,
417  mtstate->rootResultRelInfo);
418  Assert(dispatch->indexes[partidx] >= 0 &&
419  dispatch->indexes[partidx] < proute->num_dispatch);
420 
421  rri = proute->nonleaf_partitions[dispatch->indexes[partidx]];
422  dispatch = subdispatch;
423  }
424 
425  /*
426  * Convert the tuple to the new parent's layout, if different from
427  * the previous parent.
428  */
429  if (dispatch->tupslot)
430  {
431  AttrMap *map = dispatch->tupmap;
432  TupleTableSlot *tempslot = myslot;
433 
434  myslot = dispatch->tupslot;
435  slot = execute_attr_map_slot(map, slot, myslot);
436 
437  if (tempslot != NULL)
438  ExecClearTuple(tempslot);
439  }
440  }
441 
442  /*
443  * If this partition is the default one, we must check its partition
444  * constraint now, which may have changed concurrently due to
445  * partitions being added to the parent.
446  *
447  * (We do this here, and do not rely on ExecInsert doing it, because
448  * we don't want to miss doing it for non-leaf partitions.)
449  */
450  if (partidx == partdesc->boundinfo->default_index)
451  {
452  /*
453  * The tuple must match the partition's layout for the constraint
454  * expression to be evaluated successfully. If the partition is
455  * sub-partitioned, that would already be the case due to the code
456  * above, but for a leaf partition the tuple still matches the
457  * parent's layout.
458  *
459  * Note that we have a map to convert from root to current
460  * partition, but not from immediate parent to current partition.
461  * So if we have to convert, do it from the root slot; if not, use
462  * the root slot as-is.
463  */
464  if (is_leaf)
465  {
467 
468  if (map)
469  slot = execute_attr_map_slot(map->attrMap, rootslot,
470  rri->ri_PartitionTupleSlot);
471  else
472  slot = rootslot;
473  }
474 
475  ExecPartitionCheck(rri, slot, estate, true);
476  }
477  }
478 
479  /* Release the tuple in the lowest parent's dedicated slot. */
480  if (myslot != NULL)
481  ExecClearTuple(myslot);
482  /* and restore ecxt's scantuple */
483  ecxt->ecxt_scantuple = ecxt_scantuple_saved;
484  MemoryContextSwitchTo(oldcxt);
485 
486  return rri;
487 }
#define likely(x)
Definition: c.h:272
int errdetail(const char *fmt,...)
Definition: elog.c:1037
int errcode(int sqlerrcode)
Definition: elog.c:693
int errmsg(const char *fmt,...)
Definition: elog.c:904
#define ereport(elevel,...)
Definition: elog.h:143
bool ExecPartitionCheck(ResultRelInfo *resultRelInfo, TupleTableSlot *slot, EState *estate, bool emitError)
Definition: execMain.c:1782
void CheckValidResultRel(ResultRelInfo *resultRelInfo, CmdType operation)
Definition: execMain.c:994
static PartitionDispatch ExecInitPartitionDispatchInfo(EState *estate, PartitionTupleRouting *proute, Oid partoid, PartitionDispatch parent_pd, int partidx, ResultRelInfo *rootResultRelInfo)
static ResultRelInfo * ExecInitPartitionInfo(ModifyTableState *mtstate, EState *estate, PartitionTupleRouting *proute, PartitionDispatch dispatch, ResultRelInfo *rootResultRelInfo, int partidx)
static void ExecInitRoutingInfo(ModifyTableState *mtstate, EState *estate, PartitionTupleRouting *proute, PartitionDispatch dispatch, ResultRelInfo *partRelInfo, int partidx, bool is_borrowed_rel)
static char * ExecBuildSlotPartitionKeyDescription(Relation rel, Datum *values, bool *isnull, int maxfieldlen)
static void FormPartitionKeyDatum(PartitionDispatch pd, TupleTableSlot *slot, EState *estate, Datum *values, bool *isnull)
static int get_partition_for_tuple(PartitionDispatch pd, Datum *values, bool *isnull)
#define GetPerTupleExprContext(estate)
Definition: executor.h:537
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:542
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:121
ResultRelInfo * ExecLookupResultRelByOid(ModifyTableState *node, Oid resultoid, bool missing_ok, bool update_cache)
@ CMD_INSERT
Definition: nodes.h:723
#define PARTITION_MAX_KEYS
uintptr_t Datum
Definition: postgres.h:411
#define RelationGetRelationName(relation)
Definition: rel.h:523
int errtable(Relation rel)
Definition: relcache.c:5819
Definition: attmap.h:35
TupleTableSlot * ecxt_scantuple
Definition: execnodes.h:232
ResultRelInfo * rootResultRelInfo
Definition: execnodes.h:1238
PartitionBoundInfo boundinfo
Definition: partdesc.h:38
bool * is_leaf
Definition: partdesc.h:35
PartitionDesc partdesc
int indexes[FLEXIBLE_ARRAY_MEMBER]
ResultRelInfo ** nonleaf_partitions
Definition: execPartition.c:98
Form_pg_class rd_rel
Definition: rel.h:109
TupleTableSlot * ri_PartitionTupleSlot
Definition: execnodes.h:540
TupleConversionMap * ri_RootToPartitionMap
Definition: execnodes.h:539
TupleTableSlot * execute_attr_map_slot(AttrMap *attrMap, TupleTableSlot *in_slot, TupleTableSlot *out_slot)
Definition: tupconvert.c:177
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:425

References Assert(), TupleConversionMap::attrMap, PartitionDescData::boundinfo, CHECK_FOR_INTERRUPTS, CheckValidResultRel(), CMD_INSERT, PartitionBoundInfoData::default_index, ExprContext::ecxt_scantuple, ereport, errcode(), errdetail(), errmsg(), ERROR, errtable(), ExecBuildSlotPartitionKeyDescription(), ExecClearTuple(), ExecInitPartitionDispatchInfo(), ExecInitPartitionInfo(), ExecInitRoutingInfo(), ExecLookupResultRelByOid(), ExecPartitionCheck(), execute_attr_map_slot(), FormPartitionKeyDatum(), get_partition_for_tuple(), GetPerTupleExprContext, GetPerTupleMemoryContext, PartitionDispatchData::indexes, PartitionDescData::is_leaf, likely, MemoryContextSwitchTo(), PartitionTupleRouting::nonleaf_partitions, PartitionDescData::nparts, PartitionTupleRouting::num_dispatch, PartitionTupleRouting::num_partitions, OidIsValid, PartitionDescData::oids, PartitionDispatchData::partdesc, PartitionTupleRouting::partition_dispatch_info, PARTITION_MAX_KEYS, PartitionTupleRouting::partitions, RelationData::rd_rel, RelationGetRelationName, RelationGetRelid, PartitionDispatchData::reldesc, ResultRelInfo::ri_PartitionTupleSlot, ResultRelInfo::ri_RelationDesc, ResultRelInfo::ri_RootToPartitionMap, ModifyTableState::rootResultRelInfo, PartitionDispatchData::tupmap, PartitionDispatchData::tupslot, and values.

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

◆ ExecInitPartitionDispatchInfo()

static PartitionDispatch ExecInitPartitionDispatchInfo ( EState estate,
PartitionTupleRouting proute,
Oid  partoid,
PartitionDispatch  parent_pd,
int  partidx,
ResultRelInfo rootResultRelInfo 
)
static

Definition at line 1087 of file execPartition.c.

1091 {
1092  Relation rel;
1093  PartitionDesc partdesc;
1094  PartitionDispatch pd;
1095  int dispatchidx;
1096  MemoryContext oldcxt;
1097 
1098  /*
1099  * For data modification, it is better that executor does not include
1100  * partitions being detached, except when running in snapshot-isolation
1101  * mode. This means that a read-committed transaction immediately gets a
1102  * "no partition for tuple" error when a tuple is inserted into a
1103  * partition that's being detached concurrently, but a transaction in
1104  * repeatable-read mode can still use such a partition.
1105  */
1106  if (estate->es_partition_directory == NULL)
1107  estate->es_partition_directory =
1110 
1111  oldcxt = MemoryContextSwitchTo(proute->memcxt);
1112 
1113  /*
1114  * Only sub-partitioned tables need to be locked here. The root
1115  * partitioned table will already have been locked as it's referenced in
1116  * the query's rtable.
1117  */
1118  if (partoid != RelationGetRelid(proute->partition_root))
1119  rel = table_open(partoid, RowExclusiveLock);
1120  else
1121  rel = proute->partition_root;
1122  partdesc = PartitionDirectoryLookup(estate->es_partition_directory, rel);
1123 
1125  partdesc->nparts * sizeof(int));
1126  pd->reldesc = rel;
1127  pd->key = RelationGetPartitionKey(rel);
1128  pd->keystate = NIL;
1129  pd->partdesc = partdesc;
1130  if (parent_pd != NULL)
1131  {
1132  TupleDesc tupdesc = RelationGetDescr(rel);
1133 
1134  /*
1135  * For sub-partitioned tables where the column order differs from its
1136  * direct parent partitioned table, we must store a tuple table slot
1137  * initialized with its tuple descriptor and a tuple conversion map to
1138  * convert a tuple from its parent's rowtype to its own. This is to
1139  * make sure that we are looking at the correct row using the correct
1140  * tuple descriptor when computing its partition key for tuple
1141  * routing.
1142  */
1144  tupdesc);
1145  pd->tupslot = pd->tupmap ?
1146  MakeSingleTupleTableSlot(tupdesc, &TTSOpsVirtual) : NULL;
1147  }
1148  else
1149  {
1150  /* Not required for the root partitioned table */
1151  pd->tupmap = NULL;
1152  pd->tupslot = NULL;
1153  }
1154 
1155  /*
1156  * Initialize with -1 to signify that the corresponding partition's
1157  * ResultRelInfo or PartitionDispatch has not been created yet.
1158  */
1159  memset(pd->indexes, -1, sizeof(int) * partdesc->nparts);
1160 
1161  /* Track in PartitionTupleRouting for later use */
1162  dispatchidx = proute->num_dispatch++;
1163 
1164  /* Allocate or enlarge the array, as needed */
1165  if (proute->num_dispatch >= proute->max_dispatch)
1166  {
1167  if (proute->max_dispatch == 0)
1168  {
1169  proute->max_dispatch = 4;
1171  palloc(sizeof(PartitionDispatch) * proute->max_dispatch);
1172  proute->nonleaf_partitions = (ResultRelInfo **)
1173  palloc(sizeof(ResultRelInfo *) * proute->max_dispatch);
1174  }
1175  else
1176  {
1177  proute->max_dispatch *= 2;
1180  sizeof(PartitionDispatch) * proute->max_dispatch);
1181  proute->nonleaf_partitions = (ResultRelInfo **)
1182  repalloc(proute->nonleaf_partitions,
1183  sizeof(ResultRelInfo *) * proute->max_dispatch);
1184  }
1185  }
1186  proute->partition_dispatch_info[dispatchidx] = pd;
1187 
1188  /*
1189  * If setting up a PartitionDispatch for a sub-partitioned table, we may
1190  * also need a minimally valid ResultRelInfo for checking the partition
1191  * constraint later; set that up now.
1192  */
1193  if (parent_pd)
1194  {
1196 
1197  InitResultRelInfo(rri, rel, 0, rootResultRelInfo, 0);
1198  proute->nonleaf_partitions[dispatchidx] = rri;
1199  }
1200  else
1201  proute->nonleaf_partitions[dispatchidx] = NULL;
1202 
1203  /*
1204  * Finally, if setting up a PartitionDispatch for a sub-partitioned table,
1205  * install a downlink in the parent to allow quick descent.
1206  */
1207  if (parent_pd)
1208  {
1209  Assert(parent_pd->indexes[partidx] == -1);
1210  parent_pd->indexes[partidx] = dispatchidx;
1211  }
1212 
1213  MemoryContextSwitchTo(oldcxt);
1214 
1215  return pd;
1216 }
AttrMap * build_attrmap_by_name_if_req(TupleDesc indesc, TupleDesc outdesc)
Definition: attmap.c:259
void InitResultRelInfo(ResultRelInfo *resultRelInfo, Relation resultRelationDesc, Index resultRelationIndex, ResultRelInfo *partition_root_rri, int instrument_options)
Definition: execMain.c:1195
struct PartitionDispatchData * PartitionDispatch
Definition: execPartition.h:22
const TupleTableSlotOps TTSOpsVirtual
Definition: execTuples.c:83
TupleTableSlot * MakeSingleTupleTableSlot(TupleDesc tupdesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1238
#define RowExclusiveLock
Definition: lockdefs.h:38
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1188
#define makeNode(_type_)
Definition: nodes.h:621
#define RelationGetDescr(relation)
Definition: rel.h:515
MemoryContext memcxt
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
#define IsolationUsesXactSnapshot()
Definition: xact.h:51

References Assert(), build_attrmap_by_name_if_req(), CreatePartitionDirectory(), EState::es_partition_directory, EState::es_query_cxt, PartitionDispatchData::indexes, InitResultRelInfo(), IsolationUsesXactSnapshot, PartitionDispatchData::key, PartitionDispatchData::keystate, makeNode, MakeSingleTupleTableSlot(), PartitionTupleRouting::max_dispatch, PartitionTupleRouting::memcxt, MemoryContextSwitchTo(), NIL, PartitionTupleRouting::nonleaf_partitions, PartitionDescData::nparts, PartitionTupleRouting::num_dispatch, offsetof, palloc(), PartitionDispatchData::partdesc, PartitionTupleRouting::partition_dispatch_info, PartitionTupleRouting::partition_root, PartitionDirectoryLookup(), RelationGetDescr, RelationGetPartitionKey(), RelationGetRelid, PartitionDispatchData::reldesc, repalloc(), RowExclusiveLock, table_open(), TTSOpsVirtual, PartitionDispatchData::tupmap, and PartitionDispatchData::tupslot.

Referenced by ExecFindPartition(), and ExecSetupPartitionTupleRouting().

◆ ExecInitPartitionInfo()

static ResultRelInfo * ExecInitPartitionInfo ( ModifyTableState mtstate,
EState estate,
PartitionTupleRouting proute,
PartitionDispatch  dispatch,
ResultRelInfo rootResultRelInfo,
int  partidx 
)
static

Definition at line 498 of file execPartition.c.

503 {
504  ModifyTable *node = (ModifyTable *) mtstate->ps.plan;
505  Oid partOid = dispatch->partdesc->oids[partidx];
506  Relation partrel;
507  int firstVarno = mtstate->resultRelInfo[0].ri_RangeTableIndex;
508  Relation firstResultRel = mtstate->resultRelInfo[0].ri_RelationDesc;
509  ResultRelInfo *leaf_part_rri;
510  MemoryContext oldcxt;
511  AttrMap *part_attmap = NULL;
512  bool found_whole_row;
513 
514  oldcxt = MemoryContextSwitchTo(proute->memcxt);
515 
516  partrel = table_open(partOid, RowExclusiveLock);
517 
518  leaf_part_rri = makeNode(ResultRelInfo);
519  InitResultRelInfo(leaf_part_rri,
520  partrel,
521  0,
522  rootResultRelInfo,
523  estate->es_instrument);
524 
525  /*
526  * Verify result relation is a valid target for an INSERT. An UPDATE of a
527  * partition-key becomes a DELETE+INSERT operation, so this check is still
528  * required when the operation is CMD_UPDATE.
529  */
530  CheckValidResultRel(leaf_part_rri, CMD_INSERT);
531 
532  /*
533  * Open partition indices. The user may have asked to check for conflicts
534  * within this leaf partition and do "nothing" instead of throwing an
535  * error. Be prepared in that case by initializing the index information
536  * needed by ExecInsert() to perform speculative insertions.
537  */
538  if (partrel->rd_rel->relhasindex &&
539  leaf_part_rri->ri_IndexRelationDescs == NULL)
540  ExecOpenIndices(leaf_part_rri,
541  (node != NULL &&
543 
544  /*
545  * Build WITH CHECK OPTION constraints for the partition. Note that we
546  * didn't build the withCheckOptionList for partitions within the planner,
547  * but simple translation of varattnos will suffice. This only occurs for
548  * the INSERT case or in the case of UPDATE tuple routing where we didn't
549  * find a result rel to reuse.
550  */
551  if (node && node->withCheckOptionLists != NIL)
552  {
553  List *wcoList;
554  List *wcoExprs = NIL;
555  ListCell *ll;
556 
557  /*
558  * In the case of INSERT on a partitioned table, there is only one
559  * plan. Likewise, there is only one WCO list, not one per partition.
560  * For UPDATE, there are as many WCO lists as there are plans.
561  */
562  Assert((node->operation == CMD_INSERT &&
563  list_length(node->withCheckOptionLists) == 1 &&
564  list_length(node->resultRelations) == 1) ||
565  (node->operation == CMD_UPDATE &&
567  list_length(node->resultRelations)));
568 
569  /*
570  * Use the WCO list of the first plan as a reference to calculate
571  * attno's for the WCO list of this partition. In the INSERT case,
572  * that refers to the root partitioned table, whereas in the UPDATE
573  * tuple routing case, that refers to the first partition in the
574  * mtstate->resultRelInfo array. In any case, both that relation and
575  * this partition should have the same columns, so we should be able
576  * to map attributes successfully.
577  */
578  wcoList = linitial(node->withCheckOptionLists);
579 
580  /*
581  * Convert Vars in it to contain this partition's attribute numbers.
582  */
583  part_attmap =
585  RelationGetDescr(firstResultRel));
586  wcoList = (List *)
587  map_variable_attnos((Node *) wcoList,
588  firstVarno, 0,
589  part_attmap,
590  RelationGetForm(partrel)->reltype,
591  &found_whole_row);
592  /* We ignore the value of found_whole_row. */
593 
594  foreach(ll, wcoList)
595  {
597  ExprState *wcoExpr = ExecInitQual(castNode(List, wco->qual),
598  &mtstate->ps);
599 
600  wcoExprs = lappend(wcoExprs, wcoExpr);
601  }
602 
603  leaf_part_rri->ri_WithCheckOptions = wcoList;
604  leaf_part_rri->ri_WithCheckOptionExprs = wcoExprs;
605  }
606 
607  /*
608  * Build the RETURNING projection for the partition. Note that we didn't
609  * build the returningList for partitions within the planner, but simple
610  * translation of varattnos will suffice. This only occurs for the INSERT
611  * case or in the case of UPDATE tuple routing where we didn't find a
612  * result rel to reuse.
613  */
614  if (node && node->returningLists != NIL)
615  {
616  TupleTableSlot *slot;
617  ExprContext *econtext;
618  List *returningList;
619 
620  /* See the comment above for WCO lists. */
621  Assert((node->operation == CMD_INSERT &&
622  list_length(node->returningLists) == 1 &&
623  list_length(node->resultRelations) == 1) ||
624  (node->operation == CMD_UPDATE &&
625  list_length(node->returningLists) ==
626  list_length(node->resultRelations)));
627 
628  /*
629  * Use the RETURNING list of the first plan as a reference to
630  * calculate attno's for the RETURNING list of this partition. See
631  * the comment above for WCO lists for more details on why this is
632  * okay.
633  */
634  returningList = linitial(node->returningLists);
635 
636  /*
637  * Convert Vars in it to contain this partition's attribute numbers.
638  */
639  if (part_attmap == NULL)
640  part_attmap =
642  RelationGetDescr(firstResultRel));
643  returningList = (List *)
644  map_variable_attnos((Node *) returningList,
645  firstVarno, 0,
646  part_attmap,
647  RelationGetForm(partrel)->reltype,
648  &found_whole_row);
649  /* We ignore the value of found_whole_row. */
650 
651  leaf_part_rri->ri_returningList = returningList;
652 
653  /*
654  * Initialize the projection itself.
655  *
656  * Use the slot and the expression context that would have been set up
657  * in ExecInitModifyTable() for projection's output.
658  */
659  Assert(mtstate->ps.ps_ResultTupleSlot != NULL);
660  slot = mtstate->ps.ps_ResultTupleSlot;
661  Assert(mtstate->ps.ps_ExprContext != NULL);
662  econtext = mtstate->ps.ps_ExprContext;
663  leaf_part_rri->ri_projectReturning =
664  ExecBuildProjectionInfo(returningList, econtext, slot,
665  &mtstate->ps, RelationGetDescr(partrel));
666  }
667 
668  /* Set up information needed for routing tuples to the partition. */
669  ExecInitRoutingInfo(mtstate, estate, proute, dispatch,
670  leaf_part_rri, partidx, false);
671 
672  /*
673  * If there is an ON CONFLICT clause, initialize state for it.
674  */
675  if (node && node->onConflictAction != ONCONFLICT_NONE)
676  {
677  TupleDesc partrelDesc = RelationGetDescr(partrel);
678  ExprContext *econtext = mtstate->ps.ps_ExprContext;
679  ListCell *lc;
680  List *arbiterIndexes = NIL;
681 
682  /*
683  * If there is a list of arbiter indexes, map it to a list of indexes
684  * in the partition. We do that by scanning the partition's index
685  * list and searching for ancestry relationships to each index in the
686  * ancestor table.
687  */
688  if (list_length(rootResultRelInfo->ri_onConflictArbiterIndexes) > 0)
689  {
690  List *childIdxs;
691 
692  childIdxs = RelationGetIndexList(leaf_part_rri->ri_RelationDesc);
693 
694  foreach(lc, childIdxs)
695  {
696  Oid childIdx = lfirst_oid(lc);
697  List *ancestors;
698  ListCell *lc2;
699 
700  ancestors = get_partition_ancestors(childIdx);
701  foreach(lc2, rootResultRelInfo->ri_onConflictArbiterIndexes)
702  {
703  if (list_member_oid(ancestors, lfirst_oid(lc2)))
704  arbiterIndexes = lappend_oid(arbiterIndexes, childIdx);
705  }
706  list_free(ancestors);
707  }
708  }
709 
710  /*
711  * If the resulting lists are of inequal length, something is wrong.
712  * (This shouldn't happen, since arbiter index selection should not
713  * pick up an invalid index.)
714  */
715  if (list_length(rootResultRelInfo->ri_onConflictArbiterIndexes) !=
716  list_length(arbiterIndexes))
717  elog(ERROR, "invalid arbiter index list");
718  leaf_part_rri->ri_onConflictArbiterIndexes = arbiterIndexes;
719 
720  /*
721  * In the DO UPDATE case, we have some more state to initialize.
722  */
723  if (node->onConflictAction == ONCONFLICT_UPDATE)
724  {
726  TupleConversionMap *map;
727 
728  map = leaf_part_rri->ri_RootToPartitionMap;
729 
730  Assert(node->onConflictSet != NIL);
731  Assert(rootResultRelInfo->ri_onConflict != NULL);
732 
733  leaf_part_rri->ri_onConflict = onconfl;
734 
735  /*
736  * Need a separate existing slot for each partition, as the
737  * partition could be of a different AM, even if the tuple
738  * descriptors match.
739  */
740  onconfl->oc_Existing =
741  table_slot_create(leaf_part_rri->ri_RelationDesc,
742  &mtstate->ps.state->es_tupleTable);
743 
744  /*
745  * If the partition's tuple descriptor matches exactly the root
746  * parent (the common case), we can re-use most of the parent's ON
747  * CONFLICT SET state, skipping a bunch of work. Otherwise, we
748  * need to create state specific to this partition.
749  */
750  if (map == NULL)
751  {
752  /*
753  * It's safe to reuse these from the partition root, as we
754  * only process one tuple at a time (therefore we won't
755  * overwrite needed data in slots), and the results of
756  * projections are independent of the underlying storage.
757  * Projections and where clauses themselves don't store state
758  * / are independent of the underlying storage.
759  */
760  onconfl->oc_ProjSlot =
761  rootResultRelInfo->ri_onConflict->oc_ProjSlot;
762  onconfl->oc_ProjInfo =
763  rootResultRelInfo->ri_onConflict->oc_ProjInfo;
764  onconfl->oc_WhereClause =
765  rootResultRelInfo->ri_onConflict->oc_WhereClause;
766  }
767  else
768  {
769  List *onconflset;
770  List *onconflcols;
771  bool found_whole_row;
772 
773  /*
774  * Translate expressions in onConflictSet to account for
775  * different attribute numbers. For that, map partition
776  * varattnos twice: first to catch the EXCLUDED
777  * pseudo-relation (INNER_VAR), and second to handle the main
778  * target relation (firstVarno).
779  */
780  onconflset = copyObject(node->onConflictSet);
781  if (part_attmap == NULL)
782  part_attmap =
784  RelationGetDescr(firstResultRel));
785  onconflset = (List *)
786  map_variable_attnos((Node *) onconflset,
787  INNER_VAR, 0,
788  part_attmap,
789  RelationGetForm(partrel)->reltype,
790  &found_whole_row);
791  /* We ignore the value of found_whole_row. */
792  onconflset = (List *)
793  map_variable_attnos((Node *) onconflset,
794  firstVarno, 0,
795  part_attmap,
796  RelationGetForm(partrel)->reltype,
797  &found_whole_row);
798  /* We ignore the value of found_whole_row. */
799 
800  /* Finally, adjust the target colnos to match the partition. */
801  onconflcols = adjust_partition_colnos(node->onConflictCols,
802  leaf_part_rri);
803 
804  /* create the tuple slot for the UPDATE SET projection */
805  onconfl->oc_ProjSlot =
806  table_slot_create(partrel,
807  &mtstate->ps.state->es_tupleTable);
808 
809  /* build UPDATE SET projection state */
810  onconfl->oc_ProjInfo =
811  ExecBuildUpdateProjection(onconflset,
812  true,
813  onconflcols,
814  partrelDesc,
815  econtext,
816  onconfl->oc_ProjSlot,
817  &mtstate->ps);
818 
819  /*
820  * If there is a WHERE clause, initialize state where it will
821  * be evaluated, mapping the attribute numbers appropriately.
822  * As with onConflictSet, we need to map partition varattnos
823  * to the partition's tupdesc.
824  */
825  if (node->onConflictWhere)
826  {
827  List *clause;
828 
829  clause = copyObject((List *) node->onConflictWhere);
830  clause = (List *)
831  map_variable_attnos((Node *) clause,
832  INNER_VAR, 0,
833  part_attmap,
834  RelationGetForm(partrel)->reltype,
835  &found_whole_row);
836  /* We ignore the value of found_whole_row. */
837  clause = (List *)
838  map_variable_attnos((Node *) clause,
839  firstVarno, 0,
840  part_attmap,
841  RelationGetForm(partrel)->reltype,
842  &found_whole_row);
843  /* We ignore the value of found_whole_row. */
844  onconfl->oc_WhereClause =
845  ExecInitQual((List *) clause, &mtstate->ps);
846  }
847  }
848  }
849  }
850 
851  /*
852  * Since we've just initialized this ResultRelInfo, it's not in any list
853  * attached to the estate as yet. Add it, so that it can be found later.
854  *
855  * Note that the entries in this list appear in no predetermined order,
856  * because partition result rels are initialized as and when they're
857  * needed.
858  */
862  leaf_part_rri);
863 
864  /*
865  * Initialize information about this partition that's needed to handle
866  * MERGE. We take the "first" result relation's mergeActionList as
867  * reference and make copy for this relation, converting stuff that
868  * references attribute numbers to match this relation's.
869  *
870  * This duplicates much of the logic in ExecInitMerge(), so something
871  * changes there, look here too.
872  */
873  if (node && node->operation == CMD_MERGE)
874  {
875  List *firstMergeActionList = linitial(node->mergeActionLists);
876  ListCell *lc;
877  ExprContext *econtext = mtstate->ps.ps_ExprContext;
878 
879  if (part_attmap == NULL)
880  part_attmap =
882  RelationGetDescr(firstResultRel));
883 
884  if (unlikely(!leaf_part_rri->ri_projectNewInfoValid))
885  ExecInitMergeTupleSlots(mtstate, leaf_part_rri);
886 
887  foreach(lc, firstMergeActionList)
888  {
889  /* Make a copy for this relation to be safe. */
891  MergeActionState *action_state;
892  List **list;
893 
894  /* Generate the action's state for this relation */
895  action_state = makeNode(MergeActionState);
896  action_state->mas_action = action;
897 
898  /* And put the action in the appropriate list */
899  if (action->matched)
900  list = &leaf_part_rri->ri_matchedMergeAction;
901  else
902  list = &leaf_part_rri->ri_notMatchedMergeAction;
903  *list = lappend(*list, action_state);
904 
905  switch (action->commandType)
906  {
907  case CMD_INSERT:
908 
909  /*
910  * ExecCheckPlanOutput() already done on the targetlist
911  * when "first" result relation initialized and it is same
912  * for all result relations.
913  */
914  action_state->mas_proj =
915  ExecBuildProjectionInfo(action->targetList, econtext,
916  leaf_part_rri->ri_newTupleSlot,
917  &mtstate->ps,
918  RelationGetDescr(partrel));
919  break;
920  case CMD_UPDATE:
921 
922  /*
923  * Convert updateColnos from "first" result relation
924  * attribute numbers to this result rel's.
925  */
926  if (part_attmap)
927  action->updateColnos =
929  part_attmap);
930  action_state->mas_proj =
931  ExecBuildUpdateProjection(action->targetList,
932  true,
933  action->updateColnos,
934  RelationGetDescr(leaf_part_rri->ri_RelationDesc),
935  econtext,
936  leaf_part_rri->ri_newTupleSlot,
937  NULL);
938  break;
939  case CMD_DELETE:
940  break;
941 
942  default:
943  elog(ERROR, "unknown action in MERGE WHEN clause");
944  }
945 
946  /* found_whole_row intentionally ignored. */
947  action->qual =
949  firstVarno, 0,
950  part_attmap,
951  RelationGetForm(partrel)->reltype,
952  &found_whole_row);
953  action_state->mas_whenqual =
954  ExecInitQual((List *) action->qual, &mtstate->ps);
955  }
956  }
957  MemoryContextSwitchTo(oldcxt);
958 
959  return leaf_part_rri;
960 }
AttrMap * build_attrmap_by_name(TupleDesc indesc, TupleDesc outdesc)
Definition: attmap.c:174
#define unlikely(x)
Definition: c.h:273
ProjectionInfo * ExecBuildUpdateProjection(List *targetList, bool evalTargetList, List *targetColnos, TupleDesc relDesc, ExprContext *econtext, TupleTableSlot *slot, PlanState *parent)
Definition: execExpr.c:513
ExprState * ExecInitQual(List *qual, PlanState *parent)
Definition: execExpr.c:209
ProjectionInfo * ExecBuildProjectionInfo(List *targetList, ExprContext *econtext, TupleTableSlot *slot, PlanState *parent, TupleDesc inputDesc)
Definition: execExpr.c:353
void ExecOpenIndices(ResultRelInfo *resultRelInfo, bool speculative)
Definition: execIndexing.c:156
static List * adjust_partition_colnos(List *colnos, ResultRelInfo *leaf_part_rri)
List * lappend(List *list, void *datum)
Definition: list.c:336
List * lappend_oid(List *list, Oid datum)
Definition: list.c:372
void list_free(List *list)
Definition: list.c:1505
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:701
void ExecInitMergeTupleSlots(ModifyTableState *mtstate, ResultRelInfo *resultRelInfo)
#define copyObject(obj)
Definition: nodes.h:689
@ ONCONFLICT_NONE
Definition: nodes.h:871
@ ONCONFLICT_UPDATE
Definition: nodes.h:873
@ CMD_MERGE
Definition: nodes.h:725
@ CMD_DELETE
Definition: nodes.h:724
@ CMD_UPDATE
Definition: nodes.h:722
#define castNode(_type_, nodeptr)
Definition: nodes.h:642
List * get_partition_ancestors(Oid relid)
Definition: partition.c:133
#define lfirst(lc)
Definition: pg_list.h:169
#define linitial(l)
Definition: pg_list.h:174
#define lfirst_oid(lc)
Definition: pg_list.h:171
#define INNER_VAR
Definition: primnodes.h:184
#define RelationGetForm(relation)
Definition: rel.h:483
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4675
Node * map_variable_attnos(Node *node, int target_varno, int sublevels_up, const AttrMap *attno_map, Oid to_rowtype, bool *found_whole_row)
List * es_tuple_routing_result_relations
Definition: execnodes.h:620
int es_instrument
Definition: execnodes.h:639
List * es_tupleTable
Definition: execnodes.h:634
MergeAction * mas_action
Definition: execnodes.h:402
ProjectionInfo * mas_proj
Definition: execnodes.h:403
ExprState * mas_whenqual
Definition: execnodes.h:405
ResultRelInfo * resultRelInfo
Definition: execnodes.h:1230
List * onConflictCols
Definition: plannodes.h:237
CmdType operation
Definition: plannodes.h:221
List * resultRelations
Definition: plannodes.h:226
List * onConflictSet
Definition: plannodes.h:236
List * mergeActionLists
Definition: plannodes.h:241
List * returningLists
Definition: plannodes.h:229
List * withCheckOptionLists
Definition: plannodes.h:228
Node * onConflictWhere
Definition: plannodes.h:238
OnConflictAction onConflictAction
Definition: plannodes.h:234
Definition: nodes.h:574
TupleTableSlot * oc_ProjSlot
Definition: execnodes.h:387
TupleTableSlot * oc_Existing
Definition: execnodes.h:386
ExprState * oc_WhereClause
Definition: execnodes.h:389
ProjectionInfo * oc_ProjInfo
Definition: execnodes.h:388
Plan * plan
Definition: execnodes.h:998
TupleTableSlot * ps_ResultTupleSlot
Definition: execnodes.h:1036
OnConflictSetState * ri_onConflict
Definition: execnodes.h:517
List * ri_onConflictArbiterIndexes
Definition: execnodes.h:514
Index ri_RangeTableIndex
Definition: execnodes.h:430
TupleTableSlot * table_slot_create(Relation relation, List **reglist)
Definition: tableam.c:91

References generate_unaccent_rules::action, adjust_partition_colnos(), adjust_partition_colnos_using_map(), Assert(), build_attrmap_by_name(), castNode, CheckValidResultRel(), CMD_DELETE, CMD_INSERT, CMD_MERGE, CMD_UPDATE, copyObject, elog, ERROR, EState::es_instrument, EState::es_query_cxt, EState::es_tuple_routing_result_relations, EState::es_tupleTable, ExecBuildProjectionInfo(), ExecBuildUpdateProjection(), ExecInitMergeTupleSlots(), ExecInitQual(), ExecInitRoutingInfo(), ExecOpenIndices(), get_partition_ancestors(), InitResultRelInfo(), INNER_VAR, lappend(), lappend_oid(), lfirst, lfirst_node, lfirst_oid, linitial, sort-test::list, list_free(), list_length(), list_member_oid(), makeNode, map_variable_attnos(), MergeActionState::mas_action, MergeActionState::mas_proj, MergeActionState::mas_whenqual, PartitionTupleRouting::memcxt, MemoryContextSwitchTo(), ModifyTable::mergeActionLists, NIL, OnConflictSetState::oc_Existing, OnConflictSetState::oc_ProjInfo, OnConflictSetState::oc_ProjSlot, OnConflictSetState::oc_WhereClause, PartitionDescData::oids, ONCONFLICT_NONE, ONCONFLICT_UPDATE, ModifyTable::onConflictAction, ModifyTable::onConflictCols, ModifyTable::onConflictSet, ModifyTable::onConflictWhere, ModifyTable::operation, PartitionDispatchData::partdesc, PlanState::plan, ModifyTableState::ps, PlanState::ps_ExprContext, PlanState::ps_ResultTupleSlot, WithCheckOption::qual, RelationGetDescr, RelationGetForm, RelationGetIndexList(), ModifyTable::resultRelations, ModifyTableState::resultRelInfo, ModifyTable::returningLists, ResultRelInfo::ri_onConflict, ResultRelInfo::ri_onConflictArbiterIndexes, ResultRelInfo::ri_RangeTableIndex, ResultRelInfo::ri_RelationDesc, RowExclusiveLock, PlanState::state, table_open(), table_slot_create(), unlikely, and ModifyTable::withCheckOptionLists.

Referenced by ExecFindPartition().

◆ ExecInitPartitionPruning()

PartitionPruneState* ExecInitPartitionPruning ( PlanState planstate,
int  n_total_subplans,
PartitionPruneInfo pruneinfo,
Bitmapset **  initially_valid_subplans 
)

Definition at line 1639 of file execPartition.c.

1643 {
1644  PartitionPruneState *prunestate;
1645  EState *estate = planstate->state;
1646 
1647  /* We may need an expression context to evaluate partition exprs */
1648  ExecAssignExprContext(estate, planstate);
1649 
1650  /* Create the working data structure for pruning */
1651  prunestate = CreatePartitionPruneState(planstate, pruneinfo);
1652 
1653  /*
1654  * Perform an initial partition prune pass, if required.
1655  */
1656  if (prunestate->do_initial_prune)
1657  *initially_valid_subplans = ExecFindMatchingSubPlans(prunestate, true);
1658  else
1659  {
1660  /* No pruning, so we'll need to initialize all subplans */
1661  Assert(n_total_subplans > 0);
1662  *initially_valid_subplans = bms_add_range(NULL, 0,
1663  n_total_subplans - 1);
1664  }
1665 
1666  /*
1667  * Re-sequence subplan indexes contained in prunestate to account for any
1668  * that were removed above due to initial pruning. No need to do this if
1669  * no steps were removed.
1670  */
1671  if (bms_num_members(*initially_valid_subplans) < n_total_subplans)
1672  {
1673  /*
1674  * We can safely skip this when !do_exec_prune, even though that
1675  * leaves invalid data in prunestate, because that data won't be
1676  * consulted again (cf initial Assert in ExecFindMatchingSubPlans).
1677  */
1678  if (prunestate->do_exec_prune)
1679  PartitionPruneFixSubPlanMap(prunestate,
1680  *initially_valid_subplans,
1681  n_total_subplans);
1682  }
1683 
1684  return prunestate;
1685 }
int bms_num_members(const Bitmapset *a)
Definition: bitmapset.c:648
Bitmapset * bms_add_range(Bitmapset *a, int lower, int upper)
Definition: bitmapset.c:836
static PartitionPruneState * CreatePartitionPruneState(PlanState *planstate, PartitionPruneInfo *pruneinfo)
Bitmapset * ExecFindMatchingSubPlans(PartitionPruneState *prunestate, bool initial_prune)
static void PartitionPruneFixSubPlanMap(PartitionPruneState *prunestate, Bitmapset *initially_valid_subplans, int n_total_subplans)
void ExecAssignExprContext(EState *estate, PlanState *planstate)
Definition: execUtils.c:480

References Assert(), bms_add_range(), bms_num_members(), CreatePartitionPruneState(), PartitionPruneState::do_exec_prune, PartitionPruneState::do_initial_prune, ExecAssignExprContext(), ExecFindMatchingSubPlans(), PartitionPruneFixSubPlanMap(), and PlanState::state.

Referenced by ExecInitAppend(), and ExecInitMergeAppend().

◆ ExecInitRoutingInfo()

static void ExecInitRoutingInfo ( ModifyTableState mtstate,
EState estate,
PartitionTupleRouting proute,
PartitionDispatch  dispatch,
ResultRelInfo partRelInfo,
int  partidx,
bool  is_borrowed_rel 
)
static

Definition at line 969 of file execPartition.c.

976 {
977  ResultRelInfo *rootRelInfo = partRelInfo->ri_RootResultRelInfo;
978  MemoryContext oldcxt;
979  int rri_index;
980 
981  oldcxt = MemoryContextSwitchTo(proute->memcxt);
982 
983  /*
984  * Set up a tuple conversion map to convert a tuple routed to the
985  * partition from the parent's type to the partition's.
986  */
987  partRelInfo->ri_RootToPartitionMap =
989  RelationGetDescr(partRelInfo->ri_RelationDesc));
990 
991  /*
992  * If a partition has a different rowtype than the root parent, initialize
993  * a slot dedicated to storing this partition's tuples. The slot is used
994  * for various operations that are applied to tuples after routing, such
995  * as checking constraints.
996  */
997  if (partRelInfo->ri_RootToPartitionMap != NULL)
998  {
999  Relation partrel = partRelInfo->ri_RelationDesc;
1000 
1001  /*
1002  * Initialize the slot itself setting its descriptor to this
1003  * partition's TupleDesc; TupleDesc reference will be released at the
1004  * end of the command.
1005  */
1006  partRelInfo->ri_PartitionTupleSlot =
1007  table_slot_create(partrel, &estate->es_tupleTable);
1008  }
1009  else
1010  partRelInfo->ri_PartitionTupleSlot = NULL;
1011 
1012  /*
1013  * If the partition is a foreign table, let the FDW init itself for
1014  * routing tuples to the partition.
1015  */
1016  if (partRelInfo->ri_FdwRoutine != NULL &&
1017  partRelInfo->ri_FdwRoutine->BeginForeignInsert != NULL)
1018  partRelInfo->ri_FdwRoutine->BeginForeignInsert(mtstate, partRelInfo);
1019 
1020  /*
1021  * Determine if the FDW supports batch insert and determine the batch size
1022  * (a FDW may support batching, but it may be disabled for the
1023  * server/table or for this particular query).
1024  *
1025  * If the FDW does not support batching, we set the batch size to 1.
1026  */
1027  if (mtstate->operation == CMD_INSERT &&
1028  partRelInfo->ri_FdwRoutine != NULL &&
1029  partRelInfo->ri_FdwRoutine->GetForeignModifyBatchSize &&
1030  partRelInfo->ri_FdwRoutine->ExecForeignBatchInsert)
1031  partRelInfo->ri_BatchSize =
1032  partRelInfo->ri_FdwRoutine->GetForeignModifyBatchSize(partRelInfo);
1033  else
1034  partRelInfo->ri_BatchSize = 1;
1035 
1036  Assert(partRelInfo->ri_BatchSize >= 1);
1037 
1038  partRelInfo->ri_CopyMultiInsertBuffer = NULL;
1039 
1040  /*
1041  * Keep track of it in the PartitionTupleRouting->partitions array.
1042  */
1043  Assert(dispatch->indexes[partidx] == -1);
1044 
1045  rri_index = proute->num_partitions++;
1046 
1047  /* Allocate or enlarge the array, as needed */
1048  if (proute->num_partitions >= proute->max_partitions)
1049  {
1050  if (proute->max_partitions == 0)
1051  {
1052  proute->max_partitions = 8;
1053  proute->partitions = (ResultRelInfo **)
1054  palloc(sizeof(ResultRelInfo *) * proute->max_partitions);
1055  proute->is_borrowed_rel = (bool *)
1056  palloc(sizeof(bool) * proute->max_partitions);
1057  }
1058  else
1059  {
1060  proute->max_partitions *= 2;
1061  proute->partitions = (ResultRelInfo **)
1062  repalloc(proute->partitions, sizeof(ResultRelInfo *) *
1063  proute->max_partitions);
1064  proute->is_borrowed_rel = (bool *)
1065  repalloc(proute->is_borrowed_rel, sizeof(bool) *
1066  proute->max_partitions);
1067  }
1068  }
1069 
1070  proute->partitions[rri_index] = partRelInfo;
1071  proute->is_borrowed_rel[rri_index] = is_borrowed_rel;
1072  dispatch->indexes[partidx] = rri_index;
1073 
1074  MemoryContextSwitchTo(oldcxt);
1075 }
BeginForeignInsert_function BeginForeignInsert
Definition: fdwapi.h:238
ExecForeignBatchInsert_function ExecForeignBatchInsert
Definition: fdwapi.h:233
GetForeignModifyBatchSize_function GetForeignModifyBatchSize
Definition: fdwapi.h:234
CmdType operation
Definition: execnodes.h:1226
struct ResultRelInfo * ri_RootResultRelInfo
Definition: execnodes.h:538
struct CopyMultiInsertBuffer * ri_CopyMultiInsertBuffer
Definition: execnodes.h:552
int ri_BatchSize
Definition: execnodes.h:488
TupleConversionMap * convert_tuples_by_name(TupleDesc indesc, TupleDesc outdesc)
Definition: tupconvert.c:102

References Assert(), FdwRoutine::BeginForeignInsert, CMD_INSERT, convert_tuples_by_name(), EState::es_tupleTable, FdwRoutine::ExecForeignBatchInsert, FdwRoutine::GetForeignModifyBatchSize, PartitionDispatchData::indexes, PartitionTupleRouting::is_borrowed_rel, PartitionTupleRouting::max_partitions, PartitionTupleRouting::memcxt, MemoryContextSwitchTo(), PartitionTupleRouting::num_partitions, ModifyTableState::operation, palloc(), PartitionTupleRouting::partitions, RelationGetDescr, repalloc(), ResultRelInfo::ri_BatchSize, ResultRelInfo::ri_CopyMultiInsertBuffer, ResultRelInfo::ri_FdwRoutine, ResultRelInfo::ri_PartitionTupleSlot, ResultRelInfo::ri_RelationDesc, ResultRelInfo::ri_RootResultRelInfo, ResultRelInfo::ri_RootToPartitionMap, and table_slot_create().

Referenced by ExecFindPartition(), and ExecInitPartitionInfo().

◆ ExecSetupPartitionTupleRouting()

PartitionTupleRouting* ExecSetupPartitionTupleRouting ( EState estate,
Relation  rel 
)

Definition at line 218 of file execPartition.c.

219 {
220  PartitionTupleRouting *proute;
221 
222  /*
223  * Here we attempt to expend as little effort as possible in setting up
224  * the PartitionTupleRouting. Each partition's ResultRelInfo is built on
225  * demand, only when we actually need to route a tuple to that partition.
226  * The reason for this is that a common case is for INSERT to insert a
227  * single tuple into a partitioned table and this must be fast.
228  */
230  proute->partition_root = rel;
231  proute->memcxt = CurrentMemoryContext;
232  /* Rest of members initialized by zeroing */
233 
234  /*
235  * Initialize this table's PartitionDispatch object. Here we pass in the
236  * parent as NULL as we don't need to care about any parent of the target
237  * partitioned table.
238  */
239  ExecInitPartitionDispatchInfo(estate, proute, RelationGetRelid(rel),
240  NULL, 0, NULL);
241 
242  return proute;
243 }
void * palloc0(Size size)
Definition: mcxt.c:1099

References CurrentMemoryContext, ExecInitPartitionDispatchInfo(), PartitionTupleRouting::memcxt, palloc0(), PartitionTupleRouting::partition_root, and RelationGetRelid.

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

◆ find_matching_subplans_recurse()

static void find_matching_subplans_recurse ( PartitionPruningData prunedata,
PartitionedRelPruningData pprune,
bool  initial_prune,
Bitmapset **  validsubplans 
)
static

Definition at line 2185 of file execPartition.c.

2189 {
2190  Bitmapset *partset;
2191  int i;
2192 
2193  /* Guard against stack overflow due to overly deep partition hierarchy. */
2195 
2196  /*
2197  * Prune as appropriate, if we have pruning steps matching the current
2198  * execution context. Otherwise just include all partitions at this
2199  * level.
2200  */
2201  if (initial_prune && pprune->initial_pruning_steps)
2202  partset = get_matching_partitions(&pprune->initial_context,
2203  pprune->initial_pruning_steps);
2204  else if (!initial_prune && pprune->exec_pruning_steps)
2205  partset = get_matching_partitions(&pprune->exec_context,
2206  pprune->exec_pruning_steps);
2207  else
2208  partset = pprune->present_parts;
2209 
2210  /* Translate partset into subplan indexes */
2211  i = -1;
2212  while ((i = bms_next_member(partset, i)) >= 0)
2213  {
2214  if (pprune->subplan_map[i] >= 0)
2215  *validsubplans = bms_add_member(*validsubplans,
2216  pprune->subplan_map[i]);
2217  else
2218  {
2219  int partidx = pprune->subpart_map[i];
2220 
2221  if (partidx >= 0)
2223  &prunedata->partrelprunedata[partidx],
2224  initial_prune, validsubplans);
2225  else
2226  {
2227  /*
2228  * We get here if the planner already pruned all the sub-
2229  * partitions for this partition. Silently ignore this
2230  * partition in this case. The end result is the same: we
2231  * would have pruned all partitions just the same, but we
2232  * don't have any pruning steps to execute to verify this.
2233  */
2234  }
2235  }
2236  }
2237 }
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1045
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:738
Bitmapset * get_matching_partitions(PartitionPruneContext *context, List *pruning_steps)
Definition: partprune.c:819
void check_stack_depth(void)
Definition: postgres.c:3500

References bms_add_member(), bms_next_member(), check_stack_depth(), PartitionedRelPruningData::exec_context, PartitionedRelPruningData::exec_pruning_steps, get_matching_partitions(), i, PartitionedRelPruningData::initial_context, PartitionedRelPruningData::initial_pruning_steps, PartitionPruningData::partrelprunedata, PartitionedRelPruningData::present_parts, PartitionedRelPruningData::subpart_map, and PartitionedRelPruningData::subplan_map.

Referenced by ExecFindMatchingSubPlans().

◆ FormPartitionKeyDatum()

static void FormPartitionKeyDatum ( PartitionDispatch  pd,
TupleTableSlot slot,
EState estate,
Datum values,
bool isnull 
)
static

Definition at line 1286 of file execPartition.c.

1291 {
1292  ListCell *partexpr_item;
1293  int i;
1294 
1295  if (pd->key->partexprs != NIL && pd->keystate == NIL)
1296  {
1297  /* Check caller has set up context correctly */
1298  Assert(estate != NULL &&
1299  GetPerTupleExprContext(estate)->ecxt_scantuple == slot);
1300 
1301  /* First time through, set up expression evaluation state */
1302  pd->keystate = ExecPrepareExprList(pd->key->partexprs, estate);
1303  }
1304 
1305  partexpr_item = list_head(pd->keystate);
1306  for (i = 0; i < pd->key->partnatts; i++)
1307  {
1308  AttrNumber keycol = pd->key->partattrs[i];
1309  Datum datum;
1310  bool isNull;
1311 
1312  if (keycol != 0)
1313  {
1314  /* Plain column; get the value directly from the heap tuple */
1315  datum = slot_getattr(slot, keycol, &isNull);
1316  }
1317  else
1318  {
1319  /* Expression; need to evaluate it */
1320  if (partexpr_item == NULL)
1321  elog(ERROR, "wrong number of partition key expressions");
1322  datum = ExecEvalExprSwitchContext((ExprState *) lfirst(partexpr_item),
1323  GetPerTupleExprContext(estate),
1324  &isNull);
1325  partexpr_item = lnext(pd->keystate, partexpr_item);
1326  }
1327  values[i] = datum;
1328  isnull[i] = isNull;
1329  }
1330 
1331  if (partexpr_item != NULL)
1332  elog(ERROR, "wrong number of partition key expressions");
1333 }
List * ExecPrepareExprList(List *nodes, EState *estate)
Definition: execExpr.c:820
static Datum ExecEvalExprSwitchContext(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:335
static ListCell * list_head(const List *l)
Definition: pg_list.h:125
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:322
List * partexprs
Definition: partcache.h:30
AttrNumber * partattrs
Definition: partcache.h:28
static Datum slot_getattr(TupleTableSlot *slot, int attnum, bool *isnull)
Definition: tuptable.h:381

References Assert(), elog, ERROR, ExecEvalExprSwitchContext(), ExecPrepareExprList(), GetPerTupleExprContext, i, PartitionDispatchData::key, PartitionDispatchData::keystate, lfirst, list_head(), lnext(), NIL, PartitionKeyData::partattrs, PartitionKeyData::partexprs, PartitionKeyData::partnatts, slot_getattr(), and values.

Referenced by ExecFindPartition().

◆ get_partition_for_tuple()

static int get_partition_for_tuple ( PartitionDispatch  pd,
Datum values,
bool isnull 
)
static

Definition at line 1344 of file execPartition.c.

1345 {
1346  int bound_offset;
1347  int part_index = -1;
1348  PartitionKey key = pd->key;
1349  PartitionDesc partdesc = pd->partdesc;
1350  PartitionBoundInfo boundinfo = partdesc->boundinfo;
1351 
1352  /* Route as appropriate based on partitioning strategy. */
1353  switch (key->strategy)
1354  {
1356  {
1357  uint64 rowHash;
1358 
1359  rowHash = compute_partition_hash_value(key->partnatts,
1360  key->partsupfunc,
1361  key->partcollation,
1362  values, isnull);
1363 
1364  part_index = boundinfo->indexes[rowHash % boundinfo->nindexes];
1365  }
1366  break;
1367 
1369  if (isnull[0])
1370  {
1371  if (partition_bound_accepts_nulls(boundinfo))
1372  part_index = boundinfo->null_index;
1373  }
1374  else
1375  {
1376  bool equal = false;
1377 
1378  bound_offset = partition_list_bsearch(key->partsupfunc,
1379  key->partcollation,
1380  boundinfo,
1381  values[0], &equal);
1382  if (bound_offset >= 0 && equal)
1383  part_index = boundinfo->indexes[bound_offset];
1384  }
1385  break;
1386 
1388  {
1389  bool equal = false,
1390  range_partkey_has_null = false;
1391  int i;
1392 
1393  /*
1394  * No range includes NULL, so this will be accepted by the
1395  * default partition if there is one, and otherwise rejected.
1396  */
1397  for (i = 0; i < key->partnatts; i++)
1398  {
1399  if (isnull[i])
1400  {
1401  range_partkey_has_null = true;
1402  break;
1403  }
1404  }
1405 
1406  if (!range_partkey_has_null)
1407  {
1408  bound_offset = partition_range_datum_bsearch(key->partsupfunc,
1409  key->partcollation,
1410  boundinfo,
1411  key->partnatts,
1412  values,
1413  &equal);
1414 
1415  /*
1416  * The bound at bound_offset is less than or equal to the
1417  * tuple value, so the bound at offset+1 is the upper
1418  * bound of the partition we're looking for, if there
1419  * actually exists one.
1420  */
1421  part_index = boundinfo->indexes[bound_offset + 1];
1422  }
1423  }
1424  break;
1425 
1426  default:
1427  elog(ERROR, "unexpected partition strategy: %d",
1428  (int) key->strategy);
1429  }
1430 
1431  /*
1432  * part_index < 0 means we failed to find a partition of this parent. Use
1433  * the default partition, if there is one.
1434  */
1435  if (part_index < 0)
1436  part_index = boundinfo->default_index;
1437 
1438  return part_index;
1439 }
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:3564
#define PARTITION_STRATEGY_LIST
Definition: parsenodes.h:835
#define PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:836
#define PARTITION_STRATEGY_HASH
Definition: parsenodes.h:834
uint64 compute_partition_hash_value(int partnatts, FmgrInfo *partsupfunc, Oid *partcollation, Datum *values, bool *isnull)
Definition: partbounds.c:4743
int partition_range_datum_bsearch(FmgrInfo *partsupfunc, Oid *partcollation, PartitionBoundInfo boundinfo, int nvalues, Datum *values, bool *is_equal)
Definition: partbounds.c:3711
int partition_list_bsearch(FmgrInfo *partsupfunc, Oid *partcollation, PartitionBoundInfo boundinfo, Datum value, bool *is_equal)
Definition: partbounds.c:3623
#define partition_bound_accepts_nulls(bi)
Definition: partbounds.h:98

References PartitionDescData::boundinfo, compute_partition_hash_value(), PartitionBoundInfoData::default_index, elog, equal(), ERROR, i, PartitionBoundInfoData::indexes, PartitionDispatchData::key, sort-test::key, PartitionBoundInfoData::nindexes, PartitionBoundInfoData::null_index, PartitionDispatchData::partdesc, partition_bound_accepts_nulls, partition_list_bsearch(), partition_range_datum_bsearch(), PARTITION_STRATEGY_HASH, PARTITION_STRATEGY_LIST, PARTITION_STRATEGY_RANGE, and values.

Referenced by ExecFindPartition().

◆ InitPartitionPruneContext()

static void InitPartitionPruneContext ( PartitionPruneContext context,
List pruning_steps,
PartitionDesc  partdesc,
PartitionKey  partkey,
PlanState planstate,
ExprContext econtext 
)
static

Definition at line 1921 of file execPartition.c.

1927 {
1928  int n_steps;
1929  int partnatts;
1930  ListCell *lc;
1931 
1932  n_steps = list_length(pruning_steps);
1933 
1934  context->strategy = partkey->strategy;
1935  context->partnatts = partnatts = partkey->partnatts;
1936  context->nparts = partdesc->nparts;
1937  context->boundinfo = partdesc->boundinfo;
1938  context->partcollation = partkey->partcollation;
1939  context->partsupfunc = partkey->partsupfunc;
1940 
1941  /* We'll look up type-specific support functions as needed */
1942  context->stepcmpfuncs = (FmgrInfo *)
1943  palloc0(sizeof(FmgrInfo) * n_steps * partnatts);
1944 
1945  context->ppccontext = CurrentMemoryContext;
1946  context->planstate = planstate;
1947  context->exprcontext = econtext;
1948 
1949  /* Initialize expression state for each expression we need */
1950  context->exprstates = (ExprState **)
1951  palloc0(sizeof(ExprState *) * n_steps * partnatts);
1952  foreach(lc, pruning_steps)
1953  {
1955  ListCell *lc2;
1956  int keyno;
1957 
1958  /* not needed for other step kinds */
1959  if (!IsA(step, PartitionPruneStepOp))
1960  continue;
1961 
1962  Assert(list_length(step->exprs) <= partnatts);
1963 
1964  keyno = 0;
1965  foreach(lc2, step->exprs)
1966  {
1967  Expr *expr = (Expr *) lfirst(lc2);
1968 
1969  /* not needed for Consts */
1970  if (!IsA(expr, Const))
1971  {
1972  int stateidx = PruneCxtStateIdx(partnatts,
1973  step->step.step_id,
1974  keyno);
1975 
1976  /*
1977  * When planstate is NULL, pruning_steps is known not to
1978  * contain any expressions that depend on the parent plan.
1979  * Information of any available EXTERN parameters must be
1980  * passed explicitly in that case, which the caller must have
1981  * made available via econtext.
1982  */
1983  if (planstate == NULL)
1984  context->exprstates[stateidx] =
1986  econtext->ecxt_param_list_info);
1987  else
1988  context->exprstates[stateidx] =
1989  ExecInitExpr(expr, context->planstate);
1990  }
1991  keyno++;
1992  }
1993  }
1994 }
ExprState * ExecInitExprWithParams(Expr *node, ParamListInfo ext_params)
Definition: execExpr.c:172
ExprState * ExecInitExpr(Expr *node, PlanState *parent)
Definition: execExpr.c:160
#define IsA(nodeptr, _type_)
Definition: nodes.h:624
#define PruneCxtStateIdx(partnatts, step_id, keyno)
Definition: partprune.h:70
ParamListInfo ecxt_param_list_info
Definition: execnodes.h:244
Definition: fmgr.h:57
Oid * partcollation
Definition: partcache.h:38
FmgrInfo * partsupfunc
Definition: partcache.h:35
FmgrInfo * partsupfunc
Definition: partprune.h:56
MemoryContext ppccontext
Definition: partprune.h:58
PartitionBoundInfo boundinfo
Definition: partprune.h:54
PlanState * planstate
Definition: partprune.h:59
FmgrInfo * stepcmpfuncs
Definition: partprune.h:57
ExprState ** exprstates
Definition: partprune.h:61
PartitionPruneStep step
Definition: plannodes.h:1287

References Assert(), PartitionDescData::boundinfo, PartitionPruneContext::boundinfo, CurrentMemoryContext, ExprContext::ecxt_param_list_info, ExecInitExpr(), ExecInitExprWithParams(), PartitionPruneContext::exprcontext, PartitionPruneStepOp::exprs, PartitionPruneContext::exprstates, IsA, lfirst, list_length(), PartitionDescData::nparts, PartitionPruneContext::nparts, palloc0(), PartitionPruneContext::partcollation, PartitionKeyData::partcollation, PartitionPruneContext::partnatts, PartitionKeyData::partnatts, PartitionPruneContext::partsupfunc, PartitionKeyData::partsupfunc, PartitionPruneContext::planstate, PartitionPruneContext::ppccontext, PruneCxtStateIdx, PartitionPruneStepOp::step, PartitionPruneStep::step_id, PartitionPruneContext::stepcmpfuncs, PartitionPruneContext::strategy, and PartitionKeyData::strategy.

Referenced by CreatePartitionPruneState().

◆ PartitionPruneFixSubPlanMap()

static void PartitionPruneFixSubPlanMap ( PartitionPruneState prunestate,
Bitmapset initially_valid_subplans,
int  n_total_subplans 
)
static

Definition at line 2011 of file execPartition.c.

2014 {
2015  int *new_subplan_indexes;
2016  Bitmapset *new_other_subplans;
2017  int i;
2018  int newidx;
2019 
2020  /*
2021  * First we must build a temporary array which maps old subplan indexes to
2022  * new ones. For convenience of initialization, we use 1-based indexes in
2023  * this array and leave pruned items as 0.
2024  */
2025  new_subplan_indexes = (int *) palloc0(sizeof(int) * n_total_subplans);
2026  newidx = 1;
2027  i = -1;
2028  while ((i = bms_next_member(initially_valid_subplans, i)) >= 0)
2029  {
2030  Assert(i < n_total_subplans);
2031  new_subplan_indexes[i] = newidx++;
2032  }
2033 
2034  /*
2035  * Now we can update each PartitionedRelPruneInfo's subplan_map with new
2036  * subplan indexes. We must also recompute its present_parts bitmap.
2037  */
2038  for (i = 0; i < prunestate->num_partprunedata; i++)
2039  {
2040  PartitionPruningData *prunedata = prunestate->partprunedata[i];
2041  int j;
2042 
2043  /*
2044  * Within each hierarchy, we perform this loop in back-to-front order
2045  * so that we determine present_parts for the lowest-level partitioned
2046  * tables first. This way we can tell whether a sub-partitioned
2047  * table's partitions were entirely pruned so we can exclude it from
2048  * the current level's present_parts.
2049  */
2050  for (j = prunedata->num_partrelprunedata - 1; j >= 0; j--)
2051  {
2052  PartitionedRelPruningData *pprune = &prunedata->partrelprunedata[j];
2053  int nparts = pprune->nparts;
2054  int k;
2055 
2056  /* We just rebuild present_parts from scratch */
2057  bms_free(pprune->present_parts);
2058  pprune->present_parts = NULL;
2059 
2060  for (k = 0; k < nparts; k++)
2061  {
2062  int oldidx = pprune->subplan_map[k];
2063  int subidx;
2064 
2065  /*
2066  * If this partition existed as a subplan then change the old
2067  * subplan index to the new subplan index. The new index may
2068  * become -1 if the partition was pruned above, or it may just
2069  * come earlier in the subplan list due to some subplans being
2070  * removed earlier in the list. If it's a subpartition, add
2071  * it to present_parts unless it's entirely pruned.
2072  */
2073  if (oldidx >= 0)
2074  {
2075  Assert(oldidx < n_total_subplans);
2076  pprune->subplan_map[k] = new_subplan_indexes[oldidx] - 1;
2077 
2078  if (new_subplan_indexes[oldidx] > 0)
2079  pprune->present_parts =
2080  bms_add_member(pprune->present_parts, k);
2081  }
2082  else if ((subidx = pprune->subpart_map[k]) >= 0)
2083  {
2084  PartitionedRelPruningData *subprune;
2085 
2086  subprune = &prunedata->partrelprunedata[subidx];
2087 
2088  if (!bms_is_empty(subprune->present_parts))
2089  pprune->present_parts =
2090  bms_add_member(pprune->present_parts, k);
2091  }
2092  }
2093  }
2094  }
2095 
2096  /*
2097  * We must also recompute the other_subplans set, since indexes in it may
2098  * change.
2099  */
2100  new_other_subplans = NULL;
2101  i = -1;
2102  while ((i = bms_next_member(prunestate->other_subplans, i)) >= 0)
2103  new_other_subplans = bms_add_member(new_other_subplans,
2104  new_subplan_indexes[i] - 1);
2105 
2106  bms_free(prunestate->other_subplans);
2107  prunestate->other_subplans = new_other_subplans;
2108 
2109  pfree(new_subplan_indexes);
2110 }
void bms_free(Bitmapset *a)
Definition: bitmapset.c:208
bool bms_is_empty(const Bitmapset *a)
Definition: bitmapset.c:703
void pfree(void *pointer)
Definition: mcxt.c:1175

References Assert(), bms_add_member(), bms_free(), bms_is_empty(), bms_next_member(), i, j, PartitionedRelPruningData::nparts, PartitionPruneState::num_partprunedata, PartitionPruningData::num_partrelprunedata, PartitionPruneState::other_subplans, palloc0(), PartitionPruneState::partprunedata, PartitionPruningData::partrelprunedata, pfree(), PartitionedRelPruningData::present_parts, PartitionedRelPruningData::subpart_map, and PartitionedRelPruningData::subplan_map.

Referenced by ExecInitPartitionPruning().