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:580
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:580
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
List * joinaliasvars
Definition: parsenodes.h:1051
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:529
AttrNumber varattno
Definition: primnodes.h:186
Form_pg_class rd_rel
Definition: rel.h:109
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:321
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:482
#define Assert(condition)
Definition: c.h:745
#define lfirst(lc)
Definition: pg_list.h:190
RTEKind rtekind
Definition: parsenodes.h:976
List * cteList
Definition: parsenodes.h:135
Query * subquery
Definition: parsenodes.h:1011
bool hasSubLinks
Definition: parsenodes.h:128
#define elog(elevel,...)
Definition: elog.h:214
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 2828 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().

2829 {
2830  Bitmapset *result = NULL;
2831  int col;
2832 
2833  col = -1;
2834  while ((col = bms_next_member(cols, col)) >= 0)
2835  {
2836  /* bit numbers are offset by FirstLowInvalidHeapAttributeNumber */
2838 
2839  if (attno == InvalidAttrNumber)
2840  {
2841  /*
2842  * There's a whole-row reference to the view. For permissions
2843  * purposes, treat it as a reference to each column available from
2844  * the view. (We should *not* convert this to a whole-row
2845  * reference to the base relation, since the view may not touch
2846  * all columns of the base relation.)
2847  */
2848  ListCell *lc;
2849 
2850  foreach(lc, targetlist)
2851  {
2852  TargetEntry *tle = lfirst_node(TargetEntry, lc);
2853  Var *var;
2854 
2855  if (tle->resjunk)
2856  continue;
2857  var = castNode(Var, tle->expr);
2858  result = bms_add_member(result,
2859  var->varattno - FirstLowInvalidHeapAttributeNumber);
2860  }
2861  }
2862  else
2863  {
2864  /*
2865  * Views do not have system columns, so we do not expect to see
2866  * any other system attnos here. If we do find one, the error
2867  * case will apply.
2868  */
2869  TargetEntry *tle = get_tle_by_resno(targetlist, attno);
2870 
2871  if (tle != NULL && !tle->resjunk && IsA(tle->expr, Var))
2872  {
2873  Var *var = (Var *) tle->expr;
2874 
2875  result = bms_add_member(result,
2876  var->varattno - FirstLowInvalidHeapAttributeNumber);
2877  }
2878  else
2879  elog(ERROR, "attribute number %d not found in view targetlist",
2880  attno);
2881  }
2882  }
2883 
2884  return result;
2885 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:580
#define castNode(_type_, nodeptr)
Definition: nodes.h:598
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:214
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:580
FromExpr * jointree
Definition: parsenodes.h:138
List * fromlist
Definition: primnodes.h:1510
List * list_delete_ptr(List *list, void *datum)
Definition: list.c:796
#define lfirst(lc)
Definition: pg_list.h:190
#define copyObject(obj)
Definition: nodes.h:645
Definition: pg_list.h:50

◆ ApplyRetrieveRule()

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

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

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

◆ build_column_default()

Node* build_column_default ( Relation  rel,
int  attrno 
)

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

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

◆ CopyAndAddInvertedQual()

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

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

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

◆ fireRIRonSubLink()

static bool fireRIRonSubLink ( Node node,
List activeRIRs 
)
static

Definition at line 1830 of file rewriteHandler.c.

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

Referenced by fireRIRrules().

1831 {
1832  if (node == NULL)
1833  return false;
1834  if (IsA(node, SubLink))
1835  {
1836  SubLink *sub = (SubLink *) node;
1837 
1838  /* Do what we came for */
1839  sub->subselect = (Node *) fireRIRrules((Query *) sub->subselect,
1840  activeRIRs);
1841  /* Fall through to process lefthand args of SubLink */
1842  }
1843 
1844  /*
1845  * Do NOT recurse into Query nodes, because fireRIRrules already processed
1846  * subselects of subselects for us.
1847  */
1849  (void *) activeRIRs);
1850 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:580
Definition: nodes.h:529
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 1861 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().

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

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

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

◆ get_assignment_input()

static Node * get_assignment_input ( Node node)
static

Definition at line 1094 of file rewriteHandler.c.

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

Referenced by process_matched_tle().

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

◆ get_view_query()

Query* get_view_query ( Relation  view)

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

2298 {
2299  int i;
2300 
2301  Assert(view->rd_rel->relkind == RELKIND_VIEW);
2302 
2303  for (i = 0; i < view->rd_rules->numLocks; i++)
2304  {
2305  RewriteRule *rule = view->rd_rules->rules[i];
2306 
2307  if (rule->event == CMD_SELECT)
2308  {
2309  /* A _RETURN rule should have only one action */
2310  if (list_length(rule->actions) != 1)
2311  elog(ERROR, "invalid _RETURN rule action specification");
2312 
2313  return (Query *) linitial(rule->actions);
2314  }
2315  }
2316 
2317  elog(ERROR, "failed to find _RETURN rule for view");
2318  return NULL; /* keep compiler quiet */
2319 }
int numLocks
Definition: prs2lock.h:42
Form_pg_class rd_rel
Definition: rel.h:109
Definition: localtime.c:72
#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:745
RuleLock * rd_rules
Definition: rel.h:113
static int list_length(const List *l)
Definition: pg_list.h:169
#define elog(elevel,...)
Definition: elog.h:214
int i

◆ markQueryForLocking()

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

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

1773 {
1774  if (jtnode == NULL)
1775  return;
1776  if (IsA(jtnode, RangeTblRef))
1777  {
1778  int rti = ((RangeTblRef *) jtnode)->rtindex;
1779  RangeTblEntry *rte = rt_fetch(rti, qry->rtable);
1780 
1781  if (rte->rtekind == RTE_RELATION)
1782  {
1783  applyLockingClause(qry, rti, strength, waitPolicy, pushedDown);
1785  }
1786  else if (rte->rtekind == RTE_SUBQUERY)
1787  {
1788  applyLockingClause(qry, rti, strength, waitPolicy, pushedDown);
1789  /* FOR UPDATE/SHARE of subquery is propagated to subquery's rels */
1791  strength, waitPolicy, true);
1792  }
1793  /* other RTE types are unaffected by FOR UPDATE */
1794  }
1795  else if (IsA(jtnode, FromExpr))
1796  {
1797  FromExpr *f = (FromExpr *) jtnode;
1798  ListCell *l;
1799 
1800  foreach(l, f->fromlist)
1801  markQueryForLocking(qry, lfirst(l), strength, waitPolicy, pushedDown);
1802  }
1803  else if (IsA(jtnode, JoinExpr))
1804  {
1805  JoinExpr *j = (JoinExpr *) jtnode;
1806 
1807  markQueryForLocking(qry, j->larg, strength, waitPolicy, pushedDown);
1808  markQueryForLocking(qry, j->rarg, strength, waitPolicy, pushedDown);
1809  }
1810  else
1811  elog(ERROR, "unrecognized node type: %d",
1812  (int) nodeTag(jtnode));
1813 }
static void markQueryForLocking(Query *qry, Node *jtnode, LockClauseStrength strength, LockWaitPolicy waitPolicy, bool pushedDown)
#define IsA(nodeptr, _type_)
Definition: nodes.h:580
FromExpr * jointree
Definition: parsenodes.h:138
Definition: nodes.h:529
AclMode requiredPerms
Definition: parsenodes.h:1119
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:534
RTEKind rtekind
Definition: parsenodes.h:976
Query * subquery
Definition: parsenodes.h:1011
#define elog(elevel,...)
Definition: elog.h:214
void applyLockingClause(Query *qry, Index rtindex, LockClauseStrength strength, LockWaitPolicy waitPolicy, bool pushedDown)
Definition: analyze.c:2944

