PostgreSQL Source Code  git master
rewriteHandler.c File Reference
Include dependency graph for rewriteHandler.c:

Go to the source code of this file.

Data Structures

struct  rewrite_event
 
struct  acquireLocksOnSubLinks_context
 

Macros

#define ALL_EVENTS   ((1 << CMD_INSERT) | (1 << CMD_UPDATE) | (1 << CMD_DELETE))
 

Typedefs

typedef struct rewrite_event rewrite_event
 
typedef struct acquireLocksOnSubLinks_context acquireLocksOnSubLinks_context
 

Functions

static bool acquireLocksOnSubLinks (Node *node, acquireLocksOnSubLinks_context *context)
 
static QueryrewriteRuleAction (Query *parsetree, Query *rule_action, Node *rule_qual, int rt_index, CmdType event, bool *returning_flag)
 
static ListadjustJoinTreeList (Query *parsetree, bool removert, int rt_index)
 
static ListrewriteTargetListIU (List *targetList, CmdType commandType, OverridingKind override, Relation target_relation, int result_rti, RangeTblEntry *values_rte, int values_rte_index, Bitmapset **unused_values_attrnos)
 
static TargetEntryprocess_matched_tle (TargetEntry *src_tle, TargetEntry *prior_tle, const char *attrName)
 
static Nodeget_assignment_input (Node *node)
 
static BitmapsetfindDefaultOnlyColumns (RangeTblEntry *rte)
 
static bool rewriteValuesRTE (Query *parsetree, RangeTblEntry *rte, int rti, Relation target_relation, bool force_nulls, Bitmapset *unused_cols)
 
static void markQueryForLocking (Query *qry, Node *jtnode, LockClauseStrength strength, LockWaitPolicy waitPolicy, bool pushedDown)
 
static ListmatchLocks (CmdType event, RuleLock *rulelocks, int varno, Query *parsetree, bool *hasUpdate)
 
static QueryfireRIRrules (Query *parsetree, List *activeRIRs)
 
static bool view_has_instead_trigger (Relation view, CmdType event)
 
static Bitmapsetadjust_view_column_set (Bitmapset *cols, List *targetlist)
 
void AcquireRewriteLocks (Query *parsetree, bool forExecute, bool forUpdatePushedDown)
 
Nodebuild_column_default (Relation rel, int attrno)
 
static bool searchForDefault (RangeTblEntry *rte)
 
void fill_extraUpdatedCols (RangeTblEntry *target_rte, Relation target_relation)
 
static QueryApplyRetrieveRule (Query *parsetree, RewriteRule *rule, int rt_index, Relation relation, List *activeRIRs)
 
static bool fireRIRonSubLink (Node *node, List *activeRIRs)
 
static QueryCopyAndAddInvertedQual (Query *parsetree, Node *rule_qual, int rt_index, CmdType event)
 
static ListfireRules (Query *parsetree, int rt_index, CmdType event, List *locks, bool *instead_flag, bool *returning_flag, Query **qual_product)
 
Queryget_view_query (Relation view)
 
static const char * view_col_is_auto_updatable (RangeTblRef *rtr, TargetEntry *tle)
 
const char * view_query_is_auto_updatable (Query *viewquery, bool check_cols)
 
static const char * view_cols_are_auto_updatable (Query *viewquery, Bitmapset *required_cols, Bitmapset **updatable_cols, char **non_updatable_col)
 
int relation_is_updatable (Oid reloid, List *outer_reloids, bool include_triggers, Bitmapset *include_cols)
 
static QueryrewriteTargetView (Query *parsetree, Relation view)
 
static ListRewriteQuery (Query *parsetree, List *rewrite_events)
 
ListQueryRewrite (Query *parsetree)
 

Macro Definition Documentation

◆ ALL_EVENTS

#define ALL_EVENTS   ((1 << CMD_INSERT) | (1 << CMD_UPDATE) | (1 << CMD_DELETE))

Referenced by relation_is_updatable().

Typedef Documentation

◆ acquireLocksOnSubLinks_context

◆ rewrite_event

typedef struct rewrite_event rewrite_event

Function Documentation

◆ acquireLocksOnSubLinks()

static bool acquireLocksOnSubLinks ( Node node,
acquireLocksOnSubLinks_context context 
)
static

Definition at line 302 of file rewriteHandler.c.

References AcquireRewriteLocks(), expression_tree_walker(), acquireLocksOnSubLinks_context::for_execute, IsA, and SubLink::subselect.

Referenced by AcquireRewriteLocks(), CopyAndAddInvertedQual(), fireRIRrules(), rewriteRuleAction(), and rewriteTargetView().

303 {
304  if (node == NULL)
305  return false;
306  if (IsA(node, SubLink))
307  {
308  SubLink *sub = (SubLink *) node;
309 
310  /* Do what we came for */
312  context->for_execute,
313  false);
314  /* Fall through to process lefthand args of SubLink */
315  }
316 
317  /*
318  * Do NOT recurse into Query nodes, because AcquireRewriteLocks already
319  * processed subselects of subselects for us.
320  */
321  return expression_tree_walker(node, acquireLocksOnSubLinks, context);
322 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
static bool acquireLocksOnSubLinks(Node *node, acquireLocksOnSubLinks_context *context)
void AcquireRewriteLocks(Query *parsetree, bool forExecute, bool forUpdatePushedDown)
bool expression_tree_walker(Node *node, bool(*walker)(), void *context)
Definition: nodeFuncs.c:1904

◆ AcquireRewriteLocks()

void AcquireRewriteLocks ( Query parsetree,
bool  forExecute,
bool  forUpdatePushedDown 
)

Definition at line 140 of file rewriteHandler.c.

References AccessShareLock, acquireLocksOnSubLinks(), AcquireRewriteLocks(), Assert, Query::cteList, CommonTableExpr::ctequery, elog, ERROR, acquireLocksOnSubLinks_context::for_execute, get_parse_rowmark(), get_rte_attribute_is_dropped(), Query::hasSubLinks, IsA, RangeTblEntry::joinaliasvars, lappend(), lfirst, NIL, NoLock, QTW_IGNORE_RC_SUBQUERIES, query_tree_walker(), RelationData::rd_rel, RangeTblEntry::relid, RangeTblEntry::relkind, RangeTblEntry::rellockmode, RowShareLock, rt_fetch, Query::rtable, RTE_JOIN, RTE_RELATION, RTE_SUBQUERY, RangeTblEntry::rtekind, strip_implicit_coercions(), RangeTblEntry::subquery, table_close(), table_open(), Var::varattno, Var::varlevelsup, and Var::varno.

Referenced by acquireLocksOnSubLinks(), AcquireRewriteLocks(), ApplyRetrieveRule(), get_query_def(), init_sql_fcache(), make_ruledef(), refresh_matview_datafill(), and rewriteRuleAction().

143 {
144  ListCell *l;
145  int rt_index;
147 
148  context.for_execute = forExecute;
149 
150  /*
151  * First, process RTEs of the current query level.
152  */
153  rt_index = 0;
154  foreach(l, parsetree->rtable)
155  {
156  RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);
157  Relation rel;
158  LOCKMODE lockmode;
159  List *newaliasvars;
160  Index curinputvarno;
161  RangeTblEntry *curinputrte;
162  ListCell *ll;
163 
164  ++rt_index;
165  switch (rte->rtekind)
166  {
167  case RTE_RELATION:
168 
169  /*
170  * Grab the appropriate lock type for the relation, and do not
171  * release it until end of transaction. This protects the
172  * rewriter, planner, and executor against schema changes
173  * mid-query.
174  *
175  * If forExecute is false, ignore rellockmode and just use
176  * AccessShareLock.
177  */
178  if (!forExecute)
179  lockmode = AccessShareLock;
180  else if (forUpdatePushedDown)
181  {
182  /* Upgrade RTE's lock mode to reflect pushed-down lock */
183  if (rte->rellockmode == AccessShareLock)
184  rte->rellockmode = RowShareLock;
185  lockmode = rte->rellockmode;
186  }
187  else
188  lockmode = rte->rellockmode;
189 
190  rel = table_open(rte->relid, lockmode);
191 
192  /*
193  * While we have the relation open, update the RTE's relkind,
194  * just in case it changed since this rule was made.
195  */
196  rte->relkind = rel->rd_rel->relkind;
197 
198  table_close(rel, NoLock);
199  break;
200 
201  case RTE_JOIN:
202 
203  /*
204  * Scan the join's alias var list to see if any columns have
205  * been dropped, and if so replace those Vars with null
206  * pointers.
207  *
208  * Since a join has only two inputs, we can expect to see
209  * multiple references to the same input RTE; optimize away
210  * multiple fetches.
211  */
212  newaliasvars = NIL;
213  curinputvarno = 0;
214  curinputrte = NULL;
215  foreach(ll, rte->joinaliasvars)
216  {
217  Var *aliasitem = (Var *) lfirst(ll);
218  Var *aliasvar = aliasitem;
219 
220  /* Look through any implicit coercion */
221  aliasvar = (Var *) strip_implicit_coercions((Node *) aliasvar);
222 
223  /*
224  * If the list item isn't a simple Var, then it must
225  * represent a merged column, ie a USING column, and so it
226  * couldn't possibly be dropped, since it's referenced in
227  * the join clause. (Conceivably it could also be a null
228  * pointer already? But that's OK too.)
229  */
230  if (aliasvar && IsA(aliasvar, Var))
231  {
232  /*
233  * The elements of an alias list have to refer to
234  * earlier RTEs of the same rtable, because that's the
235  * order the planner builds things in. So we already
236  * processed the referenced RTE, and so it's safe to
237  * use get_rte_attribute_is_dropped on it. (This might
238  * not hold after rewriting or planning, but it's OK
239  * to assume here.)
240  */
241  Assert(aliasvar->varlevelsup == 0);
242  if (aliasvar->varno != curinputvarno)
243  {
244  curinputvarno = aliasvar->varno;
245  if (curinputvarno >= rt_index)
246  elog(ERROR, "unexpected varno %d in JOIN RTE %d",
247  curinputvarno, rt_index);
248  curinputrte = rt_fetch(curinputvarno,
249  parsetree->rtable);
250  }
251  if (get_rte_attribute_is_dropped(curinputrte,
252  aliasvar->varattno))
253  {
254  /* Replace the join alias item with a NULL */
255  aliasitem = NULL;
256  }
257  }
258  newaliasvars = lappend(newaliasvars, aliasitem);
259  }
260  rte->joinaliasvars = newaliasvars;
261  break;
262 
263  case RTE_SUBQUERY:
264 
265  /*
266  * The subquery RTE itself is all right, but we have to
267  * recurse to process the represented subquery.
268  */
270  forExecute,
271  (forUpdatePushedDown ||
272  get_parse_rowmark(parsetree, rt_index) != NULL));
273  break;
274 
275  default:
276  /* ignore other types of RTEs */
277  break;
278  }
279  }
280 
281  /* Recurse into subqueries in WITH */
282  foreach(l, parsetree->cteList)
283  {
284  CommonTableExpr *cte = (CommonTableExpr *) lfirst(l);
285 
286  AcquireRewriteLocks((Query *) cte->ctequery, forExecute, false);
287  }
288 
289  /*
290  * Recurse into sublink subqueries, too. But we already did the ones in
291  * the rtable and cteList.
292  */
293  if (parsetree->hasSubLinks)
294  query_tree_walker(parsetree, acquireLocksOnSubLinks, &context,
296 }
#define NIL
Definition: pg_list.h:65
bool query_tree_walker(Query *query, bool(*walker)(), void *context, int flags)
Definition: nodeFuncs.c:2355
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
List * joinaliasvars
Definition: parsenodes.h:1070
Index varlevelsup
Definition: primnodes.h:196
RowMarkClause * get_parse_rowmark(Query *qry, Index rtindex)
static bool acquireLocksOnSubLinks(Node *node, acquireLocksOnSubLinks_context *context)
int LOCKMODE
Definition: lockdefs.h:26
#define AccessShareLock
Definition: lockdefs.h:36
Definition: nodes.h:539
AttrNumber varattno
Definition: primnodes.h:191
Form_pg_class rd_rel
Definition: rel.h:110
Definition: primnodes.h:186
#define QTW_IGNORE_RC_SUBQUERIES
Definition: nodeFuncs.h:22
List * rtable
Definition: parsenodes.h:147
#define ERROR
Definition: elog.h:46
#define NoLock
Definition: lockdefs.h:34
void AcquireRewriteLocks(Query *parsetree, bool forExecute, bool forUpdatePushedDown)
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
List * lappend(List *list, void *datum)
Definition: list.c:336
Index varno
Definition: primnodes.h:189
#define RowShareLock
Definition: lockdefs.h:37
bool get_rte_attribute_is_dropped(RangeTblEntry *rte, AttrNumber attnum)
unsigned int Index
Definition: c.h:549
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
RTEKind rtekind
Definition: parsenodes.h:995
List * cteList
Definition: parsenodes.h:145
Query * subquery
Definition: parsenodes.h:1030
bool hasSubLinks
Definition: parsenodes.h:136
#define elog(elevel,...)
Definition: elog.h:232
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: pg_list.h:50
Node * strip_implicit_coercions(Node *node)
Definition: nodeFuncs.c:651

◆ adjust_view_column_set()

static Bitmapset * adjust_view_column_set ( Bitmapset cols,
List targetlist 
)
static

Definition at line 2973 of file rewriteHandler.c.

References bms_add_member(), bms_next_member(), castNode, elog, ERROR, TargetEntry::expr, FirstLowInvalidHeapAttributeNumber, get_tle_by_resno(), InvalidAttrNumber, IsA, lfirst_node, TargetEntry::resjunk, and Var::varattno.

Referenced by relation_is_updatable(), and rewriteTargetView().

