PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
nodeModifyTable.h File Reference
#include "nodes/execnodes.h"
Include dependency graph for nodeModifyTable.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

ModifyTableStateExecInitModifyTable (ModifyTable *node, EState *estate, int eflags)
 
TupleTableSlotExecModifyTable (ModifyTableState *node)
 
void ExecEndModifyTable (ModifyTableState *node)
 
void ExecReScanModifyTable (ModifyTableState *node)
 

Function Documentation

void ExecEndModifyTable ( ModifyTableState node)

Definition at line 2129 of file nodeModifyTable.c.

References FdwRoutine::EndForeignModify, EvalPlanQualEnd(), ExecClearTuple(), ExecCloseIndices(), ExecDropSingleTupleTableSlot(), ExecEndNode(), ExecFreeExprContext(), heap_close, i, ModifyTableState::mt_epqstate, ModifyTableState::mt_nplans, ModifyTableState::mt_num_dispatch, ModifyTableState::mt_num_partitions, ModifyTableState::mt_partition_dispatch_info, ModifyTableState::mt_partition_tuple_slot, ModifyTableState::mt_partitions, ModifyTableState::mt_plans, NoLock, NULL, ModifyTableState::ps, PlanState::ps_ResultTupleSlot, PartitionDispatchData::reldesc, ModifyTableState::resultRelInfo, ResultRelInfo::ri_FdwRoutine, ResultRelInfo::ri_RelationDesc, ResultRelInfo::ri_usesFdwDirectModify, PlanState::state, and PartitionDispatchData::tupslot.

Referenced by ExecEndNode().

2130 {
2131  int i;
2132 
2133  /*
2134  * Allow any FDWs to shut down
2135  */
2136  for (i = 0; i < node->mt_nplans; i++)
2137  {
2138  ResultRelInfo *resultRelInfo = node->resultRelInfo + i;
2139 
2140  if (!resultRelInfo->ri_usesFdwDirectModify &&
2141  resultRelInfo->ri_FdwRoutine != NULL &&
2142  resultRelInfo->ri_FdwRoutine->EndForeignModify != NULL)
2143  resultRelInfo->ri_FdwRoutine->EndForeignModify(node->ps.state,
2144  resultRelInfo);
2145  }
2146 
2147  /*
2148  * Close all the partitioned tables, leaf partitions, and their indices
2149  *
2150  * Remember node->mt_partition_dispatch_info[0] corresponds to the root
2151  * partitioned table, which we must not try to close, because it is the
2152  * main target table of the query that will be closed by ExecEndPlan().
2153  * Also, tupslot is NULL for the root partitioned table.
2154  */
2155  for (i = 1; i < node->mt_num_dispatch; i++)
2156  {
2158 
2159  heap_close(pd->reldesc, NoLock);
2161  }
2162  for (i = 0; i < node->mt_num_partitions; i++)
2163  {
2164  ResultRelInfo *resultRelInfo = node->mt_partitions + i;
2165 
2166  ExecCloseIndices(resultRelInfo);
2167  heap_close(resultRelInfo->ri_RelationDesc, NoLock);
2168  }
2169 
2170  /* Release the standalone partition tuple descriptor, if any */
2171  if (node->mt_partition_tuple_slot)
2173 
2174  /*
2175  * Free the exprcontext
2176  */
2177  ExecFreeExprContext(&node->ps);
2178 
2179  /*
2180  * clean out the tuple table
2181  */
2183 
2184  /*
2185  * Terminate EPQ execution if active
2186  */
2187  EvalPlanQualEnd(&node->mt_epqstate);
2188 
2189  /*
2190  * shut down subplans
2191  */
2192  for (i = 0; i < node->mt_nplans; i++)
2193  ExecEndNode(node->mt_plans[i]);
2194 }
Relation ri_RelationDesc
Definition: execnodes.h:373
ResultRelInfo * mt_partitions
Definition: execnodes.h:931
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:644
ResultRelInfo * resultRelInfo
Definition: execnodes.h:913
TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: execTuples.c:439
#define heap_close(r, l)
Definition: heapam.h:97
EState * state
Definition: execnodes.h:802
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:511
void EvalPlanQualEnd(EPQState *epqstate)
Definition: execMain.c:3066
TupleTableSlot * ps_ResultTupleSlot
Definition: execnodes.h:829
PlanState ps
Definition: execnodes.h:906
bool ri_usesFdwDirectModify
Definition: execnodes.h:383
#define NoLock
Definition: lockdefs.h:34
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:216
EPQState mt_epqstate
Definition: execnodes.h:915
struct FdwRoutine * ri_FdwRoutine
Definition: execnodes.h:381
EndForeignModify_function EndForeignModify
Definition: fdwapi.h:200
PlanState ** mt_plans
Definition: execnodes.h:910
TupleTableSlot * tupslot
Definition: partition.h:66
TupleTableSlot * mt_partition_tuple_slot
Definition: execnodes.h:934
#define NULL
Definition: c.h:229
int i
struct PartitionDispatchData ** mt_partition_dispatch_info
Definition: execnodes.h:925
void ExecCloseIndices(ResultRelInfo *resultRelInfo)
Definition: execIndexing.c:224
ModifyTableState* ExecInitModifyTable ( ModifyTable node,
EState estate,
int  eflags 
)

Definition at line 1627 of file nodeModifyTable.c.