◆ matchLocks()

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

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

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

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

◆ QueryRewrite()

List* QueryRewrite ( Query parsetree)

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

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

◆ relation_is_updatable()

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

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

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

◆ RewriteQuery()

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

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

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

◆ 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:529
List * list_concat(List *list1, const List *list2)
Definition: list.c:515
int errcode(int sqlerrcode)
Definition: elog.c:610
static List * adjustJoinTreeList(Query *parsetree, bool removert, int rt_index)
List * fromlist
Definition: primnodes.h:1510
List * values_lists
Definition: parsenodes.h:1074
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:1069
void AcquireRewriteLocks(Query *parsetree, bool forExecute, bool forUpdatePushedDown)
List * returningList
Definition: parsenodes.h:146
#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)
#define ereport(elevel,...)
Definition: elog.h:144
CmdType commandType
Definition: parsenodes.h:112
#define Assert(condition)
Definition: c.h:745
#define lfirst(lc)
Definition: pg_list.h:190
List * functions
Definition: parsenodes.h:1063
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:976
List * cteList
Definition: parsenodes.h:135
Node * setOperations
Definition: parsenodes.h:166
int errmsg(const char *fmt,...)
Definition: elog.c:824
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:645
Definition: pg_list.h:50
struct TableSampleClause * tablesample
Definition: parsenodes.h:1006
#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_USER_VALUE)
812  apply_default = true;
813  else if (override != OVERRIDING_SYSTEM_VALUE)
814  ereport(ERROR,
815  (errcode(ERRCODE_GENERATED_ALWAYS),
816  errmsg("cannot insert into column \"%s\"", NameStr(att_tup->attname)),
817  errdetail("Column \"%s\" is an identity column defined as GENERATED ALWAYS.",
818  NameStr(att_tup->attname)),
819  errhint("Use OVERRIDING SYSTEM VALUE to override.")));
820  }
821 
822  if (att_tup->attidentity == ATTRIBUTE_IDENTITY_BY_DEFAULT && override == OVERRIDING_USER_VALUE)
823  apply_default = true;
824 
825  if (att_tup->attgenerated && !apply_default)
826  ereport(ERROR,
827  (errcode(ERRCODE_SYNTAX_ERROR),
828  errmsg("cannot insert into column \"%s\"", NameStr(att_tup->attname)),
829  errdetail("Column \"%s\" is a generated column.",
830  NameStr(att_tup->attname))));
831  }
832 
833  if (commandType == CMD_UPDATE)
834  {
835  if (att_tup->attidentity == ATTRIBUTE_IDENTITY_ALWAYS && new_tle && !apply_default)
836  ereport(ERROR,
837  (errcode(ERRCODE_GENERATED_ALWAYS),
838  errmsg("column \"%s\" can only be updated to DEFAULT", NameStr(att_tup->attname)),
839  errdetail("Column \"%s\" is an identity column defined as GENERATED ALWAYS.",
840  NameStr(att_tup->attname))));
841 
842  if (att_tup->attgenerated && new_tle && !apply_default)
843  ereport(ERROR,
844  (errcode(ERRCODE_SYNTAX_ERROR),
845  errmsg("column \"%s\" can only be updated to DEFAULT", NameStr(att_tup->attname)),
846  errdetail("Column \"%s\" is a generated column.",
847  NameStr(att_tup->attname))));
848  }
849 
850  if (att_tup->attgenerated)
851  {
852  /*
853  * stored generated column will be fixed in executor
854  */
855  new_tle = NULL;
856  }
857  else if (apply_default)
858  {
859  Node *new_expr;
860 
861  new_expr = build_column_default(target_relation, attrno);
862 
863  /*
864  * If there is no default (ie, default is effectively NULL), we
865  * can omit the tlist entry in the INSERT case, since the planner
866  * can insert a NULL for itself, and there's no point in spending
867  * any more rewriter cycles on the entry. But in the UPDATE case
868  * we've got to explicitly set the column to NULL.
869  */
870  if (!new_expr)
871  {
872  if (commandType == CMD_INSERT)
873  new_tle = NULL;
874  else
875  {
876  new_expr = (Node *) makeConst(att_tup->atttypid,
877  -1,
878  att_tup->attcollation,
879  att_tup->attlen,
880  (Datum) 0,
881  true, /* isnull */
882  att_tup->attbyval);
883  /* this is to catch a NOT NULL domain constraint */
884  new_expr = coerce_to_domain(new_expr,
885  InvalidOid, -1,
886  att_tup->atttypid,
889  -1,
890  false);
891  }
892  }
893 
894  if (new_expr)
895  new_tle = makeTargetEntry((Expr *) new_expr,
896  attrno,
897  pstrdup(NameStr(att_tup->attname)),
898  false);
899  }
900 
901  /*
902  * For an UPDATE on a trigger-updatable view, provide a dummy entry
903  * whenever there is no explicit assignment.
904  */
905  if (new_tle == NULL && commandType == CMD_UPDATE &&
906  target_relation->rd_rel->relkind == RELKIND_VIEW &&
907  view_has_instead_trigger(target_relation, CMD_UPDATE))
908  {
909  Node *new_expr;
910 
911  new_expr = (Node *) makeVar(result_rti,
912  attrno,
913  att_tup->atttypid,
914  att_tup->atttypmod,
915  att_tup->attcollation,
916  0);
917 
918  new_tle = makeTargetEntry((Expr *) new_expr,
919  attrno,
920  pstrdup(NameStr(att_tup->attname)),
921  false);
922  }
923 
924  if (new_tle)
925  new_tlist = lappend(new_tlist, new_tle);
926  }
927 
928  pfree(new_tles);
929 
930  return list_concat(new_tlist, junk_tlist);
931 }
#define NIL
Definition: pg_list.h:65
#define IsA(nodeptr, _type_)
Definition: nodes.h:580
int errhint(const char *fmt,...)
Definition: elog.c:1071
static bool view_has_instead_trigger(Relation view, CmdType event)
#define RelationGetNumberOfAttributes(relation)
Definition: rel.h:462
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
char * pstrdup(const char *in)
Definition: mcxt.c:1186
Definition: nodes.h:529
List * list_concat(List *list1, const List *list2)
Definition: list.c:515
int errcode(int sqlerrcode)
Definition: elog.c:610
Form_pg_class rd_rel
Definition: rel.h:109
Const * makeConst(Oid consttype, int32 consttypmod, Oid constcollid, int constlen, Datum constvalue, bool constisnull, bool constbyval)
Definition: makefuncs.c:299
void pfree(void *pointer)
Definition: mcxt.c: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:666
int errdetail(const char *fmt,...)
Definition: elog.c:957
AttrNumber resno
Definition: primnodes.h:1408
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:193
TargetEntry * flatCopyTargetEntry(TargetEntry *src_tle)
Definition: makefuncs.c:271
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:238
Var * makeVar(Index varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:66
List * lappend(List *list, void *datum)
Definition: list.c:321
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:110
#define InvalidOid
Definition: postgres_ext.h:36
#define ereport(elevel,...)
Definition: elog.h:144
#define lfirst(lc)
Definition: pg_list.h:190
Expr * expr
Definition: primnodes.h:1407
int errmsg(const char *fmt,...)
Definition: elog.c:824
static TargetEntry * process_matched_tle(TargetEntry *src_tle, TargetEntry *prior_tle, const char *attrName)
#define elog(elevel,...)
Definition: elog.h:214
#define NameStr(name)
Definition: c.h:622
Definition: pg_list.h:50

◆ rewriteTargetListUD()

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

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

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

◆ rewriteTargetView()

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

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

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

◆ rewriteValuesRTE()

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

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

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

References IsA, lfirst, and RangeTblEntry::values_lists.

Referenced by rewriteValuesRTE().

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

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

2568 {
2569  RangeTblRef *rtr;
2570  AttrNumber col;
2571  ListCell *cell;
2572 
2573  /*
2574  * The caller should have verified that this view is auto-updatable and so
2575  * there should be a single base relation.
2576  */
2577  Assert(list_length(viewquery->jointree->fromlist) == 1);
2578  rtr = linitial_node(RangeTblRef, viewquery->jointree->fromlist);
2579 
2580  /* Initialize the optional return values */
2581  if (updatable_cols != NULL)
2582  *updatable_cols = NULL;
2583  if (non_updatable_col != NULL)
2584  *non_updatable_col = NULL;
2585 
2586  /* Test each view column for updatability */
2588  foreach(cell, viewquery->targetList)
2589  {
2590  TargetEntry *tle = (TargetEntry *) lfirst(cell);
2591  const char *col_update_detail;
2592 
2593  col++;
2594  col_update_detail = view_col_is_auto_updatable(rtr, tle);
2595 
2596  if (col_update_detail == NULL)
2597  {
2598  /* The column is updatable */
2599  if (updatable_cols != NULL)
2600  *updatable_cols = bms_add_member(*updatable_cols, col);
2601  }
2602  else if (bms_is_member(col, required_cols))
2603  {
2604  /* The required column is not updatable */
2605  if (non_updatable_col != NULL)
2606  *non_updatable_col = tle->resname;
2607  return col_update_detail;
2608  }
2609  }
2610 
2611  return NULL; /* all the required view columns are updatable */
2612 }
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:745
#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 2330 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().

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

◆ view_query_is_auto_updatable()

const char* view_query_is_auto_updatable ( Query viewquery,
bool  check_cols 
)

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

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