2974 {
2975  Bitmapset *result = NULL;
2976  int col;
2977 
2978  col = -1;
2979  while ((col = bms_next_member(cols, col)) >= 0)
2980  {
2981  /* bit numbers are offset by FirstLowInvalidHeapAttributeNumber */
2983 
2984  if (attno == InvalidAttrNumber)
2985  {
2986  /*
2987  * There's a whole-row reference to the view. For permissions
2988  * purposes, treat it as a reference to each column available from
2989  * the view. (We should *not* convert this to a whole-row
2990  * reference to the base relation, since the view may not touch
2991  * all columns of the base relation.)
2992  */
2993  ListCell *lc;
2994 
2995  foreach(lc, targetlist)
2996  {
2997  TargetEntry *tle = lfirst_node(TargetEntry, lc);
2998  Var *var;
2999 
3000  if (tle->resjunk)
3001  continue;
3002  var = castNode(Var, tle->expr);
3003  result = bms_add_member(result,
3004  var->varattno - FirstLowInvalidHeapAttributeNumber);
3005  }
3006  }
3007  else
3008  {
3009  /*
3010  * Views do not have system columns, so we do not expect to see
3011  * any other system attnos here. If we do find one, the error
3012  * case will apply.
3013  */
3014  TargetEntry *tle = get_tle_by_resno(targetlist, attno);
3015 
3016  if (tle != NULL && !tle->resjunk && IsA(tle->expr, Var))
3017  {
3018  Var *var = (Var *) tle->expr;
3019 
3020  result = bms_add_member(result,
3021  var->varattno - FirstLowInvalidHeapAttributeNumber);
3022  }
3023  else
3024  elog(ERROR, "attribute number %d not found in view targetlist",
3025  attno);
3026  }
3027  }
3028 
3029  return result;
3030 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
#define castNode(_type_, nodeptr)
Definition: nodes.h:608
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1043
AttrNumber varattno
Definition: primnodes.h:191
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
Definition: primnodes.h:186
bool resjunk
Definition: primnodes.h:1451
#define ERROR
Definition: elog.h:46
#define lfirst_node(type, lc)
Definition: pg_list.h:172
Expr * expr
Definition: primnodes.h:1444
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:736
#define InvalidAttrNumber
Definition: attnum.h:23
#define elog(elevel,...)
Definition: elog.h:232
TargetEntry * get_tle_by_resno(List *tlist, AttrNumber resno)
int16 AttrNumber
Definition: attnum.h:21

◆ adjustJoinTreeList()

static List * adjustJoinTreeList ( Query parsetree,
bool  removert,
int  rt_index 
)
static

Definition at line 646 of file rewriteHandler.c.

References copyObject, foreach_delete_current, FromExpr::fromlist, IsA, Query::jointree, lfirst, and RangeTblRef::rtindex.

Referenced by rewriteRuleAction().

647 {
648  List *newjointree = copyObject(parsetree->jointree->fromlist);
649  ListCell *l;
650 
651  if (removert)
652  {
653  foreach(l, newjointree)
654  {
655  RangeTblRef *rtr = lfirst(l);
656 
657  if (IsA(rtr, RangeTblRef) &&
658  rtr->rtindex == rt_index)
659  {
660  newjointree = foreach_delete_current(newjointree, l);
661  break;
662  }
663  }
664  }
665  return newjointree;
666 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
FromExpr * jointree
Definition: parsenodes.h:148
List * fromlist
Definition: primnodes.h:1553
#define foreach_delete_current(lst, cell)
Definition: pg_list.h:369
#define lfirst(lc)
Definition: pg_list.h:169
#define copyObject(obj)
Definition: nodes.h:655
Definition: pg_list.h:50

◆ ApplyRetrieveRule()

static Query* ApplyRetrieveRule ( Query parsetree,
RewriteRule rule,
int  rt_index,
Relation  relation,
List activeRIRs 
)
static

Definition at line 1714 of file rewriteHandler.c.

References AcquireRewriteLocks(), RewriteRule::actions, Assert, ChangeVarNodes(), RangeTblEntry::checkAsUser, CMD_DELETE, CMD_INSERT, CMD_UPDATE, Query::commandType, copyObject, elog, ERROR, RangeTblEntry::extraUpdatedCols, fireRIRrules(), get_parse_rowmark(), RangeTblEntry::inh, RangeTblEntry::insertedCols, InvalidOid, Query::jointree, lappend(), linitial, list_length(), makeTargetEntry(), makeWholeRowVar(), markQueryForLocking(), PRS2_OLD_VARNO, pstrdup(), RewriteRule::qual, RelationData::rd_id, RelationIsSecurityView, RangeTblEntry::relid, RangeTblEntry::relkind, RangeTblEntry::rellockmode, RangeTblEntry::requiredPerms, Query::resultRelation, Query::returningList, rt_fetch, Query::rtable, RTE_SUBQUERY, RangeTblEntry::rtekind, RangeTblEntry::security_barrier, RangeTblEntry::selectedCols, RowMarkClause::strength, RangeTblEntry::subquery, RangeTblEntry::tablesample, Query::targetList, RangeTblEntry::updatedCols, and RowMarkClause::waitPolicy.

Referenced by fireRIRrules().

1719 {
1720  Query *rule_action;
1721  RangeTblEntry *rte,
1722  *subrte;
1723  RowMarkClause *rc;
1724 
1725  if (list_length(rule->actions) != 1)
1726  elog(ERROR, "expected just one rule action");
1727  if (rule->qual != NULL)
1728  elog(ERROR, "cannot handle qualified ON SELECT rule");
1729 
1730  if (rt_index == parsetree->resultRelation)
1731  {
1732  /*
1733  * We have a view as the result relation of the query, and it wasn't
1734  * rewritten by any rule. This case is supported if there is an
1735  * INSTEAD OF trigger that will trap attempts to insert/update/delete
1736  * view rows. The executor will check that; for the moment just plow
1737  * ahead. We have two cases:
1738  *
1739  * For INSERT, we needn't do anything. The unmodified RTE will serve
1740  * fine as the result relation.
1741  *
1742  * For UPDATE/DELETE, we need to expand the view so as to have source
1743  * data for the operation. But we also need an unmodified RTE to
1744  * serve as the target. So, copy the RTE and add the copy to the
1745  * rangetable. Note that the copy does not get added to the jointree.
1746  * Also note that there's a hack in fireRIRrules to avoid calling this
1747  * function again when it arrives at the copied RTE.
1748  */
1749  if (parsetree->commandType == CMD_INSERT)
1750  return parsetree;
1751  else if (parsetree->commandType == CMD_UPDATE ||
1752  parsetree->commandType == CMD_DELETE)
1753  {
1754  RangeTblEntry *newrte;
1755  Var *var;
1756  TargetEntry *tle;
1757 
1758  rte = rt_fetch(rt_index, parsetree->rtable);
1759  newrte = copyObject(rte);
1760  parsetree->rtable = lappend(parsetree->rtable, newrte);
1761  parsetree->resultRelation = list_length(parsetree->rtable);
1762 
1763  /*
1764  * There's no need to do permissions checks twice, so wipe out the
1765  * permissions info for the original RTE (we prefer to keep the
1766  * bits set on the result RTE).
1767  */
1768  rte->requiredPerms = 0;
1769  rte->checkAsUser = InvalidOid;
1770  rte->selectedCols = NULL;
1771  rte->insertedCols = NULL;
1772  rte->updatedCols = NULL;
1773  rte->extraUpdatedCols = NULL;
1774 
1775  /*
1776  * For the most part, Vars referencing the view should remain as
1777  * they are, meaning that they implicitly represent OLD values.
1778  * But in the RETURNING list if any, we want such Vars to
1779  * represent NEW values, so change them to reference the new RTE.
1780  *
1781  * Since ChangeVarNodes scribbles on the tree in-place, copy the
1782  * RETURNING list first for safety.
1783  */
1784  parsetree->returningList = copyObject(parsetree->returningList);
1785  ChangeVarNodes((Node *) parsetree->returningList, rt_index,
1786  parsetree->resultRelation, 0);
1787 
1788  /*
1789  * To allow the executor to compute the original view row to pass
1790  * to the INSTEAD OF trigger, we add a resjunk whole-row Var
1791  * referencing the original RTE. This will later get expanded
1792  * into a RowExpr computing all the OLD values of the view row.
1793  */
1794  var = makeWholeRowVar(rte, rt_index, 0, false);
1795  tle = makeTargetEntry((Expr *) var,
1796  list_length(parsetree->targetList) + 1,
1797  pstrdup("wholerow"),
1798  true);
1799 
1800  parsetree->targetList = lappend(parsetree->targetList, tle);
1801 
1802  /* Now, continue with expanding the original view RTE */
1803  }
1804  else
1805  elog(ERROR, "unrecognized commandType: %d",
1806  (int) parsetree->commandType);
1807  }
1808 
1809  /*
1810  * Check if there's a FOR [KEY] UPDATE/SHARE clause applying to this view.
1811  *
1812  * Note: we needn't explicitly consider any such clauses appearing in
1813  * ancestor query levels; their effects have already been pushed down to
1814  * here by markQueryForLocking, and will be reflected in "rc".
1815  */
1816  rc = get_parse_rowmark(parsetree, rt_index);
1817 
1818  /*
1819  * Make a modifiable copy of the view query, and acquire needed locks on
1820  * the relations it mentions. Force at least RowShareLock for all such
1821  * rels if there's a FOR [KEY] UPDATE/SHARE clause affecting this view.
1822  */
1823  rule_action = copyObject(linitial(rule->actions));
1824 
1825  AcquireRewriteLocks(rule_action, true, (rc != NULL));
1826 
1827  /*
1828  * If FOR [KEY] UPDATE/SHARE of view, mark all the contained tables as
1829  * implicit FOR [KEY] UPDATE/SHARE, the same as the parser would have done
1830  * if the view's subquery had been written out explicitly.
1831  */
1832  if (rc != NULL)
1833  markQueryForLocking(rule_action, (Node *) rule_action->jointree,
1834  rc->strength, rc->waitPolicy, true);
1835 
1836  /*
1837  * Recursively expand any view references inside the view.
1838  *
1839  * Note: this must happen after markQueryForLocking. That way, any UPDATE
1840  * permission bits needed for sub-views are initially applied to their
1841  * RTE_RELATION RTEs by markQueryForLocking, and then transferred to their
1842  * OLD rangetable entries by the action below (in a recursive call of this
1843  * routine).
1844  */
1845  rule_action = fireRIRrules(rule_action, activeRIRs);
1846 
1847  /*
1848  * Now, plug the view query in as a subselect, converting the relation's
1849  * original RTE to a subquery RTE.
1850  */
1851  rte = rt_fetch(rt_index, parsetree->rtable);
1852 
1853  rte->rtekind = RTE_SUBQUERY;
1854  rte->subquery = rule_action;
1855  rte->security_barrier = RelationIsSecurityView(relation);
1856  /* Clear fields that should not be set in a subquery RTE */
1857  rte->relid = InvalidOid;
1858  rte->relkind = 0;
1859  rte->rellockmode = 0;
1860  rte->tablesample = NULL;
1861  rte->inh = false; /* must not be set for a subquery */
1862 
1863  /*
1864  * We move the view's permission check data down to its rangetable. The
1865  * checks will actually be done against the OLD entry therein.
1866  */
1867  subrte = rt_fetch(PRS2_OLD_VARNO, rule_action->rtable);
1868  Assert(subrte->relid == relation->rd_id);
1869  subrte->requiredPerms = rte->requiredPerms;
1870  subrte->checkAsUser = rte->checkAsUser;
1871  subrte->selectedCols = rte->selectedCols;
1872  subrte->insertedCols = rte->insertedCols;
1873  subrte->updatedCols = rte->updatedCols;
1874  subrte->extraUpdatedCols = rte->extraUpdatedCols;
1875 
1876  rte->requiredPerms = 0; /* no permission check on subquery itself */
1877  rte->checkAsUser = InvalidOid;
1878  rte->selectedCols = NULL;
1879  rte->insertedCols = NULL;
1880  rte->updatedCols = NULL;
1881  rte->extraUpdatedCols = NULL;
1882 
1883  return parsetree;
1884 }
static void markQueryForLocking(Query *qry, Node *jtnode, LockClauseStrength strength, LockWaitPolicy waitPolicy, bool pushedDown)
Node * qual
Definition: prs2lock.h:28
RowMarkClause * get_parse_rowmark(Query *qry, Index rtindex)
FromExpr * jointree
Definition: parsenodes.h:148
char * pstrdup(const char *in)
Definition: mcxt.c:1299
int resultRelation
Definition: parsenodes.h:130
Definition: nodes.h:539
Var * makeWholeRowVar(RangeTblEntry *rte, Index varno, Index varlevelsup, bool allowScalar)
Definition: makefuncs.c:133
AclMode requiredPerms
Definition: parsenodes.h:1145
Definition: primnodes.h:186
LockClauseStrength strength
Definition: parsenodes.h:1409
List * targetList
Definition: parsenodes.h:150
Bitmapset * extraUpdatedCols
Definition: parsenodes.h:1150
Bitmapset * selectedCols
Definition: parsenodes.h:1147
#define linitial(l)
Definition: pg_list.h:174
List * rtable
Definition: parsenodes.h:147
#define ERROR
Definition: elog.h:46
void AcquireRewriteLocks(Query *parsetree, bool forExecute, bool forUpdatePushedDown)
List * actions
Definition: prs2lock.h:29
List * returningList
Definition: parsenodes.h:156
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:238
Oid rd_id
Definition: rel.h:112
List * lappend(List *list, void *datum)
Definition: list.c:336
#define PRS2_OLD_VARNO
Definition: primnodes.h:183
bool security_barrier
Definition: parsenodes.h:1031
#define InvalidOid
Definition: postgres_ext.h:36
Bitmapset * updatedCols
Definition: parsenodes.h:1149
CmdType commandType
Definition: parsenodes.h:120
#define Assert(condition)
Definition: c.h:804
static int list_length(const List *l)
Definition: pg_list.h:149
LockWaitPolicy waitPolicy
Definition: parsenodes.h:1410
RTEKind rtekind
Definition: parsenodes.h:995
Query * subquery
Definition: parsenodes.h:1030
#define elog(elevel,...)
Definition: elog.h:232
Bitmapset * insertedCols
Definition: parsenodes.h:1148
#define RelationIsSecurityView(relation)
Definition: rel.h:388
void ChangeVarNodes(Node *node, int rt_index, int new_index, int sublevels_up)
Definition: rewriteManip.c:610
#define copyObject(obj)
Definition: nodes.h:655
static Query * fireRIRrules(Query *parsetree, List *activeRIRs)
struct TableSampleClause * tablesample
Definition: parsenodes.h:1025

◆ build_column_default()

Node* build_column_default ( Relation  rel,
int  attrno 
)

Definition at line 1211 of file rewriteHandler.c.

References COERCE_IMPLICIT_CAST, coerce_to_target_type(), COERCION_ASSIGNMENT, TupleDescData::constr, TupleConstr::defval, elog, ereport, errcode(), errhint(), errmsg(), ERROR, exprType(), format_type_be(), get_typdefault(), getIdentitySequence(), makeNode, NameStr, TupleConstr::num_defval, RelationData::rd_att, RelationGetRelationName, RelationGetRelid, NextValueExpr::seqid, stringToNode(), TupleDescAttr, and NextValueExpr::typeId.

Referenced by ATExecAddColumn(), ATExecAlterColumnType(), BeginCopyFrom(), ExecComputeStoredGenerated(), rewriteTargetListIU(), rewriteValuesRTE(), and slot_fill_defaults().

1212 {
1213  TupleDesc rd_att = rel->rd_att;
1214  Form_pg_attribute att_tup = TupleDescAttr(rd_att, attrno - 1);
1215  Oid atttype = att_tup->atttypid;
1216  int32 atttypmod = att_tup->atttypmod;
1217  Node *expr = NULL;
1218  Oid exprtype;
1219 
1220  if (att_tup->attidentity)
1221  {
1223 
1224  nve->seqid = getIdentitySequence(RelationGetRelid(rel), attrno, false);
1225  nve->typeId = att_tup->atttypid;
1226 
1227  return (Node *) nve;
1228  }
1229 
1230  /*
1231  * If relation has a default for this column, fetch that expression.
1232  */
1233  if (att_tup->atthasdef)
1234  {
1235  if (rd_att->constr && rd_att->constr->num_defval > 0)
1236  {
1237  AttrDefault *defval = rd_att->constr->defval;
1238  int ndef = rd_att->constr->num_defval;
1239 
1240  while (--ndef >= 0)
1241  {
1242  if (attrno == defval[ndef].adnum)
1243  {
1244  /* Found it, convert string representation to node tree. */
1245  expr = stringToNode(defval[ndef].adbin);
1246  break;
1247  }
1248  }
1249  }
1250  if (expr == NULL)
1251  elog(ERROR, "default expression not found for attribute %d of relation \"%s\"",
1252  attrno, RelationGetRelationName(rel));
1253  }
1254 
1255  /*
1256  * No per-column default, so look for a default for the type itself. But
1257  * not for generated columns.
1258  */
1259  if (expr == NULL && !att_tup->attgenerated)
1260  expr = get_typdefault(atttype);
1261 
1262  if (expr == NULL)
1263  return NULL; /* No default anywhere */
1264 
1265  /*
1266  * Make sure the value is coerced to the target column type; this will
1267  * generally be true already, but there seem to be some corner cases
1268  * involving domain defaults where it might not be true. This should match
1269  * the parser's processing of non-defaulted expressions --- see
1270  * transformAssignedExpr().
1271  */
1272  exprtype = exprType(expr);
1273 
1274  expr = coerce_to_target_type(NULL, /* no UNKNOWN params here */
1275  expr, exprtype,
1276  atttype, atttypmod,
1279  -1);
1280  if (expr == NULL)
1281  ereport(ERROR,
1282  (errcode(ERRCODE_DATATYPE_MISMATCH),
1283  errmsg("column \"%s\" is of type %s"
1284  " but default expression is of type %s",
1285  NameStr(att_tup->attname),
1286  format_type_be(atttype),
1287  format_type_be(exprtype)),
1288  errhint("You will need to rewrite or cast the expression.")));
1289 
1290  return expr;
1291 }
int errhint(const char *fmt,...)
Definition: elog.c:1156
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
Definition: nodes.h:539
int errcode(int sqlerrcode)
Definition: elog.c:698
void * stringToNode(const char *str)
Definition: read.c:89
char * format_type_be(Oid type_oid)
Definition: format_type.c:339
unsigned int Oid
Definition: postgres_ext.h:31
Oid getIdentitySequence(Oid relid, AttrNumber attnum, bool missing_ok)
Definition: pg_depend.c:945
signed int int32
Definition: c.h:429
AttrDefault * defval
Definition: tupdesc.h:39
#define ERROR
Definition: elog.h:46
Node * coerce_to_target_type(ParseState *pstate, Node *expr, Oid exprtype, Oid targettype, int32 targettypmod, CoercionContext ccontext, CoercionForm cformat, int location)
Definition: parse_coerce.c:78
TupleConstr * constr
Definition: tupdesc.h:85
#define RelationGetRelationName(relation)
Definition: rel.h:491
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:203
TupleDesc rd_att
Definition: rel.h:111
#define ereport(elevel,...)
Definition: elog.h:157
#define makeNode(_type_)
Definition: nodes.h:587
Node * get_typdefault(Oid typid)
Definition: lsyscache.c:2395
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:41
uint16 num_defval
Definition: tupdesc.h:42
int errmsg(const char *fmt,...)
Definition: elog.c:909
#define elog(elevel,...)
Definition: elog.h:232
#define NameStr(name)
Definition: c.h:681
#define RelationGetRelid(relation)
Definition: rel.h:457

◆ CopyAndAddInvertedQual()

static Query* CopyAndAddInvertedQual ( Query parsetree,
Node rule_qual,
int  rt_index,
CmdType  event 
)
static

Definition at line 2281 of file rewriteHandler.c.

References acquireLocksOnSubLinks(), AddInvertedQual(), ChangeVarNodes(), CMD_INSERT, CMD_UPDATE, copyObject, acquireLocksOnSubLinks_context::for_execute, Query::hasSubLinks, PRS2_NEW_VARNO, PRS2_OLD_VARNO, REPLACEVARS_CHANGE_VARNO, REPLACEVARS_SUBSTITUTE_NULL, ReplaceVarsFromTargetList(), rt_fetch, Query::rtable, and Query::targetList.

Referenced by fireRules().

2285 {
2286  /* Don't scribble on the passed qual (it's in the relcache!) */
2287  Node *new_qual = copyObject(rule_qual);
2289 
2290  context.for_execute = true;
2291 
2292  /*
2293  * In case there are subqueries in the qual, acquire necessary locks and
2294  * fix any deleted JOIN RTE entries. (This is somewhat redundant with
2295  * rewriteRuleAction, but not entirely ... consider restructuring so that
2296  * we only need to process the qual this way once.)
2297  */
2298  (void) acquireLocksOnSubLinks(new_qual, &context);
2299 
2300  /* Fix references to OLD */
2301  ChangeVarNodes(new_qual, PRS2_OLD_VARNO, rt_index, 0);
2302  /* Fix references to NEW */
2303  if (event == CMD_INSERT || event == CMD_UPDATE)
2304  new_qual = ReplaceVarsFromTargetList(new_qual,
2306  0,
2307  rt_fetch(rt_index,
2308  parsetree->rtable),
2309  parsetree->targetList,
2310  (event == CMD_UPDATE) ?
2313  rt_index,
2314  &parsetree->hasSubLinks);
2315  /* And attach the fixed qual */
2316  AddInvertedQual(parsetree, new_qual);
2317 
2318  return parsetree;
2319 }
static bool acquireLocksOnSubLinks(Node *node, acquireLocksOnSubLinks_context *context)
void AddInvertedQual(Query *parsetree, Node *qual)
Definition: nodes.h:539
List * targetList
Definition: parsenodes.h:150
List * rtable
Definition: parsenodes.h:147
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
#define PRS2_OLD_VARNO
Definition: primnodes.h:183
Node * ReplaceVarsFromTargetList(Node *node, int target_varno, int sublevels_up, RangeTblEntry *target_rte, List *targetlist, ReplaceVarsNoMatchOption nomatch_option, int nomatch_varno, bool *outer_hasSubLinks)
bool hasSubLinks
Definition: parsenodes.h:136
void ChangeVarNodes(Node *node, int rt_index, int new_index, int sublevels_up)
Definition: rewriteManip.c:610
#define copyObject(obj)
Definition: nodes.h:655
#define PRS2_NEW_VARNO
Definition: primnodes.h:184

◆ fill_extraUpdatedCols()

void fill_extraUpdatedCols ( RangeTblEntry target_rte,
Relation  target_relation 
)

Definition at line 1611 of file rewriteHandler.c.

References AttrDefault::adbin, AttrDefault::adnum, bms_add_member(), bms_overlap(), TupleDescData::constr, TupleConstr::defval, RangeTblEntry::extraUpdatedCols, FirstLowInvalidHeapAttributeNumber, TupleConstr::has_generated_stored, i, TupleConstr::num_defval, pull_varattnos(), RelationGetDescr, stringToNode(), TupleDescAttr, and RangeTblEntry::updatedCols.

Referenced by apply_handle_update(), and RewriteQuery().

1612 {
1613  TupleDesc tupdesc = RelationGetDescr(target_relation);
1614  TupleConstr *constr = tupdesc->constr;
1615 
1616  target_rte->extraUpdatedCols = NULL;
1617 
1618  if (constr && constr->has_generated_stored)
1619  {
1620  for (int i = 0; i < constr->num_defval; i++)
1621  {
1622  AttrDefault *defval = &constr->defval[i];
1623  Node *expr;
1624  Bitmapset *attrs_used = NULL;
1625 
1626  /* skip if not generated column */
1627  if (!TupleDescAttr(tupdesc, defval->adnum - 1)->attgenerated)
1628  continue;
1629 
1630  /* identify columns this generated column depends on */
1631  expr = stringToNode(defval->adbin);
1632  pull_varattnos(expr, 1, &attrs_used);
1633 
1634  if (bms_overlap(target_rte->updatedCols, attrs_used))
1635  target_rte->extraUpdatedCols =
1636  bms_add_member(target_rte->extraUpdatedCols,
1638  }
1639  }
1640 }
#define RelationGetDescr(relation)
Definition: rel.h:483
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
Definition: nodes.h:539
void * stringToNode(const char *str)
Definition: read.c:89
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
void pull_varattnos(Node *node, Index varno, Bitmapset **varattnos)
Definition: var.c:246
AttrDefault * defval
Definition: tupdesc.h:39
bool has_generated_stored
Definition: tupdesc.h:45
Bitmapset * extraUpdatedCols
Definition: parsenodes.h:1150
TupleConstr * constr
Definition: tupdesc.h:85
Bitmapset * updatedCols
Definition: parsenodes.h:1149
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:736
bool bms_overlap(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:494
uint16 num_defval
Definition: tupdesc.h:42
int i
AttrNumber adnum
Definition: tupdesc.h:24
char * adbin
Definition: tupdesc.h:25

◆ findDefaultOnlyColumns()

static Bitmapset * findDefaultOnlyColumns ( RangeTblEntry rte)
static

Definition at line 1322 of file rewriteHandler.c.

References bms_add_member(), bms_del_member(), bms_is_empty(), i, IsA, lfirst, and RangeTblEntry::values_lists.

Referenced by rewriteTargetListIU().

1323 {
1324  Bitmapset *default_only_cols = NULL;
1325  ListCell *lc;
1326 
1327  foreach(lc, rte->values_lists)
1328  {
1329  List *sublist = (List *) lfirst(lc);
1330  ListCell *lc2;
1331  int i;
1332 
1333  if (default_only_cols == NULL)
1334  {
1335  /* Populate the initial result bitmap from the first row */
1336  i = 0;
1337  foreach(lc2, sublist)
1338  {
1339  Node *col = (Node *) lfirst(lc2);
1340 
1341  i++;
1342  if (IsA(col, SetToDefault))
1343  default_only_cols = bms_add_member(default_only_cols, i);
1344  }
1345  }
1346  else
1347  {
1348  /* Update the result bitmap from this next row */
1349  i = 0;
1350  foreach(lc2, sublist)
1351  {
1352  Node *col = (Node *) lfirst(lc2);
1353 
1354  i++;
1355  if (!IsA(col, SetToDefault))
1356  default_only_cols = bms_del_member(default_only_cols, i);
1357  }
1358  }
1359 
1360  /*
1361  * If no column in the rows read so far contains only DEFAULT items,
1362  * we are done.
1363  */
1364  if (bms_is_empty(default_only_cols))
1365  break;
1366  }
1367 
1368  return default_only_cols;
1369 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
Definition: nodes.h:539
List * values_lists
Definition: parsenodes.h:1100
bool bms_is_empty(const Bitmapset *a)
Definition: bitmapset.c:701
#define lfirst(lc)
Definition: pg_list.h:169
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:736
int i
Bitmapset * bms_del_member(Bitmapset *a, int x)
Definition: bitmapset.c:773
Definition: pg_list.h:50

◆ fireRIRonSubLink()

static bool fireRIRonSubLink ( Node node,
List activeRIRs 
)
static

Definition at line 1958 of file rewriteHandler.c.

References expression_tree_walker(), fireRIRrules(), IsA, and SubLink::subselect.

Referenced by fireRIRrules().

1959 {
1960  if (node == NULL)
1961  return false;
1962  if (IsA(node, SubLink))
1963  {
1964  SubLink *sub = (SubLink *) node;
1965 
1966  /* Do what we came for */
1967  sub->subselect = (Node *) fireRIRrules((Query *) sub->subselect,
1968  activeRIRs);
1969  /* Fall through to process lefthand args of SubLink */
1970  }
1971 
1972  /*
1973  * Do NOT recurse into Query nodes, because fireRIRrules already processed
1974  * subselects of subselects for us.
1975  */
1977  (void *) activeRIRs);
1978 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
Definition: nodes.h:539
static bool fireRIRonSubLink(Node *node, List *activeRIRs)
bool expression_tree_walker(Node *node, bool(*walker)(), void *context)
Definition: nodeFuncs.c:1904
static Query * fireRIRrules(Query *parsetree, List *activeRIRs)

◆ fireRIRrules()

static Query * fireRIRrules ( Query parsetree,
List activeRIRs 
)
static

Definition at line 1989 of file rewriteHandler.c.

References acquireLocksOnSubLinks(), ApplyRetrieveRule(), CMD_SELECT, Query::cteList, CommonTableExpr::ctequery, CommonTableExpr::cycle_clause, ereport, errcode(), errmsg(), ERROR, RewriteRule::event, OnConflictExpr::exclRelIndex, expression_tree_walker(), fireRIRonSubLink(), acquireLocksOnSubLinks_context::for_execute, get_row_security_policies(), Query::hasRowSecurity, Query::hasSubLinks, i, lappend(), lappend_oid(), lfirst, lfirst_node, list_concat(), list_delete_last(), list_length(), list_member_oid(), NIL, NoLock, RuleLock::numLocks, Query::onConflict, QTW_IGNORE_RC_SUBQUERIES, query_tree_walker(), rangeTableEntry_used(), RelationData::rd_rules, RelationGetRelationName, RelationGetRelid, RangeTblEntry::relid, RangeTblEntry::relkind, Query::resultRelation, rewriteSearchAndCycle(), rt_fetch, Query::rtable, RTE_RELATION, RTE_SUBQUERY, RangeTblEntry::rtekind, RuleLock::rules, rules, CommonTableExpr::search_clause, RangeTblEntry::securityQuals, RangeTblEntry::subquery, table_close(), table_open(), and Query::withCheckOptions.

Referenced by ApplyRetrieveRule(), fireRIRonSubLink(), and QueryRewrite().

1990 {
1991  int origResultRelation = parsetree->resultRelation;
1992  int rt_index;
1993  ListCell *lc;
1994 
1995  /*
1996  * Expand SEARCH and CYCLE clauses in CTEs.
1997  *
1998  * This is just a convenient place to do this, since we are already
1999  * looking at each Query.
2000  */
2001  foreach(lc, parsetree->cteList)
2002  {
2004 
2005  if (cte->search_clause || cte->cycle_clause)
2006  {
2007  cte = rewriteSearchAndCycle(cte);
2008  lfirst(lc) = cte;
2009  }
2010  }
2011 
2012  /*
2013  * don't try to convert this into a foreach loop, because rtable list can
2014  * get changed each time through...
2015  */
2016  rt_index = 0;
2017  while (rt_index < list_length(parsetree->rtable))
2018  {
2019  RangeTblEntry *rte;
2020  Relation rel;
2021  List *locks;
2022  RuleLock *rules;
2023  RewriteRule *rule;
2024  int i;
2025 
2026  ++rt_index;
2027 
2028  rte = rt_fetch(rt_index, parsetree->rtable);
2029 
2030  /*
2031  * A subquery RTE can't have associated rules, so there's nothing to
2032  * do to this level of the query, but we must recurse into the
2033  * subquery to expand any rule references in it.
2034  */
2035  if (rte->rtekind == RTE_SUBQUERY)
2036  {
2037  rte->subquery = fireRIRrules(rte->subquery, activeRIRs);
2038  continue;
2039  }
2040 
2041  /*
2042  * Joins and other non-relation RTEs can be ignored completely.
2043  */
2044  if (rte->rtekind != RTE_RELATION)
2045  continue;
2046 
2047  /*
2048  * Always ignore RIR rules for materialized views referenced in
2049  * queries. (This does not prevent refreshing MVs, since they aren't
2050  * referenced in their own query definitions.)
2051  *
2052  * Note: in the future we might want to allow MVs to be conditionally
2053  * expanded as if they were regular views, if they are not scannable.
2054  * In that case this test would need to be postponed till after we've
2055  * opened the rel, so that we could check its state.
2056  */
2057  if (rte->relkind == RELKIND_MATVIEW)
2058  continue;
2059 
2060  /*
2061  * In INSERT ... ON CONFLICT, ignore the EXCLUDED pseudo-relation;
2062  * even if it points to a view, we needn't expand it, and should not
2063  * because we want the RTE to remain of RTE_RELATION type. Otherwise,
2064  * it would get changed to RTE_SUBQUERY type, which is an
2065  * untested/unsupported situation.
2066  */
2067  if (parsetree->onConflict &&
2068  rt_index == parsetree->onConflict->exclRelIndex)
2069  continue;
2070 
2071  /*
2072  * If the table is not referenced in the query, then we ignore it.
2073  * This prevents infinite expansion loop due to new rtable entries
2074  * inserted by expansion of a rule. A table is referenced if it is
2075  * part of the join set (a source table), or is referenced by any Var
2076  * nodes, or is the result table.
2077  */
2078  if (rt_index != parsetree->resultRelation &&
2079  !rangeTableEntry_used((Node *) parsetree, rt_index, 0))
2080  continue;
2081 
2082  /*
2083  * Also, if this is a new result relation introduced by
2084  * ApplyRetrieveRule, we don't want to do anything more with it.
2085  */
2086  if (rt_index == parsetree->resultRelation &&
2087  rt_index != origResultRelation)
2088  continue;
2089 
2090  /*
2091  * We can use NoLock here since either the parser or
2092  * AcquireRewriteLocks should have locked the rel already.
2093  */
2094  rel = table_open(rte->relid, NoLock);
2095 
2096  /*
2097  * Collect the RIR rules that we must apply
2098  */
2099  rules = rel->rd_rules;
2100  if (rules != NULL)
2101  {
2102  locks = NIL;
2103  for (i = 0; i < rules->numLocks; i++)
2104  {
2105  rule = rules->rules[i];
2106  if (rule->event != CMD_SELECT)
2107  continue;
2108 
2109  locks = lappend(locks, rule);
2110  }
2111 
2112  /*
2113  * If we found any, apply them --- but first check for recursion!
2114  */
2115  if (locks != NIL)
2116  {
2117  ListCell *l;
2118 
2119  if (list_member_oid(activeRIRs, RelationGetRelid(rel)))
2120  ereport(ERROR,
2121  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2122  errmsg("infinite recursion detected in rules for relation \"%s\"",
2123  RelationGetRelationName(rel))));
2124  activeRIRs = lappend_oid(activeRIRs, RelationGetRelid(rel));
2125 
2126  foreach(l, locks)
2127  {
2128  rule = lfirst(l);
2129 
2130  parsetree = ApplyRetrieveRule(parsetree,
2131  rule,
2132  rt_index,
2133  rel,
2134  activeRIRs);
2135  }
2136 
2137  activeRIRs = list_delete_last(activeRIRs);
2138  }
2139  }
2140 
2141  table_close(rel, NoLock);
2142  }
2143 
2144  /* Recurse into subqueries in WITH */
2145  foreach(lc, parsetree->cteList)
2146  {
2147  CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
2148 
2149  cte->ctequery = (Node *)
2150  fireRIRrules((Query *) cte->ctequery, activeRIRs);
2151  }
2152 
2153  /*
2154  * Recurse into sublink subqueries, too. But we already did the ones in
2155  * the rtable and cteList.
2156  */
2157  if (parsetree->hasSubLinks)
2158  query_tree_walker(parsetree, fireRIRonSubLink, (void *) activeRIRs,
2160 
2161  /*
2162  * Apply any row-level security policies. We do this last because it
2163  * requires special recursion detection if the new quals have sublink
2164  * subqueries, and if we did it in the loop above query_tree_walker would
2165  * then recurse into those quals a second time.
2166  */
2167  rt_index = 0;
2168  foreach(lc, parsetree->rtable)
2169  {
2170  RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
2171  Relation rel;
2172  List *securityQuals;
2173  List *withCheckOptions;
2174  bool hasRowSecurity;
2175  bool hasSubLinks;
2176 
2177  ++rt_index;
2178 
2179  /* Only normal relations can have RLS policies */
2180  if (rte->rtekind != RTE_RELATION ||
2181  (rte->relkind != RELKIND_RELATION &&
2182  rte->relkind != RELKIND_PARTITIONED_TABLE))
2183  continue;
2184 
2185  rel = table_open(rte->relid, NoLock);
2186 
2187  /*
2188  * Fetch any new security quals that must be applied to this RTE.
2189  */
2190  get_row_security_policies(parsetree, rte, rt_index,
2191  &securityQuals, &withCheckOptions,
2192  &hasRowSecurity, &hasSubLinks);
2193 
2194  if (securityQuals != NIL || withCheckOptions != NIL)
2195  {
2196  if (hasSubLinks)
2197  {
2199 
2200  /*
2201  * Recursively process the new quals, checking for infinite
2202  * recursion.
2203  */
2204  if (list_member_oid(activeRIRs, RelationGetRelid(rel)))
2205  ereport(ERROR,
2206  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2207  errmsg("infinite recursion detected in policy for relation \"%s\"",
2208  RelationGetRelationName(rel))));
2209 
2210  activeRIRs = lappend_oid(activeRIRs, RelationGetRelid(rel));
2211 
2212  /*
2213  * get_row_security_policies just passed back securityQuals
2214  * and/or withCheckOptions, and there were SubLinks, make sure
2215  * we lock any relations which are referenced.
2216  *
2217  * These locks would normally be acquired by the parser, but
2218  * securityQuals and withCheckOptions are added post-parsing.
2219  */
2220  context.for_execute = true;
2221  (void) acquireLocksOnSubLinks((Node *) securityQuals, &context);
2222  (void) acquireLocksOnSubLinks((Node *) withCheckOptions,
2223  &context);
2224 
2225  /*
2226  * Now that we have the locks on anything added by
2227  * get_row_security_policies, fire any RIR rules for them.
2228  */
2229  expression_tree_walker((Node *) securityQuals,
2230  fireRIRonSubLink, (void *) activeRIRs);
2231 
2232  expression_tree_walker((Node *) withCheckOptions,
2233  fireRIRonSubLink, (void *) activeRIRs);
2234 
2235  activeRIRs = list_delete_last(activeRIRs);
2236  }
2237 
2238  /*
2239  * Add the new security barrier quals to the start of the RTE's
2240  * list so that they get applied before any existing barrier quals
2241  * (which would have come from a security-barrier view, and should
2242  * get lower priority than RLS conditions on the table itself).
2243  */
2244  rte->securityQuals = list_concat(securityQuals,
2245  rte->securityQuals);
2246 
2247  parsetree->withCheckOptions = list_concat(withCheckOptions,
2248  parsetree->withCheckOptions);
2249  }
2250 
2251  /*
2252  * Make sure the query is marked correctly if row-level security
2253  * applies, or if the new quals had sublinks.
2254  */
2255  if (hasRowSecurity)
2256  parsetree->hasRowSecurity = true;
2257  if (hasSubLinks)
2258  parsetree->hasSubLinks = true;
2259 
2260  table_close(rel, NoLock);
2261  }
2262 
2263  return parsetree;
2264 }
#define NIL
Definition: pg_list.h:65
bool query_tree_walker(Query *query, bool(*walker)(), void *context, int flags)
Definition: nodeFuncs.c:2355
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
int numLocks
Definition: prs2lock.h:42
CommonTableExpr * rewriteSearchAndCycle(CommonTableExpr *cte)
static bool acquireLocksOnSubLinks(Node *node, acquireLocksOnSubLinks_context *context)
static Query * ApplyRetrieveRule(Query *parsetree, RewriteRule *rule, int rt_index, Relation relation, List *activeRIRs)
OnConflictExpr * onConflict
Definition: parsenodes.h:154
void get_row_security_policies(Query *root, RangeTblEntry *rte, int rt_index, List **securityQuals, List **withCheckOptions, bool *hasRowSecurity, bool *hasSubLinks)
Definition: rowsecurity.c:108
List * securityQuals
Definition: parsenodes.h:1151
int resultRelation
Definition: parsenodes.h:130
Definition: nodes.h:539
List * list_concat(List *list1, const List *list2)
Definition: list.c:530
int errcode(int sqlerrcode)
Definition: elog.c:698
List * lappend_oid(List *list, Oid datum)
Definition: list.c:372
Definition: localtime.c:72
#define QTW_IGNORE_RC_SUBQUERIES
Definition: nodeFuncs.h:22
List * rtable
Definition: parsenodes.h:147
#define ERROR
Definition: elog.h:46
CTESearchClause * search_clause
Definition: parsenodes.h:1505
static bool fireRIRonSubLink(Node *node, List *activeRIRs)
#define lfirst_node(type, lc)
Definition: pg_list.h:172
#define NoLock
Definition: lockdefs.h:34
CmdType event
Definition: prs2lock.h:27
List * list_delete_last(List *list)
Definition: list.c:892
static struct rule * rules
Definition: zic.c:281
#define RelationGetRelationName(relation)
Definition: rel.h:491
RewriteRule ** rules
Definition: prs2lock.h:43
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
List * lappend(List *list, void *datum)
Definition: list.c:336
#define ereport(elevel,...)
Definition: elog.h:157
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:689
#define lfirst(lc)
Definition: pg_list.h:169
RuleLock * rd_rules
Definition: rel.h:114
bool expression_tree_walker(Node *node, bool(*walker)(), void *context)
Definition: nodeFuncs.c:1904
static int list_length(const List *l)
Definition: pg_list.h:149
RTEKind rtekind
Definition: parsenodes.h:995
List * cteList
Definition: parsenodes.h:145
CTECycleClause * cycle_clause
Definition: parsenodes.h:1506
Query * subquery
Definition: parsenodes.h:1030
int errmsg(const char *fmt,...)
Definition: elog.c:909
int i
bool rangeTableEntry_used(Node *node, int rt_index, int sublevels_up)
Definition: rewriteManip.c:892
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
static Query * fireRIRrules(Query *parsetree, List *activeRIRs)
Definition: pg_list.h:50
#define RelationGetRelid(relation)
Definition: rel.h:457

◆ fireRules()

static List* fireRules ( Query parsetree,
int  rt_index,
CmdType  event,
List locks,
bool instead_flag,
bool returning_flag,
Query **  qual_product 
)
static

Definition at line 2351 of file rewriteHandler.c.

References RewriteRule::actions, Query::canSetTag, CMD_NOTHING, Query::commandType, CopyAndAddInvertedQual(), copyObject, RewriteRule::isInstead, lappend(), lfirst, NIL, QSRC_INSTEAD_RULE, QSRC_NON_INSTEAD_RULE, QSRC_QUAL_INSTEAD_RULE, RewriteRule::qual, Query::querySource, and rewriteRuleAction().

Referenced by RewriteQuery().

2358 {
2359  List *results = NIL;
2360  ListCell *l;
2361 
2362  foreach(l, locks)
2363  {
2364  RewriteRule *rule_lock = (RewriteRule *) lfirst(l);
2365  Node *event_qual = rule_lock->qual;
2366  List *actions = rule_lock->actions;
2367  QuerySource qsrc;
2368  ListCell *r;
2369 
2370  /* Determine correct QuerySource value for actions */
2371  if (rule_lock->isInstead)
2372  {
2373  if (event_qual != NULL)
2374  qsrc = QSRC_QUAL_INSTEAD_RULE;
2375  else
2376  {
2377  qsrc = QSRC_INSTEAD_RULE;
2378  *instead_flag = true; /* report unqualified INSTEAD */
2379  }
2380  }
2381  else
2382  qsrc = QSRC_NON_INSTEAD_RULE;
2383 
2384  if (qsrc == QSRC_QUAL_INSTEAD_RULE)
2385  {
2386  /*
2387  * If there are INSTEAD rules with qualifications, the original
2388  * query is still performed. But all the negated rule
2389  * qualifications of the INSTEAD rules are added so it does its
2390  * actions only in cases where the rule quals of all INSTEAD rules
2391  * are false. Think of it as the default action in a case. We save
2392  * this in *qual_product so RewriteQuery() can add it to the query
2393  * list after we mangled it up enough.
2394  *
2395  * If we have already found an unqualified INSTEAD rule, then
2396  * *qual_product won't be used, so don't bother building it.
2397  */
2398  if (!*instead_flag)
2399  {
2400  if (*qual_product == NULL)
2401  *qual_product = copyObject(parsetree);
2402  *qual_product = CopyAndAddInvertedQual(*qual_product,
2403  event_qual,
2404  rt_index,
2405  event);
2406  }
2407  }
2408 
2409  /* Now process the rule's actions and add them to the result list */
2410  foreach(r, actions)
2411  {
2412  Query *rule_action = lfirst(r);
2413 
2414  if (rule_action->commandType == CMD_NOTHING)
2415  continue;
2416 
2417  rule_action = rewriteRuleAction(parsetree, rule_action,
2418  event_qual, rt_index, event,
2419  returning_flag);
2420 
2421  rule_action->querySource = qsrc;
2422  rule_action->canSetTag = false; /* might change later */
2423 
2424  results = lappend(results, rule_action);
2425  }
2426  }
2427 
2428  return results;
2429 }
#define NIL
Definition: pg_list.h:65
Node * qual
Definition: prs2lock.h:28
QuerySource
Definition: parsenodes.h:40
Definition: nodes.h:539
bool isInstead
Definition: prs2lock.h:31
static Query * CopyAndAddInvertedQual(Query *parsetree, Node *rule_qual, int rt_index, CmdType event)
List * actions
Definition: prs2lock.h:29
List * lappend(List *list, void *datum)
Definition: list.c:336
CmdType commandType
Definition: parsenodes.h:120
QuerySource querySource
Definition: parsenodes.h:122
#define lfirst(lc)
Definition: pg_list.h:169
bool canSetTag
Definition: parsenodes.h:126
static Query * rewriteRuleAction(Query *parsetree, Query *rule_action, Node *rule_qual, int rt_index, CmdType event, bool *returning_flag)
#define copyObject(obj)
Definition: nodes.h:655
Definition: pg_list.h:50

◆ get_assignment_input()

static Node * get_assignment_input ( Node node)
static

Definition at line 1182 of file rewriteHandler.c.

References FieldStore::arg, IsA, SubscriptingRef::refassgnexpr, and SubscriptingRef::refexpr.

Referenced by process_matched_tle().

1183 {
1184  if (node == NULL)
1185  return NULL;
1186  if (IsA(node, FieldStore))
1187  {
1188  FieldStore *fstore = (FieldStore *) node;
1189 
1190  return (Node *) fstore->arg;
1191  }
1192  else if (IsA(node, SubscriptingRef))
1193  {
1194  SubscriptingRef *sbsref = (SubscriptingRef *) node;
1195 
1196  if (sbsref->refassgnexpr == NULL)
1197  return NULL;
1198 
1199  return (Node *) sbsref->refexpr;
1200  }
1201 
1202  return NULL;
1203 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
Expr * arg
Definition: primnodes.h:827
Definition: nodes.h:539
Expr * refassgnexpr
Definition: primnodes.h:451
Expr * refexpr
Definition: primnodes.h:449

◆ get_view_query()

Query* get_view_query ( Relation  view)

Definition at line 2442 of file rewriteHandler.c.

References RewriteRule::actions, Assert, CMD_SELECT, elog, ERROR, RewriteRule::event, i, linitial, list_length(), RuleLock::numLocks, RelationData::rd_rel, RelationData::rd_rules, and RuleLock::rules.

Referenced by ATExecSetRelOptions(), LockViewRecurse(), relation_is_updatable(), and rewriteTargetView().

2443 {
2444  int i;
2445 
2446  Assert(view->rd_rel->relkind == RELKIND_VIEW);
2447 
2448  for (i = 0; i < view->rd_rules->numLocks; i++)
2449  {
2450  RewriteRule *rule = view->rd_rules->rules[i];
2451 
2452  if (rule->event == CMD_SELECT)
2453  {
2454  /* A _RETURN rule should have only one action */
2455  if (list_length(rule->actions) != 1)
2456  elog(ERROR, "invalid _RETURN rule action specification");
2457 
2458  return (Query *) linitial(rule->actions);
2459  }
2460  }
2461 
2462  elog(ERROR, "failed to find _RETURN rule for view");
2463  return NULL; /* keep compiler quiet */
2464 }
int numLocks
Definition: prs2lock.h:42
Form_pg_class rd_rel
Definition: rel.h:110
Definition: localtime.c:72
#define linitial(l)
Definition: pg_list.h:174
#define ERROR
Definition: elog.h:46
CmdType event
Definition: prs2lock.h:27
RewriteRule ** rules
Definition: prs2lock.h:43
List * actions
Definition: prs2lock.h:29
#define Assert(condition)
Definition: c.h:804
RuleLock * rd_rules
Definition: rel.h:114
static int list_length(const List *l)
Definition: pg_list.h:149
#define elog(elevel,...)
Definition: elog.h:232
int i

◆ markQueryForLocking()

static void markQueryForLocking ( Query qry,
Node jtnode,
LockClauseStrength  strength,
LockWaitPolicy  waitPolicy,
bool  pushedDown 
)
static

Definition at line 1898 of file rewriteHandler.c.

References ACL_SELECT_FOR_UPDATE, applyLockingClause(), elog, ERROR, FromExpr::fromlist, IsA, Query::jointree, JoinExpr::larg, lfirst, nodeTag, JoinExpr::rarg, RangeTblEntry::requiredPerms, rt_fetch, Query::rtable, RTE_RELATION, RTE_SUBQUERY, RangeTblEntry::rtekind, and RangeTblEntry::subquery.

Referenced by ApplyRetrieveRule().

1901 {
1902  if (jtnode == NULL)
1903  return;
1904  if (IsA(jtnode, RangeTblRef))
1905  {
1906  int rti = ((RangeTblRef *) jtnode)->rtindex;
1907  RangeTblEntry *rte = rt_fetch(rti, qry->rtable);
1908 
1909  if (rte->rtekind == RTE_RELATION)
1910  {
1911  applyLockingClause(qry, rti, strength, waitPolicy, pushedDown);
1913  }
1914  else if (rte->rtekind == RTE_SUBQUERY)
1915  {
1916  applyLockingClause(qry, rti, strength, waitPolicy, pushedDown);
1917  /* FOR UPDATE/SHARE of subquery is propagated to subquery's rels */
1919  strength, waitPolicy, true);
1920  }
1921  /* other RTE types are unaffected by FOR UPDATE */
1922  }
1923  else if (IsA(jtnode, FromExpr))
1924  {
1925  FromExpr *f = (FromExpr *) jtnode;
1926  ListCell *l;
1927 
1928  foreach(l, f->fromlist)
1929  markQueryForLocking(qry, lfirst(l), strength, waitPolicy, pushedDown);
1930  }
1931  else if (IsA(jtnode, JoinExpr))
1932  {
1933  JoinExpr *j = (JoinExpr *) jtnode;
1934 
1935  markQueryForLocking(qry, j->larg, strength, waitPolicy, pushedDown);
1936  markQueryForLocking(qry, j->rarg, strength, waitPolicy, pushedDown);
1937  }
1938  else
1939  elog(ERROR, "unrecognized node type: %d",
1940  (int) nodeTag(jtnode));
1941 }
static void markQueryForLocking(Query *qry, Node *jtnode, LockClauseStrength strength, LockWaitPolicy waitPolicy, bool pushedDown)
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
FromExpr * jointree
Definition: parsenodes.h:148
Definition: nodes.h:539
AclMode requiredPerms
Definition: parsenodes.h:1145
List * fromlist
Definition: primnodes.h:1553
Node * larg
Definition: primnodes.h:1532
List * rtable
Definition: parsenodes.h:147
#define ERROR
Definition: elog.h:46
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
Node * rarg
Definition: primnodes.h:1533
#define lfirst(lc)
Definition: pg_list.h:169
#define ACL_SELECT_FOR_UPDATE
Definition: parsenodes.h:98
#define nodeTag(nodeptr)
Definition: nodes.h:544
RTEKind rtekind
Definition: parsenodes.h:995
Query * subquery
Definition: parsenodes.h:1030
#define elog(elevel,...)
Definition: elog.h:232
void applyLockingClause(Query *qry, Index rtindex, LockClauseStrength strength, LockWaitPolicy waitPolicy, bool pushedDown)
Definition: analyze.c:3242

◆ matchLocks()

static List * matchLocks ( CmdType  event,
RuleLock rulelocks,
int  varno,
Query parsetree,
bool hasUpdate 
)
static

Definition at line 1648 of file rewriteHandler.c.

References CMD_SELECT, CMD_UPDATE, Query::commandType, RewriteRule::enabled, RewriteRule::event, i, lappend(), NIL, RuleLock::numLocks, rangeTableEntry_used(), Query::resultRelation, RULE_DISABLED, RULE_FIRES_ON_ORIGIN, RULE_FIRES_ON_REPLICA, RuleLock::rules, SESSION_REPLICATION_ROLE_REPLICA, and SessionReplicationRole.

Referenced by RewriteQuery(), and rewriteValuesRTE().

1653 {
1654  List *matching_locks = NIL;
1655  int nlocks;
1656  int i;
1657 
1658  if (rulelocks == NULL)
1659  return NIL;
1660 
1661  if (parsetree->commandType != CMD_SELECT)
1662  {
1663  if (parsetree->resultRelation != varno)
1664  return NIL;
1665  }
1666 
1667  nlocks = rulelocks->numLocks;
1668 
1669  for (i = 0; i < nlocks; i++)
1670  {
1671  RewriteRule *oneLock = rulelocks->rules[i];
1672 
1673  if (oneLock->event == CMD_UPDATE)
1674  *hasUpdate = true;
1675 
1676  /*
1677  * Suppress ON INSERT/UPDATE/DELETE rules that are disabled or
1678  * configured to not fire during the current sessions replication
1679  * role. ON SELECT rules will always be applied in order to keep views
1680  * working even in LOCAL or REPLICA role.
1681  */
1682  if (oneLock->event != CMD_SELECT)
1683  {
1685  {
1686  if (oneLock->enabled == RULE_FIRES_ON_ORIGIN ||
1687  oneLock->enabled == RULE_DISABLED)
1688  continue;
1689  }
1690  else /* ORIGIN or LOCAL ROLE */
1691  {
1692  if (oneLock->enabled == RULE_FIRES_ON_REPLICA ||
1693  oneLock->enabled == RULE_DISABLED)
1694  continue;
1695  }
1696  }
1697 
1698  if (oneLock->event == event)
1699  {
1700  if (parsetree->commandType != CMD_SELECT ||
1701  rangeTableEntry_used((Node *) parsetree, varno, 0))
1702  matching_locks = lappend(matching_locks, oneLock);
1703  }
1704  }
1705 
1706  return matching_locks;
1707 }
#define NIL
Definition: pg_list.h:65
int numLocks
Definition: prs2lock.h:42
int resultRelation
Definition: parsenodes.h:130
Definition: nodes.h:539
int SessionReplicationRole
Definition: trigger.c:68
CmdType event
Definition: prs2lock.h:27
RewriteRule ** rules
Definition: prs2lock.h:43
#define RULE_DISABLED
Definition: rewriteDefine.h:24
List * lappend(List *list, void *datum)
Definition: list.c:336
#define RULE_FIRES_ON_ORIGIN
Definition: rewriteDefine.h:21
#define SESSION_REPLICATION_ROLE_REPLICA
Definition: trigger.h:140
#define RULE_FIRES_ON_REPLICA
Definition: rewriteDefine.h:23
CmdType commandType
Definition: parsenodes.h:120
int i
bool rangeTableEntry_used(Node *node, int rt_index, int sublevels_up)
Definition: rewriteManip.c:892
Definition: pg_list.h:50
char enabled
Definition: prs2lock.h:30

◆ process_matched_tle()

static TargetEntry * process_matched_tle ( TargetEntry src_tle,
TargetEntry prior_tle,
const char *  attrName 
)
static

Definition at line 1029 of file rewriteHandler.c.

References arg, FieldStore::arg, CoerceToDomain::arg, elog, equal(), ereport, errcode(), errmsg(), ERROR, TargetEntry::expr, exprType(), FieldStore::fieldnums, flatCopyTargetEntry(), get_assignment_input(), IsA, list_concat_copy(), makeNode, FieldStore::newvals, and SubscriptingRef::refexpr.

Referenced by rewriteTargetListIU().

1032 {
1033  TargetEntry *result;
1034  CoerceToDomain *coerce_expr = NULL;
1035  Node *src_expr;
1036  Node *prior_expr;
1037  Node *src_input;
1038  Node *prior_input;
1039  Node *priorbottom;
1040  Node *newexpr;
1041 
1042  if (prior_tle == NULL)
1043  {
1044  /*
1045  * Normal case where this is the first assignment to the attribute.
1046  */
1047  return src_tle;
1048  }
1049 
1050  /*----------
1051  * Multiple assignments to same attribute. Allow only if all are
1052  * FieldStore or SubscriptingRef assignment operations. This is a bit
1053  * tricky because what we may actually be looking at is a nest of
1054  * such nodes; consider
1055  * UPDATE tab SET col.fld1.subfld1 = x, col.fld2.subfld2 = y
1056  * The two expressions produced by the parser will look like
1057  * FieldStore(col, fld1, FieldStore(placeholder, subfld1, x))
1058  * FieldStore(col, fld2, FieldStore(placeholder, subfld2, y))
1059  * However, we can ignore the substructure and just consider the top
1060  * FieldStore or SubscriptingRef from each assignment, because it works to
1061  * combine these as
1062  * FieldStore(FieldStore(col, fld1,
1063  * FieldStore(placeholder, subfld1, x)),
1064  * fld2, FieldStore(placeholder, subfld2, y))
1065  * Note the leftmost expression goes on the inside so that the
1066  * assignments appear to occur left-to-right.
1067  *
1068  * For FieldStore, instead of nesting we can generate a single
1069  * FieldStore with multiple target fields. We must nest when
1070  * SubscriptingRefs are involved though.
1071  *
1072  * As a further complication, the destination column might be a domain,
1073  * resulting in each assignment containing a CoerceToDomain node over a
1074  * FieldStore or SubscriptingRef. These should have matching target
1075  * domains, so we strip them and reconstitute a single CoerceToDomain over
1076  * the combined FieldStore/SubscriptingRef nodes. (Notice that this has the
1077  * result that the domain's checks are applied only after we do all the
1078  * field or element updates, not after each one. This is arguably desirable.)
1079  *----------
1080  */
1081  src_expr = (Node *) src_tle->expr;
1082  prior_expr = (Node *) prior_tle->expr;
1083 
1084  if (src_expr && IsA(src_expr, CoerceToDomain) &&
1085  prior_expr && IsA(prior_expr, CoerceToDomain) &&
1086  ((CoerceToDomain *) src_expr)->resulttype ==
1087  ((CoerceToDomain *) prior_expr)->resulttype)
1088  {
1089  /* we assume without checking that resulttypmod/resultcollid match */
1090  coerce_expr = (CoerceToDomain *) src_expr;
1091  src_expr = (Node *) ((CoerceToDomain *) src_expr)->arg;
1092  prior_expr = (Node *) ((CoerceToDomain *) prior_expr)->arg;
1093  }
1094 
1095  src_input = get_assignment_input(src_expr);
1096  prior_input = get_assignment_input(prior_expr);
1097  if (src_input == NULL ||
1098  prior_input == NULL ||
1099  exprType(src_expr) != exprType(prior_expr))
1100  ereport(ERROR,
1101  (errcode(ERRCODE_SYNTAX_ERROR),
1102  errmsg("multiple assignments to same column \"%s\"",
1103  attrName)));
1104 
1105  /*
1106  * Prior TLE could be a nest of assignments if we do this more than once.
1107  */
1108  priorbottom = prior_input;
1109  for (;;)
1110  {
1111  Node *newbottom = get_assignment_input(priorbottom);
1112 
1113  if (newbottom == NULL)
1114  break; /* found the original Var reference */
1115  priorbottom = newbottom;
1116  }
1117  if (!equal(priorbottom, src_input))
1118  ereport(ERROR,
1119  (errcode(ERRCODE_SYNTAX_ERROR),
1120  errmsg("multiple assignments to same column \"%s\"",
1121  attrName)));
1122 
1123  /*
1124  * Looks OK to nest 'em.
1125  */
1126  if (IsA(src_expr, FieldStore))
1127  {
1128  FieldStore *fstore = makeNode(FieldStore);
1129 
1130  if (IsA(prior_expr, FieldStore))
1131  {
1132  /* combine the two */
1133  memcpy(fstore, prior_expr, sizeof(FieldStore));
1134  fstore->newvals =
1135  list_concat_copy(((FieldStore *) prior_expr)->newvals,
1136  ((FieldStore *) src_expr)->newvals);
1137  fstore->fieldnums =
1138  list_concat_copy(((FieldStore *) prior_expr)->fieldnums,
1139  ((FieldStore *) src_expr)->fieldnums);
1140  }
1141  else
1142  {
1143  /* general case, just nest 'em */
1144  memcpy(fstore, src_expr, sizeof(FieldStore));
1145  fstore->arg = (Expr *) prior_expr;
1146  }
1147  newexpr = (Node *) fstore;
1148  }
1149  else if (IsA(src_expr, SubscriptingRef))
1150  {
1152 
1153  memcpy(sbsref, src_expr, sizeof(SubscriptingRef));
1154  sbsref->refexpr = (Expr *) prior_expr;
1155  newexpr = (Node *) sbsref;
1156  }
1157  else
1158  {
1159  elog(ERROR, "cannot happen");
1160  newexpr = NULL;
1161  }
1162 
1163  if (coerce_expr)
1164  {
1165  /* put back the CoerceToDomain */
1166  CoerceToDomain *newcoerce = makeNode(CoerceToDomain);
1167 
1168  memcpy(newcoerce, coerce_expr, sizeof(CoerceToDomain));
1169  newcoerce->arg = (Expr *) newexpr;
1170  newexpr = (Node *) newcoerce;
1171  }
1172 
1173  result = flatCopyTargetEntry(src_tle);
1174  result->expr = (Expr *) newexpr;
1175  return result;
1176 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
Expr * arg
Definition: primnodes.h:827
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:3105
Definition: nodes.h:539
int errcode(int sqlerrcode)
Definition: elog.c:698
#define ERROR
Definition: elog.h:46
List * list_concat_copy(const List *list1, const List *list2)
Definition: list.c:567
TargetEntry * flatCopyTargetEntry(TargetEntry *src_tle)
Definition: makefuncs.c:271
List * newvals
Definition: primnodes.h:828
static Node * get_assignment_input(Node *node)
#define ereport(elevel,...)
Definition: elog.h:157
#define makeNode(_type_)
Definition: nodes.h:587
Expr * expr
Definition: primnodes.h:1444
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:41
int errmsg(const char *fmt,...)
Definition: elog.c:909
List * fieldnums
Definition: primnodes.h:829
#define elog(elevel,...)
Definition: elog.h:232
void * arg
Expr * refexpr
Definition: primnodes.h:449

◆ QueryRewrite()

List* QueryRewrite ( Query parsetree)

Definition at line 4085 of file rewriteHandler.c.

References Assert, Query::canSetTag, Query::commandType, fireRIRrules(), lappend(), lfirst, NIL, QSRC_INSTEAD_RULE, QSRC_ORIGINAL, QSRC_QUAL_INSTEAD_RULE, Query::queryId, Query::querySource, and RewriteQuery().

Referenced by ExecCreateTableAs(), ExplainOneUtility(), ExplainQuery(), PerformCursorOpen(), pg_rewrite_query(), PrepareQuery(), and refresh_matview_datafill().

4086 {
4087  uint64 input_query_id = parsetree->queryId;
4088  List *querylist;
4089  List *results;
4090  ListCell *l;
4091  CmdType origCmdType;
4092  bool foundOriginalQuery;
4093  Query *lastInstead;
4094 
4095  /*
4096  * This function is only applied to top-level original queries
4097  */
4098  Assert(parsetree->querySource == QSRC_ORIGINAL);
4099  Assert(parsetree->canSetTag);
4100 
4101  /*
4102  * Step 1
4103  *
4104  * Apply all non-SELECT rules possibly getting 0 or many queries
4105  */
4106  querylist = RewriteQuery(parsetree, NIL);
4107 
4108  /*
4109  * Step 2
4110  *
4111  * Apply all the RIR rules on each query
4112  *
4113  * This is also a handy place to mark each query with the original queryId
4114  */
4115  results = NIL;
4116  foreach(l, querylist)
4117  {
4118  Query *query = (Query *) lfirst(l);
4119 
4120  query = fireRIRrules(query, NIL);
4121 
4122  query->queryId = input_query_id;
4123 
4124  results = lappend(results, query);
4125  }
4126 
4127  /*
4128  * Step 3
4129  *
4130  * Determine which, if any, of the resulting queries is supposed to set
4131  * the command-result tag; and update the canSetTag fields accordingly.
4132  *
4133  * If the original query is still in the list, it sets the command tag.
4134  * Otherwise, the last INSTEAD query of the same kind as the original is
4135  * allowed to set the tag. (Note these rules can leave us with no query
4136  * setting the tag. The tcop code has to cope with this by setting up a
4137  * default tag based on the original un-rewritten query.)
4138  *
4139  * The Asserts verify that at most one query in the result list is marked
4140  * canSetTag. If we aren't checking asserts, we can fall out of the loop
4141  * as soon as we find the original query.
4142  */
4143  origCmdType = parsetree->commandType;
4144  foundOriginalQuery = false;
4145  lastInstead = NULL;
4146 
4147  foreach(l, results)
4148  {
4149  Query *query = (Query *) lfirst(l);
4150 
4151  if (query->querySource == QSRC_ORIGINAL)
4152  {
4153  Assert(query->canSetTag);
4154  Assert(!foundOriginalQuery);
4155  foundOriginalQuery = true;
4156 #ifndef USE_ASSERT_CHECKING
4157  break;
4158 #endif
4159  }
4160  else
4161  {
4162  Assert(!query->canSetTag);
4163  if (query->commandType == origCmdType &&
4164  (query->querySource == QSRC_INSTEAD_RULE ||
4166  lastInstead = query;
4167  }
4168  }
4169 
4170  if (!foundOriginalQuery && lastInstead != NULL)
4171  lastInstead->canSetTag = true;
4172 
4173  return results;
4174 }
#define NIL
Definition: pg_list.h:65
static List * RewriteQuery(Query *parsetree, List *rewrite_events)
List * lappend(List *list, void *datum)
Definition: list.c:336
uint64 queryId
Definition: parsenodes.h:124
CmdType commandType
Definition: parsenodes.h:120
QuerySource querySource
Definition: parsenodes.h:122
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
bool canSetTag
Definition: parsenodes.h:126
static Query * fireRIRrules(Query *parsetree, List *activeRIRs)
Definition: pg_list.h:50
CmdType
Definition: nodes.h:682

◆ relation_is_updatable()

int relation_is_updatable ( Oid  reloid,
List outer_reloids,
bool  include_triggers,
Bitmapset include_cols 
)

Definition at line 2792 of file rewriteHandler.c.

References AccessShareLock, adjust_view_column_set(), ALL_EVENTS, Assert, bms_int_members(), bms_is_empty(), check_stack_depth(), CMD_DELETE, CMD_INSERT, CMD_UPDATE, RewriteRule::event, FdwRoutine::ExecForeignDelete, FdwRoutine::ExecForeignInsert, FdwRoutine::ExecForeignUpdate, FromExpr::fromlist, get_view_query(), GetFdwRoutineForRelation(), i, FdwRoutine::IsForeignRelUpdatable, RewriteRule::isInstead, Query::jointree, lappend_oid(), linitial, list_delete_last(), list_member_oid(), RuleLock::numLocks, RewriteRule::qual, RelationData::rd_rel, RelationData::rd_rules, relation_close(), relation_is_updatable(), RelationGetRelid, RangeTblEntry::relid, RangeTblEntry::relkind, rt_fetch, Query::rtable, RTE_RELATION, RangeTblEntry::rtekind, RangeTblRef::rtindex, RuleLock::rules, Query::targetList, TriggerDesc::trig_delete_instead_row, TriggerDesc::trig_insert_instead_row, TriggerDesc::trig_update_instead_row, RelationData::trigdesc, try_relation_open(), view_cols_are_auto_updatable(), and view_query_is_auto_updatable().

Referenced by pg_column_is_updatable(), pg_relation_is_updatable(), and relation_is_updatable().

2796 {
2797  int events = 0;
2798  Relation rel;
2799  RuleLock *rulelocks;
2800 
2801 #define ALL_EVENTS ((1 << CMD_INSERT) | (1 << CMD_UPDATE) | (1 << CMD_DELETE))
2802 
2803  /* Since this function recurses, it could be driven to stack overflow */
2805 
2806  rel = try_relation_open(reloid, AccessShareLock);
2807 
2808  /*
2809  * If the relation doesn't exist, return zero rather than throwing an
2810  * error. This is helpful since scanning an information_schema view under
2811  * MVCC rules can result in referencing rels that have actually been
2812  * deleted already.
2813  */
2814  if (rel == NULL)
2815  return 0;
2816 
2817  /* If we detect a recursive view, report that it is not updatable */
2818  if (list_member_oid(outer_reloids, RelationGetRelid(rel)))
2819  {
2821  return 0;
2822  }
2823 
2824  /* If the relation is a table, it is always updatable */
2825  if (rel->rd_rel->relkind == RELKIND_RELATION ||
2826  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
2827  {
2829  return ALL_EVENTS;
2830  }
2831 
2832  /* Look for unconditional DO INSTEAD rules, and note supported events */
2833  rulelocks = rel->rd_rules;
2834  if (rulelocks != NULL)
2835  {
2836  int i;
2837 
2838  for (i = 0; i < rulelocks->numLocks; i++)
2839  {
2840  if (rulelocks->rules[i]->isInstead &&
2841  rulelocks->rules[i]->qual == NULL)
2842  {
2843  events |= ((1 << rulelocks->rules[i]->event) & ALL_EVENTS);
2844  }
2845  }
2846 
2847  /* If we have rules for all events, we're done */
2848  if (events == ALL_EVENTS)
2849  {
2851  return events;
2852  }
2853  }
2854 
2855  /* Similarly look for INSTEAD OF triggers, if they are to be included */
2856  if (include_triggers)
2857  {
2858  TriggerDesc *trigDesc = rel->trigdesc;
2859 
2860  if (trigDesc)
2861  {
2862  if (trigDesc->trig_insert_instead_row)
2863  events |= (1 << CMD_INSERT);
2864  if (trigDesc->trig_update_instead_row)
2865  events |= (1 << CMD_UPDATE);
2866  if (trigDesc->trig_delete_instead_row)
2867  events |= (1 << CMD_DELETE);
2868 
2869  /* If we have triggers for all events, we're done */
2870  if (events == ALL_EVENTS)
2871  {
2873  return events;
2874  }
2875  }
2876  }
2877 
2878  /* If this is a foreign table, check which update events it supports */
2879  if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
2880  {
2881  FdwRoutine *fdwroutine = GetFdwRoutineForRelation(rel, false);
2882 
2883  if (fdwroutine->IsForeignRelUpdatable != NULL)
2884  events |= fdwroutine->IsForeignRelUpdatable(rel);
2885  else
2886  {
2887  /* Assume presence of executor functions is sufficient */
2888  if (fdwroutine->ExecForeignInsert != NULL)
2889  events |= (1 << CMD_INSERT);
2890  if (fdwroutine->ExecForeignUpdate != NULL)
2891  events |= (1 << CMD_UPDATE);
2892  if (fdwroutine->ExecForeignDelete != NULL)
2893  events |= (1 << CMD_DELETE);
2894  }
2895 
2897  return events;
2898  }
2899 
2900  /* Check if this is an automatically updatable view */
2901  if (rel->rd_rel->relkind == RELKIND_VIEW)
2902  {
2903  Query *viewquery = get_view_query(rel);
2904 
2905  if (view_query_is_auto_updatable(viewquery, false) == NULL)
2906  {
2907  Bitmapset *updatable_cols;
2908  int auto_events;
2909  RangeTblRef *rtr;
2910  RangeTblEntry *base_rte;
2911  Oid baseoid;
2912 
2913  /*
2914  * Determine which of the view's columns are updatable. If there
2915  * are none within the set of columns we are looking at, then the
2916  * view doesn't support INSERT/UPDATE, but it may still support
2917  * DELETE.
2918  */
2919  view_cols_are_auto_updatable(viewquery, NULL,
2920  &updatable_cols, NULL);
2921 
2922  if (include_cols != NULL)
2923  updatable_cols = bms_int_members(updatable_cols, include_cols);
2924 
2925  if (bms_is_empty(updatable_cols))
2926  auto_events = (1 << CMD_DELETE); /* May support DELETE */
2927  else
2928  auto_events = ALL_EVENTS; /* May support all events */
2929 
2930  /*
2931  * The base relation must also support these update commands.
2932  * Tables are always updatable, but for any other kind of base
2933  * relation we must do a recursive check limited to the columns
2934  * referenced by the locally updatable columns in this view.
2935  */
2936  rtr = (RangeTblRef *) linitial(viewquery->jointree->fromlist);
2937  base_rte = rt_fetch(rtr->rtindex, viewquery->rtable);
2938  Assert(base_rte->rtekind == RTE_RELATION);
2939 
2940  if (base_rte->relkind != RELKIND_RELATION &&
2941  base_rte->relkind != RELKIND_PARTITIONED_TABLE)
2942  {
2943  baseoid = base_rte->relid;
2944  outer_reloids = lappend_oid(outer_reloids,
2945  RelationGetRelid(rel));
2946  include_cols = adjust_view_column_set(updatable_cols,
2947  viewquery->targetList);
2948  auto_events &= relation_is_updatable(baseoid,
2949  outer_reloids,
2950  include_triggers,
2951  include_cols);
2952  outer_reloids = list_delete_last(outer_reloids);
2953  }
2954  events |= auto_events;
2955  }
2956  }
2957 
2958  /* If we reach here, the relation may support some update commands */
2960  return events;
2961 }
ExecForeignDelete_function ExecForeignDelete
Definition: fdwapi.h:237
Node * qual
Definition: prs2lock.h:28
int numLocks
Definition: prs2lock.h:42
FromExpr * jointree
Definition: parsenodes.h:148
ExecForeignInsert_function ExecForeignInsert
Definition: fdwapi.h:233
static const char * view_cols_are_auto_updatable(Query *viewquery, Bitmapset *required_cols, Bitmapset **updatable_cols, char **non_updatable_col)
#define AccessShareLock
Definition: lockdefs.h:36
List * fromlist
Definition: primnodes.h:1553
Form_pg_class rd_rel
Definition: rel.h:110
unsigned int Oid
Definition: postgres_ext.h:31
List * lappend_oid(List *list, Oid datum)
Definition: list.c:372
bool isInstead
Definition: prs2lock.h:31
Relation try_relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:89
List * targetList
Definition: parsenodes.h:150
bool trig_insert_instead_row
Definition: reltrigger.h:58
#define linitial(l)
Definition: pg_list.h:174
List * rtable
Definition: parsenodes.h:147
#define ALL_EVENTS
TriggerDesc * trigdesc
Definition: rel.h:116
void check_stack_depth(void)
Definition: postgres.c:3441
CmdType event
Definition: prs2lock.h:27
List * list_delete_last(List *list)
Definition: list.c:892
RewriteRule ** rules
Definition: prs2lock.h:43
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
int relation_is_updatable(Oid reloid, List *outer_reloids, bool include_triggers, Bitmapset *include_cols)
bool trig_update_instead_row
Definition: reltrigger.h:63
bool bms_is_empty(const Bitmapset *a)
Definition: bitmapset.c:701
bool trig_delete_instead_row
Definition: reltrigger.h:68
static Bitmapset * adjust_view_column_set(Bitmapset *cols, List *targetlist)
ExecForeignUpdate_function ExecForeignUpdate
Definition: fdwapi.h:236
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:689
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
#define Assert(condition)
Definition: c.h:804
RuleLock * rd_rules
Definition: rel.h:114
RTEKind rtekind
Definition: parsenodes.h:995
FdwRoutine * GetFdwRoutineForRelation(Relation relation, bool makecopy)
Definition: foreign.c:427
Query * get_view_query(Relation view)
int i
IsForeignRelUpdatable_function IsForeignRelUpdatable
Definition: fdwapi.h:241
Bitmapset * bms_int_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:902
const char * view_query_is_auto_updatable(Query *viewquery, bool check_cols)
#define RelationGetRelid(relation)
Definition: rel.h:457

◆ RewriteQuery()

static List* RewriteQuery ( Query parsetree,
List rewrite_events 
)
static

Definition at line 3598 of file rewriteHandler.c.

References OnConflictExpr::action, Assert, Query::canSetTag, castNode, CMD_DELETE, CMD_INSERT, CMD_SELECT, CMD_UPDATE, CMD_UTILITY, Query::commandType, Query::cteList, CommonTableExpr::ctequery, elog, ereport, errcode(), errdetail(), errhint(), errmsg(), ERROR, rewrite_event::event, fill_extraUpdatedCols(), fireRules(), FromExpr::fromlist, IsA, Query::jointree, lappend(), lcons(), lfirst, lfirst_node, linitial, linitial_node, list_concat(), list_delete_last(), list_length(), matchLocks(), NIL, NoLock, Query::onConflict, ONCONFLICT_UPDATE, OnConflictExpr::onConflictSet, Query::override, palloc(), QSRC_NON_INSTEAD_RULE, QSRC_QUAL_INSTEAD_RULE, Query::querySource, RelationData::rd_rel, RelationData::rd_rules, rewrite_event::relation, RelationGetRelationName, RelationGetRelid, RangeTblEntry::relid, Query::resultRelation, Query::returningList, rewriteTargetListIU(), rewriteTargetView(), rewriteValuesRTE(), rt_fetch, Query::rtable, RTE_RELATION, RTE_VALUES, RangeTblEntry::rtekind, RangeTblRef::rtindex, table_close(), table_open(), Query::targetList, and view_has_instead_trigger().

Referenced by QueryRewrite().

3599 {
3600  CmdType event = parsetree->commandType;
3601  bool instead = false;
3602  bool returning = false;
3603  bool updatableview = false;
3604  Query *qual_product = NULL;
3605  List *rewritten = NIL;
3606  ListCell *lc1;
3607 
3608  /*
3609  * First, recursively process any insert/update/delete statements in WITH
3610  * clauses. (We have to do this first because the WITH clauses may get
3611  * copied into rule actions below.)
3612  */
3613  foreach(lc1, parsetree->cteList)
3614  {
3616  Query *ctequery = castNode(Query, cte->ctequery);
3617  List *newstuff;
3618 
3619  if (ctequery->commandType == CMD_SELECT)
3620  continue;
3621 
3622  newstuff = RewriteQuery(ctequery, rewrite_events);
3623 
3624  /*
3625  * Currently we can only handle unconditional, single-statement DO
3626  * INSTEAD rules correctly; we have to get exactly one Query out of
3627  * the rewrite operation to stuff back into the CTE node.
3628  */
3629  if (list_length(newstuff) == 1)
3630  {
3631  /* Push the single Query back into the CTE node */
3632  ctequery = linitial_node(Query, newstuff);
3633  /* WITH queries should never be canSetTag */
3634  Assert(!ctequery->canSetTag);
3635  cte->ctequery = (Node *) ctequery;
3636  }
3637  else if (newstuff == NIL)
3638  {
3639  ereport(ERROR,
3640  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3641  errmsg("DO INSTEAD NOTHING rules are not supported for data-modifying statements in WITH")));
3642  }
3643  else
3644  {
3645  ListCell *lc2;
3646 
3647  /* examine queries to determine which error message to issue */
3648  foreach(lc2, newstuff)
3649  {
3650  Query *q = (Query *) lfirst(lc2);
3651 
3653  ereport(ERROR,
3654  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3655  errmsg("conditional DO INSTEAD rules are not supported for data-modifying statements in WITH")));
3657  ereport(ERROR,
3658  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3659  errmsg("DO ALSO rules are not supported for data-modifying statements in WITH")));
3660  }
3661 
3662  ereport(ERROR,
3663  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3664  errmsg("multi-statement DO INSTEAD rules are not supported for data-modifying statements in WITH")));
3665  }
3666  }
3667 
3668  /*
3669  * If the statement is an insert, update, or delete, adjust its targetlist
3670  * as needed, and then fire INSERT/UPDATE/DELETE rules on it.
3671  *
3672  * SELECT rules are handled later when we have all the queries that should
3673  * get executed. Also, utilities aren't rewritten at all (do we still
3674  * need that check?)
3675  */
3676  if (event != CMD_SELECT && event != CMD_UTILITY)
3677  {
3678  int result_relation;
3679  RangeTblEntry *rt_entry;
3680  Relation rt_entry_relation;
3681  List *locks;
3682  List *product_queries;
3683  bool hasUpdate = false;
3684  int values_rte_index = 0;
3685  bool defaults_remaining = false;
3686 
3687  result_relation = parsetree->resultRelation;
3688  Assert(result_relation != 0);
3689  rt_entry = rt_fetch(result_relation, parsetree->rtable);
3690  Assert(rt_entry->rtekind == RTE_RELATION);
3691 
3692  /*
3693  * We can use NoLock here since either the parser or
3694  * AcquireRewriteLocks should have locked the rel already.
3695  */
3696  rt_entry_relation = table_open(rt_entry->relid, NoLock);
3697 
3698  /*
3699  * Rewrite the targetlist as needed for the command type.
3700  */
3701  if (event == CMD_INSERT)
3702  {
3703  RangeTblEntry *values_rte = NULL;
3704 
3705  /*
3706  * If it's an INSERT ... VALUES (...), (...), ... there will be a
3707  * single RTE for the VALUES targetlists.
3708  */
3709  if (list_length(parsetree->jointree->fromlist) == 1)
3710  {
3711  RangeTblRef *rtr = (RangeTblRef *) linitial(parsetree->jointree->fromlist);
3712 
3713  if (IsA(rtr, RangeTblRef))
3714  {
3715  RangeTblEntry *rte = rt_fetch(rtr->rtindex,
3716  parsetree->rtable);
3717 
3718  if (rte->rtekind == RTE_VALUES)
3719  {
3720  values_rte = rte;
3721  values_rte_index = rtr->rtindex;
3722  }
3723  }
3724  }
3725 
3726  if (values_rte)
3727  {
3728  Bitmapset *unused_values_attrnos = NULL;
3729 
3730  /* Process the main targetlist ... */
3731  parsetree->targetList = rewriteTargetListIU(parsetree->targetList,
3732  parsetree->commandType,
3733  parsetree->override,
3734  rt_entry_relation,
3735  parsetree->resultRelation,
3736  values_rte,
3737  values_rte_index,
3738  &unused_values_attrnos);
3739  /* ... and the VALUES expression lists */
3740  if (!rewriteValuesRTE(parsetree, values_rte, values_rte_index,
3741  rt_entry_relation, false,
3742  unused_values_attrnos))
3743  defaults_remaining = true;
3744  }
3745  else
3746  {
3747  /* Process just the main targetlist */
3748  parsetree->targetList =
3749  rewriteTargetListIU(parsetree->targetList,
3750  parsetree->commandType,
3751  parsetree->override,
3752  rt_entry_relation,
3753  parsetree->resultRelation,
3754  NULL, 0, NULL);
3755  }
3756 
3757  if (parsetree->onConflict &&
3758  parsetree->onConflict->action == ONCONFLICT_UPDATE)
3759  {
3760  parsetree->onConflict->onConflictSet =
3762  CMD_UPDATE,
3763  parsetree->override,
3764  rt_entry_relation,
3765  parsetree->resultRelation,
3766  NULL, 0, NULL);
3767  }
3768  }
3769  else if (event == CMD_UPDATE)
3770  {
3771  parsetree->targetList =
3772  rewriteTargetListIU(parsetree->targetList,
3773  parsetree->commandType,
3774  parsetree->override,
3775  rt_entry_relation,
3776  parsetree->resultRelation,
3777  NULL, 0, NULL);
3778 
3779  /* Also populate extraUpdatedCols (for generated columns) */
3780  fill_extraUpdatedCols(rt_entry, rt_entry_relation);
3781  }
3782  else if (event == CMD_DELETE)
3783  {
3784  /* Nothing to do here */
3785  }
3786  else
3787  elog(ERROR, "unrecognized commandType: %d", (int) event);
3788 
3789  /*
3790  * Collect and apply the appropriate rules.
3791  */
3792  locks = matchLocks(event, rt_entry_relation->rd_rules,
3793  result_relation, parsetree, &hasUpdate);
3794 
3795  product_queries = fireRules(parsetree,
3796  result_relation,
3797  event,
3798  locks,
3799  &instead,
3800  &returning,
3801  &qual_product);
3802 
3803  /*
3804  * If we have a VALUES RTE with any remaining untouched DEFAULT items,
3805  * and we got any product queries, finalize the VALUES RTE for each
3806  * product query (replacing the remaining DEFAULT items with NULLs).
3807  * We don't do this for the original query, because we know that it
3808  * must be an auto-insert on a view, and so should use the base
3809  * relation's defaults for any remaining DEFAULT items.
3810  */
3811  if (defaults_remaining && product_queries != NIL)
3812  {
3813  ListCell *n;
3814 
3815  /*
3816  * Each product query has its own copy of the VALUES RTE at the
3817  * same index in the rangetable, so we must finalize each one.
3818  */
3819  foreach(n, product_queries)
3820  {
3821  Query *pt = (Query *) lfirst(n);
3822  RangeTblEntry *values_rte = rt_fetch(values_rte_index,
3823  pt->rtable);
3824 
3825  rewriteValuesRTE(pt, values_rte, values_rte_index,
3826  rt_entry_relation,
3827  true, /* Force remaining defaults to NULL */
3828  NULL);
3829  }
3830  }
3831 
3832  /*
3833  * If there was no unqualified INSTEAD rule, and the target relation
3834  * is a view without any INSTEAD OF triggers, see if the view can be
3835  * automatically updated. If so, we perform the necessary query
3836  * transformation here and add the resulting query to the
3837  * product_queries list, so that it gets recursively rewritten if
3838  * necessary.
3839  *
3840  * If the view cannot be automatically updated, we throw an error here
3841  * which is OK since the query would fail at runtime anyway. Throwing
3842  * the error here is preferable to the executor check since we have
3843  * more detailed information available about why the view isn't
3844  * updatable.
3845  */
3846  if (!instead &&
3847  rt_entry_relation->rd_rel->relkind == RELKIND_VIEW &&
3848  !view_has_instead_trigger(rt_entry_relation, event))
3849  {
3850  /*
3851  * If there were any qualified INSTEAD rules, don't allow the view
3852  * to be automatically updated (an unqualified INSTEAD rule or
3853  * INSTEAD OF trigger is required).
3854  *
3855  * The messages here should match execMain.c's CheckValidResultRel
3856  * and in principle make those checks in executor unnecessary, but
3857  * we keep them just in case.
3858  */
3859  if (qual_product != NULL)
3860  {
3861  switch (parsetree->commandType)
3862  {
3863  case CMD_INSERT:
3864  ereport(ERROR,
3865  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3866  errmsg("cannot insert into view \"%s\"",
3867  RelationGetRelationName(rt_entry_relation)),
3868  errdetail("Views with conditional DO INSTEAD rules are not automatically updatable."),
3869  errhint("To enable inserting into the view, provide an INSTEAD OF INSERT trigger or an unconditional ON INSERT DO INSTEAD rule.")));
3870  break;
3871  case CMD_UPDATE:
3872  ereport(ERROR,
3873  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3874  errmsg("cannot update view \"%s\"",
3875  RelationGetRelationName(rt_entry_relation)),
3876  errdetail("Views with conditional DO INSTEAD rules are not automatically updatable."),
3877  errhint("To enable updating the view, provide an INSTEAD OF UPDATE trigger or an unconditional ON UPDATE DO INSTEAD rule.")));
3878  break;
3879  case CMD_DELETE:
3880  ereport(ERROR,
3881  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3882  errmsg("cannot delete from view \"%s\"",
3883  RelationGetRelationName(rt_entry_relation)),
3884  errdetail("Views with conditional DO INSTEAD rules are not automatically updatable."),
3885  errhint("To enable deleting from the view, provide an INSTEAD OF DELETE trigger or an unconditional ON DELETE DO INSTEAD rule.")));
3886  break;
3887  default:
3888  elog(ERROR, "unrecognized CmdType: %d",
3889  (int) parsetree->commandType);
3890  break;
3891  }
3892  }
3893 
3894  /*
3895  * Attempt to rewrite the query to automatically update the view.
3896  * This throws an error if the view can't be automatically
3897  * updated.
3898  */
3899  parsetree = rewriteTargetView(parsetree, rt_entry_relation);
3900 
3901  /*
3902  * At this point product_queries contains any DO ALSO rule
3903  * actions. Add the rewritten query before or after those. This
3904  * must match the handling the original query would have gotten
3905  * below, if we allowed it to be included again.
3906  */
3907  if (parsetree->commandType == CMD_INSERT)
3908  product_queries = lcons(parsetree, product_queries);
3909  else
3910  product_queries = lappend(product_queries, parsetree);
3911 
3912  /*
3913  * Set the "instead" flag, as if there had been an unqualified
3914  * INSTEAD, to prevent the original query from being included a
3915  * second time below. The transformation will have rewritten any
3916  * RETURNING list, so we can also set "returning" to forestall
3917  * throwing an error below.
3918  */
3919  instead = true;
3920  returning = true;
3921  updatableview = true;
3922  }
3923 
3924  /*
3925  * If we got any product queries, recursively rewrite them --- but
3926  * first check for recursion!
3927  */
3928  if (product_queries != NIL)
3929  {
3930  ListCell *n;
3931  rewrite_event *rev;
3932 
3933  foreach(n, rewrite_events)
3934  {
3935  rev = (rewrite_event *) lfirst(n);
3936  if (rev->relation == RelationGetRelid(rt_entry_relation) &&
3937  rev->event == event)
3938  ereport(ERROR,
3939  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
3940  errmsg("infinite recursion detected in rules for relation \"%s\"",
3941  RelationGetRelationName(rt_entry_relation))));
3942  }
3943 
3944  rev = (rewrite_event *) palloc(sizeof(rewrite_event));
3945  rev->relation = RelationGetRelid(rt_entry_relation);
3946  rev->event = event;
3947  rewrite_events = lappend(rewrite_events, rev);
3948 
3949  foreach(n, product_queries)
3950  {
3951  Query *pt = (Query *) lfirst(n);
3952  List *newstuff;
3953 
3954  newstuff = RewriteQuery(pt, rewrite_events);
3955  rewritten = list_concat(rewritten, newstuff);
3956  }
3957 
3958  rewrite_events = list_delete_last(rewrite_events);
3959  }
3960 
3961  /*
3962  * If there is an INSTEAD, and the original query has a RETURNING, we
3963  * have to have found a RETURNING in the rule(s), else fail. (Because
3964  * DefineQueryRewrite only allows RETURNING in unconditional INSTEAD
3965  * rules, there's no need to worry whether the substituted RETURNING
3966  * will actually be executed --- it must be.)
3967  */
3968  if ((instead || qual_product != NULL) &&
3969  parsetree->returningList &&
3970  !returning)
3971  {
3972  switch (event)
3973  {
3974  case CMD_INSERT:
3975  ereport(ERROR,
3976  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3977  errmsg("cannot perform INSERT RETURNING on relation \"%s\"",
3978  RelationGetRelationName(rt_entry_relation)),
3979  errhint("You need an unconditional ON INSERT DO INSTEAD rule with a RETURNING clause.")));
3980  break;
3981  case CMD_UPDATE:
3982  ereport(ERROR,
3983  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3984  errmsg("cannot perform UPDATE RETURNING on relation \"%s\"",
3985  RelationGetRelationName(rt_entry_relation)),
3986  errhint("You need an unconditional ON UPDATE DO INSTEAD rule with a RETURNING clause.")));
3987  break;
3988  case CMD_DELETE:
3989  ereport(ERROR,
3990  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3991  errmsg("cannot perform DELETE RETURNING on relation \"%s\"",
3992  RelationGetRelationName(rt_entry_relation)),
3993  errhint("You need an unconditional ON DELETE DO INSTEAD rule with a RETURNING clause.")));
3994  break;
3995  default:
3996  elog(ERROR, "unrecognized commandType: %d",
3997  (int) event);
3998  break;
3999  }
4000  }
4001 
4002  /*
4003  * Updatable views are supported by ON CONFLICT, so don't prevent that
4004  * case from proceeding
4005  */
4006  if (parsetree->onConflict &&
4007  (product_queries != NIL || hasUpdate) &&
4008  !updatableview)
4009  ereport(ERROR,
4010  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4011  errmsg("INSERT with ON CONFLICT clause cannot be used with table that has INSERT or UPDATE rules")));
4012 
4013  table_close(rt_entry_relation, NoLock);
4014  }
4015 
4016  /*
4017  * For INSERTs, the original query is done first; for UPDATE/DELETE, it is
4018  * done last. This is needed because update and delete rule actions might
4019  * not do anything if they are invoked after the update or delete is
4020  * performed. The command counter increment between the query executions
4021  * makes the deleted (and maybe the updated) tuples disappear so the scans
4022  * for them in the rule actions cannot find them.
4023  *
4024  * If we found any unqualified INSTEAD, the original query is not done at
4025  * all, in any form. Otherwise, we add the modified form if qualified
4026  * INSTEADs were found, else the unmodified form.
4027  */
4028  if (!instead)
4029  {
4030  if (parsetree->commandType == CMD_INSERT)
4031  {
4032  if (qual_product != NULL)
4033  rewritten = lcons(qual_product, rewritten);
4034  else
4035  rewritten = lcons(parsetree, rewritten);
4036  }
4037  else
4038  {
4039  if (qual_product != NULL)
4040  rewritten = lappend(rewritten, qual_product);
4041  else
4042  rewritten = lappend(rewritten, parsetree);
4043  }
4044  }
4045 
4046  /*
4047  * If the original query has a CTE list, and we generated more than one
4048  * non-utility result query, we have to fail because we'll have copied the
4049  * CTE list into each result query. That would break the expectation of
4050  * single evaluation of CTEs. This could possibly be fixed by
4051  * restructuring so that a CTE list can be shared across multiple Query
4052  * and PlannableStatement nodes.
4053  */
4054  if (parsetree->cteList != NIL)
4055  {
4056  int qcount = 0;
4057 
4058  foreach(lc1, rewritten)
4059  {
4060  Query *q = (Query *) lfirst(lc1);
4061 
4062  if (q->commandType != CMD_UTILITY)
4063  qcount++;
4064  }
4065  if (qcount > 1)
4066  ereport(ERROR,
4067  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4068  errmsg("WITH cannot be used in a query that is rewritten by rules into multiple queries")));
4069  }
4070 
4071  return rewritten;
4072 }
#define NIL
Definition: pg_list.h:65
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
int errhint(const char *fmt,...)
Definition: elog.c:1156
static bool view_has_instead_trigger(Relation view, CmdType event)
FromExpr * jointree
Definition: parsenodes.h:148
static List * rewriteTargetListIU(List *targetList, CmdType commandType, OverridingKind override, Relation target_relation, int result_rti, RangeTblEntry *values_rte, int values_rte_index, Bitmapset **unused_values_attrnos)
OnConflictExpr * onConflict
Definition: parsenodes.h:154
#define castNode(_type_, nodeptr)
Definition: nodes.h:608
int resultRelation
Definition: parsenodes.h:130
Definition: nodes.h:539
static List * RewriteQuery(Query *parsetree, List *rewrite_events)
List * list_concat(List *list1, const List *list2)
Definition: list.c:530
int errcode(int sqlerrcode)
Definition: elog.c:698
List * fromlist
Definition: primnodes.h:1553
Form_pg_class rd_rel
Definition: rel.h:110
#define linitial_node(type, l)
Definition: pg_list.h:177
List * targetList
Definition: parsenodes.h:150
#define linitial(l)
Definition: pg_list.h:174
List * rtable
Definition: parsenodes.h:147
#define ERROR
Definition: elog.h:46
void fill_extraUpdatedCols(RangeTblEntry *target_rte, Relation target_relation)
static bool rewriteValuesRTE(Query *parsetree, RangeTblEntry *rte, int rti, Relation target_relation, bool force_nulls, Bitmapset *unused_cols)
#define lfirst_node(type, lc)
Definition: pg_list.h:172
#define NoLock
Definition: lockdefs.h:34
int errdetail(const char *fmt,...)
Definition: elog.c:1042
static Query * rewriteTargetView(Query *parsetree, Relation view)
List * list_delete_last(List *list)
Definition: list.c:892
#define RelationGetRelationName(relation)
Definition: rel.h:491
List * returningList
Definition: parsenodes.h:156
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
List * lappend(List *list, void *datum)
Definition: list.c:336
OnConflictAction action
Definition: primnodes.h:1569
static List * fireRules(Query *parsetree, int rt_index, CmdType event, List *locks, bool *instead_flag, bool *returning_flag, Query **qual_product)
OverridingKind override
Definition: parsenodes.h:152
#define ereport(elevel,...)
Definition: elog.h:157
CmdType commandType
Definition: parsenodes.h:120
List * lcons(void *datum, List *list)
Definition: list.c:468
QuerySource querySource
Definition: parsenodes.h:122
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
RuleLock * rd_rules
Definition: rel.h:114
bool canSetTag
Definition: parsenodes.h:126
static int list_length(const List *l)
Definition: pg_list.h:149
RTEKind rtekind
Definition: parsenodes.h:995
List * cteList
Definition: parsenodes.h:145
void * palloc(Size size)
Definition: mcxt.c:1062
int errmsg(const char *fmt,...)
Definition: elog.c:909
#define elog(elevel,...)
Definition: elog.h:232
List * onConflictSet
Definition: primnodes.h:1578
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: pg_list.h:50
static List * matchLocks(CmdType event, RuleLock *rulelocks, int varno, Query *parsetree, bool *hasUpdate)
#define RelationGetRelid(relation)
Definition: rel.h:457
CmdType
Definition: nodes.h:682

