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 "optimizer/optimizer.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)
 
void fill_extraUpdatedCols (RangeTblEntry *target_rte, Relation target_relation)
 
static QueryApplyRetrieveRule (Query *parsetree, RewriteRule *rule, int rt_index, Relation relation, List *activeRIRs)
 
static bool fireRIRonSubLink (Node *node, List *activeRIRs)
 
static QueryCopyAndAddInvertedQual (Query *parsetree, Node *rule_qual, int rt_index, CmdType event)
 
static ListfireRules (Query *parsetree, int rt_index, CmdType event, List *locks, bool *instead_flag, bool *returning_flag, Query **qual_product)
 
Queryget_view_query (Relation view)
 
static const char * view_col_is_auto_updatable (RangeTblRef *rtr, TargetEntry *tle)
 
const char * view_query_is_auto_updatable (Query *viewquery, bool check_cols)
 
static const char * view_cols_are_auto_updatable (Query *viewquery, Bitmapset *required_cols, Bitmapset **updatable_cols, char **non_updatable_col)
 
int relation_is_updatable (Oid reloid, List *outer_reloids, bool include_triggers, Bitmapset *include_cols)
 
static QueryrewriteTargetView (Query *parsetree, Relation view)
 
static ListRewriteQuery (Query *parsetree, List *rewrite_events)
 
ListQueryRewrite (Query *parsetree)
 

Macro Definition Documentation

◆ ALL_EVENTS

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

Referenced by relation_is_updatable().

Typedef Documentation

◆ acquireLocksOnSubLinks_context

◆ rewrite_event

typedef struct rewrite_event rewrite_event

Function Documentation

◆ acquireLocksOnSubLinks()

static bool acquireLocksOnSubLinks ( Node node,
acquireLocksOnSubLinks_context context 
)
static

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

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

◆ AcquireRewriteLocks()

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

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

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

◆ adjust_view_column_set()

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

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

