PostgreSQL Source Code  git master
rewriteHandler.c File Reference
#include "postgres.h"
#include "access/relation.h"
#include "access/sysattr.h"
#include "access/table.h"
#include "catalog/dependency.h"
#include "catalog/pg_type.h"
#include "commands/trigger.h"
#include "foreign/fdwapi.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "parser/analyze.h"
#include "parser/parse_coerce.h"
#include "parser/parse_relation.h"
#include "parser/parsetree.h"
#include "rewrite/rewriteDefine.h"
#include "rewrite/rewriteHandler.h"
#include "rewrite/rewriteManip.h"
#include "rewrite/rowsecurity.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
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)
 
static TargetEntryprocess_matched_tle (TargetEntry *src_tle, TargetEntry *prior_tle, const char *attrName)
 
static Nodeget_assignment_input (Node *node)
 
static bool rewriteValuesRTE (Query *parsetree, RangeTblEntry *rte, int rti, Relation target_relation, bool force_nulls)
 
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 rewriteTargetListUD (Query *parsetree, 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 295 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().

296 {
297  if (node == NULL)
298  return false;
299  if (IsA(node, SubLink))
300  {
301  SubLink *sub = (SubLink *) node;
302 
303  /* Do what we came for */
305  context->for_execute,
306  false);
307  /* Fall through to process lefthand args of SubLink */
308  }
309 
310  /*
311  * Do NOT recurse into Query nodes, because AcquireRewriteLocks already
312  * processed subselects of subselects for us.
313  */
314  return expression_tree_walker(node, acquireLocksOnSubLinks, context);
315 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
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:1839

◆ AcquireRewriteLocks()

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

Definition at line 133 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(), make_ruledef(), refresh_matview_datafill(), and rewriteRuleAction().

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

◆ adjust_view_column_set()

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

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

2827 {
2828  Bitmapset *result = NULL;
2829  int col;
2830 
2831  col = -1;
2832  while ((col = bms_next_member(cols, col)) >= 0)
2833  {
2834  /* bit numbers are offset by FirstLowInvalidHeapAttributeNumber */
2836 
2837  if (attno == InvalidAttrNumber)
2838  {
2839  /*
2840  * There's a whole-row reference to the view. For permissions
2841  * purposes, treat it as a reference to each column available from
2842  * the view. (We should *not* convert this to a whole-row
2843  * reference to the base relation, since the view may not touch
2844  * all columns of the base relation.)
2845  */
2846  ListCell *lc;
2847 
2848  foreach(lc, targetlist)
2849  {
2850  TargetEntry *tle = lfirst_node(TargetEntry, lc);
2851  Var *var;
2852 
2853  if (tle->resjunk)
2854  continue;
2855  var = castNode(Var, tle->expr);
2856  result = bms_add_member(result,
2857  var->varattno - FirstLowInvalidHeapAttributeNumber);
2858  }
2859  }
2860  else
2861  {
2862  /*
2863  * Views do not have system columns, so we do not expect to see
2864  * any other system attnos here. If we do find one, the error
2865  * case will apply.
2866  */
2867  TargetEntry *tle = get_tle_by_resno(targetlist, attno);
2868 
2869  if (tle != NULL && !tle->resjunk && IsA(tle->expr, Var))
2870  {
2871  Var *var = (Var *) tle->expr;
2872 
2873  result = bms_add_member(result,
2874  var->varattno - FirstLowInvalidHeapAttributeNumber);
2875  }
2876  else
2877  elog(ERROR, "attribute number %d not found in view targetlist",
2878  attno);
2879  }
2880  }
2881 
2882  return result;
2883 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
#define castNode(_type_, nodeptr)
Definition: nodes.h:594
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1043
AttrNumber varattno
Definition: primnodes.h:186
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
Definition: primnodes.h:181
bool resjunk
Definition: primnodes.h:1414
#define ERROR
Definition: elog.h:43
#define lfirst_node(type, lc)
Definition: pg_list.h:193
Expr * expr
Definition: primnodes.h:1407
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:736
#define InvalidAttrNumber
Definition: attnum.h:23
#define elog(elevel,...)
Definition: elog.h:228
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 639 of file rewriteHandler.c.

References copyObject, FromExpr::fromlist, IsA, Query::jointree, lfirst, list_delete_ptr(), and RangeTblRef::rtindex.

Referenced by rewriteRuleAction().

640 {
641  List *newjointree = copyObject(parsetree->jointree->fromlist);
642  ListCell *l;
643 
644  if (removert)
645  {
646  foreach(l, newjointree)
647  {
648  RangeTblRef *rtr = lfirst(l);
649 
650  if (IsA(rtr, RangeTblRef) &&
651  rtr->rtindex == rt_index)
652  {
653  newjointree = list_delete_ptr(newjointree, rtr);
654 
655  /*
656  * foreach is safe because we exit loop after list_delete...
657  */
658  break;
659  }
660  }
661  }
662  return newjointree;
663 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
FromExpr * jointree
Definition: parsenodes.h:138
List * fromlist
Definition: primnodes.h:1510
List * list_delete_ptr(List *list, void *datum)
Definition: list.c:797
#define lfirst(lc)
Definition: pg_list.h:190
#define copyObject(obj)
Definition: nodes.h:641
Definition: pg_list.h:50

◆ ApplyRetrieveRule()

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

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

1590 {
1591  Query *rule_action;
1592  RangeTblEntry *rte,
1593  *subrte;
1594  RowMarkClause *rc;
1595 
1596  if (list_length(rule->actions) != 1)
1597  elog(ERROR, "expected just one rule action");
1598  if (rule->qual != NULL)
1599  elog(ERROR, "cannot handle qualified ON SELECT rule");
1600 
1601  if (rt_index == parsetree->resultRelation)
1602  {
1603  /*
1604  * We have a view as the result relation of the query, and it wasn't
1605  * rewritten by any rule. This case is supported if there is an
1606  * INSTEAD OF trigger that will trap attempts to insert/update/delete
1607  * view rows. The executor will check that; for the moment just plow
1608  * ahead. We have two cases:
1609  *
1610  * For INSERT, we needn't do anything. The unmodified RTE will serve
1611  * fine as the result relation.
1612  *
1613  * For UPDATE/DELETE, we need to expand the view so as to have source
1614  * data for the operation. But we also need an unmodified RTE to
1615  * serve as the target. So, copy the RTE and add the copy to the
1616  * rangetable. Note that the copy does not get added to the jointree.
1617  * Also note that there's a hack in fireRIRrules to avoid calling this
1618  * function again when it arrives at the copied RTE.
1619  */
1620  if (parsetree->commandType == CMD_INSERT)
1621  return parsetree;
1622  else if (parsetree->commandType == CMD_UPDATE ||
1623  parsetree->commandType == CMD_DELETE)
1624  {
1625  RangeTblEntry *newrte;
1626  Var *var;
1627  TargetEntry *tle;
1628 
1629  rte = rt_fetch(rt_index, parsetree->rtable);
1630  newrte = copyObject(rte);
1631  parsetree->rtable = lappend(parsetree->rtable, newrte);
1632  parsetree->resultRelation = list_length(parsetree->rtable);
1633 
1634  /*
1635  * There's no need to do permissions checks twice, so wipe out the
1636  * permissions info for the original RTE (we prefer to keep the
1637  * bits set on the result RTE).
1638  */
1639  rte->requiredPerms = 0;
1640  rte->checkAsUser = InvalidOid;
1641  rte->selectedCols = NULL;
1642  rte->insertedCols = NULL;
1643  rte->updatedCols = NULL;
1644 
1645  /*
1646  * For the most part, Vars referencing the view should remain as
1647  * they are, meaning that they implicitly represent OLD values.
1648  * But in the RETURNING list if any, we want such Vars to
1649  * represent NEW values, so change them to reference the new RTE.
1650  *
1651  * Since ChangeVarNodes scribbles on the tree in-place, copy the
1652  * RETURNING list first for safety.
1653  */
1654  parsetree->returningList = copyObject(parsetree->returningList);
1655  ChangeVarNodes((Node *) parsetree->returningList, rt_index,
1656  parsetree->resultRelation, 0);
1657 
1658  /*
1659  * To allow the executor to compute the original view row to pass
1660  * to the INSTEAD OF trigger, we add a resjunk whole-row Var
1661  * referencing the original RTE. This will later get expanded
1662  * into a RowExpr computing all the OLD values of the view row.
1663  */
1664  var = makeWholeRowVar(rte, rt_index, 0, false);
1665  tle = makeTargetEntry((Expr *) var,
1666  list_length(parsetree->targetList) + 1,
1667  pstrdup("wholerow"),
1668  true);
1669 
1670  parsetree->targetList = lappend(parsetree->targetList, tle);
1671 
1672  /* Now, continue with expanding the original view RTE */
1673  }
1674  else
1675  elog(ERROR, "unrecognized commandType: %d",
1676  (int) parsetree->commandType);
1677  }
1678 
1679  /*
1680  * Check if there's a FOR [KEY] UPDATE/SHARE clause applying to this view.
1681  *
1682  * Note: we needn't explicitly consider any such clauses appearing in
1683  * ancestor query levels; their effects have already been pushed down to
1684  * here by markQueryForLocking, and will be reflected in "rc".
1685  */
1686  rc = get_parse_rowmark(parsetree, rt_index);
1687 
1688  /*
1689  * Make a modifiable copy of the view query, and acquire needed locks on
1690  * the relations it mentions. Force at least RowShareLock for all such
1691  * rels if there's a FOR [KEY] UPDATE/SHARE clause affecting this view.
1692  */
1693  rule_action = copyObject(linitial(rule->actions));
1694 
1695  AcquireRewriteLocks(rule_action, true, (rc != NULL));
1696 
1697  /*
1698  * If FOR [KEY] UPDATE/SHARE of view, mark all the contained tables as
1699  * implicit FOR [KEY] UPDATE/SHARE, the same as the parser would have done
1700  * if the view's subquery had been written out explicitly.
1701  */
1702  if (rc != NULL)
1703  markQueryForLocking(rule_action, (Node *) rule_action->jointree,
1704  rc->strength, rc->waitPolicy, true);
1705 
1706  /*
1707  * Recursively expand any view references inside the view.
1708  *
1709  * Note: this must happen after markQueryForLocking. That way, any UPDATE
1710  * permission bits needed for sub-views are initially applied to their
1711  * RTE_RELATION RTEs by markQueryForLocking, and then transferred to their
1712  * OLD rangetable entries by the action below (in a recursive call of this
1713  * routine).
1714  */
1715  rule_action = fireRIRrules(rule_action, activeRIRs);
1716 
1717  /*
1718  * Now, plug the view query in as a subselect, converting the relation's
1719  * original RTE to a subquery RTE.
1720  */
1721  rte = rt_fetch(rt_index, parsetree->rtable);
1722 
1723  rte->rtekind = RTE_SUBQUERY;
1724  rte->subquery = rule_action;
1725  rte->security_barrier = RelationIsSecurityView(relation);
1726  /* Clear fields that should not be set in a subquery RTE */
1727  rte->relid = InvalidOid;
1728  rte->relkind = 0;
1729  rte->rellockmode = 0;
1730  rte->tablesample = NULL;
1731  rte->inh = false; /* must not be set for a subquery */
1732 
1733  /*
1734  * We move the view's permission check data down to its rangetable. The
1735  * checks will actually be done against the OLD entry therein.
1736  */
1737  subrte = rt_fetch(PRS2_OLD_VARNO, rule_action->rtable);
1738  Assert(subrte->relid == relation->rd_id);
1739  subrte->requiredPerms = rte->requiredPerms;
1740  subrte->checkAsUser = rte->checkAsUser;
1741  subrte->selectedCols = rte->selectedCols;
1742  subrte->insertedCols = rte->insertedCols;
1743  subrte->updatedCols = rte->updatedCols;
1744  subrte->extraUpdatedCols = rte->extraUpdatedCols;
1745 
1746  rte->requiredPerms = 0; /* no permission check on subquery itself */
1747  rte->checkAsUser = InvalidOid;
1748  rte->selectedCols = NULL;
1749  rte->insertedCols = NULL;
1750  rte->updatedCols = NULL;
1751  rte->extraUpdatedCols = NULL;
1752 
1753  return parsetree;
1754 }
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:138
char * pstrdup(const char *in)
Definition: mcxt.c:1186
int resultRelation
Definition: parsenodes.h:122
Definition: nodes.h:525
Var * makeWholeRowVar(RangeTblEntry *rte, Index varno, Index varlevelsup, bool allowScalar)
Definition: makefuncs.c:133
AclMode requiredPerms
Definition: parsenodes.h:1117
Definition: primnodes.h:181
LockClauseStrength strength
Definition: parsenodes.h:1381
List * targetList
Definition: parsenodes.h:140
Bitmapset * extraUpdatedCols
Definition: parsenodes.h:1122
Bitmapset * selectedCols
Definition: parsenodes.h:1119
#define linitial(l)
Definition: pg_list.h:195
List * rtable
Definition: parsenodes.h:137
#define ERROR
Definition: elog.h:43
void AcquireRewriteLocks(Query *parsetree, bool forExecute, bool forUpdatePushedDown)
List * actions
Definition: prs2lock.h:29
List * returningList
Definition: parsenodes.h:146
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:236
Oid rd_id
Definition: rel.h:86
List * lappend(List *list, void *datum)
Definition: list.c:322
#define PRS2_OLD_VARNO
Definition: primnodes.h:178
bool security_barrier
Definition: parsenodes.h:1010
#define InvalidOid
Definition: postgres_ext.h:36
Bitmapset * updatedCols
Definition: parsenodes.h:1121
CmdType commandType
Definition: parsenodes.h:112
#define Assert(condition)
Definition: c.h:739
static int list_length(const List *l)
Definition: pg_list.h:169
LockWaitPolicy waitPolicy
Definition: parsenodes.h:1382
RTEKind rtekind
Definition: parsenodes.h:974
Query * subquery
Definition: parsenodes.h:1009
#define elog(elevel,...)
Definition: elog.h:228
Bitmapset * insertedCols
Definition: parsenodes.h:1120
#define RelationIsSecurityView(relation)
Definition: rel.h:359
void ChangeVarNodes(Node *node, int rt_index, int new_index, int sublevels_up)
Definition: rewriteManip.c:610
#define copyObject(obj)
Definition: nodes.h:641
static Query * fireRIRrules(Query *parsetree, List *activeRIRs)
struct TableSampleClause * tablesample
Definition: parsenodes.h:1004

◆ build_column_default()

Node* build_column_default ( Relation  rel,
int  attrno 
)

Definition at line 1121 of file rewriteHandler.c.

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

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

1122 {
1123  TupleDesc rd_att = rel->rd_att;
1124  Form_pg_attribute att_tup = TupleDescAttr(rd_att, attrno - 1);
1125  Oid atttype = att_tup->atttypid;
1126  int32 atttypmod = att_tup->atttypmod;
1127  Node *expr = NULL;
1128  Oid exprtype;
1129 
1130  if (att_tup->attidentity)
1131  {
1133 
1134  nve->seqid = getIdentitySequence(RelationGetRelid(rel), attrno, false);
1135  nve->typeId = att_tup->atttypid;
1136 
1137  return (Node *) nve;
1138  }
1139 
1140  /*
1141  * Scan to see if relation has a default for this column.
1142  */
1143  if (att_tup->atthasdef && rd_att->constr &&
1144  rd_att->constr->num_defval > 0)
1145  {
1146  AttrDefault *defval = rd_att->constr->defval;
1147  int ndef = rd_att->constr->num_defval;
1148 
1149  while (--ndef >= 0)
1150  {
1151  if (attrno == defval[ndef].adnum)
1152  {
1153  /*
1154  * Found it, convert string representation to node tree.
1155  */
1156  expr = stringToNode(defval[ndef].adbin);
1157  break;
1158  }
1159  }
1160  }
1161 
1162  /*
1163  * No per-column default, so look for a default for the type itself. But
1164  * not for generated columns.
1165  */
1166  if (expr == NULL && !att_tup->attgenerated)
1167  expr = get_typdefault(atttype);
1168 
1169  if (expr == NULL)
1170  return NULL; /* No default anywhere */
1171 
1172  /*
1173  * Make sure the value is coerced to the target column type; this will
1174  * generally be true already, but there seem to be some corner cases
1175  * involving domain defaults where it might not be true. This should match
1176  * the parser's processing of non-defaulted expressions --- see
1177  * transformAssignedExpr().
1178  */
1179  exprtype = exprType(expr);
1180 
1181  expr = coerce_to_target_type(NULL, /* no UNKNOWN params here */
1182  expr, exprtype,
1183  atttype, atttypmod,
1186  -1);
1187  if (expr == NULL)
1188  ereport(ERROR,
1189  (errcode(ERRCODE_DATATYPE_MISMATCH),
1190  errmsg("column \"%s\" is of type %s"
1191  " but default expression is of type %s",
1192  NameStr(att_tup->attname),
1193  format_type_be(atttype),
1194  format_type_be(exprtype)),
1195  errhint("You will need to rewrite or cast the expression.")));
1196 
1197  return expr;
1198 }
int errhint(const char *fmt,...)
Definition: elog.c:1069
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
Definition: nodes.h:525
int errcode(int sqlerrcode)
Definition: elog.c:608
void * stringToNode(const char *str)
Definition: read.c:89
char * format_type_be(Oid type_oid)
Definition: format_type.c:326
unsigned int Oid
Definition: postgres_ext.h:31
Oid getIdentitySequence(Oid relid, AttrNumber attnum, bool missing_ok)
Definition: pg_depend.c:780
signed int int32
Definition: c.h:347
AttrDefault * defval
Definition: tupdesc.h:39
#define ERROR
Definition: elog.h:43
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
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:200
#define ereport(elevel, rest)
Definition: elog.h:141
TupleDesc rd_att
Definition: rel.h:85
#define makeNode(_type_)
Definition: nodes.h:573
Node * get_typdefault(Oid typid)
Definition: lsyscache.c:2226
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:41
uint16 num_defval
Definition: tupdesc.h:42
int errmsg(const char *fmt,...)
Definition: elog.c:822
#define NameStr(name)
Definition: c.h:616
#define RelationGetRelid(relation)
Definition: rel.h:428

◆ CopyAndAddInvertedQual()

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

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

2138 {
2139  /* Don't scribble on the passed qual (it's in the relcache!) */
2140  Node *new_qual = copyObject(rule_qual);
2142 
2143  context.for_execute = true;
2144 
2145  /*
2146  * In case there are subqueries in the qual, acquire necessary locks and
2147  * fix any deleted JOIN RTE entries. (This is somewhat redundant with
2148  * rewriteRuleAction, but not entirely ... consider restructuring so that
2149  * we only need to process the qual this way once.)
2150  */
2151  (void) acquireLocksOnSubLinks(new_qual, &context);
2152 
2153  /* Fix references to OLD */
2154  ChangeVarNodes(new_qual, PRS2_OLD_VARNO, rt_index, 0);
2155  /* Fix references to NEW */
2156  if (event == CMD_INSERT || event == CMD_UPDATE)
2157  new_qual = ReplaceVarsFromTargetList(new_qual,
2159  0,
2160  rt_fetch(rt_index,
2161  parsetree->rtable),
2162  parsetree->targetList,
2163  (event == CMD_UPDATE) ?
2166  rt_index,
2167  &parsetree->hasSubLinks);
2168  /* And attach the fixed qual */
2169  AddInvertedQual(parsetree, new_qual);
2170 
2171  return parsetree;
2172 }
static bool acquireLocksOnSubLinks(Node *node, acquireLocksOnSubLinks_context *context)
void AddInvertedQual(Query *parsetree, Node *qual)
Definition: nodes.h:525
List * targetList
Definition: parsenodes.h:140
List * rtable
Definition: parsenodes.h:137
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
#define PRS2_OLD_VARNO
Definition: primnodes.h:178
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:128
void ChangeVarNodes(Node *node, int rt_index, int new_index, int sublevels_up)
Definition: rewriteManip.c:610
#define copyObject(obj)
Definition: nodes.h:641
#define PRS2_NEW_VARNO
Definition: primnodes.h:179

◆ fireRIRonSubLink()

static bool fireRIRonSubLink ( Node node,
List activeRIRs 
)
static

Definition at line 1828 of file rewriteHandler.c.

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

Referenced by fireRIRrules().

1829 {
1830  if (node == NULL)
1831  return false;
1832  if (IsA(node, SubLink))
1833  {
1834  SubLink *sub = (SubLink *) node;
1835 
1836  /* Do what we came for */
1837  sub->subselect = (Node *) fireRIRrules((Query *) sub->subselect,
1838  activeRIRs);
1839  /* Fall through to process lefthand args of SubLink */
1840  }
1841 
1842  /*
1843  * Do NOT recurse into Query nodes, because fireRIRrules already processed
1844  * subselects of subselects for us.
1845  */
1847  (void *) activeRIRs);
1848 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
Definition: nodes.h:525
static bool fireRIRonSubLink(Node *node, List *activeRIRs)
bool expression_tree_walker(Node *node, bool(*walker)(), void *context)
Definition: nodeFuncs.c:1839
static Query * fireRIRrules(Query *parsetree, List *activeRIRs)

◆ fireRIRrules()

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

Definition at line 1859 of file rewriteHandler.c.

References acquireLocksOnSubLinks(), ApplyRetrieveRule(), CMD_SELECT, Query::cteList, CommonTableExpr::ctequery, 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, 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, rt_fetch, Query::rtable, RTE_RELATION, RTE_SUBQUERY, RangeTblEntry::rtekind, RuleLock::rules, rules, RangeTblEntry::securityQuals, RangeTblEntry::subquery, table_close(), table_open(), and Query::withCheckOptions.

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

1860 {
1861  int origResultRelation = parsetree->resultRelation;
1862  int rt_index;
1863  ListCell *lc;
1864 
1865  /*
1866  * don't try to convert this into a foreach loop, because rtable list can
1867  * get changed each time through...
1868  */
1869  rt_index = 0;
1870  while (rt_index < list_length(parsetree->rtable))
1871  {
1872  RangeTblEntry *rte;
1873  Relation rel;
1874  List *locks;
1875  RuleLock *rules;
1876  RewriteRule *rule;
1877  int i;
1878 
1879  ++rt_index;
1880 
1881  rte = rt_fetch(rt_index, parsetree->rtable);
1882 
1883  /*
1884  * A subquery RTE can't have associated rules, so there's nothing to
1885  * do to this level of the query, but we must recurse into the
1886  * subquery to expand any rule references in it.
1887  */
1888  if (rte->rtekind == RTE_SUBQUERY)
1889  {
1890  rte->subquery = fireRIRrules(rte->subquery, activeRIRs);
1891  continue;
1892  }
1893 
1894  /*
1895  * Joins and other non-relation RTEs can be ignored completely.
1896  */
1897  if (rte->rtekind != RTE_RELATION)
1898  continue;
1899 
1900  /*
1901  * Always ignore RIR rules for materialized views referenced in
1902  * queries. (This does not prevent refreshing MVs, since they aren't
1903  * referenced in their own query definitions.)
1904  *
1905  * Note: in the future we might want to allow MVs to be conditionally
1906  * expanded as if they were regular views, if they are not scannable.
1907  * In that case this test would need to be postponed till after we've
1908  * opened the rel, so that we could check its state.
1909  */
1910  if (rte->relkind == RELKIND_MATVIEW)
1911  continue;
1912 
1913  /*
1914  * In INSERT ... ON CONFLICT, ignore the EXCLUDED pseudo-relation;
1915  * even if it points to a view, we needn't expand it, and should not
1916  * because we want the RTE to remain of RTE_RELATION type. Otherwise,
1917  * it would get changed to RTE_SUBQUERY type, which is an
1918  * untested/unsupported situation.
1919  */
1920  if (parsetree->onConflict &&
1921  rt_index == parsetree->onConflict->exclRelIndex)
1922  continue;
1923 
1924  /*
1925  * If the table is not referenced in the query, then we ignore it.
1926  * This prevents infinite expansion loop due to new rtable entries
1927  * inserted by expansion of a rule. A table is referenced if it is
1928  * part of the join set (a source table), or is referenced by any Var
1929  * nodes, or is the result table.
1930  */
1931  if (rt_index != parsetree->resultRelation &&
1932  !rangeTableEntry_used((Node *) parsetree, rt_index, 0))
1933  continue;
1934 
1935  /*
1936  * Also, if this is a new result relation introduced by
1937  * ApplyRetrieveRule, we don't want to do anything more with it.
1938  */
1939  if (rt_index == parsetree->resultRelation &&
1940  rt_index != origResultRelation)
1941  continue;
1942 
1943  /*
1944  * We can use NoLock here since either the parser or
1945  * AcquireRewriteLocks should have locked the rel already.
1946  */
1947  rel = table_open(rte->relid, NoLock);
1948 
1949  /*
1950  * Collect the RIR rules that we must apply
1951  */
1952  rules = rel->rd_rules;
1953  if (rules != NULL)
1954  {
1955  locks = NIL;
1956  for (i = 0; i < rules->numLocks; i++)
1957  {
1958  rule = rules->rules[i];
1959  if (rule->event != CMD_SELECT)
1960  continue;
1961 
1962  locks = lappend(locks, rule);
1963  }
1964 
1965  /*
1966  * If we found any, apply them --- but first check for recursion!
1967  */
1968  if (locks != NIL)
1969  {
1970  ListCell *l;
1971 
1972  if (list_member_oid(activeRIRs, RelationGetRelid(rel)))
1973  ereport(ERROR,
1974  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1975  errmsg("infinite recursion detected in rules for relation \"%s\"",
1976  RelationGetRelationName(rel))));
1977  activeRIRs = lappend_oid(activeRIRs, RelationGetRelid(rel));
1978 
1979  foreach(l, locks)
1980  {
1981  rule = lfirst(l);
1982 
1983  parsetree = ApplyRetrieveRule(parsetree,
1984  rule,
1985  rt_index,
1986  rel,
1987  activeRIRs);
1988  }
1989 
1990  activeRIRs = list_delete_last(activeRIRs);
1991  }
1992  }
1993 
1994  table_close(rel, NoLock);
1995  }
1996 
1997  /* Recurse into subqueries in WITH */
1998  foreach(lc, parsetree->cteList)
1999  {
2000  CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
2001 
2002  cte->ctequery = (Node *)
2003  fireRIRrules((Query *) cte->ctequery, activeRIRs);
2004  }
2005 
2006  /*
2007  * Recurse into sublink subqueries, too. But we already did the ones in
2008  * the rtable and cteList.
2009  */
2010  if (parsetree->hasSubLinks)
2011  query_tree_walker(parsetree, fireRIRonSubLink, (void *) activeRIRs,
2013 
2014  /*
2015  * Apply any row level security policies. We do this last because it
2016  * requires special recursion detection if the new quals have sublink
2017  * subqueries, and if we did it in the loop above query_tree_walker would
2018  * then recurse into those quals a second time.
2019  */
2020  rt_index = 0;
2021  foreach(lc, parsetree->rtable)
2022  {
2023  RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
2024  Relation rel;
2025  List *securityQuals;
2026  List *withCheckOptions;
2027  bool hasRowSecurity;
2028  bool hasSubLinks;
2029 
2030  ++rt_index;
2031 
2032  /* Only normal relations can have RLS policies */
2033  if (rte->rtekind != RTE_RELATION ||
2034  (rte->relkind != RELKIND_RELATION &&
2035  rte->relkind != RELKIND_PARTITIONED_TABLE))
2036  continue;
2037 
2038  rel = table_open(rte->relid, NoLock);
2039 
2040  /*
2041  * Fetch any new security quals that must be applied to this RTE.
2042  */
2043  get_row_security_policies(parsetree, rte, rt_index,
2044  &securityQuals, &withCheckOptions,
2045  &hasRowSecurity, &hasSubLinks);
2046 
2047  if (securityQuals != NIL || withCheckOptions != NIL)
2048  {
2049  if (hasSubLinks)
2050  {
2052 
2053  /*
2054  * Recursively process the new quals, checking for infinite
2055  * recursion.
2056  */
2057  if (list_member_oid(activeRIRs, RelationGetRelid(rel)))
2058  ereport(ERROR,
2059  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2060  errmsg("infinite recursion detected in policy for relation \"%s\"",
2061  RelationGetRelationName(rel))));
2062 
2063  activeRIRs = lappend_oid(activeRIRs, RelationGetRelid(rel));
2064 
2065  /*
2066  * get_row_security_policies just passed back securityQuals
2067  * and/or withCheckOptions, and there were SubLinks, make sure
2068  * we lock any relations which are referenced.
2069  *
2070  * These locks would normally be acquired by the parser, but
2071  * securityQuals and withCheckOptions are added post-parsing.
2072  */
2073  context.for_execute = true;
2074  (void) acquireLocksOnSubLinks((Node *) securityQuals, &context);
2075  (void) acquireLocksOnSubLinks((Node *) withCheckOptions,
2076  &context);
2077 
2078  /*
2079  * Now that we have the locks on anything added by
2080  * get_row_security_policies, fire any RIR rules for them.
2081  */
2082  expression_tree_walker((Node *) securityQuals,
2083  fireRIRonSubLink, (void *) activeRIRs);
2084 
2085  expression_tree_walker((Node *) withCheckOptions,
2086  fireRIRonSubLink, (void *) activeRIRs);
2087 
2088  activeRIRs = list_delete_last(activeRIRs);
2089  }
2090 
2091  /*
2092  * Add the new security barrier quals to the start of the RTE's
2093  * list so that they get applied before any existing barrier quals
2094  * (which would have come from a security-barrier view, and should
2095  * get lower priority than RLS conditions on the table itself).
2096  */
2097  rte->securityQuals = list_concat(securityQuals,
2098  rte->securityQuals);
2099 
2100  parsetree->withCheckOptions = list_concat(withCheckOptions,
2101  parsetree->withCheckOptions);
2102  }
2103 
2104  /*
2105  * Make sure the query is marked correctly if row level security
2106  * applies, or if the new quals had sublinks.
2107  */
2108  if (hasRowSecurity)
2109  parsetree->hasRowSecurity = true;
2110  if (hasSubLinks)
2111  parsetree->hasSubLinks = true;
2112 
2113  table_close(rel, NoLock);
2114  }
2115 
2116  return parsetree;
2117 }
#define NIL
Definition: pg_list.h:65
bool query_tree_walker(Query *query, bool(*walker)(), void *context, int flags)
Definition: nodeFuncs.c:2273
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
int numLocks
Definition: prs2lock.h:42
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:144
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:1123
int resultRelation
Definition: parsenodes.h:122
Definition: nodes.h:525
List * list_concat(List *list1, const List *list2)
Definition: list.c:516
int errcode(int sqlerrcode)
Definition: elog.c:608
List * lappend_oid(List *list, Oid datum)
Definition: list.c:358
Definition: localtime.c:79
#define QTW_IGNORE_RC_SUBQUERIES
Definition: nodeFuncs.h:22
List * rtable
Definition: parsenodes.h:137
#define ERROR
Definition: elog.h:43
static bool fireRIRonSubLink(Node *node, List *activeRIRs)
#define NoLock
Definition: lockdefs.h:34
CmdType event
Definition: prs2lock.h:27
List * list_delete_last(List *list)
Definition: list.c:878
static struct rule * rules
Definition: zic.c:278
#define RelationGetRelationName(relation)
Definition: rel.h:462
RewriteRule ** rules
Definition: prs2lock.h:43
#define ereport(elevel, rest)
Definition: elog.h:141
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
List * lappend(List *list, void *datum)
Definition: list.c:322
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:675
#define lfirst(lc)
Definition: pg_list.h:190
RuleLock * rd_rules
Definition: rel.h:88
bool expression_tree_walker(Node *node, bool(*walker)(), void *context)
Definition: nodeFuncs.c:1839
static int list_length(const List *l)
Definition: pg_list.h:169
RTEKind rtekind
Definition: parsenodes.h:974
Query * subquery
Definition: parsenodes.h:1009
int errmsg(const char *fmt,...)
Definition: elog.c:822
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:428

◆ 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 2204 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().

2211 {
2212  List *results = NIL;
2213  ListCell *l;
2214 
2215  foreach(l, locks)
2216  {
2217  RewriteRule *rule_lock = (RewriteRule *) lfirst(l);
2218  Node *event_qual = rule_lock->qual;
2219  List *actions = rule_lock->actions;
2220  QuerySource qsrc;
2221  ListCell *r;
2222 
2223  /* Determine correct QuerySource value for actions */
2224  if (rule_lock->isInstead)
2225  {
2226  if (event_qual != NULL)
2227  qsrc = QSRC_QUAL_INSTEAD_RULE;
2228  else
2229  {
2230  qsrc = QSRC_INSTEAD_RULE;
2231  *instead_flag = true; /* report unqualified INSTEAD */
2232  }
2233  }
2234  else
2235  qsrc = QSRC_NON_INSTEAD_RULE;
2236 
2237  if (qsrc == QSRC_QUAL_INSTEAD_RULE)
2238  {
2239  /*
2240  * If there are INSTEAD rules with qualifications, the original
2241  * query is still performed. But all the negated rule
2242  * qualifications of the INSTEAD rules are added so it does its
2243  * actions only in cases where the rule quals of all INSTEAD rules
2244  * are false. Think of it as the default action in a case. We save
2245  * this in *qual_product so RewriteQuery() can add it to the query
2246  * list after we mangled it up enough.
2247  *
2248  * If we have already found an unqualified INSTEAD rule, then
2249  * *qual_product won't be used, so don't bother building it.
2250  */
2251  if (!*instead_flag)
2252  {
2253  if (*qual_product == NULL)
2254  *qual_product = copyObject(parsetree);
2255  *qual_product = CopyAndAddInvertedQual(*qual_product,
2256  event_qual,
2257  rt_index,
2258  event);
2259  }
2260  }
2261 
2262  /* Now process the rule's actions and add them to the result list */
2263  foreach(r, actions)
2264  {
2265  Query *rule_action = lfirst(r);
2266 
2267  if (rule_action->commandType == CMD_NOTHING)
2268  continue;
2269 
2270  rule_action = rewriteRuleAction(parsetree, rule_action,
2271  event_qual, rt_index, event,
2272  returning_flag);
2273 
2274  rule_action->querySource = qsrc;
2275  rule_action->canSetTag = false; /* might change later */
2276 
2277  results = lappend(results, rule_action);
2278  }
2279  }
2280 
2281  return results;
2282 }
#define NIL
Definition: pg_list.h:65
Node * qual
Definition: prs2lock.h:28
QuerySource
Definition: parsenodes.h:40
Definition: nodes.h:525
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:322
CmdType commandType
Definition: parsenodes.h:112
QuerySource querySource
Definition: parsenodes.h:114
#define lfirst(lc)
Definition: pg_list.h:190
bool canSetTag
Definition: parsenodes.h:118
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:641
Definition: pg_list.h:50

◆ get_assignment_input()

static Node * get_assignment_input ( Node node)
static

Definition at line 1092 of file rewriteHandler.c.

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

Referenced by process_matched_tle().

1093 {
1094  if (node == NULL)
1095  return NULL;
1096  if (IsA(node, FieldStore))
1097  {
1098  FieldStore *fstore = (FieldStore *) node;
1099 
1100  return (Node *) fstore->arg;
1101  }
1102  else if (IsA(node, SubscriptingRef))
1103  {
1104  SubscriptingRef *sbsref = (SubscriptingRef *) node;
1105 
1106  if (sbsref->refassgnexpr == NULL)
1107  return NULL;
1108 
1109  return (Node *) sbsref->refexpr;
1110  }
1111 
1112  return NULL;
1113 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
Expr * arg
Definition: primnodes.h:791
Definition: nodes.h:525
Expr * refassgnexpr
Definition: primnodes.h:430
Expr * refexpr
Definition: primnodes.h:427

◆ get_view_query()

Query* get_view_query ( Relation  view)

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

2296 {
2297  int i;
2298 
2299  Assert(view->rd_rel->relkind == RELKIND_VIEW);
2300 
2301  for (i = 0; i < view->rd_rules->numLocks; i++)
2302  {
2303  RewriteRule *rule = view->rd_rules->rules[i];
2304 
2305  if (rule->event == CMD_SELECT)
2306  {
2307  /* A _RETURN rule should have only one action */
2308  if (list_length(rule->actions) != 1)
2309  elog(ERROR, "invalid _RETURN rule action specification");
2310 
2311  return (Query *) linitial(rule->actions);
2312  }
2313  }
2314 
2315  elog(ERROR, "failed to find _RETURN rule for view");
2316  return NULL; /* keep compiler quiet */
2317 }
int numLocks
Definition: prs2lock.h:42
Form_pg_class rd_rel
Definition: rel.h:84
Definition: localtime.c:79
#define linitial(l)
Definition: pg_list.h:195
#define ERROR
Definition: elog.h:43
CmdType event
Definition: prs2lock.h:27
RewriteRule ** rules
Definition: prs2lock.h:43
List * actions
Definition: prs2lock.h:29
#define Assert(condition)
Definition: c.h:739
RuleLock * rd_rules
Definition: rel.h:88
static int list_length(const List *l)
Definition: pg_list.h:169
#define elog(elevel,...)
Definition: elog.h:228
int i

◆ markQueryForLocking()

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

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

1771 {
1772  if (jtnode == NULL)
1773  return;
1774  if (IsA(jtnode, RangeTblRef))
1775  {
1776  int rti = ((RangeTblRef *) jtnode)->rtindex;
1777  RangeTblEntry *rte = rt_fetch(rti, qry->rtable);
1778 
1779  if (rte->rtekind == RTE_RELATION)
1780  {
1781  applyLockingClause(qry, rti, strength, waitPolicy, pushedDown);
1783  }
1784  else if (rte->rtekind == RTE_SUBQUERY)
1785  {
1786  applyLockingClause(qry, rti, strength, waitPolicy, pushedDown);
1787  /* FOR UPDATE/SHARE of subquery is propagated to subquery's rels */
1789  strength, waitPolicy, true);
1790  }
1791  /* other RTE types are unaffected by FOR UPDATE */
1792  }
1793  else if (IsA(jtnode, FromExpr))
1794  {
1795  FromExpr *f = (FromExpr *) jtnode;
1796  ListCell *l;
1797 
1798  foreach(l, f->fromlist)
1799  markQueryForLocking(qry, lfirst(l), strength, waitPolicy, pushedDown);
1800  }
1801  else if (IsA(jtnode, JoinExpr))
1802  {
1803  JoinExpr *j = (JoinExpr *) jtnode;
1804 
1805  markQueryForLocking(qry, j->larg, strength, waitPolicy, pushedDown);
1806  markQueryForLocking(qry, j->rarg, strength, waitPolicy, pushedDown);
1807  }
1808  else
1809  elog(ERROR, "unrecognized node type: %d",
1810  (int) nodeTag(jtnode));
1811 }
static void markQueryForLocking(Query *qry, Node *jtnode, LockClauseStrength strength, LockWaitPolicy waitPolicy, bool pushedDown)
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
FromExpr * jointree
Definition: parsenodes.h:138
Definition: nodes.h:525
AclMode requiredPerms
Definition: parsenodes.h:1117
List * fromlist
Definition: primnodes.h:1510
Node * larg
Definition: primnodes.h:1490
List * rtable
Definition: parsenodes.h:137
#define ERROR
Definition: elog.h:43
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
Node * rarg
Definition: primnodes.h:1491
#define lfirst(lc)
Definition: pg_list.h:190
#define ACL_SELECT_FOR_UPDATE
Definition: parsenodes.h:90
#define nodeTag(nodeptr)
Definition: nodes.h:530
RTEKind rtekind
Definition: parsenodes.h:974
Query * subquery
Definition: parsenodes.h:1009
#define elog(elevel,...)
Definition: elog.h:228
void applyLockingClause(Query *qry, Index rtindex, LockClauseStrength strength, LockWaitPolicy waitPolicy, bool pushedDown)
Definition: analyze.c:2929

◆ matchLocks()

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

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

1524 {
1525  List *matching_locks = NIL;
1526  int nlocks;
1527  int i;
1528 
1529  if (rulelocks == NULL)
1530  return NIL;
1531 
1532  if (parsetree->commandType != CMD_SELECT)
1533  {
1534  if (parsetree->resultRelation != varno)
1535  return NIL;
1536  }
1537 
1538  nlocks = rulelocks->numLocks;
1539 
1540  for (i = 0; i < nlocks; i++)
1541  {
1542  RewriteRule *oneLock = rulelocks->rules[i];
1543 
1544  if (oneLock->event == CMD_UPDATE)
1545  *hasUpdate = true;
1546 
1547  /*
1548  * Suppress ON INSERT/UPDATE/DELETE rules that are disabled or
1549  * configured to not fire during the current sessions replication
1550  * role. ON SELECT rules will always be applied in order to keep views
1551  * working even in LOCAL or REPLICA role.
1552  */
1553  if (oneLock->event != CMD_SELECT)
1554  {
1556  {
1557  if (oneLock->enabled == RULE_FIRES_ON_ORIGIN ||
1558  oneLock->enabled == RULE_DISABLED)
1559  continue;
1560  }
1561  else /* ORIGIN or LOCAL ROLE */
1562  {
1563  if (oneLock->enabled == RULE_FIRES_ON_REPLICA ||
1564  oneLock->enabled == RULE_DISABLED)
1565  continue;
1566  }
1567  }
1568 
1569  if (oneLock->event == event)
1570  {
1571  if (parsetree->commandType != CMD_SELECT ||
1572  rangeTableEntry_used((Node *) parsetree, varno, 0))
1573  matching_locks = lappend(matching_locks, oneLock);
1574  }
1575  }
1576 
1577  return matching_locks;
1578 }
#define NIL
Definition: pg_list.h:65
int numLocks
Definition: prs2lock.h:42
int resultRelation
Definition: parsenodes.h:122
Definition: nodes.h:525
int SessionReplicationRole
Definition: trigger.c:67
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:322
#define RULE_FIRES_ON_ORIGIN
Definition: rewriteDefine.h:21
#define SESSION_REPLICATION_ROLE_REPLICA
Definition: trigger.h:147
#define RULE_FIRES_ON_REPLICA
Definition: rewriteDefine.h:23
CmdType commandType
Definition: parsenodes.h:112
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 939 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().

942 {
943  TargetEntry *result;
944  CoerceToDomain *coerce_expr = NULL;
945  Node *src_expr;
946  Node *prior_expr;
947  Node *src_input;
948  Node *prior_input;
949  Node *priorbottom;
950  Node *newexpr;
951 
952  if (prior_tle == NULL)
953  {
954  /*
955  * Normal case where this is the first assignment to the attribute.
956  */
957  return src_tle;
958  }
959 
960  /*----------
961  * Multiple assignments to same attribute. Allow only if all are
962  * FieldStore or SubscriptingRef assignment operations. This is a bit
963  * tricky because what we may actually be looking at is a nest of
964  * such nodes; consider
965  * UPDATE tab SET col.fld1.subfld1 = x, col.fld2.subfld2 = y
966  * The two expressions produced by the parser will look like
967  * FieldStore(col, fld1, FieldStore(placeholder, subfld1, x))
968  * FieldStore(col, fld2, FieldStore(placeholder, subfld2, y))
969  * However, we can ignore the substructure and just consider the top
970  * FieldStore or SubscriptingRef from each assignment, because it works to
971  * combine these as
972  * FieldStore(FieldStore(col, fld1,
973  * FieldStore(placeholder, subfld1, x)),
974  * fld2, FieldStore(placeholder, subfld2, y))
975  * Note the leftmost expression goes on the inside so that the
976  * assignments appear to occur left-to-right.
977  *
978  * For FieldStore, instead of nesting we can generate a single
979  * FieldStore with multiple target fields. We must nest when
980  * SubscriptingRefs are involved though.
981  *
982  * As a further complication, the destination column might be a domain,
983  * resulting in each assignment containing a CoerceToDomain node over a
984  * FieldStore or SubscriptingRef. These should have matching target
985  * domains, so we strip them and reconstitute a single CoerceToDomain over
986  * the combined FieldStore/SubscriptingRef nodes. (Notice that this has the
987  * result that the domain's checks are applied only after we do all the
988  * field or element updates, not after each one. This is arguably desirable.)
989  *----------
990  */
991  src_expr = (Node *) src_tle->expr;
992  prior_expr = (Node *) prior_tle->expr;
993 
994  if (src_expr && IsA(src_expr, CoerceToDomain) &&
995  prior_expr && IsA(prior_expr, CoerceToDomain) &&
996  ((CoerceToDomain *) src_expr)->resulttype ==
997  ((CoerceToDomain *) prior_expr)->resulttype)
998  {
999  /* we assume without checking that resulttypmod/resultcollid match */
1000  coerce_expr = (CoerceToDomain *) src_expr;
1001  src_expr = (Node *) ((CoerceToDomain *) src_expr)->arg;
1002  prior_expr = (Node *) ((CoerceToDomain *) prior_expr)->arg;
1003  }
1004 
1005  src_input = get_assignment_input(src_expr);
1006  prior_input = get_assignment_input(prior_expr);
1007  if (src_input == NULL ||
1008  prior_input == NULL ||
1009  exprType(src_expr) != exprType(prior_expr))
1010  ereport(ERROR,
1011  (errcode(ERRCODE_SYNTAX_ERROR),
1012  errmsg("multiple assignments to same column \"%s\"",
1013  attrName)));
1014 
1015  /*
1016  * Prior TLE could be a nest of assignments if we do this more than once.
1017  */
1018  priorbottom = prior_input;
1019  for (;;)
1020  {
1021  Node *newbottom = get_assignment_input(priorbottom);
1022 
1023  if (newbottom == NULL)
1024  break; /* found the original Var reference */
1025  priorbottom = newbottom;
1026  }
1027  if (!equal(priorbottom, src_input))
1028  ereport(ERROR,
1029  (errcode(ERRCODE_SYNTAX_ERROR),
1030  errmsg("multiple assignments to same column \"%s\"",
1031  attrName)));
1032 
1033  /*
1034  * Looks OK to nest 'em.
1035  */
1036  if (IsA(src_expr, FieldStore))
1037  {
1038  FieldStore *fstore = makeNode(FieldStore);
1039 
1040  if (IsA(prior_expr, FieldStore))
1041  {
1042  /* combine the two */
1043  memcpy(fstore, prior_expr, sizeof(FieldStore));
1044  fstore->newvals =
1045  list_concat_copy(((FieldStore *) prior_expr)->newvals,
1046  ((FieldStore *) src_expr)->newvals);
1047  fstore->fieldnums =
1048  list_concat_copy(((FieldStore *) prior_expr)->fieldnums,
1049  ((FieldStore *) src_expr)->fieldnums);
1050  }
1051  else
1052  {
1053  /* general case, just nest 'em */
1054  memcpy(fstore, src_expr, sizeof(FieldStore));
1055  fstore->arg = (Expr *) prior_expr;
1056  }
1057  newexpr = (Node *) fstore;
1058  }
1059  else if (IsA(src_expr, SubscriptingRef))
1060  {
1062 
1063  memcpy(sbsref, src_expr, sizeof(SubscriptingRef));
1064  sbsref->refexpr = (Expr *) prior_expr;
1065  newexpr = (Node *) sbsref;
1066  }
1067  else
1068  {
1069  elog(ERROR, "cannot happen");
1070  newexpr = NULL;
1071  }
1072 
1073  if (coerce_expr)
1074  {
1075  /* put back the CoerceToDomain */
1076  CoerceToDomain *newcoerce = makeNode(CoerceToDomain);
1077 
1078  memcpy(newcoerce, coerce_expr, sizeof(CoerceToDomain));
1079  newcoerce->arg = (Expr *) newexpr;
1080  newexpr = (Node *) newcoerce;
1081  }
1082 
1083  result = flatCopyTargetEntry(src_tle);
1084  result->expr = (Expr *) newexpr;
1085  return result;
1086 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
Expr * arg
Definition: primnodes.h:791
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:3018
Definition: nodes.h:525
int errcode(int sqlerrcode)
Definition: elog.c:608
#define ERROR
Definition: elog.h:43
List * list_concat_copy(const List *list1, const List *list2)
Definition: list.c:553
TargetEntry * flatCopyTargetEntry(TargetEntry *src_tle)
Definition: makefuncs.c:269
#define ereport(elevel, rest)
Definition: elog.h:141
List * newvals
Definition: primnodes.h:792
static Node * get_assignment_input(Node *node)
#define makeNode(_type_)
Definition: nodes.h:573
Expr * expr
Definition: primnodes.h:1407
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:41
int errmsg(const char *fmt,...)
Definition: elog.c:822
List * fieldnums
Definition: primnodes.h:793
#define elog(elevel,...)
Definition: elog.h:228
void * arg
Expr * refexpr
Definition: primnodes.h:427

◆ QueryRewrite()

List* QueryRewrite ( Query parsetree)

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

3926 {
3927  uint64 input_query_id = parsetree->queryId;
3928  List *querylist;
3929  List *results;
3930  ListCell *l;
3931  CmdType origCmdType;
3932  bool foundOriginalQuery;
3933  Query *lastInstead;
3934 
3935  /*
3936  * This function is only applied to top-level original queries
3937  */
3938  Assert(parsetree->querySource == QSRC_ORIGINAL);
3939  Assert(parsetree->canSetTag);
3940 
3941  /*
3942  * Step 1
3943  *
3944  * Apply all non-SELECT rules possibly getting 0 or many queries
3945  */
3946  querylist = RewriteQuery(parsetree, NIL);
3947 
3948  /*
3949  * Step 2
3950  *
3951  * Apply all the RIR rules on each query
3952  *
3953  * This is also a handy place to mark each query with the original queryId
3954  */
3955  results = NIL;
3956  foreach(l, querylist)
3957  {
3958  Query *query = (Query *) lfirst(l);
3959 
3960  query = fireRIRrules(query, NIL);
3961 
3962  query->queryId = input_query_id;
3963 
3964  results = lappend(results, query);
3965  }
3966 
3967  /*
3968  * Step 3
3969  *
3970  * Determine which, if any, of the resulting queries is supposed to set
3971  * the command-result tag; and update the canSetTag fields accordingly.
3972  *
3973  * If the original query is still in the list, it sets the command tag.
3974  * Otherwise, the last INSTEAD query of the same kind as the original is
3975  * allowed to set the tag. (Note these rules can leave us with no query
3976  * setting the tag. The tcop code has to cope with this by setting up a
3977  * default tag based on the original un-rewritten query.)
3978  *
3979  * The Asserts verify that at most one query in the result list is marked
3980  * canSetTag. If we aren't checking asserts, we can fall out of the loop
3981  * as soon as we find the original query.
3982  */
3983  origCmdType = parsetree->commandType;
3984  foundOriginalQuery = false;
3985  lastInstead = NULL;
3986 
3987  foreach(l, results)
3988  {
3989  Query *query = (Query *) lfirst(l);
3990 
3991  if (query->querySource == QSRC_ORIGINAL)
3992  {
3993  Assert(query->canSetTag);
3994  Assert(!foundOriginalQuery);
3995  foundOriginalQuery = true;
3996 #ifndef USE_ASSERT_CHECKING
3997  break;
3998 #endif
3999  }
4000  else
4001  {
4002  Assert(!query->canSetTag);
4003  if (query->commandType == origCmdType &&
4004  (query->querySource == QSRC_INSTEAD_RULE ||
4006  lastInstead = query;
4007  }
4008  }
4009 
4010  if (!foundOriginalQuery && lastInstead != NULL)
4011  lastInstead->canSetTag = true;
4012 
4013  return results;
4014 }
#define NIL
Definition: pg_list.h:65
static List * RewriteQuery(Query *parsetree, List *rewrite_events)
List * lappend(List *list, void *datum)
Definition: list.c:322
uint64 queryId
Definition: parsenodes.h:116
CmdType commandType
Definition: parsenodes.h:112
QuerySource querySource
Definition: parsenodes.h:114
#define Assert(condition)
Definition: c.h:739
#define lfirst(lc)
Definition: pg_list.h:190
bool canSetTag
Definition: parsenodes.h:118
static Query * fireRIRrules(Query *parsetree, List *activeRIRs)
Definition: pg_list.h:50
CmdType
Definition: nodes.h:668

◆ relation_is_updatable()

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

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

2649 {
2650  int events = 0;
2651  Relation rel;
2652  RuleLock *rulelocks;
2653 
2654 #define ALL_EVENTS ((1 << CMD_INSERT) | (1 << CMD_UPDATE) | (1 << CMD_DELETE))
2655 
2656  /* Since this function recurses, it could be driven to stack overflow */
2658 
2659  rel = try_relation_open(reloid, AccessShareLock);
2660 
2661  /*
2662  * If the relation doesn't exist, return zero rather than throwing an
2663  * error. This is helpful since scanning an information_schema view under
2664  * MVCC rules can result in referencing rels that have actually been
2665  * deleted already.
2666  */
2667  if (rel == NULL)
2668  return 0;
2669 
2670  /* If we detect a recursive view, report that it is not updatable */
2671  if (list_member_oid(outer_reloids, RelationGetRelid(rel)))
2672  {
2674  return 0;
2675  }
2676 
2677  /* If the relation is a table, it is always updatable */
2678  if (rel->rd_rel->relkind == RELKIND_RELATION ||
2679  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
2680  {
2682  return ALL_EVENTS;
2683  }
2684 
2685  /* Look for unconditional DO INSTEAD rules, and note supported events */
2686  rulelocks = rel->rd_rules;
2687  if (rulelocks != NULL)
2688  {
2689  int i;
2690 
2691  for (i = 0; i < rulelocks->numLocks; i++)
2692  {
2693  if (rulelocks->rules[i]->isInstead &&
2694  rulelocks->rules[i]->qual == NULL)
2695  {
2696  events |= ((1 << rulelocks->rules[i]->event) & ALL_EVENTS);
2697  }
2698  }
2699 
2700  /* If we have rules for all events, we're done */
2701  if (events == ALL_EVENTS)
2702  {
2704  return events;
2705  }
2706  }
2707 
2708  /* Similarly look for INSTEAD OF triggers, if they are to be included */
2709  if (include_triggers)
2710  {
2711  TriggerDesc *trigDesc = rel->trigdesc;
2712 
2713  if (trigDesc)
2714  {
2715  if (trigDesc->trig_insert_instead_row)
2716  events |= (1 << CMD_INSERT);
2717  if (trigDesc->trig_update_instead_row)
2718  events |= (1 << CMD_UPDATE);
2719  if (trigDesc->trig_delete_instead_row)
2720  events |= (1 << CMD_DELETE);
2721 
2722  /* If we have triggers for all events, we're done */
2723  if (events == ALL_EVENTS)
2724  {
2726  return events;
2727  }
2728  }
2729  }
2730 
2731  /* If this is a foreign table, check which update events it supports */
2732  if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
2733  {
2734  FdwRoutine *fdwroutine = GetFdwRoutineForRelation(rel, false);
2735 
2736  if (fdwroutine->IsForeignRelUpdatable != NULL)
2737  events |= fdwroutine->IsForeignRelUpdatable(rel);
2738  else
2739  {
2740  /* Assume presence of executor functions is sufficient */
2741  if (fdwroutine->ExecForeignInsert != NULL)
2742  events |= (1 << CMD_INSERT);
2743  if (fdwroutine->ExecForeignUpdate != NULL)
2744  events |= (1 << CMD_UPDATE);
2745  if (fdwroutine->ExecForeignDelete != NULL)
2746  events |= (1 << CMD_DELETE);
2747  }
2748 
2750  return events;
2751  }
2752 
2753  /* Check if this is an automatically updatable view */
2754  if (rel->rd_rel->relkind == RELKIND_VIEW)
2755  {
2756  Query *viewquery = get_view_query(rel);
2757 
2758  if (view_query_is_auto_updatable(viewquery, false) == NULL)
2759  {
2760  Bitmapset *updatable_cols;
2761  int auto_events;
2762  RangeTblRef *rtr;
2763  RangeTblEntry *base_rte;
2764  Oid baseoid;
2765 
2766  /*
2767  * Determine which of the view's columns are updatable. If there
2768  * are none within the set of columns we are looking at, then the
2769  * view doesn't support INSERT/UPDATE, but it may still support
2770  * DELETE.
2771  */
2772  view_cols_are_auto_updatable(viewquery, NULL,
2773  &updatable_cols, NULL);
2774 
2775  if (include_cols != NULL)
2776  updatable_cols = bms_int_members(updatable_cols, include_cols);
2777 
2778  if (bms_is_empty(updatable_cols))
2779  auto_events = (1 << CMD_DELETE); /* May support DELETE */
2780  else
2781  auto_events = ALL_EVENTS; /* May support all events */
2782 
2783  /*
2784  * The base relation must also support these update commands.
2785  * Tables are always updatable, but for any other kind of base
2786  * relation we must do a recursive check limited to the columns
2787  * referenced by the locally updatable columns in this view.
2788  */
2789  rtr = (RangeTblRef *) linitial(viewquery->jointree->fromlist);
2790  base_rte = rt_fetch(rtr->rtindex, viewquery->rtable);
2791  Assert(base_rte->rtekind == RTE_RELATION);
2792 
2793  if (base_rte->relkind != RELKIND_RELATION &&
2794  base_rte->relkind != RELKIND_PARTITIONED_TABLE)
2795  {
2796  baseoid = base_rte->relid;
2797  outer_reloids = lappend_oid(outer_reloids,
2798  RelationGetRelid(rel));
2799  include_cols = adjust_view_column_set(updatable_cols,
2800  viewquery->targetList);
2801  auto_events &= relation_is_updatable(baseoid,
2802  outer_reloids,
2803  include_triggers,
2804  include_cols);
2805  outer_reloids = list_delete_last(outer_reloids);
2806  }
2807  events |= auto_events;
2808  }
2809  }
2810 
2811  /* If we reach here, the relation may support some update commands */
2813  return events;
2814 }
ExecForeignDelete_function ExecForeignDelete
Definition: fdwapi.h:213
Node * qual
Definition: prs2lock.h:28
int numLocks
Definition: prs2lock.h:42
FromExpr * jointree
Definition: parsenodes.h:138
ExecForeignInsert_function ExecForeignInsert
Definition: fdwapi.h:211
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:1510
Form_pg_class rd_rel
Definition: rel.h:84
unsigned int Oid
Definition: postgres_ext.h:31
List * lappend_oid(List *list, Oid datum)
Definition: list.c:358
bool isInstead
Definition: prs2lock.h:31
Relation try_relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:89
List * targetList
Definition: parsenodes.h:140
bool trig_insert_instead_row
Definition: reltrigger.h:57
#define linitial(l)
Definition: pg_list.h:195
List * rtable
Definition: parsenodes.h:137
#define ALL_EVENTS
TriggerDesc * trigdesc
Definition: rel.h:90
void check_stack_depth(void)
Definition: postgres.c:3288
CmdType event
Definition: prs2lock.h:27
List * list_delete_last(List *list)
Definition: list.c:878
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:62
bool bms_is_empty(const Bitmapset *a)
Definition: bitmapset.c:701
bool trig_delete_instead_row
Definition: reltrigger.h:67
static Bitmapset * adjust_view_column_set(Bitmapset *cols, List *targetlist)
ExecForeignUpdate_function ExecForeignUpdate
Definition: fdwapi.h:212
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:675
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
#define Assert(condition)
Definition: c.h:739
RuleLock * rd_rules
Definition: rel.h:88
RTEKind rtekind
Definition: parsenodes.h:974
FdwRoutine * GetFdwRoutineForRelation(Relation relation, bool makecopy)
Definition: foreign.c:427
Query * get_view_query(Relation view)
int i
IsForeignRelUpdatable_function IsForeignRelUpdatable
Definition: fdwapi.h:217
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:428

◆ RewriteQuery()

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

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

3452 {
3453  CmdType event = parsetree->commandType;
3454  bool instead = false;
3455  bool returning = false;
3456  bool updatableview = false;
3457  Query *qual_product = NULL;
3458  List *rewritten = NIL;
3459  ListCell *lc1;
3460 
3461  /*
3462  * First, recursively process any insert/update/delete statements in WITH
3463  * clauses. (We have to do this first because the WITH clauses may get
3464  * copied into rule actions below.)
3465  */
3466  foreach(lc1, parsetree->cteList)
3467  {
3469  Query *ctequery = castNode(Query, cte->ctequery);
3470  List *newstuff;
3471 
3472  if (ctequery->commandType == CMD_SELECT)
3473  continue;
3474 
3475  newstuff = RewriteQuery(ctequery, rewrite_events);
3476 
3477  /*
3478  * Currently we can only handle unconditional, single-statement DO
3479  * INSTEAD rules correctly; we have to get exactly one Query out of
3480  * the rewrite operation to stuff back into the CTE node.
3481  */
3482  if (list_length(newstuff) == 1)
3483  {
3484  /* Push the single Query back into the CTE node */
3485  ctequery = linitial_node(Query, newstuff);
3486  /* WITH queries should never be canSetTag */
3487  Assert(!ctequery->canSetTag);
3488  cte->ctequery = (Node *) ctequery;
3489  }
3490  else if (newstuff == NIL)
3491  {
3492  ereport(ERROR,
3493  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3494  errmsg("DO INSTEAD NOTHING rules are not supported for data-modifying statements in WITH")));
3495  }
3496  else
3497  {
3498  ListCell *lc2;
3499 
3500  /* examine queries to determine which error message to issue */
3501  foreach(lc2, newstuff)
3502  {
3503  Query *q = (Query *) lfirst(lc2);
3504 
3506  ereport(ERROR,
3507  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3508  errmsg("conditional DO INSTEAD rules are not supported for data-modifying statements in WITH")));
3510  ereport(ERROR,
3511  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3512  errmsg("DO ALSO rules are not supported for data-modifying statements in WITH")));
3513  }
3514 
3515  ereport(ERROR,
3516  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3517  errmsg("multi-statement DO INSTEAD rules are not supported for data-modifying statements in WITH")));
3518  }
3519  }
3520 
3521  /*
3522  * If the statement is an insert, update, or delete, adjust its targetlist
3523  * as needed, and then fire INSERT/UPDATE/DELETE rules on it.
3524  *
3525  * SELECT rules are handled later when we have all the queries that should
3526  * get executed. Also, utilities aren't rewritten at all (do we still
3527  * need that check?)
3528  */
3529  if (event != CMD_SELECT && event != CMD_UTILITY)
3530  {
3531  int result_relation;
3532  RangeTblEntry *rt_entry;
3533  Relation rt_entry_relation;
3534  List *locks;
3535  List *product_queries;
3536  bool hasUpdate = false;
3537  int values_rte_index = 0;
3538  bool defaults_remaining = false;
3539 
3540  result_relation = parsetree->resultRelation;
3541  Assert(result_relation != 0);
3542  rt_entry = rt_fetch(result_relation, parsetree->rtable);
3543  Assert(rt_entry->rtekind == RTE_RELATION);
3544 
3545  /*
3546  * We can use NoLock here since either the parser or
3547  * AcquireRewriteLocks should have locked the rel already.
3548  */
3549  rt_entry_relation = table_open(rt_entry->relid, NoLock);
3550 
3551  /*
3552  * Rewrite the targetlist as needed for the command type.
3553  */
3554  if (event == CMD_INSERT)
3555  {
3556  RangeTblEntry *values_rte = NULL;
3557 
3558  /*
3559  * If it's an INSERT ... VALUES (...), (...), ... there will be a
3560  * single RTE for the VALUES targetlists.
3561  */
3562  if (list_length(parsetree->jointree->fromlist) == 1)
3563  {
3564  RangeTblRef *rtr = (RangeTblRef *) linitial(parsetree->jointree->fromlist);
3565 
3566  if (IsA(rtr, RangeTblRef))
3567  {
3568  RangeTblEntry *rte = rt_fetch(rtr->rtindex,
3569  parsetree->rtable);
3570 
3571  if (rte->rtekind == RTE_VALUES)
3572  {
3573  values_rte = rte;
3574  values_rte_index = rtr->rtindex;
3575  }
3576  }
3577  }
3578 
3579  if (values_rte)
3580  {
3581  /* Process the main targetlist ... */
3582  parsetree->targetList = rewriteTargetListIU(parsetree->targetList,
3583  parsetree->commandType,
3584  parsetree->override,
3585  rt_entry_relation,
3586  parsetree->resultRelation);
3587  /* ... and the VALUES expression lists */
3588  if (!rewriteValuesRTE(parsetree, values_rte, values_rte_index,
3589  rt_entry_relation, false))
3590  defaults_remaining = true;
3591  }
3592  else
3593  {
3594  /* Process just the main targetlist */
3595  parsetree->targetList =
3596  rewriteTargetListIU(parsetree->targetList,
3597  parsetree->commandType,
3598  parsetree->override,
3599  rt_entry_relation,
3600  parsetree->resultRelation);
3601  }
3602 
3603  if (parsetree->onConflict &&
3604  parsetree->onConflict->action == ONCONFLICT_UPDATE)
3605  {
3606  parsetree->onConflict->onConflictSet =
3608  CMD_UPDATE,
3609  parsetree->override,
3610  rt_entry_relation,
3611  parsetree->resultRelation);
3612  }
3613  }
3614  else if (event == CMD_UPDATE)
3615  {
3616  parsetree->targetList =
3617  rewriteTargetListIU(parsetree->targetList,
3618  parsetree->commandType,
3619  parsetree->override,
3620  rt_entry_relation,
3621  parsetree->resultRelation);
3622  }
3623  else if (event == CMD_DELETE)
3624  {
3625  /* Nothing to do here */
3626  }
3627  else
3628  elog(ERROR, "unrecognized commandType: %d", (int) event);
3629 
3630  /*
3631  * Collect and apply the appropriate rules.
3632  */
3633  locks = matchLocks(event, rt_entry_relation->rd_rules,
3634  result_relation, parsetree, &hasUpdate);
3635 
3636  product_queries = fireRules(parsetree,
3637  result_relation,
3638  event,
3639  locks,
3640  &instead,
3641  &returning,
3642  &qual_product);
3643 
3644  /*
3645  * If we have a VALUES RTE with any remaining untouched DEFAULT items,
3646  * and we got any product queries, finalize the VALUES RTE for each
3647  * product query (replacing the remaining DEFAULT items with NULLs).
3648  * We don't do this for the original query, because we know that it
3649  * must be an auto-insert on a view, and so should use the base
3650  * relation's defaults for any remaining DEFAULT items.
3651  */
3652  if (defaults_remaining && product_queries != NIL)
3653  {
3654  ListCell *n;
3655 
3656  /*
3657  * Each product query has its own copy of the VALUES RTE at the
3658  * same index in the rangetable, so we must finalize each one.
3659  */
3660  foreach(n, product_queries)
3661  {
3662  Query *pt = (Query *) lfirst(n);
3663  RangeTblEntry *values_rte = rt_fetch(values_rte_index,
3664  pt->rtable);
3665 
3666  rewriteValuesRTE(pt, values_rte, values_rte_index,
3667  rt_entry_relation,
3668  true); /* Force remaining defaults to NULL */
3669  }
3670  }
3671 
3672  /*
3673  * If there was no unqualified INSTEAD rule, and the target relation
3674  * is a view without any INSTEAD OF triggers, see if the view can be
3675  * automatically updated. If so, we perform the necessary query
3676  * transformation here and add the resulting query to the
3677  * product_queries list, so that it gets recursively rewritten if
3678  * necessary.
3679  *
3680  * If the view cannot be automatically updated, we throw an error here
3681  * which is OK since the query would fail at runtime anyway. Throwing
3682  * the error here is preferable to the executor check since we have
3683  * more detailed information available about why the view isn't
3684  * updatable.
3685  */
3686  if (!instead &&
3687  rt_entry_relation->rd_rel->relkind == RELKIND_VIEW &&
3688  !view_has_instead_trigger(rt_entry_relation, event))
3689  {
3690  /*
3691  * If there were any qualified INSTEAD rules, don't allow the view
3692  * to be automatically updated (an unqualified INSTEAD rule or
3693  * INSTEAD OF trigger is required).
3694  *
3695  * The messages here should match execMain.c's CheckValidResultRel
3696  * and in principle make those checks in executor unnecessary, but
3697  * we keep them just in case.
3698  */
3699  if (qual_product != NULL)
3700  {
3701  switch (parsetree->commandType)
3702  {
3703  case CMD_INSERT:
3704  ereport(ERROR,
3705  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3706  errmsg("cannot insert into view \"%s\"",
3707  RelationGetRelationName(rt_entry_relation)),
3708  errdetail("Views with conditional DO INSTEAD rules are not automatically updatable."),
3709  errhint("To enable inserting into the view, provide an INSTEAD OF INSERT trigger or an unconditional ON INSERT DO INSTEAD rule.")));
3710  break;
3711  case CMD_UPDATE:
3712  ereport(ERROR,
3713  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3714  errmsg("cannot update view \"%s\"",
3715  RelationGetRelationName(rt_entry_relation)),
3716  errdetail("Views with conditional DO INSTEAD rules are not automatically updatable."),
3717  errhint("To enable updating the view, provide an INSTEAD OF UPDATE trigger or an unconditional ON UPDATE DO INSTEAD rule.")));
3718  break;
3719  case CMD_DELETE:
3720  ereport(ERROR,
3721  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3722  errmsg("cannot delete from view \"%s\"",
3723  RelationGetRelationName(rt_entry_relation)),
3724  errdetail("Views with conditional DO INSTEAD rules are not automatically updatable."),
3725  errhint("To enable deleting from the view, provide an INSTEAD OF DELETE trigger or an unconditional ON DELETE DO INSTEAD rule.")));
3726  break;
3727  default:
3728  elog(ERROR, "unrecognized CmdType: %d",
3729  (int) parsetree->commandType);
3730  break;
3731  }
3732  }
3733 
3734  /*
3735  * Attempt to rewrite the query to automatically update the view.
3736  * This throws an error if the view can't be automatically
3737  * updated.
3738  */
3739  parsetree = rewriteTargetView(parsetree, rt_entry_relation);
3740 
3741  /*
3742  * At this point product_queries contains any DO ALSO rule
3743  * actions. Add the rewritten query before or after those. This
3744  * must match the handling the original query would have gotten
3745  * below, if we allowed it to be included again.
3746  */
3747  if (parsetree->commandType == CMD_INSERT)
3748  product_queries = lcons(parsetree, product_queries);
3749  else
3750  product_queries = lappend(product_queries, parsetree);
3751 
3752  /*
3753  * Set the "instead" flag, as if there had been an unqualified
3754  * INSTEAD, to prevent the original query from being included a
3755  * second time below. The transformation will have rewritten any
3756  * RETURNING list, so we can also set "returning" to forestall
3757  * throwing an error below.
3758  */
3759  instead = true;
3760  returning = true;
3761  updatableview = true;
3762  }
3763 
3764  /*
3765  * If we got any product queries, recursively rewrite them --- but
3766  * first check for recursion!
3767  */
3768  if (product_queries != NIL)
3769  {
3770  ListCell *n;
3771  rewrite_event *rev;
3772 
3773  foreach(n, rewrite_events)
3774  {
3775  rev = (rewrite_event *) lfirst(n);
3776  if (rev->relation == RelationGetRelid(rt_entry_relation) &&
3777  rev->event == event)
3778  ereport(ERROR,
3779  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
3780  errmsg("infinite recursion detected in rules for relation \"%s\"",
3781  RelationGetRelationName(rt_entry_relation))));
3782  }
3783 
3784  rev = (rewrite_event *) palloc(sizeof(rewrite_event));
3785  rev->relation = RelationGetRelid(rt_entry_relation);
3786  rev->event = event;
3787  rewrite_events = lappend(rewrite_events, rev);
3788 
3789  foreach(n, product_queries)
3790  {
3791  Query *pt = (Query *) lfirst(n);
3792  List *newstuff;
3793 
3794  newstuff = RewriteQuery(pt, rewrite_events);
3795  rewritten = list_concat(rewritten, newstuff);
3796  }
3797 
3798  rewrite_events = list_delete_last(rewrite_events);
3799  }
3800 
3801  /*
3802  * If there is an INSTEAD, and the original query has a RETURNING, we
3803  * have to have found a RETURNING in the rule(s), else fail. (Because
3804  * DefineQueryRewrite only allows RETURNING in unconditional INSTEAD
3805  * rules, there's no need to worry whether the substituted RETURNING
3806  * will actually be executed --- it must be.)
3807  */
3808  if ((instead || qual_product != NULL) &&
3809  parsetree->returningList &&
3810  !returning)
3811  {
3812  switch (event)
3813  {
3814  case CMD_INSERT:
3815  ereport(ERROR,
3816  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3817  errmsg("cannot perform INSERT RETURNING on relation \"%s\"",
3818  RelationGetRelationName(rt_entry_relation)),
3819  errhint("You need an unconditional ON INSERT DO INSTEAD rule with a RETURNING clause.")));
3820  break;
3821  case CMD_UPDATE:
3822  ereport(ERROR,
3823  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3824  errmsg("cannot perform UPDATE RETURNING on relation \"%s\"",
3825  RelationGetRelationName(rt_entry_relation)),
3826  errhint("You need an unconditional ON UPDATE DO INSTEAD rule with a RETURNING clause.")));
3827  break;
3828  case CMD_DELETE:
3829  ereport(ERROR,
3830  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3831  errmsg("cannot perform DELETE RETURNING on relation \"%s\"",
3832  RelationGetRelationName(rt_entry_relation)),
3833  errhint("You need an unconditional ON DELETE DO INSTEAD rule with a RETURNING clause.")));
3834  break;
3835  default:
3836  elog(ERROR, "unrecognized commandType: %d",
3837  (int) event);
3838  break;
3839  }
3840  }
3841 
3842  /*
3843  * Updatable views are supported by ON CONFLICT, so don't prevent that
3844  * case from proceeding
3845  */
3846  if (parsetree->onConflict &&
3847  (product_queries != NIL || hasUpdate) &&
3848  !updatableview)
3849  ereport(ERROR,
3850  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3851  errmsg("INSERT with ON CONFLICT clause cannot be used with table that has INSERT or UPDATE rules")));
3852 
3853  table_close(rt_entry_relation, NoLock);
3854  }
3855 
3856  /*
3857  * For INSERTs, the original query is done first; for UPDATE/DELETE, it is
3858  * done last. This is needed because update and delete rule actions might
3859  * not do anything if they are invoked after the update or delete is
3860  * performed. The command counter increment between the query executions
3861  * makes the deleted (and maybe the updated) tuples disappear so the scans
3862  * for them in the rule actions cannot find them.
3863  *
3864  * If we found any unqualified INSTEAD, the original query is not done at
3865  * all, in any form. Otherwise, we add the modified form if qualified
3866  * INSTEADs were found, else the unmodified form.
3867  */
3868  if (!instead)
3869  {
3870  if (parsetree->commandType == CMD_INSERT)
3871  {
3872  if (qual_product != NULL)
3873  rewritten = lcons(qual_product, rewritten);
3874  else
3875  rewritten = lcons(parsetree, rewritten);
3876  }
3877  else
3878  {
3879  if (qual_product != NULL)
3880  rewritten = lappend(rewritten, qual_product);
3881  else
3882  rewritten = lappend(rewritten, parsetree);
3883  }
3884  }
3885 
3886  /*
3887  * If the original query has a CTE list, and we generated more than one
3888  * non-utility result query, we have to fail because we'll have copied the
3889  * CTE list into each result query. That would break the expectation of
3890  * single evaluation of CTEs. This could possibly be fixed by
3891  * restructuring so that a CTE list can be shared across multiple Query
3892  * and PlannableStatement nodes.
3893  */
3894  if (parsetree->cteList != NIL)
3895  {
3896  int qcount = 0;
3897 
3898  foreach(lc1, rewritten)
3899  {
3900  Query *q = (Query *) lfirst(lc1);
3901 
3902  if (q->commandType != CMD_UTILITY)
3903  qcount++;
3904  }
3905  if (qcount > 1)
3906  ereport(ERROR,
3907  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3908  errmsg("WITH cannot be used in a query that is rewritten by rules into multiple queries")));
3909  }
3910 
3911  return rewritten;
3912 }
#define NIL
Definition: pg_list.h:65
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
int errhint(const char *fmt,...)
Definition: elog.c:1069
static bool view_has_instead_trigger(Relation view, CmdType event)
FromExpr * jointree
Definition: parsenodes.h:138
OnConflictExpr * onConflict
Definition: parsenodes.h:144
#define castNode(_type_, nodeptr)
Definition: nodes.h:594
int resultRelation
Definition: parsenodes.h:122
Definition: nodes.h:525
static List * RewriteQuery(Query *parsetree, List *rewrite_events)
List * list_concat(List *list1, const List *list2)
Definition: list.c:516
int errcode(int sqlerrcode)
Definition: elog.c:608
List * fromlist
Definition: primnodes.h:1510
Form_pg_class rd_rel
Definition: rel.h:84
#define linitial_node(type, l)
Definition: pg_list.h:198
List * targetList
Definition: parsenodes.h:140
#define linitial(l)
Definition: pg_list.h:195
List * rtable
Definition: parsenodes.h:137
#define ERROR
Definition: elog.h:43
#define lfirst_node(type, lc)
Definition: pg_list.h:193
#define NoLock
Definition: lockdefs.h:34
int errdetail(const char *fmt,...)
Definition: elog.c:955
static Query * rewriteTargetView(Query *parsetree, Relation view)
List * list_delete_last(List *list)
Definition: list.c:878
#define RelationGetRelationName(relation)
Definition: rel.h:462
List * returningList
Definition: parsenodes.h:146
#define ereport(elevel, rest)
Definition: elog.h:141
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
List * lappend(List *list, void *datum)
Definition: list.c:322
OnConflictAction action
Definition: primnodes.h:1526
static List * fireRules(Query *parsetree, int rt_index, CmdType event, List *locks, bool *instead_flag, bool *returning_flag, Query **qual_product)
static List * rewriteTargetListIU(List *targetList, CmdType commandType, OverridingKind override, Relation target_relation, int result_rti)
OverridingKind override
Definition: parsenodes.h:142
CmdType commandType
Definition: parsenodes.h:112
List * lcons(void *datum, List *list)
Definition: list.c:454
QuerySource querySource
Definition: parsenodes.h:114
#define Assert(condition)
Definition: c.h:739
#define lfirst(lc)
Definition: pg_list.h:190
RuleLock * rd_rules
Definition: rel.h:88
bool canSetTag
Definition: parsenodes.h:118
static int list_length(const List *l)
Definition: pg_list.h:169
RTEKind rtekind
Definition: parsenodes.h:974
List * cteList
Definition: parsenodes.h:135
void * palloc(Size size)
Definition: mcxt.c:949
int errmsg(const char *fmt,...)
Definition: elog.c:822
#define elog(elevel,...)
Definition: elog.h:228
List * onConflictSet
Definition: primnodes.h:1535
static bool rewriteValuesRTE(Query *parsetree, RangeTblEntry *rte, int rti, Relation target_relation, bool force_nulls)
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:428
CmdType
Definition: nodes.h:668