◆ rewriteRuleAction()

static Query * rewriteRuleAction ( Query parsetree,
Query rule_action,
Node rule_qual,
int  rt_index,
CmdType  event,
bool returning_flag 
)
static

Definition at line 343 of file rewriteHandler.c.

References acquireLocksOnSubLinks(), AcquireRewriteLocks(), AddQual(), adjustJoinTreeList(), Assert, ChangeVarNodes(), checkExprHasSubLink(), CMD_INSERT, CMD_UPDATE, CMD_UTILITY, copyObject, Query::cteList, CommonTableExpr::ctename, ereport, errcode(), errmsg(), ERROR, acquireLocksOnSubLinks_context::for_execute, RangeTblEntry::functions, getInsertSelectQuery(), Query::hasRowSecurity, Query::hasSubLinks, Query::jointree, lfirst, list_concat(), list_length(), NIL, OffsetVarNodes(), PRS2_NEW_VARNO, PRS2_OLD_VARNO, FromExpr::quals, rangeTableEntry_used(), REPLACEVARS_CHANGE_VARNO, REPLACEVARS_REPORT_ERROR, REPLACEVARS_SUBSTITUTE_NULL, ReplaceVarsFromTargetList(), Query::resultRelation, Query::returningList, rt_fetch, Query::rtable, RTE_FUNCTION, RTE_RELATION, RTE_TABLEFUNC, RTE_VALUES, RangeTblEntry::rtekind, RangeTblEntry::tablefunc, RangeTblEntry::tablesample, Query::targetList, and RangeTblEntry::values_lists.

