PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
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 rewriteTargetListUD (Query *parsetree, RangeTblEntry *target_rte, Relation target_relation)
 
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, bool forUpdatePushedDown)
 
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)
 
static QueryApplyRetrieveRule (Query *parsetree, RewriteRule *rule, int rt_index, Relation relation, List *activeRIRs, bool forUpdatePushedDown)
 
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

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

Referenced by relation_is_updatable().

Typedef Documentation

Function Documentation

static bool acquireLocksOnSubLinks ( Node node,
acquireLocksOnSubLinks_context context 
)
static

Definition at line 293 of file rewriteHandler.c.

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

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

294 {
295  if (node == NULL)
296  return false;
297  if (IsA(node, SubLink))
298  {
299  SubLink *sub = (SubLink *) node;
300 
301  /* Do what we came for */
303  context->for_execute,
304  false);
305  /* Fall through to process lefthand args of SubLink */
306  }
307 
308  /*
309  * Do NOT recurse into Query nodes, because AcquireRewriteLocks already
310  * processed subselects of subselects for us.
311  */
312  return expression_tree_walker(node, acquireLocksOnSubLinks, context);
313 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:560
static bool acquireLocksOnSubLinks(Node *node, acquireLocksOnSubLinks_context *context)
void AcquireRewriteLocks(Query *parsetree, bool forExecute, bool forUpdatePushedDown)
#define NULL
Definition: c.h:229
bool expression_tree_walker(Node *node, bool(*walker)(), void *context)
Definition: nodeFuncs.c:1864
void AcquireRewriteLocks ( Query parsetree,
bool  forExecute,
bool  forUpdatePushedDown 
)

Definition at line 134 of file rewriteHandler.c.

References AccessShareLock, acquireLocksOnSubLinks(), AcquireRewriteLocks(), Assert, Query::cteList, CommonTableExpr::ctequery, elog, ERROR, acquireLocksOnSubLinks_context::for_execute, get_parse_rowmark(), get_rte_attribute_is_dropped(), Query::hasSubLinks, heap_close, heap_open(), IsA, RangeTblEntry::joinaliasvars, lappend(), lfirst, NIL, NoLock, NULL, 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().

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

Definition at line 2598 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, NULL, TargetEntry::resjunk, result, and Var::varattno.

Referenced by relation_is_updatable(), and rewriteTargetView().