◆ rewriteRuleAction()

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

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

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

◆ rewriteTargetListIU()

static List * rewriteTargetListIU ( List targetList,
CmdType  commandType,
OverridingKind  override,
Relation  target_relation,
int  result_rti 
)
static

Definition at line 716 of file rewriteHandler.c.

References build_column_default(), CMD_INSERT, CMD_UPDATE, COERCE_IMPLICIT_CAST, coerce_to_domain(), COERCION_IMPLICIT, elog, ereport, errcode(), errdetail(), errhint(), errmsg(), ERROR, TargetEntry::expr, 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, and view_has_instead_trigger().

Referenced by RewriteQuery().

721 {
722  TargetEntry **new_tles;
723  List *new_tlist = NIL;
724  List *junk_tlist = NIL;
725  Form_pg_attribute att_tup;
726  int attrno,
727  next_junk_attrno,
728  numattrs;
729  ListCell *temp;
730 
731  /*
732  * We process the normal (non-junk) attributes by scanning the input tlist
733  * once and transferring TLEs into an array, then scanning the array to
734  * build an output tlist. This avoids O(N^2) behavior for large numbers
735  * of attributes.
736  *
737  * Junk attributes are tossed into a separate list during the same tlist
738  * scan, then appended to the reconstructed tlist.
739  */
740  numattrs = RelationGetNumberOfAttributes(target_relation);
741  new_tles = (TargetEntry **) palloc0(numattrs * sizeof(TargetEntry *));
742  next_junk_attrno = numattrs + 1;
743 
744  foreach(temp, targetList)
745  {
746  TargetEntry *old_tle = (TargetEntry *) lfirst(temp);
747 
748  if (!old_tle->resjunk)
749  {
750  /* Normal attr: stash it into new_tles[] */
751  attrno = old_tle->resno;
752  if (attrno < 1 || attrno > numattrs)
753  elog(ERROR, "bogus resno %d in targetlist", attrno);
754  att_tup = TupleDescAttr(target_relation->rd_att, attrno - 1);
755 
756  /* We can (and must) ignore deleted attributes */
757  if (att_tup->attisdropped)
758  continue;
759 
760  /* Merge with any prior assignment to same attribute */
761  new_tles[attrno - 1] =
762  process_matched_tle(old_tle,
763  new_tles[attrno - 1],
764  NameStr(att_tup->attname));
765  }
766  else
767  {
768  /*
769  * Copy all resjunk tlist entries to junk_tlist, and assign them
770  * resnos above the last real resno.
771  *
772  * Typical junk entries include ORDER BY or GROUP BY expressions
773  * (are these actually possible in an INSERT or UPDATE?), system
774  * attribute references, etc.
775  */
776 
777  /* Get the resno right, but don't copy unnecessarily */
778  if (old_tle->resno != next_junk_attrno)
779  {
780  old_tle = flatCopyTargetEntry(old_tle);
781  old_tle->resno = next_junk_attrno;
782  }
783  junk_tlist = lappend(junk_tlist, old_tle);
784  next_junk_attrno++;
785  }
786  }
787 
788  for (attrno = 1; attrno <= numattrs; attrno++)
789  {
790  TargetEntry *new_tle = new_tles[attrno - 1];
791  bool apply_default;
792 
793  att_tup = TupleDescAttr(target_relation->rd_att, attrno - 1);
794 
795  /* We can (and must) ignore deleted attributes */
796  if (att_tup->attisdropped)
797  continue;
798 
799  /*
800  * Handle the two cases where we need to insert a default expression:
801  * it's an INSERT and there's no tlist entry for the column, or the
802  * tlist entry is a DEFAULT placeholder node.
803  */
804  apply_default = ((new_tle == NULL && commandType == CMD_INSERT) ||
805  (new_tle && new_tle->expr && IsA(new_tle->expr, SetToDefault)));
806 
807  if (commandType == CMD_INSERT)
808  {
809  if (att_tup->attidentity == ATTRIBUTE_IDENTITY_ALWAYS && !apply_default)
810  {
811  if (override != OVERRIDING_SYSTEM_VALUE)
812  ereport(ERROR,
813  (errcode(ERRCODE_GENERATED_ALWAYS),
814  errmsg("cannot insert into column \"%s\"", NameStr(att_tup->attname)),
815  errdetail("Column \"%s\" is an identity column defined as GENERATED ALWAYS.",
816  NameStr(att_tup->attname)),
817  errhint("Use OVERRIDING SYSTEM VALUE to override.")));
818  }
819 
820  if (att_tup->attidentity == ATTRIBUTE_IDENTITY_BY_DEFAULT && override == OVERRIDING_USER_VALUE)
821  apply_default = true;
822 
823  if (att_tup->attgenerated && !apply_default)
824  ereport(ERROR,
825  (errcode(ERRCODE_SYNTAX_ERROR),
826  errmsg("cannot insert into column \"%s\"", NameStr(att_tup->attname)),
827  errdetail("Column \"%s\" is a generated column.",
828  NameStr(att_tup->attname))));
829  }
830 
831  if (commandType == CMD_UPDATE)
832  {
833  if (att_tup->attidentity == ATTRIBUTE_IDENTITY_ALWAYS && new_tle && !apply_default)
834  ereport(ERROR,
835  (errcode(ERRCODE_GENERATED_ALWAYS),
836  errmsg("column \"%s\" can only be updated to DEFAULT", NameStr(att_tup->attname)),
837  errdetail("Column \"%s\" is an identity column defined as GENERATED ALWAYS.",
838  NameStr(att_tup->attname))));
839 
840  if (att_tup->attgenerated && new_tle && !apply_default)
841  ereport(ERROR,
842  (errcode(ERRCODE_SYNTAX_ERROR),
843  errmsg("column \"%s\" can only be updated to DEFAULT", NameStr(att_tup->attname)),
844  errdetail("Column \"%s\" is a generated column.",
845  NameStr(att_tup->attname))));
846  }
847 
848  if (att_tup->attgenerated)
849  {
850  /*
851  * stored generated column will be fixed in executor
852  */
853  new_tle = NULL;
854  }
855  else if (apply_default)
856  {
857  Node *new_expr;
858 
859  new_expr = build_column_default(target_relation, attrno);
860 
861  /*
862  * If there is no default (ie, default is effectively NULL), we
863  * can omit the tlist entry in the INSERT case, since the planner
864  * can insert a NULL for itself, and there's no point in spending
865  * any more rewriter cycles on the entry. But in the UPDATE case
866  * we've got to explicitly set the column to NULL.
867  */
868  if (!new_expr)
869  {
870  if (commandType == CMD_INSERT)
871  new_tle = NULL;
872  else
873  {
874  new_expr = (Node *) makeConst(att_tup->atttypid,
875  -1,
876  att_tup->attcollation,
877  att_tup->attlen,
878  (Datum) 0,
879  true, /* isnull */
880  att_tup->attbyval);
881  /* this is to catch a NOT NULL domain constraint */
882  new_expr = coerce_to_domain(new_expr,
883  InvalidOid, -1,
884  att_tup->atttypid,
887  -1,
888  false);
889  }
890  }
891 
892  if (new_expr)
893  new_tle = makeTargetEntry((Expr *) new_expr,
894  attrno,
895  pstrdup(NameStr(att_tup->attname)),
896  false);
897  }
898 
899  /*
900  * For an UPDATE on a trigger-updatable view, provide a dummy entry
901  * whenever there is no explicit assignment.
902  */
903  if (new_tle == NULL && commandType == CMD_UPDATE &&
904  target_relation->rd_rel->relkind == RELKIND_VIEW &&
905  view_has_instead_trigger(target_relation, CMD_UPDATE))
906  {
907  Node *new_expr;
908 
909  new_expr = (Node *) makeVar(result_rti,
910  attrno,
911  att_tup->atttypid,
912  att_tup->atttypmod,
913  att_tup->attcollation,
914  0);
915 
916  new_tle = makeTargetEntry((Expr *) new_expr,
917  attrno,
918  pstrdup(NameStr(att_tup->attname)),
919  false);
920  }
921 
922  if (new_tle)
923  new_tlist = lappend(new_tlist, new_tle);
924  }
925 
926  pfree(new_tles);
927 
928  return list_concat(new_tlist, junk_tlist);
929 }
#define NIL
Definition: pg_list.h:65
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
int errhint(const char *fmt,...)
Definition: elog.c:1069
static bool view_has_instead_trigger(Relation view, CmdType event)
#define RelationGetNumberOfAttributes(relation)
Definition: rel.h:434
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
char * pstrdup(const char *in)
Definition: mcxt.c:1186
Definition: nodes.h:525
List * list_concat(List *list1, const List *list2)
Definition: list.c:516
int errcode(int sqlerrcode)
Definition: elog.c:608
Form_pg_class rd_rel
Definition: rel.h:84
Const * makeConst(Oid consttype, int32 consttypmod, Oid constcollid, int constlen, Datum constvalue, bool constisnull, bool constbyval)
Definition: makefuncs.c:297
void pfree(void *pointer)
Definition: mcxt.c:1056
bool resjunk
Definition: primnodes.h:1414
#define ERROR
Definition: elog.h:43
Node * coerce_to_domain(Node *arg, Oid baseTypeId, int32 baseTypeMod, Oid typeId, CoercionContext ccontext, CoercionForm cformat, int location, bool hideInputCoercion)
Definition: parse_coerce.c:663
int errdetail(const char *fmt,...)
Definition: elog.c:955
AttrNumber resno
Definition: primnodes.h:1408
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:200
TargetEntry * flatCopyTargetEntry(TargetEntry *src_tle)
Definition: makefuncs.c:269
#define ereport(elevel, rest)
Definition: elog.h:141
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:236
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:322
Node * build_column_default(Relation rel, int attrno)
void * palloc0(Size size)
Definition: mcxt.c:980
uintptr_t Datum
Definition: postgres.h:367
TupleDesc rd_att
Definition: rel.h:85
#define InvalidOid
Definition: postgres_ext.h:36
#define lfirst(lc)
Definition: pg_list.h:190
Expr * expr
Definition: primnodes.h:1407
int errmsg(const char *fmt,...)
Definition: elog.c:822
static TargetEntry * process_matched_tle(TargetEntry *src_tle, TargetEntry *prior_tle, const char *attrName)
#define elog(elevel,...)
Definition: elog.h:228
#define NameStr(name)
Definition: c.h:616
Definition: pg_list.h:50

