PostgreSQL Source Code  git master
rewriteHandler.c File Reference
#include "postgres.h"
#include "access/sysattr.h"
#include "catalog/dependency.h"
#include "catalog/pg_type.h"
#include "commands/trigger.h"
#include "foreign/fdwapi.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "parser/analyze.h"
#include "parser/parse_coerce.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, List **attrno_list)
 
static TargetEntryprocess_matched_tle (TargetEntry *src_tle, TargetEntry *prior_tle, const char *attrName)
 
static Nodeget_assignment_input (Node *node)
 
static void rewriteValuesRTE (RangeTblEntry *rte, Relation target_relation, List *attrnos)
 
static void markQueryForLocking (Query *qry, Node *jtnode, LockClauseStrength strength, LockWaitPolicy waitPolicy, bool pushedDown)
 
static ListmatchLocks (CmdType event, RuleLock *rulelocks, int varno, Query *parsetree, bool *hasUpdate)
 
static QueryfireRIRrules (Query *parsetree, List *activeRIRs)
 
static bool view_has_instead_trigger (Relation view, CmdType event)
 
static Bitmapsetadjust_view_column_set (Bitmapset *cols, List *targetlist)
 
void AcquireRewriteLocks (Query *parsetree, bool forExecute, bool forUpdatePushedDown)
 
Nodebuild_column_default (Relation rel, int attrno)
 
static bool searchForDefault (RangeTblEntry *rte)
 
void rewriteTargetListUD (Query *parsetree, RangeTblEntry *target_rte, Relation target_relation)
 
static QueryApplyRetrieveRule (Query *parsetree, RewriteRule *rule, int rt_index, Relation relation, List *activeRIRs)
 
static bool fireRIRonSubLink (Node *node, List *activeRIRs)
 
static QueryCopyAndAddInvertedQual (Query *parsetree, Node *rule_qual, int rt_index, CmdType event)
 
static ListfireRules (Query *parsetree, int rt_index, CmdType event, List *locks, bool *instead_flag, bool *returning_flag, Query **qual_product)
 
Queryget_view_query (Relation view)
 
static const char * view_col_is_auto_updatable (RangeTblRef *rtr, TargetEntry *tle)
 
const char * view_query_is_auto_updatable (Query *viewquery, bool check_cols)
 
static const char * view_cols_are_auto_updatable (Query *viewquery, Bitmapset *required_cols, Bitmapset **updatable_cols, char **non_updatable_col)
 