Referenced by fireRules().

349 {
350  int current_varno,
351  new_varno;
352  int rt_length;
353  Query *sub_action;
354  Query **sub_action_ptr;
356 
357  context.for_execute = true;
358 
359  /*
360  * Make modifiable copies of rule action and qual (what we're passed are
361  * the stored versions in the relcache; don't touch 'em!).
362  */
363  rule_action = copyObject(rule_action);
364  rule_qual = copyObject(rule_qual);
365 
366  /*
367  * Acquire necessary locks and fix any deleted JOIN RTE entries.
368  */
369  AcquireRewriteLocks(rule_action, true, false);
370  (void) acquireLocksOnSubLinks(rule_qual, &context);
371 
372  current_varno = rt_index;
373  rt_length = list_length(parsetree->rtable);
374  new_varno = PRS2_NEW_VARNO + rt_length;
375 
376  /*
377  * Adjust rule action and qual to offset its varnos, so that we can merge
378  * its rtable with the main parsetree's rtable.
379  *
380  * If the rule action is an INSERT...SELECT, the OLD/NEW rtable entries
381  * will be in the SELECT part, and we have to modify that rather than the
382  * top-level INSERT (kluge!).
383  */
384  sub_action = getInsertSelectQuery(rule_action, &sub_action_ptr);
385 
386  OffsetVarNodes((Node *) sub_action, rt_length, 0);
387  OffsetVarNodes(rule_qual, rt_length, 0);
388  /* but references to OLD should point at original rt_index */
389  ChangeVarNodes((Node *) sub_action,
390  PRS2_OLD_VARNO + rt_length, rt_index, 0);
391  ChangeVarNodes(rule_qual,
392  PRS2_OLD_VARNO + rt_length, rt_index, 0);
393 
394  /*
395  * Generate expanded rtable consisting of main parsetree's rtable plus
396  * rule action's rtable; this becomes the complete rtable for the rule
397  * action. Some of the entries may be unused after we finish rewriting,
398  * but we leave them all in place for two reasons:
399  *
400  * We'd have a much harder job to adjust the query's varnos if we
401  * selectively removed RT entries.
402  *
403  * If the rule is INSTEAD, then the original query won't be executed at
404  * all, and so its rtable must be preserved so that the executor will do
405  * the correct permissions checks on it.
406  *
407  * RT entries that are not referenced in the completed jointree will be
408  * ignored by the planner, so they do not affect query semantics. But any
409  * permissions checks specified in them will be applied during executor
410  * startup (see ExecCheckRTEPerms()). This allows us to check that the
411  * caller has, say, insert-permission on a view, when the view is not
412  * semantically referenced at all in the resulting query.
413  *
414  * When a rule is not INSTEAD, the permissions checks done on its copied
415  * RT entries will be redundant with those done during execution of the
416  * original query, but we don't bother to treat that case differently.
417  *
418  * NOTE: because planner will destructively alter rtable, we must ensure
419  * that rule action's rtable is separate and shares no substructure with
420  * the main rtable. Hence do a deep copy here.
421  */
422  sub_action->rtable = list_concat(copyObject(parsetree->rtable),
423  sub_action->rtable);
424 
425  /*
426  * There could have been some SubLinks in parsetree's rtable, in which
427  * case we'd better mark the sub_action correctly.
428  */
429  if (parsetree->hasSubLinks && !sub_action->hasSubLinks)
430  {
431  ListCell *lc;
432 
433  foreach(lc, parsetree->rtable)
434  {
435  RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
436 
437  switch (rte->rtekind)
438  {
439  case RTE_RELATION:
440  sub_action->hasSubLinks =
442  break;
443  case RTE_FUNCTION:
444  sub_action->hasSubLinks =
446  break;
447  case RTE_TABLEFUNC:
448  sub_action->hasSubLinks =
450  break;
451  case RTE_VALUES:
452  sub_action->hasSubLinks =
454  break;
455  default:
456  /* other RTE types don't contain bare expressions */
457  break;
458  }
459  if (sub_action->hasSubLinks)
460  break; /* no need to keep scanning rtable */
461  }
462  }
463 
464  /*
465  * Also, we might have absorbed some RTEs with RLS conditions into the
466  * sub_action. If so, mark it as hasRowSecurity, whether or not those
467  * RTEs will be referenced after we finish rewriting. (Note: currently
468  * this is a no-op because RLS conditions aren't added till later, but it
469  * seems like good future-proofing to do this anyway.)
470  */
471  sub_action->hasRowSecurity |= parsetree->hasRowSecurity;
472 
473  /*
474  * Each rule action's jointree should be the main parsetree's jointree
475  * plus that rule's jointree, but usually *without* the original rtindex
476  * that we're replacing (if present, which it won't be for INSERT). Note
477  * that if the rule action refers to OLD, its jointree will add a
478  * reference to rt_index. If the rule action doesn't refer to OLD, but
479  * either the rule_qual or the user query quals do, then we need to keep
480  * the original rtindex in the jointree to provide data for the quals. We
481  * don't want the original rtindex to be joined twice, however, so avoid
482  * keeping it if the rule action mentions it.
483  *
484  * As above, the action's jointree must not share substructure with the
485  * main parsetree's.
486  */
487  if (sub_action->commandType != CMD_UTILITY)
488  {
489  bool keeporig;
490  List *newjointree;
491 
492  Assert(sub_action->jointree != NULL);
493  keeporig = (!rangeTableEntry_used((Node *) sub_action->jointree,
494  rt_index, 0)) &&
495  (rangeTableEntry_used(rule_qual, rt_index, 0) ||
496  rangeTableEntry_used(parsetree->jointree->quals, rt_index, 0));
497  newjointree = adjustJoinTreeList(parsetree, !keeporig, rt_index);
498  if (newjointree != NIL)
499  {
500  /*
501  * If sub_action is a setop, manipulating its jointree will do no
502  * good at all, because the jointree is dummy. (Perhaps someday
503  * we could push the joining and quals down to the member
504  * statements of the setop?)
505  */
506  if (sub_action->setOperations != NULL)
507  ereport(ERROR,
508  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
509  errmsg("conditional UNION/INTERSECT/EXCEPT statements are not implemented")));
510 
511  sub_action->jointree->fromlist =
512  list_concat(newjointree, sub_action->jointree->fromlist);
513 
514  /*
515  * There could have been some SubLinks in newjointree, in which
516  * case we'd better mark the sub_action correctly.
517  */
518  if (parsetree->hasSubLinks && !sub_action->hasSubLinks)
519  sub_action->hasSubLinks =
520  checkExprHasSubLink((Node *) newjointree);
521  }
522  }
523 
524  /*
525  * If the original query has any CTEs, copy them into the rule action. But
526  * we don't need them for a utility action.
527  */
528  if (parsetree->cteList != NIL && sub_action->commandType != CMD_UTILITY)
529  {
530  ListCell *lc;
531 
532  /*
533  * Annoying implementation restriction: because CTEs are identified by
534  * name within a cteList, we can't merge a CTE from the original query
535  * if it has the same name as any CTE in the rule action.
536  *
537  * This could possibly be fixed by using some sort of internally
538  * generated ID, instead of names, to link CTE RTEs to their CTEs.
539  */
540  foreach(lc, parsetree->cteList)
541  {
542  CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
543  ListCell *lc2;
544 
545  foreach(lc2, sub_action->cteList)
546  {
547  CommonTableExpr *cte2 = (CommonTableExpr *) lfirst(lc2);
548 
549  if (strcmp(cte->ctename, cte2->ctename) == 0)
550  ereport(ERROR,
551  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
552  errmsg("WITH query name \"%s\" appears in both a rule action and the query being rewritten",
553  cte->ctename)));
554  }
555  }
556 
557  /* OK, it's safe to combine the CTE lists */
558  sub_action->cteList = list_concat(sub_action->cteList,
559  copyObject(parsetree->cteList));
560  }
561 
562  /*
563  * Event Qualification forces copying of parsetree and splitting into two
564  * queries one w/rule_qual, one w/NOT rule_qual. Also add user query qual
565  * onto rule action
566  */
567  AddQual(sub_action, rule_qual);
568 
569  AddQual(sub_action, parsetree->jointree->quals);
570 
571  /*
572  * Rewrite new.attribute with right hand side of target-list entry for
573  * appropriate field name in insert/update.
574  *
575  * KLUGE ALERT: since ReplaceVarsFromTargetList returns a mutated copy, we
576  * can't just apply it to sub_action; we have to remember to update the
577  * sublink inside rule_action, too.
578  */
579  if ((event == CMD_INSERT || event == CMD_UPDATE) &&
580  sub_action->commandType != CMD_UTILITY)
581  {
582  sub_action = (Query *)
583  ReplaceVarsFromTargetList((Node *) sub_action,
584  new_varno,
585  0,
586  rt_fetch(new_varno, sub_action->rtable),
587  parsetree->targetList,
588  (event == CMD_UPDATE) ?
591  current_varno,
592  NULL);
593  if (sub_action_ptr)
594  *sub_action_ptr = sub_action;
595  else
596  rule_action = sub_action;
597  }
598 
599  /*
600  * If rule_action has a RETURNING clause, then either throw it away if the
601  * triggering query has no RETURNING clause, or rewrite it to emit what
602  * the triggering query's RETURNING clause asks for. Throw an error if
603  * more than one rule has a RETURNING clause.
604  */
605  if (!parsetree->returningList)
606  rule_action->returningList = NIL;
607  else if (rule_action->returningList)
608  {
609  if (*returning_flag)
610  ereport(ERROR,
611  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
612  errmsg("cannot have RETURNING lists in multiple rules")));
613  *returning_flag = true;
614  rule_action->returningList = (List *)
616  parsetree->resultRelation,
617  0,
618  rt_fetch(parsetree->resultRelation,
619  parsetree->rtable),
620  rule_action->returningList,
622  0,
623  &rule_action->hasSubLinks);
624 
625  /*
626  * There could have been some SubLinks in parsetree's returningList,
627  * in which case we'd better mark the rule_action correctly.
628  */
629  if (parsetree->hasSubLinks && !rule_action->hasSubLinks)
630  rule_action->hasSubLinks =
631  checkExprHasSubLink((Node *) rule_action->returningList);
632  }
633 
634  return rule_action;
635 }
#define NIL
Definition: pg_list.h:65
Query * getInsertSelectQuery(Query *parsetree, Query ***subquery_ptr)
Definition: rewriteManip.c:924
void OffsetVarNodes(Node *node, int offset, int sublevels_up)
Definition: rewriteManip.c:425
static bool acquireLocksOnSubLinks(Node *node, acquireLocksOnSubLinks_context *context)
FromExpr * jointree
Definition: parsenodes.h:148
bool checkExprHasSubLink(Node *node)
Definition: rewriteManip.c:277
int resultRelation
Definition: parsenodes.h:130
Definition: nodes.h:539
List * list_concat(List *list1, const List *list2)
Definition: list.c:530
int errcode(int sqlerrcode)
Definition: elog.c:698
static List * adjustJoinTreeList(Query *parsetree, bool removert, int rt_index)
List * fromlist
Definition: primnodes.h:1553
List * values_lists
Definition: parsenodes.h:1100
Node * quals
Definition: primnodes.h:1554
List * targetList
Definition: parsenodes.h:150
List * rtable
Definition: parsenodes.h:147
#define ERROR
Definition: elog.h:46
TableFunc * tablefunc
Definition: parsenodes.h:1095
void AcquireRewriteLocks(Query *parsetree, bool forExecute, bool forUpdatePushedDown)
List * returningList
Definition: parsenodes.h:156
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
#define PRS2_OLD_VARNO
Definition: primnodes.h:183
Node * ReplaceVarsFromTargetList(Node *node, int target_varno, int sublevels_up, RangeTblEntry *target_rte, List *targetlist, ReplaceVarsNoMatchOption nomatch_option, int nomatch_varno, bool *outer_hasSubLinks)
#define ereport(elevel,...)
Definition: elog.h:157
CmdType commandType
Definition: parsenodes.h:120
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
List * functions
Definition: parsenodes.h:1089
void AddQual(Query *parsetree, Node *qual)
Definition: rewriteManip.c:979
static int list_length(const List *l)
Definition: pg_list.h:149
RTEKind rtekind
Definition: parsenodes.h:995
List * cteList
Definition: parsenodes.h:145
Node * setOperations
Definition: parsenodes.h:177
int errmsg(const char *fmt,...)
Definition: elog.c:909
bool hasSubLinks
Definition: parsenodes.h:136
void ChangeVarNodes(Node *node, int rt_index, int new_index, int sublevels_up)
Definition: rewriteManip.c:610
bool rangeTableEntry_used(Node *node, int rt_index, int sublevels_up)
Definition: rewriteManip.c:892
#define copyObject(obj)
Definition: nodes.h:655
Definition: pg_list.h:50
struct TableSampleClause * tablesample
Definition: parsenodes.h:1025
#define PRS2_NEW_VARNO
Definition: primnodes.h:184
bool hasRowSecurity
Definition: parsenodes.h:141