References ModifyTable::arbiterIndexes, Assert, AttributeNumberIsValid, FdwRoutine::BeginForeignModify, bms_is_member(), ModifyTable::canSetTag, ModifyTableState::canSetTag, castNode, CheckValidResultRel(), CMD_DELETE, CMD_INSERT, CMD_UPDATE, elog, ModifyTable::epqParam, ERROR, EState::es_auxmodifytables, EState::es_range_table, EState::es_result_relation_info, EState::es_result_relations, EState::es_trig_tuple_slot, EvalPlanQualInit(), EvalPlanQualSetPlan(), ModifyTable::exclRelTlist, EXEC_FLAG_BACKWARD, EXEC_FLAG_MARK, ExecAssignExprContext(), ExecAssignResultType(), ExecBuildAuxRowMark(), ExecBuildProjectionInfo(), ExecCheckPlanOutput(), ExecFindJunkAttribute(), ExecFindRowMark(), ExecInitExtraTupleSlot(), ExecInitJunkFilter(), ExecInitNode(), ExecInitQual(), ExecInitResultTupleSlot(), ExecOpenIndices(), ExecSetSlotDescriptor(), ExecSetupPartitionTupleRouting(), ExecTypeFromTL(), ModifyTable::fdwDirectModifyPlans, ModifyTable::fdwPrivLists, ModifyTableState::fireBSTriggers, getrelid, heap_close, heap_open(), i, PlanRowMark::isParent, JunkFilter::jf_junkAttNo, lappend(), lcons(), lfirst, linitial, linitial_int, list_length(), list_nth(), makeNode, map_partition_varattnos(), ModifyTableState::mt_arbiterindexes, ModifyTableState::mt_arowmarks, ModifyTableState::mt_conflproj, ModifyTableState::mt_done, ModifyTableState::mt_epqstate, ModifyTableState::mt_excludedtlist, ModifyTableState::mt_existing, ModifyTableState::mt_nplans, ModifyTableState::mt_num_dispatch, ModifyTableState::mt_num_partitions, ModifyTableState::mt_onconflict, ModifyTableState::mt_partition_dispatch_info, ModifyTableState::mt_partition_tupconv_maps, ModifyTableState::mt_partition_tuple_slot, ModifyTableState::mt_partitions, ModifyTableState::mt_plans, ModifyTableState::mt_whichplan, NIL, NoLock, ModifyTable::nominalRelation, NULL, ONCONFLICT_NONE, ONCONFLICT_UPDATE, ModifyTable::onConflictAction, ModifyTable::onConflictSet, ModifyTable::onConflictWhere, ModifyTable::operation, ModifyTableState::operation, palloc0(), ModifyTable::partitioned_rels, PlanState::plan, ModifyTable::plans, ModifyTableState::ps, PlanState::ps_ExprContext, PlanState::ps_ResultTupleSlot, WithCheckOption::qual, RelationData::rd_att, RelationData::rd_rel, RELKIND_FOREIGN_TABLE, RELKIND_MATVIEW, RELKIND_PARTITIONED_TABLE, RELKIND_RELATION, TargetEntry::resjunk, ModifyTable::resultRelIndex, ModifyTableState::resultRelInfo, ModifyTable::returningLists, ResultRelInfo::ri_FdwRoutine, ResultRelInfo::ri_IndexRelationDescs, ResultRelInfo::ri_junkFilter, ResultRelInfo::ri_onConflictSetProj, ResultRelInfo::ri_onConflictSetWhere, ResultRelInfo::ri_projectReturning, ResultRelInfo::ri_RelationDesc, ResultRelInfo::ri_usesFdwDirectModify, ResultRelInfo::ri_WithCheckOptionExprs, ResultRelInfo::ri_WithCheckOptions, ModifyTable::rowMarks, PlanRowMark::rti, PlanState::state, Plan::targetlist, tupleDesc::tdhasoid, and ModifyTable::withCheckOptionLists.

Referenced by ExecInitNode().