int relation_is_updatable (Oid reloid, 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

Function Documentation

◆ acquireLocksOnSubLinks()

static bool acquireLocksOnSubLinks ( Node node,
acquireLocksOnSubLinks_context context 
)
static

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

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

◆ AcquireRewriteLocks()

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

Definition at line 131 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, heap_close, heap_open(), IsA, RangeTblEntry::joinaliasvars, lappend(), lfirst, NIL, NoLock, QTW_IGNORE_RC_SUBQUERIES, query_tree_walker(), RelationData::rd_rel, RangeTblEntry::relid, RangeTblEntry::relkind, Query::resultRelation, RowExclusiveLock, RowShareLock, rt_fetch, Query::rtable, RTE_JOIN, RTE_RELATION, RTE_SUBQUERY, RangeTblEntry::rtekind, strip_implicit_coercions(), RangeTblEntry::subquery, Var::varattno, Var::varlevelsup, and Var::varno.

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

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

◆ adjust_view_column_set()

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

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

2647 {
2648  Bitmapset *result = NULL;
2649  int col;
2650 
2651  col = -1;
2652  while ((col = bms_next_member(cols, col)) >= 0)
2653  {
2654  /* bit numbers are offset by FirstLowInvalidHeapAttributeNumber */
2656 
2657  if (attno == InvalidAttrNumber)
2658  {
2659  /*
2660  * There's a whole-row reference to the view. For permissions
2661  * purposes, treat it as a reference to each column available from
2662  * the view. (We should *not* convert this to a whole-row
2663  * reference to the base relation, since the view may not touch
2664  * all columns of the base relation.)
2665  */
2666  ListCell *lc;
2667 
2668  foreach(lc, targetlist)
2669  {
2670  TargetEntry *tle = lfirst_node(TargetEntry, lc);
2671  Var *var;
2672 
2673  if (tle->resjunk)
2674  continue;
2675  var = castNode(Var, tle->expr);
2676  result = bms_add_member(result,
2677  var->varattno - FirstLowInvalidHeapAttributeNumber);
2678  }
2679  }
2680  else
2681  {
2682  /*
2683  * Views do not have system columns, so we do not expect to see
2684  * any other system attnos here. If we do find one, the error
2685  * case will apply.
2686  */
2687  TargetEntry *tle = get_tle_by_resno(targetlist, attno);
2688 
2689  if (tle != NULL && !tle->resjunk && IsA(tle->expr, Var))
2690  {
2691  Var *var = (Var *) tle->expr;
2692 
2693  result = bms_add_member(result,
2694  var->varattno - FirstLowInvalidHeapAttributeNumber);
2695  }
2696  else
2697  elog(ERROR, "attribute number %d not found in view targetlist",
2698  attno);
2699  }
2700  }
2701 
2702  return result;
2703 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:568
#define castNode(_type_, nodeptr)
Definition: nodes.h:586
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1075
AttrNumber varattno
Definition: primnodes.h:169
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:28
Definition: primnodes.h:164
bool resjunk
Definition: primnodes.h:1383
#define ERROR
Definition: elog.h:43
#define lfirst_node(type, lc)
Definition: pg_list.h:109
Expr * expr
Definition: primnodes.h:1376
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:764
#define InvalidAttrNumber
Definition: attnum.h:23
TargetEntry * get_tle_by_resno(List *tlist, AttrNumber resno)
#define elog
Definition: elog.h:219
int16 AttrNumber
Definition: attnum.h:21

◆ adjustJoinTreeList()

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

Definition at line 634 of file rewriteHandler.c.

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

Referenced by rewriteRuleAction().

635 {
636  List *newjointree = copyObject(parsetree->jointree->fromlist);
637  ListCell *l;
638 
639  if (removert)
640  {
641  foreach(l, newjointree)
642  {
643  RangeTblRef *rtr = lfirst(l);
644 
645  if (IsA(rtr, RangeTblRef) &&
646  rtr->rtindex == rt_index)
647  {
648  newjointree = list_delete_ptr(newjointree, rtr);
649 
650  /*
651  * foreach is safe because we exit loop after list_delete...
652  */
653  break;
654  }
655  }
656  }
657  return newjointree;
658 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:568
FromExpr * jointree
Definition: parsenodes.h:138
List * fromlist
Definition: primnodes.h:1479
List * list_delete_ptr(List *list, void *datum)
Definition: list.c:590
#define lfirst(lc)
Definition: pg_list.h:106
#define copyObject(obj)
Definition: nodes.h:630
Definition: pg_list.h:45

◆ ApplyRetrieveRule()

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

Definition at line 1451 of file rewriteHandler.c.

References AcquireRewriteLocks(), RewriteRule::actions, Assert, ChangeVarNodes(), RangeTblEntry::checkAsUser, CMD_DELETE, CMD_INSERT, CMD_UPDATE, Query::commandType, copyObject, elog, ERROR, 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::requiredPerms, Query::resultRelation, Query::returningList, rt_fetch, Query::rtable, RTE_SUBQUERY, RangeTblEntry::rtekind, RangeTblEntry::security_barrier, RangeTblEntry::selectedCols, RowMarkClause::strength, RangeTblEntry::subquery, Query::targetList, RangeTblEntry::updatedCols, and RowMarkClause::waitPolicy.

Referenced by fireRIRrules().

1456 {
1457  Query *rule_action;
1458  RangeTblEntry *rte,
1459  *subrte;
1460  RowMarkClause *rc;
1461 
1462  if (list_length(rule->actions) != 1)
1463  elog(ERROR, "expected just one rule action");
1464  if (rule->qual != NULL)
1465  elog(ERROR, "cannot handle qualified ON SELECT rule");
1466 
1467  if (rt_index == parsetree->resultRelation)
1468  {
1469  /*
1470  * We have a view as the result relation of the query, and it wasn't
1471  * rewritten by any rule. This case is supported if there is an
1472  * INSTEAD OF trigger that will trap attempts to insert/update/delete
1473  * view rows. The executor will check that; for the moment just plow
1474  * ahead. We have two cases:
1475  *
1476  * For INSERT, we needn't do anything. The unmodified RTE will serve
1477  * fine as the result relation.
1478  *
1479  * For UPDATE/DELETE, we need to expand the view so as to have source
1480  * data for the operation. But we also need an unmodified RTE to
1481  * serve as the target. So, copy the RTE and add the copy to the
1482  * rangetable. Note that the copy does not get added to the jointree.
1483  * Also note that there's a hack in fireRIRrules to avoid calling this
1484  * function again when it arrives at the copied RTE.
1485  */
1486  if (parsetree->commandType == CMD_INSERT)
1487  return parsetree;
1488  else if (parsetree->commandType == CMD_UPDATE ||
1489  parsetree->commandType == CMD_DELETE)
1490  {
1491  RangeTblEntry *newrte;
1492  Var *var;
1493  TargetEntry *tle;
1494 
1495  rte = rt_fetch(rt_index, parsetree->rtable);
1496  newrte = copyObject(rte);
1497  parsetree->rtable = lappend(parsetree->rtable, newrte);
1498  parsetree->resultRelation = list_length(parsetree->rtable);
1499 
1500  /*
1501  * There's no need to do permissions checks twice, so wipe out the
1502  * permissions info for the original RTE (we prefer to keep the
1503  * bits set on the result RTE).
1504  */
1505  rte->requiredPerms = 0;
1506  rte->checkAsUser = InvalidOid;
1507  rte->selectedCols = NULL;
1508  rte->insertedCols = NULL;
1509  rte->updatedCols = NULL;
1510 
1511  /*
1512  * For the most part, Vars referencing the view should remain as
1513  * they are, meaning that they implicitly represent OLD values.
1514  * But in the RETURNING list if any, we want such Vars to
1515  * represent NEW values, so change them to reference the new RTE.
1516  *
1517  * Since ChangeVarNodes scribbles on the tree in-place, copy the
1518  * RETURNING list first for safety.
1519  */
1520  parsetree->returningList = copyObject(parsetree->returningList);
1521  ChangeVarNodes((Node *) parsetree->returningList, rt_index,
1522  parsetree->resultRelation, 0);
1523 
1524  /*
1525  * To allow the executor to compute the original view row to pass
1526  * to the INSTEAD OF trigger, we add a resjunk whole-row Var
1527  * referencing the original RTE. This will later get expanded
1528  * into a RowExpr computing all the OLD values of the view row.
1529  */
1530  var = makeWholeRowVar(rte, rt_index, 0, false);
1531  tle = makeTargetEntry((Expr *) var,
1532  list_length(parsetree->targetList) + 1,
1533  pstrdup("wholerow"),
1534  true);
1535 
1536  parsetree->targetList = lappend(parsetree->targetList, tle);
1537 
1538  /* Now, continue with expanding the original view RTE */
1539  }
1540  else
1541  elog(ERROR, "unrecognized commandType: %d",
1542  (int) parsetree->commandType);
1543  }
1544 
1545  /*
1546  * Check if there's a FOR [KEY] UPDATE/SHARE clause applying to this view.
1547  *
1548  * Note: we needn't explicitly consider any such clauses appearing in
1549  * ancestor query levels; their effects have already been pushed down to
1550  * here by markQueryForLocking, and will be reflected in "rc".
1551  */
1552  rc = get_parse_rowmark(parsetree, rt_index);
1553 
1554  /*
1555  * Make a modifiable copy of the view query, and acquire needed locks on
1556  * the relations it mentions. Force at least RowShareLock for all such
1557  * rels if there's a FOR [KEY] UPDATE/SHARE clause affecting this view.
1558  */
1559  rule_action = copyObject(linitial(rule->actions));
1560 
1561  AcquireRewriteLocks(rule_action, true, (rc != NULL));
1562 
1563  /*
1564  * If FOR [KEY] UPDATE/SHARE of view, mark all the contained tables as
1565  * implicit FOR [KEY] UPDATE/SHARE, the same as the parser would have done
1566  * if the view's subquery had been written out explicitly.
1567  */
1568  if (rc != NULL)
1569  markQueryForLocking(rule_action, (Node *) rule_action->jointree,
1570  rc->strength, rc->waitPolicy, true);
1571 
1572  /*
1573  * Recursively expand any view references inside the view.
1574  *
1575  * Note: this must happen after markQueryForLocking. That way, any UPDATE
1576  * permission bits needed for sub-views are initially applied to their
1577  * RTE_RELATION RTEs by markQueryForLocking, and then transferred to their
1578  * OLD rangetable entries by the action below (in a recursive call of this
1579  * routine).
1580  */
1581  rule_action = fireRIRrules(rule_action, activeRIRs);
1582 
1583  /*
1584  * Now, plug the view query in as a subselect, replacing the relation's
1585  * original RTE.
1586  */
1587  rte = rt_fetch(rt_index, parsetree->rtable);
1588 
1589  rte->rtekind = RTE_SUBQUERY;
1590  rte->relid = InvalidOid;
1591  rte->security_barrier = RelationIsSecurityView(relation);
1592  rte->subquery = rule_action;
1593  rte->inh = false; /* must not be set for a subquery */
1594 
1595  /*
1596  * We move the view's permission check data down to its rangetable. The
1597  * checks will actually be done against the OLD entry therein.
1598  */
1599  subrte = rt_fetch(PRS2_OLD_VARNO, rule_action->rtable);
1600  Assert(subrte->relid == relation->rd_id);
1601  subrte->requiredPerms = rte->requiredPerms;
1602  subrte->checkAsUser = rte->checkAsUser;
1603  subrte->selectedCols = rte->selectedCols;
1604  subrte->insertedCols = rte->insertedCols;
1605  subrte->updatedCols = rte->updatedCols;
1606 
1607  rte->requiredPerms = 0; /* no permission check on subquery itself */
1608  rte->checkAsUser = InvalidOid;
1609  rte->selectedCols = NULL;
1610  rte->insertedCols = NULL;
1611  rte->updatedCols = NULL;
1612 
1613  return parsetree;
1614 }
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:1161
int resultRelation
Definition: parsenodes.h:122
Definition: nodes.h:517
Var * makeWholeRowVar(RangeTblEntry *rte, Index varno, Index varlevelsup, bool allowScalar)
Definition: makefuncs.c:134
AclMode requiredPerms
Definition: parsenodes.h:1070
Definition: primnodes.h:164
LockClauseStrength strength
Definition: parsenodes.h:1333
List * targetList
Definition: parsenodes.h:140
Bitmapset * selectedCols
Definition: parsenodes.h:1072
#define linitial(l)
Definition: pg_list.h:111
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:237
Oid rd_id
Definition: rel.h:86
List * lappend(List *list, void *datum)
Definition: list.c:128
#define PRS2_OLD_VARNO
Definition: primnodes.h:161
bool security_barrier
Definition: parsenodes.h:986
#define InvalidOid
Definition: postgres_ext.h:36
Bitmapset * updatedCols
Definition: parsenodes.h:1074
CmdType commandType
Definition: parsenodes.h:112
#define Assert(condition)
Definition: c.h:699
static int list_length(const List *l)
Definition: pg_list.h:89
LockWaitPolicy waitPolicy
Definition: parsenodes.h:1334
RTEKind rtekind
Definition: parsenodes.h:962
Query * subquery
Definition: parsenodes.h:985
Bitmapset * insertedCols
Definition: parsenodes.h:1073
#define RelationIsSecurityView(relation)
Definition: rel.h:338
void ChangeVarNodes(Node *node, int rt_index, int new_index, int sublevels_up)
Definition: rewriteManip.c:607
#define elog
Definition: elog.h:219
#define copyObject(obj)
Definition: nodes.h:630
static Query * fireRIRrules(Query *parsetree, List *activeRIRs)

◆ build_column_default()

Node* build_column_default ( Relation  rel,
int  attrno 
)

Definition at line 1106 of file rewriteHandler.c.

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

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

1107 {
1108  TupleDesc rd_att = rel->rd_att;
1109  Form_pg_attribute att_tup = TupleDescAttr(rd_att, attrno - 1);
1110  Oid atttype = att_tup->atttypid;
1111  int32 atttypmod = att_tup->atttypmod;
1112  Node *expr = NULL;
1113  Oid exprtype;
1114 
1115  if (att_tup->attidentity)
1116  {
1118 
1119  nve->seqid = getOwnedSequence(RelationGetRelid(rel), attrno);
1120  nve->typeId = att_tup->atttypid;
1121 
1122  return (Node *) nve;
1123  }
1124 
1125  /*
1126  * Scan to see if relation has a default for this column.
1127  */
1128  if (att_tup->atthasdef && rd_att->constr &&
1129  rd_att->constr->num_defval > 0)
1130  {
1131  AttrDefault *defval = rd_att->constr->defval;
1132  int ndef = rd_att->constr->num_defval;
1133 
1134  while (--ndef >= 0)
1135  {
1136  if (attrno == defval[ndef].adnum)
1137  {
1138  /*
1139  * Found it, convert string representation to node tree.
1140  */
1141  expr = stringToNode(defval[ndef].adbin);
1142  break;
1143  }
1144  }
1145  }
1146 
1147  if (expr == NULL)
1148  {
1149  /*
1150  * No per-column default, so look for a default for the type itself.
1151  */
1152  expr = get_typdefault(atttype);
1153  }
1154 
1155  if (expr == NULL)
1156  return NULL; /* No default anywhere */
1157 
1158  /*
1159  * Make sure the value is coerced to the target column type; this will
1160  * generally be true already, but there seem to be some corner cases
1161  * involving domain defaults where it might not be true. This should match
1162  * the parser's processing of non-defaulted expressions --- see
1163  * transformAssignedExpr().
1164  */
1165  exprtype = exprType(expr);
1166 
1167  expr = coerce_to_target_type(NULL, /* no UNKNOWN params here */
1168  expr, exprtype,
1169  atttype, atttypmod,
1172  -1);
1173  if (expr == NULL)
1174  ereport(ERROR,
1175  (errcode(ERRCODE_DATATYPE_MISMATCH),
1176  errmsg("column \"%s\" is of type %s"
1177  " but default expression is of type %s",
1178  NameStr(att_tup->attname),
1179  format_type_be(atttype),
1180  format_type_be(exprtype)),
1181  errhint("You will need to rewrite or cast the expression.")));
1182 
1183  return expr;
1184 }
void * stringToNode(char *str)
Definition: read.c:39
Oid getOwnedSequence(Oid relid, AttrNumber attnum)
Definition: pg_depend.c:605
int errhint(const char *fmt,...)
Definition: elog.c:987
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:93
Definition: nodes.h:517
int errcode(int sqlerrcode)
Definition: elog.c:575
char * format_type_be(Oid type_oid)
Definition: format_type.c:328
unsigned int Oid
Definition: postgres_ext.h:31
signed int int32
Definition: c.h:313
AttrDefault * defval
Definition: tupdesc.h:41
#define ERROR
Definition: elog.h:43
Node * coerce_to_target_type(ParseState *pstate, Node *expr, Oid exprtype, Oid targettype, int32 targettypmod, CoercionContext ccontext, CoercionForm cformat, int location)
Definition: parse_coerce.c:78
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:197
#define ereport(elevel, rest)
Definition: elog.h:122
TupleDesc rd_att
Definition: rel.h:85
uint16 num_defval
Definition: tupdesc.h:44
#define makeNode(_type_)
Definition: nodes.h:565
Node * get_typdefault(Oid typid)
Definition: lsyscache.c:2202
TupleConstr * constr
Definition: tupdesc.h:87
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define NameStr(name)
Definition: c.h:576
#define RelationGetRelid(relation)
Definition: rel.h:407

◆ CopyAndAddInvertedQual()

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

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

1987 {
1988  /* Don't scribble on the passed qual (it's in the relcache!) */
1989  Node *new_qual = copyObject(rule_qual);
1991 
1992  context.for_execute = true;
1993 
1994  /*
1995  * In case there are subqueries in the qual, acquire necessary locks and
1996  * fix any deleted JOIN RTE entries. (This is somewhat redundant with
1997  * rewriteRuleAction, but not entirely ... consider restructuring so that
1998  * we only need to process the qual this way once.)
1999  */
2000  (void) acquireLocksOnSubLinks(new_qual, &context);
2001 
2002  /* Fix references to OLD */
2003  ChangeVarNodes(new_qual, PRS2_OLD_VARNO, rt_index, 0);
2004  /* Fix references to NEW */
2005  if (event == CMD_INSERT || event == CMD_UPDATE)
2006  new_qual = ReplaceVarsFromTargetList(new_qual,
2008  0,
2009  rt_fetch(rt_index,
2010  parsetree->rtable),
2011  parsetree->targetList,
2012  (event == CMD_UPDATE) ?
2015  rt_index,
2016  &parsetree->hasSubLinks);
2017  /* And attach the fixed qual */
2018  AddInvertedQual(parsetree, new_qual);
2019 
2020  return parsetree;
2021 }
static bool acquireLocksOnSubLinks(Node *node, acquireLocksOnSubLinks_context *context)
void AddInvertedQual(Query *parsetree, Node *qual)
Definition: nodes.h:517
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:161
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:607
#define copyObject(obj)
Definition: nodes.h:630
#define PRS2_NEW_VARNO
Definition: primnodes.h:162

◆ fireRIRonSubLink()

static bool fireRIRonSubLink ( Node node,
List activeRIRs 
)
static

Definition at line 1688 of file rewriteHandler.c.

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

Referenced by fireRIRrules().

1689 {
1690  if (node == NULL)
1691  return false;
1692  if (IsA(node, SubLink))
1693  {
1694  SubLink *sub = (SubLink *) node;
1695 
1696  /* Do what we came for */
1697  sub->subselect = (Node *) fireRIRrules((Query *) sub->subselect,
1698  activeRIRs);
1699  /* Fall through to process lefthand args of SubLink */
1700  }
1701 
1702  /*
1703  * Do NOT recurse into Query nodes, because fireRIRrules already processed
1704  * subselects of subselects for us.
1705  */
1707  (void *) activeRIRs);
1708 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:568
Definition: nodes.h:517
static bool fireRIRonSubLink(Node *node, List *activeRIRs)
bool expression_tree_walker(Node *node, bool(*walker)(), void *context)
Definition: nodeFuncs.c:1834
static Query * fireRIRrules(Query *parsetree, List *activeRIRs)

◆ fireRIRrules()

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

Definition at line 1719 of file rewriteHandler.c.

References acquireLocksOnSubLinks(), ApplyRetrieveRule(), CMD_SELECT, Query::cteList, CommonTableExpr::ctequery, ereport, errcode(), errmsg(), ERROR, RewriteRule::event, expression_tree_walker(), fireRIRonSubLink(), acquireLocksOnSubLinks_context::for_execute, get_row_security_policies(), Query::hasRowSecurity, Query::hasSubLinks, heap_close, heap_open(), i, lappend(), lcons_oid(), lfirst, list_concat(), list_delete_first(), list_length(), list_member_oid(), NIL, NoLock, RuleLock::numLocks, 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, and Query::withCheckOptions.

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

1720 {
1721  int origResultRelation = parsetree->resultRelation;
1722  int rt_index;
1723  ListCell *lc;
1724 
1725  /*
1726  * don't try to convert this into a foreach loop, because rtable list can
1727  * get changed each time through...
1728  */
1729  rt_index = 0;
1730  while (rt_index < list_length(parsetree->rtable))
1731  {
1732  RangeTblEntry *rte;
1733  Relation rel;
1734  List *locks;
1735  RuleLock *rules;
1736  RewriteRule *rule;
1737  int i;
1738 
1739  ++rt_index;
1740 
1741  rte = rt_fetch(rt_index, parsetree->rtable);
1742 
1743  /*
1744  * A subquery RTE can't have associated rules, so there's nothing to
1745  * do to this level of the query, but we must recurse into the
1746  * subquery to expand any rule references in it.
1747  */
1748  if (rte->rtekind == RTE_SUBQUERY)
1749  {
1750  rte->subquery = fireRIRrules(rte->subquery, activeRIRs);
1751  continue;
1752  }
1753 
1754  /*
1755  * Joins and other non-relation RTEs can be ignored completely.
1756  */
1757  if (rte->rtekind != RTE_RELATION)
1758  continue;
1759 
1760  /*
1761  * Always ignore RIR rules for materialized views referenced in
1762  * queries. (This does not prevent refreshing MVs, since they aren't
1763  * referenced in their own query definitions.)
1764  *
1765  * Note: in the future we might want to allow MVs to be conditionally
1766  * expanded as if they were regular views, if they are not scannable.
1767  * In that case this test would need to be postponed till after we've
1768  * opened the rel, so that we could check its state.
1769  */
1770  if (rte->relkind == RELKIND_MATVIEW)
1771  continue;
1772 
1773  /*
1774  * If the table is not referenced in the query, then we ignore it.
1775  * This prevents infinite expansion loop due to new rtable entries
1776  * inserted by expansion of a rule. A table is referenced if it is
1777  * part of the join set (a source table), or is referenced by any Var
1778  * nodes, or is the result table.
1779  */
1780  if (rt_index != parsetree->resultRelation &&
1781  !rangeTableEntry_used((Node *) parsetree, rt_index, 0))
1782  continue;
1783 
1784  /*
1785  * Also, if this is a new result relation introduced by
1786  * ApplyRetrieveRule, we don't want to do anything more with it.
1787  */
1788  if (rt_index == parsetree->resultRelation &&
1789  rt_index != origResultRelation)
1790  continue;
1791 
1792  /*
1793  * We can use NoLock here since either the parser or
1794  * AcquireRewriteLocks should have locked the rel already.
1795  */
1796  rel = heap_open(rte->relid, NoLock);
1797 
1798  /*
1799  * Collect the RIR rules that we must apply
1800  */
1801  rules = rel->rd_rules;
1802  if (rules != NULL)
1803  {
1804  locks = NIL;
1805  for (i = 0; i < rules->numLocks; i++)
1806  {
1807  rule = rules->rules[i];
1808  if (rule->event != CMD_SELECT)
1809  continue;
1810 
1811  locks = lappend(locks, rule);
1812  }
1813 
1814  /*
1815  * If we found any, apply them --- but first check for recursion!
1816  */
1817  if (locks != NIL)
1818  {
1819  ListCell *l;
1820 
1821  if (list_member_oid(activeRIRs, RelationGetRelid(rel)))
1822  ereport(ERROR,
1823  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1824  errmsg("infinite recursion detected in rules for relation \"%s\"",
1825  RelationGetRelationName(rel))));
1826  activeRIRs = lcons_oid(RelationGetRelid(rel), activeRIRs);
1827 
1828  foreach(l, locks)
1829  {
1830  rule = lfirst(l);
1831 
1832  parsetree = ApplyRetrieveRule(parsetree,
1833  rule,
1834  rt_index,
1835  rel,
1836  activeRIRs);
1837  }
1838 
1839  activeRIRs = list_delete_first(activeRIRs);
1840  }
1841  }
1842 
1843  heap_close(rel, NoLock);
1844  }
1845 
1846  /* Recurse into subqueries in WITH */
1847  foreach(lc, parsetree->cteList)
1848  {
1849  CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
1850 
1851  cte->ctequery = (Node *)
1852  fireRIRrules((Query *) cte->ctequery, activeRIRs);
1853  }
1854 
1855  /*
1856  * Recurse into sublink subqueries, too. But we already did the ones in
1857  * the rtable and cteList.
1858  */
1859  if (parsetree->hasSubLinks)
1860  query_tree_walker(parsetree, fireRIRonSubLink, (void *) activeRIRs,
1862 
1863  /*
1864  * Apply any row level security policies. We do this last because it
1865  * requires special recursion detection if the new quals have sublink
1866  * subqueries, and if we did it in the loop above query_tree_walker would
1867  * then recurse into those quals a second time.
1868  */
1869  rt_index = 0;
1870  foreach(lc, parsetree->rtable)
1871  {
1872  RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
1873  Relation rel;
1874  List *securityQuals;
1875  List *withCheckOptions;
1876  bool hasRowSecurity;
1877  bool hasSubLinks;
1878 
1879  ++rt_index;
1880 
1881  /* Only normal relations can have RLS policies */
1882  if (rte->rtekind != RTE_RELATION ||
1883  (rte->relkind != RELKIND_RELATION &&
1884  rte->relkind != RELKIND_PARTITIONED_TABLE))
1885  continue;
1886 
1887  rel = heap_open(rte->relid, NoLock);
1888 
1889  /*
1890  * Fetch any new security quals that must be applied to this RTE.
1891  */
1892  get_row_security_policies(parsetree, rte, rt_index,
1893  &securityQuals, &withCheckOptions,
1894  &hasRowSecurity, &hasSubLinks);
1895 
1896  if (securityQuals != NIL || withCheckOptions != NIL)
1897  {
1898  if (hasSubLinks)
1899  {
1901 
1902  /*
1903  * Recursively process the new quals, checking for infinite
1904  * recursion.
1905  */
1906  if (list_member_oid(activeRIRs, RelationGetRelid(rel)))
1907  ereport(ERROR,
1908  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1909  errmsg("infinite recursion detected in policy for relation \"%s\"",
1910  RelationGetRelationName(rel))));
1911 
1912  activeRIRs = lcons_oid(RelationGetRelid(rel), activeRIRs);
1913 
1914  /*
1915  * get_row_security_policies just passed back securityQuals
1916  * and/or withCheckOptions, and there were SubLinks, make sure
1917  * we lock any relations which are referenced.
1918  *
1919  * These locks would normally be acquired by the parser, but
1920  * securityQuals and withCheckOptions are added post-parsing.
1921  */
1922  context.for_execute = true;
1923  (void) acquireLocksOnSubLinks((Node *) securityQuals, &context);
1924  (void) acquireLocksOnSubLinks((Node *) withCheckOptions,
1925  &context);
1926 
1927  /*
1928  * Now that we have the locks on anything added by
1929  * get_row_security_policies, fire any RIR rules for them.
1930  */
1931  expression_tree_walker((Node *) securityQuals,
1932  fireRIRonSubLink, (void *) activeRIRs);
1933 
1934  expression_tree_walker((Node *) withCheckOptions,
1935  fireRIRonSubLink, (void *) activeRIRs);
1936 
1937  activeRIRs = list_delete_first(activeRIRs);
1938  }
1939 
1940  /*
1941  * Add the new security barrier quals to the start of the RTE's
1942  * list so that they get applied before any existing barrier quals
1943  * (which would have come from a security-barrier view, and should
1944  * get lower priority than RLS conditions on the table itself).
1945  */
1946  rte->securityQuals = list_concat(securityQuals,
1947  rte->securityQuals);
1948 
1949  parsetree->withCheckOptions = list_concat(withCheckOptions,
1950  parsetree->withCheckOptions);
1951  }
1952 
1953  /*
1954  * Make sure the query is marked correctly if row level security
1955  * applies, or if the new quals had sublinks.
1956  */
1957  if (hasRowSecurity)
1958  parsetree->hasRowSecurity = true;
1959  if (hasSubLinks)
1960  parsetree->hasSubLinks = true;
1961 
1962  heap_close(rel, NoLock);
1963  }
1964 
1965  return parsetree;
1966 }
#define NIL
Definition: pg_list.h:69
bool query_tree_walker(Query *query, bool(*walker)(), void *context, int flags)
Definition: nodeFuncs.c:2256
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)
void get_row_security_policies(Query *root, RangeTblEntry *rte, int rt_index, List **securityQuals, List **withCheckOptions, bool *hasRowSecurity, bool *hasSubLinks)
Definition: rowsecurity.c:107
List * securityQuals
Definition: parsenodes.h:1075
int resultRelation
Definition: parsenodes.h:122
Definition: nodes.h:517
int errcode(int sqlerrcode)
Definition: elog.c:575
List * list_concat(List *list1, List *list2)
Definition: list.c:321
List * lcons_oid(Oid datum, List *list)
Definition: list.c:295
#define heap_close(r, l)
Definition: heapam.h:97
Definition: localtime.c:77
#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
static struct rule * rules
Definition: zic.c:277
#define RelationGetRelationName(relation)
Definition: rel.h:441
RewriteRule ** rules
Definition: prs2lock.h:43
#define ereport(elevel, rest)
Definition: elog.h:122
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
List * lappend(List *list, void *datum)
Definition: list.c:128
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1294
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:505
#define lfirst(lc)
Definition: pg_list.h:106
RuleLock * rd_rules
Definition: rel.h:88
bool expression_tree_walker(Node *node, bool(*walker)(), void *context)
Definition: nodeFuncs.c:1834
static int list_length(const List *l)
Definition: pg_list.h:89
RTEKind rtekind
Definition: parsenodes.h:962
Query * subquery
Definition: parsenodes.h:985
int errmsg(const char *fmt,...)
Definition: elog.c:797
int i
bool rangeTableEntry_used(Node *node, int rt_index, int sublevels_up)
Definition: rewriteManip.c:889
static Query * fireRIRrules(Query *parsetree, List *activeRIRs)
Definition: pg_list.h:45
#define RelationGetRelid(relation)
Definition: rel.h:407
List * list_delete_first(List *list)
Definition: list.c:666

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

2060 {
2061  List *results = NIL;
2062  ListCell *l;
2063 
2064  foreach(l, locks)
2065  {
2066  RewriteRule *rule_lock = (RewriteRule *) lfirst(l);
2067  Node *event_qual = rule_lock->qual;
2068  List *actions = rule_lock->actions;
2069  QuerySource qsrc;
2070  ListCell *r;
2071 
2072  /* Determine correct QuerySource value for actions */
2073  if (rule_lock->isInstead)
2074  {
2075  if (event_qual != NULL)
2076  qsrc = QSRC_QUAL_INSTEAD_RULE;
2077  else
2078  {
2079  qsrc = QSRC_INSTEAD_RULE;
2080  *instead_flag = true; /* report unqualified INSTEAD */
2081  }
2082  }
2083  else
2084  qsrc = QSRC_NON_INSTEAD_RULE;
2085 
2086  if (qsrc == QSRC_QUAL_INSTEAD_RULE)
2087  {
2088  /*
2089  * If there are INSTEAD rules with qualifications, the original
2090  * query is still performed. But all the negated rule
2091  * qualifications of the INSTEAD rules are added so it does its
2092  * actions only in cases where the rule quals of all INSTEAD rules
2093  * are false. Think of it as the default action in a case. We save
2094  * this in *qual_product so RewriteQuery() can add it to the query
2095  * list after we mangled it up enough.
2096  *
2097  * If we have already found an unqualified INSTEAD rule, then
2098  * *qual_product won't be used, so don't bother building it.
2099  */
2100  if (!*instead_flag)
2101  {
2102  if (*qual_product == NULL)
2103  *qual_product = copyObject(parsetree);
2104  *qual_product = CopyAndAddInvertedQual(*qual_product,
2105  event_qual,
2106  rt_index,
2107  event);
2108  }
2109  }
2110 
2111  /* Now process the rule's actions and add them to the result list */
2112  foreach(r, actions)
2113  {
2114  Query *rule_action = lfirst(r);
2115 
2116  if (rule_action->commandType == CMD_NOTHING)
2117  continue;
2118 
2119  rule_action = rewriteRuleAction(parsetree, rule_action,
2120  event_qual, rt_index, event,
2121  returning_flag);
2122 
2123  rule_action->querySource = qsrc;
2124  rule_action->canSetTag = false; /* might change later */
2125 
2126  results = lappend(results, rule_action);
2127  }
2128  }
2129 
2130  return results;
2131 }
#define NIL
Definition: pg_list.h:69
Node * qual
Definition: prs2lock.h:28
QuerySource
Definition: parsenodes.h:40
Definition: nodes.h:517
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:128
CmdType commandType
Definition: parsenodes.h:112
QuerySource querySource
Definition: parsenodes.h:114
#define lfirst(lc)
Definition: pg_list.h:106
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:630
Definition: pg_list.h:45

◆ get_assignment_input()

static Node * get_assignment_input ( Node node)
static

Definition at line 1079 of file rewriteHandler.c.

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

Referenced by process_matched_tle().

1080 {
1081  if (node == NULL)
1082  return NULL;
1083  if (IsA(node, FieldStore))
1084  {
1085  FieldStore *fstore = (FieldStore *) node;
1086 
1087  return (Node *) fstore->arg;
1088  }
1089  else if (IsA(node, ArrayRef))
1090  {
1091  ArrayRef *aref = (ArrayRef *) node;
1092 
1093  if (aref->refassgnexpr == NULL)
1094  return NULL;
1095  return (Node *) aref->refexpr;
1096  }
1097  return NULL;
1098 }
Expr * refassgnexpr
Definition: primnodes.h:411
#define IsA(nodeptr, _type_)
Definition: nodes.h:568
Expr * arg
Definition: primnodes.h:772
Definition: nodes.h:517
Expr * refexpr
Definition: primnodes.h:409

◆ get_view_query()

Query* get_view_query ( Relation  view)

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

2145 {
2146  int i;
2147 
2148  Assert(view->rd_rel->relkind == RELKIND_VIEW);
2149 
2150  for (i = 0; i < view->rd_rules->numLocks; i++)
2151  {
2152  RewriteRule *rule = view->rd_rules->rules[i];
2153 
2154  if (rule->event == CMD_SELECT)
2155  {
2156  /* A _RETURN rule should have only one action */
2157  if (list_length(rule->actions) != 1)
2158  elog(ERROR, "invalid _RETURN rule action specification");
2159 
2160  return (Query *) linitial(rule->actions);
2161  }
2162  }
2163 
2164  elog(ERROR, "failed to find _RETURN rule for view");
2165  return NULL; /* keep compiler quiet */
2166 }
int numLocks
Definition: prs2lock.h:42
Form_pg_class rd_rel
Definition: rel.h:84
Definition: localtime.c:77
#define linitial(l)
Definition: pg_list.h:111
#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:699
RuleLock * rd_rules
Definition: rel.h:88
static int list_length(const List *l)
Definition: pg_list.h:89
int i
#define elog
Definition: elog.h:219

◆ markQueryForLocking()

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

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

1631 {
1632  if (jtnode == NULL)
1633  return;
1634  if (IsA(jtnode, RangeTblRef))
1635  {
1636  int rti = ((RangeTblRef *) jtnode)->rtindex;
1637  RangeTblEntry *rte = rt_fetch(rti, qry->rtable);
1638 
1639  if (rte->rtekind == RTE_RELATION)
1640  {
1641  applyLockingClause(qry, rti, strength, waitPolicy, pushedDown);
1643  }
1644  else if (rte->rtekind == RTE_SUBQUERY)
1645  {
1646  applyLockingClause(qry, rti, strength, waitPolicy, pushedDown);
1647  /* FOR UPDATE/SHARE of subquery is propagated to subquery's rels */
1649  strength, waitPolicy, true);
1650  }
1651  /* other RTE types are unaffected by FOR UPDATE */
1652  }
1653  else if (IsA(jtnode, FromExpr))
1654  {
1655  FromExpr *f = (FromExpr *) jtnode;
1656  ListCell *l;
1657 
1658  foreach(l, f->fromlist)
1659  markQueryForLocking(qry, lfirst(l), strength, waitPolicy, pushedDown);
1660  }
1661  else if (IsA(jtnode, JoinExpr))
1662  {
1663  JoinExpr *j = (JoinExpr *) jtnode;
1664 
1665  markQueryForLocking(qry, j->larg, strength, waitPolicy, pushedDown);
1666  markQueryForLocking(qry, j->rarg, strength, waitPolicy, pushedDown);
1667  }
1668  else
1669  elog(ERROR, "unrecognized node type: %d",
1670  (int) nodeTag(jtnode));
1671 }
static void markQueryForLocking(Query *qry, Node *jtnode, LockClauseStrength strength, LockWaitPolicy waitPolicy, bool pushedDown)
#define IsA(nodeptr, _type_)
Definition: nodes.h:568
FromExpr * jointree
Definition: parsenodes.h:138
Definition: nodes.h:517
AclMode requiredPerms
Definition: parsenodes.h:1070
List * fromlist
Definition: primnodes.h:1479
Node * larg
Definition: primnodes.h:1459
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:1460
#define lfirst(lc)
Definition: pg_list.h:106
#define ACL_SELECT_FOR_UPDATE
Definition: parsenodes.h:90
#define nodeTag(nodeptr)
Definition: nodes.h:522
RTEKind rtekind
Definition: parsenodes.h:962
Query * subquery
Definition: parsenodes.h:985
#define elog
Definition: elog.h:219
void applyLockingClause(Query *qry, Index rtindex, LockClauseStrength strength, LockWaitPolicy waitPolicy, bool pushedDown)
Definition: analyze.c:2879