2599 {
2600  Bitmapset *result = NULL;
2601  int col;
2602 
2603  col = -1;
2604  while ((col = bms_next_member(cols, col)) >= 0)
2605  {
2606  /* bit numbers are offset by FirstLowInvalidHeapAttributeNumber */
2608 
2609  if (attno == InvalidAttrNumber)
2610  {
2611  /*
2612  * There's a whole-row reference to the view. For permissions
2613  * purposes, treat it as a reference to each column available from
2614  * the view. (We should *not* convert this to a whole-row
2615  * reference to the base relation, since the view may not touch
2616  * all columns of the base relation.)
2617  */
2618  ListCell *lc;
2619 
2620  foreach(lc, targetlist)
2621  {
2622  TargetEntry *tle = lfirst_node(TargetEntry, lc);
2623  Var *var;
2624 
2625  if (tle->resjunk)
2626  continue;
2627  var = castNode(Var, tle->expr);
2628  result = bms_add_member(result,
2629  var->varattno - FirstLowInvalidHeapAttributeNumber);
2630  }
2631  }
2632  else
2633  {
2634  /*
2635  * Views do not have system columns, so we do not expect to see
2636  * any other system attnos here. If we do find one, the error
2637  * case will apply.
2638  */
2639  TargetEntry *tle = get_tle_by_resno(targetlist, attno);
2640 
2641  if (tle != NULL && !tle->resjunk && IsA(tle->expr, Var))
2642  {
2643  Var *var = (Var *) tle->expr;
2644 
2645  result = bms_add_member(result,
2646  var->varattno - FirstLowInvalidHeapAttributeNumber);
2647  }
2648  else
2649  elog(ERROR, "attribute number %d not found in view targetlist",
2650  attno);
2651  }
2652  }
2653 
2654  return result;
2655 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:560
#define castNode(_type_, nodeptr)
Definition: nodes.h:578
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:937
AttrNumber varattno
Definition: primnodes.h:168
return result
Definition: formatting.c:1618
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:28
Definition: primnodes.h:163
bool resjunk
Definition: primnodes.h:1374
#define ERROR
Definition: elog.h:43
#define lfirst_node(type, lc)
Definition: pg_list.h:109
#define NULL
Definition: c.h:229
Expr * expr
Definition: primnodes.h:1367
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:698
#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
static List * adjustJoinTreeList ( Query parsetree,
bool  removert,
int  rt_index 
)
static

Definition at line 637 of file rewriteHandler.c.

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

Referenced by rewriteRuleAction().

638 {
639  List *newjointree = copyObject(parsetree->jointree->fromlist);
640  ListCell *l;
641 
642  if (removert)
643  {
644  foreach(l, newjointree)
645  {
646  RangeTblRef *rtr = lfirst(l);
647 
648  if (IsA(rtr, RangeTblRef) &&
649  rtr->rtindex == rt_index)
650  {
651  newjointree = list_delete_ptr(newjointree, rtr);
652 
653  /*
654  * foreach is safe because we exit loop after list_delete...
655  */
656  break;
657  }
658  }
659  }
660  return newjointree;
661 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:560
FromExpr * jointree
Definition: parsenodes.h:136
List * fromlist
Definition: primnodes.h:1470
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:621
Definition: pg_list.h:45
static Query* ApplyRetrieveRule ( Query parsetree,
RewriteRule rule,
int  rt_index,
Relation  relation,
List activeRIRs,
bool  forUpdatePushedDown 
)
static

Definition at line 1427 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(), markQueryForLocking(), NULL, PRS2_OLD_VARNO, 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, RangeTblEntry::updatedCols, and RowMarkClause::waitPolicy.

Referenced by fireRIRrules().

1433 {
1434  Query *rule_action;
1435  RangeTblEntry *rte,
1436  *subrte;
1437  RowMarkClause *rc;
1438 
1439  if (list_length(rule->actions) != 1)
1440  elog(ERROR, "expected just one rule action");
1441  if (rule->qual != NULL)
1442  elog(ERROR, "cannot handle qualified ON SELECT rule");
1443 
1444  if (rt_index == parsetree->resultRelation)
1445  {
1446  /*
1447  * We have a view as the result relation of the query, and it wasn't
1448  * rewritten by any rule. This case is supported if there is an
1449  * INSTEAD OF trigger that will trap attempts to insert/update/delete
1450  * view rows. The executor will check that; for the moment just plow
1451  * ahead. We have two cases:
1452  *
1453  * For INSERT, we needn't do anything. The unmodified RTE will serve
1454  * fine as the result relation.
1455  *
1456  * For UPDATE/DELETE, we need to expand the view so as to have source
1457  * data for the operation. But we also need an unmodified RTE to
1458  * serve as the target. So, copy the RTE and add the copy to the
1459  * rangetable. Note that the copy does not get added to the jointree.
1460  * Also note that there's a hack in fireRIRrules to avoid calling this
1461  * function again when it arrives at the copied RTE.
1462  */
1463  if (parsetree->commandType == CMD_INSERT)
1464  return parsetree;
1465  else if (parsetree->commandType == CMD_UPDATE ||
1466  parsetree->commandType == CMD_DELETE)
1467  {
1468  RangeTblEntry *newrte;
1469 
1470  rte = rt_fetch(rt_index, parsetree->rtable);
1471  newrte = copyObject(rte);
1472  parsetree->rtable = lappend(parsetree->rtable, newrte);
1473  parsetree->resultRelation = list_length(parsetree->rtable);
1474 
1475  /*
1476  * There's no need to do permissions checks twice, so wipe out the
1477  * permissions info for the original RTE (we prefer to keep the
1478  * bits set on the result RTE).
1479  */
1480  rte->requiredPerms = 0;
1481  rte->checkAsUser = InvalidOid;
1482  rte->selectedCols = NULL;
1483  rte->insertedCols = NULL;
1484  rte->updatedCols = NULL;
1485 
1486  /*
1487  * For the most part, Vars referencing the view should remain as
1488  * they are, meaning that they implicitly represent OLD values.
1489  * But in the RETURNING list if any, we want such Vars to
1490  * represent NEW values, so change them to reference the new RTE.
1491  *
1492  * Since ChangeVarNodes scribbles on the tree in-place, copy the
1493  * RETURNING list first for safety.
1494  */
1495  parsetree->returningList = copyObject(parsetree->returningList);
1496  ChangeVarNodes((Node *) parsetree->returningList, rt_index,
1497  parsetree->resultRelation, 0);
1498 
1499  /* Now, continue with expanding the original view RTE */
1500  }
1501  else
1502  elog(ERROR, "unrecognized commandType: %d",
1503  (int) parsetree->commandType);
1504  }
1505 
1506  /*
1507  * If FOR [KEY] UPDATE/SHARE of view, be sure we get right initial lock on
1508  * the relations it references.
1509  */
1510  rc = get_parse_rowmark(parsetree, rt_index);
1511  forUpdatePushedDown |= (rc != NULL);
1512 
1513  /*
1514  * Make a modifiable copy of the view query, and acquire needed locks on
1515  * the relations it mentions.
1516  */
1517  rule_action = copyObject(linitial(rule->actions));
1518 
1519  AcquireRewriteLocks(rule_action, true, forUpdatePushedDown);
1520 
1521  /*
1522  * Recursively expand any view references inside the view.
1523  */
1524  rule_action = fireRIRrules(rule_action, activeRIRs, forUpdatePushedDown);
1525 
1526  /*
1527  * Now, plug the view query in as a subselect, replacing the relation's
1528  * original RTE.
1529  */
1530  rte = rt_fetch(rt_index, parsetree->rtable);
1531 
1532  rte->rtekind = RTE_SUBQUERY;
1533  rte->relid = InvalidOid;
1534  rte->security_barrier = RelationIsSecurityView(relation);
1535  rte->subquery = rule_action;
1536  rte->inh = false; /* must not be set for a subquery */
1537 
1538  /*
1539  * We move the view's permission check data down to its rangetable. The
1540  * checks will actually be done against the OLD entry therein.
1541  */
1542  subrte = rt_fetch(PRS2_OLD_VARNO, rule_action->rtable);
1543  Assert(subrte->relid == relation->rd_id);
1544  subrte->requiredPerms = rte->requiredPerms;
1545  subrte->checkAsUser = rte->checkAsUser;
1546  subrte->selectedCols = rte->selectedCols;
1547  subrte->insertedCols = rte->insertedCols;
1548  subrte->updatedCols = rte->updatedCols;
1549 
1550  rte->requiredPerms = 0; /* no permission check on subquery itself */
1551  rte->checkAsUser = InvalidOid;
1552  rte->selectedCols = NULL;
1553  rte->insertedCols = NULL;
1554  rte->updatedCols = NULL;
1555 
1556  /*
1557  * If FOR [KEY] UPDATE/SHARE of view, mark all the contained tables as
1558  * implicit FOR [KEY] UPDATE/SHARE, the same as the parser would have done
1559  * if the view's subquery had been written out explicitly.
1560  *
1561  * Note: we don't consider forUpdatePushedDown here; such marks will be
1562  * made by recursing from the upper level in markQueryForLocking.
1563  */
1564  if (rc != NULL)
1565  markQueryForLocking(rule_action, (Node *) rule_action->jointree,
1566  rc->strength, rc->waitPolicy, true);
1567 
1568  return parsetree;
1569 }
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:136
int resultRelation
Definition: parsenodes.h:120
Definition: nodes.h:509
AclMode requiredPerms
Definition: parsenodes.h:1019
LockClauseStrength strength
Definition: parsenodes.h:1274
Bitmapset * selectedCols
Definition: parsenodes.h:1021
#define linitial(l)
Definition: pg_list.h:111
List * rtable
Definition: parsenodes.h:135
#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:144
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
Oid rd_id
Definition: rel.h:116
List * lappend(List *list, void *datum)
Definition: list.c:128
#define PRS2_OLD_VARNO
Definition: primnodes.h:160
bool security_barrier
Definition: parsenodes.h:947
#define InvalidOid
Definition: postgres_ext.h:36
Bitmapset * updatedCols
Definition: parsenodes.h:1023
CmdType commandType
Definition: parsenodes.h:110
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
static Query * fireRIRrules(Query *parsetree, List *activeRIRs, bool forUpdatePushedDown)
static int list_length(const List *l)
Definition: pg_list.h:89
LockWaitPolicy waitPolicy
Definition: parsenodes.h:1275
RTEKind rtekind
Definition: parsenodes.h:928
Query * subquery
Definition: parsenodes.h:946
Bitmapset * insertedCols
Definition: parsenodes.h:1022
#define RelationIsSecurityView(relation)
Definition: rel.h:348
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:621
Node* build_column_default ( Relation  rel,
int  attrno 
)

Definition at line 1081 of file rewriteHandler.c.

References tupleDesc::attrs, COERCE_IMPLICIT_CAST, coerce_to_target_type(), COERCION_ASSIGNMENT, tupleDesc::constr, tupleConstr::defval, ereport, errcode(), errhint(), errmsg(), ERROR, exprType(), format_type_be(), get_typdefault(), NameStr, NULL, tupleConstr::num_defval, RelationData::rd_att, and stringToNode().

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

1082 {
1083  TupleDesc rd_att = rel->rd_att;
1084  Form_pg_attribute att_tup = rd_att->attrs[attrno - 1];
1085  Oid atttype = att_tup->atttypid;
1086  int32 atttypmod = att_tup->atttypmod;
1087  Node *expr = NULL;
1088  Oid exprtype;
1089 
1090  /*
1091  * Scan to see if relation has a default for this column.
1092  */
1093  if (rd_att->constr && rd_att->constr->num_defval > 0)
1094  {
1095  AttrDefault *defval = rd_att->constr->defval;
1096  int ndef = rd_att->constr->num_defval;
1097 
1098  while (--ndef >= 0)
1099  {
1100  if (attrno == defval[ndef].adnum)
1101  {
1102  /*
1103  * Found it, convert string representation to node tree.
1104  */
1105  expr = stringToNode(defval[ndef].adbin);
1106  break;
1107  }
1108  }
1109  }
1110 
1111  if (expr == NULL)
1112  {
1113  /*
1114  * No per-column default, so look for a default for the type itself.
1115  */
1116  expr = get_typdefault(atttype);
1117  }
1118 
1119  if (expr == NULL)
1120  return NULL; /* No default anywhere */
1121 
1122  /*
1123  * Make sure the value is coerced to the target column type; this will
1124  * generally be true already, but there seem to be some corner cases
1125  * involving domain defaults where it might not be true. This should match
1126  * the parser's processing of non-defaulted expressions --- see
1127  * transformAssignedExpr().
1128  */
1129  exprtype = exprType(expr);
1130 
1131  expr = coerce_to_target_type(NULL, /* no UNKNOWN params here */
1132  expr, exprtype,
1133  atttype, atttypmod,
1136  -1);
1137  if (expr == NULL)
1138  ereport(ERROR,
1139  (errcode(ERRCODE_DATATYPE_MISMATCH),
1140  errmsg("column \"%s\" is of type %s"
1141  " but default expression is of type %s",
1142  NameStr(att_tup->attname),
1143  format_type_be(atttype),
1144  format_type_be(exprtype)),
1145  errhint("You will need to rewrite or cast the expression.")));
1146 
1147  return expr;
1148 }
void * stringToNode(char *str)
Definition: read.c:38
int errhint(const char *fmt,...)
Definition: elog.c:987
Form_pg_attribute * attrs
Definition: tupdesc.h:74
Definition: nodes.h:509
int errcode(int sqlerrcode)
Definition: elog.c:575
char * format_type_be(Oid type_oid)
Definition: format_type.c:94
unsigned int Oid
Definition: postgres_ext.h:31
signed int int32
Definition: c.h:256
AttrDefault * defval
Definition: tupdesc.h:39
#define ERROR
Definition: elog.h:43
Node * coerce_to_target_type(ParseState *pstate, Node *expr, Oid exprtype, Oid targettype, int32 targettypmod, CoercionContext ccontext, CoercionForm cformat, int location)
Definition: parse_coerce.c:77
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:187
#define ereport(elevel, rest)
Definition: elog.h:122
TupleDesc rd_att
Definition: rel.h:115
uint16 num_defval
Definition: tupdesc.h:41
#define NULL
Definition: c.h:229
Node * get_typdefault(Oid typid)
Definition: lsyscache.c:2198
TupleConstr * constr
Definition: tupdesc.h:76
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define NameStr(name)
Definition: c.h:499
static Query* CopyAndAddInvertedQual ( Query parsetree,
Node rule_qual,
int  rt_index,
CmdType  event 
)
static

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

1941 {
1942  /* Don't scribble on the passed qual (it's in the relcache!) */
1943  Node *new_qual = copyObject(rule_qual);
1945 
1946  context.for_execute = true;
1947 
1948  /*
1949  * In case there are subqueries in the qual, acquire necessary locks and
1950  * fix any deleted JOIN RTE entries. (This is somewhat redundant with
1951  * rewriteRuleAction, but not entirely ... consider restructuring so that
1952  * we only need to process the qual this way once.)
1953  */
1954  (void) acquireLocksOnSubLinks(new_qual, &context);
1955 
1956  /* Fix references to OLD */
1957  ChangeVarNodes(new_qual, PRS2_OLD_VARNO, rt_index, 0);
1958  /* Fix references to NEW */
1959  if (event == CMD_INSERT || event == CMD_UPDATE)
1960  new_qual = ReplaceVarsFromTargetList(new_qual,
1962  0,
1963  rt_fetch(rt_index,
1964  parsetree->rtable),
1965  parsetree->targetList,
1966  (event == CMD_UPDATE) ?
1969  rt_index,
1970  &parsetree->hasSubLinks);
1971  /* And attach the fixed qual */
1972  AddInvertedQual(parsetree, new_qual);
1973 
1974  return parsetree;
1975 }
static bool acquireLocksOnSubLinks(Node *node, acquireLocksOnSubLinks_context *context)
void AddInvertedQual(Query *parsetree, Node *qual)
Definition: nodes.h:509
List * targetList
Definition: parsenodes.h:138
List * rtable
Definition: parsenodes.h:135
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
#define PRS2_OLD_VARNO
Definition: primnodes.h:160
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:126
void ChangeVarNodes(Node *node, int rt_index, int new_index, int sublevels_up)
Definition: rewriteManip.c:607
#define copyObject(obj)
Definition: nodes.h:621
#define PRS2_NEW_VARNO
Definition: primnodes.h:161
static bool fireRIRonSubLink ( Node node,
List activeRIRs 
)
static

Definition at line 1643 of file rewriteHandler.c.

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

Referenced by fireRIRrules().

1644 {
1645  if (node == NULL)
1646  return false;
1647  if (IsA(node, SubLink))
1648  {
1649  SubLink *sub = (SubLink *) node;
1650 
1651  /* Do what we came for */
1652  sub->subselect = (Node *) fireRIRrules((Query *) sub->subselect,
1653  activeRIRs, false);
1654  /* Fall through to process lefthand args of SubLink */
1655  }
1656 
1657  /*
1658  * Do NOT recurse into Query nodes, because fireRIRrules already processed
1659  * subselects of subselects for us.
1660  */
1662  (void *) activeRIRs);
1663 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:560
Definition: nodes.h:509
static bool fireRIRonSubLink(Node *node, List *activeRIRs)
#define NULL
Definition: c.h:229
static Query * fireRIRrules(Query *parsetree, List *activeRIRs, bool forUpdatePushedDown)
bool expression_tree_walker(Node *node, bool(*walker)(), void *context)
Definition: nodeFuncs.c:1864
static Query * fireRIRrules ( Query parsetree,
List activeRIRs,
bool  forUpdatePushedDown 
)
static

Definition at line 1671 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_parse_rowmark(), 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, NULL, RuleLock::numLocks, QTW_IGNORE_RC_SUBQUERIES, query_tree_walker(), rangeTableEntry_used(), RelationData::rd_rules, RelationGetRelationName, RelationGetRelid, RangeTblEntry::relid, RangeTblEntry::relkind, RELKIND_MATVIEW, RELKIND_RELATION, 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().

1672 {
1673  int origResultRelation = parsetree->resultRelation;
1674  int rt_index;
1675  ListCell *lc;
1676 
1677  /*
1678  * don't try to convert this into a foreach loop, because rtable list can
1679  * get changed each time through...
1680  */
1681  rt_index = 0;
1682  while (rt_index < list_length(parsetree->rtable))
1683  {
1684  RangeTblEntry *rte;
1685  Relation rel;
1686  List *locks;
1687  RuleLock *rules;
1688  RewriteRule *rule;
1689  int i;
1690 
1691  ++rt_index;
1692 
1693  rte = rt_fetch(rt_index, parsetree->rtable);
1694 
1695  /*
1696  * A subquery RTE can't have associated rules, so there's nothing to
1697  * do to this level of the query, but we must recurse into the
1698  * subquery to expand any rule references in it.
1699  */
1700  if (rte->rtekind == RTE_SUBQUERY)
1701  {
1702  rte->subquery = fireRIRrules(rte->subquery, activeRIRs,
1703  (forUpdatePushedDown ||
1704  get_parse_rowmark(parsetree, rt_index) != NULL));
1705  continue;
1706  }
1707 
1708  /*
1709  * Joins and other non-relation RTEs can be ignored completely.
1710  */
1711  if (rte->rtekind != RTE_RELATION)
1712  continue;
1713 
1714  /*
1715  * Always ignore RIR rules for materialized views referenced in
1716  * queries. (This does not prevent refreshing MVs, since they aren't
1717  * referenced in their own query definitions.)
1718  *
1719  * Note: in the future we might want to allow MVs to be conditionally
1720  * expanded as if they were regular views, if they are not scannable.
1721  * In that case this test would need to be postponed till after we've
1722  * opened the rel, so that we could check its state.
1723  */
1724  if (rte->relkind == RELKIND_MATVIEW)
1725  continue;
1726 
1727  /*
1728  * If the table is not referenced in the query, then we ignore it.
1729  * This prevents infinite expansion loop due to new rtable entries
1730  * inserted by expansion of a rule. A table is referenced if it is
1731  * part of the join set (a source table), or is referenced by any Var
1732  * nodes, or is the result table.
1733  */
1734  if (rt_index != parsetree->resultRelation &&
1735  !rangeTableEntry_used((Node *) parsetree, rt_index, 0))
1736  continue;
1737 
1738  /*
1739  * Also, if this is a new result relation introduced by
1740  * ApplyRetrieveRule, we don't want to do anything more with it.
1741  */
1742  if (rt_index == parsetree->resultRelation &&
1743  rt_index != origResultRelation)
1744  continue;
1745 
1746  /*
1747  * We can use NoLock here since either the parser or
1748  * AcquireRewriteLocks should have locked the rel already.
1749  */
1750  rel = heap_open(rte->relid, NoLock);
1751 
1752  /*
1753  * Collect the RIR rules that we must apply
1754  */
1755  rules = rel->rd_rules;
1756  if (rules != NULL)
1757  {
1758  locks = NIL;
1759  for (i = 0; i < rules->numLocks; i++)
1760  {
1761  rule = rules->rules[i];
1762  if (rule->event != CMD_SELECT)
1763  continue;
1764 
1765  locks = lappend(locks, rule);
1766  }
1767 
1768  /*
1769  * If we found any, apply them --- but first check for recursion!
1770  */
1771  if (locks != NIL)
1772  {
1773  ListCell *l;
1774 
1775  if (list_member_oid(activeRIRs, RelationGetRelid(rel)))
1776  ereport(ERROR,
1777  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1778  errmsg("infinite recursion detected in rules for relation \"%s\"",
1779  RelationGetRelationName(rel))));
1780  activeRIRs = lcons_oid(RelationGetRelid(rel), activeRIRs);
1781 
1782  foreach(l, locks)
1783  {
1784  rule = lfirst(l);
1785 
1786  parsetree = ApplyRetrieveRule(parsetree,
1787  rule,
1788  rt_index,
1789  rel,
1790  activeRIRs,
1791  forUpdatePushedDown);
1792  }
1793 
1794  activeRIRs = list_delete_first(activeRIRs);
1795  }
1796  }
1797 
1798  heap_close(rel, NoLock);
1799  }
1800 
1801  /* Recurse into subqueries in WITH */
1802  foreach(lc, parsetree->cteList)
1803  {
1804  CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
1805 
1806  cte->ctequery = (Node *)
1807  fireRIRrules((Query *) cte->ctequery, activeRIRs, false);
1808  }
1809 
1810  /*
1811  * Recurse into sublink subqueries, too. But we already did the ones in
1812  * the rtable and cteList.
1813  */
1814  if (parsetree->hasSubLinks)
1815  query_tree_walker(parsetree, fireRIRonSubLink, (void *) activeRIRs,
1817 
1818  /*
1819  * Apply any row level security policies. We do this last because it
1820  * requires special recursion detection if the new quals have sublink
1821  * subqueries, and if we did it in the loop above query_tree_walker would
1822  * then recurse into those quals a second time.
1823  */
1824  rt_index = 0;
1825  foreach(lc, parsetree->rtable)
1826  {
1827  RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
1828  Relation rel;
1829  List *securityQuals;
1830  List *withCheckOptions;
1831  bool hasRowSecurity;
1832  bool hasSubLinks;
1833 
1834  ++rt_index;
1835 
1836  /* Only normal relations can have RLS policies */
1837  if (rte->rtekind != RTE_RELATION ||
1838  rte->relkind != RELKIND_RELATION)
1839  continue;
1840 
1841  rel = heap_open(rte->relid, NoLock);
1842 
1843  /*
1844  * Fetch any new security quals that must be applied to this RTE.
1845  */
1846  get_row_security_policies(parsetree, rte, rt_index,
1847  &securityQuals, &withCheckOptions,
1848  &hasRowSecurity, &hasSubLinks);
1849 
1850  if (securityQuals != NIL || withCheckOptions != NIL)
1851  {
1852  if (hasSubLinks)
1853  {
1855 
1856  /*
1857  * Recursively process the new quals, checking for infinite
1858  * recursion.
1859  */
1860  if (list_member_oid(activeRIRs, RelationGetRelid(rel)))
1861  ereport(ERROR,
1862  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1863  errmsg("infinite recursion detected in policy for relation \"%s\"",
1864  RelationGetRelationName(rel))));
1865 
1866  activeRIRs = lcons_oid(RelationGetRelid(rel), activeRIRs);
1867 
1868  /*
1869  * get_row_security_policies just passed back securityQuals
1870  * and/or withCheckOptions, and there were SubLinks, make sure
1871  * we lock any relations which are referenced.
1872  *
1873  * These locks would normally be acquired by the parser, but
1874  * securityQuals and withCheckOptions are added post-parsing.
1875  */
1876  context.for_execute = true;
1877  (void) acquireLocksOnSubLinks((Node *) securityQuals, &context);
1878  (void) acquireLocksOnSubLinks((Node *) withCheckOptions,
1879  &context);
1880 
1881  /*
1882  * Now that we have the locks on anything added by
1883  * get_row_security_policies, fire any RIR rules for them.
1884  */
1885  expression_tree_walker((Node *) securityQuals,
1886  fireRIRonSubLink, (void *) activeRIRs);
1887 
1888  expression_tree_walker((Node *) withCheckOptions,
1889  fireRIRonSubLink, (void *) activeRIRs);
1890 
1891  activeRIRs = list_delete_first(activeRIRs);
1892  }
1893 
1894  /*
1895  * Add the new security barrier quals to the start of the RTE's
1896  * list so that they get applied before any existing barrier quals
1897  * (which would have come from a security-barrier view, and should
1898  * get lower priority than RLS conditions on the table itself).
1899  */
1900  rte->securityQuals = list_concat(securityQuals,
1901  rte->securityQuals);
1902 
1903  parsetree->withCheckOptions = list_concat(withCheckOptions,
1904  parsetree->withCheckOptions);
1905  }
1906 
1907  /*
1908  * Make sure the query is marked correctly if row level security
1909  * applies, or if the new quals had sublinks.
1910  */
1911  if (hasRowSecurity)
1912  parsetree->hasRowSecurity = true;
1913  if (hasSubLinks)
1914  parsetree->hasSubLinks = true;
1915 
1916  heap_close(rel, NoLock);
1917  }
1918 
1919  return parsetree;
1920 }
#define NIL
Definition: pg_list.h:69
bool query_tree_walker(Query *query, bool(*walker)(), void *context, int flags)
Definition: nodeFuncs.c:2267
int numLocks
Definition: prs2lock.h:42
RowMarkClause * get_parse_rowmark(Query *qry, Index rtindex)
static bool acquireLocksOnSubLinks(Node *node, acquireLocksOnSubLinks_context *context)
void get_row_security_policies(Query *root, RangeTblEntry *rte, int rt_index, List **securityQuals, List **withCheckOptions, bool *hasRowSecurity, bool *hasSubLinks)
Definition: rowsecurity.c:106
List * withCheckOptions
Definition: parsenodes.h:169
List * securityQuals
Definition: parsenodes.h:1024
int resultRelation
Definition: parsenodes.h:120
#define RELKIND_MATVIEW
Definition: pg_class.h:165
Definition: nodes.h:509
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
static Query * ApplyRetrieveRule(Query *parsetree, RewriteRule *rule, int rt_index, Relation relation, List *activeRIRs, bool forUpdatePushedDown)
Definition: localtime.c:74
#define QTW_IGNORE_RC_SUBQUERIES
Definition: nodeFuncs.h:22
List * rtable
Definition: parsenodes.h:135
#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:267
#define RelationGetRelationName(relation)
Definition: rel.h:437
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:1284
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:505
#define NULL
Definition: c.h:229
#define lfirst(lc)
Definition: pg_list.h:106
static Query * fireRIRrules(Query *parsetree, List *activeRIRs, bool forUpdatePushedDown)
RuleLock * rd_rules
Definition: rel.h:118
bool expression_tree_walker(Node *node, bool(*walker)(), void *context)
Definition: nodeFuncs.c:1864
static int list_length(const List *l)
Definition: pg_list.h:89
RTEKind rtekind
Definition: parsenodes.h:928
List * cteList
Definition: parsenodes.h:133
Query * subquery
Definition: parsenodes.h:946
int errmsg(const char *fmt,...)
Definition: elog.c:797
bool hasSubLinks
Definition: parsenodes.h:126
int i
bool rangeTableEntry_used(Node *node, int rt_index, int sublevels_up)
Definition: rewriteManip.c:889
#define RELKIND_RELATION
Definition: pg_class.h:160
Definition: pg_list.h:45
#define RelationGetRelid(relation)
Definition: rel.h:417
List * list_delete_first(List *list)
Definition: list.c:666
bool hasRowSecurity
Definition: parsenodes.h:131
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 2007 of file rewriteHandler.c.

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

Referenced by RewriteQuery().

2014 {
2015  List *results = NIL;
2016  ListCell *l;
2017 
2018  foreach(l, locks)
2019  {
2020  RewriteRule *rule_lock = (RewriteRule *) lfirst(l);
2021  Node *event_qual = rule_lock->qual;
2022  List *actions = rule_lock->actions;
2023  QuerySource qsrc;
2024  ListCell *r;
2025 
2026  /* Determine correct QuerySource value for actions */
2027  if (rule_lock->isInstead)
2028  {
2029  if (event_qual != NULL)
2030  qsrc = QSRC_QUAL_INSTEAD_RULE;
2031  else
2032  {
2033  qsrc = QSRC_INSTEAD_RULE;
2034  *instead_flag = true; /* report unqualified INSTEAD */
2035  }
2036  }
2037  else
2038  qsrc = QSRC_NON_INSTEAD_RULE;
2039 
2040  if (qsrc == QSRC_QUAL_INSTEAD_RULE)
2041  {
2042  /*
2043  * If there are INSTEAD rules with qualifications, the original
2044  * query is still performed. But all the negated rule
2045  * qualifications of the INSTEAD rules are added so it does its
2046  * actions only in cases where the rule quals of all INSTEAD rules
2047  * are false. Think of it as the default action in a case. We save
2048  * this in *qual_product so RewriteQuery() can add it to the query
2049  * list after we mangled it up enough.
2050  *
2051  * If we have already found an unqualified INSTEAD rule, then
2052  * *qual_product won't be used, so don't bother building it.
2053  */
2054  if (!*instead_flag)
2055  {
2056  if (*qual_product == NULL)
2057  *qual_product = copyObject(parsetree);
2058  *qual_product = CopyAndAddInvertedQual(*qual_product,
2059  event_qual,
2060  rt_index,
2061  event);
2062  }
2063  }
2064 
2065  /* Now process the rule's actions and add them to the result list */
2066  foreach(r, actions)
2067  {
2068  Query *rule_action = lfirst(r);
2069 
2070  if (rule_action->commandType == CMD_NOTHING)
2071  continue;
2072 
2073  rule_action = rewriteRuleAction(parsetree, rule_action,
2074  event_qual, rt_index, event,
2075  returning_flag);
2076 
2077  rule_action->querySource = qsrc;
2078  rule_action->canSetTag = false; /* might change later */
2079 
2080  results = lappend(results, rule_action);
2081  }
2082  }
2083 
2084  return results;
2085 }
#define NIL
Definition: pg_list.h:69
Node * qual
Definition: prs2lock.h:28
QuerySource
Definition: parsenodes.h:38
Definition: nodes.h:509
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:110
#define NULL
Definition: c.h:229
QuerySource querySource
Definition: parsenodes.h:112
#define lfirst(lc)
Definition: pg_list.h:106
bool canSetTag
Definition: parsenodes.h:116
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:621
Definition: pg_list.h:45
static Node * get_assignment_input ( Node node)
static

Definition at line 1054 of file rewriteHandler.c.

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

Referenced by process_matched_tle().

1055 {
1056  if (node == NULL)
1057  return NULL;
1058  if (IsA(node, FieldStore))
1059  {
1060  FieldStore *fstore = (FieldStore *) node;
1061 
1062  return (Node *) fstore->arg;
1063  }
1064  else if (IsA(node, ArrayRef))
1065  {
1066  ArrayRef *aref = (ArrayRef *) node;
1067 
1068  if (aref->refassgnexpr == NULL)
1069  return NULL;
1070  return (Node *) aref->refexpr;
1071  }
1072  return NULL;
1073 }
Expr * refassgnexpr
Definition: primnodes.h:409
#define IsA(nodeptr, _type_)
Definition: nodes.h:560
Expr * arg
Definition: primnodes.h:767
Definition: nodes.h:509
#define NULL
Definition: c.h:229
Expr * refexpr
Definition: primnodes.h:407
Query* get_view_query ( Relation  view)

Definition at line 2098 of file rewriteHandler.c.

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

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

2099 {
2100  int i;
2101 
2102  Assert(view->rd_rel->relkind == RELKIND_VIEW);
2103 
2104  for (i = 0; i < view->rd_rules->numLocks; i++)
2105  {
2106  RewriteRule *rule = view->rd_rules->rules[i];
2107 
2108  if (rule->event == CMD_SELECT)
2109  {
2110  /* A _RETURN rule should have only one action */
2111  if (list_length(rule->actions) != 1)
2112  elog(ERROR, "invalid _RETURN rule action specification");
2113 
2114  return (Query *) linitial(rule->actions);
2115  }
2116  }
2117 
2118  elog(ERROR, "failed to find _RETURN rule for view");
2119  return NULL; /* keep compiler quiet */
2120 }
int numLocks
Definition: prs2lock.h:42
Form_pg_class rd_rel
Definition: rel.h:114
Definition: localtime.c:74
#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 NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
RuleLock * rd_rules
Definition: rel.h:118
static int list_length(const List *l)
Definition: pg_list.h:89
#define RELKIND_VIEW
Definition: pg_class.h:164
int i
#define elog
Definition: elog.h:219
static void markQueryForLocking ( Query qry,
Node jtnode,
LockClauseStrength  strength,
LockWaitPolicy  waitPolicy,
bool  pushedDown 
)
static

Definition at line 1583 of file rewriteHandler.c.

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

Referenced by ApplyRetrieveRule().

1586 {
1587  if (jtnode == NULL)
1588  return;
1589  if (IsA(jtnode, RangeTblRef))
1590  {
1591  int rti = ((RangeTblRef *) jtnode)->rtindex;
1592  RangeTblEntry *rte = rt_fetch(rti, qry->rtable);
1593 
1594  if (rte->rtekind == RTE_RELATION)
1595  {
1596  applyLockingClause(qry, rti, strength, waitPolicy, pushedDown);
1598  }
1599  else if (rte->rtekind == RTE_SUBQUERY)
1600  {
1601  applyLockingClause(qry, rti, strength, waitPolicy, pushedDown);
1602  /* FOR UPDATE/SHARE of subquery is propagated to subquery's rels */
1604  strength, waitPolicy, true);
1605  }
1606  /* other RTE types are unaffected by FOR UPDATE */
1607  }
1608  else if (IsA(jtnode, FromExpr))
1609  {
1610  FromExpr *f = (FromExpr *) jtnode;
1611  ListCell *l;
1612 
1613  foreach(l, f->fromlist)
1614  markQueryForLocking(qry, lfirst(l), strength, waitPolicy, pushedDown);
1615  }
1616  else if (IsA(jtnode, JoinExpr))
1617  {
1618  JoinExpr *j = (JoinExpr *) jtnode;
1619 
1620  markQueryForLocking(qry, j->larg, strength, waitPolicy, pushedDown);
1621  markQueryForLocking(qry, j->rarg, strength, waitPolicy, pushedDown);
1622  }
1623  else
1624  elog(ERROR, "unrecognized node type: %d",
1625  (int) nodeTag(jtnode));
1626 }
static void markQueryForLocking(Query *qry, Node *jtnode, LockClauseStrength strength, LockWaitPolicy waitPolicy, bool pushedDown)
#define IsA(nodeptr, _type_)
Definition: nodes.h:560
FromExpr * jointree
Definition: parsenodes.h:136
Definition: nodes.h:509
AclMode requiredPerms
Definition: parsenodes.h:1019
List * fromlist
Definition: primnodes.h:1470
Node * larg
Definition: primnodes.h:1450
List * rtable
Definition: parsenodes.h:135
#define ERROR
Definition: elog.h:43
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
Node * rarg
Definition: primnodes.h:1451
#define NULL
Definition: c.h:229
#define lfirst(lc)
Definition: pg_list.h:106
#define ACL_SELECT_FOR_UPDATE
Definition: parsenodes.h:88
#define nodeTag(nodeptr)
Definition: nodes.h:514
RTEKind rtekind
Definition: parsenodes.h:928
Query * subquery
Definition: parsenodes.h:946
#define elog
Definition: elog.h:219
void applyLockingClause(Query *qry, Index rtindex, LockClauseStrength strength, LockWaitPolicy waitPolicy, bool pushedDown)
Definition: analyze.c:2841
static List * matchLocks ( CmdType  event,
RuleLock rulelocks,
int  varno,
Query parsetree,
bool hasUpdate 
)
static