1628 {
1629  ModifyTableState *mtstate;
1630  CmdType operation = node->operation;
1631  int nplans = list_length(node->plans);
1632  ResultRelInfo *saved_resultRelInfo;
1633  ResultRelInfo *resultRelInfo;
1634  TupleDesc tupDesc;
1635  Plan *subplan;
1636  ListCell *l;
1637  int i;
1638  Relation rel;
1639 
1640  /* check for unsupported flags */
1641  Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
1642 
1643  /*
1644  * create state structure
1645  */
1646  mtstate = makeNode(ModifyTableState);
1647  mtstate->ps.plan = (Plan *) node;
1648  mtstate->ps.state = estate;
1649 
1650  mtstate->operation = operation;
1651  mtstate->canSetTag = node->canSetTag;
1652  mtstate->mt_done = false;
1653 
1654  mtstate->mt_plans = (PlanState **) palloc0(sizeof(PlanState *) * nplans);
1655  mtstate->resultRelInfo = estate->es_result_relations + node->resultRelIndex;
1656  mtstate->mt_arowmarks = (List **) palloc0(sizeof(List *) * nplans);
1657  mtstate->mt_nplans = nplans;
1658  mtstate->mt_onconflict = node->onConflictAction;
1659  mtstate->mt_arbiterindexes = node->arbiterIndexes;
1660 
1661  /* set up epqstate with dummy subplan data for the moment */
1662  EvalPlanQualInit(&mtstate->mt_epqstate, estate, NULL, NIL, node->epqParam);
1663  mtstate->fireBSTriggers = true;
1664 
1665  /*
1666  * call ExecInitNode on each of the plans to be executed and save the
1667  * results into the array "mt_plans". This is also a convenient place to
1668  * verify that the proposed target relations are valid and open their
1669  * indexes for insertion of new index entries. Note we *must* set
1670  * estate->es_result_relation_info correctly while we initialize each
1671  * sub-plan; ExecContextForcesOids depends on that!
1672  */
1673  saved_resultRelInfo = estate->es_result_relation_info;
1674 
1675  resultRelInfo = mtstate->resultRelInfo;
1676  i = 0;
1677  foreach(l, node->plans)
1678  {
1679  subplan = (Plan *) lfirst(l);
1680 
1681  /* Initialize the usesFdwDirectModify flag */
1682  resultRelInfo->ri_usesFdwDirectModify = bms_is_member(i,
1683  node->fdwDirectModifyPlans);
1684 
1685  /*
1686  * Verify result relation is a valid target for the current operation
1687  */
1688  CheckValidResultRel(resultRelInfo->ri_RelationDesc, operation);
1689 
1690  /*
1691  * If there are indices on the result relation, open them and save
1692  * descriptors in the result relation info, so that we can add new
1693  * index entries for the tuples we add/update. We need not do this
1694  * for a DELETE, however, since deletion doesn't affect indexes. Also,
1695  * inside an EvalPlanQual operation, the indexes might be open
1696  * already, since we share the resultrel state with the original
1697  * query.
1698  */
1699  if (resultRelInfo->ri_RelationDesc->rd_rel->relhasindex &&
1700  operation != CMD_DELETE &&
1701  resultRelInfo->ri_IndexRelationDescs == NULL)
1702  ExecOpenIndices(resultRelInfo, mtstate->mt_onconflict != ONCONFLICT_NONE);
1703 
1704  /* Now init the plan for this result rel */
1705  estate->es_result_relation_info = resultRelInfo;
1706  mtstate->mt_plans[i] = ExecInitNode(subplan, estate, eflags);
1707 
1708  /* Also let FDWs init themselves for foreign-table result rels */
1709  if (!resultRelInfo->ri_usesFdwDirectModify &&
1710  resultRelInfo->ri_FdwRoutine != NULL &&
1711  resultRelInfo->ri_FdwRoutine->BeginForeignModify != NULL)
1712  {
1713  List *fdw_private = (List *) list_nth(node->fdwPrivLists, i);
1714 
1715  resultRelInfo->ri_FdwRoutine->BeginForeignModify(mtstate,
1716  resultRelInfo,
1717  fdw_private,
1718  i,
1719  eflags);
1720  }
1721 
1722  resultRelInfo++;
1723  i++;
1724  }
1725 
1726  estate->es_result_relation_info = saved_resultRelInfo;
1727 
1728  /* The root table RT index is at the head of the partitioned_rels list */
1729  if (node->partitioned_rels)
1730  {
1731  Index root_rti;
1732  Oid root_oid;
1733 
1734  root_rti = linitial_int(node->partitioned_rels);
1735  root_oid = getrelid(root_rti, estate->es_range_table);
1736  rel = heap_open(root_oid, NoLock); /* locked by InitPlan */
1737  }
1738  else
1739  rel = mtstate->resultRelInfo->ri_RelationDesc;
1740 
1741  /* Build state for INSERT tuple routing */
1742  if (operation == CMD_INSERT &&
1743  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1744  {
1745  PartitionDispatch *partition_dispatch_info;
1746  ResultRelInfo *partitions;
1747  TupleConversionMap **partition_tupconv_maps;
1748  TupleTableSlot *partition_tuple_slot;
1749  int num_parted,
1750  num_partitions;
1751 
1753  &partition_dispatch_info,
1754  &partitions,
1755  &partition_tupconv_maps,
1756  &partition_tuple_slot,
1757  &num_parted, &num_partitions);
1758  mtstate->mt_partition_dispatch_info = partition_dispatch_info;
1759  mtstate->mt_num_dispatch = num_parted;
1760  mtstate->mt_partitions = partitions;
1761  mtstate->mt_num_partitions = num_partitions;
1762  mtstate->mt_partition_tupconv_maps = partition_tupconv_maps;
1763  mtstate->mt_partition_tuple_slot = partition_tuple_slot;
1764  }
1765 
1766  /*
1767  * Initialize any WITH CHECK OPTION constraints if needed.
1768  */
1769  resultRelInfo = mtstate->resultRelInfo;
1770  i = 0;
1771  foreach(l, node->withCheckOptionLists)
1772  {
1773  List *wcoList = (List *) lfirst(l);
1774  List *wcoExprs = NIL;
1775  ListCell *ll;
1776 
1777  foreach(ll, wcoList)
1778  {
1779  WithCheckOption *wco = (WithCheckOption *) lfirst(ll);
1780  ExprState *wcoExpr = ExecInitQual((List *) wco->qual,
1781  mtstate->mt_plans[i]);
1782 
1783  wcoExprs = lappend(wcoExprs, wcoExpr);
1784  }
1785 
1786  resultRelInfo->ri_WithCheckOptions = wcoList;
1787  resultRelInfo->ri_WithCheckOptionExprs = wcoExprs;
1788  resultRelInfo++;
1789  i++;
1790  }
1791 
1792  /*
1793  * Build WITH CHECK OPTION constraints for each leaf partition rel.
1794  * Note that we didn't build the withCheckOptionList for each partition
1795  * within the planner, but simple translation of the varattnos for each
1796  * partition will suffice. This only occurs for the INSERT case;
1797  * UPDATE/DELETE cases are handled above.
1798  */
1799  if (node->withCheckOptionLists != NIL && mtstate->mt_num_partitions > 0)
1800  {
1801  List *wcoList;
1802 
1803  Assert(operation == CMD_INSERT);
1804  resultRelInfo = mtstate->mt_partitions;
1805  wcoList = linitial(node->withCheckOptionLists);
1806  for (i = 0; i < mtstate->mt_num_partitions; i++)
1807  {
1808  Relation partrel = resultRelInfo->ri_RelationDesc;
1809  List *mapped_wcoList;
1810  List *wcoExprs = NIL;
1811  ListCell *ll;
1812 
1813  /* varno = node->nominalRelation */
1814  mapped_wcoList = map_partition_varattnos(wcoList,
1815  node->nominalRelation,
1816  partrel, rel);
1817  foreach(ll, mapped_wcoList)
1818  {
1819  WithCheckOption *wco = (WithCheckOption *) lfirst(ll);
1820  ExprState *wcoExpr = ExecInitQual((List *) wco->qual,
1821  mtstate->mt_plans[i]);
1822 
1823  wcoExprs = lappend(wcoExprs, wcoExpr);
1824  }
1825 
1826  resultRelInfo->ri_WithCheckOptions = mapped_wcoList;
1827  resultRelInfo->ri_WithCheckOptionExprs = wcoExprs;
1828  resultRelInfo++;
1829  }
1830  }
1831 
1832  /*
1833  * Initialize RETURNING projections if needed.
1834  */
1835  if (node->returningLists)
1836  {
1837  TupleTableSlot *slot;
1838  ExprContext *econtext;
1839  List *returningList;
1840 
1841  /*
1842  * Initialize result tuple slot and assign its rowtype using the first
1843  * RETURNING list. We assume the rest will look the same.
1844  */
1845  tupDesc = ExecTypeFromTL((List *) linitial(node->returningLists),
1846  false);
1847 
1848  /* Set up a slot for the output of the RETURNING projection(s) */
1849  ExecInitResultTupleSlot(estate, &mtstate->ps);
1850  ExecAssignResultType(&mtstate->ps, tupDesc);
1851  slot = mtstate->ps.ps_ResultTupleSlot;
1852 
1853  /* Need an econtext too */
1854  if (mtstate->ps.ps_ExprContext == NULL)
1855  ExecAssignExprContext(estate, &mtstate->ps);
1856  econtext = mtstate->ps.ps_ExprContext;
1857 
1858  /*
1859  * Build a projection for each result rel.
1860  */
1861  resultRelInfo = mtstate->resultRelInfo;
1862  foreach(l, node->returningLists)
1863  {
1864  List *rlist = (List *) lfirst(l);
1865 
1866  resultRelInfo->ri_projectReturning =
1867  ExecBuildProjectionInfo(rlist, econtext, slot, &mtstate->ps,
1868  resultRelInfo->ri_RelationDesc->rd_att);
1869  resultRelInfo++;
1870  }
1871 
1872  /*
1873  * Build a projection for each leaf partition rel. Note that we
1874  * didn't build the returningList for each partition within the
1875  * planner, but simple translation of the varattnos for each partition
1876  * will suffice. This only occurs for the INSERT case; UPDATE/DELETE
1877  * are handled above.
1878  */
1879  resultRelInfo = mtstate->mt_partitions;
1880  returningList = linitial(node->returningLists);
1881  for (i = 0; i < mtstate->mt_num_partitions; i++)
1882  {
1883  Relation partrel = resultRelInfo->ri_RelationDesc;
1884  List *rlist;
1885 
1886  /* varno = node->nominalRelation */
1887  rlist = map_partition_varattnos(returningList,
1888  node->nominalRelation,
1889  partrel, rel);
1890  resultRelInfo->ri_projectReturning =
1891  ExecBuildProjectionInfo(rlist, econtext, slot, &mtstate->ps,
1892  resultRelInfo->ri_RelationDesc->rd_att);
1893  resultRelInfo++;
1894  }
1895  }
1896  else
1897  {
1898  /*
1899  * We still must construct a dummy result tuple type, because InitPlan
1900  * expects one (maybe should change that?).
1901  */
1902  tupDesc = ExecTypeFromTL(NIL, false);
1903  ExecInitResultTupleSlot(estate, &mtstate->ps);
1904  ExecAssignResultType(&mtstate->ps, tupDesc);
1905 
1906  mtstate->ps.ps_ExprContext = NULL;
1907  }
1908 
1909  /* Close the root partitioned rel if we opened it above. */
1910  if (rel != mtstate->resultRelInfo->ri_RelationDesc)
1911  heap_close(rel, NoLock);
1912 
1913  /*
1914  * If needed, Initialize target list, projection and qual for ON CONFLICT
1915  * DO UPDATE.
1916  */
1917  resultRelInfo = mtstate->resultRelInfo;
1918  if (node->onConflictAction == ONCONFLICT_UPDATE)
1919  {
1920  ExprContext *econtext;
1921  TupleDesc tupDesc;
1922 
1923  /* insert may only have one plan, inheritance is not expanded */
1924  Assert(nplans == 1);
1925 
1926  /* already exists if created by RETURNING processing above */
1927  if (mtstate->ps.ps_ExprContext == NULL)
1928  ExecAssignExprContext(estate, &mtstate->ps);
1929 
1930  econtext = mtstate->ps.ps_ExprContext;
1931 
1932  /* initialize slot for the existing tuple */
1933  mtstate->mt_existing = ExecInitExtraTupleSlot(mtstate->ps.state);
1935  resultRelInfo->ri_RelationDesc->rd_att);
1936 
1937  /* carried forward solely for the benefit of explain */
1938  mtstate->mt_excludedtlist = node->exclRelTlist;
1939 
1940  /* create target slot for UPDATE SET projection */
1941  tupDesc = ExecTypeFromTL((List *) node->onConflictSet,
1942  resultRelInfo->ri_RelationDesc->rd_rel->relhasoids);
1943  mtstate->mt_conflproj = ExecInitExtraTupleSlot(mtstate->ps.state);
1944  ExecSetSlotDescriptor(mtstate->mt_conflproj, tupDesc);
1945 
1946  /* build UPDATE SET projection state */
1947  resultRelInfo->ri_onConflictSetProj =
1948  ExecBuildProjectionInfo(node->onConflictSet, econtext,
1949  mtstate->mt_conflproj, &mtstate->ps,
1950  resultRelInfo->ri_RelationDesc->rd_att);
1951 
1952  /* build DO UPDATE WHERE clause expression */
1953  if (node->onConflictWhere)
1954  {
1955  ExprState *qualexpr;
1956 
1957  qualexpr = ExecInitQual((List *) node->onConflictWhere,
1958  &mtstate->ps);
1959 
1960  resultRelInfo->ri_onConflictSetWhere = qualexpr;
1961  }
1962  }
1963 
1964  /*
1965  * If we have any secondary relations in an UPDATE or DELETE, they need to
1966  * be treated like non-locked relations in SELECT FOR UPDATE, ie, the
1967  * EvalPlanQual mechanism needs to be told about them. Locate the
1968  * relevant ExecRowMarks.
1969  */
1970  foreach(l, node->rowMarks)
1971  {
1973  ExecRowMark *erm;
1974 
1975  /* ignore "parent" rowmarks; they are irrelevant at runtime */
1976  if (rc->isParent)
1977  continue;
1978 
1979  /* find ExecRowMark (same for all subplans) */
1980  erm = ExecFindRowMark(estate, rc->rti, false);
1981 
1982  /* build ExecAuxRowMark for each subplan */
1983  for (i = 0; i < nplans; i++)
1984  {
1985  ExecAuxRowMark *aerm;
1986 
1987  subplan = mtstate->mt_plans[i]->plan;
1988  aerm = ExecBuildAuxRowMark(erm, subplan->targetlist);
1989  mtstate->mt_arowmarks[i] = lappend(mtstate->mt_arowmarks[i], aerm);
1990  }
1991  }
1992 
1993  /* select first subplan */
1994  mtstate->mt_whichplan = 0;
1995  subplan = (Plan *) linitial(node->plans);
1996  EvalPlanQualSetPlan(&mtstate->mt_epqstate, subplan,
1997  mtstate->mt_arowmarks[0]);
1998 
1999  /*
2000  * Initialize the junk filter(s) if needed. INSERT queries need a filter
2001  * if there are any junk attrs in the tlist. UPDATE and DELETE always
2002  * need a filter, since there's always a junk 'ctid' or 'wholerow'
2003  * attribute present --- no need to look first.
2004  *
2005  * If there are multiple result relations, each one needs its own junk
2006  * filter. Note multiple rels are only possible for UPDATE/DELETE, so we
2007  * can't be fooled by some needing a filter and some not.
2008  *
2009  * This section of code is also a convenient place to verify that the
2010  * output of an INSERT or UPDATE matches the target table(s).
2011  */
2012  {
2013  bool junk_filter_needed = false;
2014 
2015  switch (operation)
2016  {
2017  case CMD_INSERT:
2018  foreach(l, subplan->targetlist)
2019  {
2020  TargetEntry *tle = (TargetEntry *) lfirst(l);
2021 
2022  if (tle->resjunk)
2023  {
2024  junk_filter_needed = true;
2025  break;
2026  }
2027  }
2028  break;
2029  case CMD_UPDATE:
2030  case CMD_DELETE:
2031  junk_filter_needed = true;
2032  break;
2033  default:
2034  elog(ERROR, "unknown operation");
2035  break;
2036  }
2037 
2038  if (junk_filter_needed)
2039  {
2040  resultRelInfo = mtstate->resultRelInfo;
2041  for (i = 0; i < nplans; i++)
2042  {
2043  JunkFilter *j;
2044 
2045  subplan = mtstate->mt_plans[i]->plan;
2046  if (operation == CMD_INSERT || operation == CMD_UPDATE)
2047  ExecCheckPlanOutput(resultRelInfo->ri_RelationDesc,
2048  subplan->targetlist);
2049 
2050  j = ExecInitJunkFilter(subplan->targetlist,
2051  resultRelInfo->ri_RelationDesc->rd_att->tdhasoid,
2052  ExecInitExtraTupleSlot(estate));
2053 
2054  if (operation == CMD_UPDATE || operation == CMD_DELETE)
2055  {
2056  /* For UPDATE/DELETE, find the appropriate junk attr now */
2057  char relkind;
2058 
2059  relkind = resultRelInfo->ri_RelationDesc->rd_rel->relkind;
2060  if (relkind == RELKIND_RELATION ||
2061  relkind == RELKIND_MATVIEW ||
2062  relkind == RELKIND_PARTITIONED_TABLE)
2063  {
2064  j->jf_junkAttNo = ExecFindJunkAttribute(j, "ctid");
2066  elog(ERROR, "could not find junk ctid column");
2067  }
2068  else if (relkind == RELKIND_FOREIGN_TABLE)
2069  {
2070  /*
2071  * When there is an AFTER trigger, there should be a
2072  * wholerow attribute.
2073  */
2074  j->jf_junkAttNo = ExecFindJunkAttribute(j, "wholerow");
2075  }
2076  else
2077  {
2078  j->jf_junkAttNo = ExecFindJunkAttribute(j, "wholerow");
2080  elog(ERROR, "could not find junk wholerow column");
2081  }
2082  }
2083 
2084  resultRelInfo->ri_junkFilter = j;
2085  resultRelInfo++;
2086  }
2087  }
2088  else
2089  {
2090  if (operation == CMD_INSERT)
2092  subplan->targetlist);
2093  }
2094  }
2095 
2096  /*
2097  * Set up a tuple table slot for use for trigger output tuples. In a plan
2098  * containing multiple ModifyTable nodes, all can share one such slot, so
2099  * we keep it in the estate.
2100  */
2101  if (estate->es_trig_tuple_slot == NULL)
2102  estate->es_trig_tuple_slot = ExecInitExtraTupleSlot(estate);
2103 
2104  /*
2105  * Lastly, if this is not the primary (canSetTag) ModifyTable node, add it
2106  * to estate->es_auxmodifytables so that it will be run to completion by
2107  * ExecPostprocessPlan. (It'd actually work fine to add the primary
2108  * ModifyTable node too, but there's no need.) Note the use of lcons not
2109  * lappend: we need later-initialized ModifyTable nodes to be shut down
2110  * before earlier ones. This ensures that we don't throw away RETURNING
2111  * rows that need to be seen by a later CTE subplan.
2112  */
2113  if (!mtstate->canSetTag)
2114  estate->es_auxmodifytables = lcons(mtstate,
2115  estate->es_auxmodifytables);
2116 
2117  return mtstate;
2118 }
AttrNumber jf_junkAttNo
Definition: execnodes.h:335
#define NIL
Definition: pg_list.h:69
JunkFilter * ri_junkFilter
Definition: execnodes.h:387
List * arbiterIndexes
Definition: plannodes.h:220
Relation ri_RelationDesc
Definition: execnodes.h:373
Bitmapset * fdwDirectModifyPlans
Definition: plannodes.h:216
ExprState * ri_onConflictSetWhere
Definition: execnodes.h:390
TupleTableSlot * ExecInitExtraTupleSlot(EState *estate)
Definition: execTuples.c:852
Index nominalRelation
Definition: plannodes.h:207
bool tdhasoid
Definition: tupdesc.h:79
ProjectionInfo * ri_onConflictSetProj
Definition: execnodes.h:389
ResultRelInfo * mt_partitions
Definition: execnodes.h:931
List * withCheckOptionLists
Definition: plannodes.h:213
#define castNode(_type_, nodeptr)
Definition: nodes.h:575
int resultRelIndex
Definition: plannodes.h:211
ResultRelInfo * resultRelInfo
Definition: execnodes.h:913
AttrNumber ExecFindJunkAttribute(JunkFilter *junkfilter, const char *attrName)
Definition: execJunk.c:209
ExprContext * ps_ExprContext
Definition: execnodes.h:830
TupleTableSlot * mt_conflproj
Definition: execnodes.h:923
#define RELKIND_MATVIEW
Definition: pg_class.h:165
bool canSetTag
Definition: plannodes.h:206
CmdType operation
Definition: execnodes.h:907
void EvalPlanQualSetPlan(EPQState *epqstate, Plan *subplan, List *auxrowmarks)
Definition: execMain.c:2674
#define heap_close(r, l)
Definition: heapam.h:97
EState * state
Definition: execnodes.h:802
List * es_range_table
Definition: execnodes.h:410
Form_pg_class rd_rel
Definition: rel.h:114
unsigned int Oid
Definition: postgres_ext.h:31
List * plans
Definition: plannodes.h:212
void ExecAssignResultType(PlanState *planstate, TupleDesc tupDesc)
Definition: execUtils.c:423
ExprState * ExecInitQual(List *qual, PlanState *parent)
Definition: execExpr.c:160
List * onConflictSet
Definition: plannodes.h:221
void ExecOpenIndices(ResultRelInfo *resultRelInfo, bool speculative)
Definition: execIndexing.c:149
TupleTableSlot * mt_existing
Definition: execnodes.h:920
List * ri_WithCheckOptionExprs
Definition: execnodes.h:385
#define linitial_int(l)
Definition: pg_list.h:111
OnConflictAction mt_onconflict
Definition: execnodes.h:917
TupleTableSlot * ps_ResultTupleSlot
Definition: execnodes.h:829
List * rowMarks
Definition: plannodes.h:217
void ExecSetupPartitionTupleRouting(Relation rel, PartitionDispatch **pd, ResultRelInfo **partitions, TupleConversionMap ***tup_conv_maps, TupleTableSlot **partition_tuple_slot, int *num_parted, int *num_partitions)
Definition: execMain.c:3135
bool resjunk
Definition: primnodes.h:1359
#define linitial(l)
Definition: pg_list.h:110
#define ERROR
Definition: elog.h:43
PlanState ps
Definition: execnodes.h:906
void ExecInitResultTupleSlot(EState *estate, PlanState *planstate)
Definition: execTuples.c:832
bool ri_usesFdwDirectModify
Definition: execnodes.h:383
#define EXEC_FLAG_BACKWARD
Definition: executor.h:60
void * list_nth(const List *list, int n)
Definition: list.c:410
#define NoLock
Definition: lockdefs.h:34
ResultRelInfo * es_result_relations
Definition: execnodes.h:420
JunkFilter * ExecInitJunkFilter(List *targetList, bool hasoid, TupleTableSlot *slot)
Definition: execJunk.c:61
List * fdwPrivLists
Definition: plannodes.h:215
EPQState mt_epqstate
Definition: execnodes.h:915
ProjectionInfo * ri_projectReturning
Definition: execnodes.h:388
void CheckValidResultRel(Relation resultRel, CmdType operation)
Definition: execMain.c:1055
struct FdwRoutine * ri_FdwRoutine
Definition: execnodes.h:381
#define RELKIND_FOREIGN_TABLE
Definition: pg_class.h:167
List * partitioned_rels
Definition: plannodes.h:209
TupleTableSlot * es_trig_tuple_slot
Definition: execnodes.h:426
TupleDesc ExecTypeFromTL(List *targetList, bool hasoid)
Definition: execTuples.c:888
List * lappend(List *list, void *datum)
Definition: list.c:128
PlanState ** mt_plans
Definition: execnodes.h:910
#define AttributeNumberIsValid(attributeNumber)
Definition: attnum.h:34
#define RELKIND_PARTITIONED_TABLE
Definition: pg_class.h:168
void * palloc0(Size size)
Definition: mcxt.c:878
List * es_auxmodifytables
Definition: execnodes.h:452
void ExecSetSlotDescriptor(TupleTableSlot *slot, TupleDesc tupdesc)
Definition: execTuples.c:247
List * ri_WithCheckOptions
Definition: execnodes.h:384
TupleTableSlot * mt_partition_tuple_slot
Definition: execnodes.h:934
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1287
unsigned int Index
Definition: c.h:365
TupleDesc rd_att
Definition: rel.h:115
void EvalPlanQualInit(EPQState *epqstate, EState *estate, Plan *subplan, List *auxrowmarks, int epqParam)
Definition: execMain.c:2655
Plan * plan
Definition: execnodes.h:800
Index rti
Definition: plannodes.h:978
List * lcons(void *datum, List *list)
Definition: list.c:259
#define makeNode(_type_)
Definition: nodes.h:554
static void ExecCheckPlanOutput(Relation resultRel, List *targetList)
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
#define lfirst(lc)
Definition: pg_list.h:106
#define EXEC_FLAG_MARK
Definition: executor.h:61
OnConflictAction onConflictAction
Definition: plannodes.h:219
void ExecAssignExprContext(EState *estate, PlanState *planstate)
Definition: execUtils.c:413
static int list_length(const List *l)
Definition: pg_list.h:89
List * targetlist
Definition: plannodes.h:132
List * mt_arbiterindexes
Definition: execnodes.h:918
List * mt_excludedtlist
Definition: execnodes.h:921
ProjectionInfo * ExecBuildProjectionInfo(List *targetList, ExprContext *econtext, TupleTableSlot *slot, PlanState *parent, TupleDesc inputDesc)
Definition: execExpr.c:301
#define getrelid(rangeindex, rangetable)
Definition: parsetree.h:41
CmdType operation
Definition: plannodes.h:205
int i
struct PartitionDispatchData ** mt_partition_dispatch_info
Definition: execnodes.h:925
List * returningLists
Definition: plannodes.h:214
bool isParent
Definition: plannodes.h:985
TupleConversionMap ** mt_partition_tupconv_maps
Definition: execnodes.h:932
#define elog
Definition: elog.h:219
BeginForeignModify_function BeginForeignModify
Definition: fdwapi.h:196
#define RELKIND_RELATION
Definition: pg_class.h:160
PlanState * ExecInitNode(Plan *node, EState *estate, int eflags)
Definition: execProcnode.c:139
Definition: pg_list.h:45
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:420
CmdType
Definition: nodes.h:639
RelationPtr ri_IndexRelationDescs
Definition: execnodes.h:375
ExecAuxRowMark * ExecBuildAuxRowMark(ExecRowMark *erm, List *targetlist)
Definition: execMain.c:2268
List * exclRelTlist
Definition: plannodes.h:224
List ** mt_arowmarks
Definition: execnodes.h:914
int epqParam
Definition: plannodes.h:218
List * map_partition_varattnos(List *expr, int target_varno, Relation partrel, Relation parent)
Definition: partition.c:932
Node * onConflictWhere
Definition: plannodes.h:222
ExecRowMark * ExecFindRowMark(EState *estate, Index rti, bool missing_ok)
Definition: execMain.c:2244
ResultRelInfo * es_result_relation_info
Definition: execnodes.h:422
TupleTableSlot* ExecModifyTable ( ModifyTableState node)