2863 {
2864  Bitmapset *result = NULL;
2865  int col;
2866 
2867  col = -1;
2868  while ((col = bms_next_member(cols, col)) >= 0)
2869  {
2870  /* bit numbers are offset by FirstLowInvalidHeapAttributeNumber */
2872 
2873  if (attno == InvalidAttrNumber)
2874  {
2875  /*
2876  * There's a whole-row reference to the view. For permissions
2877  * purposes, treat it as a reference to each column available from
2878  * the view. (We should *not* convert this to a whole-row
2879  * reference to the base relation, since the view may not touch
2880  * all columns of the base relation.)
2881  */
2882  ListCell *lc;
2883 
2884  foreach(lc, targetlist)
2885  {
2886  TargetEntry *tle = lfirst_node(TargetEntry, lc);
2887  Var *var;
2888 
2889  if (tle->resjunk)
2890  continue;
2891  var = castNode(Var, tle->expr);
2892  result = bms_add_member(result,
2893  var->varattno - FirstLowInvalidHeapAttributeNumber);
2894  }
2895  }
2896  else
2897  {
2898  /*
2899  * Views do not have system columns, so we do not expect to see
2900  * any other system attnos here. If we do find one, the error
2901  * case will apply.
2902  */
2903  TargetEntry *tle = get_tle_by_resno(targetlist, attno);
2904 
2905  if (tle != NULL && !tle->resjunk && IsA(tle->expr, Var))
2906  {
2907  Var *var = (Var *) tle->expr;
2908 
2909  result = bms_add_member(result,
2910  var->varattno - FirstLowInvalidHeapAttributeNumber);
2911  }
2912  else
2913  elog(ERROR, "attribute number %d not found in view targetlist",
2914  attno);
2915  }
2916  }
2917 
2918  return result;
2919 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:579
#define castNode(_type_, nodeptr)
Definition: nodes.h:597
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:1417
#define ERROR
Definition: elog.h:43
#define lfirst_node(type, lc)
Definition: pg_list.h:172
Expr * expr
Definition: primnodes.h:1410
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 640 of file rewriteHandler.c.

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

Referenced by rewriteRuleAction().

641 {
642  List *newjointree = copyObject(parsetree->jointree->fromlist);
643  ListCell *l;
644 
645  if (removert)
646  {
647  foreach(l, newjointree)
648  {
649  RangeTblRef *rtr = lfirst(l);
650 
651  if (IsA(rtr, RangeTblRef) &&
652  rtr->rtindex == rt_index)
653  {
654  newjointree = foreach_delete_current(newjointree, l);
655  break;
656  }
657  }
658  }
659  return newjointree;
660 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:579
FromExpr * jointree
Definition: parsenodes.h:138
List * fromlist
Definition: primnodes.h:1513
#define foreach_delete_current(lst, cell)
Definition: pg_list.h:357
#define lfirst(lc)
Definition: pg_list.h:169
#define copyObject(obj)
Definition: nodes.h:644
Definition: pg_list.h:50

◆ ApplyRetrieveRule()

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

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

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

◆ build_column_default()

Node* build_column_default ( Relation  rel,
int  attrno 
)

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

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

2174 {
2175  /* Don't scribble on the passed qual (it's in the relcache!) */
2176  Node *new_qual = copyObject(rule_qual);
2178 
2179  context.for_execute = true;
2180 
2181  /*
2182  * In case there are subqueries in the qual, acquire necessary locks and
2183  * fix any deleted JOIN RTE entries. (This is somewhat redundant with
2184  * rewriteRuleAction, but not entirely ... consider restructuring so that
2185  * we only need to process the qual this way once.)
2186  */
2187  (void) acquireLocksOnSubLinks(new_qual, &context);
2188 
2189  /* Fix references to OLD */
2190  ChangeVarNodes(new_qual, PRS2_OLD_VARNO, rt_index, 0);
2191  /* Fix references to NEW */
2192  if (event == CMD_INSERT || event == CMD_UPDATE)
2193  new_qual = ReplaceVarsFromTargetList(new_qual,
2195  0,
2196  rt_fetch(rt_index,
2197  parsetree->rtable),
2198  parsetree->targetList,
2199  (event == CMD_UPDATE) ?
2202  rt_index,
2203  &parsetree->hasSubLinks);
2204  /* And attach the fixed qual */
2205  AddInvertedQual(parsetree, new_qual);
2206 
2207  return parsetree;
2208 }
static bool acquireLocksOnSubLinks(Node *node, acquireLocksOnSubLinks_context *context)
void AddInvertedQual(Query *parsetree, Node *qual)
Definition: nodes.h:528
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:644
#define PRS2_NEW_VARNO
Definition: primnodes.h:179

◆ fill_extraUpdatedCols()

void fill_extraUpdatedCols ( RangeTblEntry target_rte,
Relation  target_relation 
)

Definition at line 1517 of file rewriteHandler.c.

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

Referenced by apply_handle_update(), and RewriteQuery().

1518 {
1519  TupleDesc tupdesc = RelationGetDescr(target_relation);
1520  TupleConstr *constr = tupdesc->constr;
1521 
1522  target_rte->extraUpdatedCols = NULL;
1523 
1524  if (constr && constr->has_generated_stored)
1525  {
1526  for (int i = 0; i < constr->num_defval; i++)
1527  {
1528  AttrDefault *defval = &constr->defval[i];
1529  Node *expr;
1530  Bitmapset *attrs_used = NULL;
1531 
1532  /* skip if not generated column */
1533  if (!TupleDescAttr(tupdesc, defval->adnum - 1)->attgenerated)
1534  continue;
1535 
1536  /* identify columns this generated column depends on */
1537  expr = stringToNode(defval->adbin);
1538  pull_varattnos(expr, 1, &attrs_used);
1539 
1540  if (bms_overlap(target_rte->updatedCols, attrs_used))
1541  target_rte->extraUpdatedCols =
1542  bms_add_member(target_rte->extraUpdatedCols,
1544  }
1545  }
1546 }
#define RelationGetDescr(relation)
Definition: rel.h:482
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
Definition: nodes.h:528
void * stringToNode(const char *str)
Definition: read.c:89
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
void pull_varattnos(Node *node, Index varno, Bitmapset **varattnos)
Definition: var.c:219
AttrDefault * defval
Definition: tupdesc.h:39
bool has_generated_stored
Definition: tupdesc.h:45
Bitmapset * extraUpdatedCols
Definition: parsenodes.h:1129
TupleConstr * constr
Definition: tupdesc.h:85
Bitmapset * updatedCols
Definition: parsenodes.h:1128
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:736
bool bms_overlap(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:494
uint16 num_defval
Definition: tupdesc.h:42
int i
AttrNumber adnum
Definition: tupdesc.h:24
char * adbin
Definition: tupdesc.h:25

◆ fireRIRonSubLink()

static bool fireRIRonSubLink ( Node node,
List activeRIRs 
)
static

Definition at line 1864 of file rewriteHandler.c.

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

Referenced by fireRIRrules().

1865 {
1866  if (node == NULL)
1867  return false;
1868  if (IsA(node, SubLink))
1869  {
1870  SubLink *sub = (SubLink *) node;
1871 
1872  /* Do what we came for */
1873  sub->subselect = (Node *) fireRIRrules((Query *) sub->subselect,
1874  activeRIRs);
1875  /* Fall through to process lefthand args of SubLink */
1876  }
1877 
1878  /*
1879  * Do NOT recurse into Query nodes, because fireRIRrules already processed
1880  * subselects of subselects for us.
1881  */
1883  (void *) activeRIRs);
1884 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:579
Definition: nodes.h:528
static bool fireRIRonSubLink(Node *node, List *activeRIRs)
bool expression_tree_walker(Node *node, bool(*walker)(), void *context)
Definition: nodeFuncs.c:1888
static Query * fireRIRrules(Query *parsetree, List *activeRIRs)

◆ fireRIRrules()

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

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

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

2247 {
2248  List *results = NIL;
2249  ListCell *l;
2250 
2251  foreach(l, locks)
2252  {
2253  RewriteRule *rule_lock = (RewriteRule *) lfirst(l);
2254  Node *event_qual = rule_lock->qual;
2255  List *actions = rule_lock->actions;
2256  QuerySource qsrc;
2257  ListCell *r;
2258 
2259  /* Determine correct QuerySource value for actions */
2260  if (rule_lock->isInstead)
2261  {
2262  if (event_qual != NULL)
2263  qsrc = QSRC_QUAL_INSTEAD_RULE;
2264  else
2265  {
2266  qsrc = QSRC_INSTEAD_RULE;
2267  *instead_flag = true; /* report unqualified INSTEAD */
2268  }
2269  }
2270  else
2271  qsrc = QSRC_NON_INSTEAD_RULE;
2272 
2273  if (qsrc == QSRC_QUAL_INSTEAD_RULE)
2274  {
2275  /*
2276  * If there are INSTEAD rules with qualifications, the original
2277  * query is still performed. But all the negated rule
2278  * qualifications of the INSTEAD rules are added so it does its
2279  * actions only in cases where the rule quals of all INSTEAD rules
2280  * are false. Think of it as the default action in a case. We save
2281  * this in *qual_product so RewriteQuery() can add it to the query
2282  * list after we mangled it up enough.
2283  *
2284  * If we have already found an unqualified INSTEAD rule, then
2285  * *qual_product won't be used, so don't bother building it.
2286  */
2287  if (!*instead_flag)
2288  {
2289  if (*qual_product == NULL)
2290  *qual_product = copyObject(parsetree);
2291  *qual_product = CopyAndAddInvertedQual(*qual_product,
2292  event_qual,
2293  rt_index,
2294  event);
2295  }
2296  }
2297 
2298  /* Now process the rule's actions and add them to the result list */
2299  foreach(r, actions)
2300  {
2301  Query *rule_action = lfirst(r);
2302 
2303  if (rule_action->commandType == CMD_NOTHING)
2304  continue;
2305 
2306  rule_action = rewriteRuleAction(parsetree, rule_action,
2307  event_qual, rt_index, event,
2308  returning_flag);
2309 
2310  rule_action->querySource = qsrc;
2311  rule_action->canSetTag = false; /* might change later */
2312 
2313  results = lappend(results, rule_action);
2314  }
2315  }
2316 
2317  return results;
2318 }
#define NIL
Definition: pg_list.h:65
Node * qual
Definition: prs2lock.h:28
QuerySource
Definition: parsenodes.h:40
Definition: nodes.h:528
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:169
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:644
Definition: pg_list.h:50

◆ get_assignment_input()

static Node * get_assignment_input ( Node node)
static

Definition at line 1091 of file rewriteHandler.c.

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

Referenced by process_matched_tle().

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

◆ get_view_query()

Query* get_view_query ( Relation  view)

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

2332 {
2333  int i;
2334 
2335  Assert(view->rd_rel->relkind == RELKIND_VIEW);
2336 
2337  for (i = 0; i < view->rd_rules->numLocks; i++)
2338  {
2339  RewriteRule *rule = view->rd_rules->rules[i];
2340 
2341  if (rule->event == CMD_SELECT)
2342  {
2343  /* A _RETURN rule should have only one action */
2344  if (list_length(rule->actions) != 1)
2345  elog(ERROR, "invalid _RETURN rule action specification");
2346 
2347  return (Query *) linitial(rule->actions);
2348  }
2349  }
2350 
2351  elog(ERROR, "failed to find _RETURN rule for view");
2352  return NULL; /* keep compiler quiet */
2353 }
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:174
#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:746
RuleLock * rd_rules
Definition: rel.h:113
static int list_length(const List *l)
Definition: pg_list.h:149
#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 1804 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().

1807 {
1808  if (jtnode == NULL)
1809  return;
1810  if (IsA(jtnode, RangeTblRef))
1811  {
1812  int rti = ((RangeTblRef *) jtnode)->rtindex;
1813  RangeTblEntry *rte = rt_fetch(rti, qry->rtable);
1814 
1815  if (rte->rtekind == RTE_RELATION)
1816  {
1817  applyLockingClause(qry, rti, strength, waitPolicy, pushedDown);
1819  }
1820  else if (rte->rtekind == RTE_SUBQUERY)
1821  {
1822  applyLockingClause(qry, rti, strength, waitPolicy, pushedDown);
1823  /* FOR UPDATE/SHARE of subquery is propagated to subquery's rels */
1825  strength, waitPolicy, true);
1826  }
1827  /* other RTE types are unaffected by FOR UPDATE */
1828  }
1829  else if (IsA(jtnode, FromExpr))
1830  {
1831  FromExpr *f = (FromExpr *) jtnode;
1832  ListCell *l;
1833 
1834  foreach(l, f->fromlist)
1835  markQueryForLocking(qry, lfirst(l), strength, waitPolicy, pushedDown);
1836  }
1837  else if (IsA(jtnode, JoinExpr))
1838  {
1839  JoinExpr *j = (JoinExpr *) jtnode;
1840 
1841  markQueryForLocking(qry, j->larg, strength, waitPolicy, pushedDown);
1842  markQueryForLocking(qry, j->rarg, strength, waitPolicy, pushedDown);
1843  }
1844  else
1845  elog(ERROR, "unrecognized node type: %d",
1846  (int) nodeTag(jtnode));
1847 }
static void markQueryForLocking(Query *qry, Node *jtnode, LockClauseStrength strength, LockWaitPolicy waitPolicy, bool pushedDown)
#define IsA(nodeptr, _type_)
Definition: nodes.h:579
FromExpr * jointree
Definition: parsenodes.h:138
Definition: nodes.h:528
AclMode requiredPerms
Definition: parsenodes.h:1124
List * fromlist
Definition: primnodes.h:1513
Node * larg
Definition: primnodes.h:1493
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:1494
#define lfirst(lc)
Definition: pg_list.h:169
#define ACL_SELECT_FOR_UPDATE
Definition: parsenodes.h:90
#define nodeTag(nodeptr)
Definition: nodes.h:533
RTEKind rtekind
Definition: parsenodes.h:981
Query * subquery
Definition: parsenodes.h:1016
#define elog(elevel,...)
Definition: elog.h:214
void applyLockingClause(Query *qry, Index rtindex, LockClauseStrength strength, LockWaitPolicy waitPolicy, bool pushedDown)
Definition: analyze.c:2897

◆ matchLocks()

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

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

1559 {
1560  List *matching_locks = NIL;
1561  int nlocks;
1562  int i;
1563 
1564  if (rulelocks == NULL)
1565  return NIL;
1566 
1567  if (parsetree->commandType != CMD_SELECT)
1568  {
1569  if (parsetree->resultRelation != varno)
1570  return NIL;
1571  }
1572 
1573  nlocks = rulelocks->numLocks;
1574 
1575  for (i = 0; i < nlocks; i++)
1576  {
1577  RewriteRule *oneLock = rulelocks->rules[i];
1578 
1579  if (oneLock->event == CMD_UPDATE)
1580  *hasUpdate = true;
1581 
1582  /*
1583  * Suppress ON INSERT/UPDATE/DELETE rules that are disabled or
1584  * configured to not fire during the current sessions replication
1585  * role. ON SELECT rules will always be applied in order to keep views
1586  * working even in LOCAL or REPLICA role.
1587  */
1588  if (oneLock->event != CMD_SELECT)
1589  {
1591  {
1592  if (oneLock->enabled == RULE_FIRES_ON_ORIGIN ||
1593  oneLock->enabled == RULE_DISABLED)
1594  continue;
1595  }
1596  else /* ORIGIN or LOCAL ROLE */
1597  {
1598  if (oneLock->enabled == RULE_FIRES_ON_REPLICA ||
1599  oneLock->enabled == RULE_DISABLED)
1600  continue;
1601  }
1602  }
1603 
1604  if (oneLock->event == event)
1605  {
1606  if (parsetree->commandType != CMD_SELECT ||
1607  rangeTableEntry_used((Node *) parsetree, varno, 0))
1608  matching_locks = lappend(matching_locks, oneLock);
1609  }
1610  }
1611 
1612  return matching_locks;
1613 }
#define NIL
Definition: pg_list.h:65
int numLocks
Definition: prs2lock.h:42
int resultRelation
Definition: parsenodes.h:122
Definition: nodes.h:528
int SessionReplicationRole
Definition: trigger.c:68
CmdType event
Definition: prs2lock.h:27
RewriteRule ** rules
Definition: prs2lock.h:43
#define RULE_DISABLED
Definition: rewriteDefine.h:24
List * lappend(List *list, void *datum)
Definition: list.c:321
#define RULE_FIRES_ON_ORIGIN
Definition: rewriteDefine.h:21
#define SESSION_REPLICATION_ROLE_REPLICA
Definition: trigger.h:140
#define RULE_FIRES_ON_REPLICA
Definition: rewriteDefine.h:23
CmdType commandType
Definition: parsenodes.h: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 938 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().

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

◆ QueryRewrite()

List* QueryRewrite ( Query parsetree)

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

3965 {
3966  uint64 input_query_id = parsetree->queryId;
3967  List *querylist;
3968  List *results;
3969  ListCell *l;
3970  CmdType origCmdType;
3971  bool foundOriginalQuery;
3972  Query *lastInstead;
3973 
3974  /*
3975  * This function is only applied to top-level original queries
3976  */
3977  Assert(parsetree->querySource == QSRC_ORIGINAL);
3978  Assert(parsetree->canSetTag);
3979 
3980  /*
3981  * Step 1
3982  *
3983  * Apply all non-SELECT rules possibly getting 0 or many queries
3984  */
3985  querylist = RewriteQuery(parsetree, NIL);
3986 
3987  /*
3988  * Step 2
3989  *
3990  * Apply all the RIR rules on each query
3991  *
3992  * This is also a handy place to mark each query with the original queryId
3993  */
3994  results = NIL;
3995  foreach(l, querylist)
3996  {
3997  Query *query = (Query *) lfirst(l);
3998 
3999  query = fireRIRrules(query, NIL);
4000 
4001  query->queryId = input_query_id;
4002 
4003  results = lappend(results, query);
4004  }
4005 
4006  /*
4007  * Step 3
4008  *
4009  * Determine which, if any, of the resulting queries is supposed to set
4010  * the command-result tag; and update the canSetTag fields accordingly.
4011  *
4012  * If the original query is still in the list, it sets the command tag.
4013  * Otherwise, the last INSTEAD query of the same kind as the original is
4014  * allowed to set the tag. (Note these rules can leave us with no query
4015  * setting the tag. The tcop code has to cope with this by setting up a
4016  * default tag based on the original un-rewritten query.)
4017  *
4018  * The Asserts verify that at most one query in the result list is marked
4019  * canSetTag. If we aren't checking asserts, we can fall out of the loop
4020  * as soon as we find the original query.
4021  */
4022  origCmdType = parsetree->commandType;
4023  foundOriginalQuery = false;
4024  lastInstead = NULL;
4025 
4026  foreach(l, results)
4027  {
4028  Query *query = (Query *) lfirst(l);
4029 
4030  if (query->querySource == QSRC_ORIGINAL)
4031  {
4032  Assert(query->canSetTag);
4033  Assert(!foundOriginalQuery);
4034  foundOriginalQuery = true;
4035 #ifndef USE_ASSERT_CHECKING
4036  break;
4037 #endif
4038  }
4039  else
4040  {
4041  Assert(!query->canSetTag);
4042  if (query->commandType == origCmdType &&
4043  (query->querySource == QSRC_INSTEAD_RULE ||
4045  lastInstead = query;
4046  }
4047  }
4048 
4049  if (!foundOriginalQuery && lastInstead != NULL)
4050  lastInstead->canSetTag = true;
4051 
4052  return results;
4053 }
#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:746
#define lfirst(lc)
Definition: pg_list.h:169
bool canSetTag
Definition: parsenodes.h:118
static Query * fireRIRrules(Query *parsetree, List *activeRIRs)
Definition: pg_list.h:50
CmdType
Definition: nodes.h:671

◆ relation_is_updatable()

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

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

2685 {
2686  int events = 0;
2687  Relation rel;
2688  RuleLock *rulelocks;
2689 
2690 #define ALL_EVENTS ((1 << CMD_INSERT) | (1 << CMD_UPDATE) | (1 << CMD_DELETE))
2691 
2692  /* Since this function recurses, it could be driven to stack overflow */
2694 
2695  rel = try_relation_open(reloid, AccessShareLock);
2696 
2697  /*
2698  * If the relation doesn't exist, return zero rather than throwing an
2699  * error. This is helpful since scanning an information_schema view under
2700  * MVCC rules can result in referencing rels that have actually been
2701  * deleted already.
2702  */
2703  if (rel == NULL)
2704  return 0;
2705 
2706  /* If we detect a recursive view, report that it is not updatable */
2707  if (list_member_oid(outer_reloids, RelationGetRelid(rel)))
2708  {
2710  return 0;
2711  }
2712 
2713  /* If the relation is a table, it is always updatable */
2714  if (rel->rd_rel->relkind == RELKIND_RELATION ||
2715  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
2716  {
2718  return ALL_EVENTS;
2719  }
2720 
2721  /* Look for unconditional DO INSTEAD rules, and note supported events */
2722  rulelocks = rel->rd_rules;
2723  if (rulelocks != NULL)
2724  {
2725  int i;
2726 
2727  for (i = 0; i < rulelocks->numLocks; i++)
2728  {
2729  if (rulelocks->rules[i]->isInstead &&
2730  rulelocks->rules[i]->qual == NULL)
2731  {
2732  events |= ((1 << rulelocks->rules[i]->event) & ALL_EVENTS);
2733  }
2734  }
2735 
2736  /* If we have rules for all events, we're done */
2737  if (events == ALL_EVENTS)
2738  {
2740  return events;
2741  }
2742  }
2743 
2744  /* Similarly look for INSTEAD OF triggers, if they are to be included */
2745  if (include_triggers)
2746  {
2747  TriggerDesc *trigDesc = rel->trigdesc;
2748 
2749  if (trigDesc)
2750  {
2751  if (trigDesc->trig_insert_instead_row)
2752  events |= (1 << CMD_INSERT);
2753  if (trigDesc->trig_update_instead_row)
2754  events |= (1 << CMD_UPDATE);
2755  if (trigDesc->trig_delete_instead_row)
2756  events |= (1 << CMD_DELETE);
2757 
2758  /* If we have triggers for all events, we're done */
2759  if (events == ALL_EVENTS)
2760  {
2762  return events;
2763  }
2764  }
2765  }
2766 
2767  /* If this is a foreign table, check which update events it supports */
2768  if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
2769  {
2770  FdwRoutine *fdwroutine = GetFdwRoutineForRelation(rel, false);
2771 
2772  if (fdwroutine->IsForeignRelUpdatable != NULL)
2773  events |= fdwroutine->IsForeignRelUpdatable(rel);
2774  else
2775  {
2776  /* Assume presence of executor functions is sufficient */
2777  if (fdwroutine->ExecForeignInsert != NULL)
2778  events |= (1 << CMD_INSERT);
2779  if (fdwroutine->ExecForeignUpdate != NULL)
2780  events |= (1 << CMD_UPDATE);
2781  if (fdwroutine->ExecForeignDelete != NULL)
2782  events |= (1 << CMD_DELETE);
2783  }
2784 
2786  return events;
2787  }
2788 
2789  /* Check if this is an automatically updatable view */
2790  if (rel->rd_rel->relkind == RELKIND_VIEW)
2791  {
2792  Query *viewquery = get_view_query(rel);
2793 
2794  if (view_query_is_auto_updatable(viewquery, false) == NULL)
2795  {
2796  Bitmapset *updatable_cols;
2797  int auto_events;
2798  RangeTblRef *rtr;
2799  RangeTblEntry *base_rte;
2800  Oid baseoid;
2801 
2802  /*
2803  * Determine which of the view's columns are updatable. If there
2804  * are none within the set of columns we are looking at, then the
2805  * view doesn't support INSERT/UPDATE, but it may still support
2806  * DELETE.
2807  */
2808  view_cols_are_auto_updatable(viewquery, NULL,
2809  &updatable_cols, NULL);
2810 
2811  if (include_cols != NULL)
2812  updatable_cols = bms_int_members(updatable_cols, include_cols);
2813 
2814  if (bms_is_empty(updatable_cols))
2815  auto_events = (1 << CMD_DELETE); /* May support DELETE */
2816  else
2817  auto_events = ALL_EVENTS; /* May support all events */
2818 
2819  /*
2820  * The base relation must also support these update commands.
2821  * Tables are always updatable, but for any other kind of base
2822  * relation we must do a recursive check limited to the columns
2823  * referenced by the locally updatable columns in this view.
2824  */
2825  rtr = (RangeTblRef *) linitial(viewquery->jointree->fromlist);
2826  base_rte = rt_fetch(rtr->rtindex, viewquery->rtable);
2827  Assert(base_rte->rtekind == RTE_RELATION);
2828 
2829  if (base_rte->relkind != RELKIND_RELATION &&
2830  base_rte->relkind != RELKIND_PARTITIONED_TABLE)
2831  {
2832  baseoid = base_rte->relid;
2833  outer_reloids = lappend_oid(outer_reloids,
2834  RelationGetRelid(rel));
2835  include_cols = adjust_view_column_set(updatable_cols,
2836  viewquery->targetList);
2837  auto_events &= relation_is_updatable(baseoid,
2838  outer_reloids,
2839  include_triggers,
2840  include_cols);
2841  outer_reloids = list_delete_last(outer_reloids);
2842  }
2843  events |= auto_events;
2844  }
2845  }
2846 
2847  /* If we reach here, the relation may support some update commands */
2849  return events;
2850 }
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:1513
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:174
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:746
RuleLock * rd_rules
Definition: rel.h:113
RTEKind rtekind
Definition: parsenodes.h:981
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 3487 of file rewriteHandler.c.

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

Referenced by QueryRewrite().

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

◆ rewriteRuleAction()

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

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

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

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

◆ rewriteTargetListUD()

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

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

1445 {
1446  Var *var = NULL;
1447  const char *attrname;
1448  TargetEntry *tle;
1449 
1450  if (target_relation->rd_rel->relkind == RELKIND_RELATION ||
1451  target_relation->rd_rel->relkind == RELKIND_MATVIEW ||
1452  target_relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1453  {
1454  /*
1455  * Emit CTID so that executor can find the row to update or delete.
1456  */
1457  var = makeVar(parsetree->resultRelation,
1459  TIDOID,
1460  -1,
1461  InvalidOid,
1462  0);
1463 
1464  attrname = "ctid";
1465  }
1466  else if (target_relation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
1467  {
1468  /*
1469  * Let the foreign table's FDW add whatever junk TLEs it wants.
1470  */
1471  FdwRoutine *fdwroutine;
1472 
1473  fdwroutine = GetFdwRoutineForRelation(target_relation, false);
1474 
1475  if (fdwroutine->AddForeignUpdateTargets != NULL)
1476  fdwroutine->AddForeignUpdateTargets(parsetree, target_rte,
1477  target_relation);
1478 
1479  /*
1480  * If we have a row-level trigger corresponding to the operation, emit
1481  * a whole-row Var so that executor will have the "old" row to pass to
1482  * the trigger. Alas, this misses system columns.
1483  */
1484  if (target_relation->trigdesc &&
1485  ((parsetree->commandType == CMD_UPDATE &&
1486  (target_relation->trigdesc->trig_update_after_row ||
1487  target_relation->trigdesc->trig_update_before_row)) ||
1488  (parsetree->commandType == CMD_DELETE &&
1489  (target_relation->trigdesc->trig_delete_after_row ||
1490  target_relation->trigdesc->trig_delete_before_row))))
1491  {
1492  var = makeWholeRowVar(target_rte,
1493  parsetree->resultRelation,
1494  0,
1495  false);
1496 
1497  attrname = "wholerow";
1498  }
1499  }
1500 
1501  if (var != NULL)
1502  {
1503  tle = makeTargetEntry((Expr *) var,
1504  list_length(parsetree->targetList) + 1,
1505  pstrdup(attrname),
1506  true);
1507 
1508  parsetree->targetList = lappend(parsetree->targetList, tle);
1509  }
1510 }
char * pstrdup(const char *in)
Definition: mcxt.c:1187
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:149
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 2932 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().

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

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

References IsA, lfirst, and RangeTblEntry::values_lists.

Referenced by rewriteValuesRTE().

1203 {
1204  ListCell *lc;
1205 
1206  foreach(lc, rte->values_lists)
1207  {
1208  List *sublist = (List *) lfirst(lc);
1209  ListCell *lc2;
1210 
1211  foreach(lc2, sublist)
1212  {
1213  Node *col = (Node *) lfirst(lc2);
1214 
1215  if (IsA(col, SetToDefault))
1216  return true;
1217  }
1218  }
1219  return false;
1220 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:579
Definition: nodes.h:528
List * values_lists
Definition: parsenodes.h:1079
#define lfirst(lc)
Definition: pg_list.h:169
Definition: pg_list.h:50

◆ view_col_is_auto_updatable()

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

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

2403 {
2404  Var *var = (Var *) tle->expr;
2405 
2406  /*
2407  * For now, the only updatable columns we support are those that are Vars
2408  * referring to user columns of the underlying base relation.
2409  *
2410  * The view targetlist may contain resjunk columns (e.g., a view defined
2411  * like "SELECT * FROM t ORDER BY a+b" is auto-updatable) but such columns
2412  * are not auto-updatable, and in fact should never appear in the outer
2413  * query's targetlist.
2414  */
2415  if (tle->resjunk)
2416  return gettext_noop("Junk view columns are not updatable.");
2417 
2418  if (!IsA(var, Var) ||
2419  var->varno != rtr->rtindex ||
2420  var->varlevelsup != 0)
2421  return gettext_noop("View columns that are not columns of their base relation are not updatable.");
2422 
2423  if (var->varattno < 0)
2424  return gettext_noop("View columns that refer to system columns are not updatable.");
2425 
2426  if (var->varattno == 0)
2427  return gettext_noop("View columns that return whole-row references are not updatable.");
2428 
2429  return NULL; /* the view column is updatable */
2430 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:579
Index varlevelsup
Definition: primnodes.h:191
#define gettext_noop(x)
Definition: c.h:1139
AttrNumber varattno
Definition: primnodes.h:186
Definition: primnodes.h:181
bool resjunk
Definition: primnodes.h:1417
Index varno
Definition: primnodes.h:184
Expr * expr
Definition: primnodes.h:1410

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

2602 {
2603  RangeTblRef *rtr;
2604  AttrNumber col;
2605  ListCell *cell;
2606 
2607  /*
2608  * The caller should have verified that this view is auto-updatable and so
2609  * there should be a single base relation.
2610  */
2611  Assert(list_length(viewquery->jointree->fromlist) == 1);
2612  rtr = linitial_node(RangeTblRef, viewquery->jointree->fromlist);
2613 
2614  /* Initialize the optional return values */
2615  if (updatable_cols != NULL)
2616  *updatable_cols = NULL;
2617  if (non_updatable_col != NULL)
2618  *non_updatable_col = NULL;
2619 
2620  /* Test each view column for updatability */
2622  foreach(cell, viewquery->targetList)
2623  {
2624  TargetEntry *tle = (TargetEntry *) lfirst(cell);
2625  const char *col_update_detail;
2626 
2627  col++;
2628  col_update_detail = view_col_is_auto_updatable(rtr, tle);
2629 
2630  if (col_update_detail == NULL)
2631  {
2632  /* The column is updatable */
2633  if (updatable_cols != NULL)
2634  *updatable_cols = bms_add_member(*updatable_cols, col);
2635  }
2636  else if (bms_is_member(col, required_cols))
2637  {
2638  /* The required column is not updatable */
2639  if (non_updatable_col != NULL)
2640  *non_updatable_col = tle->resname;
2641  return col_update_detail;
2642  }
2643  }
2644 
2645  return NULL; /* all the required view columns are updatable */
2646 }
FromExpr * jointree
Definition: parsenodes.h:138
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
List * fromlist
Definition: primnodes.h:1513
char * resname
Definition: primnodes.h:1412
#define linitial_node(type, l)
Definition: pg_list.h:177
List * targetList
Definition: parsenodes.h:140
#define Assert(condition)
Definition: c.h:746
#define lfirst(lc)
Definition: pg_list.h:169
static int list_length(const List *l)
Definition: pg_list.h:149
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:736
static const char * view_col_is_auto_updatable(RangeTblRef *rtr, TargetEntry *tle)
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:427
int16 AttrNumber
Definition: attnum.h:21

◆ view_has_instead_trigger()

static bool view_has_instead_trigger ( Relation  view,
CmdType  event 
)
static

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

2365 {
2366  TriggerDesc *trigDesc = view->trigdesc;
2367 
2368  switch (event)
2369  {
2370  case CMD_INSERT:
2371  if (trigDesc && trigDesc->trig_insert_instead_row)
2372  return true;
2373  break;
2374  case CMD_UPDATE:
2375  if (trigDesc && trigDesc->trig_update_instead_row)
2376  return true;
2377  break;
2378  case CMD_DELETE:
2379  if (trigDesc && trigDesc->trig_delete_instead_row)
2380  return true;
2381  break;
2382  default:
2383  elog(ERROR, "unrecognized CmdType: %d", (int) event);
2384  break;
2385  }
2386  return false;
2387 }
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 2450 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().

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