◆ matchLocks()

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

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

1390 {
1391  List *matching_locks = NIL;
1392  int nlocks;
1393  int i;
1394 
1395  if (rulelocks == NULL)
1396  return NIL;
1397 
1398  if (parsetree->commandType != CMD_SELECT)
1399  {
1400  if (parsetree->resultRelation != varno)
1401  return NIL;
1402  }
1403 
1404  nlocks = rulelocks->numLocks;
1405 
1406  for (i = 0; i < nlocks; i++)
1407  {
1408  RewriteRule *oneLock = rulelocks->rules[i];
1409 
1410  if (oneLock->event == CMD_UPDATE)
1411  *hasUpdate = true;
1412 
1413  /*
1414  * Suppress ON INSERT/UPDATE/DELETE rules that are disabled or
1415  * configured to not fire during the current sessions replication
1416  * role. ON SELECT rules will always be applied in order to keep views
1417  * working even in LOCAL or REPLICA role.
1418  */
1419  if (oneLock->event != CMD_SELECT)
1420  {
1422  {
1423  if (oneLock->enabled == RULE_FIRES_ON_ORIGIN ||
1424  oneLock->enabled == RULE_DISABLED)
1425  continue;
1426  }
1427  else /* ORIGIN or LOCAL ROLE */
1428  {
1429  if (oneLock->enabled == RULE_FIRES_ON_REPLICA ||
1430  oneLock->enabled == RULE_DISABLED)
1431  continue;
1432  }
1433  }
1434 
1435  if (oneLock->event == event)
1436  {
1437  if (parsetree->commandType != CMD_SELECT ||
1438  rangeTableEntry_used((Node *) parsetree, varno, 0))
1439  matching_locks = lappend(matching_locks, oneLock);
1440  }
1441  }
1442 
1443  return matching_locks;
1444 }
#define NIL
Definition: pg_list.h:69
int numLocks
Definition: prs2lock.h:42
int resultRelation
Definition: parsenodes.h:122
Definition: nodes.h:517
int SessionReplicationRole
Definition: trigger.c:66
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:128
#define RULE_FIRES_ON_ORIGIN
Definition: rewriteDefine.h:21
#define SESSION_REPLICATION_ROLE_REPLICA
Definition: trigger.h:147
#define RULE_FIRES_ON_REPLICA
Definition: rewriteDefine.h:23
CmdType commandType
Definition: parsenodes.h:112
int i
bool rangeTableEntry_used(Node *node, int rt_index, int sublevels_up)
Definition: rewriteManip.c:889
Definition: pg_list.h:45
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 926 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(), list_copy(), makeNode, FieldStore::newvals, and ArrayRef::refexpr.