Definition at line 1361 of file rewriteHandler.c.

References CMD_SELECT, CMD_UPDATE, Query::commandType, RewriteRule::enabled, RewriteRule::event, i, lappend(), NIL, NULL, 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().

1366 {
1367  List *matching_locks = NIL;
1368  int nlocks;
1369  int i;
1370 
1371  if (rulelocks == NULL)
1372  return NIL;
1373 
1374  if (parsetree->commandType != CMD_SELECT)
1375  {
1376  if (parsetree->resultRelation != varno)
1377  return NIL;
1378  }
1379 
1380  nlocks = rulelocks->numLocks;
1381 
1382  for (i = 0; i < nlocks; i++)
1383  {
1384  RewriteRule *oneLock = rulelocks->rules[i];
1385 
1386  if (oneLock->event == CMD_UPDATE)
1387  *hasUpdate = true;
1388 
1389  /*
1390  * Suppress ON INSERT/UPDATE/DELETE rules that are disabled or
1391  * configured to not fire during the current sessions replication
1392  * role. ON SELECT rules will always be applied in order to keep views
1393  * working even in LOCAL or REPLICA role.
1394  */
1395  if (oneLock->event != CMD_SELECT)
1396  {
1398  {
1399  if (oneLock->enabled == RULE_FIRES_ON_ORIGIN ||
1400  oneLock->enabled == RULE_DISABLED)
1401  continue;
1402  }
1403  else /* ORIGIN or LOCAL ROLE */
1404  {
1405  if (oneLock->enabled == RULE_FIRES_ON_REPLICA ||
1406  oneLock->enabled == RULE_DISABLED)
1407  continue;
1408  }
1409  }
1410 
1411  if (oneLock->event == event)
1412  {
1413  if (parsetree->commandType != CMD_SELECT ||
1414  rangeTableEntry_used((Node *) parsetree, varno, 0))
1415  matching_locks = lappend(matching_locks, oneLock);
1416  }
1417  }
1418 
1419  return matching_locks;
1420 }
#define NIL
Definition: pg_list.h:69
int numLocks
Definition: prs2lock.h:42
int resultRelation
Definition: parsenodes.h:120
Definition: nodes.h:509
int SessionReplicationRole
Definition: trigger.c:64
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:101
#define RULE_FIRES_ON_REPLICA
Definition: rewriteDefine.h:23
CmdType commandType
Definition: parsenodes.h:110
#define NULL
Definition: c.h:229
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
static TargetEntry * process_matched_tle ( TargetEntry src_tle,
TargetEntry prior_tle,
const char *  attrName 
)
static