◆ rewriteTargetListIU()

static List * rewriteTargetListIU ( List targetList,
CmdType  commandType,
OverridingKind  override,
Relation  target_relation,
int  result_rti,
RangeTblEntry values_rte,
int  values_rte_index,
Bitmapset **  unused_values_attrnos 
)
static

Definition at line 721 of file rewriteHandler.c.

References bms_add_member(), bms_is_member(), build_column_default(), CMD_INSERT, CMD_UPDATE, COERCE_IMPLICIT_CAST, coerce_to_domain(), COERCION_IMPLICIT, elog, ereport, errcode(), errdetail(), errhint(), errmsg(), ERROR, TargetEntry::expr, findDefaultOnlyColumns(), flatCopyTargetEntry(), InvalidOid, IsA, lappend(), lfirst, list_concat(), makeConst(), makeTargetEntry(), makeVar(), NameStr, NIL, OVERRIDING_SYSTEM_VALUE, OVERRIDING_USER_VALUE, palloc0(), pfree(), process_matched_tle(), pstrdup(), RelationData::rd_att, RelationData::rd_rel, RelationGetNumberOfAttributes, TargetEntry::resjunk, TargetEntry::resno, TupleDescAttr, Var::varattno, Var::varno, and view_has_instead_trigger().

Referenced by RewriteQuery().