◆ rewriteTargetListUD()

void rewriteTargetListUD ( Query parsetree,
RangeTblEntry target_rte,
Relation  target_relation 
)

Definition at line 1444 of file rewriteHandler.c.

References FdwRoutine::AddForeignUpdateTargets, CMD_DELETE, CMD_UPDATE, Query::commandType, GetFdwRoutineForRelation(), InvalidOid, lappend(), list_length(), makeTargetEntry(), makeVar(), makeWholeRowVar(), pstrdup(), RelationData::rd_rel, Query::resultRelation, SelfItemPointerAttributeNumber, Query::targetList, TriggerDesc::trig_delete_after_row, TriggerDesc::trig_delete_before_row, TriggerDesc::trig_update_after_row, TriggerDesc::trig_update_before_row, and RelationData::trigdesc.

Referenced by preprocess_targetlist().

1446 {
1447  Var *var = NULL;
1448  const char *attrname;
1449  TargetEntry *tle;
1450 
1451  if (target_relation->rd_rel->relkind == RELKIND_RELATION ||
1452  target_relation->rd_rel->relkind == RELKIND_MATVIEW ||
1453  target_relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1454  {
1455  /*
1456  * Emit CTID so that executor can find the row to update or delete.
1457  */
1458  var = makeVar(parsetree->resultRelation,
1460  TIDOID,
1461  -1,
1462  InvalidOid,
1463  0);
1464 
1465  attrname = "ctid";
1466  }
1467  else if (target_relation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
1468  {
1469  /*
1470  * Let the foreign table's FDW add whatever junk TLEs it wants.
1471  */
1472  FdwRoutine *fdwroutine;
1473 
1474  fdwroutine = GetFdwRoutineForRelation(target_relation, false);
1475 
1476  if (fdwroutine->AddForeignUpdateTargets != NULL)
1477  fdwroutine->AddForeignUpdateTargets(parsetree, target_rte,
1478  target_relation);
1479 
1480  /*
1481  * If we have a row-level trigger corresponding to the operation, emit
1482  * a whole-row Var so that executor will have the "old" row to pass to
1483  * the trigger. Alas, this misses system columns.
1484  */
1485  if (target_relation->trigdesc &&
1486  ((parsetree->commandType == CMD_UPDATE &&
1487  (target_relation->trigdesc->trig_update_after_row ||
1488  target_relation->trigdesc->trig_update_before_row)) ||
1489  (parsetree->commandType == CMD_DELETE &&
1490  (target_relation->trigdesc->trig_delete_after_row ||
1491  target_relation->trigdesc->trig_delete_before_row))))
1492  {
1493  var = makeWholeRowVar(target_rte,
1494  parsetree->resultRelation,
1495  0,
1496  false);
1497 
1498  attrname = "wholerow";
1499  }
1500  }
1501 
1502  if (var != NULL)
1503  {
1504  tle = makeTargetEntry((Expr *) var,
1505  list_length(parsetree->targetList) + 1,
1506  pstrdup(attrname),
1507  true);
1508 
1509  parsetree->targetList = lappend(parsetree->targetList, tle);
1510  }
1511 }
char * pstrdup(const char *in)
Definition: mcxt.c:1186
int resultRelation
Definition: parsenodes.h:122
Var * makeWholeRowVar(RangeTblEntry *rte, Index varno, Index varlevelsup, bool allowScalar)
Definition: makefuncs.c:133
Form_pg_class rd_rel
Definition: rel.h:84
Definition: primnodes.h:181
AddForeignUpdateTargets_function AddForeignUpdateTargets
Definition: fdwapi.h:208
List * targetList
Definition: parsenodes.h:140
TriggerDesc * trigdesc
Definition: rel.h:90
bool trig_delete_after_row
Definition: reltrigger.h:66
bool trig_update_before_row
Definition: reltrigger.h:60
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:236
Var * makeVar(Index varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:66
bool trig_update_after_row
Definition: reltrigger.h:61
List * lappend(List *list, void *datum)
Definition: list.c:322
#define InvalidOid
Definition: postgres_ext.h:36
CmdType commandType
Definition: parsenodes.h:112
static int list_length(const List *l)
Definition: pg_list.h:169
FdwRoutine * GetFdwRoutineForRelation(Relation relation, bool makecopy)
Definition: foreign.c:427
#define SelfItemPointerAttributeNumber
Definition: sysattr.h:21
bool trig_delete_before_row
Definition: reltrigger.h:65

◆ rewriteTargetView()

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

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

2897 {
2898  Query *viewquery;
2899  const char *auto_update_detail;
2900  RangeTblRef *rtr;
2901  int base_rt_index;
2902  int new_rt_index;
2903  RangeTblEntry *base_rte;
2904  RangeTblEntry *view_rte;
2905  RangeTblEntry *new_rte;
2906  Relation base_rel;
2907  List *view_targetlist;
2908  ListCell *lc;
2909 
2910  /*
2911  * Get the Query from the view's ON SELECT rule. We're going to munge the
2912  * Query to change the view's base relation into the target relation,
2913  * along with various other changes along the way, so we need to make a
2914  * copy of it (get_view_query() returns a pointer into the relcache, so we
2915  * have to treat it as read-only).
2916  */
2917  viewquery = copyObject(get_view_query(view));
2918 
2919  /* The view must be updatable, else fail */
2920  auto_update_detail =
2921  view_query_is_auto_updatable(viewquery,
2922  parsetree->commandType != CMD_DELETE);
2923 
2924  if (auto_update_detail)
2925  {
2926  /* messages here should match execMain.c's CheckValidResultRel */
2927  switch (parsetree->commandType)
2928  {
2929  case CMD_INSERT:
2930  ereport(ERROR,
2931  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
2932  errmsg("cannot insert into view \"%s\"",
2933  RelationGetRelationName(view)),
2934  errdetail_internal("%s", _(auto_update_detail)),
2935  errhint("To enable inserting into the view, provide an INSTEAD OF INSERT trigger or an unconditional ON INSERT DO INSTEAD rule.")));
2936  break;
2937  case CMD_UPDATE:
2938  ereport(ERROR,
2939  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
2940  errmsg("cannot update view \"%s\"",
2941  RelationGetRelationName(view)),
2942  errdetail_internal("%s", _(auto_update_detail)),
2943  errhint("To enable updating the view, provide an INSTEAD OF UPDATE trigger or an unconditional ON UPDATE DO INSTEAD rule.")));
2944  break;
2945  case CMD_DELETE:
2946  ereport(ERROR,
2947  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
2948  errmsg("cannot delete from view \"%s\"",
2949  RelationGetRelationName(view)),
2950  errdetail_internal("%s", _(auto_update_detail)),
2951  errhint("To enable deleting from the view, provide an INSTEAD OF DELETE trigger or an unconditional ON DELETE DO INSTEAD rule.")));
2952  break;
2953  default:
2954  elog(ERROR, "unrecognized CmdType: %d",
2955  (int) parsetree->commandType);
2956  break;
2957  }
2958  }
2959 
2960  /*
2961  * For INSERT/UPDATE the modified columns must all be updatable. Note that
2962  * we get the modified columns from the query's targetlist, not from the
2963  * result RTE's insertedCols and/or updatedCols set, since
2964  * rewriteTargetListIU may have added additional targetlist entries for
2965  * view defaults, and these must also be updatable.
2966  */
2967  if (parsetree->commandType != CMD_DELETE)
2968  {
2969  Bitmapset *modified_cols = NULL;
2970  char *non_updatable_col;
2971 
2972  foreach(lc, parsetree->targetList)
2973  {
2974  TargetEntry *tle = (TargetEntry *) lfirst(lc);
2975 
2976  if (!tle->resjunk)
2977  modified_cols = bms_add_member(modified_cols,
2979  }
2980 
2981  if (parsetree->onConflict)
2982  {
2983  foreach(lc, parsetree->onConflict->onConflictSet)
2984  {
2985  TargetEntry *tle = (TargetEntry *) lfirst(lc);
2986 
2987  if (!tle->resjunk)
2988  modified_cols = bms_add_member(modified_cols,
2990  }
2991  }
2992 
2993  auto_update_detail = view_cols_are_auto_updatable(viewquery,
2994  modified_cols,
2995  NULL,
2996  &non_updatable_col);
2997  if (auto_update_detail)
2998  {
2999  /*
3000  * This is a different error, caused by an attempt to update a
3001  * non-updatable column in an otherwise updatable view.
3002  */
3003  switch (parsetree->commandType)
3004  {
3005  case CMD_INSERT:
3006  ereport(ERROR,
3007  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3008  errmsg("cannot insert into column \"%s\" of view \"%s\"",
3009  non_updatable_col,
3010  RelationGetRelationName(view)),
3011  errdetail_internal("%s", _(auto_update_detail))));
3012  break;
3013  case CMD_UPDATE:
3014  ereport(ERROR,
3015  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3016  errmsg("cannot update column \"%s\" of view \"%s\"",
3017  non_updatable_col,
3018  RelationGetRelationName(view)),
3019  errdetail_internal("%s", _(auto_update_detail))));
3020  break;
3021  default:
3022  elog(ERROR, "unrecognized CmdType: %d",
3023  (int) parsetree->commandType);
3024  break;
3025  }
3026  }
3027  }
3028 
3029  /* Locate RTE describing the view in the outer query */
3030  view_rte = rt_fetch(parsetree->resultRelation, parsetree->rtable);
3031 
3032  /*
3033  * If we get here, view_query_is_auto_updatable() has verified that the
3034  * view contains a single base relation.
3035  */
3036  Assert(list_length(viewquery->jointree->fromlist) == 1);
3037  rtr = linitial_node(RangeTblRef, viewquery->jointree->fromlist);
3038 
3039  base_rt_index = rtr->rtindex;
3040  base_rte = rt_fetch(base_rt_index, viewquery->rtable);
3041  Assert(base_rte->rtekind == RTE_RELATION);
3042 
3043  /*
3044  * Up to now, the base relation hasn't been touched at all in our query.
3045  * We need to acquire lock on it before we try to do anything with it.
3046  * (The subsequent recursive call of RewriteQuery will suppose that we
3047  * already have the right lock!) Since it will become the query target
3048  * relation, RowExclusiveLock is always the right thing.
3049  */
3050  base_rel = table_open(base_rte->relid, RowExclusiveLock);
3051 
3052  /*
3053  * While we have the relation open, update the RTE's relkind, just in case
3054  * it changed since this view was made (cf. AcquireRewriteLocks).
3055  */
3056  base_rte->relkind = base_rel->rd_rel->relkind;
3057 
3058  /*
3059  * If the view query contains any sublink subqueries then we need to also
3060  * acquire locks on any relations they refer to. We know that there won't
3061  * be any subqueries in the range table or CTEs, so we can skip those, as
3062  * in AcquireRewriteLocks.
3063  */
3064  if (viewquery->hasSubLinks)
3065  {
3067 
3068  context.for_execute = true;
3069  query_tree_walker(viewquery, acquireLocksOnSubLinks, &context,
3071  }
3072 
3073  /*
3074  * Create a new target RTE describing the base relation, and add it to the
3075  * outer query's rangetable. (What's happening in the next few steps is
3076  * very much like what the planner would do to "pull up" the view into the
3077  * outer query. Perhaps someday we should refactor things enough so that
3078  * we can share code with the planner.)
3079  *
3080  * Be sure to set rellockmode to the correct thing for the target table.
3081  * Since we copied the whole viewquery above, we can just scribble on
3082  * base_rte instead of copying it.
3083  */
3084  new_rte = base_rte;
3085  new_rte->rellockmode = RowExclusiveLock;
3086 
3087  parsetree->rtable = lappend(parsetree->rtable, new_rte);
3088  new_rt_index = list_length(parsetree->rtable);
3089 
3090  /*
3091  * INSERTs never inherit. For UPDATE/DELETE, we use the view query's
3092  * inheritance flag for the base relation.
3093  */
3094  if (parsetree->commandType == CMD_INSERT)
3095  new_rte->inh = false;
3096 
3097  /*
3098  * Adjust the view's targetlist Vars to reference the new target RTE, ie
3099  * make their varnos be new_rt_index instead of base_rt_index. There can
3100  * be no Vars for other rels in the tlist, so this is sufficient to pull
3101  * up the tlist expressions for use in the outer query. The tlist will
3102  * provide the replacement expressions used by ReplaceVarsFromTargetList
3103  * below.
3104  */
3105  view_targetlist = viewquery->targetList;
3106 
3107  ChangeVarNodes((Node *) view_targetlist,
3108  base_rt_index,
3109  new_rt_index,
3110  0);
3111 
3112  /*
3113  * Mark the new target RTE for the permissions checks that we want to
3114  * enforce against the view owner, as distinct from the query caller. At
3115  * the relation level, require the same INSERT/UPDATE/DELETE permissions
3116  * that the query caller needs against the view. We drop the ACL_SELECT
3117  * bit that is presumably in new_rte->requiredPerms initially.
3118  *
3119  * Note: the original view RTE remains in the query's rangetable list.
3120  * Although it will be unused in the query plan, we need it there so that
3121  * the executor still performs appropriate permissions checks for the
3122  * query caller's use of the view.
3123  */
3124  new_rte->checkAsUser = view->rd_rel->relowner;
3125  new_rte->requiredPerms = view_rte->requiredPerms;
3126 
3127  /*
3128  * Now for the per-column permissions bits.
3129  *
3130  * Initially, new_rte contains selectedCols permission check bits for all
3131  * base-rel columns referenced by the view, but since the view is a SELECT
3132  * query its insertedCols/updatedCols is empty. We set insertedCols and
3133  * updatedCols to include all the columns the outer query is trying to
3134  * modify, adjusting the column numbers as needed. But we leave
3135  * selectedCols as-is, so the view owner must have read permission for all
3136  * columns used in the view definition, even if some of them are not read
3137  * by the outer query. We could try to limit selectedCols to only columns
3138  * used in the transformed query, but that does not correspond to what
3139  * happens in ordinary SELECT usage of a view: all referenced columns must
3140  * have read permission, even if optimization finds that some of them can
3141  * be discarded during query transformation. The flattening we're doing
3142  * here is an optional optimization, too. (If you are unpersuaded and
3143  * want to change this, note that applying adjust_view_column_set to
3144  * view_rte->selectedCols is clearly *not* the right answer, since that
3145  * neglects base-rel columns used in the view's WHERE quals.)
3146  *
3147  * This step needs the modified view targetlist, so we have to do things
3148  * in this order.
3149  */
3150  Assert(bms_is_empty(new_rte->insertedCols) &&
3151  bms_is_empty(new_rte->updatedCols));
3152 
3153  new_rte->insertedCols = adjust_view_column_set(view_rte->insertedCols,
3154  view_targetlist);
3155 
3156  new_rte->updatedCols = adjust_view_column_set(view_rte->updatedCols,
3157  view_targetlist);
3158 
3159  /*
3160  * Move any security barrier quals from the view RTE onto the new target
3161  * RTE. Any such quals should now apply to the new target RTE and will
3162  * not reference the original view RTE in the rewritten query.
3163  */
3164  new_rte->securityQuals = view_rte->securityQuals;
3165  view_rte->securityQuals = NIL;
3166 
3167  /*
3168  * Now update all Vars in the outer query that reference the view to
3169  * reference the appropriate column of the base relation instead.
3170  */
3171  parsetree = (Query *)
3172  ReplaceVarsFromTargetList((Node *) parsetree,
3173  parsetree->resultRelation,
3174  0,
3175  view_rte,
3176  view_targetlist,
3178  0,
3179  &parsetree->hasSubLinks);
3180 
3181  /*
3182  * Update all other RTI references in the query that point to the view
3183  * (for example, parsetree->resultRelation itself) to point to the new
3184  * base relation instead. Vars will not be affected since none of them
3185  * reference parsetree->resultRelation any longer.
3186  */
3187  ChangeVarNodes((Node *) parsetree,
3188  parsetree->resultRelation,
3189  new_rt_index,
3190  0);
3191  Assert(parsetree->resultRelation == new_rt_index);
3192 
3193  /*
3194  * For INSERT/UPDATE we must also update resnos in the targetlist to refer
3195  * to columns of the base relation, since those indicate the target
3196  * columns to be affected.
3197  *
3198  * Note that this destroys the resno ordering of the targetlist, but that
3199  * will be fixed when we recurse through rewriteQuery, which will invoke
3200  * rewriteTargetListIU again on the updated targetlist.
3201  */
3202  if (parsetree->commandType != CMD_DELETE)
3203  {
3204  foreach(lc, parsetree->targetList)
3205  {
3206  TargetEntry *tle = (TargetEntry *) lfirst(lc);
3207  TargetEntry *view_tle;
3208 
3209  if (tle->resjunk)
3210  continue;
3211 
3212  view_tle = get_tle_by_resno(view_targetlist, tle->resno);
3213  if (view_tle != NULL && !view_tle->resjunk && IsA(view_tle->expr, Var))
3214  tle->resno = ((Var *) view_tle->expr)->varattno;
3215  else
3216  elog(ERROR, "attribute number %d not found in view targetlist",
3217  tle->resno);
3218  }
3219  }
3220 
3221  /*
3222  * For INSERT .. ON CONFLICT .. DO UPDATE, we must also update assorted
3223  * stuff in the onConflict data structure.
3224  */
3225  if (parsetree->onConflict &&
3226  parsetree->onConflict->action == ONCONFLICT_UPDATE)
3227  {
3228  Index old_exclRelIndex,
3229  new_exclRelIndex;
3230  ParseNamespaceItem *new_exclNSItem;
3231  RangeTblEntry *new_exclRte;
3232  List *tmp_tlist;
3233 
3234  /*
3235  * Like the INSERT/UPDATE code above, update the resnos in the
3236  * auxiliary UPDATE targetlist to refer to columns of the base
3237  * relation.
3238  */
3239  foreach(lc, parsetree->onConflict->onConflictSet)
3240  {
3241  TargetEntry *tle = (TargetEntry *) lfirst(lc);
3242  TargetEntry *view_tle;
3243 
3244  if (tle->resjunk)
3245  continue;
3246 
3247  view_tle = get_tle_by_resno(view_targetlist, tle->resno);
3248  if (view_tle != NULL && !view_tle->resjunk && IsA(view_tle->expr, Var))
3249  tle->resno = ((Var *) view_tle->expr)->varattno;
3250  else
3251  elog(ERROR, "attribute number %d not found in view targetlist",
3252  tle->resno);
3253  }
3254 
3255  /*
3256  * Also, create a new RTE for the EXCLUDED pseudo-relation, using the
3257  * query's new base rel (which may well have a different column list
3258  * from the view, hence we need a new column alias list). This should
3259  * match transformOnConflictClause. In particular, note that the
3260  * relkind is set to composite to signal that we're not dealing with
3261  * an actual relation, and no permissions checks are wanted.
3262  */
3263  old_exclRelIndex = parsetree->onConflict->exclRelIndex;
3264 
3265  new_exclNSItem = addRangeTableEntryForRelation(make_parsestate(NULL),
3266  base_rel,
3268  makeAlias("excluded", NIL),
3269  false, false);
3270  new_exclRte = new_exclNSItem->p_rte;
3271  new_exclRte->relkind = RELKIND_COMPOSITE_TYPE;
3272  new_exclRte->requiredPerms = 0;
3273  /* other permissions fields in new_exclRte are already empty */
3274 
3275  parsetree->rtable = lappend(parsetree->rtable, new_exclRte);
3276  new_exclRelIndex = parsetree->onConflict->exclRelIndex =
3277  list_length(parsetree->rtable);
3278 
3279  /*
3280  * Replace the targetlist for the EXCLUDED pseudo-relation with a new
3281  * one, representing the columns from the new base relation.
3282  */
3283  parsetree->onConflict->exclRelTlist =
3284  BuildOnConflictExcludedTargetlist(base_rel, new_exclRelIndex);
3285 
3286  /*
3287  * Update all Vars in the ON CONFLICT clause that refer to the old
3288  * EXCLUDED pseudo-relation. We want to use the column mappings
3289  * defined in the view targetlist, but we need the outputs to refer to
3290  * the new EXCLUDED pseudo-relation rather than the new target RTE.
3291  * Also notice that "EXCLUDED.*" will be expanded using the view's
3292  * rowtype, which seems correct.
3293  */
3294  tmp_tlist = copyObject(view_targetlist);
3295 
3296  ChangeVarNodes((Node *) tmp_tlist, new_rt_index,
3297  new_exclRelIndex, 0);
3298 
3299  parsetree->onConflict = (OnConflictExpr *)
3300  ReplaceVarsFromTargetList((Node *) parsetree->onConflict,
3301  old_exclRelIndex,
3302  0,
3303  view_rte,
3304  tmp_tlist,
3306  0,
3307  &parsetree->hasSubLinks);
3308  }
3309 
3310  /*
3311  * For UPDATE/DELETE, pull up any WHERE quals from the view. We know that
3312  * any Vars in the quals must reference the one base relation, so we need
3313  * only adjust their varnos to reference the new target (just the same as
3314  * we did with the view targetlist).
3315  *
3316  * If it's a security-barrier view, its WHERE quals must be applied before
3317  * quals from the outer query, so we attach them to the RTE as security
3318  * barrier quals rather than adding them to the main WHERE clause.
3319  *
3320  * For INSERT, the view's quals can be ignored in the main query.
3321  */
3322  if (parsetree->commandType != CMD_INSERT &&
3323  viewquery->jointree->quals != NULL)
3324  {
3325  Node *viewqual = (Node *) viewquery->jointree->quals;
3326 
3327  /*
3328  * Even though we copied viewquery already at the top of this
3329  * function, we must duplicate the viewqual again here, because we may
3330  * need to use the quals again below for a WithCheckOption clause.
3331  */
3332  viewqual = copyObject(viewqual);
3333 
3334  ChangeVarNodes(viewqual, base_rt_index, new_rt_index, 0);
3335 
3336  if (RelationIsSecurityView(view))
3337  {
3338  /*
3339  * The view's quals go in front of existing barrier quals: those
3340  * would have come from an outer level of security-barrier view,
3341  * and so must get evaluated later.
3342  *
3343  * Note: the parsetree has been mutated, so the new_rte pointer is
3344  * stale and needs to be re-computed.
3345  */
3346  new_rte = rt_fetch(new_rt_index, parsetree->rtable);
3347  new_rte->securityQuals = lcons(viewqual, new_rte->securityQuals);
3348 
3349  /*
3350  * Do not set parsetree->hasRowSecurity, because these aren't RLS
3351  * conditions (they aren't affected by enabling/disabling RLS).
3352  */
3353 
3354  /*
3355  * Make sure that the query is marked correctly if the added qual
3356  * has sublinks.
3357  */
3358  if (!parsetree->hasSubLinks)
3359  parsetree->hasSubLinks = checkExprHasSubLink(viewqual);
3360  }
3361  else
3362  AddQual(parsetree, (Node *) viewqual);
3363  }
3364 
3365  /*
3366  * For INSERT/UPDATE, if the view has the WITH CHECK OPTION, or any parent
3367  * view specified WITH CASCADED CHECK OPTION, add the quals from the view
3368  * to the query's withCheckOptions list.
3369  */
3370  if (parsetree->commandType != CMD_DELETE)
3371  {
3372  bool has_wco = RelationHasCheckOption(view);
3373  bool cascaded = RelationHasCascadedCheckOption(view);
3374 
3375  /*
3376  * If the parent view has a cascaded check option, treat this view as
3377  * if it also had a cascaded check option.
3378  *
3379  * New WithCheckOptions are added to the start of the list, so if
3380  * there is a cascaded check option, it will be the first item in the
3381  * list.
3382  */
3383  if (parsetree->withCheckOptions != NIL)
3384  {
3385  WithCheckOption *parent_wco =
3386  (WithCheckOption *) linitial(parsetree->withCheckOptions);
3387 
3388  if (parent_wco->cascaded)
3389  {
3390  has_wco = true;
3391  cascaded = true;
3392  }
3393  }
3394 
3395  /*
3396  * Add the new WithCheckOption to the start of the list, so that
3397  * checks on inner views are run before checks on outer views, as
3398  * required by the SQL standard.
3399  *
3400  * If the new check is CASCADED, we need to add it even if this view
3401  * has no quals, since there may be quals on child views. A LOCAL
3402  * check can be omitted if this view has no quals.
3403  */
3404  if (has_wco && (cascaded || viewquery->jointree->quals != NULL))
3405  {
3406  WithCheckOption *wco;
3407 
3408  wco = makeNode(WithCheckOption);
3409  wco->kind = WCO_VIEW_CHECK;
3410  wco->relname = pstrdup(RelationGetRelationName(view));
3411  wco->polname = NULL;
3412  wco->qual = NULL;
3413  wco->cascaded = cascaded;
3414 
3415  parsetree->withCheckOptions = lcons(wco,
3416  parsetree->withCheckOptions);
3417 
3418  if (viewquery->jointree->quals != NULL)
3419  {
3420  wco->qual = (Node *) viewquery->jointree->quals;
3421  ChangeVarNodes(wco->qual, base_rt_index, new_rt_index, 0);
3422 
3423  /*
3424  * Make sure that the query is marked correctly if the added
3425  * qual has sublinks. We can skip this check if the query is
3426  * already marked, or if the command is an UPDATE, in which
3427  * case the same qual will have already been added, and this
3428  * check will already have been done.
3429  */
3430  if (!parsetree->hasSubLinks &&
3431  parsetree->commandType != CMD_UPDATE)
3432  parsetree->hasSubLinks = checkExprHasSubLink(wco->qual);
3433  }
3434  }
3435  }
3436 
3437  table_close(base_rel, NoLock);
3438 
3439  return parsetree;
3440 }
#define NIL
Definition: pg_list.h:65
bool query_tree_walker(Query *query, bool(*walker)(), void *context, int flags)
Definition: nodeFuncs.c:2273
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
int errhint(const char *fmt,...)
Definition: elog.c:1069
static bool acquireLocksOnSubLinks(Node *node, acquireLocksOnSubLinks_context *context)
FromExpr * jointree
Definition: parsenodes.h:138
bool checkExprHasSubLink(Node *node)
Definition: rewriteManip.c:277
OnConflictExpr * onConflict
Definition: parsenodes.h:144
List * withCheckOptions
Definition: parsenodes.h:171
List * securityQuals
Definition: parsenodes.h:1123
char * pstrdup(const char *in)
Definition: mcxt.c:1186
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:122
List * BuildOnConflictExcludedTargetlist(Relation targetrel, Index exclRelIndex)
Definition: analyze.c:1078
Definition: nodes.h:525
int errcode(int sqlerrcode)
Definition: elog.c:608
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
AclMode requiredPerms
Definition: parsenodes.h:1117
List * fromlist
Definition: primnodes.h:1510
Form_pg_class rd_rel
Definition: rel.h:84
Definition: primnodes.h:181
#define linitial_node(type, l)
Definition: pg_list.h:198
Node * quals
Definition: primnodes.h:1511
int errdetail_internal(const char *fmt,...)
Definition: elog.c:982
List * targetList
Definition: parsenodes.h:140
ParseNamespaceItem * addRangeTableEntryForRelation(ParseState *pstate, Relation rel, int lockmode, Alias *alias, bool inh, bool inFromCl)
ParseState * make_parsestate(ParseState *parentParseState)
Definition: parse_node.c:43
#define QTW_IGNORE_RC_SUBQUERIES
Definition: nodeFuncs.h:22
Alias * makeAlias(const char *aliasname, List *colnames)
Definition: makefuncs.c:385
RangeTblEntry * p_rte
Definition: parse_node.h:257
bool resjunk
Definition: primnodes.h:1414
#define linitial(l)
Definition: pg_list.h:195
List * rtable
Definition: parsenodes.h:137
#define ERROR
Definition: elog.h:43
#define NoLock
Definition: lockdefs.h:34
List * exclRelTlist
Definition: primnodes.h:1538
#define RowExclusiveLock
Definition: lockdefs.h:38
AttrNumber resno
Definition: primnodes.h:1408
#define RelationGetRelationName(relation)
Definition: rel.h:462
#define ereport(elevel, rest)
Definition: elog.h:141
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
List * lappend(List *list, void *datum)
Definition: list.c:322
OnConflictAction action
Definition: primnodes.h:1526
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:476
Bitmapset * updatedCols
Definition: parsenodes.h:1121
static Bitmapset * adjust_view_column_set(Bitmapset *cols, List *targetlist)
CmdType commandType
Definition: parsenodes.h:112
List * lcons(void *datum, List *list)
Definition: list.c:454
#define makeNode(_type_)
Definition: nodes.h:573
#define Assert(condition)
Definition: c.h:739
#define lfirst(lc)
Definition: pg_list.h:190
void AddQual(Query *parsetree, Node *qual)
Definition: rewriteManip.c:979
Expr * expr
Definition: primnodes.h:1407
static int list_length(const List *l)
Definition: pg_list.h:169
#define RelationHasCascadedCheckOption(relation)
Definition: rel.h:391
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:736
RTEKind rtekind
Definition: parsenodes.h:974
int errmsg(const char *fmt,...)
Definition: elog.c:822
bool hasSubLinks
Definition: parsenodes.h:128
Query * get_view_query(Relation view)
#define elog(elevel,...)
Definition: elog.h:228
Bitmapset * insertedCols
Definition: parsenodes.h:1120
#define RelationIsSecurityView(relation)
Definition: rel.h:359
TargetEntry * get_tle_by_resno(List *tlist, AttrNumber resno)
List * onConflictSet
Definition: primnodes.h:1535
void ChangeVarNodes(Node *node, int rt_index, int new_index, int sublevels_up)
Definition: rewriteManip.c:610
#define copyObject(obj)
Definition: nodes.h:641
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:87
#define RelationHasCheckOption(relation)
Definition: rel.h:369

◆ rewriteValuesRTE()

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

Definition at line 1261 of file rewriteHandler.c.

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

Referenced by RewriteQuery().

1263 {
1264  List *newValues;
1265  ListCell *lc;
1266  bool isAutoUpdatableView;
1267  bool allReplaced;
1268  int numattrs;
1269  int *attrnos;
1270 
1271  /*
1272  * Rebuilding all the lists is a pretty expensive proposition in a big
1273  * VALUES list, and it's a waste of time if there aren't any DEFAULT
1274  * placeholders. So first scan to see if there are any.
1275  *
1276  * We skip this check if force_nulls is true, because we know that there
1277  * are DEFAULT items present in that case.
1278  */
1279  if (!force_nulls && !searchForDefault(rte))
1280  return true; /* nothing to do */
1281 
1282  /*
1283  * Scan the targetlist for entries referring to the VALUES RTE, and note
1284  * the target attributes. As noted above, we should only need to do this
1285  * for targetlist entries containing simple Vars --- nothing else in the
1286  * VALUES RTE should contain DEFAULT items, and we complain if such a
1287  * thing does occur.
1288  */
1289  numattrs = list_length(linitial(rte->values_lists));
1290  attrnos = (int *) palloc0(numattrs * sizeof(int));
1291 
1292  foreach(lc, parsetree->targetList)
1293  {
1294  TargetEntry *tle = (TargetEntry *) lfirst(lc);
1295 
1296  if (IsA(tle->expr, Var))
1297  {
1298  Var *var = (Var *) tle->expr;
1299 
1300  if (var->varno == rti)
1301  {
1302  int attrno = var->varattno;
1303 
1304  Assert(attrno >= 1 && attrno <= numattrs);
1305  attrnos[attrno - 1] = tle->resno;
1306  }
1307  }
1308  }
1309 
1310  /*
1311  * Check if the target relation is an auto-updatable view, in which case
1312  * unresolved defaults will be left untouched rather than being set to
1313  * NULL. If force_nulls is true, we always set DEFAULT items to NULL, so
1314  * skip this check in that case --- it isn't an auto-updatable view.
1315  */
1316  isAutoUpdatableView = false;
1317  if (!force_nulls &&
1318  target_relation->rd_rel->relkind == RELKIND_VIEW &&
1319  !view_has_instead_trigger(target_relation, CMD_INSERT))
1320  {
1321  List *locks;
1322  bool hasUpdate;
1323  bool found;
1324  ListCell *l;
1325 
1326  /* Look for an unconditional DO INSTEAD rule */
1327  locks = matchLocks(CMD_INSERT, target_relation->rd_rules,
1328  parsetree->resultRelation, parsetree, &hasUpdate);
1329 
1330  found = false;
1331  foreach(l, locks)
1332  {
1333  RewriteRule *rule_lock = (RewriteRule *) lfirst(l);
1334 
1335  if (rule_lock->isInstead &&
1336  rule_lock->qual == NULL)
1337  {
1338  found = true;
1339  break;
1340  }
1341  }
1342 
1343  /*
1344  * If we didn't find an unconditional DO INSTEAD rule, assume that the
1345  * view is auto-updatable. If it isn't, rewriteTargetView() will
1346  * throw an error.
1347  */
1348  if (!found)
1349  isAutoUpdatableView = true;
1350  }
1351 
1352  newValues = NIL;
1353  allReplaced = true;
1354  foreach(lc, rte->values_lists)
1355  {
1356  List *sublist = (List *) lfirst(lc);
1357  List *newList = NIL;
1358  ListCell *lc2;
1359  int i;
1360 
1361  Assert(list_length(sublist) == numattrs);
1362 
1363  i = 0;
1364  foreach(lc2, sublist)
1365  {
1366  Node *col = (Node *) lfirst(lc2);
1367  int attrno = attrnos[i++];
1368 
1369  if (IsA(col, SetToDefault))
1370  {
1371  Form_pg_attribute att_tup;
1372  Node *new_expr;
1373 
1374  if (attrno == 0)
1375  elog(ERROR, "cannot set value in column %d to DEFAULT", i);
1376  att_tup = TupleDescAttr(target_relation->rd_att, attrno - 1);
1377 
1378  if (!force_nulls && !att_tup->attisdropped)
1379  new_expr = build_column_default(target_relation, attrno);
1380  else
1381  new_expr = NULL; /* force a NULL if dropped */
1382 
1383  /*
1384  * If there is no default (ie, default is effectively NULL),
1385  * we've got to explicitly set the column to NULL, unless the
1386  * target relation is an auto-updatable view.
1387  */
1388  if (!new_expr)
1389  {
1390  if (isAutoUpdatableView)
1391  {
1392  /* Leave the value untouched */
1393  newList = lappend(newList, col);
1394  allReplaced = false;
1395  continue;
1396  }
1397 
1398  new_expr = (Node *) makeConst(att_tup->atttypid,
1399  -1,
1400  att_tup->attcollation,
1401  att_tup->attlen,
1402  (Datum) 0,
1403  true, /* isnull */
1404  att_tup->attbyval);
1405  /* this is to catch a NOT NULL domain constraint */
1406  new_expr = coerce_to_domain(new_expr,
1407  InvalidOid, -1,
1408  att_tup->atttypid,
1411  -1,
1412  false);
1413  }
1414  newList = lappend(newList, new_expr);
1415  }
1416  else
1417  newList = lappend(newList, col);
1418  }
1419  newValues = lappend(newValues, newList);
1420  }
1421  rte->values_lists = newValues;
1422 
1423  pfree(attrnos);
1424 
1425  return allReplaced;
1426 }
#define NIL
Definition: pg_list.h:65
Node * qual
Definition: prs2lock.h:28
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
static bool view_has_instead_trigger(Relation view, CmdType event)
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
int resultRelation
Definition: parsenodes.h:122
Definition: nodes.h:525
AttrNumber varattno
Definition: primnodes.h:186
Form_pg_class rd_rel
Definition: rel.h:84
Definition: primnodes.h:181
Const * makeConst(Oid consttype, int32 consttypmod, Oid constcollid, int constlen, Datum constvalue, bool constisnull, bool constbyval)
Definition: makefuncs.c:297
bool isInstead
Definition: prs2lock.h:31
List * values_lists
Definition: parsenodes.h:1072
List * targetList
Definition: parsenodes.h:140
void pfree(void *pointer)
Definition: mcxt.c:1056
#define linitial(l)
Definition: pg_list.h:195
#define ERROR
Definition: elog.h:43
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:663
AttrNumber resno
Definition: primnodes.h:1408
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:200
List * lappend(List *list, void *datum)
Definition: list.c:322
Index varno
Definition: primnodes.h:184
Node * build_column_default(Relation rel, int attrno)
void * palloc0(Size size)
Definition: mcxt.c:980
uintptr_t Datum
Definition: postgres.h:367
TupleDesc rd_att
Definition: rel.h:85
#define InvalidOid
Definition: postgres_ext.h:36
#define Assert(condition)
Definition: c.h:739
#define lfirst(lc)
Definition: pg_list.h:190
Expr * expr
Definition: primnodes.h:1407
RuleLock * rd_rules
Definition: rel.h:88
static int list_length(const List *l)
Definition: pg_list.h:169
#define elog(elevel,...)
Definition: elog.h:228
int i
Definition: pg_list.h:50
static List * matchLocks(CmdType event, RuleLock *rulelocks, int varno, Query *parsetree, bool *hasUpdate)

◆ searchForDefault()

static bool searchForDefault ( RangeTblEntry rte)
static

Definition at line 1203 of file rewriteHandler.c.

References IsA, lfirst, and RangeTblEntry::values_lists.

Referenced by rewriteValuesRTE().

1204 {
1205  ListCell *lc;
1206 
1207  foreach(lc, rte->values_lists)
1208  {
1209  List *sublist = (List *) lfirst(lc);
1210  ListCell *lc2;
1211 
1212  foreach(lc2, sublist)
1213  {
1214  Node *col = (Node *) lfirst(lc2);
1215 
1216  if (IsA(col, SetToDefault))
1217  return true;
1218  }
1219  }
1220  return false;
1221 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
Definition: nodes.h:525
List * values_lists
Definition: parsenodes.h:1072
#define lfirst(lc)
Definition: pg_list.h:190
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 2366 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().

2367 {
2368  Var *var = (Var *) tle->expr;
2369 
2370  /*
2371  * For now, the only updatable columns we support are those that are Vars
2372  * referring to user columns of the underlying base relation.
2373  *
2374  * The view targetlist may contain resjunk columns (e.g., a view defined
2375  * like "SELECT * FROM t ORDER BY a+b" is auto-updatable) but such columns
2376  * are not auto-updatable, and in fact should never appear in the outer
2377  * query's targetlist.
2378  */
2379  if (tle->resjunk)
2380  return gettext_noop("Junk view columns are not updatable.");
2381 
2382  if (!IsA(var, Var) ||
2383  var->varno != rtr->rtindex ||
2384  var->varlevelsup != 0)
2385  return gettext_noop("View columns that are not columns of their base relation are not updatable.");
2386 
2387  if (var->varattno < 0)
2388  return gettext_noop("View columns that refer to system columns are not updatable.");
2389 
2390  if (var->varattno == 0)
2391  return gettext_noop("View columns that return whole-row references are not updatable.");
2392 
2393  return NULL; /* the view column is updatable */
2394 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
Index varlevelsup
Definition: primnodes.h:191
#define gettext_noop(x)
Definition: c.h:1147
AttrNumber varattno
Definition: primnodes.h:186
Definition: primnodes.h:181
bool resjunk
Definition: primnodes.h:1414
Index varno
Definition: primnodes.h:184
Expr * expr
Definition: primnodes.h:1407

◆ 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 2562 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().

2566 {
2567  RangeTblRef *rtr;
2568  AttrNumber col;
2569  ListCell *cell;
2570 
2571  /*
2572  * The caller should have verified that this view is auto-updatable and so
2573  * there should be a single base relation.
2574  */
2575  Assert(list_length(viewquery->jointree->fromlist) == 1);
2576  rtr = linitial_node(RangeTblRef, viewquery->jointree->fromlist);
2577 
2578  /* Initialize the optional return values */
2579  if (updatable_cols != NULL)
2580  *updatable_cols = NULL;
2581  if (non_updatable_col != NULL)
2582  *non_updatable_col = NULL;
2583 
2584  /* Test each view column for updatability */
2586  foreach(cell, viewquery->targetList)
2587  {
2588  TargetEntry *tle = (TargetEntry *) lfirst(cell);
2589  const char *col_update_detail;
2590 
2591  col++;
2592  col_update_detail = view_col_is_auto_updatable(rtr, tle);
2593 
2594  if (col_update_detail == NULL)
2595  {
2596  /* The column is updatable */
2597  if (updatable_cols != NULL)
2598  *updatable_cols = bms_add_member(*updatable_cols, col);
2599  }
2600  else if (bms_is_member(col, required_cols))
2601  {
2602  /* The required column is not updatable */
2603  if (non_updatable_col != NULL)
2604  *non_updatable_col = tle->resname;
2605  return col_update_detail;
2606  }
2607  }
2608 
2609  return NULL; /* all the required view columns are updatable */
2610 }
FromExpr * jointree
Definition: parsenodes.h:138
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
List * fromlist
Definition: primnodes.h:1510
char * resname
Definition: primnodes.h:1409
#define linitial_node(type, l)
Definition: pg_list.h:198
List * targetList
Definition: parsenodes.h:140
#define Assert(condition)
Definition: c.h:739
#define lfirst(lc)
Definition: pg_list.h:190
static int list_length(const List *l)
Definition: pg_list.h:169
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 2328 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().

2329 {
2330  TriggerDesc *trigDesc = view->trigdesc;
2331 
2332  switch (event)
2333  {
2334  case CMD_INSERT:
2335  if (trigDesc && trigDesc->trig_insert_instead_row)
2336  return true;
2337  break;
2338  case CMD_UPDATE:
2339  if (trigDesc && trigDesc->trig_update_instead_row)
2340  return true;
2341  break;
2342  case CMD_DELETE:
2343  if (trigDesc && trigDesc->trig_delete_instead_row)
2344  return true;
2345  break;
2346  default:
2347  elog(ERROR, "unrecognized CmdType: %d", (int) event);
2348  break;
2349  }
2350  return false;
2351 }
bool trig_insert_instead_row
Definition: reltrigger.h:57
#define ERROR
Definition: elog.h:43
TriggerDesc * trigdesc
Definition: rel.h:90
bool trig_update_instead_row
Definition: reltrigger.h:62
bool trig_delete_instead_row
Definition: reltrigger.h:67
#define elog(elevel,...)
Definition: elog.h:228

◆ view_query_is_auto_updatable()

const char* view_query_is_auto_updatable ( Query viewquery,
bool  check_cols 
)

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

2415 {
2416  RangeTblRef *rtr;
2417  RangeTblEntry *base_rte;
2418 
2419  /*----------
2420  * Check if the view is simply updatable. According to SQL-92 this means:
2421  * - No DISTINCT clause.
2422  * - Each TLE is a column reference, and each column appears at most once.
2423  * - FROM contains exactly one base relation.
2424  * - No GROUP BY or HAVING clauses.
2425  * - No set operations (UNION, INTERSECT or EXCEPT).
2426  * - No sub-queries in the WHERE clause that reference the target table.
2427  *
2428  * We ignore that last restriction since it would be complex to enforce
2429  * and there isn't any actual benefit to disallowing sub-queries. (The
2430  * semantic issues that the standard is presumably concerned about don't
2431  * arise in Postgres, since any such sub-query will not see any updates
2432  * executed by the outer query anyway, thanks to MVCC snapshotting.)
2433  *
2434  * We also relax the second restriction by supporting part of SQL:1999
2435  * feature T111, which allows for a mix of updatable and non-updatable
2436  * columns, provided that an INSERT or UPDATE doesn't attempt to assign to
2437  * a non-updatable column.
2438  *
2439  * In addition we impose these constraints, involving features that are
2440  * not part of SQL-92:
2441  * - No CTEs (WITH clauses).
2442  * - No OFFSET or LIMIT clauses (this matches a SQL:2008 restriction).
2443  * - No system columns (including whole-row references) in the tlist.
2444  * - No window functions in the tlist.
2445  * - No set-returning functions in the tlist.
2446  *
2447  * Note that we do these checks without recursively expanding the view.
2448  * If the base relation is a view, we'll recursively deal with it later.
2449  *----------
2450  */
2451  if (viewquery->distinctClause != NIL)
2452  return gettext_noop("Views containing DISTINCT are not automatically updatable.");
2453 
2454  if (viewquery->groupClause != NIL || viewquery->groupingSets)
2455  return gettext_noop("Views containing GROUP BY are not automatically updatable.");
2456 
2457  if (viewquery->havingQual != NULL)
2458  return gettext_noop("Views containing HAVING are not automatically updatable.");
2459 
2460  if (viewquery->setOperations != NULL)
2461  return gettext_noop("Views containing UNION, INTERSECT, or EXCEPT are not automatically updatable.");
2462 
2463  if (viewquery->cteList != NIL)
2464  return gettext_noop("Views containing WITH are not automatically updatable.");
2465 
2466  if (viewquery->limitOffset != NULL || viewquery->limitCount != NULL)
2467  return gettext_noop("Views containing LIMIT or OFFSET are not automatically updatable.");
2468 
2469  /*
2470  * We must not allow window functions or set returning functions in the
2471  * targetlist. Otherwise we might end up inserting them into the quals of
2472  * the main query. We must also check for aggregates in the targetlist in
2473  * case they appear without a GROUP BY.
2474  *
2475  * These restrictions ensure that each row of the view corresponds to a
2476  * unique row in the underlying base relation.
2477  */
2478  if (viewquery->hasAggs)
2479  return gettext_noop("Views that return aggregate functions are not automatically updatable.");
2480 
2481  if (viewquery->hasWindowFuncs)
2482  return gettext_noop("Views that return window functions are not automatically updatable.");
2483 
2484  if (viewquery->hasTargetSRFs)
2485  return gettext_noop("Views that return set-returning functions are not automatically updatable.");
2486 
2487  /*
2488  * The view query should select from a single base relation, which must be
2489  * a table or another view.
2490  */
2491  if (list_length(viewquery->jointree->fromlist) != 1)
2492  return gettext_noop("Views that do not select from a single table or view are not automatically updatable.");
2493 
2494  rtr = (RangeTblRef *) linitial(viewquery->jointree->fromlist);
2495  if (!IsA(rtr, RangeTblRef))
2496  return gettext_noop("Views that do not select from a single table or view are not automatically updatable.");
2497 
2498  base_rte = rt_fetch(rtr->rtindex, viewquery->rtable);
2499  if (base_rte->rtekind != RTE_RELATION ||
2500  (base_rte->relkind != RELKIND_RELATION &&
2501  base_rte->relkind != RELKIND_FOREIGN_TABLE &&
2502  base_rte->relkind != RELKIND_VIEW &&
2503  base_rte->relkind != RELKIND_PARTITIONED_TABLE))
2504  return gettext_noop("Views that do not select from a single table or view are not automatically updatable.");
2505 
2506  if (base_rte->tablesample)
2507  return gettext_noop("Views containing TABLESAMPLE are not automatically updatable.");
2508 
2509  /*
2510  * Check that the view has at least one updatable column. This is required
2511  * for INSERT/UPDATE but not for DELETE.
2512  */
2513  if (check_cols)
2514  {
2515  ListCell *cell;
2516  bool found;
2517 
2518  found = false;
2519  foreach(cell, viewquery->targetList)
2520  {
2521  TargetEntry *tle = (TargetEntry *) lfirst(cell);
2522 
2523  if (view_col_is_auto_updatable(rtr, tle) == NULL)
2524  {
2525  found = true;
2526  break;
2527  }
2528  }
2529 
2530  if (!found)
2531  return gettext_noop("Views that have no updatable columns are not automatically updatable.");
2532  }
2533 
2534  return NULL; /* the view is updatable */
2535 }
Node * limitOffset
Definition: parsenodes.h:160
#define NIL
Definition: pg_list.h:65
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
FromExpr * jointree
Definition: parsenodes.h:138
bool hasAggs
Definition: parsenodes.h:125
List * groupingSets
Definition: parsenodes.h:150
#define gettext_noop(x)
Definition: c.h:1147
List * fromlist
Definition: primnodes.h:1510
List * targetList
Definition: parsenodes.h:140
#define linitial(l)
Definition: pg_list.h:195
List * rtable
Definition: parsenodes.h:137
List * distinctClause
Definition: parsenodes.h:156
Node * limitCount
Definition: parsenodes.h:161
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
bool hasTargetSRFs
Definition: parsenodes.h:127
#define lfirst(lc)
Definition: pg_list.h:190
bool hasWindowFuncs
Definition: parsenodes.h:126
static int list_length(const List *l)
Definition: pg_list.h:169
RTEKind rtekind
Definition: parsenodes.h:974
List * cteList
Definition: parsenodes.h:135
Node * setOperations
Definition: parsenodes.h:165
List * groupClause
Definition: parsenodes.h:148
static const char * view_col_is_auto_updatable(RangeTblRef *rtr, TargetEntry *tle)
Node * havingQual
Definition: parsenodes.h:152
struct TableSampleClause * tablesample
Definition: parsenodes.h:1004