Referenced by rewriteTargetListIU().

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

◆ QueryRewrite()

List* QueryRewrite ( Query parsetree)

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

3570 {
3571  uint64 input_query_id = parsetree->queryId;
3572  List *querylist;
3573  List *results;
3574  ListCell *l;
3575  CmdType origCmdType;
3576  bool foundOriginalQuery;
3577  Query *lastInstead;
3578 
3579  /*
3580  * This function is only applied to top-level original queries
3581  */
3582  Assert(parsetree->querySource == QSRC_ORIGINAL);
3583  Assert(parsetree->canSetTag);
3584 
3585  /*
3586  * Step 1
3587  *
3588  * Apply all non-SELECT rules possibly getting 0 or many queries
3589  */
3590  querylist = RewriteQuery(parsetree, NIL);
3591 
3592  /*
3593  * Step 2
3594  *
3595  * Apply all the RIR rules on each query
3596  *
3597  * This is also a handy place to mark each query with the original queryId
3598  */
3599  results = NIL;
3600  foreach(l, querylist)
3601  {
3602  Query *query = (Query *) lfirst(l);
3603 
3604  query = fireRIRrules(query, NIL);
3605 
3606  query->queryId = input_query_id;
3607 
3608  results = lappend(results, query);
3609  }
3610 
3611  /*
3612  * Step 3
3613  *
3614  * Determine which, if any, of the resulting queries is supposed to set
3615  * the command-result tag; and update the canSetTag fields accordingly.
3616  *
3617  * If the original query is still in the list, it sets the command tag.
3618  * Otherwise, the last INSTEAD query of the same kind as the original is
3619  * allowed to set the tag. (Note these rules can leave us with no query
3620  * setting the tag. The tcop code has to cope with this by setting up a
3621  * default tag based on the original un-rewritten query.)
3622  *
3623  * The Asserts verify that at most one query in the result list is marked
3624  * canSetTag. If we aren't checking asserts, we can fall out of the loop
3625  * as soon as we find the original query.
3626  */
3627  origCmdType = parsetree->commandType;
3628  foundOriginalQuery = false;
3629  lastInstead = NULL;
3630 
3631  foreach(l, results)
3632  {
3633  Query *query = (Query *) lfirst(l);
3634 
3635  if (query->querySource == QSRC_ORIGINAL)
3636  {
3637  Assert(query->canSetTag);
3638  Assert(!foundOriginalQuery);
3639  foundOriginalQuery = true;
3640 #ifndef USE_ASSERT_CHECKING
3641  break;
3642 #endif
3643  }
3644  else
3645  {
3646  Assert(!query->canSetTag);
3647  if (query->commandType == origCmdType &&
3648  (query->querySource == QSRC_INSTEAD_RULE ||
3650  lastInstead = query;
3651  }
3652  }
3653 
3654  if (!foundOriginalQuery && lastInstead != NULL)
3655  lastInstead->canSetTag = true;
3656 
3657  return results;
3658 }
#define NIL
Definition: pg_list.h:69
static List * RewriteQuery(Query *parsetree, List *rewrite_events)
List * lappend(List *list, void *datum)
Definition: list.c:128
uint64 queryId
Definition: parsenodes.h:116
CmdType commandType
Definition: parsenodes.h:112
QuerySource querySource
Definition: parsenodes.h:114
#define Assert(condition)
Definition: c.h:699
#define lfirst(lc)
Definition: pg_list.h:106
bool canSetTag
Definition: parsenodes.h:118
static Query * fireRIRrules(Query *parsetree, List *activeRIRs)
Definition: pg_list.h:45
CmdType
Definition: nodes.h:657

◆ relation_is_updatable()

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

Definition at line 2480 of file rewriteHandler.c.

References AccessShareLock, adjust_view_column_set(), ALL_EVENTS, Assert, bms_int_members(), bms_is_empty(), 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, linitial, RuleLock::numLocks, RewriteRule::qual, RelationData::rd_rel, RelationData::rd_rules, relation_close(), relation_is_updatable(), 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().

2483 {
2484  int events = 0;
2485  Relation rel;
2486  RuleLock *rulelocks;
2487 
2488 #define ALL_EVENTS ((1 << CMD_INSERT) | (1 << CMD_UPDATE) | (1 << CMD_DELETE))
2489 
2490  rel = try_relation_open(reloid, AccessShareLock);
2491 
2492  /*
2493  * If the relation doesn't exist, return zero rather than throwing an
2494  * error. This is helpful since scanning an information_schema view under
2495  * MVCC rules can result in referencing rels that have actually been
2496  * deleted already.
2497  */
2498  if (rel == NULL)
2499  return 0;
2500 
2501  /* If the relation is a table, it is always updatable */
2502  if (rel->rd_rel->relkind == RELKIND_RELATION ||
2503  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
2504  {
2506  return ALL_EVENTS;
2507  }
2508 
2509  /* Look for unconditional DO INSTEAD rules, and note supported events */
2510  rulelocks = rel->rd_rules;
2511  if (rulelocks != NULL)
2512  {
2513  int i;
2514 
2515  for (i = 0; i < rulelocks->numLocks; i++)
2516  {
2517  if (rulelocks->rules[i]->isInstead &&
2518  rulelocks->rules[i]->qual == NULL)
2519  {
2520  events |= ((1 << rulelocks->rules[i]->event) & ALL_EVENTS);
2521  }
2522  }
2523 
2524  /* If we have rules for all events, we're done */
2525  if (events == ALL_EVENTS)
2526  {
2528  return events;
2529  }
2530  }
2531 
2532  /* Similarly look for INSTEAD OF triggers, if they are to be included */
2533  if (include_triggers)
2534  {
2535  TriggerDesc *trigDesc = rel->trigdesc;
2536 
2537  if (trigDesc)
2538  {
2539  if (trigDesc->trig_insert_instead_row)
2540  events |= (1 << CMD_INSERT);
2541  if (trigDesc->trig_update_instead_row)
2542  events |= (1 << CMD_UPDATE);
2543  if (trigDesc->trig_delete_instead_row)
2544  events |= (1 << CMD_DELETE);
2545 
2546  /* If we have triggers for all events, we're done */
2547  if (events == ALL_EVENTS)
2548  {
2550  return events;
2551  }
2552  }
2553  }
2554 
2555  /* If this is a foreign table, check which update events it supports */
2556  if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
2557  {
2558  FdwRoutine *fdwroutine = GetFdwRoutineForRelation(rel, false);
2559 
2560  if (fdwroutine->IsForeignRelUpdatable != NULL)
2561  events |= fdwroutine->IsForeignRelUpdatable(rel);
2562  else
2563  {
2564  /* Assume presence of executor functions is sufficient */
2565  if (fdwroutine->ExecForeignInsert != NULL)
2566  events |= (1 << CMD_INSERT);
2567  if (fdwroutine->ExecForeignUpdate != NULL)
2568  events |= (1 << CMD_UPDATE);
2569  if (fdwroutine->ExecForeignDelete != NULL)
2570  events |= (1 << CMD_DELETE);
2571  }
2572 
2574  return events;
2575  }
2576 
2577  /* Check if this is an automatically updatable view */
2578  if (rel->rd_rel->relkind == RELKIND_VIEW)
2579  {
2580  Query *viewquery = get_view_query(rel);
2581 
2582  if (view_query_is_auto_updatable(viewquery, false) == NULL)
2583  {
2584  Bitmapset *updatable_cols;
2585  int auto_events;
2586  RangeTblRef *rtr;
2587  RangeTblEntry *base_rte;
2588  Oid baseoid;
2589 
2590  /*
2591  * Determine which of the view's columns are updatable. If there
2592  * are none within the set of columns we are looking at, then the
2593  * view doesn't support INSERT/UPDATE, but it may still support
2594  * DELETE.
2595  */
2596  view_cols_are_auto_updatable(viewquery, NULL,
2597  &updatable_cols, NULL);
2598 
2599  if (include_cols != NULL)
2600  updatable_cols = bms_int_members(updatable_cols, include_cols);
2601 
2602  if (bms_is_empty(updatable_cols))
2603  auto_events = (1 << CMD_DELETE); /* May support DELETE */
2604  else
2605  auto_events = ALL_EVENTS; /* May support all events */
2606 
2607  /*
2608  * The base relation must also support these update commands.
2609  * Tables are always updatable, but for any other kind of base
2610  * relation we must do a recursive check limited to the columns
2611  * referenced by the locally updatable columns in this view.
2612  */
2613  rtr = (RangeTblRef *) linitial(viewquery->jointree->fromlist);
2614  base_rte = rt_fetch(rtr->rtindex, viewquery->rtable);
2615  Assert(base_rte->rtekind == RTE_RELATION);
2616 
2617  if (base_rte->relkind != RELKIND_RELATION &&
2618  base_rte->relkind != RELKIND_PARTITIONED_TABLE)
2619  {
2620  baseoid = base_rte->relid;
2621  include_cols = adjust_view_column_set(updatable_cols,
2622  viewquery->targetList);
2623  auto_events &= relation_is_updatable(baseoid,
2624  include_triggers,
2625  include_cols);
2626  }
2627  events |= auto_events;
2628  }
2629  }
2630 
2631  /* If we reach here, the relation may support some update commands */
2633  return events;
2634 }
ExecForeignDelete_function ExecForeignDelete
Definition: fdwapi.h:212
Node * qual
Definition: prs2lock.h:28
int numLocks
Definition: prs2lock.h:42
FromExpr * jointree
Definition: parsenodes.h:138
Relation try_relation_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1157
ExecForeignInsert_function ExecForeignInsert
Definition: fdwapi.h:210
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
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: heapam.c:1270
List * fromlist
Definition: primnodes.h:1479
Form_pg_class rd_rel
Definition: rel.h:84
unsigned int Oid
Definition: postgres_ext.h:31
bool isInstead
Definition: prs2lock.h:31
List * targetList
Definition: parsenodes.h:140
bool trig_insert_instead_row
Definition: reltrigger.h:57
#define linitial(l)
Definition: pg_list.h:111
List * rtable
Definition: parsenodes.h:137
#define ALL_EVENTS
TriggerDesc * trigdesc
Definition: rel.h:90
int relation_is_updatable(Oid reloid, bool include_triggers, Bitmapset *include_cols)
CmdType event
Definition: prs2lock.h:27
RewriteRule ** rules
Definition: prs2lock.h:43
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
bool trig_update_instead_row
Definition: reltrigger.h:62
bool bms_is_empty(const Bitmapset *a)
Definition: bitmapset.c:729
bool trig_delete_instead_row
Definition: reltrigger.h:67
static Bitmapset * adjust_view_column_set(Bitmapset *cols, List *targetlist)
ExecForeignUpdate_function ExecForeignUpdate
Definition: fdwapi.h:211
#define Assert(condition)
Definition: c.h:699
RuleLock * rd_rules
Definition: rel.h:88
RTEKind rtekind
Definition: parsenodes.h:962
FdwRoutine * GetFdwRoutineForRelation(Relation relation, bool makecopy)
Definition: foreign.c:395
Query * get_view_query(Relation view)
int i
IsForeignRelUpdatable_function IsForeignRelUpdatable
Definition: fdwapi.h:216
Bitmapset * bms_int_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:929
const char * view_query_is_auto_updatable(Query *viewquery, bool check_cols)

◆ RewriteQuery()

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

Definition at line 3176 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(), errhint(), errmsg(), ERROR, rewrite_event::event, fireRules(), FromExpr::fromlist, heap_close, heap_open(), IsA, Query::jointree, lappend(), lcons(), lfirst, lfirst_node, linitial, linitial_node, list_concat(), list_delete_first(), 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, Query::targetList, and view_has_instead_trigger().

Referenced by QueryRewrite().

3177 {
3178  CmdType event = parsetree->commandType;
3179  bool instead = false;
3180  bool returning = false;
3181  bool updatableview = false;
3182  Query *qual_product = NULL;
3183  List *rewritten = NIL;
3184  ListCell *lc1;
3185 
3186  /*
3187  * First, recursively process any insert/update/delete statements in WITH
3188  * clauses. (We have to do this first because the WITH clauses may get
3189  * copied into rule actions below.)
3190  */
3191  foreach(lc1, parsetree->cteList)
3192  {
3194  Query *ctequery = castNode(Query, cte->ctequery);
3195  List *newstuff;
3196 
3197  if (ctequery->commandType == CMD_SELECT)
3198  continue;
3199 
3200  newstuff = RewriteQuery(ctequery, rewrite_events);
3201 
3202  /*
3203  * Currently we can only handle unconditional, single-statement DO
3204  * INSTEAD rules correctly; we have to get exactly one Query out of
3205  * the rewrite operation to stuff back into the CTE node.
3206  */
3207  if (list_length(newstuff) == 1)
3208  {
3209  /* Push the single Query back into the CTE node */
3210  ctequery = linitial_node(Query, newstuff);
3211  /* WITH queries should never be canSetTag */
3212  Assert(!ctequery->canSetTag);
3213  cte->ctequery = (Node *) ctequery;
3214  }
3215  else if (newstuff == NIL)
3216  {
3217  ereport(ERROR,
3218  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3219  errmsg("DO INSTEAD NOTHING rules are not supported for data-modifying statements in WITH")));
3220  }
3221  else
3222  {
3223  ListCell *lc2;
3224 
3225  /* examine queries to determine which error message to issue */
3226  foreach(lc2, newstuff)
3227  {
3228  Query *q = (Query *) lfirst(lc2);
3229 
3231  ereport(ERROR,
3232  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3233  errmsg("conditional DO INSTEAD rules are not supported for data-modifying statements in WITH")));
3235  ereport(ERROR,
3236  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3237  errmsg("DO ALSO rules are not supported for data-modifying statements in WITH")));
3238  }
3239 
3240  ereport(ERROR,
3241  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3242  errmsg("multi-statement DO INSTEAD rules are not supported for data-modifying statements in WITH")));
3243  }
3244  }
3245 
3246  /*
3247  * If the statement is an insert, update, or delete, adjust its targetlist
3248  * as needed, and then fire INSERT/UPDATE/DELETE rules on it.
3249  *
3250  * SELECT rules are handled later when we have all the queries that should
3251  * get executed. Also, utilities aren't rewritten at all (do we still
3252  * need that check?)
3253  */
3254  if (event != CMD_SELECT && event != CMD_UTILITY)
3255  {
3256  int result_relation;
3257  RangeTblEntry *rt_entry;
3258  Relation rt_entry_relation;
3259  List *locks;
3260  List *product_queries;
3261  bool hasUpdate = false;
3262 
3263  result_relation = parsetree->resultRelation;
3264  Assert(result_relation != 0);
3265  rt_entry = rt_fetch(result_relation, parsetree->rtable);
3266  Assert(rt_entry->rtekind == RTE_RELATION);
3267 
3268  /*
3269  * We can use NoLock here since either the parser or
3270  * AcquireRewriteLocks should have locked the rel already.
3271  */
3272  rt_entry_relation = heap_open(rt_entry->relid, NoLock);
3273 
3274  /*
3275  * Rewrite the targetlist as needed for the command type.
3276  */
3277  if (event == CMD_INSERT)
3278  {
3279  RangeTblEntry *values_rte = NULL;
3280 
3281  /*
3282  * If it's an INSERT ... VALUES (...), (...), ... there will be a
3283  * single RTE for the VALUES targetlists.
3284  */
3285  if (list_length(parsetree->jointree->fromlist) == 1)
3286  {
3287  RangeTblRef *rtr = (RangeTblRef *) linitial(parsetree->jointree->fromlist);
3288 
3289  if (IsA(rtr, RangeTblRef))
3290  {
3291  RangeTblEntry *rte = rt_fetch(rtr->rtindex,
3292  parsetree->rtable);
3293 
3294  if (rte->rtekind == RTE_VALUES)
3295  values_rte = rte;
3296  }
3297  }
3298 
3299  if (values_rte)
3300  {
3301  List *attrnos;
3302 
3303  /* Process the main targetlist ... */
3304  parsetree->targetList = rewriteTargetListIU(parsetree->targetList,
3305  parsetree->commandType,
3306  parsetree->override,
3307  rt_entry_relation,
3308  parsetree->resultRelation,
3309  &attrnos);
3310  /* ... and the VALUES expression lists */
3311  rewriteValuesRTE(values_rte, rt_entry_relation, attrnos);
3312  }
3313  else
3314  {
3315  /* Process just the main targetlist */
3316  parsetree->targetList =
3317  rewriteTargetListIU(parsetree->targetList,
3318  parsetree->commandType,
3319  parsetree->override,
3320  rt_entry_relation,
3321  parsetree->resultRelation, NULL);
3322  }
3323 
3324  if (parsetree->onConflict &&
3325  parsetree->onConflict->action == ONCONFLICT_UPDATE)
3326  {
3327  parsetree->onConflict->onConflictSet =
3329  CMD_UPDATE,
3330  parsetree->override,
3331  rt_entry_relation,
3332  parsetree->resultRelation,
3333  NULL);
3334  }
3335  }
3336  else if (event == CMD_UPDATE)
3337  {
3338  parsetree->targetList =
3339  rewriteTargetListIU(parsetree->targetList,
3340  parsetree->commandType,
3341  parsetree->override,
3342  rt_entry_relation,
3343  parsetree->resultRelation, NULL);
3344  }
3345  else if (event == CMD_DELETE)
3346  {
3347  /* Nothing to do here */
3348  }
3349  else
3350  elog(ERROR, "unrecognized commandType: %d", (int) event);
3351 
3352  /*
3353  * Collect and apply the appropriate rules.
3354  */
3355  locks = matchLocks(event, rt_entry_relation->rd_rules,
3356  result_relation, parsetree, &hasUpdate);
3357 
3358  product_queries = fireRules(parsetree,
3359  result_relation,
3360  event,
3361  locks,
3362  &instead,
3363  &returning,
3364  &qual_product);
3365 
3366  /*
3367  * If there were no INSTEAD rules, and the target relation is a view
3368  * without any INSTEAD OF triggers, see if the view can be
3369  * automatically updated. If so, we perform the necessary query
3370  * transformation here and add the resulting query to the
3371  * product_queries list, so that it gets recursively rewritten if
3372  * necessary.
3373  */
3374  if (!instead && qual_product == NULL &&
3375  rt_entry_relation->rd_rel->relkind == RELKIND_VIEW &&
3376  !view_has_instead_trigger(rt_entry_relation, event))
3377  {
3378  /*
3379  * This throws an error if the view can't be automatically
3380  * updated, but that's OK since the query would fail at runtime
3381  * anyway.
3382  */
3383  parsetree = rewriteTargetView(parsetree, rt_entry_relation);
3384 
3385  /*
3386  * At this point product_queries contains any DO ALSO rule
3387  * actions. Add the rewritten query before or after those. This
3388  * must match the handling the original query would have gotten
3389  * below, if we allowed it to be included again.
3390  */
3391  if (parsetree->commandType == CMD_INSERT)
3392  product_queries = lcons(parsetree, product_queries);
3393  else
3394  product_queries = lappend(product_queries, parsetree);
3395 
3396  /*
3397  * Set the "instead" flag, as if there had been an unqualified
3398  * INSTEAD, to prevent the original query from being included a
3399  * second time below. The transformation will have rewritten any
3400  * RETURNING list, so we can also set "returning" to forestall
3401  * throwing an error below.
3402  */
3403  instead = true;
3404  returning = true;
3405  updatableview = true;
3406  }
3407 
3408  /*
3409  * If we got any product queries, recursively rewrite them --- but
3410  * first check for recursion!
3411  */
3412  if (product_queries != NIL)
3413  {
3414  ListCell *n;
3415  rewrite_event *rev;
3416 
3417  foreach(n, rewrite_events)
3418  {
3419  rev = (rewrite_event *) lfirst(n);
3420  if (rev->relation == RelationGetRelid(rt_entry_relation) &&
3421  rev->event == event)
3422  ereport(ERROR,
3423  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
3424  errmsg("infinite recursion detected in rules for relation \"%s\"",
3425  RelationGetRelationName(rt_entry_relation))));
3426  }
3427 
3428  rev = (rewrite_event *) palloc(sizeof(rewrite_event));
3429  rev->relation = RelationGetRelid(rt_entry_relation);
3430  rev->event = event;
3431  rewrite_events = lcons(rev, rewrite_events);
3432 
3433  foreach(n, product_queries)
3434  {
3435  Query *pt = (Query *) lfirst(n);
3436  List *newstuff;
3437 
3438  newstuff = RewriteQuery(pt, rewrite_events);
3439  rewritten = list_concat(rewritten, newstuff);
3440  }
3441 
3442  rewrite_events = list_delete_first(rewrite_events);
3443  }
3444 
3445  /*
3446  * If there is an INSTEAD, and the original query has a RETURNING, we
3447  * have to have found a RETURNING in the rule(s), else fail. (Because
3448  * DefineQueryRewrite only allows RETURNING in unconditional INSTEAD
3449  * rules, there's no need to worry whether the substituted RETURNING
3450  * will actually be executed --- it must be.)
3451  */
3452  if ((instead || qual_product != NULL) &&
3453  parsetree->returningList &&
3454  !returning)
3455  {
3456  switch (event)
3457  {
3458  case CMD_INSERT:
3459  ereport(ERROR,
3460  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3461  errmsg("cannot perform INSERT RETURNING on relation \"%s\"",
3462  RelationGetRelationName(rt_entry_relation)),
3463  errhint("You need an unconditional ON INSERT DO INSTEAD rule with a RETURNING clause.")));
3464  break;
3465  case CMD_UPDATE:
3466  ereport(ERROR,
3467  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3468  errmsg("cannot perform UPDATE RETURNING on relation \"%s\"",
3469  RelationGetRelationName(rt_entry_relation)),
3470  errhint("You need an unconditional ON UPDATE DO INSTEAD rule with a RETURNING clause.")));
3471  break;
3472  case CMD_DELETE:
3473  ereport(ERROR,
3474  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3475  errmsg("cannot perform DELETE RETURNING on relation \"%s\"",
3476  RelationGetRelationName(rt_entry_relation)),
3477  errhint("You need an unconditional ON DELETE DO INSTEAD rule with a RETURNING clause.")));
3478  break;
3479  default:
3480  elog(ERROR, "unrecognized commandType: %d",
3481  (int) event);
3482  break;
3483  }
3484  }
3485 
3486  /*
3487  * Updatable views are supported by ON CONFLICT, so don't prevent that
3488  * case from proceeding
3489  */
3490  if (parsetree->onConflict &&
3491  (product_queries != NIL || hasUpdate) &&
3492  !updatableview)
3493  ereport(ERROR,
3494  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3495  errmsg("INSERT with ON CONFLICT clause cannot be used with table that has INSERT or UPDATE rules")));
3496 
3497  heap_close(rt_entry_relation, NoLock);
3498  }
3499 
3500  /*
3501  * For INSERTs, the original query is done first; for UPDATE/DELETE, it is
3502  * done last. This is needed because update and delete rule actions might
3503  * not do anything if they are invoked after the update or delete is
3504  * performed. The command counter increment between the query executions
3505  * makes the deleted (and maybe the updated) tuples disappear so the scans
3506  * for them in the rule actions cannot find them.
3507  *
3508  * If we found any unqualified INSTEAD, the original query is not done at
3509  * all, in any form. Otherwise, we add the modified form if qualified
3510  * INSTEADs were found, else the unmodified form.
3511  */
3512  if (!instead)
3513  {
3514  if (parsetree->commandType == CMD_INSERT)
3515  {
3516  if (qual_product != NULL)
3517  rewritten = lcons(qual_product, rewritten);
3518  else
3519  rewritten = lcons(parsetree, rewritten);
3520  }
3521  else
3522  {
3523  if (qual_product != NULL)
3524  rewritten = lappend(rewritten, qual_product);
3525  else
3526  rewritten = lappend(rewritten, parsetree);
3527  }
3528  }
3529 
3530  /*
3531  * If the original query has a CTE list, and we generated more than one
3532  * non-utility result query, we have to fail because we'll have copied the
3533  * CTE list into each result query. That would break the expectation of
3534  * single evaluation of CTEs. This could possibly be fixed by
3535  * restructuring so that a CTE list can be shared across multiple Query
3536  * and PlannableStatement nodes.
3537  */
3538  if (parsetree->cteList != NIL)
3539  {
3540  int qcount = 0;
3541 
3542  foreach(lc1, rewritten)
3543  {
3544  Query *q = (Query *) lfirst(lc1);
3545 
3546  if (q->commandType != CMD_UTILITY)
3547  qcount++;
3548  }
3549  if (qcount > 1)
3550  ereport(ERROR,
3551  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3552  errmsg("WITH cannot be used in a query that is rewritten by rules into multiple queries")));
3553  }
3554 
3555  return rewritten;
3556 }
#define NIL
Definition: pg_list.h:69
#define IsA(nodeptr, _type_)
Definition: nodes.h:568
int errhint(const char *fmt,...)
Definition: elog.c:987
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:586
int resultRelation
Definition: parsenodes.h:122
Definition: nodes.h:517
static List * RewriteQuery(Query *parsetree, List *rewrite_events)
int errcode(int sqlerrcode)
Definition: elog.c:575
List * list_concat(List *list1, List *list2)
Definition: list.c:321
static void rewriteValuesRTE(RangeTblEntry *rte, Relation target_relation, List *attrnos)
List * fromlist
Definition: primnodes.h:1479
#define heap_close(r, l)
Definition: heapam.h:97
Form_pg_class rd_rel
Definition: rel.h:84
#define linitial_node(type, l)
Definition: pg_list.h:114
static List * rewriteTargetListIU(List *targetList, CmdType commandType, OverridingKind override, Relation target_relation, int result_rti, List **attrno_list)
List * targetList
Definition: parsenodes.h:140
#define linitial(l)
Definition: pg_list.h:111
List * rtable
Definition: parsenodes.h:137
#define ERROR
Definition: elog.h:43
#define lfirst_node(type, lc)
Definition: pg_list.h:109
#define NoLock
Definition: lockdefs.h:34
static Query * rewriteTargetView(Query *parsetree, Relation view)
#define RelationGetRelationName(relation)
Definition: rel.h:441
List * returningList
Definition: parsenodes.h:146
#define ereport(elevel, rest)
Definition: elog.h:122
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
List * lappend(List *list, void *datum)
Definition: list.c:128
OnConflictAction action
Definition: primnodes.h:1495
static List * fireRules(Query *parsetree, int rt_index, CmdType event, List *locks, bool *instead_flag, bool *returning_flag, Query **qual_product)
OverridingKind override
Definition: parsenodes.h:142
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1294
CmdType commandType
Definition: parsenodes.h:112
List * lcons(void *datum, List *list)
Definition: list.c:259
QuerySource querySource
Definition: parsenodes.h:114
#define Assert(condition)
Definition: c.h:699
#define lfirst(lc)
Definition: pg_list.h:106
RuleLock * rd_rules
Definition: rel.h:88
bool canSetTag
Definition: parsenodes.h:118
static int list_length(const List *l)
Definition: pg_list.h:89
RTEKind rtekind
Definition: parsenodes.h:962
List * cteList
Definition: parsenodes.h:135
void * palloc(Size size)
Definition: mcxt.c:924
int errmsg(const char *fmt,...)
Definition: elog.c:797
List * onConflictSet
Definition: primnodes.h:1504
#define elog
Definition: elog.h:219
Definition: pg_list.h:45
static List * matchLocks(CmdType event, RuleLock *rulelocks, int varno, Query *parsetree, bool *hasUpdate)
#define RelationGetRelid(relation)
Definition: rel.h:407
CmdType
Definition: nodes.h:657
List * list_delete_first(List *list)
Definition: list.c:666