729 {
730  TargetEntry **new_tles;
731  List *new_tlist = NIL;
732  List *junk_tlist = NIL;
733  Form_pg_attribute att_tup;
734  int attrno,
735  next_junk_attrno,
736  numattrs;
737  ListCell *temp;
738  Bitmapset *default_only_cols = NULL;
739 
740  /*
741  * We process the normal (non-junk) attributes by scanning the input tlist
742  * once and transferring TLEs into an array, then scanning the array to
743  * build an output tlist. This avoids O(N^2) behavior for large numbers
744  * of attributes.
745  *
746  * Junk attributes are tossed into a separate list during the same tlist
747  * scan, then appended to the reconstructed tlist.
748  */
749  numattrs = RelationGetNumberOfAttributes(target_relation);
750  new_tles = (TargetEntry **) palloc0(numattrs * sizeof(TargetEntry *));
751  next_junk_attrno = numattrs + 1;
752 
753  foreach(temp, targetList)
754  {
755  TargetEntry *old_tle = (TargetEntry *) lfirst(temp);
756 
757  if (!old_tle->resjunk)
758  {
759  /* Normal attr: stash it into new_tles[] */
760  attrno = old_tle->resno;
761  if (attrno < 1 || attrno > numattrs)
762  elog(ERROR, "bogus resno %d in targetlist", attrno);
763  att_tup = TupleDescAttr(target_relation->rd_att, attrno - 1);
764 
765  /* We can (and must) ignore deleted attributes */
766  if (att_tup->attisdropped)
767  continue;
768 
769  /* Merge with any prior assignment to same attribute */
770  new_tles[attrno - 1] =
771  process_matched_tle(old_tle,
772  new_tles[attrno - 1],
773  NameStr(att_tup->attname));
774  }
775  else
776  {
777  /*
778  * Copy all resjunk tlist entries to junk_tlist, and assign them
779  * resnos above the last real resno.
780  *
781  * Typical junk entries include ORDER BY or GROUP BY expressions
782  * (are these actually possible in an INSERT or UPDATE?), system
783  * attribute references, etc.
784  */
785 
786  /* Get the resno right, but don't copy unnecessarily */
787  if (old_tle->resno != next_junk_attrno)
788  {
789  old_tle = flatCopyTargetEntry(old_tle);
790  old_tle->resno = next_junk_attrno;
791  }
792  junk_tlist = lappend(junk_tlist, old_tle);
793  next_junk_attrno++;
794  }
795  }
796 
797  for (attrno = 1; attrno <= numattrs; attrno++)
798  {
799  TargetEntry *new_tle = new_tles[attrno - 1];
800  bool apply_default;
801 
802  att_tup = TupleDescAttr(target_relation->rd_att, attrno - 1);
803 
804  /* We can (and must) ignore deleted attributes */
805  if (att_tup->attisdropped)
806  continue;
807 
808  /*
809  * Handle the two cases where we need to insert a default expression:
810  * it's an INSERT and there's no tlist entry for the column, or the
811  * tlist entry is a DEFAULT placeholder node.
812  */
813  apply_default = ((new_tle == NULL && commandType == CMD_INSERT) ||
814  (new_tle && new_tle->expr && IsA(new_tle->expr, SetToDefault)));
815 
816  if (commandType == CMD_INSERT)
817  {
818  int values_attrno = 0;
819 
820  /* Source attribute number for values that come from a VALUES RTE */
821  if (values_rte && new_tle && IsA(new_tle->expr, Var))
822  {
823  Var *var = (Var *) new_tle->expr;
824 
825  if (var->varno == values_rte_index)
826  values_attrno = var->varattno;
827  }
828 
829  /*
830  * Can only insert DEFAULT into GENERATED ALWAYS identity columns,
831  * unless either OVERRIDING USER VALUE or OVERRIDING SYSTEM VALUE
832  * is specified.
833  */
834  if (att_tup->attidentity == ATTRIBUTE_IDENTITY_ALWAYS && !apply_default)
835  {
836  if (override == OVERRIDING_USER_VALUE)
837  apply_default = true;
838  else if (override != OVERRIDING_SYSTEM_VALUE)
839  {
840  /*
841  * If this column's values come from a VALUES RTE, test
842  * whether it contains only SetToDefault items. Since the
843  * VALUES list might be quite large, we arrange to only
844  * scan it once.
845  */
846  if (values_attrno != 0)
847  {
848  if (default_only_cols == NULL)
849  default_only_cols = findDefaultOnlyColumns(values_rte);
850 
851  if (bms_is_member(values_attrno, default_only_cols))
852  apply_default = true;
853  }
854 
855  if (!apply_default)
856  ereport(ERROR,
857  (errcode(ERRCODE_GENERATED_ALWAYS),
858  errmsg("cannot insert a non-DEFAULT value into column \"%s\"",
859  NameStr(att_tup->attname)),
860  errdetail("Column \"%s\" is an identity column defined as GENERATED ALWAYS.",
861  NameStr(att_tup->attname)),
862  errhint("Use OVERRIDING SYSTEM VALUE to override.")));
863  }
864  }
865 
866  /*
867  * Although inserting into a GENERATED BY DEFAULT identity column
868  * is allowed, apply the default if OVERRIDING USER VALUE is
869  * specified.
870  */
871  if (att_tup->attidentity == ATTRIBUTE_IDENTITY_BY_DEFAULT &&
872  override == OVERRIDING_USER_VALUE)
873  apply_default = true;
874 
875  /*
876  * Can only insert DEFAULT into generated columns, regardless of
877  * any OVERRIDING clauses.
878  */
879  if (att_tup->attgenerated && !apply_default)
880  {
881  /*
882  * If this column's values come from a VALUES RTE, test
883  * whether it contains only SetToDefault items, as above.
884  */
885  if (values_attrno != 0)
886  {
887  if (default_only_cols == NULL)
888  default_only_cols = findDefaultOnlyColumns(values_rte);
889 
890  if (bms_is_member(values_attrno, default_only_cols))
891  apply_default = true;
892  }
893 
894  if (!apply_default)
895  ereport(ERROR,
896  (errcode(ERRCODE_GENERATED_ALWAYS),
897  errmsg("cannot insert a non-DEFAULT value into column \"%s\"",
898  NameStr(att_tup->attname)),
899  errdetail("Column \"%s\" is a generated column.",
900  NameStr(att_tup->attname))));
901  }
902 
903  /*
904  * For an INSERT from a VALUES RTE, return the attribute numbers
905  * of any VALUES columns that will no longer be used (due to the
906  * targetlist entry being replaced by a default expression).
907  */
908  if (values_attrno != 0 && apply_default && unused_values_attrnos)
909  *unused_values_attrnos = bms_add_member(*unused_values_attrnos,
910  values_attrno);
911  }
912 
913  /*
914  * Updates to identity and generated columns follow the same rules as
915  * above, except that UPDATE doesn't admit OVERRIDING clauses. Also,
916  * the source can't be a VALUES RTE, so we needn't consider that.
917  */
918  if (commandType == CMD_UPDATE)
919  {
920  if (att_tup->attidentity == ATTRIBUTE_IDENTITY_ALWAYS &&
921  new_tle && !apply_default)
922  ereport(ERROR,
923  (errcode(ERRCODE_GENERATED_ALWAYS),
924  errmsg("column \"%s\" can only be updated to DEFAULT",
925  NameStr(att_tup->attname)),
926  errdetail("Column \"%s\" is an identity column defined as GENERATED ALWAYS.",
927  NameStr(att_tup->attname))));
928 
929  if (att_tup->attgenerated && new_tle && !apply_default)
930  ereport(ERROR,
931  (errcode(ERRCODE_GENERATED_ALWAYS),
932  errmsg("column \"%s\" can only be updated to DEFAULT",
933  NameStr(att_tup->attname)),
934  errdetail("Column \"%s\" is a generated column.",
935  NameStr(att_tup->attname))));
936  }
937 
938  if (att_tup->attgenerated)
939  {
940  /*
941  * stored generated column will be fixed in executor
942  */
943  new_tle = NULL;
944  }
945  else if (apply_default)
946  {
947  Node *new_expr;
948 
949  new_expr = build_column_default(target_relation, attrno);
950 
951  /*
952  * If there is no default (ie, default is effectively NULL), we
953  * can omit the tlist entry in the INSERT case, since the planner
954  * can insert a NULL for itself, and there's no point in spending
955  * any more rewriter cycles on the entry. But in the UPDATE case
956  * we've got to explicitly set the column to NULL.
957  */
958  if (!new_expr)
959  {
960  if (commandType == CMD_INSERT)
961  new_tle = NULL;
962  else
963  {
964  new_expr = (Node *) makeConst(att_tup->atttypid,
965  -1,
966  att_tup->attcollation,
967  att_tup->attlen,
968  (Datum) 0,
969  true, /* isnull */
970  att_tup->attbyval);
971  /* this is to catch a NOT NULL domain constraint */
972  new_expr = coerce_to_domain(new_expr,
973  InvalidOid, -1,
974  att_tup->atttypid,
977  -1,
978  false);
979  }
980  }
981 
982  if (new_expr)
983  new_tle = makeTargetEntry((Expr *) new_expr,
984  attrno,
985  pstrdup(NameStr(att_tup->attname)),
986  false);
987  }
988 
989  /*
990  * For an UPDATE on a trigger-updatable view, provide a dummy entry
991  * whenever there is no explicit assignment.
992  */
993  if (new_tle == NULL && commandType == CMD_UPDATE &&
994  target_relation->rd_rel->relkind == RELKIND_VIEW &&
995  view_has_instead_trigger(target_relation, CMD_UPDATE))
996  {
997  Node *new_expr;
998 
999  new_expr = (Node *) makeVar(result_rti,
1000  attrno,
1001  att_tup->atttypid,
1002  att_tup->atttypmod,
1003  att_tup->attcollation,
1004  0);
1005 
1006  new_tle = makeTargetEntry((Expr *) new_expr,
1007  attrno,
1008  pstrdup(NameStr(att_tup->attname)),
1009  false);
1010  }
1011 
1012  if (new_tle)
1013  new_tlist = lappend(new_tlist, new_tle);
1014  }
1015 
1016  pfree(new_tles);
1017 
1018  return list_concat(new_tlist, junk_tlist);
1019 }
#define NIL
Definition: pg_list.h:65
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
int errhint(const char *fmt,...)
Definition: elog.c:1156
static bool view_has_instead_trigger(Relation view, CmdType event)
#define RelationGetNumberOfAttributes(relation)
Definition: rel.h:463
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
char * pstrdup(const char *in)
Definition: mcxt.c:1299
Definition: nodes.h:539
List * list_concat(List *list1, const List *list2)
Definition: list.c:530
int errcode(int sqlerrcode)
Definition: elog.c:698
AttrNumber varattno
Definition: primnodes.h:191
Form_pg_class rd_rel
Definition: rel.h:110
Definition: primnodes.h:186
Const * makeConst(Oid consttype, int32 consttypmod, Oid constcollid, int constlen, Datum constvalue, bool constisnull, bool constbyval)
Definition: makefuncs.c:299
void pfree(void *pointer)
Definition: mcxt.c:1169
bool resjunk
Definition: primnodes.h:1451
#define ERROR
Definition: elog.h:46
Node * coerce_to_domain(Node *arg, Oid baseTypeId, int32 baseTypeMod, Oid typeId, CoercionContext ccontext, CoercionForm cformat, int location, bool hideInputCoercion)
Definition: parse_coerce.c:676
int errdetail(const char *fmt,...)
Definition: elog.c:1042
AttrNumber resno
Definition: primnodes.h:1445
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:203
TargetEntry * flatCopyTargetEntry(TargetEntry *src_tle)
Definition: makefuncs.c:271
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:238
Var * makeVar(Index varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:66
List * lappend(List *list, void *datum)
Definition: list.c:336
Index varno
Definition: primnodes.h:189
static Bitmapset * findDefaultOnlyColumns(RangeTblEntry *rte)
Node * build_column_default(Relation rel, int attrno)
void * palloc0(Size size)
Definition: mcxt.c:1093
uintptr_t Datum
Definition: postgres.h:411
TupleDesc rd_att
Definition: rel.h:111
#define InvalidOid
Definition: postgres_ext.h:36
#define ereport(elevel,...)
Definition: elog.h:157
#define lfirst(lc)
Definition: pg_list.h:169
Expr * expr
Definition: primnodes.h:1444
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:736
int errmsg(const char *fmt,...)
Definition: elog.c:909
static TargetEntry * process_matched_tle(TargetEntry *src_tle, TargetEntry *prior_tle, const char *attrName)
#define elog(elevel,...)
Definition: elog.h:232
#define NameStr(name)
Definition: c.h:681
Definition: pg_list.h:50
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:427

◆ rewriteTargetView()

static Query* rewriteTargetView ( Query parsetree,
Relation  view 
)
static

Definition at line 3043 of file rewriteHandler.c.

References _, acquireLocksOnSubLinks(), AddQual(), addRangeTableEntryForRelation(), adjust_view_column_set(), Assert, bms_add_member(), bms_is_empty(), BuildOnConflictExcludedTargetlist(), WithCheckOption::cascaded, ChangeVarNodes(), RangeTblEntry::checkAsUser, checkExprHasSubLink(), CMD_DELETE, CMD_INSERT, CMD_UPDATE, Query::commandType, copyObject, elog, ereport, errcode(), errdetail_internal(), errhint(), errmsg(), ERROR, TargetEntry::expr, FirstLowInvalidHeapAttributeNumber, acquireLocksOnSubLinks_context::for_execute, FromExpr::fromlist, get_tle_by_resno(), get_view_query(), Query::hasSubLinks, RangeTblEntry::inh, RangeTblEntry::insertedCols, IsA, Query::jointree, WithCheckOption::kind, lappend(), lcons(), lfirst, linitial, linitial_node, list_length(), make_parsestate(), makeAlias(), makeNode, NIL, NoLock, Query::onConflict, ONCONFLICT_UPDATE, OnConflictExpr::onConflictSet, ParseNamespaceItem::p_rte, WithCheckOption::polname, pstrdup(), QTW_IGNORE_RC_SUBQUERIES, WithCheckOption::qual, FromExpr::quals, query_tree_walker(), RelationData::rd_rel, RelationGetRelationName, RelationHasCascadedCheckOption, RelationHasCheckOption, RelationIsSecurityView, RangeTblEntry::relid, RangeTblEntry::relkind, RangeTblEntry::rellockmode, WithCheckOption::relname, REPLACEVARS_REPORT_ERROR, ReplaceVarsFromTargetList(), RangeTblEntry::requiredPerms, TargetEntry::resjunk, TargetEntry::resno, Query::resultRelation, RowExclusiveLock, rt_fetch, Query::rtable, RTE_RELATION, RangeTblEntry::rtekind, RangeTblRef::rtindex, RangeTblEntry::securityQuals, table_close(), table_open(), Query::targetList, RangeTblEntry::updatedCols, view_cols_are_auto_updatable(), view_query_is_auto_updatable(), and WCO_VIEW_CHECK.

Referenced by RewriteQuery().

3044 {
3045  Query *viewquery;
3046  const char *auto_update_detail;
3047  RangeTblRef *rtr;
3048  int base_rt_index;
3049  int new_rt_index;
3050  RangeTblEntry *base_rte;
3051  RangeTblEntry *view_rte;
3052  RangeTblEntry *new_rte;
3053  Relation base_rel;
3054  List *view_targetlist;
3055  ListCell *lc;
3056 
3057  /*
3058  * Get the Query from the view's ON SELECT rule. We're going to munge the
3059  * Query to change the view's base relation into the target relation,
3060  * along with various other changes along the way, so we need to make a
3061  * copy of it (get_view_query() returns a pointer into the relcache, so we
3062  * have to treat it as read-only).
3063  */
3064  viewquery = copyObject(get_view_query(view));
3065 
3066  /* The view must be updatable, else fail */
3067  auto_update_detail =
3068  view_query_is_auto_updatable(viewquery,
3069  parsetree->commandType != CMD_DELETE);
3070 
3071  if (auto_update_detail)
3072  {
3073  /* messages here should match execMain.c's CheckValidResultRel */
3074  switch (parsetree->commandType)
3075  {
3076  case CMD_INSERT:
3077  ereport(ERROR,
3078  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3079  errmsg("cannot insert into view \"%s\"",
3080  RelationGetRelationName(view)),
3081  errdetail_internal("%s", _(auto_update_detail)),
3082  errhint("To enable inserting into the view, provide an INSTEAD OF INSERT trigger or an unconditional ON INSERT DO INSTEAD rule.")));
3083  break;
3084  case CMD_UPDATE:
3085  ereport(ERROR,
3086  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3087  errmsg("cannot update view \"%s\"",
3088  RelationGetRelationName(view)),
3089  errdetail_internal("%s", _(auto_update_detail)),
3090  errhint("To enable updating the view, provide an INSTEAD OF UPDATE trigger or an unconditional ON UPDATE DO INSTEAD rule.")));
3091  break;
3092  case CMD_DELETE:
3093  ereport(ERROR,
3094  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3095  errmsg("cannot delete from view \"%s\"",
3096  RelationGetRelationName(view)),
3097  errdetail_internal("%s", _(auto_update_detail)),
3098  errhint("To enable deleting from the view, provide an INSTEAD OF DELETE trigger or an unconditional ON DELETE DO INSTEAD rule.")));
3099  break;
3100  default:
3101  elog(ERROR, "unrecognized CmdType: %d",
3102  (int) parsetree->commandType);
3103  break;
3104  }
3105  }
3106 
3107  /*
3108  * For INSERT/UPDATE the modified columns must all be updatable. Note that
3109  * we get the modified columns from the query's targetlist, not from the
3110  * result RTE's insertedCols and/or updatedCols set, since
3111  * rewriteTargetListIU may have added additional targetlist entries for
3112  * view defaults, and these must also be updatable.
3113  */
3114  if (parsetree->commandType != CMD_DELETE)
3115  {
3116  Bitmapset *modified_cols = NULL;
3117  char *non_updatable_col;
3118 
3119  foreach(lc, parsetree->targetList)
3120  {
3121  TargetEntry *tle = (TargetEntry *) lfirst(lc);
3122 
3123  if (!tle->resjunk)
3124  modified_cols = bms_add_member(modified_cols,
3126  }
3127 
3128  if (parsetree->onConflict)
3129  {
3130  foreach(lc, parsetree->onConflict->onConflictSet)
3131  {
3132  TargetEntry *tle = (TargetEntry *) lfirst(lc);
3133 
3134  if (!tle->resjunk)
3135  modified_cols = bms_add_member(modified_cols,
3137  }
3138  }
3139 
3140  auto_update_detail = view_cols_are_auto_updatable(viewquery,
3141  modified_cols,
3142  NULL,
3143  &non_updatable_col);
3144  if (auto_update_detail)
3145  {
3146  /*
3147  * This is a different error, caused by an attempt to update a
3148  * non-updatable column in an otherwise updatable view.
3149  */
3150  switch (parsetree->commandType)
3151  {
3152  case CMD_INSERT:
3153  ereport(ERROR,
3154  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3155  errmsg("cannot insert into column \"%s\" of view \"%s\"",
3156  non_updatable_col,
3157  RelationGetRelationName(view)),
3158  errdetail_internal("%s", _(auto_update_detail))));
3159  break;
3160  case CMD_UPDATE:
3161  ereport(ERROR,
3162  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3163  errmsg("cannot update column \"%s\" of view \"%s\"",
3164  non_updatable_col,
3165  RelationGetRelationName(view)),
3166  errdetail_internal("%s", _(auto_update_detail))));
3167  break;
3168  default:
3169  elog(ERROR, "unrecognized CmdType: %d",
3170  (int) parsetree->commandType);
3171  break;
3172  }
3173  }
3174  }
3175 
3176  /* Locate RTE describing the view in the outer query */
3177  view_rte = rt_fetch(parsetree->resultRelation, parsetree->rtable);
3178 
3179  /*
3180  * If we get here, view_query_is_auto_updatable() has verified that the
3181  * view contains a single base relation.
3182  */
3183  Assert(list_length(viewquery->jointree->fromlist) == 1);
3184  rtr = linitial_node(RangeTblRef, viewquery->jointree->fromlist);
3185 
3186  base_rt_index = rtr->rtindex;
3187  base_rte = rt_fetch(base_rt_index, viewquery->rtable);
3188  Assert(base_rte->rtekind == RTE_RELATION);
3189 
3190  /*
3191  * Up to now, the base relation hasn't been touched at all in our query.
3192  * We need to acquire lock on it before we try to do anything with it.
3193  * (The subsequent recursive call of RewriteQuery will suppose that we
3194  * already have the right lock!) Since it will become the query target
3195  * relation, RowExclusiveLock is always the right thing.
3196  */
3197  base_rel = table_open(base_rte->relid, RowExclusiveLock);
3198 
3199  /*
3200  * While we have the relation open, update the RTE's relkind, just in case
3201  * it changed since this view was made (cf. AcquireRewriteLocks).
3202  */
3203  base_rte->relkind = base_rel->rd_rel->relkind;
3204 
3205  /*
3206  * If the view query contains any sublink subqueries then we need to also
3207  * acquire locks on any relations they refer to. We know that there won't
3208  * be any subqueries in the range table or CTEs, so we can skip those, as
3209  * in AcquireRewriteLocks.
3210  */
3211  if (viewquery->hasSubLinks)
3212  {
3214 
3215  context.for_execute = true;
3216  query_tree_walker(viewquery, acquireLocksOnSubLinks, &context,
3218  }
3219 
3220  /*
3221  * Create a new target RTE describing the base relation, and add it to the
3222  * outer query's rangetable. (What's happening in the next few steps is
3223  * very much like what the planner would do to "pull up" the view into the
3224  * outer query. Perhaps someday we should refactor things enough so that
3225  * we can share code with the planner.)
3226  *
3227  * Be sure to set rellockmode to the correct thing for the target table.
3228  * Since we copied the whole viewquery above, we can just scribble on
3229  * base_rte instead of copying it.
3230  */
3231  new_rte = base_rte;
3232  new_rte->rellockmode = RowExclusiveLock;
3233 
3234  parsetree->rtable = lappend(parsetree->rtable, new_rte);
3235  new_rt_index = list_length(parsetree->rtable);
3236 
3237  /*
3238  * INSERTs never inherit. For UPDATE/DELETE, we use the view query's
3239  * inheritance flag for the base relation.
3240  */
3241  if (parsetree->commandType == CMD_INSERT)
3242  new_rte->inh = false;
3243 
3244  /*
3245  * Adjust the view's targetlist Vars to reference the new target RTE, ie
3246  * make their varnos be new_rt_index instead of base_rt_index. There can
3247  * be no Vars for other rels in the tlist, so this is sufficient to pull
3248  * up the tlist expressions for use in the outer query. The tlist will
3249  * provide the replacement expressions used by ReplaceVarsFromTargetList
3250  * below.
3251  */
3252  view_targetlist = viewquery->targetList;
3253 
3254  ChangeVarNodes((Node *) view_targetlist,
3255  base_rt_index,
3256  new_rt_index,
3257  0);
3258 
3259  /*
3260  * Mark the new target RTE for the permissions checks that we want to
3261  * enforce against the view owner, as distinct from the query caller. At
3262  * the relation level, require the same INSERT/UPDATE/DELETE permissions
3263  * that the query caller needs against the view. We drop the ACL_SELECT
3264  * bit that is presumably in new_rte->requiredPerms initially.
3265  *
3266  * Note: the original view RTE remains in the query's rangetable list.
3267  * Although it will be unused in the query plan, we need it there so that
3268  * the executor still performs appropriate permissions checks for the
3269  * query caller's use of the view.
3270  */
3271  new_rte->checkAsUser = view->rd_rel->relowner;
3272  new_rte->requiredPerms = view_rte->requiredPerms;
3273 
3274  /*
3275  * Now for the per-column permissions bits.
3276  *
3277  * Initially, new_rte contains selectedCols permission check bits for all
3278  * base-rel columns referenced by the view, but since the view is a SELECT
3279  * query its insertedCols/updatedCols is empty. We set insertedCols and
3280  * updatedCols to include all the columns the outer query is trying to
3281  * modify, adjusting the column numbers as needed. But we leave
3282  * selectedCols as-is, so the view owner must have read permission for all
3283  * columns used in the view definition, even if some of them are not read
3284  * by the outer query. We could try to limit selectedCols to only columns
3285  * used in the transformed query, but that does not correspond to what
3286  * happens in ordinary SELECT usage of a view: all referenced columns must
3287  * have read permission, even if optimization finds that some of them can
3288  * be discarded during query transformation. The flattening we're doing
3289  * here is an optional optimization, too. (If you are unpersuaded and
3290  * want to change this, note that applying adjust_view_column_set to
3291  * view_rte->selectedCols is clearly *not* the right answer, since that
3292  * neglects base-rel columns used in the view's WHERE quals.)
3293  *
3294  * This step needs the modified view targetlist, so we have to do things
3295  * in this order.
3296  */
3297  Assert(bms_is_empty(new_rte->insertedCols) &&
3298  bms_is_empty(new_rte->updatedCols));
3299 
3300  new_rte->insertedCols = adjust_view_column_set(view_rte->insertedCols,
3301  view_targetlist);
3302 
3303  new_rte->updatedCols = adjust_view_column_set(view_rte->updatedCols,
3304  view_targetlist);
3305 
3306  /*
3307  * Move any security barrier quals from the view RTE onto the new target
3308  * RTE. Any such quals should now apply to the new target RTE and will
3309  * not reference the original view RTE in the rewritten query.
3310  */
3311  new_rte->securityQuals = view_rte->securityQuals;
3312  view_rte->securityQuals = NIL;
3313 
3314  /*
3315  * Now update all Vars in the outer query that reference the view to
3316  * reference the appropriate column of the base relation instead.
3317  */
3318  parsetree = (Query *)
3319  ReplaceVarsFromTargetList((Node *) parsetree,
3320  parsetree->resultRelation,
3321  0,
3322  view_rte,
3323  view_targetlist,
3325  0,
3326  &parsetree->hasSubLinks);
3327 
3328  /*
3329  * Update all other RTI references in the query that point to the view
3330  * (for example, parsetree->resultRelation itself) to point to the new
3331  * base relation instead. Vars will not be affected since none of them
3332  * reference parsetree->resultRelation any longer.
3333  */
3334  ChangeVarNodes((Node *) parsetree,
3335  parsetree->resultRelation,
3336  new_rt_index,
3337  0);
3338  Assert(parsetree->resultRelation == new_rt_index);
3339 
3340  /*
3341  * For INSERT/UPDATE we must also update resnos in the targetlist to refer
3342  * to columns of the base relation, since those indicate the target
3343  * columns to be affected.
3344  *
3345  * Note that this destroys the resno ordering of the targetlist, but that
3346  * will be fixed when we recurse through rewriteQuery, which will invoke
3347  * rewriteTargetListIU again on the updated targetlist.
3348  */
3349  if (parsetree->commandType != CMD_DELETE)
3350  {
3351  foreach(lc, parsetree->targetList)
3352  {
3353  TargetEntry *tle = (TargetEntry *) lfirst(lc);
3354  TargetEntry *view_tle;
3355 
3356  if (tle->resjunk)
3357  continue;
3358 
3359  view_tle = get_tle_by_resno(view_targetlist, tle->resno);
3360  if (view_tle != NULL && !view_tle->resjunk && IsA(view_tle->expr, Var))
3361  tle->resno = ((Var *) view_tle->expr)->varattno;
3362  else
3363  elog(ERROR, "attribute number %d not found in view targetlist",
3364  tle->resno);
3365  }
3366  }
3367 
3368  /*
3369  * For INSERT .. ON CONFLICT .. DO UPDATE, we must also update assorted
3370  * stuff in the onConflict data structure.
3371  */
3372  if (parsetree->onConflict &&
3373  parsetree->onConflict->action == ONCONFLICT_UPDATE)
3374  {
3375  Index old_exclRelIndex,
3376  new_exclRelIndex;
3377  ParseNamespaceItem *new_exclNSItem;
3378  RangeTblEntry *new_exclRte;
3379  List *tmp_tlist;
3380 
3381  /*
3382  * Like the INSERT/UPDATE code above, update the resnos in the
3383  * auxiliary UPDATE targetlist to refer to columns of the base
3384  * relation.
3385  */
3386  foreach(lc, parsetree->onConflict->onConflictSet)
3387  {
3388  TargetEntry *tle = (TargetEntry *) lfirst(lc);
3389  TargetEntry *view_tle;
3390 
3391  if (tle->resjunk)
3392  continue;
3393 
3394  view_tle = get_tle_by_resno(view_targetlist, tle->resno);
3395  if (view_tle != NULL && !view_tle->resjunk && IsA(view_tle->expr, Var))
3396  tle->resno = ((Var *) view_tle->expr)->varattno;
3397  else
3398  elog(ERROR, "attribute number %d not found in view targetlist",
3399  tle->resno);
3400  }
3401 
3402  /*
3403  * Also, create a new RTE for the EXCLUDED pseudo-relation, using the
3404  * query's new base rel (which may well have a different column list
3405  * from the view, hence we need a new column alias list). This should
3406  * match transformOnConflictClause. In particular, note that the
3407  * relkind is set to composite to signal that we're not dealing with
3408  * an actual relation, and no permissions checks are wanted.
3409  */
3410  old_exclRelIndex = parsetree->onConflict->exclRelIndex;
3411 
3412  new_exclNSItem = addRangeTableEntryForRelation(make_parsestate(NULL),
3413  base_rel,
3415  makeAlias("excluded", NIL),
3416  false, false);
3417  new_exclRte = new_exclNSItem->p_rte;
3418  new_exclRte->relkind = RELKIND_COMPOSITE_TYPE;
3419  new_exclRte->requiredPerms = 0;
3420  /* other permissions fields in new_exclRte are already empty */
3421 
3422  parsetree->rtable = lappend(parsetree->rtable, new_exclRte);
3423  new_exclRelIndex = parsetree->onConflict->exclRelIndex =
3424  list_length(parsetree->rtable);
3425 
3426  /*
3427  * Replace the targetlist for the EXCLUDED pseudo-relation with a new
3428  * one, representing the columns from the new base relation.
3429  */
3430  parsetree->onConflict->exclRelTlist =
3431  BuildOnConflictExcludedTargetlist(base_rel, new_exclRelIndex);
3432 
3433  /*
3434  * Update all Vars in the ON CONFLICT clause that refer to the old
3435  * EXCLUDED pseudo-relation. We want to use the column mappings
3436  * defined in the view targetlist, but we need the outputs to refer to
3437  * the new EXCLUDED pseudo-relation rather than the new target RTE.
3438  * Also notice that "EXCLUDED.*" will be expanded using the view's
3439  * rowtype, which seems correct.
3440  */
3441  tmp_tlist = copyObject(view_targetlist);
3442 
3443  ChangeVarNodes((Node *) tmp_tlist, new_rt_index,
3444  new_exclRelIndex, 0);
3445 
3446  parsetree->onConflict = (OnConflictExpr *)
3447  ReplaceVarsFromTargetList((Node *) parsetree->onConflict,
3448  old_exclRelIndex,
3449  0,
3450  view_rte,
3451  tmp_tlist,
3453  0,
3454  &parsetree->hasSubLinks);
3455  }
3456 
3457  /*
3458  * For UPDATE/DELETE, pull up any WHERE quals from the view. We know that
3459  * any Vars in the quals must reference the one base relation, so we need
3460  * only adjust their varnos to reference the new target (just the same as
3461  * we did with the view targetlist).
3462  *
3463  * If it's a security-barrier view, its WHERE quals must be applied before
3464  * quals from the outer query, so we attach them to the RTE as security
3465  * barrier quals rather than adding them to the main WHERE clause.
3466  *
3467  * For INSERT, the view's quals can be ignored in the main query.
3468  */
3469  if (parsetree->commandType != CMD_INSERT &&
3470  viewquery->jointree->quals != NULL)
3471  {
3472  Node *viewqual = (Node *) viewquery->jointree->quals;
3473 
3474  /*
3475  * Even though we copied viewquery already at the top of this
3476  * function, we must duplicate the viewqual again here, because we may
3477  * need to use the quals again below for a WithCheckOption clause.
3478  */
3479  viewqual = copyObject(viewqual);
3480 
3481  ChangeVarNodes(viewqual, base_rt_index, new_rt_index, 0);
3482 
3483  if (RelationIsSecurityView(view))
3484  {
3485  /*
3486  * The view's quals go in front of existing barrier quals: those
3487  * would have come from an outer level of security-barrier view,
3488  * and so must get evaluated later.
3489  *
3490  * Note: the parsetree has been mutated, so the new_rte pointer is
3491  * stale and needs to be re-computed.
3492  */
3493  new_rte = rt_fetch(new_rt_index, parsetree->rtable);
3494  new_rte->securityQuals = lcons(viewqual, new_rte->securityQuals);
3495 
3496  /*
3497  * Do not set parsetree->hasRowSecurity, because these aren't RLS
3498  * conditions (they aren't affected by enabling/disabling RLS).
3499  */
3500 
3501  /*
3502  * Make sure that the query is marked correctly if the added qual
3503  * has sublinks.
3504  */
3505  if (!parsetree->hasSubLinks)
3506  parsetree->hasSubLinks = checkExprHasSubLink(viewqual);
3507  }
3508  else
3509  AddQual(parsetree, (Node *) viewqual);
3510  }
3511 
3512  /*
3513  * For INSERT/UPDATE, if the view has the WITH CHECK OPTION, or any parent
3514  * view specified WITH CASCADED CHECK OPTION, add the quals from the view
3515  * to the query's withCheckOptions list.
3516  */
3517  if (parsetree->commandType != CMD_DELETE)
3518  {
3519  bool has_wco = RelationHasCheckOption(view);
3520  bool cascaded = RelationHasCascadedCheckOption(view);
3521 
3522  /*
3523  * If the parent view has a cascaded check option, treat this view as
3524  * if it also had a cascaded check option.
3525  *
3526  * New WithCheckOptions are added to the start of the list, so if
3527  * there is a cascaded check option, it will be the first item in the
3528  * list.
3529  */
3530  if (parsetree->withCheckOptions != NIL)
3531  {
3532  WithCheckOption *parent_wco =
3533  (WithCheckOption *) linitial(parsetree->withCheckOptions);
3534 
3535  if (parent_wco->cascaded)
3536  {
3537  has_wco = true;
3538  cascaded = true;
3539  }
3540  }
3541 
3542  /*
3543  * Add the new WithCheckOption to the start of the list, so that
3544  * checks on inner views are run before checks on outer views, as
3545  * required by the SQL standard.
3546  *
3547  * If the new check is CASCADED, we need to add it even if this view
3548  * has no quals, since there may be quals on child views. A LOCAL
3549  * check can be omitted if this view has no quals.
3550  */
3551  if (has_wco && (cascaded || viewquery->jointree->quals != NULL))
3552  {
3553  WithCheckOption *wco;
3554 
3555  wco = makeNode(WithCheckOption);
3556  wco->kind = WCO_VIEW_CHECK;
3557  wco->relname = pstrdup(RelationGetRelationName(view));
3558  wco->polname = NULL;
3559  wco->qual = NULL;
3560  wco->cascaded = cascaded;
3561 
3562  parsetree->withCheckOptions = lcons(wco,
3563  parsetree->withCheckOptions);
3564 
3565  if (viewquery->jointree->quals != NULL)
3566  {
3567  wco->qual = (Node *) viewquery->jointree->quals;
3568  ChangeVarNodes(wco->qual, base_rt_index, new_rt_index, 0);
3569 
3570  /*
3571  * Make sure that the query is marked correctly if the added
3572  * qual has sublinks. We can skip this check if the query is
3573  * already marked, or if the command is an UPDATE, in which
3574  * case the same qual will have already been added, and this
3575  * check will already have been done.
3576  */
3577  if (!parsetree->hasSubLinks &&
3578  parsetree->commandType != CMD_UPDATE)
3579  parsetree->hasSubLinks = checkExprHasSubLink(wco->qual);
3580  }
3581  }
3582  }
3583 
3584  table_close(base_rel, NoLock);
3585 
3586  return parsetree;
3587 }
#define NIL
Definition: pg_list.h:65
bool query_tree_walker(Query *query, bool(*walker)(), void *context, int flags)
Definition: nodeFuncs.c:2355
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
int errhint(const char *fmt,...)
Definition: elog.c:1156
static bool acquireLocksOnSubLinks(Node *node, acquireLocksOnSubLinks_context *context)
FromExpr * jointree
Definition: parsenodes.h:148
bool checkExprHasSubLink(Node *node)
Definition: rewriteManip.c:277
OnConflictExpr * onConflict
Definition: parsenodes.h:154
List * withCheckOptions
Definition: parsenodes.h:183
List * securityQuals
Definition: parsenodes.h:1151
char * pstrdup(const char *in)
Definition: mcxt.c:1299
static const char * view_cols_are_auto_updatable(Query *viewquery, Bitmapset *required_cols, Bitmapset **updatable_cols, char **non_updatable_col)
int resultRelation
Definition: parsenodes.h:130
List * BuildOnConflictExcludedTargetlist(Relation targetrel, Index exclRelIndex)
Definition: analyze.c:1125
Definition: nodes.h:539
int errcode(int sqlerrcode)
Definition: elog.c:698
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
AclMode requiredPerms
Definition: parsenodes.h:1145
List * fromlist
Definition: primnodes.h:1553
Form_pg_class rd_rel
Definition: rel.h:110
Definition: primnodes.h:186
#define linitial_node(type, l)
Definition: pg_list.h:177
Node * quals
Definition: primnodes.h:1554
int errdetail_internal(const char *fmt,...)
Definition: elog.c:1069
List * targetList
Definition: parsenodes.h:150
ParseNamespaceItem * addRangeTableEntryForRelation(ParseState *pstate, Relation rel, int lockmode, Alias *alias, bool inh, bool inFromCl)
ParseState * make_parsestate(ParseState *parentParseState)
Definition: parse_node.c:44
#define QTW_IGNORE_RC_SUBQUERIES
Definition: nodeFuncs.h:22
Alias * makeAlias(const char *aliasname, List *colnames)
Definition: makefuncs.c:387
RangeTblEntry * p_rte
Definition: parse_node.h:268
bool resjunk
Definition: primnodes.h:1451
#define linitial(l)
Definition: pg_list.h:174
List * rtable
Definition: parsenodes.h:147
#define ERROR
Definition: elog.h:46
#define NoLock
Definition: lockdefs.h:34
List * exclRelTlist
Definition: primnodes.h:1581
#define RowExclusiveLock
Definition: lockdefs.h:38
AttrNumber resno
Definition: primnodes.h:1445
#define RelationGetRelationName(relation)
Definition: rel.h:491
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
List * lappend(List *list, void *datum)
Definition: list.c:336
OnConflictAction action
Definition: primnodes.h:1569
bool bms_is_empty(const Bitmapset *a)
Definition: bitmapset.c:701
Node * ReplaceVarsFromTargetList(Node *node, int target_varno, int sublevels_up, RangeTblEntry *target_rte, List *targetlist, ReplaceVarsNoMatchOption nomatch_option, int nomatch_varno, bool *outer_hasSubLinks)
unsigned int Index
Definition: c.h:549
#define ereport(elevel,...)
Definition: elog.h:157
Bitmapset * updatedCols
Definition: parsenodes.h:1149
static Bitmapset * adjust_view_column_set(Bitmapset *cols, List *targetlist)
CmdType commandType
Definition: parsenodes.h:120
List * lcons(void *datum, List *list)
Definition: list.c:468
#define makeNode(_type_)
Definition: nodes.h:587
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
void AddQual(Query *parsetree, Node *qual)
Definition: rewriteManip.c:979
Expr * expr
Definition: primnodes.h:1444
static int list_length(const List *l)
Definition: pg_list.h:149
#define RelationHasCascadedCheckOption(relation)
Definition: rel.h:420
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:736
RTEKind rtekind
Definition: parsenodes.h:995
int errmsg(const char *fmt,...)
Definition: elog.c:909
bool hasSubLinks
Definition: parsenodes.h:136
Query * get_view_query(Relation view)
#define elog(elevel,...)
Definition: elog.h:232
Bitmapset * insertedCols
Definition: parsenodes.h:1148
#define RelationIsSecurityView(relation)
Definition: rel.h:388
TargetEntry * get_tle_by_resno(List *tlist, AttrNumber resno)
List * onConflictSet
Definition: primnodes.h:1578
void ChangeVarNodes(Node *node, int rt_index, int new_index, int sublevels_up)
Definition: rewriteManip.c:610
#define copyObject(obj)
Definition: nodes.h:655
const char * view_query_is_auto_updatable(Query *viewquery, bool check_cols)
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: pg_list.h:50
#define _(x)
Definition: elog.c:89
#define RelationHasCheckOption(relation)
Definition: rel.h:398