Definition at line 1387 of file nodeModifyTable.c.

References Assert, AttributeNumberIsValid, ModifyTableState::canSetTag, CMD_DELETE, CMD_INSERT, CMD_UPDATE, DatumGetHeapTupleHeader, DatumGetPointer, elog, ERROR, EState::es_epqTuple, EState::es_result_relation_info, EvalPlanQualSetPlan(), EvalPlanQualSetSlot, ExecDelete(), ExecFilterJunk(), ExecGetJunkAttribute(), ExecInsert(), ExecProcessReturning(), ExecProcNode(), ExecUpdate(), fireASTriggers(), ModifyTableState::fireBSTriggers, fireBSTriggers(), HeapTupleHeaderGetDatumLength, InvalidOid, ItemPointerSetInvalid, JunkFilter::jf_junkAttNo, ModifyTableState::mt_arbiterindexes, ModifyTableState::mt_arowmarks, ModifyTableState::mt_done, ModifyTableState::mt_epqstate, ModifyTableState::mt_nplans, ModifyTableState::mt_onconflict, ModifyTableState::mt_plans, ModifyTableState::mt_whichplan, NULL, ModifyTableState::operation, PlanState::plan, ModifyTableState::ps, RelationData::rd_rel, RelationGetRelid, RELKIND_FOREIGN_TABLE, RELKIND_MATVIEW, RELKIND_RELATION, RELKIND_VIEW, ResetPerTupleExprContext, ModifyTableState::resultRelInfo, ResultRelInfo::ri_junkFilter, ResultRelInfo::ri_projectReturning, ResultRelInfo::ri_RelationDesc, ResultRelInfo::ri_usesFdwDirectModify, PlanState::state, HeapTupleData::t_data, HeapTupleData::t_len, HeapTupleData::t_self, HeapTupleData::t_tableOid, and TupIsNull.