◆ rewriteRuleAction()

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

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

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

◆ rewriteTargetListIU()

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

Definition at line 716 of file rewriteHandler.c.

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

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

◆ rewriteTargetListUD()

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

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

1312 {
1313  Var *var = NULL;
1314  const char *attrname;
1315  TargetEntry *tle;
1316 
1317  if (target_relation->rd_rel->relkind == RELKIND_RELATION ||
1318  target_relation->rd_rel->relkind == RELKIND_MATVIEW ||
1319  target_relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1320  {
1321  /*
1322  * Emit CTID so that executor can find the row to update or delete.
1323  */
1324  var = makeVar(parsetree->resultRelation,
1326  TIDOID,
1327  -1,
1328  InvalidOid,
1329  0);
1330 
1331  attrname = "ctid";
1332  }
1333  else if (target_relation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
1334  {
1335  /*
1336  * Let the foreign table's FDW add whatever junk TLEs it wants.
1337  */
1338  FdwRoutine *fdwroutine;
1339 
1340  fdwroutine = GetFdwRoutineForRelation(target_relation, false);
1341 
1342  if (fdwroutine->AddForeignUpdateTargets != NULL)
1343  fdwroutine->AddForeignUpdateTargets(parsetree, target_rte,
1344  target_relation);
1345 
1346  /*
1347  * If we have a row-level trigger corresponding to the operation, emit
1348  * a whole-row Var so that executor will have the "old" row to pass to
1349  * the trigger. Alas, this misses system columns.
1350  */
1351  if (target_relation->trigdesc &&
1352  ((parsetree->commandType == CMD_UPDATE &&
1353  (target_relation->trigdesc->trig_update_after_row ||
1354  target_relation->trigdesc->trig_update_before_row)) ||
1355  (parsetree->commandType == CMD_DELETE &&
1356  (target_relation->trigdesc->trig_delete_after_row ||
1357  target_relation->trigdesc->trig_delete_before_row))))
1358  {
1359  var = makeWholeRowVar(target_rte,
1360  parsetree->resultRelation,
1361  0,
1362  false);
1363 
1364  attrname = "wholerow";
1365  }
1366  }
1367 
1368  if (var != NULL)
1369  {
1370  tle = makeTargetEntry((Expr *) var,
1371  list_length(parsetree->targetList) + 1,
1372  pstrdup(attrname),
1373  true);
1374 
1375  parsetree->targetList = lappend(parsetree->targetList, tle);
1376  }
1377 }
char * pstrdup(const char *in)
Definition: mcxt.c:1161
int resultRelation
Definition: parsenodes.h:122
Var * makeWholeRowVar(RangeTblEntry *rte, Index varno, Index varlevelsup, bool allowScalar)
Definition: makefuncs.c:134
Form_pg_class rd_rel
Definition: rel.h:84
Definition: primnodes.h:164
AddForeignUpdateTargets_function AddForeignUpdateTargets
Definition: fdwapi.h:207
List * targetList
Definition: parsenodes.h:140
TriggerDesc * trigdesc
Definition: rel.h:90
bool trig_delete_after_row
Definition: reltrigger.h:66
bool trig_update_before_row
Definition: reltrigger.h:60
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:237
Var * makeVar(Index varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:67
bool trig_update_after_row
Definition: reltrigger.h:61
List * lappend(List *list, void *datum)
Definition: list.c:128
#define InvalidOid
Definition: postgres_ext.h:36
CmdType commandType
Definition: parsenodes.h:112
static int list_length(const List *l)
Definition: pg_list.h:89
FdwRoutine * GetFdwRoutineForRelation(Relation relation, bool makecopy)
Definition: foreign.c:395
#define SelfItemPointerAttributeNumber
Definition: sysattr.h:21
bool trig_delete_before_row
Definition: reltrigger.h:65

◆ rewriteTargetView()

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

Definition at line 2716 of file rewriteHandler.c.

References _, acquireLocksOnSubLinks(), AddQual(), adjust_view_column_set(), Assert, bms_add_member(), bms_is_empty(), 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, heap_close, heap_open(), RangeTblEntry::inh, RangeTblEntry::insertedCols, IsA, Query::jointree, WithCheckOption::kind, lappend(), lcons(), lfirst, linitial, linitial_node, list_length(), makeNode, NIL, NoLock, Query::onConflict, OnConflictExpr::onConflictSet, 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, 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, Query::targetList, RangeTblEntry::updatedCols, view_cols_are_auto_updatable(), view_query_is_auto_updatable(), and WCO_VIEW_CHECK.

Referenced by RewriteQuery().

2717 {
2718  Query *viewquery;
2719  const char *auto_update_detail;
2720  RangeTblRef *rtr;
2721  int base_rt_index;
2722  int new_rt_index;
2723  RangeTblEntry *base_rte;
2724  RangeTblEntry *view_rte;
2725  RangeTblEntry *new_rte;
2726  Relation base_rel;
2727  List *view_targetlist;
2728  ListCell *lc;
2729 
2730  /*
2731  * Get the Query from the view's ON SELECT rule. We're going to munge the
2732  * Query to change the view's base relation into the target relation,
2733  * along with various other changes along the way, so we need to make a
2734  * copy of it (get_view_query() returns a pointer into the relcache, so we
2735  * have to treat it as read-only).
2736  */
2737  viewquery = copyObject(get_view_query(view));
2738 
2739  /* The view must be updatable, else fail */
2740  auto_update_detail =
2741  view_query_is_auto_updatable(viewquery,
2742  parsetree->commandType != CMD_DELETE);
2743 
2744  if (auto_update_detail)
2745  {
2746  /* messages here should match execMain.c's CheckValidResultRel */
2747  switch (parsetree->commandType)
2748  {
2749  case CMD_INSERT:
2750  ereport(ERROR,
2751  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
2752  errmsg("cannot insert into view \"%s\"",
2753  RelationGetRelationName(view)),
2754  errdetail_internal("%s", _(auto_update_detail)),
2755  errhint("To enable inserting into the view, provide an INSTEAD OF INSERT trigger or an unconditional ON INSERT DO INSTEAD rule.")));
2756  break;
2757  case CMD_UPDATE:
2758  ereport(ERROR,
2759  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
2760  errmsg("cannot update view \"%s\"",
2761  RelationGetRelationName(view)),
2762  errdetail_internal("%s", _(auto_update_detail)),
2763  errhint("To enable updating the view, provide an INSTEAD OF UPDATE trigger or an unconditional ON UPDATE DO INSTEAD rule.")));
2764  break;
2765  case CMD_DELETE:
2766  ereport(ERROR,
2767  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
2768  errmsg("cannot delete from view \"%s\"",
2769  RelationGetRelationName(view)),
2770  errdetail_internal("%s", _(auto_update_detail)),
2771  errhint("To enable deleting from the view, provide an INSTEAD OF DELETE trigger or an unconditional ON DELETE DO INSTEAD rule.")));
2772  break;
2773  default:
2774  elog(ERROR, "unrecognized CmdType: %d",
2775  (int) parsetree->commandType);
2776  break;
2777  }
2778  }
2779 
2780  /*
2781  * For INSERT/UPDATE the modified columns must all be updatable. Note that
2782  * we get the modified columns from the query's targetlist, not from the
2783  * result RTE's insertedCols and/or updatedCols set, since
2784  * rewriteTargetListIU may have added additional targetlist entries for
2785  * view defaults, and these must also be updatable.
2786  */
2787  if (parsetree->commandType != CMD_DELETE)
2788  {
2789  Bitmapset *modified_cols = NULL;
2790  char *non_updatable_col;
2791 
2792  foreach(lc, parsetree->targetList)
2793  {
2794  TargetEntry *tle = (TargetEntry *) lfirst(lc);
2795 
2796  if (!tle->resjunk)
2797  modified_cols = bms_add_member(modified_cols,
2799  }
2800 
2801  if (parsetree->onConflict)
2802  {
2803  foreach(lc, parsetree->onConflict->onConflictSet)
2804  {
2805  TargetEntry *tle = (TargetEntry *) lfirst(lc);
2806 
2807  if (!tle->resjunk)
2808  modified_cols = bms_add_member(modified_cols,
2810  }
2811  }
2812 
2813  auto_update_detail = view_cols_are_auto_updatable(viewquery,
2814  modified_cols,
2815  NULL,
2816  &non_updatable_col);
2817  if (auto_update_detail)
2818  {
2819  /*
2820  * This is a different error, caused by an attempt to update a
2821  * non-updatable column in an otherwise updatable view.
2822  */
2823  switch (parsetree->commandType)
2824  {
2825  case CMD_INSERT:
2826  ereport(ERROR,
2827  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2828  errmsg("cannot insert into column \"%s\" of view \"%s\"",
2829  non_updatable_col,
2830  RelationGetRelationName(view)),
2831  errdetail_internal("%s", _(auto_update_detail))));
2832  break;
2833  case CMD_UPDATE:
2834  ereport(ERROR,
2835  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2836  errmsg("cannot update column \"%s\" of view \"%s\"",
2837  non_updatable_col,
2838  RelationGetRelationName(view)),
2839  errdetail_internal("%s", _(auto_update_detail))));
2840  break;
2841  default:
2842  elog(ERROR, "unrecognized CmdType: %d",
2843  (int) parsetree->commandType);
2844  break;
2845  }
2846  }
2847  }
2848 
2849  /* Locate RTE describing the view in the outer query */
2850  view_rte = rt_fetch(parsetree->resultRelation, parsetree->rtable);
2851 
2852  /*
2853  * If we get here, view_query_is_auto_updatable() has verified that the
2854  * view contains a single base relation.
2855  */
2856  Assert(list_length(viewquery->jointree->fromlist) == 1);
2857  rtr = linitial_node(RangeTblRef, viewquery->jointree->fromlist);
2858 
2859  base_rt_index = rtr->rtindex;
2860  base_rte = rt_fetch(base_rt_index, viewquery->rtable);
2861  Assert(base_rte->rtekind == RTE_RELATION);
2862 
2863  /*
2864  * Up to now, the base relation hasn't been touched at all in our query.
2865  * We need to acquire lock on it before we try to do anything with it.
2866  * (The subsequent recursive call of RewriteQuery will suppose that we
2867  * already have the right lock!) Since it will become the query target
2868  * relation, RowExclusiveLock is always the right thing.
2869  */
2870  base_rel = heap_open(base_rte->relid, RowExclusiveLock);
2871 
2872  /*
2873  * While we have the relation open, update the RTE's relkind, just in case
2874  * it changed since this view was made (cf. AcquireRewriteLocks).
2875  */
2876  base_rte->relkind = base_rel->rd_rel->relkind;
2877 
2878  heap_close(base_rel, NoLock);
2879 
2880  /*
2881  * If the view query contains any sublink subqueries then we need to also
2882  * acquire locks on any relations they refer to. We know that there won't
2883  * be any subqueries in the range table or CTEs, so we can skip those, as
2884  * in AcquireRewriteLocks.
2885  */
2886  if (viewquery->hasSubLinks)
2887  {
2889 
2890  context.for_execute = true;
2891  query_tree_walker(viewquery, acquireLocksOnSubLinks, &context,
2893  }
2894 
2895  /*
2896  * Create a new target RTE describing the base relation, and add it to the
2897  * outer query's rangetable. (What's happening in the next few steps is
2898  * very much like what the planner would do to "pull up" the view into the
2899  * outer query. Perhaps someday we should refactor things enough so that
2900  * we can share code with the planner.)
2901  */
2902  new_rte = (RangeTblEntry *) base_rte;
2903  parsetree->rtable = lappend(parsetree->rtable, new_rte);
2904  new_rt_index = list_length(parsetree->rtable);
2905 
2906  /*
2907  * INSERTs never inherit. For UPDATE/DELETE, we use the view query's
2908  * inheritance flag for the base relation.
2909  */
2910  if (parsetree->commandType == CMD_INSERT)
2911  new_rte->inh = false;
2912 
2913  /*
2914  * Adjust the view's targetlist Vars to reference the new target RTE, ie
2915  * make their varnos be new_rt_index instead of base_rt_index. There can
2916  * be no Vars for other rels in the tlist, so this is sufficient to pull
2917  * up the tlist expressions for use in the outer query. The tlist will
2918  * provide the replacement expressions used by ReplaceVarsFromTargetList
2919  * below.
2920  */
2921  view_targetlist = viewquery->targetList;
2922 
2923  ChangeVarNodes((Node *) view_targetlist,
2924  base_rt_index,
2925  new_rt_index,
2926  0);
2927 
2928  /*
2929  * Mark the new target RTE for the permissions checks that we want to
2930  * enforce against the view owner, as distinct from the query caller. At
2931  * the relation level, require the same INSERT/UPDATE/DELETE permissions
2932  * that the query caller needs against the view. We drop the ACL_SELECT
2933  * bit that is presumably in new_rte->requiredPerms initially.
2934  *
2935  * Note: the original view RTE remains in the query's rangetable list.
2936  * Although it will be unused in the query plan, we need it there so that
2937  * the executor still performs appropriate permissions checks for the
2938  * query caller's use of the view.
2939  */
2940  new_rte->checkAsUser = view->rd_rel->relowner;
2941  new_rte->requiredPerms = view_rte->requiredPerms;
2942 
2943  /*
2944  * Now for the per-column permissions bits.
2945  *
2946  * Initially, new_rte contains selectedCols permission check bits for all
2947  * base-rel columns referenced by the view, but since the view is a SELECT
2948  * query its insertedCols/updatedCols is empty. We set insertedCols and
2949  * updatedCols to include all the columns the outer query is trying to
2950  * modify, adjusting the column numbers as needed. But we leave
2951  * selectedCols as-is, so the view owner must have read permission for all
2952  * columns used in the view definition, even if some of them are not read
2953  * by the outer query. We could try to limit selectedCols to only columns
2954  * used in the transformed query, but that does not correspond to what
2955  * happens in ordinary SELECT usage of a view: all referenced columns must
2956  * have read permission, even if optimization finds that some of them can
2957  * be discarded during query transformation. The flattening we're doing
2958  * here is an optional optimization, too. (If you are unpersuaded and
2959  * want to change this, note that applying adjust_view_column_set to
2960  * view_rte->selectedCols is clearly *not* the right answer, since that
2961  * neglects base-rel columns used in the view's WHERE quals.)
2962  *
2963  * This step needs the modified view targetlist, so we have to do things
2964  * in this order.
2965  */
2966  Assert(bms_is_empty(new_rte->insertedCols) &&
2967  bms_is_empty(new_rte->updatedCols));
2968 
2969  new_rte->insertedCols = adjust_view_column_set(view_rte->insertedCols,
2970  view_targetlist);
2971 
2972  new_rte->updatedCols = adjust_view_column_set(view_rte->updatedCols,
2973  view_targetlist);
2974 
2975  /*
2976  * Move any security barrier quals from the view RTE onto the new target
2977  * RTE. Any such quals should now apply to the new target RTE and will
2978  * not reference the original view RTE in the rewritten query.
2979  */
2980  new_rte->securityQuals = view_rte->securityQuals;
2981  view_rte->securityQuals = NIL;
2982 
2983  /*
2984  * Now update all Vars in the outer query that reference the view to
2985  * reference the appropriate column of the base relation instead.
2986  */
2987  parsetree = (Query *)
2988  ReplaceVarsFromTargetList((Node *) parsetree,
2989  parsetree->resultRelation,
2990  0,
2991  view_rte,
2992  view_targetlist,
2994  0,
2995  &parsetree->hasSubLinks);
2996 
2997  /*
2998  * Update all other RTI references in the query that point to the view
2999  * (for example, parsetree->resultRelation itself) to point to the new
3000  * base relation instead. Vars will not be affected since none of them
3001  * reference parsetree->resultRelation any longer.
3002  */
3003  ChangeVarNodes((Node *) parsetree,
3004  parsetree->resultRelation,
3005  new_rt_index,
3006  0);
3007  Assert(parsetree->resultRelation == new_rt_index);
3008 
3009  /*
3010  * For INSERT/UPDATE we must also update resnos in the targetlist to refer
3011  * to columns of the base relation, since those indicate the target
3012  * columns to be affected.
3013  *
3014  * Note that this destroys the resno ordering of the targetlist, but that
3015  * will be fixed when we recurse through rewriteQuery, which will invoke
3016  * rewriteTargetListIU again on the updated targetlist.
3017  */
3018  if (parsetree->commandType != CMD_DELETE)
3019  {
3020  foreach(lc, parsetree->targetList)
3021  {
3022  TargetEntry *tle = (TargetEntry *) lfirst(lc);
3023  TargetEntry *view_tle;
3024 
3025  if (tle->resjunk)
3026  continue;
3027 
3028  view_tle = get_tle_by_resno(view_targetlist, tle->resno);
3029  if (view_tle != NULL && !view_tle->resjunk && IsA(view_tle->expr, Var))
3030  tle->resno = ((Var *) view_tle->expr)->varattno;
3031  else
3032  elog(ERROR, "attribute number %d not found in view targetlist",
3033  tle->resno);
3034  }
3035  }
3036 
3037  /*
3038  * For UPDATE/DELETE, pull up any WHERE quals from the view. We know that
3039  * any Vars in the quals must reference the one base relation, so we need
3040  * only adjust their varnos to reference the new target (just the same as
3041  * we did with the view targetlist).
3042  *
3043  * If it's a security-barrier view, its WHERE quals must be applied before
3044  * quals from the outer query, so we attach them to the RTE as security
3045  * barrier quals rather than adding them to the main WHERE clause.
3046  *
3047  * For INSERT, the view's quals can be ignored in the main query.
3048  */
3049  if (parsetree->commandType != CMD_INSERT &&
3050  viewquery->jointree->quals != NULL)
3051  {
3052  Node *viewqual = (Node *) viewquery->jointree->quals;
3053 
3054  /*
3055  * Even though we copied viewquery already at the top of this
3056  * function, we must duplicate the viewqual again here, because we may
3057  * need to use the quals again below for a WithCheckOption clause.
3058  */
3059  viewqual = copyObject(viewqual);
3060 
3061  ChangeVarNodes(viewqual, base_rt_index, new_rt_index, 0);
3062 
3063  if (RelationIsSecurityView(view))
3064  {
3065  /*
3066  * The view's quals go in front of existing barrier quals: those
3067  * would have come from an outer level of security-barrier view,
3068  * and so must get evaluated later.
3069  *
3070  * Note: the parsetree has been mutated, so the new_rte pointer is
3071  * stale and needs to be re-computed.
3072  */
3073  new_rte = rt_fetch(new_rt_index, parsetree->rtable);
3074  new_rte->securityQuals = lcons(viewqual, new_rte->securityQuals);
3075 
3076  /*
3077  * Do not set parsetree->hasRowSecurity, because these aren't RLS
3078  * conditions (they aren't affected by enabling/disabling RLS).
3079  */
3080 
3081  /*
3082  * Make sure that the query is marked correctly if the added qual
3083  * has sublinks.
3084  */
3085  if (!parsetree->hasSubLinks)
3086  parsetree->hasSubLinks = checkExprHasSubLink(viewqual);
3087  }
3088  else
3089  AddQual(parsetree, (Node *) viewqual);
3090  }
3091 
3092  /*
3093  * For INSERT/UPDATE, if the view has the WITH CHECK OPTION, or any parent
3094  * view specified WITH CASCADED CHECK OPTION, add the quals from the view
3095  * to the query's withCheckOptions list.
3096  */
3097  if (parsetree->commandType != CMD_DELETE)
3098  {
3099  bool has_wco = RelationHasCheckOption(view);
3100  bool cascaded = RelationHasCascadedCheckOption(view);
3101 
3102  /*
3103  * If the parent view has a cascaded check option, treat this view as
3104  * if it also had a cascaded check option.
3105  *
3106  * New WithCheckOptions are added to the start of the list, so if
3107  * there is a cascaded check option, it will be the first item in the
3108  * list.
3109  */
3110  if (parsetree->withCheckOptions != NIL)
3111  {
3112  WithCheckOption *parent_wco =
3113  (WithCheckOption *) linitial(parsetree->withCheckOptions);
3114 
3115  if (parent_wco->cascaded)
3116  {
3117  has_wco = true;
3118  cascaded = true;
3119  }
3120  }
3121 
3122  /*
3123  * Add the new WithCheckOption to the start of the list, so that
3124  * checks on inner views are run before checks on outer views, as
3125  * required by the SQL standard.
3126  *
3127  * If the new check is CASCADED, we need to add it even if this view
3128  * has no quals, since there may be quals on child views. A LOCAL
3129  * check can be omitted if this view has no quals.
3130  */
3131  if (has_wco && (cascaded || viewquery->jointree->quals != NULL))
3132  {
3133  WithCheckOption *wco;
3134 
3135  wco = makeNode(WithCheckOption);
3136  wco->kind = WCO_VIEW_CHECK;
3137  wco->relname = pstrdup(RelationGetRelationName(view));
3138  wco->polname = NULL;
3139  wco->qual = NULL;
3140  wco->cascaded = cascaded;
3141 
3142  parsetree->withCheckOptions = lcons(wco,
3143  parsetree->withCheckOptions);
3144 
3145  if (viewquery->jointree->quals != NULL)
3146  {
3147  wco->qual = (Node *) viewquery->jointree->quals;
3148  ChangeVarNodes(wco->qual, base_rt_index, new_rt_index, 0);
3149 
3150  /*
3151  * Make sure that the query is marked correctly if the added
3152  * qual has sublinks. We can skip this check if the query is
3153  * already marked, or if the command is an UPDATE, in which
3154  * case the same qual will have already been added, and this
3155  * check will already have been done.
3156  */
3157  if (!parsetree->hasSubLinks &&
3158  parsetree->commandType != CMD_UPDATE)
3159  parsetree->hasSubLinks = checkExprHasSubLink(wco->qual);
3160  }
3161  }
3162  }
3163 
3164  return parsetree;
3165 }
#define NIL
Definition: pg_list.h:69
bool query_tree_walker(Query *query, bool(*walker)(), void *context, int flags)
Definition: nodeFuncs.c:2256
#define IsA(nodeptr, _type_)
Definition: nodes.h:568
int errhint(const char *fmt,...)
Definition: elog.c:987
static bool acquireLocksOnSubLinks(Node *node, acquireLocksOnSubLinks_context *context)
FromExpr * jointree
Definition: parsenodes.h:138
bool checkExprHasSubLink(Node *node)
Definition: rewriteManip.c:277
OnConflictExpr * onConflict
Definition: parsenodes.h:144
List * withCheckOptions
Definition: parsenodes.h:171
List * securityQuals
Definition: parsenodes.h:1075
char * pstrdup(const char *in)
Definition: mcxt.c:1161
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
Definition: nodes.h:517
int errcode(int sqlerrcode)
Definition: elog.c:575
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:28
AclMode requiredPerms
Definition: parsenodes.h:1070
List * fromlist
Definition: primnodes.h:1479
#define heap_close(r, l)
Definition: heapam.h:97
Form_pg_class rd_rel
Definition: rel.h:84
Definition: primnodes.h:164
#define linitial_node(type, l)
Definition: pg_list.h:114
Node * quals
Definition: primnodes.h:1480
int errdetail_internal(const char *fmt,...)
Definition: elog.c:900
List * targetList
Definition: parsenodes.h:140
#define QTW_IGNORE_RC_SUBQUERIES
Definition: nodeFuncs.h:22
bool resjunk
Definition: primnodes.h:1383
#define linitial(l)
Definition: pg_list.h:111
List * rtable
Definition: parsenodes.h:137
#define ERROR
Definition: elog.h:43
#define NoLock
Definition: lockdefs.h:34
#define RowExclusiveLock
Definition: lockdefs.h:38
AttrNumber resno
Definition: primnodes.h:1377
#define RelationGetRelationName(relation)
Definition: rel.h:441
#define ereport(elevel, rest)
Definition: elog.h:122
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
List * lappend(List *list, void *datum)
Definition: list.c:128
bool bms_is_empty(const Bitmapset *a)
Definition: bitmapset.c:729
Node * ReplaceVarsFromTargetList(Node *node, int target_varno, int sublevels_up, RangeTblEntry *target_rte, List *targetlist, ReplaceVarsNoMatchOption nomatch_option, int nomatch_varno, bool *outer_hasSubLinks)
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1294
Bitmapset * updatedCols
Definition: parsenodes.h:1074
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:259
#define makeNode(_type_)
Definition: nodes.h:565
#define Assert(condition)
Definition: c.h:699
#define lfirst(lc)
Definition: pg_list.h:106
void AddQual(Query *parsetree, Node *qual)
Definition: rewriteManip.c:976
Expr * expr
Definition: primnodes.h:1376
static int list_length(const List *l)
Definition: pg_list.h:89
#define RelationHasCascadedCheckOption(relation)
Definition: rel.h:368
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:764
RTEKind rtekind
Definition: parsenodes.h:962
int errmsg(const char *fmt,...)
Definition: elog.c:797
bool hasSubLinks
Definition: parsenodes.h:128
Query * get_view_query(Relation view)
Bitmapset * insertedCols
Definition: parsenodes.h:1073
#define RelationIsSecurityView(relation)
Definition: rel.h:338
TargetEntry * get_tle_by_resno(List *tlist, AttrNumber resno)
List * onConflictSet
Definition: primnodes.h:1504
void ChangeVarNodes(Node *node, int rt_index, int new_index, int sublevels_up)
Definition: rewriteManip.c:607
#define elog
Definition: elog.h:219
#define copyObject(obj)
Definition: nodes.h:630
const char * view_query_is_auto_updatable(Query *viewquery, bool check_cols)
Definition: pg_list.h:45
#define _(x)
Definition: elog.c:84
#define RelationHasCheckOption(relation)
Definition: rel.h:347

◆ rewriteValuesRTE()

static void rewriteValuesRTE ( RangeTblEntry rte,
Relation  target_relation,
List attrnos 
)
static

Definition at line 1221 of file rewriteHandler.c.

References Assert, build_column_default(), COERCE_IMPLICIT_CAST, coerce_to_domain(), COERCION_IMPLICIT, forboth, InvalidOid, IsA, lappend(), lfirst, lfirst_int, linitial, list_length(), makeConst(), NIL, RelationData::rd_att, searchForDefault(), TupleDescAttr, and RangeTblEntry::values_lists.

Referenced by RewriteQuery().

1222 {
1223  List *newValues;
1224  ListCell *lc;
1225 
1226  /*
1227  * Rebuilding all the lists is a pretty expensive proposition in a big
1228  * VALUES list, and it's a waste of time if there aren't any DEFAULT
1229  * placeholders. So first scan to see if there are any.
1230  */
1231  if (!searchForDefault(rte))
1232  return; /* nothing to do */
1233 
1234  /* Check list lengths (we can assume all the VALUES sublists are alike) */
1235  Assert(list_length(attrnos) == list_length(linitial(rte->values_lists)));
1236 
1237  newValues = NIL;
1238  foreach(lc, rte->values_lists)
1239  {
1240  List *sublist = (List *) lfirst(lc);
1241  List *newList = NIL;
1242  ListCell *lc2;
1243  ListCell *lc3;
1244 
1245  forboth(lc2, sublist, lc3, attrnos)
1246  {
1247  Node *col = (Node *) lfirst(lc2);
1248  int attrno = lfirst_int(lc3);
1249 
1250  if (IsA(col, SetToDefault))
1251  {
1252  Form_pg_attribute att_tup;
1253  Node *new_expr;
1254 
1255  att_tup = TupleDescAttr(target_relation->rd_att, attrno - 1);
1256 
1257  if (!att_tup->attisdropped)
1258  new_expr = build_column_default(target_relation, attrno);
1259  else
1260  new_expr = NULL; /* force a NULL if dropped */
1261 
1262  /*
1263  * If there is no default (ie, default is effectively NULL),
1264  * we've got to explicitly set the column to NULL.
1265  */
1266  if (!new_expr)
1267  {
1268  new_expr = (Node *) makeConst(att_tup->atttypid,
1269  -1,
1270  att_tup->attcollation,
1271  att_tup->attlen,
1272  (Datum) 0,
1273  true, /* isnull */
1274  att_tup->attbyval);
1275  /* this is to catch a NOT NULL domain constraint */
1276  new_expr = coerce_to_domain(new_expr,
1277  InvalidOid, -1,
1278  att_tup->atttypid,
1281  -1,
1282  false);
1283  }
1284  newList = lappend(newList, new_expr);
1285  }
1286  else
1287  newList = lappend(newList, col);
1288  }
1289  newValues = lappend(newValues, newList);
1290  }
1291  rte->values_lists = newValues;
1292 }
#define NIL
Definition: pg_list.h:69
#define IsA(nodeptr, _type_)
Definition: nodes.h:568
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:180
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:93
Definition: nodes.h:517
Const * makeConst(Oid consttype, int32 consttypmod, Oid constcollid, int constlen, Datum constvalue, bool constisnull, bool constbyval)
Definition: makefuncs.c:298
List * values_lists
Definition: parsenodes.h:1027
#define linitial(l)
Definition: pg_list.h:111
static bool searchForDefault(RangeTblEntry *rte)
#define lfirst_int(lc)
Definition: pg_list.h:107
Node * coerce_to_domain(Node *arg, Oid baseTypeId, int32 baseTypeMod, Oid typeId, CoercionContext ccontext, CoercionForm cformat, int location, bool hideInputCoercion)
Definition: parse_coerce.c:663
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:197
List * lappend(List *list, void *datum)
Definition: list.c:128
Node * build_column_default(Relation rel, int attrno)
uintptr_t Datum
Definition: postgres.h:367
TupleDesc rd_att
Definition: rel.h:85
#define InvalidOid
Definition: postgres_ext.h:36
#define Assert(condition)
Definition: c.h:699
#define lfirst(lc)
Definition: pg_list.h:106
static int list_length(const List *l)
Definition: pg_list.h:89
Definition: pg_list.h:45

◆ searchForDefault()

static bool searchForDefault ( RangeTblEntry rte)
static

Definition at line 1189 of file rewriteHandler.c.

References IsA, lfirst, and RangeTblEntry::values_lists.

Referenced by rewriteValuesRTE().

1190 {
1191  ListCell *lc;
1192 
1193  foreach(lc, rte->values_lists)
1194  {
1195  List *sublist = (List *) lfirst(lc);
1196  ListCell *lc2;
1197 
1198  foreach(lc2, sublist)
1199  {
1200  Node *col = (Node *) lfirst(lc2);
1201 
1202  if (IsA(col, SetToDefault))
1203  return true;
1204  }
1205  }
1206  return false;
1207 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:568
Definition: nodes.h:517
List * values_lists
Definition: parsenodes.h:1027
#define lfirst(lc)
Definition: pg_list.h:106
Definition: pg_list.h:45

◆ view_col_is_auto_updatable()

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

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

2213 {
2214  Var *var = (Var *) tle->expr;
2215 
2216  /*
2217  * For now, the only updatable columns we support are those that are Vars
2218  * referring to user columns of the underlying base relation.
2219  *
2220  * The view targetlist may contain resjunk columns (e.g., a view defined
2221  * like "SELECT * FROM t ORDER BY a+b" is auto-updatable) but such columns
2222  * are not auto-updatable, and in fact should never appear in the outer
2223  * query's targetlist.
2224  */
2225  if (tle->resjunk)
2226  return gettext_noop("Junk view columns are not updatable.");
2227 
2228  if (!IsA(var, Var) ||
2229  var->varno != rtr->rtindex ||
2230  var->varlevelsup != 0)
2231  return gettext_noop("View columns that are not columns of their base relation are not updatable.");
2232 
2233  if (var->varattno < 0)
2234  return gettext_noop("View columns that refer to system columns are not updatable.");
2235 
2236  if (var->varattno == 0)
2237  return gettext_noop("View columns that return whole-row references are not updatable.");
2238 
2239  return NULL; /* the view column is updatable */
2240 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:568
Index varlevelsup
Definition: primnodes.h:174
#define gettext_noop(x)
Definition: c.h:1036
AttrNumber varattno
Definition: primnodes.h:169
Definition: primnodes.h:164
bool resjunk
Definition: primnodes.h:1383
Index varno
Definition: primnodes.h:167
Expr * expr
Definition: primnodes.h:1376

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

2406 {
2407  RangeTblRef *rtr;
2408  AttrNumber col;
2409  ListCell *cell;
2410 
2411  /*
2412  * The caller should have verified that this view is auto-updatable and so
2413  * there should be a single base relation.
2414  */
2415  Assert(list_length(viewquery->jointree->fromlist) == 1);
2416  rtr = linitial_node(RangeTblRef, viewquery->jointree->fromlist);
2417 
2418  /* Initialize the optional return values */
2419  if (updatable_cols != NULL)
2420  *updatable_cols = NULL;
2421  if (non_updatable_col != NULL)
2422  *non_updatable_col = NULL;
2423 
2424  /* Test each view column for updatability */
2426  foreach(cell, viewquery->targetList)
2427  {
2428  TargetEntry *tle = (TargetEntry *) lfirst(cell);
2429  const char *col_update_detail;
2430 
2431  col++;
2432  col_update_detail = view_col_is_auto_updatable(rtr, tle);
2433 
2434  if (col_update_detail == NULL)
2435  {
2436  /* The column is updatable */
2437  if (updatable_cols != NULL)
2438  *updatable_cols = bms_add_member(*updatable_cols, col);
2439  }
2440  else if (bms_is_member(col, required_cols))
2441  {
2442  /* The required column is not updatable */
2443  if (non_updatable_col != NULL)
2444  *non_updatable_col = tle->resname;
2445  return col_update_detail;
2446  }
2447  }
2448 
2449  return NULL; /* all the required view columns are updatable */
2450 }
FromExpr * jointree
Definition: parsenodes.h:138
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:28
List * fromlist
Definition: primnodes.h:1479
char * resname
Definition: primnodes.h:1378
#define linitial_node(type, l)
Definition: pg_list.h:114
List * targetList
Definition: parsenodes.h:140
#define Assert(condition)
Definition: c.h:699
#define lfirst(lc)
Definition: pg_list.h:106
static int list_length(const List *l)
Definition: pg_list.h:89
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:764
static const char * view_col_is_auto_updatable(RangeTblRef *rtr, TargetEntry *tle)
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:486
int16 AttrNumber
Definition: attnum.h:21

◆ view_has_instead_trigger()

static bool view_has_instead_trigger ( Relation  view,
CmdType  event 
)
static

Definition at line 2177 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(), and rewriteTargetListIU().

2178 {
2179  TriggerDesc *trigDesc = view->trigdesc;
2180 
2181  switch (event)
2182  {
2183  case CMD_INSERT:
2184  if (trigDesc && trigDesc->trig_insert_instead_row)
2185  return true;
2186  break;
2187  case CMD_UPDATE:
2188  if (trigDesc && trigDesc->trig_update_instead_row)
2189  return true;
2190  break;
2191  case CMD_DELETE:
2192  if (trigDesc && trigDesc->trig_delete_instead_row)
2193  return true;
2194  break;
2195  default:
2196  elog(ERROR, "unrecognized CmdType: %d", (int) event);
2197  break;
2198  }
2199  return false;
2200 }
bool trig_insert_instead_row
Definition: reltrigger.h:57
#define ERROR
Definition: elog.h:43
TriggerDesc * trigdesc
Definition: rel.h:90
bool trig_update_instead_row
Definition: reltrigger.h:62
bool trig_delete_instead_row
Definition: reltrigger.h:67
#define elog
Definition: elog.h:219

◆ view_query_is_auto_updatable()

const char* view_query_is_auto_updatable ( Query viewquery,
bool  check_cols 
)

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

2258 {
2259  RangeTblRef *rtr;
2260  RangeTblEntry *base_rte;
2261 
2262  /*----------
2263  * Check if the view is simply updatable. According to SQL-92 this means:
2264  * - No DISTINCT clause.
2265  * - Each TLE is a column reference, and each column appears at most once.
2266  * - FROM contains exactly one base relation.
2267  * - No GROUP BY or HAVING clauses.
2268  * - No set operations (UNION, INTERSECT or EXCEPT).
2269  * - No sub-queries in the WHERE clause that reference the target table.
2270  *
2271  * We ignore that last restriction since it would be complex to enforce
2272  * and there isn't any actual benefit to disallowing sub-queries. (The
2273  * semantic issues that the standard is presumably concerned about don't
2274  * arise in Postgres, since any such sub-query will not see any updates
2275  * executed by the outer query anyway, thanks to MVCC snapshotting.)
2276  *
2277  * We also relax the second restriction by supporting part of SQL:1999
2278  * feature T111, which allows for a mix of updatable and non-updatable
2279  * columns, provided that an INSERT or UPDATE doesn't attempt to assign to
2280  * a non-updatable column.
2281  *
2282  * In addition we impose these constraints, involving features that are
2283  * not part of SQL-92:
2284  * - No CTEs (WITH clauses).
2285  * - No OFFSET or LIMIT clauses (this matches a SQL:2008 restriction).
2286  * - No system columns (including whole-row references) in the tlist.
2287  * - No window functions in the tlist.
2288  * - No set-returning functions in the tlist.
2289  *
2290  * Note that we do these checks without recursively expanding the view.
2291  * If the base relation is a view, we'll recursively deal with it later.
2292  *----------
2293  */
2294  if (viewquery->distinctClause != NIL)
2295  return gettext_noop("Views containing DISTINCT are not automatically updatable.");
2296 
2297  if (viewquery->groupClause != NIL || viewquery->groupingSets)
2298  return gettext_noop("Views containing GROUP BY are not automatically updatable.");
2299 
2300  if (viewquery->havingQual != NULL)
2301  return gettext_noop("Views containing HAVING are not automatically updatable.");
2302 
2303  if (viewquery->setOperations != NULL)
2304  return gettext_noop("Views containing UNION, INTERSECT, or EXCEPT are not automatically updatable.");
2305 
2306  if (viewquery->cteList != NIL)
2307  return gettext_noop("Views containing WITH are not automatically updatable.");
2308 
2309  if (viewquery->limitOffset != NULL || viewquery->limitCount != NULL)
2310  return gettext_noop("Views containing LIMIT or OFFSET are not automatically updatable.");
2311 
2312  /*
2313  * We must not allow window functions or set returning functions in the
2314  * targetlist. Otherwise we might end up inserting them into the quals of
2315  * the main query. We must also check for aggregates in the targetlist in
2316  * case they appear without a GROUP BY.
2317  *
2318  * These restrictions ensure that each row of the view corresponds to a
2319  * unique row in the underlying base relation.
2320  */
2321  if (viewquery->hasAggs)
2322  return gettext_noop("Views that return aggregate functions are not automatically updatable.");
2323 
2324  if (viewquery->hasWindowFuncs)
2325  return gettext_noop("Views that return window functions are not automatically updatable.");
2326 
2327  if (viewquery->hasTargetSRFs)
2328  return gettext_noop("Views that return set-returning functions are not automatically updatable.");
2329 
2330  /*
2331  * The view query should select from a single base relation, which must be
2332  * a table or another view.
2333  */
2334  if (list_length(viewquery->jointree->fromlist) != 1)
2335  return gettext_noop("Views that do not select from a single table or view are not automatically updatable.");
2336 
2337  rtr = (RangeTblRef *) linitial(viewquery->jointree->fromlist);
2338  if (!IsA(rtr, RangeTblRef))
2339  return gettext_noop("Views that do not select from a single table or view are not automatically updatable.");
2340 
2341  base_rte = rt_fetch(rtr->rtindex, viewquery->rtable);
2342  if (base_rte->rtekind != RTE_RELATION ||
2343  (base_rte->relkind != RELKIND_RELATION &&
2344  base_rte->relkind != RELKIND_FOREIGN_TABLE &&
2345  base_rte->relkind != RELKIND_VIEW &&
2346  base_rte->relkind != RELKIND_PARTITIONED_TABLE))
2347  return gettext_noop("Views that do not select from a single table or view are not automatically updatable.");
2348 
2349  if (base_rte->tablesample)
2350  return gettext_noop("Views containing TABLESAMPLE are not automatically updatable.");
2351 
2352  /*
2353  * Check that the view has at least one updatable column. This is required
2354  * for INSERT/UPDATE but not for DELETE.
2355  */
2356  if (check_cols)
2357  {
2358  ListCell *cell;
2359  bool found;
2360 
2361  found = false;
2362  foreach(cell, viewquery->targetList)
2363  {
2364  TargetEntry *tle = (TargetEntry *) lfirst(cell);
2365 
2366  if (view_col_is_auto_updatable(rtr, tle) == NULL)
2367  {
2368  found = true;
2369  break;
2370  }
2371  }
2372 
2373  if (!found)
2374  return gettext_noop("Views that have no updatable columns are not automatically updatable.");
2375  }
2376 
2377  return NULL; /* the view is updatable */
2378 }
Node * limitOffset
Definition: parsenodes.h:160
#define NIL
Definition: pg_list.h:69
#define IsA(nodeptr, _type_)
Definition: nodes.h:568
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:1036
List * fromlist
Definition: primnodes.h:1479
List * targetList
Definition: parsenodes.h:140
#define linitial(l)
Definition: pg_list.h:111
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:106
bool hasWindowFuncs
Definition: parsenodes.h:126
static int list_length(const List *l)
Definition: pg_list.h:89
RTEKind rtekind
Definition: parsenodes.h:962
List * cteList
Definition: parsenodes.h:135
Node * setOperations
Definition: parsenodes.h:165
List * groupClause
Definition: parsenodes.h:148
static const char * view_col_is_auto_updatable(RangeTblRef *rtr, TargetEntry *tle)
Node * havingQual
Definition: parsenodes.h:152
struct TableSampleClause * tablesample
Definition: parsenodes.h:980