◆ rewriteValuesRTE()

static bool rewriteValuesRTE ( Query parsetree,
RangeTblEntry rte,
int  rti,
Relation  target_relation,
bool  force_nulls,
Bitmapset unused_cols 
)
static

Definition at line 1421 of file rewriteHandler.c.

References Assert, bms_is_member(), build_column_default(), CMD_INSERT, COERCE_IMPLICIT_CAST, coerce_to_domain(), COERCION_IMPLICIT, SetToDefault::collation, elog, ERROR, TargetEntry::expr, i, InvalidOid, IsA, RewriteRule::isInstead, lappend(), lfirst, linitial, list_length(), makeConst(), makeNullConst(), matchLocks(), NIL, palloc0(), pfree(), RewriteRule::qual, RelationData::rd_att, RelationData::rd_rel, RelationData::rd_rules, TargetEntry::resno, Query::resultRelation, searchForDefault(), Query::targetList, TupleDescAttr, SetToDefault::typeId, SetToDefault::typeMod, RangeTblEntry::values_lists, Var::varattno, Var::varno, and view_has_instead_trigger().

Referenced by RewriteQuery().

1424 {
1425  List *newValues;
1426  ListCell *lc;
1427  bool isAutoUpdatableView;
1428  bool allReplaced;
1429  int numattrs;
1430  int *attrnos;
1431 
1432  /*
1433  * Rebuilding all the lists is a pretty expensive proposition in a big
1434  * VALUES list, and it's a waste of time if there aren't any DEFAULT
1435  * placeholders. So first scan to see if there are any.
1436  *
1437  * We skip this check if force_nulls is true, because we know that there
1438  * are DEFAULT items present in that case.
1439  */
1440  if (!force_nulls && !searchForDefault(rte))
1441  return true; /* nothing to do */
1442 
1443  /*
1444  * Scan the targetlist for entries referring to the VALUES RTE, and note
1445  * the target attributes. As noted above, we should only need to do this
1446  * for targetlist entries containing simple Vars --- nothing else in the
1447  * VALUES RTE should contain DEFAULT items (except possibly for unused
1448  * columns), and we complain if such a thing does occur.
1449  */
1450  numattrs = list_length(linitial(rte->values_lists));
1451  attrnos = (int *) palloc0(numattrs * sizeof(int));
1452 
1453  foreach(lc, parsetree->targetList)
1454  {
1455  TargetEntry *tle = (TargetEntry *) lfirst(lc);
1456 
1457  if (IsA(tle->expr, Var))
1458  {
1459  Var *var = (Var *) tle->expr;
1460 
1461  if (var->varno == rti)
1462  {
1463  int attrno = var->varattno;
1464 
1465  Assert(attrno >= 1 && attrno <= numattrs);
1466  attrnos[attrno - 1] = tle->resno;
1467  }
1468  }
1469  }
1470 
1471  /*
1472  * Check if the target relation is an auto-updatable view, in which case
1473  * unresolved defaults will be left untouched rather than being set to
1474  * NULL. If force_nulls is true, we always set DEFAULT items to NULL, so
1475  * skip this check in that case --- it isn't an auto-updatable view.
1476  */
1477  isAutoUpdatableView = false;
1478  if (!force_nulls &&
1479  target_relation->rd_rel->relkind == RELKIND_VIEW &&
1480  !view_has_instead_trigger(target_relation, CMD_INSERT))
1481  {
1482  List *locks;
1483  bool hasUpdate;
1484  bool found;
1485  ListCell *l;
1486 
1487  /* Look for an unconditional DO INSTEAD rule */
1488  locks = matchLocks(CMD_INSERT, target_relation->rd_rules,
1489  parsetree->resultRelation, parsetree, &hasUpdate);
1490 
1491  found = false;
1492  foreach(l, locks)
1493  {
1494  RewriteRule *rule_lock = (RewriteRule *) lfirst(l);
1495 
1496  if (rule_lock->isInstead &&
1497  rule_lock->qual == NULL)
1498  {
1499  found = true;
1500  break;
1501  }
1502  }
1503 
1504  /*
1505  * If we didn't find an unconditional DO INSTEAD rule, assume that the
1506  * view is auto-updatable. If it isn't, rewriteTargetView() will
1507  * throw an error.
1508  */
1509  if (!found)
1510  isAutoUpdatableView = true;
1511  }
1512 
1513  newValues = NIL;
1514  allReplaced = true;
1515  foreach(lc, rte->values_lists)
1516  {
1517  List *sublist = (List *) lfirst(lc);
1518  List *newList = NIL;
1519  ListCell *lc2;
1520  int i;
1521 
1522  Assert(list_length(sublist) == numattrs);
1523 
1524  i = 0;
1525  foreach(lc2, sublist)
1526  {
1527  Node *col = (Node *) lfirst(lc2);
1528  int attrno = attrnos[i++];
1529 
1530  if (IsA(col, SetToDefault))
1531  {
1532  Form_pg_attribute att_tup;
1533  Node *new_expr;
1534 
1535  /*
1536  * If this column isn't used, just replace the DEFAULT with
1537  * NULL (attrno will be 0 in this case because the targetlist
1538  * entry will have been replaced by the default expression).
1539  */
1540  if (bms_is_member(i, unused_cols))
1541  {
1542  SetToDefault *def = (SetToDefault *) col;
1543 
1544  newList = lappend(newList,
1545  makeNullConst(def->typeId,
1546  def->typeMod,
1547  def->collation));
1548  continue;
1549  }
1550 
1551  if (attrno == 0)
1552  elog(ERROR, "cannot set value in column %d to DEFAULT", i);
1553  att_tup = TupleDescAttr(target_relation->rd_att, attrno - 1);
1554 
1555  if (!force_nulls && !att_tup->attisdropped)
1556  new_expr = build_column_default(target_relation, attrno);
1557  else
1558  new_expr = NULL; /* force a NULL if dropped */
1559 
1560  /*
1561  * If there is no default (ie, default is effectively NULL),
1562  * we've got to explicitly set the column to NULL, unless the
1563  * target relation is an auto-updatable view.
1564  */
1565  if (!new_expr)
1566  {
1567  if (isAutoUpdatableView)
1568  {
1569  /* Leave the value untouched */
1570  newList = lappend(newList, col);
1571  allReplaced = false;
1572  continue;
1573  }
1574 
1575  new_expr = (Node *) makeConst(att_tup->atttypid,
1576  -1,
1577  att_tup->attcollation,
1578  att_tup->attlen,
1579  (Datum) 0,
1580  true, /* isnull */
1581  att_tup->attbyval);
1582  /* this is to catch a NOT NULL domain constraint */
1583  new_expr = coerce_to_domain(new_expr,
1584  InvalidOid, -1,
1585  att_tup->atttypid,
1588  -1,
1589  false);
1590  }
1591  newList = lappend(newList, new_expr);
1592  }
1593  else
1594  newList = lappend(newList, col);
1595  }
1596  newValues = lappend(newValues, newList);
1597  }
1598  rte->values_lists = newValues;
1599 
1600  pfree(attrnos);
1601 
1602  return allReplaced;
1603 }
#define NIL
Definition: pg_list.h:65
Node * qual
Definition: prs2lock.h:28
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
static bool view_has_instead_trigger(Relation view, CmdType event)
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
int resultRelation
Definition: parsenodes.h:130
Definition: nodes.h:539
AttrNumber varattno
Definition: primnodes.h:191
Form_pg_class rd_rel
Definition: rel.h:110
Definition: primnodes.h:186
Const * makeConst(Oid consttype, int32 consttypmod, Oid constcollid, int constlen, Datum constvalue, bool constisnull, bool constbyval)
Definition: makefuncs.c:299
bool isInstead
Definition: prs2lock.h:31
List * values_lists
Definition: parsenodes.h:1100
List * targetList
Definition: parsenodes.h:150
Const * makeNullConst(Oid consttype, int32 consttypmod, Oid constcollid)
Definition: makefuncs.c:337
void pfree(void *pointer)
Definition: mcxt.c:1169
#define linitial(l)
Definition: pg_list.h:174
#define ERROR
Definition: elog.h:46
static bool searchForDefault(RangeTblEntry *rte)
Node * coerce_to_domain(Node *arg, Oid baseTypeId, int32 baseTypeMod, Oid typeId, CoercionContext ccontext, CoercionForm cformat, int location, bool hideInputCoercion)
Definition: parse_coerce.c:676
int32 typeMod
Definition: primnodes.h:1332
AttrNumber resno
Definition: primnodes.h:1445
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:203
List * lappend(List *list, void *datum)
Definition: list.c:336
Index varno
Definition: primnodes.h:189
Node * build_column_default(Relation rel, int attrno)
void * palloc0(Size size)
Definition: mcxt.c:1093
uintptr_t Datum
Definition: postgres.h:411
TupleDesc rd_att
Definition: rel.h:111
#define InvalidOid
Definition: postgres_ext.h:36
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
Expr * expr
Definition: primnodes.h:1444
RuleLock * rd_rules
Definition: rel.h:114
static int list_length(const List *l)
Definition: pg_list.h:149
#define elog(elevel,...)
Definition: elog.h:232
int i
Definition: pg_list.h:50
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:427
static List * matchLocks(CmdType event, RuleLock *rulelocks, int varno, Query *parsetree, bool *hasUpdate)