Definition at line 932 of file rewriteHandler.c.

References FieldStore::arg, elog, equal(), ereport, errcode(), errmsg(), ERROR, TargetEntry::expr, exprType(), FieldStore::fieldnums, flatCopyTargetEntry(), get_assignment_input(), IsA, list_concat(), list_copy(), makeNode, FieldStore::newvals, NULL, ArrayRef::refexpr, and result.

Referenced by rewriteTargetListIU().

935 {
937  Node *src_expr;
938  Node *prior_expr;
939  Node *src_input;
940  Node *prior_input;
941  Node *priorbottom;
942  Node *newexpr;
943 
944  if (prior_tle == NULL)
945  {
946  /*
947  * Normal case where this is the first assignment to the attribute.
948  */
949  return src_tle;
950  }
951 
952  /*----------
953  * Multiple assignments to same attribute. Allow only if all are
954  * FieldStore or ArrayRef assignment operations. This is a bit
955  * tricky because what we may actually be looking at is a nest of
956  * such nodes; consider
957  * UPDATE tab SET col.fld1.subfld1 = x, col.fld2.subfld2 = y
958  * The two expressions produced by the parser will look like
959  * FieldStore(col, fld1, FieldStore(placeholder, subfld1, x))
960  * FieldStore(col, fld2, FieldStore(placeholder, subfld2, y))
961  * However, we can ignore the substructure and just consider the top
962  * FieldStore or ArrayRef from each assignment, because it works to
963  * combine these as
964  * FieldStore(FieldStore(col, fld1,
965  * FieldStore(placeholder, subfld1, x)),
966  * fld2, FieldStore(placeholder, subfld2, y))
967  * Note the leftmost expression goes on the inside so that the
968  * assignments appear to occur left-to-right.
969  *
970  * For FieldStore, instead of nesting we can generate a single
971  * FieldStore with multiple target fields. We must nest when
972  * ArrayRefs are involved though.
973  *----------
974  */
975  src_expr = (Node *) src_tle->expr;
976  prior_expr = (Node *) prior_tle->expr;
977  src_input = get_assignment_input(src_expr);
978  prior_input = get_assignment_input(prior_expr);
979  if (src_input == NULL ||
980  prior_input == NULL ||
981  exprType(src_expr) != exprType(prior_expr))
982  ereport(ERROR,
983  (errcode(ERRCODE_SYNTAX_ERROR),
984  errmsg("multiple assignments to same column \"%s\"",
985  attrName)));
986 
987  /*
988  * Prior TLE could be a nest of assignments if we do this more than once.
989  */
990  priorbottom = prior_input;
991  for (;;)
992  {
993  Node *newbottom = get_assignment_input(priorbottom);
994 
995  if (newbottom == NULL)
996  break; /* found the original Var reference */
997  priorbottom = newbottom;
998  }
999  if (!equal(priorbottom, src_input))
1000  ereport(ERROR,
1001  (errcode(ERRCODE_SYNTAX_ERROR),
1002  errmsg("multiple assignments to same column \"%s\"",
1003  attrName)));
1004 
1005  /*
1006  * Looks OK to nest 'em.
1007  */
1008  if (IsA(src_expr, FieldStore))
1009  {
1010  FieldStore *fstore = makeNode(FieldStore);
1011 
1012  if (IsA(prior_expr, FieldStore))
1013  {
1014  /* combine the two */
1015  memcpy(fstore, prior_expr, sizeof(FieldStore));
1016  fstore->newvals =
1017  list_concat(list_copy(((FieldStore *) prior_expr)->newvals),
1018  list_copy(((FieldStore *) src_expr)->newvals));
1019  fstore->fieldnums =
1020  list_concat(list_copy(((FieldStore *) prior_expr)->fieldnums),
1021  list_copy(((FieldStore *) src_expr)->fieldnums));
1022  }
1023  else
1024  {
1025  /* general case, just nest 'em */
1026  memcpy(fstore, src_expr, sizeof(FieldStore));
1027  fstore->arg = (Expr *) prior_expr;
1028  }
1029  newexpr = (Node *) fstore;
1030  }
1031  else if (IsA(src_expr, ArrayRef))
1032  {
1033  ArrayRef *aref = makeNode(ArrayRef);
1034 
1035  memcpy(aref, src_expr, sizeof(ArrayRef));
1036  aref->refexpr = (Expr *) prior_expr;
1037  newexpr = (Node *) aref;
1038  }
1039  else
1040  {
1041  elog(ERROR, "cannot happen");
1042  newexpr = NULL;
1043  }
1044 
1045  result = flatCopyTargetEntry(src_tle);
1046  result->expr = (Expr *) newexpr;
1047  return result;
1048 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:560
Expr * arg
Definition: primnodes.h:767
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:2961
List * list_copy(const List *oldlist)
Definition: list.c:1160
Definition: nodes.h:509
int errcode(int sqlerrcode)
Definition: elog.c:575
List * list_concat(List *list1, List *list2)
Definition: list.c:321
return result
Definition: formatting.c:1618
#define ERROR
Definition: elog.h:43
TargetEntry * flatCopyTargetEntry(TargetEntry *src_tle)
Definition: makefuncs.c:268
#define ereport(elevel, rest)
Definition: elog.h:122
List * newvals
Definition: primnodes.h:768
static Node * get_assignment_input(Node *node)
#define makeNode(_type_)
Definition: nodes.h:557
#define NULL
Definition: c.h:229
Expr * expr
Definition: primnodes.h:1367
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
int errmsg(const char *fmt,...)
Definition: elog.c:797
List * fieldnums
Definition: primnodes.h:769
#define elog
Definition: elog.h:219
Expr * refexpr
Definition: primnodes.h:407
List* QueryRewrite ( Query parsetree)

Definition at line 3542 of file rewriteHandler.c.

References Assert, Query::canSetTag, Query::commandType, fireRIRrules(), lappend(), lfirst, NIL, NULL, 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().

3543 {
3544  uint32 input_query_id = parsetree->queryId;
3545  List *querylist;
3546  List *results;
3547  ListCell *l;
3548  CmdType origCmdType;
3549  bool foundOriginalQuery;
3550  Query *lastInstead;
3551 
3552  /*
3553  * This function is only applied to top-level original queries
3554  */
3555  Assert(parsetree->querySource == QSRC_ORIGINAL);
3556  Assert(parsetree->canSetTag);
3557 
3558  /*
3559  * Step 1
3560  *
3561  * Apply all non-SELECT rules possibly getting 0 or many queries
3562  */
3563  querylist = RewriteQuery(parsetree, NIL);
3564 
3565  /*
3566  * Step 2
3567  *
3568  * Apply all the RIR rules on each query
3569  *
3570  * This is also a handy place to mark each query with the original queryId
3571  */
3572  results = NIL;
3573  foreach(l, querylist)
3574  {
3575  Query *query = (Query *) lfirst(l);
3576 
3577  query = fireRIRrules(query, NIL, false);
3578 
3579  query->queryId = input_query_id;
3580 
3581  results = lappend(results, query);
3582  }
3583 
3584  /*
3585  * Step 3
3586  *
3587  * Determine which, if any, of the resulting queries is supposed to set
3588  * the command-result tag; and update the canSetTag fields accordingly.
3589  *
3590  * If the original query is still in the list, it sets the command tag.
3591  * Otherwise, the last INSTEAD query of the same kind as the original is
3592  * allowed to set the tag. (Note these rules can leave us with no query
3593  * setting the tag. The tcop code has to cope with this by setting up a
3594  * default tag based on the original un-rewritten query.)
3595  *
3596  * The Asserts verify that at most one query in the result list is marked
3597  * canSetTag. If we aren't checking asserts, we can fall out of the loop
3598  * as soon as we find the original query.
3599  */
3600  origCmdType = parsetree->commandType;
3601  foundOriginalQuery = false;
3602  lastInstead = NULL;
3603 
3604  foreach(l, results)
3605  {
3606  Query *query = (Query *) lfirst(l);
3607 
3608  if (query->querySource == QSRC_ORIGINAL)
3609  {
3610  Assert(query->canSetTag);
3611  Assert(!foundOriginalQuery);
3612  foundOriginalQuery = true;
3613 #ifndef USE_ASSERT_CHECKING
3614  break;
3615 #endif
3616  }
3617  else
3618  {
3619  Assert(!query->canSetTag);
3620  if (query->commandType == origCmdType &&
3621  (query->querySource == QSRC_INSTEAD_RULE ||
3623  lastInstead = query;
3624  }
3625  }
3626 
3627  if (!foundOriginalQuery && lastInstead != NULL)
3628  lastInstead->canSetTag = true;
3629 
3630  return results;
3631 }
#define NIL
Definition: pg_list.h:69
uint32 queryId
Definition: parsenodes.h:114
static List * RewriteQuery(Query *parsetree, List *rewrite_events)
unsigned int uint32
Definition: c.h:268
List * lappend(List *list, void *datum)
Definition: list.c:128
CmdType commandType
Definition: parsenodes.h:110
#define NULL
Definition: c.h:229
QuerySource querySource
Definition: parsenodes.h:112
#define Assert(condition)
Definition: c.h:675
#define lfirst(lc)
Definition: pg_list.h:106
static Query * fireRIRrules(Query *parsetree, List *activeRIRs, bool forUpdatePushedDown)
bool canSetTag
Definition: parsenodes.h:116
Definition: pg_list.h:45
CmdType
Definition: nodes.h:648
int relation_is_updatable ( Oid  reloid,
bool  include_triggers,
Bitmapset include_cols 
)

Definition at line 2434 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, NULL, RuleLock::numLocks, RewriteRule::qual, RelationData::rd_rel, RelationData::rd_rules, relation_close(), relation_is_updatable(), RangeTblEntry::relid, RangeTblEntry::relkind, RELKIND_FOREIGN_TABLE, RELKIND_RELATION, RELKIND_VIEW, 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().

2437 {
2438  int events = 0;
2439  Relation rel;
2440  RuleLock *rulelocks;
2441 
2442 #define ALL_EVENTS ((1 << CMD_INSERT) | (1 << CMD_UPDATE) | (1 << CMD_DELETE))
2443 
2444  rel = try_relation_open(reloid, AccessShareLock);
2445 
2446  /*
2447  * If the relation doesn't exist, return zero rather than throwing an
2448  * error. This is helpful since scanning an information_schema view under
2449  * MVCC rules can result in referencing rels that have actually been
2450  * deleted already.
2451  */
2452  if (rel == NULL)
2453  return 0;
2454 
2455  /* If the relation is a table, it is always updatable */
2456  if (rel->rd_rel->relkind == RELKIND_RELATION)
2457  {
2459  return ALL_EVENTS;
2460  }
2461 
2462  /* Look for unconditional DO INSTEAD rules, and note supported events */
2463  rulelocks = rel->rd_rules;
2464  if (rulelocks != NULL)
2465  {
2466  int i;
2467 
2468  for (i = 0; i < rulelocks->numLocks; i++)
2469  {
2470  if (rulelocks->rules[i]->isInstead &&
2471  rulelocks->rules[i]->qual == NULL)
2472  {
2473  events |= ((1 << rulelocks->rules[i]->event) & ALL_EVENTS);
2474  }
2475  }
2476 
2477  /* If we have rules for all events, we're done */
2478  if (events == ALL_EVENTS)
2479  {
2481  return events;
2482  }
2483  }
2484 
2485  /* Similarly look for INSTEAD OF triggers, if they are to be included */
2486  if (include_triggers)
2487  {
2488  TriggerDesc *trigDesc = rel->trigdesc;
2489 
2490  if (trigDesc)
2491  {
2492  if (trigDesc->trig_insert_instead_row)
2493  events |= (1 << CMD_INSERT);
2494  if (trigDesc->trig_update_instead_row)
2495  events |= (1 << CMD_UPDATE);
2496  if (trigDesc->trig_delete_instead_row)
2497  events |= (1 << CMD_DELETE);
2498 
2499  /* If we have triggers for all events, we're done */
2500  if (events == ALL_EVENTS)
2501  {
2503  return events;
2504  }
2505  }
2506  }
2507 
2508  /* If this is a foreign table, check which update events it supports */
2509  if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
2510  {
2511  FdwRoutine *fdwroutine = GetFdwRoutineForRelation(rel, false);
2512 
2513  if (fdwroutine->IsForeignRelUpdatable != NULL)
2514  events |= fdwroutine->IsForeignRelUpdatable(rel);
2515  else
2516  {
2517  /* Assume presence of executor functions is sufficient */
2518  if (fdwroutine->ExecForeignInsert != NULL)
2519  events |= (1 << CMD_INSERT);
2520  if (fdwroutine->ExecForeignUpdate != NULL)
2521  events |= (1 << CMD_UPDATE);
2522  if (fdwroutine->ExecForeignDelete != NULL)
2523  events |= (1 << CMD_DELETE);
2524  }
2525 
2527  return events;
2528  }
2529 
2530  /* Check if this is an automatically updatable view */
2531  if (rel->rd_rel->relkind == RELKIND_VIEW)
2532  {
2533  Query *viewquery = get_view_query(rel);
2534 
2535  if (view_query_is_auto_updatable(viewquery, false) == NULL)
2536  {
2537  Bitmapset *updatable_cols;
2538  int auto_events;
2539  RangeTblRef *rtr;
2540  RangeTblEntry *base_rte;
2541  Oid baseoid;
2542 
2543  /*
2544  * Determine which of the view's columns are updatable. If there
2545  * are none within the set of columns we are looking at, then the
2546  * view doesn't support INSERT/UPDATE, but it may still support
2547  * DELETE.
2548  */
2550  &updatable_cols, NULL);
2551 
2552  if (include_cols != NULL)
2553  updatable_cols = bms_int_members(updatable_cols, include_cols);
2554 
2555  if (bms_is_empty(updatable_cols))
2556  auto_events = (1 << CMD_DELETE); /* May support DELETE */
2557  else
2558  auto_events = ALL_EVENTS; /* May support all events */
2559 
2560  /*
2561  * The base relation must also support these update commands.
2562  * Tables are always updatable, but for any other kind of base
2563  * relation we must do a recursive check limited to the columns
2564  * referenced by the locally updatable columns in this view.
2565  */
2566  rtr = (RangeTblRef *) linitial(viewquery->jointree->fromlist);
2567  base_rte = rt_fetch(rtr->rtindex, viewquery->rtable);
2568  Assert(base_rte->rtekind == RTE_RELATION);
2569 
2570  if (base_rte->relkind != RELKIND_RELATION)
2571  {
2572  baseoid = base_rte->relid;
2573  include_cols = adjust_view_column_set(updatable_cols,
2574  viewquery->targetList);
2575  auto_events &= relation_is_updatable(baseoid,
2576  include_triggers,
2577  include_cols);
2578  }
2579  events |= auto_events;
2580  }
2581  }
2582 
2583  /* If we reach here, the relation may support some update commands */
2585  return events;
2586 }
ExecForeignDelete_function ExecForeignDelete
Definition: fdwapi.h:199
Node * qual
Definition: prs2lock.h:28
int numLocks
Definition: prs2lock.h:42
FromExpr * jointree
Definition: parsenodes.h:136
Relation try_relation_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1147
ExecForeignInsert_function ExecForeignInsert
Definition: fdwapi.h:197
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:1260
List * fromlist
Definition: primnodes.h:1470
Form_pg_class rd_rel
Definition: rel.h:114
unsigned int Oid
Definition: postgres_ext.h:31
bool isInstead
Definition: prs2lock.h:31
List * targetList
Definition: parsenodes.h:138
bool trig_insert_instead_row
Definition: reltrigger.h:57
#define linitial(l)
Definition: pg_list.h:111
List * rtable
Definition: parsenodes.h:135
#define ALL_EVENTS
TriggerDesc * trigdesc
Definition: rel.h:120
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 RELKIND_FOREIGN_TABLE
Definition: pg_class.h:167
#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:663
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:198
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
RuleLock * rd_rules
Definition: rel.h:118
RTEKind rtekind
Definition: parsenodes.h:928
FdwRoutine * GetFdwRoutineForRelation(Relation relation, bool makecopy)
Definition: foreign.c:395
#define RELKIND_VIEW
Definition: pg_class.h:164
Query * get_view_query(Relation view)
int i
IsForeignRelUpdatable_function IsForeignRelUpdatable
Definition: fdwapi.h:201
Bitmapset * bms_int_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:791
const char * view_query_is_auto_updatable(Query *viewquery, bool check_cols)
#define RELKIND_RELATION
Definition: pg_class.h:160
static List* RewriteQuery ( Query parsetree,
List rewrite_events 
)
static

Definition at line 3148 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, NULL, 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, RELKIND_VIEW, Query::resultRelation, Query::returningList, rewriteTargetListIU(), rewriteTargetListUD(), rewriteTargetView(), rewriteValuesRTE(), rt_fetch, Query::rtable, RTE_RELATION, RTE_VALUES, RangeTblEntry::rtekind, RangeTblRef::rtindex, Query::targetList, and view_has_instead_trigger().

Referenced by QueryRewrite().

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

Definition at line 334 of file rewriteHandler.c.

References acquireLocksOnSubLinks(), AcquireRewriteLocks(), AddQual(), adjustJoinTreeList(), Assert, ChangeVarNodes(), checkExprHasSubLink(), CMD_INSERT, CMD_UPDATE, CMD_UTILITY, Query::commandType, copyObject, Query::cteList, CommonTableExpr::ctename, ereport, errcode(), errmsg(), ERROR, acquireLocksOnSubLinks_context::for_execute, FromExpr::fromlist, RangeTblEntry::functions, getInsertSelectQuery(), Query::hasRowSecurity, Query::hasSubLinks, Query::jointree, lfirst, list_concat(), list_length(), NIL, NULL, 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, Query::setOperations, RangeTblEntry::tablefunc, RangeTblEntry::tablesample, Query::targetList, and RangeTblEntry::values_lists.

Referenced by fireRules().

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

Definition at line 712 of file rewriteHandler.c.

References ATTRIBUTE_IDENTITY_ALWAYS, ATTRIBUTE_IDENTITY_BY_DEFAULT, tupleDesc::attrs, build_column_default(), CMD_INSERT, CMD_UPDATE, COERCE_IMPLICIT_CAST, coerce_to_domain(), elog, ereport, errcode(), errdetail(), errhint(), errmsg(), ERROR, TargetEntry::expr, flatCopyTargetEntry(), getOwnedSequence(), InvalidOid, IsA, lappend(), lappend_int(), lfirst, list_concat(), makeConst(), makeNode, makeTargetEntry(), makeVar(), NameStr, NIL, NULL, OVERRIDING_SYSTEM_VALUE, OVERRIDING_USER_VALUE, palloc0(), pfree(), process_matched_tle(), pstrdup(), RelationData::rd_att, RelationData::rd_rel, RelationGetNumberOfAttributes, RelationGetRelid, RELKIND_VIEW, TargetEntry::resjunk, TargetEntry::resno, NextValueExpr::seqid, NextValueExpr::typeId, and view_has_instead_trigger().

Referenced by RewriteQuery().

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

Definition at line 1273 of file rewriteHandler.c.

References FdwRoutine::AddForeignUpdateTargets, CMD_DELETE, CMD_UPDATE, Query::commandType, GetFdwRoutineForRelation(), InvalidOid, lappend(), list_length(), makeTargetEntry(), makeVar(), makeWholeRowVar(), NULL, pstrdup(), RelationData::rd_rel, RELKIND_FOREIGN_TABLE, RELKIND_MATVIEW, RELKIND_PARTITIONED_TABLE, RELKIND_RELATION, Query::resultRelation, SelfItemPointerAttributeNumber, Query::targetList, TIDOID, 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 RewriteQuery().

1275 {
1276  Var *var = NULL;
1277  const char *attrname;
1278  TargetEntry *tle;
1279 
1280  if (target_relation->rd_rel->relkind == RELKIND_RELATION ||
1281  target_relation->rd_rel->relkind == RELKIND_MATVIEW ||
1282  target_relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1283  {
1284  /*
1285  * Emit CTID so that executor can find the row to update or delete.
1286  */
1287  var = makeVar(parsetree->resultRelation,
1289  TIDOID,
1290  -1,
1291  InvalidOid,
1292  0);
1293 
1294  attrname = "ctid";
1295  }
1296  else if (target_relation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
1297  {
1298  /*
1299  * Let the foreign table's FDW add whatever junk TLEs it wants.
1300  */
1301  FdwRoutine *fdwroutine;
1302 
1303  fdwroutine = GetFdwRoutineForRelation(target_relation, false);
1304 
1305  if (fdwroutine->AddForeignUpdateTargets != NULL)
1306  fdwroutine->AddForeignUpdateTargets(parsetree, target_rte,
1307  target_relation);
1308 
1309  /*
1310  * If we have a row-level trigger corresponding to the operation, emit
1311  * a whole-row Var so that executor will have the "old" row to pass to
1312  * the trigger. Alas, this misses system columns.
1313  */
1314  if (target_relation->trigdesc &&
1315  ((parsetree->commandType == CMD_UPDATE &&
1316  (target_relation->trigdesc->trig_update_after_row ||
1317  target_relation->trigdesc->trig_update_before_row)) ||
1318  (parsetree->commandType == CMD_DELETE &&
1319  (target_relation->trigdesc->trig_delete_after_row ||
1320  target_relation->trigdesc->trig_delete_before_row))))
1321  {
1322  var = makeWholeRowVar(target_rte,
1323  parsetree->resultRelation,
1324  0,
1325  false);
1326 
1327  attrname = "wholerow";
1328  }
1329  }
1330  else
1331  {
1332  /*
1333  * Emit whole-row Var so that executor will have the "old" view row to
1334  * pass to the INSTEAD OF trigger.
1335  */
1336  var = makeWholeRowVar(target_rte,
1337  parsetree->resultRelation,
1338  0,
1339  false);
1340 
1341  attrname = "wholerow";
1342  }
1343 
1344  if (var != NULL)
1345  {
1346  tle = makeTargetEntry((Expr *) var,
1347  list_length(parsetree->targetList) + 1,
1348  pstrdup(attrname),
1349  true);
1350 
1351  parsetree->targetList = lappend(parsetree->targetList, tle);
1352  }
1353 }
char * pstrdup(const char *in)
Definition: mcxt.c:1077
int resultRelation
Definition: parsenodes.h:120
#define RELKIND_MATVIEW
Definition: pg_class.h:165
Var * makeWholeRowVar(RangeTblEntry *rte, Index varno, Index varlevelsup, bool allowScalar)
Definition: makefuncs.c:132
Form_pg_class rd_rel
Definition: rel.h:114
Definition: primnodes.h:163
AddForeignUpdateTargets_function AddForeignUpdateTargets
Definition: fdwapi.h:194
List * targetList
Definition: parsenodes.h:138
#define TIDOID
Definition: pg_type.h:332
TriggerDesc * trigdesc
Definition: rel.h:120
bool trig_delete_after_row
Definition: reltrigger.h:66
bool trig_update_before_row
Definition: reltrigger.h:60
#define RELKIND_FOREIGN_TABLE
Definition: pg_class.h:167
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:235
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 RELKIND_PARTITIONED_TABLE
Definition: pg_class.h:168
#define InvalidOid
Definition: postgres_ext.h:36
CmdType commandType
Definition: parsenodes.h:110
#define NULL
Definition: c.h:229
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
#define RELKIND_RELATION
Definition: pg_class.h:160
bool trig_delete_before_row
Definition: reltrigger.h:65
static Query* rewriteTargetView ( Query parsetree,
Relation  view 
)
static

Definition at line 2668 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_delete_ptr(), list_length(), llast, makeNode, NIL, NoLock, NULL, 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(), WCO_VIEW_CHECK, and Query::withCheckOptions.

Referenced by RewriteQuery().

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

Definition at line 1185 of file rewriteHandler.c.

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

Referenced by RewriteQuery().

1186 {
1187  List *newValues;
1188  ListCell *lc;
1189 
1190  /*
1191  * Rebuilding all the lists is a pretty expensive proposition in a big
1192  * VALUES list, and it's a waste of time if there aren't any DEFAULT
1193  * placeholders. So first scan to see if there are any.
1194  */
1195  if (!searchForDefault(rte))
1196  return; /* nothing to do */
1197 
1198  /* Check list lengths (we can assume all the VALUES sublists are alike) */
1199  Assert(list_length(attrnos) == list_length(linitial(rte->values_lists)));
1200 
1201  newValues = NIL;
1202  foreach(lc, rte->values_lists)
1203  {
1204  List *sublist = (List *) lfirst(lc);
1205  List *newList = NIL;
1206  ListCell *lc2;
1207  ListCell *lc3;
1208 
1209  forboth(lc2, sublist, lc3, attrnos)
1210  {
1211  Node *col = (Node *) lfirst(lc2);
1212  int attrno = lfirst_int(lc3);
1213 
1214  if (IsA(col, SetToDefault))
1215  {
1216  Form_pg_attribute att_tup;
1217  Node *new_expr;
1218 
1219  att_tup = target_relation->rd_att->attrs[attrno - 1];
1220 
1221  if (!att_tup->attisdropped)
1222  new_expr = build_column_default(target_relation, attrno);
1223  else
1224  new_expr = NULL; /* force a NULL if dropped */
1225 
1226  /*
1227  * If there is no default (ie, default is effectively NULL),
1228  * we've got to explicitly set the column to NULL.
1229  */
1230  if (!new_expr)
1231  {
1232  new_expr = (Node *) makeConst(att_tup->atttypid,
1233  -1,
1234  att_tup->attcollation,
1235  att_tup->attlen,
1236  (Datum) 0,
1237  true, /* isnull */
1238  att_tup->attbyval);
1239  /* this is to catch a NOT NULL domain constraint */
1240  new_expr = coerce_to_domain(new_expr,
1241  InvalidOid, -1,
1242  att_tup->atttypid,
1244  -1,
1245  false,
1246  false);
1247  }
1248  newList = lappend(newList, new_expr);
1249  }
1250  else
1251  newList = lappend(newList, col);
1252  }
1253  newValues = lappend(newValues, newList);
1254  }
1255  rte->values_lists = newValues;
1256 }
#define NIL
Definition: pg_list.h:69
#define IsA(nodeptr, _type_)
Definition: nodes.h:560
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:180
Form_pg_attribute * attrs
Definition: tupdesc.h:74
Definition: nodes.h:509
Const * makeConst(Oid consttype, int32 consttypmod, Oid constcollid, int constlen, Datum constvalue, bool constisnull, bool constbyval)
Definition: makefuncs.c:296
List * values_lists
Definition: parsenodes.h:988
#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, CoercionForm cformat, int location, bool hideInputCoercion, bool lengthCoercionDone)
Definition: parse_coerce.c:648
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:187
List * lappend(List *list, void *datum)
Definition: list.c:128
Node * build_column_default(Relation rel, int attrno)
uintptr_t Datum
Definition: postgres.h:372
TupleDesc rd_att
Definition: rel.h:115
#define InvalidOid
Definition: postgres_ext.h:36
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
#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
static bool searchForDefault ( RangeTblEntry rte)
static

Definition at line 1153 of file rewriteHandler.c.

References IsA, lfirst, and RangeTblEntry::values_lists.

Referenced by rewriteValuesRTE().

1154 {
1155  ListCell *lc;
1156 
1157  foreach(lc, rte->values_lists)
1158  {
1159  List *sublist = (List *) lfirst(lc);
1160  ListCell *lc2;
1161 
1162  foreach(lc2, sublist)
1163  {
1164  Node *col = (Node *) lfirst(lc2);
1165 
1166  if (IsA(col, SetToDefault))
1167  return true;
1168  }
1169  }
1170  return false;
1171 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:560
Definition: nodes.h:509
List * values_lists
Definition: parsenodes.h:988
#define lfirst(lc)
Definition: pg_list.h:106
Definition: pg_list.h:45
static const char* view_col_is_auto_updatable ( RangeTblRef rtr,
TargetEntry tle 
)
static

Definition at line 2166 of file rewriteHandler.c.

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

Referenced by view_cols_are_auto_updatable(), and view_query_is_auto_updatable().

2167 {
2168  Var *var = (Var *) tle->expr;
2169 
2170  /*
2171  * For now, the only updatable columns we support are those that are Vars
2172  * referring to user columns of the underlying base relation.
2173  *
2174  * The view targetlist may contain resjunk columns (e.g., a view defined
2175  * like "SELECT * FROM t ORDER BY a+b" is auto-updatable) but such columns
2176  * are not auto-updatable, and in fact should never appear in the outer
2177  * query's targetlist.
2178  */
2179  if (tle->resjunk)
2180  return gettext_noop("Junk view columns are not updatable.");
2181 
2182  if (!IsA(var, Var) ||
2183  var->varno != rtr->rtindex ||
2184  var->varlevelsup != 0)
2185  return gettext_noop("View columns that are not columns of their base relation are not updatable.");
2186 
2187  if (var->varattno < 0)
2188  return gettext_noop("View columns that refer to system columns are not updatable.");
2189 
2190  if (var->varattno == 0)
2191  return gettext_noop("View columns that return whole-row references are not updatable.");
2192 
2193  return NULL; /* the view column is updatable */
2194 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:560
Index varlevelsup
Definition: primnodes.h:173
#define gettext_noop(x)
Definition: c.h:139
AttrNumber varattno
Definition: primnodes.h:168
Definition: primnodes.h:163
bool resjunk
Definition: primnodes.h:1374
Index varno
Definition: primnodes.h:166
#define NULL
Definition: c.h:229
Expr * expr
Definition: primnodes.h:1367
static const char* view_cols_are_auto_updatable ( Query viewquery,
Bitmapset required_cols,
Bitmapset **  updatable_cols,
char **  non_updatable_col 
)
static

Definition at line 2356 of file rewriteHandler.c.

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

Referenced by relation_is_updatable(), and rewriteTargetView().

2360 {
2361  RangeTblRef *rtr;
2362  AttrNumber col;
2363  ListCell *cell;
2364 
2365  /*
2366  * The caller should have verified that this view is auto-updatable and so
2367  * there should be a single base relation.
2368  */
2369  Assert(list_length(viewquery->jointree->fromlist) == 1);
2370  rtr = linitial_node(RangeTblRef, viewquery->jointree->fromlist);
2371 
2372  /* Initialize the optional return values */
2373  if (updatable_cols != NULL)
2374  *updatable_cols = NULL;
2375  if (non_updatable_col != NULL)
2376  *non_updatable_col = NULL;
2377 
2378  /* Test each view column for updatability */
2380  foreach(cell, viewquery->targetList)
2381  {
2382  TargetEntry *tle = (TargetEntry *) lfirst(cell);
2383  const char *col_update_detail;
2384 
2385  col++;
2386  col_update_detail = view_col_is_auto_updatable(rtr, tle);
2387 
2388  if (col_update_detail == NULL)
2389  {
2390  /* The column is updatable */
2391  if (updatable_cols != NULL)
2392  *updatable_cols = bms_add_member(*updatable_cols, col);
2393  }
2394  else if (bms_is_member(col, required_cols))
2395  {
2396  /* The required column is not updatable */
2397  if (non_updatable_col != NULL)
2398  *non_updatable_col = tle->resname;
2399  return col_update_detail;
2400  }
2401  }
2402 
2403  return NULL; /* all the required view columns are updatable */
2404 }
FromExpr * jointree
Definition: parsenodes.h:136
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:28
List * fromlist
Definition: primnodes.h:1470
char * resname
Definition: primnodes.h:1369
#define linitial_node(type, l)
Definition: pg_list.h:114
List * targetList
Definition: parsenodes.h:138
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
#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:698
static const char * view_col_is_auto_updatable(RangeTblRef *rtr, TargetEntry *tle)
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:420
int16 AttrNumber
Definition: attnum.h:21
static bool view_has_instead_trigger ( Relation  view,
CmdType  event 
)
static

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

2132 {
2133  TriggerDesc *trigDesc = view->trigdesc;
2134 
2135  switch (event)
2136  {
2137  case CMD_INSERT:
2138  if (trigDesc && trigDesc->trig_insert_instead_row)
2139  return true;
2140  break;
2141  case CMD_UPDATE:
2142  if (trigDesc && trigDesc->trig_update_instead_row)
2143  return true;
2144  break;
2145  case CMD_DELETE:
2146  if (trigDesc && trigDesc->trig_delete_instead_row)
2147  return true;
2148  break;
2149  default:
2150  elog(ERROR, "unrecognized CmdType: %d", (int) event);
2151  break;
2152  }
2153  return false;
2154 }
bool trig_insert_instead_row
Definition: reltrigger.h:57
#define ERROR
Definition: elog.h:43
TriggerDesc * trigdesc
Definition: rel.h:120
bool trig_update_instead_row
Definition: reltrigger.h:62
bool trig_delete_instead_row
Definition: reltrigger.h:67
#define elog
Definition: elog.h:219
const char* view_query_is_auto_updatable ( Query viewquery,
bool  check_cols 
)

Definition at line 2211 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, NULL, RangeTblEntry::relkind, RELKIND_FOREIGN_TABLE, RELKIND_PARTITIONED_TABLE, RELKIND_RELATION, RELKIND_VIEW, 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().

2212 {
2213  RangeTblRef *rtr;
2214  RangeTblEntry *base_rte;
2215 
2216  /*----------
2217  * Check if the view is simply updatable. According to SQL-92 this means:
2218  * - No DISTINCT clause.
2219  * - Each TLE is a column reference, and each column appears at most once.
2220  * - FROM contains exactly one base relation.
2221  * - No GROUP BY or HAVING clauses.
2222  * - No set operations (UNION, INTERSECT or EXCEPT).
2223  * - No sub-queries in the WHERE clause that reference the target table.
2224  *
2225  * We ignore that last restriction since it would be complex to enforce
2226  * and there isn't any actual benefit to disallowing sub-queries. (The
2227  * semantic issues that the standard is presumably concerned about don't
2228  * arise in Postgres, since any such sub-query will not see any updates
2229  * executed by the outer query anyway, thanks to MVCC snapshotting.)
2230  *
2231  * We also relax the second restriction by supporting part of SQL:1999
2232  * feature T111, which allows for a mix of updatable and non-updatable
2233  * columns, provided that an INSERT or UPDATE doesn't attempt to assign to
2234  * a non-updatable column.
2235  *
2236  * In addition we impose these constraints, involving features that are
2237  * not part of SQL-92:
2238  * - No CTEs (WITH clauses).
2239  * - No OFFSET or LIMIT clauses (this matches a SQL:2008 restriction).
2240  * - No system columns (including whole-row references) in the tlist.
2241  * - No window functions in the tlist.
2242  * - No set-returning functions in the tlist.
2243  *
2244  * Note that we do these checks without recursively expanding the view.
2245  * If the base relation is a view, we'll recursively deal with it later.
2246  *----------
2247  */
2248  if (viewquery->distinctClause != NIL)
2249  return gettext_noop("Views containing DISTINCT are not automatically updatable.");
2250 
2251  if (viewquery->groupClause != NIL || viewquery->groupingSets)
2252  return gettext_noop("Views containing GROUP BY are not automatically updatable.");
2253 
2254  if (viewquery->havingQual != NULL)
2255  return gettext_noop("Views containing HAVING are not automatically updatable.");
2256 
2257  if (viewquery->setOperations != NULL)
2258  return gettext_noop("Views containing UNION, INTERSECT, or EXCEPT are not automatically updatable.");
2259 
2260  if (viewquery->cteList != NIL)
2261  return gettext_noop("Views containing WITH are not automatically updatable.");
2262 
2263  if (viewquery->limitOffset != NULL || viewquery->limitCount != NULL)
2264  return gettext_noop("Views containing LIMIT or OFFSET are not automatically updatable.");
2265 
2266  /*
2267  * We must not allow window functions or set returning functions in the
2268  * targetlist. Otherwise we might end up inserting them into the quals of
2269  * the main query. We must also check for aggregates in the targetlist in
2270  * case they appear without a GROUP BY.
2271  *
2272  * These restrictions ensure that each row of the view corresponds to a
2273  * unique row in the underlying base relation.
2274  */
2275  if (viewquery->hasAggs)
2276  return gettext_noop("Views that return aggregate functions are not automatically updatable.");
2277 
2278  if (viewquery->hasWindowFuncs)
2279  return gettext_noop("Views that return window functions are not automatically updatable.");
2280 
2281  if (viewquery->hasTargetSRFs)
2282  return gettext_noop("Views that return set-returning functions are not automatically updatable.");
2283 
2284  /*
2285  * The view query should select from a single base relation, which must be
2286  * a table or another view.
2287  */
2288  if (list_length(viewquery->jointree->fromlist) != 1)
2289  return gettext_noop("Views that do not select from a single table or view are not automatically updatable.");
2290 
2291  rtr = (RangeTblRef *) linitial(viewquery->jointree->fromlist);
2292  if (!IsA(rtr, RangeTblRef))
2293  return gettext_noop("Views that do not select from a single table or view are not automatically updatable.");
2294 
2295  base_rte = rt_fetch(rtr->rtindex, viewquery->rtable);
2296  if (base_rte->rtekind != RTE_RELATION ||
2297  (base_rte->relkind != RELKIND_RELATION &&
2298  base_rte->relkind != RELKIND_FOREIGN_TABLE &&
2299  base_rte->relkind != RELKIND_VIEW &&
2300  base_rte->relkind != RELKIND_PARTITIONED_TABLE))
2301  return gettext_noop("Views that do not select from a single table or view are not automatically updatable.");
2302 
2303  if (base_rte->tablesample)
2304  return gettext_noop("Views containing TABLESAMPLE are not automatically updatable.");
2305 
2306  /*
2307  * Check that the view has at least one updatable column. This is required
2308  * for INSERT/UPDATE but not for DELETE.
2309  */
2310  if (check_cols)
2311  {
2312  ListCell *cell;
2313  bool found;
2314 
2315  found = false;
2316  foreach(cell, viewquery->targetList)
2317  {
2318  TargetEntry *tle = (TargetEntry *) lfirst(cell);
2319 
2320  if (view_col_is_auto_updatable(rtr, tle) == NULL)
2321  {
2322  found = true;
2323  break;
2324  }
2325  }
2326 
2327  if (!found)
2328  return gettext_noop("Views that have no updatable columns are not automatically updatable.");
2329  }
2330 
2331  return NULL; /* the view is updatable */
2332 }
Node * limitOffset
Definition: parsenodes.h:158
#define NIL
Definition: pg_list.h:69
#define IsA(nodeptr, _type_)
Definition: nodes.h:560
FromExpr * jointree
Definition: parsenodes.h:136
bool hasAggs
Definition: parsenodes.h:123
List * groupingSets
Definition: parsenodes.h:148
#define gettext_noop(x)
Definition: c.h:139
List * fromlist
Definition: primnodes.h:1470
List * targetList
Definition: parsenodes.h:138
#define linitial(l)
Definition: pg_list.h:111
List * rtable
Definition: parsenodes.h:135
List * distinctClause
Definition: parsenodes.h:154
Node * limitCount
Definition: parsenodes.h:159
#define RELKIND_FOREIGN_TABLE
Definition: pg_class.h:167
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
#define RELKIND_PARTITIONED_TABLE
Definition: pg_class.h:168
bool hasTargetSRFs
Definition: parsenodes.h:125
#define NULL
Definition: c.h:229
#define lfirst(lc)
Definition: pg_list.h:106
bool hasWindowFuncs
Definition: parsenodes.h:124
static int list_length(const List *l)
Definition: pg_list.h:89
RTEKind rtekind
Definition: parsenodes.h:928
List * cteList
Definition: parsenodes.h:133
Node * setOperations
Definition: parsenodes.h:163
List * groupClause
Definition: parsenodes.h:146
#define RELKIND_VIEW
Definition: pg_class.h:164
static const char * view_col_is_auto_updatable(RangeTblRef *rtr, TargetEntry *tle)
Node * havingQual
Definition: parsenodes.h:150
#define RELKIND_RELATION
Definition: pg_class.h:160
struct TableSampleClause * tablesample
Definition: parsenodes.h:941