Referenced by ExecProcNode().

1388 {
1389  EState *estate = node->ps.state;
1390  CmdType operation = node->operation;
1391  ResultRelInfo *saved_resultRelInfo;
1392  ResultRelInfo *resultRelInfo;
1393  PlanState *subplanstate;
1394  JunkFilter *junkfilter;
1395  TupleTableSlot *slot;
1396  TupleTableSlot *planSlot;
1397  ItemPointer tupleid = NULL;
1398  ItemPointerData tuple_ctid;
1399  HeapTupleData oldtupdata;
1400  HeapTuple oldtuple;
1401 
1402  /*
1403  * This should NOT get called during EvalPlanQual; we should have passed a
1404  * subplan tree to EvalPlanQual, instead. Use a runtime test not just
1405  * Assert because this condition is easy to miss in testing. (Note:
1406  * although ModifyTable should not get executed within an EvalPlanQual
1407  * operation, we do have to allow it to be initialized and shut down in
1408  * case it is within a CTE subplan. Hence this test must be here, not in
1409  * ExecInitModifyTable.)
1410  */
1411  if (estate->es_epqTuple != NULL)
1412  elog(ERROR, "ModifyTable should not be called during EvalPlanQual");
1413 
1414  /*
1415  * If we've already completed processing, don't try to do more. We need
1416  * this test because ExecPostprocessPlan might call us an extra time, and
1417  * our subplan's nodes aren't necessarily robust against being called
1418  * extra times.
1419  */
1420  if (node->mt_done)
1421  return NULL;
1422 
1423  /*
1424  * On first call, fire BEFORE STATEMENT triggers before proceeding.
1425  */
1426  if (node->fireBSTriggers)
1427  {
1428  fireBSTriggers(node);
1429  node->fireBSTriggers = false;
1430  }
1431 
1432  /* Preload local variables */
1433  resultRelInfo = node->resultRelInfo + node->mt_whichplan;
1434  subplanstate = node->mt_plans[node->mt_whichplan];
1435  junkfilter = resultRelInfo->ri_junkFilter;
1436 
1437  /*
1438  * es_result_relation_info must point to the currently active result
1439  * relation while we are within this ModifyTable node. Even though
1440  * ModifyTable nodes can't be nested statically, they can be nested
1441  * dynamically (since our subplan could include a reference to a modifying
1442  * CTE). So we have to save and restore the caller's value.
1443  */
1444  saved_resultRelInfo = estate->es_result_relation_info;
1445 
1446  estate->es_result_relation_info = resultRelInfo;
1447 
1448  /*
1449  * Fetch rows from subplan(s), and execute the required table modification
1450  * for each row.
1451  */
1452  for (;;)
1453  {
1454  /*
1455  * Reset the per-output-tuple exprcontext. This is needed because
1456  * triggers expect to use that context as workspace. It's a bit ugly
1457  * to do this below the top level of the plan, however. We might need
1458  * to rethink this later.
1459  */
1460  ResetPerTupleExprContext(estate);
1461 
1462  planSlot = ExecProcNode(subplanstate);
1463 
1464  if (TupIsNull(planSlot))
1465  {
1466  /* advance to next subplan if any */
1467  node->mt_whichplan++;
1468  if (node->mt_whichplan < node->mt_nplans)
1469  {
1470  resultRelInfo++;
1471  subplanstate = node->mt_plans[node->mt_whichplan];
1472  junkfilter = resultRelInfo->ri_junkFilter;
1473  estate->es_result_relation_info = resultRelInfo;
1474  EvalPlanQualSetPlan(&node->mt_epqstate, subplanstate->plan,
1475  node->mt_arowmarks[node->mt_whichplan]);
1476  continue;
1477  }
1478  else
1479  break;
1480  }
1481 
1482  /*
1483  * If resultRelInfo->ri_usesFdwDirectModify is true, all we need to do
1484  * here is compute the RETURNING expressions.
1485  */
1486  if (resultRelInfo->ri_usesFdwDirectModify)
1487  {
1488  Assert(resultRelInfo->ri_projectReturning);
1489 
1490  /*
1491  * A scan slot containing the data that was actually inserted,
1492  * updated or deleted has already been made available to
1493  * ExecProcessReturning by IterateDirectModify, so no need to
1494  * provide it here.
1495  */
1496  slot = ExecProcessReturning(resultRelInfo, NULL, planSlot);
1497 
1498  estate->es_result_relation_info = saved_resultRelInfo;
1499  return slot;
1500  }
1501 
1502  EvalPlanQualSetSlot(&node->mt_epqstate, planSlot);
1503  slot = planSlot;
1504 
1505  oldtuple = NULL;
1506  if (junkfilter != NULL)
1507  {
1508  /*
1509  * extract the 'ctid' or 'wholerow' junk attribute.
1510  */
1511  if (operation == CMD_UPDATE || operation == CMD_DELETE)
1512  {
1513  char relkind;
1514  Datum datum;
1515  bool isNull;
1516 
1517  relkind = resultRelInfo->ri_RelationDesc->rd_rel->relkind;
1518  if (relkind == RELKIND_RELATION || relkind == RELKIND_MATVIEW)
1519  {
1520  datum = ExecGetJunkAttribute(slot,
1521  junkfilter->jf_junkAttNo,
1522  &isNull);
1523  /* shouldn't ever get a null result... */
1524  if (isNull)
1525  elog(ERROR, "ctid is NULL");
1526 
1527  tupleid = (ItemPointer) DatumGetPointer(datum);
1528  tuple_ctid = *tupleid; /* be sure we don't free
1529  * ctid!! */
1530  tupleid = &tuple_ctid;
1531  }
1532 
1533  /*
1534  * Use the wholerow attribute, when available, to reconstruct
1535  * the old relation tuple.
1536  *
1537  * Foreign table updates have a wholerow attribute when the
1538  * relation has an AFTER ROW trigger. Note that the wholerow
1539  * attribute does not carry system columns. Foreign table
1540  * triggers miss seeing those, except that we know enough here
1541  * to set t_tableOid. Quite separately from this, the FDW may
1542  * fetch its own junk attrs to identify the row.
1543  *
1544  * Other relevant relkinds, currently limited to views, always
1545  * have a wholerow attribute.
1546  */
1547  else if (AttributeNumberIsValid(junkfilter->jf_junkAttNo))
1548  {
1549  datum = ExecGetJunkAttribute(slot,
1550  junkfilter->jf_junkAttNo,
1551  &isNull);
1552  /* shouldn't ever get a null result... */
1553  if (isNull)
1554  elog(ERROR, "wholerow is NULL");
1555 
1556  oldtupdata.t_data = DatumGetHeapTupleHeader(datum);
1557  oldtupdata.t_len =
1559  ItemPointerSetInvalid(&(oldtupdata.t_self));
1560  /* Historically, view triggers see invalid t_tableOid. */
1561  oldtupdata.t_tableOid =
1562  (relkind == RELKIND_VIEW) ? InvalidOid :
1563  RelationGetRelid(resultRelInfo->ri_RelationDesc);
1564 
1565  oldtuple = &oldtupdata;
1566  }
1567  else
1568  Assert(relkind == RELKIND_FOREIGN_TABLE);
1569  }
1570 
1571  /*
1572  * apply the junkfilter if needed.
1573  */
1574  if (operation != CMD_DELETE)
1575  slot = ExecFilterJunk(junkfilter, slot);
1576  }
1577 
1578  switch (operation)
1579  {
1580  case CMD_INSERT:
1581  slot = ExecInsert(node, slot, planSlot,
1582  node->mt_arbiterindexes, node->mt_onconflict,
1583  estate, node->canSetTag);
1584  break;
1585  case CMD_UPDATE:
1586  slot = ExecUpdate(tupleid, oldtuple, slot, planSlot,
1587  &node->mt_epqstate, estate, node->canSetTag);
1588  break;
1589  case CMD_DELETE:
1590  slot = ExecDelete(tupleid, oldtuple, planSlot,
1591  &node->mt_epqstate, estate, node->canSetTag);
1592  break;
1593  default:
1594  elog(ERROR, "unknown operation");
1595  break;
1596  }
1597 
1598  /*
1599  * If we got a RETURNING result, return it to caller. We'll continue
1600  * the work on next call.
1601  */
1602  if (slot)
1603  {
1604  estate->es_result_relation_info = saved_resultRelInfo;
1605  return slot;
1606  }
1607  }
1608 
1609  /* Restore es_result_relation_info before exiting */
1610  estate->es_result_relation_info = saved_resultRelInfo;
1611 
1612  /*
1613  * We're done, but fire AFTER STATEMENT triggers before exiting.
1614  */
1615  fireASTriggers(node);
1616 
1617  node->mt_done = true;
1618 
1619  return NULL;
1620 }
AttrNumber jf_junkAttNo
Definition: execnodes.h:335
JunkFilter * ri_junkFilter
Definition: execnodes.h:387
HeapTuple * es_epqTuple
Definition: execnodes.h:470
Relation ri_RelationDesc
Definition: execnodes.h:373
TupleTableSlot * ExecProcNode(PlanState *node)
Definition: execProcnode.c:392
#define ResetPerTupleExprContext(estate)
Definition: executor.h:465
static TupleTableSlot * ExecUpdate(ItemPointer tupleid, HeapTuple oldtuple, TupleTableSlot *slot, TupleTableSlot *planSlot, EPQState *epqstate, EState *estate, bool canSetTag)
ResultRelInfo * resultRelInfo
Definition: execnodes.h:913
static void fireBSTriggers(ModifyTableState *node)
#define RELKIND_MATVIEW
Definition: pg_class.h:165
CmdType operation
Definition: execnodes.h:907
void EvalPlanQualSetPlan(EPQState *epqstate, Plan *subplan, List *auxrowmarks)
Definition: execMain.c:2674
EState * state
Definition: execnodes.h:802
Form_pg_class rd_rel
Definition: rel.h:114
#define DatumGetHeapTupleHeader(X)
Definition: fmgr.h:259
ItemPointerData * ItemPointer
Definition: itemptr.h:48
HeapTupleHeader t_data
Definition: htup.h:67
static TupleTableSlot * ExecDelete(ItemPointer tupleid, HeapTuple oldtuple, TupleTableSlot *planSlot, EPQState *epqstate, EState *estate, bool canSetTag)
OnConflictAction mt_onconflict
Definition: execnodes.h:917
#define ERROR
Definition: elog.h:43
PlanState ps
Definition: execnodes.h:906
ItemPointerData t_self
Definition: htup.h:65
bool ri_usesFdwDirectModify
Definition: execnodes.h:383
uint32 t_len
Definition: htup.h:64
EPQState mt_epqstate
Definition: execnodes.h:915
ProjectionInfo * ri_projectReturning
Definition: execnodes.h:388
#define TupIsNull(slot)
Definition: tuptable.h:138
Oid t_tableOid
Definition: htup.h:66
#define RELKIND_FOREIGN_TABLE
Definition: pg_class.h:167
static TupleTableSlot * ExecProcessReturning(ResultRelInfo *resultRelInfo, TupleTableSlot *tupleSlot, TupleTableSlot *planSlot)
PlanState ** mt_plans
Definition: execnodes.h:910
#define AttributeNumberIsValid(attributeNumber)
Definition: attnum.h:34
static void fireASTriggers(ModifyTableState *node)
uintptr_t Datum
Definition: postgres.h:372
TupleTableSlot * ExecFilterJunk(JunkFilter *junkfilter, TupleTableSlot *slot)
Definition: execJunk.c:262
Plan * plan
Definition: execnodes.h:800
#define InvalidOid
Definition: postgres_ext.h:36
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
static TupleTableSlot * ExecInsert(ModifyTableState *mtstate, TupleTableSlot *slot, TupleTableSlot *planSlot, List *arbiterIndexes, OnConflictAction onconflict, EState *estate, bool canSetTag)
#define DatumGetPointer(X)
Definition: postgres.h:555
List * mt_arbiterindexes
Definition: execnodes.h:918
#define ItemPointerSetInvalid(pointer)
Definition: itemptr.h:131
Datum ExecGetJunkAttribute(TupleTableSlot *slot, AttrNumber attno, bool *isNull)
Definition: execJunk.c:248
#define RELKIND_VIEW
Definition: pg_class.h:164
#define elog
Definition: elog.h:219
#define RELKIND_RELATION
Definition: pg_class.h:160
#define RelationGetRelid(relation)
Definition: rel.h:417
CmdType
Definition: nodes.h:639
List ** mt_arowmarks
Definition: execnodes.h:914
#define EvalPlanQualSetSlot(epqstate, slot)
Definition: executor.h:220
#define HeapTupleHeaderGetDatumLength(tup)
Definition: htup_details.h:439
ResultRelInfo * es_result_relation_info
Definition: execnodes.h:422
void ExecReScanModifyTable ( ModifyTableState node)

Definition at line 2197 of file nodeModifyTable.c.

References elog, and ERROR.

Referenced by ExecReScan().

2198 {
2199  /*
2200  * Currently, we don't need to support rescan on ModifyTable nodes. The
2201  * semantics of that would be a bit debatable anyway.
2202  */
2203  elog(ERROR, "ExecReScanModifyTable is not implemented");
2204 }
#define ERROR
Definition: elog.h:43
#define elog
Definition: elog.h:219