◆ searchForDefault()

static bool searchForDefault ( RangeTblEntry rte)
static

Definition at line 1296 of file rewriteHandler.c.

References IsA, lfirst, and RangeTblEntry::values_lists.

Referenced by rewriteValuesRTE().

1297 {
1298  ListCell *lc;
1299 
1300  foreach(lc, rte->values_lists)
1301  {
1302  List *sublist = (List *) lfirst(lc);
1303  ListCell *lc2;
1304 
1305  foreach(lc2, sublist)
1306  {
1307  Node *col = (Node *) lfirst(lc2);
1308 
1309  if (IsA(col, SetToDefault))
1310  return true;
1311  }
1312  }
1313  return false;
1314 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
Definition: nodes.h:539
List * values_lists
Definition: parsenodes.h:1100
#define lfirst(lc)
Definition: pg_list.h:169
Definition: pg_list.h:50

◆ view_col_is_auto_updatable()

static const char* view_col_is_auto_updatable ( RangeTblRef rtr,
TargetEntry tle 
)
static

Definition at line 2513 of file rewriteHandler.c.

References TargetEntry::expr, gettext_noop, IsA, TargetEntry::resjunk, RangeTblRef::rtindex, Var::varattno, Var::varlevelsup, and Var::varno.

Referenced by view_cols_are_auto_updatable(), and view_query_is_auto_updatable().

2514 {
2515  Var *var = (Var *) tle->expr;
2516 
2517  /*
2518  * For now, the only updatable columns we support are those that are Vars
2519  * referring to user columns of the underlying base relation.
2520  *
2521  * The view targetlist may contain resjunk columns (e.g., a view defined
2522  * like "SELECT * FROM t ORDER BY a+b" is auto-updatable) but such columns
2523  * are not auto-updatable, and in fact should never appear in the outer
2524  * query's targetlist.
2525  */
2526  if (tle->resjunk)
2527  return gettext_noop("Junk view columns are not updatable.");
2528 
2529  if (!IsA(var, Var) ||
2530  var->varno != rtr->rtindex ||
2531  var->varlevelsup != 0)
2532  return gettext_noop("View columns that are not columns of their base relation are not updatable.");
2533 
2534  if (var->varattno < 0)
2535  return gettext_noop("View columns that refer to system columns are not updatable.");
2536 
2537  if (var->varattno == 0)
2538  return gettext_noop("View columns that return whole-row references are not updatable.");
2539 
2540  return NULL; /* the view column is updatable */
2541 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
Index varlevelsup
Definition: primnodes.h:196
#define gettext_noop(x)
Definition: c.h:1197
AttrNumber varattno
Definition: primnodes.h:191
Definition: primnodes.h:186
bool resjunk
Definition: primnodes.h:1451
Index varno
Definition: primnodes.h:189
Expr * expr
Definition: primnodes.h:1444

◆ view_cols_are_auto_updatable()

static const char* view_cols_are_auto_updatable ( Query viewquery,
Bitmapset required_cols,
Bitmapset **  updatable_cols,
char **  non_updatable_col 
)
static

Definition at line 2709 of file rewriteHandler.c.

References Assert, bms_add_member(), bms_is_member(), FirstLowInvalidHeapAttributeNumber, FromExpr::fromlist, Query::jointree, lfirst, linitial_node, list_length(), TargetEntry::resname, Query::targetList, and view_col_is_auto_updatable().

Referenced by relation_is_updatable(), and rewriteTargetView().

2713 {
2714  RangeTblRef *rtr;
2715  AttrNumber col;
2716  ListCell *cell;
2717 
2718  /*
2719  * The caller should have verified that this view is auto-updatable and so
2720  * there should be a single base relation.
2721  */
2722  Assert(list_length(viewquery->jointree->fromlist) == 1);
2723  rtr = linitial_node(RangeTblRef, viewquery->jointree->fromlist);
2724 
2725  /* Initialize the optional return values */
2726  if (updatable_cols != NULL)
2727  *updatable_cols = NULL;
2728  if (non_updatable_col != NULL)
2729  *non_updatable_col = NULL;
2730 
2731  /* Test each view column for updatability */
2733  foreach(cell, viewquery->targetList)
2734  {
2735  TargetEntry *tle = (TargetEntry *) lfirst(cell);
2736  const char *col_update_detail;
2737 
2738  col++;
2739  col_update_detail = view_col_is_auto_updatable(rtr, tle);
2740 
2741  if (col_update_detail == NULL)
2742  {
2743  /* The column is updatable */
2744  if (updatable_cols != NULL)
2745  *updatable_cols = bms_add_member(*updatable_cols, col);
2746  }
2747  else if (bms_is_member(col, required_cols))
2748  {
2749  /* The required column is not updatable */
2750  if (non_updatable_col != NULL)
2751  *non_updatable_col = tle->resname;
2752  return col_update_detail;
2753  }
2754  }
2755 
2756  return NULL; /* all the required view columns are updatable */
2757 }
FromExpr * jointree
Definition: parsenodes.h:148
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
List * fromlist
Definition: primnodes.h:1553
char * resname
Definition: primnodes.h:1446
#define linitial_node(type, l)
Definition: pg_list.h:177
List * targetList
Definition: parsenodes.h:150
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
static int list_length(const List *l)
Definition: pg_list.h:149
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:736
static const char * view_col_is_auto_updatable(RangeTblRef *rtr, TargetEntry *tle)
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:427
int16 AttrNumber
Definition: attnum.h:21

◆ view_has_instead_trigger()

static bool view_has_instead_trigger ( Relation  view,
CmdType  event 
)
static

Definition at line 2475 of file rewriteHandler.c.

References CMD_DELETE, CMD_INSERT, CMD_UPDATE, elog, ERROR, TriggerDesc::trig_delete_instead_row, TriggerDesc::trig_insert_instead_row, TriggerDesc::trig_update_instead_row, and RelationData::trigdesc.

Referenced by RewriteQuery(), rewriteTargetListIU(), and rewriteValuesRTE().

2476 {
2477  TriggerDesc *trigDesc = view->trigdesc;
2478 
2479  switch (event)
2480  {
2481  case CMD_INSERT:
2482  if (trigDesc && trigDesc->trig_insert_instead_row)
2483  return true;
2484  break;
2485  case CMD_UPDATE:
2486  if (trigDesc && trigDesc->trig_update_instead_row)
2487  return true;
2488  break;
2489  case CMD_DELETE:
2490  if (trigDesc && trigDesc->trig_delete_instead_row)
2491  return true;
2492  break;
2493  default:
2494  elog(ERROR, "unrecognized CmdType: %d", (int) event);
2495  break;
2496  }
2497  return false;
2498 }
bool trig_insert_instead_row
Definition: reltrigger.h:58
#define ERROR
Definition: elog.h:46
TriggerDesc * trigdesc
Definition: rel.h:116
bool trig_update_instead_row
Definition: reltrigger.h:63
bool trig_delete_instead_row
Definition: reltrigger.h:68
#define elog(elevel,...)
Definition: elog.h:232

◆ view_query_is_auto_updatable()

const char* view_query_is_auto_updatable ( Query viewquery,
bool  check_cols 
)

Definition at line 2561 of file rewriteHandler.c.

References Query::cteList, Query::distinctClause, FromExpr::fromlist, gettext_noop, Query::groupClause, Query::groupingSets, Query::hasAggs, Query::hasTargetSRFs, Query::hasWindowFuncs, Query::havingQual, IsA, Query::jointree, lfirst, Query::limitCount, Query::limitOffset, linitial, list_length(), NIL, RangeTblEntry::relkind, rt_fetch, Query::rtable, RTE_RELATION, RangeTblEntry::rtekind, RangeTblRef::rtindex, Query::setOperations, RangeTblEntry::tablesample, Query::targetList, and view_col_is_auto_updatable().

Referenced by ATExecSetRelOptions(), DefineView(), relation_is_updatable(), and rewriteTargetView().

2562 {
2563  RangeTblRef *rtr;
2564  RangeTblEntry *base_rte;
2565 
2566  /*----------
2567  * Check if the view is simply updatable. According to SQL-92 this means:
2568  * - No DISTINCT clause.
2569  * - Each TLE is a column reference, and each column appears at most once.
2570  * - FROM contains exactly one base relation.
2571  * - No GROUP BY or HAVING clauses.
2572  * - No set operations (UNION, INTERSECT or EXCEPT).
2573  * - No sub-queries in the WHERE clause that reference the target table.
2574  *
2575  * We ignore that last restriction since it would be complex to enforce
2576  * and there isn't any actual benefit to disallowing sub-queries. (The
2577  * semantic issues that the standard is presumably concerned about don't
2578  * arise in Postgres, since any such sub-query will not see any updates
2579  * executed by the outer query anyway, thanks to MVCC snapshotting.)
2580  *
2581  * We also relax the second restriction by supporting part of SQL:1999
2582  * feature T111, which allows for a mix of updatable and non-updatable
2583  * columns, provided that an INSERT or UPDATE doesn't attempt to assign to
2584  * a non-updatable column.
2585  *
2586  * In addition we impose these constraints, involving features that are
2587  * not part of SQL-92:
2588  * - No CTEs (WITH clauses).
2589  * - No OFFSET or LIMIT clauses (this matches a SQL:2008 restriction).
2590  * - No system columns (including whole-row references) in the tlist.
2591  * - No window functions in the tlist.
2592  * - No set-returning functions in the tlist.
2593  *
2594  * Note that we do these checks without recursively expanding the view.
2595  * If the base relation is a view, we'll recursively deal with it later.
2596  *----------
2597  */
2598  if (viewquery->distinctClause != NIL)
2599  return gettext_noop("Views containing DISTINCT are not automatically updatable.");
2600 
2601  if (viewquery->groupClause != NIL || viewquery->groupingSets)
2602  return gettext_noop("Views containing GROUP BY are not automatically updatable.");
2603 
2604  if (viewquery->havingQual != NULL)
2605  return gettext_noop("Views containing HAVING are not automatically updatable.");
2606 
2607  if (viewquery->setOperations != NULL)
2608  return gettext_noop("Views containing UNION, INTERSECT, or EXCEPT are not automatically updatable.");
2609 
2610  if (viewquery->cteList != NIL)
2611  return gettext_noop("Views containing WITH are not automatically updatable.");
2612 
2613  if (viewquery->limitOffset != NULL || viewquery->limitCount != NULL)
2614  return gettext_noop("Views containing LIMIT or OFFSET are not automatically updatable.");
2615 
2616  /*
2617  * We must not allow window functions or set returning functions in the
2618  * targetlist. Otherwise we might end up inserting them into the quals of
2619  * the main query. We must also check for aggregates in the targetlist in
2620  * case they appear without a GROUP BY.
2621  *
2622  * These restrictions ensure that each row of the view corresponds to a
2623  * unique row in the underlying base relation.