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/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, 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 291 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().

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

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

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

Definition at line 2551 of file rewriteHandler.c.

References bms_add_member(), bms_next_member(), castNode, elog, ERROR, TargetEntry::expr, FirstLowInvalidHeapAttributeNumber, get_tle_by_resno(), InvalidAttrNumber, IsA, lfirst, NULL, TargetEntry::resjunk, and Var::varattno.

Referenced by relation_is_updatable(), and rewriteTargetView().

2552 {
2553  Bitmapset *result = NULL;
2554  int col;
2555 
2556  col = -1;
2557  while ((col = bms_next_member(cols, col)) >= 0)
2558  {
2559  /* bit numbers are offset by FirstLowInvalidHeapAttributeNumber */
2561 
2562  if (attno == InvalidAttrNumber)
2563  {
2564  /*
2565  * There's a whole-row reference to the view. For permissions
2566  * purposes, treat it as a reference to each column available from
2567  * the view. (We should *not* convert this to a whole-row
2568  * reference to the base relation, since the view may not touch
2569  * all columns of the base relation.)
2570  */
2571  ListCell *lc;
2572 
2573  foreach(lc, targetlist)
2574  {
2575  TargetEntry *tle = (TargetEntry *) lfirst(lc);
2576  Var *var;
2577 
2578  if (tle->resjunk)
2579  continue;
2580  var = castNode(Var, tle->expr);
2581  result = bms_add_member(result,
2582  var->varattno - FirstLowInvalidHeapAttributeNumber);
2583  }
2584  }
2585  else
2586  {
2587  /*
2588  * Views do not have system columns, so we do not expect to see
2589  * any other system attnos here. If we do find one, the error
2590  * case will apply.
2591  */
2592  TargetEntry *tle = get_tle_by_resno(targetlist, attno);
2593 
2594  if (tle != NULL && !tle->resjunk && IsA(tle->expr, Var))
2595  {
2596  Var *var = (Var *) tle->expr;
2597 
2598  result = bms_add_member(result,
2599  var->varattno - FirstLowInvalidHeapAttributeNumber);
2600  }
2601  else
2602  elog(ERROR, "attribute number %d not found in view targetlist",
2603  attno);
2604  }
2605  }
2606 
2607  return result;
2608 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:559
#define castNode(_type_, nodeptr)
Definition: nodes.h:577
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:907
AttrNumber varattno
Definition: primnodes.h:146
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:28
Definition: primnodes.h:141
bool resjunk
Definition: primnodes.h:1337
#define ERROR
Definition: elog.h:43
#define NULL
Definition: c.h:226
#define lfirst(lc)
Definition: pg_list.h:106
Expr * expr
Definition: primnodes.h:1330
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:668
#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 631 of file rewriteHandler.c.

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

Referenced by rewriteRuleAction().

632 {
633  List *newjointree = copyObject(parsetree->jointree->fromlist);
634  ListCell *l;
635 
636  if (removert)
637  {
638  foreach(l, newjointree)
639  {
640  RangeTblRef *rtr = lfirst(l);
641 
642  if (IsA(rtr, RangeTblRef) &&
643  rtr->rtindex == rt_index)
644  {
645  newjointree = list_delete_ptr(newjointree, rtr);
646 
647  /*
648  * foreach is safe because we exit loop after list_delete...
649  */
650  break;
651  }
652  }
653  }
654  return newjointree;
655 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:559
FromExpr * jointree
Definition: parsenodes.h:129
List * fromlist
Definition: primnodes.h:1433
List * list_delete_ptr(List *list, void *datum)
Definition: list.c:590
void * copyObject(const void *from)
Definition: copyfuncs.c:4475
#define lfirst(lc)
Definition: pg_list.h:106
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 1380 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().

1386 {
1387  Query *rule_action;
1388  RangeTblEntry *rte,
1389  *subrte;
1390  RowMarkClause *rc;
1391 
1392  if (list_length(rule->actions) != 1)
1393  elog(ERROR, "expected just one rule action");
1394  if (rule->qual != NULL)
1395  elog(ERROR, "cannot handle qualified ON SELECT rule");
1396 
1397  if (rt_index == parsetree->resultRelation)
1398  {
1399  /*
1400  * We have a view as the result relation of the query, and it wasn't
1401  * rewritten by any rule. This case is supported if there is an
1402  * INSTEAD OF trigger that will trap attempts to insert/update/delete
1403  * view rows. The executor will check that; for the moment just plow
1404  * ahead. We have two cases:
1405  *
1406  * For INSERT, we needn't do anything. The unmodified RTE will serve
1407  * fine as the result relation.
1408  *
1409  * For UPDATE/DELETE, we need to expand the view so as to have source
1410  * data for the operation. But we also need an unmodified RTE to
1411  * serve as the target. So, copy the RTE and add the copy to the
1412  * rangetable. Note that the copy does not get added to the jointree.
1413  * Also note that there's a hack in fireRIRrules to avoid calling this
1414  * function again when it arrives at the copied RTE.
1415  */
1416  if (parsetree->commandType == CMD_INSERT)
1417  return parsetree;
1418  else if (parsetree->commandType == CMD_UPDATE ||
1419  parsetree->commandType == CMD_DELETE)
1420  {
1421  RangeTblEntry *newrte;
1422 
1423  rte = rt_fetch(rt_index, parsetree->rtable);
1424  newrte = copyObject(rte);
1425  parsetree->rtable = lappend(parsetree->rtable, newrte);
1426  parsetree->resultRelation = list_length(parsetree->rtable);
1427 
1428  /*
1429  * There's no need to do permissions checks twice, so wipe out the
1430  * permissions info for the original RTE (we prefer to keep the
1431  * bits set on the result RTE).
1432  */
1433  rte->requiredPerms = 0;
1434  rte->checkAsUser = InvalidOid;
1435  rte->selectedCols = NULL;
1436  rte->insertedCols = NULL;
1437  rte->updatedCols = NULL;
1438 
1439  /*
1440  * For the most part, Vars referencing the view should remain as
1441  * they are, meaning that they implicitly represent OLD values.
1442  * But in the RETURNING list if any, we want such Vars to
1443  * represent NEW values, so change them to reference the new RTE.
1444  *
1445  * Since ChangeVarNodes scribbles on the tree in-place, copy the
1446  * RETURNING list first for safety.
1447  */
1448  parsetree->returningList = copyObject(parsetree->returningList);
1449  ChangeVarNodes((Node *) parsetree->returningList, rt_index,
1450  parsetree->resultRelation, 0);
1451 
1452  /* Now, continue with expanding the original view RTE */
1453  }
1454  else
1455  elog(ERROR, "unrecognized commandType: %d",
1456  (int) parsetree->commandType);
1457  }
1458 
1459  /*
1460  * If FOR [KEY] UPDATE/SHARE of view, be sure we get right initial lock on
1461  * the relations it references.
1462  */
1463  rc = get_parse_rowmark(parsetree, rt_index);
1464  forUpdatePushedDown |= (rc != NULL);
1465 
1466  /*
1467  * Make a modifiable copy of the view query, and acquire needed locks on
1468  * the relations it mentions.
1469  */
1470  rule_action = copyObject(linitial(rule->actions));
1471 
1472  AcquireRewriteLocks(rule_action, true, forUpdatePushedDown);
1473 
1474  /*
1475  * Recursively expand any view references inside the view.
1476  */
1477  rule_action = fireRIRrules(rule_action, activeRIRs, forUpdatePushedDown);
1478 
1479  /*
1480  * Now, plug the view query in as a subselect, replacing the relation's
1481  * original RTE.
1482  */
1483  rte = rt_fetch(rt_index, parsetree->rtable);
1484 
1485  rte->rtekind = RTE_SUBQUERY;
1486  rte->relid = InvalidOid;
1487  rte->security_barrier = RelationIsSecurityView(relation);
1488  rte->subquery = rule_action;
1489  rte->inh = false; /* must not be set for a subquery */
1490 
1491  /*
1492  * We move the view's permission check data down to its rangetable. The
1493  * checks will actually be done against the OLD entry therein.
1494  */
1495  subrte = rt_fetch(PRS2_OLD_VARNO, rule_action->rtable);
1496  Assert(subrte->relid == relation->rd_id);
1497  subrte->requiredPerms = rte->requiredPerms;
1498  subrte->checkAsUser = rte->checkAsUser;
1499  subrte->selectedCols = rte->selectedCols;
1500  subrte->insertedCols = rte->insertedCols;
1501  subrte->updatedCols = rte->updatedCols;
1502 
1503  rte->requiredPerms = 0; /* no permission check on subquery itself */
1504  rte->checkAsUser = InvalidOid;
1505  rte->selectedCols = NULL;
1506  rte->insertedCols = NULL;
1507  rte->updatedCols = NULL;
1508 
1509  /*
1510  * If FOR [KEY] UPDATE/SHARE of view, mark all the contained tables as
1511  * implicit FOR [KEY] UPDATE/SHARE, the same as the parser would have done
1512  * if the view's subquery had been written out explicitly.
1513  *
1514  * Note: we don't consider forUpdatePushedDown here; such marks will be
1515  * made by recursing from the upper level in markQueryForLocking.
1516  */
1517  if (rc != NULL)
1518  markQueryForLocking(rule_action, (Node *) rule_action->jointree,
1519  rc->strength, rc->waitPolicy, true);
1520 
1521  return parsetree;
1522 }
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:129
int resultRelation
Definition: parsenodes.h:113
Definition: nodes.h:508
AclMode requiredPerms
Definition: parsenodes.h:965
LockClauseStrength strength
Definition: parsenodes.h:1220
void * copyObject(const void *from)
Definition: copyfuncs.c:4475
Bitmapset * selectedCols
Definition: parsenodes.h:967
#define linitial(l)
Definition: pg_list.h:110
List * rtable
Definition: parsenodes.h:128
#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:135
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
Oid rd_id
Definition: rel.h:115
List * lappend(List *list, void *datum)
Definition: list.c:128
#define PRS2_OLD_VARNO
Definition: primnodes.h:138
bool security_barrier
Definition: parsenodes.h:901
#define InvalidOid
Definition: postgres_ext.h:36
Bitmapset * updatedCols
Definition: parsenodes.h:969
CmdType commandType
Definition: parsenodes.h:103
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:671
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:1221
RTEKind rtekind
Definition: parsenodes.h:882
Query * subquery
Definition: parsenodes.h:900
Bitmapset * insertedCols
Definition: parsenodes.h:968
#define RelationIsSecurityView(relation)
Definition: rel.h:344
void ChangeVarNodes(Node *node, int rt_index, int new_index, int sublevels_up)
Definition: rewriteManip.c:607
#define elog
Definition: elog.h:219
Node* build_column_default ( Relation  rel,
int  attrno 
)

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

1035 {
1036  TupleDesc rd_att = rel->rd_att;
1037  Form_pg_attribute att_tup = rd_att->attrs[attrno - 1];
1038  Oid atttype = att_tup->atttypid;
1039  int32 atttypmod = att_tup->atttypmod;
1040  Node *expr = NULL;
1041  Oid exprtype;
1042 
1043  /*
1044  * Scan to see if relation has a default for this column.
1045  */
1046  if (rd_att->constr && rd_att->constr->num_defval > 0)
1047  {
1048  AttrDefault *defval = rd_att->constr->defval;
1049  int ndef = rd_att->constr->num_defval;
1050 
1051  while (--ndef >= 0)
1052  {
1053  if (attrno == defval[ndef].adnum)
1054  {
1055  /*
1056  * Found it, convert string representation to node tree.
1057  */
1058  expr = stringToNode(defval[ndef].adbin);
1059  break;
1060  }
1061  }
1062  }
1063 
1064  if (expr == NULL)
1065  {
1066  /*
1067  * No per-column default, so look for a default for the type itself.
1068  */
1069  expr = get_typdefault(atttype);
1070  }
1071 
1072  if (expr == NULL)
1073  return NULL; /* No default anywhere */
1074 
1075  /*
1076  * Make sure the value is coerced to the target column type; this will
1077  * generally be true already, but there seem to be some corner cases
1078  * involving domain defaults where it might not be true. This should match
1079  * the parser's processing of non-defaulted expressions --- see
1080  * transformAssignedExpr().
1081  */
1082  exprtype = exprType(expr);
1083 
1084  expr = coerce_to_target_type(NULL, /* no UNKNOWN params here */
1085  expr, exprtype,
1086  atttype, atttypmod,
1089  -1);
1090  if (expr == NULL)
1091  ereport(ERROR,
1092  (errcode(ERRCODE_DATATYPE_MISMATCH),
1093  errmsg("column \"%s\" is of type %s"
1094  " but default expression is of type %s",
1095  NameStr(att_tup->attname),
1096  format_type_be(atttype),
1097  format_type_be(exprtype)),
1098  errhint("You will need to rewrite or cast the expression.")));
1099 
1100  return expr;
1101 }
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:508
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:253
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:184
#define ereport(elevel, rest)
Definition: elog.h:122
TupleDesc rd_att
Definition: rel.h:114
uint16 num_defval
Definition: tupdesc.h:41
#define NULL
Definition: c.h:226
Node * get_typdefault(Oid typid)
Definition: lsyscache.c:2166
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:495
static Query* CopyAndAddInvertedQual ( Query parsetree,
Node rule_qual,
int  rt_index,
CmdType  event 
)
static

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

1894 {
1895  /* Don't scribble on the passed qual (it's in the relcache!) */
1896  Node *new_qual = (Node *) copyObject(rule_qual);
1898 
1899  context.for_execute = true;
1900 
1901  /*
1902  * In case there are subqueries in the qual, acquire necessary locks and
1903  * fix any deleted JOIN RTE entries. (This is somewhat redundant with
1904  * rewriteRuleAction, but not entirely ... consider restructuring so that
1905  * we only need to process the qual this way once.)
1906  */
1907  (void) acquireLocksOnSubLinks(new_qual, &context);
1908 
1909  /* Fix references to OLD */
1910  ChangeVarNodes(new_qual, PRS2_OLD_VARNO, rt_index, 0);
1911  /* Fix references to NEW */
1912  if (event == CMD_INSERT || event == CMD_UPDATE)
1913  new_qual = ReplaceVarsFromTargetList(new_qual,
1915  0,
1916  rt_fetch(rt_index,
1917  parsetree->rtable),
1918  parsetree->targetList,
1919  (event == CMD_UPDATE) ?
1922  rt_index,
1923  &parsetree->hasSubLinks);
1924  /* And attach the fixed qual */
1925  AddInvertedQual(parsetree, new_qual);
1926 
1927  return parsetree;
1928 }
static bool acquireLocksOnSubLinks(Node *node, acquireLocksOnSubLinks_context *context)
void AddInvertedQual(Query *parsetree, Node *qual)
Definition: nodes.h:508
List * targetList
Definition: parsenodes.h:131
void * copyObject(const void *from)
Definition: copyfuncs.c:4475
List * rtable
Definition: parsenodes.h:128
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
#define PRS2_OLD_VARNO
Definition: primnodes.h:138
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:119
void ChangeVarNodes(Node *node, int rt_index, int new_index, int sublevels_up)
Definition: rewriteManip.c:607
#define PRS2_NEW_VARNO
Definition: primnodes.h:139
static bool fireRIRonSubLink ( Node node,
List activeRIRs 
)
static

Definition at line 1596 of file rewriteHandler.c.

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

Referenced by fireRIRrules().

1597 {
1598  if (node == NULL)
1599  return false;
1600  if (IsA(node, SubLink))
1601  {
1602  SubLink *sub = (SubLink *) node;
1603 
1604  /* Do what we came for */
1605  sub->subselect = (Node *) fireRIRrules((Query *) sub->subselect,
1606  activeRIRs, false);
1607  /* Fall through to process lefthand args of SubLink */
1608  }
1609 
1610  /*
1611  * Do NOT recurse into Query nodes, because fireRIRrules already processed
1612  * subselects of subselects for us.
1613  */
1615  (void *) activeRIRs);
1616 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:559
Definition: nodes.h:508
static bool fireRIRonSubLink(Node *node, List *activeRIRs)
#define NULL
Definition: c.h:226
static Query * fireRIRrules(Query *parsetree, List *activeRIRs, bool forUpdatePushedDown)
bool expression_tree_walker(Node *node, bool(*walker)(), void *context)
Definition: nodeFuncs.c:1852
static Query * fireRIRrules ( Query parsetree,
List activeRIRs,
bool  forUpdatePushedDown 
)
static

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

1625 {
1626  int origResultRelation = parsetree->resultRelation;
1627  int rt_index;
1628  ListCell *lc;
1629 
1630  /*
1631  * don't try to convert this into a foreach loop, because rtable list can
1632  * get changed each time through...
1633  */
1634  rt_index = 0;
1635  while (rt_index < list_length(parsetree->rtable))
1636  {
1637  RangeTblEntry *rte;
1638  Relation rel;
1639  List *locks;
1640  RuleLock *rules;
1641  RewriteRule *rule;
1642  int i;
1643 
1644  ++rt_index;
1645 
1646  rte = rt_fetch(rt_index, parsetree->rtable);
1647 
1648  /*
1649  * A subquery RTE can't have associated rules, so there's nothing to
1650  * do to this level of the query, but we must recurse into the
1651  * subquery to expand any rule references in it.
1652  */
1653  if (rte->rtekind == RTE_SUBQUERY)
1654  {
1655  rte->subquery = fireRIRrules(rte->subquery, activeRIRs,
1656  (forUpdatePushedDown ||
1657  get_parse_rowmark(parsetree, rt_index) != NULL));
1658  continue;
1659  }
1660 
1661  /*
1662  * Joins and other non-relation RTEs can be ignored completely.
1663  */
1664  if (rte->rtekind != RTE_RELATION)
1665  continue;
1666 
1667  /*
1668  * Always ignore RIR rules for materialized views referenced in
1669  * queries. (This does not prevent refreshing MVs, since they aren't
1670  * referenced in their own query definitions.)
1671  *
1672  * Note: in the future we might want to allow MVs to be conditionally
1673  * expanded as if they were regular views, if they are not scannable.
1674  * In that case this test would need to be postponed till after we've
1675  * opened the rel, so that we could check its state.
1676  */
1677  if (rte->relkind == RELKIND_MATVIEW)
1678  continue;
1679 
1680  /*
1681  * If the table is not referenced in the query, then we ignore it.
1682  * This prevents infinite expansion loop due to new rtable entries
1683  * inserted by expansion of a rule. A table is referenced if it is
1684  * part of the join set (a source table), or is referenced by any Var
1685  * nodes, or is the result table.
1686  */
1687  if (rt_index != parsetree->resultRelation &&
1688  !rangeTableEntry_used((Node *) parsetree, rt_index, 0))
1689  continue;
1690 
1691  /*
1692  * Also, if this is a new result relation introduced by
1693  * ApplyRetrieveRule, we don't want to do anything more with it.
1694  */
1695  if (rt_index == parsetree->resultRelation &&
1696  rt_index != origResultRelation)
1697  continue;
1698 
1699  /*
1700  * We can use NoLock here since either the parser or
1701  * AcquireRewriteLocks should have locked the rel already.
1702  */
1703  rel = heap_open(rte->relid, NoLock);
1704 
1705  /*
1706  * Collect the RIR rules that we must apply
1707  */
1708  rules = rel->rd_rules;
1709  if (rules != NULL)
1710  {
1711  locks = NIL;
1712  for (i = 0; i < rules->numLocks; i++)
1713  {
1714  rule = rules->rules[i];
1715  if (rule->event != CMD_SELECT)
1716  continue;
1717 
1718  locks = lappend(locks, rule);
1719  }
1720 
1721  /*
1722  * If we found any, apply them --- but first check for recursion!
1723  */
1724  if (locks != NIL)
1725  {
1726  ListCell *l;
1727 
1728  if (list_member_oid(activeRIRs, RelationGetRelid(rel)))
1729  ereport(ERROR,
1730  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1731  errmsg("infinite recursion detected in rules for relation \"%s\"",
1732  RelationGetRelationName(rel))));
1733  activeRIRs = lcons_oid(RelationGetRelid(rel), activeRIRs);
1734 
1735  foreach(l, locks)
1736  {
1737  rule = lfirst(l);
1738 
1739  parsetree = ApplyRetrieveRule(parsetree,
1740  rule,
1741  rt_index,
1742  rel,
1743  activeRIRs,
1744  forUpdatePushedDown);
1745  }
1746 
1747  activeRIRs = list_delete_first(activeRIRs);
1748  }
1749  }
1750 
1751  heap_close(rel, NoLock);
1752  }
1753 
1754  /* Recurse into subqueries in WITH */
1755  foreach(lc, parsetree->cteList)
1756  {
1757  CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
1758 
1759  cte->ctequery = (Node *)
1760  fireRIRrules((Query *) cte->ctequery, activeRIRs, false);
1761  }
1762 
1763  /*
1764  * Recurse into sublink subqueries, too. But we already did the ones in
1765  * the rtable and cteList.
1766  */
1767  if (parsetree->hasSubLinks)
1768  query_tree_walker(parsetree, fireRIRonSubLink, (void *) activeRIRs,
1770 
1771  /*
1772  * Apply any row level security policies. We do this last because it
1773  * requires special recursion detection if the new quals have sublink
1774  * subqueries, and if we did it in the loop above query_tree_walker would
1775  * then recurse into those quals a second time.
1776  */
1777  rt_index = 0;
1778  foreach(lc, parsetree->rtable)
1779  {
1780  RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
1781  Relation rel;
1782  List *securityQuals;
1783  List *withCheckOptions;
1784  bool hasRowSecurity;
1785  bool hasSubLinks;
1786 
1787  ++rt_index;
1788 
1789  /* Only normal relations can have RLS policies */
1790  if (rte->rtekind != RTE_RELATION ||
1791  rte->relkind != RELKIND_RELATION)
1792  continue;
1793 
1794  rel = heap_open(rte->relid, NoLock);
1795 
1796  /*
1797  * Fetch any new security quals that must be applied to this RTE.
1798  */
1799  get_row_security_policies(parsetree, rte, rt_index,
1800  &securityQuals, &withCheckOptions,
1801  &hasRowSecurity, &hasSubLinks);
1802 
1803  if (securityQuals != NIL || withCheckOptions != NIL)
1804  {
1805  if (hasSubLinks)
1806  {
1808 
1809  /*
1810  * Recursively process the new quals, checking for infinite
1811  * recursion.
1812  */
1813  if (list_member_oid(activeRIRs, RelationGetRelid(rel)))
1814  ereport(ERROR,
1815  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1816  errmsg("infinite recursion detected in policy for relation \"%s\"",
1817  RelationGetRelationName(rel))));
1818 
1819  activeRIRs = lcons_oid(RelationGetRelid(rel), activeRIRs);
1820 
1821  /*
1822  * get_row_security_policies just passed back securityQuals
1823  * and/or withCheckOptions, and there were SubLinks, make sure
1824  * we lock any relations which are referenced.
1825  *
1826  * These locks would normally be acquired by the parser, but
1827  * securityQuals and withCheckOptions are added post-parsing.
1828  */
1829  context.for_execute = true;
1830  (void) acquireLocksOnSubLinks((Node *) securityQuals, &context);
1831  (void) acquireLocksOnSubLinks((Node *) withCheckOptions,
1832  &context);
1833 
1834  /*
1835  * Now that we have the locks on anything added by
1836  * get_row_security_policies, fire any RIR rules for them.
1837  */
1838  expression_tree_walker((Node *) securityQuals,
1839  fireRIRonSubLink, (void *) activeRIRs);
1840 
1841  expression_tree_walker((Node *) withCheckOptions,
1842  fireRIRonSubLink, (void *) activeRIRs);
1843 
1844  activeRIRs = list_delete_first(activeRIRs);
1845  }
1846 
1847  /*
1848  * Add the new security barrier quals to the start of the RTE's
1849  * list so that they get applied before any existing barrier quals
1850  * (which would have come from a security-barrier view, and should
1851  * get lower priority than RLS conditions on the table itself).
1852  */
1853  rte->securityQuals = list_concat(securityQuals,
1854  rte->securityQuals);
1855 
1856  parsetree->withCheckOptions = list_concat(withCheckOptions,
1857  parsetree->withCheckOptions);
1858  }
1859 
1860  /*
1861  * Make sure the query is marked correctly if row level security
1862  * applies, or if the new quals had sublinks.
1863  */
1864  if (hasRowSecurity)
1865  parsetree->hasRowSecurity = true;
1866  if (hasSubLinks)
1867  parsetree->hasSubLinks = true;
1868 
1869  heap_close(rel, NoLock);
1870  }
1871 
1872  return parsetree;
1873 }
#define NIL
Definition: pg_list.h:69
bool query_tree_walker(Query *query, bool(*walker)(), void *context, int flags)
Definition: nodeFuncs.c:2238
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:160
List * securityQuals
Definition: parsenodes.h:970
int resultRelation
Definition: parsenodes.h:113
#define RELKIND_MATVIEW
Definition: pg_class.h:167
Definition: nodes.h:508
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:128
#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:268
#define RelationGetRelationName(relation)
Definition: rel.h:433
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:1287
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:505
#define NULL
Definition: c.h:226
#define lfirst(lc)
Definition: pg_list.h:106
static Query * fireRIRrules(Query *parsetree, List *activeRIRs, bool forUpdatePushedDown)
RuleLock * rd_rules
Definition: rel.h:117
bool expression_tree_walker(Node *node, bool(*walker)(), void *context)
Definition: nodeFuncs.c:1852
static int list_length(const List *l)
Definition: pg_list.h:89
RTEKind rtekind
Definition: parsenodes.h:882
List * cteList
Definition: parsenodes.h:126
Query * subquery
Definition: parsenodes.h:900
int errmsg(const char *fmt,...)
Definition: elog.c:797
bool hasSubLinks
Definition: parsenodes.h:119
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:413
List * list_delete_first(List *list)
Definition: list.c:666
bool hasRowSecurity
Definition: parsenodes.h:124
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 1960 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().

1967 {
1968  List *results = NIL;
1969  ListCell *l;
1970 
1971  foreach(l, locks)
1972  {
1973  RewriteRule *rule_lock = (RewriteRule *) lfirst(l);
1974  Node *event_qual = rule_lock->qual;
1975  List *actions = rule_lock->actions;
1976  QuerySource qsrc;
1977  ListCell *r;
1978 
1979  /* Determine correct QuerySource value for actions */
1980  if (rule_lock->isInstead)
1981  {
1982  if (event_qual != NULL)
1983  qsrc = QSRC_QUAL_INSTEAD_RULE;
1984  else
1985  {
1986  qsrc = QSRC_INSTEAD_RULE;
1987  *instead_flag = true; /* report unqualified INSTEAD */
1988  }
1989  }
1990  else
1991  qsrc = QSRC_NON_INSTEAD_RULE;
1992 
1993  if (qsrc == QSRC_QUAL_INSTEAD_RULE)
1994  {
1995  /*
1996  * If there are INSTEAD rules with qualifications, the original
1997  * query is still performed. But all the negated rule
1998  * qualifications of the INSTEAD rules are added so it does its
1999  * actions only in cases where the rule quals of all INSTEAD rules
2000  * are false. Think of it as the default action in a case. We save
2001  * this in *qual_product so RewriteQuery() can add it to the query
2002  * list after we mangled it up enough.
2003  *
2004  * If we have already found an unqualified INSTEAD rule, then
2005  * *qual_product won't be used, so don't bother building it.
2006  */
2007  if (!*instead_flag)
2008  {
2009  if (*qual_product == NULL)
2010  *qual_product = copyObject(parsetree);
2011  *qual_product = CopyAndAddInvertedQual(*qual_product,
2012  event_qual,
2013  rt_index,
2014  event);
2015  }
2016  }
2017 
2018  /* Now process the rule's actions and add them to the result list */
2019  foreach(r, actions)
2020  {
2021  Query *rule_action = lfirst(r);
2022 
2023  if (rule_action->commandType == CMD_NOTHING)
2024  continue;
2025 
2026  rule_action = rewriteRuleAction(parsetree, rule_action,
2027  event_qual, rt_index, event,
2028  returning_flag);
2029 
2030  rule_action->querySource = qsrc;
2031  rule_action->canSetTag = false; /* might change later */
2032 
2033  results = lappend(results, rule_action);
2034  }
2035  }
2036 
2037  return results;
2038 }
#define NIL
Definition: pg_list.h:69
Node * qual
Definition: prs2lock.h:28
QuerySource
Definition: parsenodes.h:31
Definition: nodes.h:508
bool isInstead
Definition: prs2lock.h:31
void * copyObject(const void *from)
Definition: copyfuncs.c:4475
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:103
#define NULL
Definition: c.h:226
QuerySource querySource
Definition: parsenodes.h:105
#define lfirst(lc)
Definition: pg_list.h:106
bool canSetTag
Definition: parsenodes.h:109
static Query * rewriteRuleAction(Query *parsetree, Query *rule_action, Node *rule_qual, int rt_index, CmdType event, bool *returning_flag)
Definition: pg_list.h:45
static Node * get_assignment_input ( Node node)
static

Definition at line 1007 of file rewriteHandler.c.

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

Referenced by process_matched_tle().

1008 {
1009  if (node == NULL)
1010  return NULL;
1011  if (IsA(node, FieldStore))
1012  {
1013  FieldStore *fstore = (FieldStore *) node;
1014 
1015  return (Node *) fstore->arg;
1016  }
1017  else if (IsA(node, ArrayRef))
1018  {
1019  ArrayRef *aref = (ArrayRef *) node;
1020 
1021  if (aref->refassgnexpr == NULL)
1022  return NULL;
1023  return (Node *) aref->refexpr;
1024  }
1025  return NULL;
1026 }
Expr * refassgnexpr
Definition: primnodes.h:387
#define IsA(nodeptr, _type_)
Definition: nodes.h:559
Expr * arg
Definition: primnodes.h:744
Definition: nodes.h:508
#define NULL
Definition: c.h:226
Expr * refexpr
Definition: primnodes.h:385
Query* get_view_query ( Relation  view)

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

2052 {
2053  int i;
2054 
2055  Assert(view->rd_rel->relkind == RELKIND_VIEW);
2056 
2057  for (i = 0; i < view->rd_rules->numLocks; i++)
2058  {
2059  RewriteRule *rule = view->rd_rules->rules[i];
2060 
2061  if (rule->event == CMD_SELECT)
2062  {
2063  /* A _RETURN rule should have only one action */
2064  if (list_length(rule->actions) != 1)
2065  elog(ERROR, "invalid _RETURN rule action specification");
2066 
2067  return (Query *) linitial(rule->actions);
2068  }
2069  }
2070 
2071  elog(ERROR, "failed to find _RETURN rule for view");
2072  return NULL; /* keep compiler quiet */
2073 }
int numLocks
Definition: prs2lock.h:42
Form_pg_class rd_rel
Definition: rel.h:113
Definition: localtime.c:74
#define linitial(l)
Definition: pg_list.h:110
#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:226
#define Assert(condition)
Definition: c.h:671
RuleLock * rd_rules
Definition: rel.h:117
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 1536 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().

1539 {
1540  if (jtnode == NULL)
1541  return;
1542  if (IsA(jtnode, RangeTblRef))
1543  {
1544  int rti = ((RangeTblRef *) jtnode)->rtindex;
1545  RangeTblEntry *rte = rt_fetch(rti, qry->rtable);
1546 
1547  if (rte->rtekind == RTE_RELATION)
1548  {
1549  applyLockingClause(qry, rti, strength, waitPolicy, pushedDown);
1551  }
1552  else if (rte->rtekind == RTE_SUBQUERY)
1553  {
1554  applyLockingClause(qry, rti, strength, waitPolicy, pushedDown);
1555  /* FOR UPDATE/SHARE of subquery is propagated to subquery's rels */
1557  strength, waitPolicy, true);
1558  }
1559  /* other RTE types are unaffected by FOR UPDATE */
1560  }
1561  else if (IsA(jtnode, FromExpr))
1562  {
1563  FromExpr *f = (FromExpr *) jtnode;
1564  ListCell *l;
1565 
1566  foreach(l, f->fromlist)
1567  markQueryForLocking(qry, lfirst(l), strength, waitPolicy, pushedDown);
1568  }
1569  else if (IsA(jtnode, JoinExpr))
1570  {
1571  JoinExpr *j = (JoinExpr *) jtnode;
1572 
1573  markQueryForLocking(qry, j->larg, strength, waitPolicy, pushedDown);
1574  markQueryForLocking(qry, j->rarg, strength, waitPolicy, pushedDown);
1575  }
1576  else
1577  elog(ERROR, "unrecognized node type: %d",
1578  (int) nodeTag(jtnode));
1579 }
static void markQueryForLocking(Query *qry, Node *jtnode, LockClauseStrength strength, LockWaitPolicy waitPolicy, bool pushedDown)
#define IsA(nodeptr, _type_)
Definition: nodes.h:559
FromExpr * jointree
Definition: parsenodes.h:129
Definition: nodes.h:508
AclMode requiredPerms
Definition: parsenodes.h:965
List * fromlist
Definition: primnodes.h:1433
Node * larg
Definition: primnodes.h:1413
List * rtable
Definition: parsenodes.h:128
#define ERROR
Definition: elog.h:43
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
Node * rarg
Definition: primnodes.h:1414
#define NULL
Definition: c.h:226
#define lfirst(lc)
Definition: pg_list.h:106
#define ACL_SELECT_FOR_UPDATE
Definition: parsenodes.h:81
#define nodeTag(nodeptr)
Definition: nodes.h:513
RTEKind rtekind
Definition: parsenodes.h:882
Query * subquery
Definition: parsenodes.h:900
#define elog
Definition: elog.h:219
void applyLockingClause(Query *qry, Index rtindex, LockClauseStrength strength, LockWaitPolicy waitPolicy, bool pushedDown)
Definition: analyze.c:2818
static List * matchLocks ( CmdType  event,
RuleLock rulelocks,
int  varno,
Query parsetree,
bool hasUpdate 
)
static

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

1319 {
1320  List *matching_locks = NIL;
1321  int nlocks;
1322  int i;
1323 
1324  if (rulelocks == NULL)
1325  return NIL;
1326 
1327  if (parsetree->commandType != CMD_SELECT)
1328  {
1329  if (parsetree->resultRelation != varno)
1330  return NIL;
1331  }
1332 
1333  nlocks = rulelocks->numLocks;
1334 
1335  for (i = 0; i < nlocks; i++)
1336  {
1337  RewriteRule *oneLock = rulelocks->rules[i];
1338 
1339  if (oneLock->event == CMD_UPDATE)
1340  *hasUpdate = true;
1341 
1342  /*
1343  * Suppress ON INSERT/UPDATE/DELETE rules that are disabled or
1344  * configured to not fire during the current sessions replication
1345  * role. ON SELECT rules will always be applied in order to keep views
1346  * working even in LOCAL or REPLICA role.
1347  */
1348  if (oneLock->event != CMD_SELECT)
1349  {
1351  {
1352  if (oneLock->enabled == RULE_FIRES_ON_ORIGIN ||
1353  oneLock->enabled == RULE_DISABLED)
1354  continue;
1355  }
1356  else /* ORIGIN or LOCAL ROLE */
1357  {
1358  if (oneLock->enabled == RULE_FIRES_ON_REPLICA ||
1359  oneLock->enabled == RULE_DISABLED)
1360  continue;
1361  }
1362  }
1363 
1364  if (oneLock->event == event)
1365  {
1366  if (parsetree->commandType != CMD_SELECT ||
1367  rangeTableEntry_used((Node *) parsetree, varno, 0))
1368  matching_locks = lappend(matching_locks, oneLock);
1369  }
1370  }
1371 
1372  return matching_locks;
1373 }
#define NIL
Definition: pg_list.h:69
int numLocks
Definition: prs2lock.h:42
int resultRelation
Definition: parsenodes.h:113
Definition: nodes.h:508
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:103
#define NULL
Definition: c.h:226
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 885 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, and ArrayRef::refexpr.

Referenced by rewriteTargetListIU().

888 {
889  TargetEntry *result;
890  Node *src_expr;
891  Node *prior_expr;
892  Node *src_input;
893  Node *prior_input;
894  Node *priorbottom;
895  Node *newexpr;
896 
897  if (prior_tle == NULL)
898  {
899  /*
900  * Normal case where this is the first assignment to the attribute.
901  */
902  return src_tle;
903  }
904 
905  /*----------
906  * Multiple assignments to same attribute. Allow only if all are
907  * FieldStore or ArrayRef assignment operations. This is a bit
908  * tricky because what we may actually be looking at is a nest of
909  * such nodes; consider
910  * UPDATE tab SET col.fld1.subfld1 = x, col.fld2.subfld2 = y
911  * The two expressions produced by the parser will look like
912  * FieldStore(col, fld1, FieldStore(placeholder, subfld1, x))
913  * FieldStore(col, fld2, FieldStore(placeholder, subfld2, y))
914  * However, we can ignore the substructure and just consider the top
915  * FieldStore or ArrayRef from each assignment, because it works to
916  * combine these as
917  * FieldStore(FieldStore(col, fld1,
918  * FieldStore(placeholder, subfld1, x)),
919  * fld2, FieldStore(placeholder, subfld2, y))
920  * Note the leftmost expression goes on the inside so that the
921  * assignments appear to occur left-to-right.
922  *
923  * For FieldStore, instead of nesting we can generate a single
924  * FieldStore with multiple target fields. We must nest when
925  * ArrayRefs are involved though.
926  *----------
927  */
928  src_expr = (Node *) src_tle->expr;
929  prior_expr = (Node *) prior_tle->expr;
930  src_input = get_assignment_input(src_expr);
931  prior_input = get_assignment_input(prior_expr);
932  if (src_input == NULL ||
933  prior_input == NULL ||
934  exprType(src_expr) != exprType(prior_expr))
935  ereport(ERROR,
936  (errcode(ERRCODE_SYNTAX_ERROR),
937  errmsg("multiple assignments to same column \"%s\"",
938  attrName)));
939 
940  /*
941  * Prior TLE could be a nest of assignments if we do this more than once.
942  */
943  priorbottom = prior_input;
944  for (;;)
945  {
946  Node *newbottom = get_assignment_input(priorbottom);
947 
948  if (newbottom == NULL)
949  break; /* found the original Var reference */
950  priorbottom = newbottom;
951  }
952  if (!equal(priorbottom, src_input))
953  ereport(ERROR,
954  (errcode(ERRCODE_SYNTAX_ERROR),
955  errmsg("multiple assignments to same column \"%s\"",
956  attrName)));
957 
958  /*
959  * Looks OK to nest 'em.
960  */
961  if (IsA(src_expr, FieldStore))
962  {
963  FieldStore *fstore = makeNode(FieldStore);
964 
965  if (IsA(prior_expr, FieldStore))
966  {
967  /* combine the two */
968  memcpy(fstore, prior_expr, sizeof(FieldStore));
969  fstore->newvals =
970  list_concat(list_copy(((FieldStore *) prior_expr)->newvals),
971  list_copy(((FieldStore *) src_expr)->newvals));
972  fstore->fieldnums =
973  list_concat(list_copy(((FieldStore *) prior_expr)->fieldnums),
974  list_copy(((FieldStore *) src_expr)->fieldnums));
975  }
976  else
977  {
978  /* general case, just nest 'em */
979  memcpy(fstore, src_expr, sizeof(FieldStore));
980  fstore->arg = (Expr *) prior_expr;
981  }
982  newexpr = (Node *) fstore;
983  }
984  else if (IsA(src_expr, ArrayRef))
985  {
986  ArrayRef *aref = makeNode(ArrayRef);
987 
988  memcpy(aref, src_expr, sizeof(ArrayRef));
989  aref->refexpr = (Expr *) prior_expr;
990  newexpr = (Node *) aref;
991  }
992  else
993  {
994  elog(ERROR, "cannot happen");
995  newexpr = NULL;
996  }
997 
998  result = flatCopyTargetEntry(src_tle);
999  result->expr = (Expr *) newexpr;
1000  return result;
1001 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:559
Expr * arg
Definition: primnodes.h:744
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:2870
List * list_copy(const List *oldlist)
Definition: list.c:1160
Definition: nodes.h:508
int errcode(int sqlerrcode)
Definition: elog.c:575
List * list_concat(List *list1, List *list2)
Definition: list.c:321
#define ERROR
Definition: elog.h:43
TargetEntry * flatCopyTargetEntry(TargetEntry *src_tle)
Definition: makefuncs.c:268
#define ereport(elevel, rest)
Definition: elog.h:122
List * newvals
Definition: primnodes.h:745
static Node * get_assignment_input(Node *node)
#define makeNode(_type_)
Definition: nodes.h:556
#define NULL
Definition: c.h:226
Expr * expr
Definition: primnodes.h:1330
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
int errmsg(const char *fmt,...)
Definition: elog.c:797
List * fieldnums
Definition: primnodes.h:746
#define elog
Definition: elog.h:219
Expr * refexpr
Definition: primnodes.h:385
List* QueryRewrite ( Query parsetree)

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

3491 {
3492  uint32 input_query_id = parsetree->queryId;
3493  List *querylist;
3494  List *results;
3495  ListCell *l;
3496  CmdType origCmdType;
3497  bool foundOriginalQuery;
3498  Query *lastInstead;
3499 
3500  /*
3501  * This function is only applied to top-level original queries
3502  */
3503  Assert(parsetree->querySource == QSRC_ORIGINAL);
3504  Assert(parsetree->canSetTag);
3505 
3506  /*
3507  * Step 1
3508  *
3509  * Apply all non-SELECT rules possibly getting 0 or many queries
3510  */
3511  querylist = RewriteQuery(parsetree, NIL);
3512 
3513  /*
3514  * Step 2
3515  *
3516  * Apply all the RIR rules on each query
3517  *
3518  * This is also a handy place to mark each query with the original queryId
3519  */
3520  results = NIL;
3521  foreach(l, querylist)
3522  {
3523  Query *query = (Query *) lfirst(l);
3524 
3525  query = fireRIRrules(query, NIL, false);
3526 
3527  query->queryId = input_query_id;
3528 
3529  results = lappend(results, query);
3530  }
3531 
3532  /*
3533  * Step 3
3534  *
3535  * Determine which, if any, of the resulting queries is supposed to set
3536  * the command-result tag; and update the canSetTag fields accordingly.
3537  *
3538  * If the original query is still in the list, it sets the command tag.
3539  * Otherwise, the last INSTEAD query of the same kind as the original is
3540  * allowed to set the tag. (Note these rules can leave us with no query
3541  * setting the tag. The tcop code has to cope with this by setting up a
3542  * default tag based on the original un-rewritten query.)
3543  *
3544  * The Asserts verify that at most one query in the result list is marked
3545  * canSetTag. If we aren't checking asserts, we can fall out of the loop
3546  * as soon as we find the original query.
3547  */
3548  origCmdType = parsetree->commandType;
3549  foundOriginalQuery = false;
3550  lastInstead = NULL;
3551 
3552  foreach(l, results)
3553  {
3554  Query *query = (Query *) lfirst(l);
3555 
3556  if (query->querySource == QSRC_ORIGINAL)
3557  {
3558  Assert(query->canSetTag);
3559  Assert(!foundOriginalQuery);
3560  foundOriginalQuery = true;
3561 #ifndef USE_ASSERT_CHECKING
3562  break;
3563 #endif
3564  }
3565  else
3566  {
3567  Assert(!query->canSetTag);
3568  if (query->commandType == origCmdType &&
3569  (query->querySource == QSRC_INSTEAD_RULE ||
3571  lastInstead = query;
3572  }
3573  }
3574 
3575  if (!foundOriginalQuery && lastInstead != NULL)
3576  lastInstead->canSetTag = true;
3577 
3578  return results;
3579 }
#define NIL
Definition: pg_list.h:69
uint32 queryId
Definition: parsenodes.h:107
static List * RewriteQuery(Query *parsetree, List *rewrite_events)
unsigned int uint32
Definition: c.h:265
List * lappend(List *list, void *datum)
Definition: list.c:128
CmdType commandType
Definition: parsenodes.h:103
#define NULL
Definition: c.h:226
QuerySource querySource
Definition: parsenodes.h:105
#define Assert(condition)
Definition: c.h:671
#define lfirst(lc)
Definition: pg_list.h:106
static Query * fireRIRrules(Query *parsetree, List *activeRIRs, bool forUpdatePushedDown)
bool canSetTag
Definition: parsenodes.h:109
Definition: pg_list.h:45
CmdType
Definition: nodes.h:641
int relation_is_updatable ( Oid  reloid,
bool  include_triggers,
Bitmapset include_cols 
)

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

2390 {
2391  int events = 0;
2392  Relation rel;
2393  RuleLock *rulelocks;
2394 
2395 #define ALL_EVENTS ((1 << CMD_INSERT) | (1 << CMD_UPDATE) | (1 << CMD_DELETE))
2396 
2397  rel = try_relation_open(reloid, AccessShareLock);
2398 
2399  /*
2400  * If the relation doesn't exist, return zero rather than throwing an
2401  * error. This is helpful since scanning an information_schema view under
2402  * MVCC rules can result in referencing rels that have actually been
2403  * deleted already.
2404  */
2405  if (rel == NULL)
2406  return 0;
2407 
2408  /* If the relation is a table, it is always updatable */
2409  if (rel->rd_rel->relkind == RELKIND_RELATION)
2410  {
2412  return ALL_EVENTS;
2413  }
2414 
2415  /* Look for unconditional DO INSTEAD rules, and note supported events */
2416  rulelocks = rel->rd_rules;
2417  if (rulelocks != NULL)
2418  {
2419  int i;
2420 
2421  for (i = 0; i < rulelocks->numLocks; i++)
2422  {
2423  if (rulelocks->rules[i]->isInstead &&
2424  rulelocks->rules[i]->qual == NULL)
2425  {
2426  events |= ((1 << rulelocks->rules[i]->event) & ALL_EVENTS);
2427  }
2428  }
2429 
2430  /* If we have rules for all events, we're done */
2431  if (events == ALL_EVENTS)
2432  {
2434  return events;
2435  }
2436  }
2437 
2438  /* Similarly look for INSTEAD OF triggers, if they are to be included */
2439  if (include_triggers)
2440  {
2441  TriggerDesc *trigDesc = rel->trigdesc;
2442 
2443  if (trigDesc)
2444  {
2445  if (trigDesc->trig_insert_instead_row)
2446  events |= (1 << CMD_INSERT);
2447  if (trigDesc->trig_update_instead_row)
2448  events |= (1 << CMD_UPDATE);
2449  if (trigDesc->trig_delete_instead_row)
2450  events |= (1 << CMD_DELETE);
2451 
2452  /* If we have triggers for all events, we're done */
2453  if (events == ALL_EVENTS)
2454  {
2456  return events;
2457  }
2458  }
2459  }
2460 
2461  /* If this is a foreign table, check which update events it supports */
2462  if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
2463  {
2464  FdwRoutine *fdwroutine = GetFdwRoutineForRelation(rel, false);
2465 
2466  if (fdwroutine->IsForeignRelUpdatable != NULL)
2467  events |= fdwroutine->IsForeignRelUpdatable(rel);
2468  else
2469  {
2470  /* Assume presence of executor functions is sufficient */
2471  if (fdwroutine->ExecForeignInsert != NULL)
2472  events |= (1 << CMD_INSERT);
2473  if (fdwroutine->ExecForeignUpdate != NULL)
2474  events |= (1 << CMD_UPDATE);
2475  if (fdwroutine->ExecForeignDelete != NULL)
2476  events |= (1 << CMD_DELETE);
2477  }
2478 
2480  return events;
2481  }
2482 
2483  /* Check if this is an automatically updatable view */
2484  if (rel->rd_rel->relkind == RELKIND_VIEW)
2485  {
2486  Query *viewquery = get_view_query(rel);
2487 
2488  if (view_query_is_auto_updatable(viewquery, false) == NULL)
2489  {
2490  Bitmapset *updatable_cols;
2491  int auto_events;
2492  RangeTblRef *rtr;
2493  RangeTblEntry *base_rte;
2494  Oid baseoid;
2495 
2496  /*
2497  * Determine which of the view's columns are updatable. If there
2498  * are none within the set of columns we are looking at, then the
2499  * view doesn't support INSERT/UPDATE, but it may still support
2500  * DELETE.
2501  */
2503  &updatable_cols, NULL);
2504 
2505  if (include_cols != NULL)
2506  updatable_cols = bms_int_members(updatable_cols, include_cols);
2507 
2508  if (bms_is_empty(updatable_cols))
2509  auto_events = (1 << CMD_DELETE); /* May support DELETE */
2510  else
2511  auto_events = ALL_EVENTS; /* May support all events */
2512 
2513  /*
2514  * The base relation must also support these update commands.
2515  * Tables are always updatable, but for any other kind of base
2516  * relation we must do a recursive check limited to the columns
2517  * referenced by the locally updatable columns in this view.
2518  */
2519  rtr = (RangeTblRef *) linitial(viewquery->jointree->fromlist);
2520  base_rte = rt_fetch(rtr->rtindex, viewquery->rtable);
2521  Assert(base_rte->rtekind == RTE_RELATION);
2522 
2523  if (base_rte->relkind != RELKIND_RELATION)
2524  {
2525  baseoid = base_rte->relid;
2526  include_cols = adjust_view_column_set(updatable_cols,
2527  viewquery->targetList);
2528  auto_events &= relation_is_updatable(baseoid,
2529  include_triggers,
2530  include_cols);
2531  }
2532  events |= auto_events;
2533  }
2534  }
2535 
2536  /* If we reach here, the relation may support some update commands */
2538  return events;
2539 }
ExecForeignDelete_function ExecForeignDelete
Definition: fdwapi.h:198
Node * qual
Definition: prs2lock.h:28
int numLocks
Definition: prs2lock.h:42
FromExpr * jointree
Definition: parsenodes.h:129
Relation try_relation_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1150
ExecForeignInsert_function ExecForeignInsert
Definition: fdwapi.h:196
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:1263
List * fromlist
Definition: primnodes.h:1433
Form_pg_class rd_rel
Definition: rel.h:113
unsigned int Oid
Definition: postgres_ext.h:31
bool isInstead
Definition: prs2lock.h:31
List * targetList
Definition: parsenodes.h:131
bool trig_insert_instead_row
Definition: reltrigger.h:57
#define linitial(l)
Definition: pg_list.h:110
List * rtable
Definition: parsenodes.h:128
#define ALL_EVENTS
TriggerDesc * trigdesc
Definition: rel.h:119
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:166
#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:633
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:197
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:671
RuleLock * rd_rules
Definition: rel.h:117
RTEKind rtekind
Definition: parsenodes.h:882
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:200
Bitmapset * bms_int_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:761
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 3101 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, linitial, list_concat(), list_delete_first(), list_length(), matchLocks(), NIL, NoLock, NULL, Query::onConflict, ONCONFLICT_UPDATE, OnConflictExpr::onConflictSet, 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().

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

Referenced by fireRules().

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

Definition at line 706 of file rewriteHandler.c.

References tupleDesc::attrs, build_column_default(), CMD_INSERT, CMD_UPDATE, COERCE_IMPLICIT_CAST, coerce_to_domain(), elog, ERROR, TargetEntry::expr, flatCopyTargetEntry(), InvalidOid, IsA, lappend(), lappend_int(), lfirst, list_concat(), makeConst(), makeTargetEntry(), makeVar(), NameStr, NIL, NULL, palloc0(), pfree(), process_matched_tle(), pstrdup(), RelationData::rd_att, RelationData::rd_rel, RelationGetNumberOfAttributes, RELKIND_VIEW, TargetEntry::resjunk, TargetEntry::resno, and view_has_instead_trigger().

Referenced by RewriteQuery().

711 {
712  TargetEntry **new_tles;
713  List *new_tlist = NIL;
714  List *junk_tlist = NIL;
715  Form_pg_attribute att_tup;
716  int attrno,
717  next_junk_attrno,
718  numattrs;
719  ListCell *temp;
720 
721  if (attrno_list) /* initialize optional result list */
722  *attrno_list = NIL;
723 
724  /*
725  * We process the normal (non-junk) attributes by scanning the input tlist
726  * once and transferring TLEs into an array, then scanning the array to
727  * build an output tlist. This avoids O(N^2) behavior for large numbers
728  * of attributes.
729  *
730  * Junk attributes are tossed into a separate list during the same tlist
731  * scan, then appended to the reconstructed tlist.
732  */
733  numattrs = RelationGetNumberOfAttributes(target_relation);
734  new_tles = (TargetEntry **) palloc0(numattrs * sizeof(TargetEntry *));
735  next_junk_attrno = numattrs + 1;
736 
737  foreach(temp, targetList)
738  {
739  TargetEntry *old_tle = (TargetEntry *) lfirst(temp);
740 
741  if (!old_tle->resjunk)
742  {
743  /* Normal attr: stash it into new_tles[] */
744  attrno = old_tle->resno;
745  if (attrno < 1 || attrno > numattrs)
746  elog(ERROR, "bogus resno %d in targetlist", attrno);
747  att_tup = target_relation->rd_att->attrs[attrno - 1];
748 
749  /* put attrno into attrno_list even if it's dropped */
750  if (attrno_list)
751  *attrno_list = lappend_int(*attrno_list, attrno);
752 
753  /* We can (and must) ignore deleted attributes */
754  if (att_tup->attisdropped)
755  continue;
756 
757  /* Merge with any prior assignment to same attribute */
758  new_tles[attrno - 1] =
759  process_matched_tle(old_tle,
760  new_tles[attrno - 1],
761  NameStr(att_tup->attname));
762  }
763  else
764  {
765  /*
766  * Copy all resjunk tlist entries to junk_tlist, and assign them
767  * resnos above the last real resno.
768  *
769  * Typical junk entries include ORDER BY or GROUP BY expressions
770  * (are these actually possible in an INSERT or UPDATE?), system
771  * attribute references, etc.
772  */
773 
774  /* Get the resno right, but don't copy unnecessarily */
775  if (old_tle->resno != next_junk_attrno)
776  {
777  old_tle = flatCopyTargetEntry(old_tle);
778  old_tle->resno = next_junk_attrno;
779  }
780  junk_tlist = lappend(junk_tlist, old_tle);
781  next_junk_attrno++;
782  }
783  }
784 
785  for (attrno = 1; attrno <= numattrs; attrno++)
786  {
787  TargetEntry *new_tle = new_tles[attrno - 1];
788 
789  att_tup = target_relation->rd_att->attrs[attrno - 1];
790 
791  /* We can (and must) ignore deleted attributes */
792  if (att_tup->attisdropped)
793  continue;
794 
795  /*
796  * Handle the two cases where we need to insert a default expression:
797  * it's an INSERT and there's no tlist entry for the column, or the
798  * tlist entry is a DEFAULT placeholder node.
799  */
800  if ((new_tle == NULL && commandType == CMD_INSERT) ||
801  (new_tle && new_tle->expr && IsA(new_tle->expr, SetToDefault)))
802  {
803  Node *new_expr;
804 
805  new_expr = build_column_default(target_relation, attrno);
806 
807  /*
808  * If there is no default (ie, default is effectively NULL), we
809  * can omit the tlist entry in the INSERT case, since the planner
810  * can insert a NULL for itself, and there's no point in spending
811  * any more rewriter cycles on the entry. But in the UPDATE case
812  * we've got to explicitly set the column to NULL.
813  */
814  if (!new_expr)
815  {
816  if (commandType == CMD_INSERT)
817  new_tle = NULL;
818  else
819  {
820  new_expr = (Node *) makeConst(att_tup->atttypid,
821  -1,
822  att_tup->attcollation,
823  att_tup->attlen,
824  (Datum) 0,
825  true, /* isnull */
826  att_tup->attbyval);
827  /* this is to catch a NOT NULL domain constraint */
828  new_expr = coerce_to_domain(new_expr,
829  InvalidOid, -1,
830  att_tup->atttypid,
832  -1,
833  false,
834  false);
835  }
836  }
837 
838  if (new_expr)
839  new_tle = makeTargetEntry((Expr *) new_expr,
840  attrno,
841  pstrdup(NameStr(att_tup->attname)),
842  false);
843  }
844 
845  /*
846  * For an UPDATE on a trigger-updatable view, provide a dummy entry
847  * whenever there is no explicit assignment.
848  */
849  if (new_tle == NULL && commandType == CMD_UPDATE &&
850  target_relation->rd_rel->relkind == RELKIND_VIEW &&
851  view_has_instead_trigger(target_relation, CMD_UPDATE))
852  {
853  Node *new_expr;
854 
855  new_expr = (Node *) makeVar(result_rti,
856  attrno,
857  att_tup->atttypid,
858  att_tup->atttypmod,
859  att_tup->attcollation,
860  0);
861 
862  new_tle = makeTargetEntry((Expr *) new_expr,
863  attrno,
864  pstrdup(NameStr(att_tup->attname)),
865  false);
866  }
867 
868  if (new_tle)
869  new_tlist = lappend(new_tlist, new_tle);
870  }
871 
872  pfree(new_tles);
873 
874  return list_concat(new_tlist, junk_tlist);
875 }
#define NIL
Definition: pg_list.h:69
#define IsA(nodeptr, _type_)
Definition: nodes.h:559
static bool view_has_instead_trigger(Relation view, CmdType event)
#define RelationGetNumberOfAttributes(relation)
Definition: rel.h:419
char * pstrdup(const char *in)
Definition: mcxt.c:1165
Form_pg_attribute * attrs
Definition: tupdesc.h:74
Definition: nodes.h:508
List * list_concat(List *list1, List *list2)
Definition: list.c:321
Form_pg_class rd_rel
Definition: rel.h:113
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:992
bool resjunk
Definition: primnodes.h:1337
#define ERROR
Definition: elog.h:43
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
AttrNumber resno
Definition: primnodes.h:1331
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:184
TargetEntry * flatCopyTargetEntry(TargetEntry *src_tle)
Definition: makefuncs.c:268
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:920
uintptr_t Datum
Definition: postgres.h:374
TupleDesc rd_att
Definition: rel.h:114
#define InvalidOid
Definition: postgres_ext.h:36
#define NULL
Definition: c.h:226
#define lfirst(lc)
Definition: pg_list.h:106
Expr * expr
Definition: primnodes.h:1330
#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:495
#define elog
Definition: elog.h:219
Definition: pg_list.h:45
static void rewriteTargetListUD ( Query parsetree,
RangeTblEntry target_rte,
Relation  target_relation 
)
static

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

1228 {
1229  Var *var = NULL;
1230  const char *attrname;
1231  TargetEntry *tle;
1232 
1233  if (target_relation->rd_rel->relkind == RELKIND_RELATION ||
1234  target_relation->rd_rel->relkind == RELKIND_MATVIEW ||
1235  target_relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1236  {
1237  /*
1238  * Emit CTID so that executor can find the row to update or delete.
1239  */
1240  var = makeVar(parsetree->resultRelation,
1242  TIDOID,
1243  -1,
1244  InvalidOid,
1245  0);
1246 
1247  attrname = "ctid";
1248  }
1249  else if (target_relation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
1250  {
1251  /*
1252  * Let the foreign table's FDW add whatever junk TLEs it wants.
1253  */
1254  FdwRoutine *fdwroutine;
1255 
1256  fdwroutine = GetFdwRoutineForRelation(target_relation, false);
1257 
1258  if (fdwroutine->AddForeignUpdateTargets != NULL)
1259  fdwroutine->AddForeignUpdateTargets(parsetree, target_rte,
1260  target_relation);
1261 
1262  /*
1263  * If we have a row-level trigger corresponding to the operation, emit
1264  * a whole-row Var so that executor will have the "old" row to pass to
1265  * the trigger. Alas, this misses system columns.
1266  */
1267  if (target_relation->trigdesc &&
1268  ((parsetree->commandType == CMD_UPDATE &&
1269  (target_relation->trigdesc->trig_update_after_row ||
1270  target_relation->trigdesc->trig_update_before_row)) ||
1271  (parsetree->commandType == CMD_DELETE &&
1272  (target_relation->trigdesc->trig_delete_after_row ||
1273  target_relation->trigdesc->trig_delete_before_row))))
1274  {
1275  var = makeWholeRowVar(target_rte,
1276  parsetree->resultRelation,
1277  0,
1278  false);
1279 
1280  attrname = "wholerow";
1281  }
1282  }
1283  else
1284  {
1285  /*
1286  * Emit whole-row Var so that executor will have the "old" view row to
1287  * pass to the INSTEAD OF trigger.
1288  */
1289  var = makeWholeRowVar(target_rte,
1290  parsetree->resultRelation,
1291  0,
1292  false);
1293 
1294  attrname = "wholerow";
1295  }
1296 
1297  if (var != NULL)
1298  {
1299  tle = makeTargetEntry((Expr *) var,
1300  list_length(parsetree->targetList) + 1,
1301  pstrdup(attrname),
1302  true);
1303 
1304  parsetree->targetList = lappend(parsetree->targetList, tle);
1305  }
1306 }
char * pstrdup(const char *in)
Definition: mcxt.c:1165
int resultRelation
Definition: parsenodes.h:113
#define RELKIND_MATVIEW
Definition: pg_class.h:167
Var * makeWholeRowVar(RangeTblEntry *rte, Index varno, Index varlevelsup, bool allowScalar)
Definition: makefuncs.c:132
Form_pg_class rd_rel
Definition: rel.h:113
Definition: primnodes.h:141
AddForeignUpdateTargets_function AddForeignUpdateTargets
Definition: fdwapi.h:193
List * targetList
Definition: parsenodes.h:131
#define TIDOID
Definition: pg_type.h:332
TriggerDesc * trigdesc
Definition: rel.h:119
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:166
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:103
#define NULL
Definition: c.h:226
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 2621 of file rewriteHandler.c.

References _, acquireLocksOnSubLinks(), AddQual(), adjust_view_column_set(), Assert, bms_add_member(), bms_is_empty(), WithCheckOption::cascaded, castNode, 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, 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().

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

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

1139 {
1140  List *newValues;
1141  ListCell *lc;
1142 
1143  /*
1144  * Rebuilding all the lists is a pretty expensive proposition in a big
1145  * VALUES list, and it's a waste of time if there aren't any DEFAULT
1146  * placeholders. So first scan to see if there are any.
1147  */
1148  if (!searchForDefault(rte))
1149  return; /* nothing to do */
1150 
1151  /* Check list lengths (we can assume all the VALUES sublists are alike) */
1152  Assert(list_length(attrnos) == list_length(linitial(rte->values_lists)));
1153 
1154  newValues = NIL;
1155  foreach(lc, rte->values_lists)
1156  {
1157  List *sublist = (List *) lfirst(lc);
1158  List *newList = NIL;
1159  ListCell *lc2;
1160  ListCell *lc3;
1161 
1162  forboth(lc2, sublist, lc3, attrnos)
1163  {
1164  Node *col = (Node *) lfirst(lc2);
1165  int attrno = lfirst_int(lc3);
1166 
1167  if (IsA(col, SetToDefault))
1168  {
1169  Form_pg_attribute att_tup;
1170  Node *new_expr;
1171 
1172  att_tup = target_relation->rd_att->attrs[attrno - 1];
1173 
1174  if (!att_tup->attisdropped)
1175  new_expr = build_column_default(target_relation, attrno);
1176  else
1177  new_expr = NULL; /* force a NULL if dropped */
1178 
1179  /*
1180  * If there is no default (ie, default is effectively NULL),
1181  * we've got to explicitly set the column to NULL.
1182  */
1183  if (!new_expr)
1184  {
1185  new_expr = (Node *) makeConst(att_tup->atttypid,
1186  -1,
1187  att_tup->attcollation,
1188  att_tup->attlen,
1189  (Datum) 0,
1190  true, /* isnull */
1191  att_tup->attbyval);
1192  /* this is to catch a NOT NULL domain constraint */
1193  new_expr = coerce_to_domain(new_expr,
1194  InvalidOid, -1,
1195  att_tup->atttypid,
1197  -1,
1198  false,
1199  false);
1200  }
1201  newList = lappend(newList, new_expr);
1202  }
1203  else
1204  newList = lappend(newList, col);
1205  }
1206  newValues = lappend(newValues, newList);
1207  }
1208  rte->values_lists = newValues;
1209 }
#define NIL
Definition: pg_list.h:69
#define IsA(nodeptr, _type_)
Definition: nodes.h:559
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:174
Form_pg_attribute * attrs
Definition: tupdesc.h:74
Definition: nodes.h:508
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:937
#define linitial(l)
Definition: pg_list.h:110
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:184
List * lappend(List *list, void *datum)
Definition: list.c:128
Node * build_column_default(Relation rel, int attrno)
uintptr_t Datum
Definition: postgres.h:374
TupleDesc rd_att
Definition: rel.h:114
#define InvalidOid
Definition: postgres_ext.h:36
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:671
#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 1106 of file rewriteHandler.c.

References IsA, lfirst, and RangeTblEntry::values_lists.

Referenced by rewriteValuesRTE().

1107 {
1108  ListCell *lc;
1109 
1110  foreach(lc, rte->values_lists)
1111  {
1112  List *sublist = (List *) lfirst(lc);
1113  ListCell *lc2;
1114 
1115  foreach(lc2, sublist)
1116  {
1117  Node *col = (Node *) lfirst(lc2);
1118 
1119  if (IsA(col, SetToDefault))
1120  return true;
1121  }
1122  }
1123  return false;
1124 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:559
Definition: nodes.h:508
List * values_lists
Definition: parsenodes.h:937
#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 2119 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().

2120 {
2121  Var *var = (Var *) tle->expr;
2122 
2123  /*
2124  * For now, the only updatable columns we support are those that are Vars
2125  * referring to user columns of the underlying base relation.
2126  *
2127  * The view targetlist may contain resjunk columns (e.g., a view defined
2128  * like "SELECT * FROM t ORDER BY a+b" is auto-updatable) but such columns
2129  * are not auto-updatable, and in fact should never appear in the outer
2130  * query's targetlist.
2131  */
2132  if (tle->resjunk)
2133  return gettext_noop("Junk view columns are not updatable.");
2134 
2135  if (!IsA(var, Var) ||
2136  var->varno != rtr->rtindex ||
2137  var->varlevelsup != 0)
2138  return gettext_noop("View columns that are not columns of their base relation are not updatable.");
2139 
2140  if (var->varattno < 0)
2141  return gettext_noop("View columns that refer to system columns are not updatable.");
2142 
2143  if (var->varattno == 0)
2144  return gettext_noop("View columns that return whole-row references are not updatable.");
2145 
2146  return NULL; /* the view column is updatable */
2147 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:559
Index varlevelsup
Definition: primnodes.h:151
#define gettext_noop(x)
Definition: c.h:139
AttrNumber varattno
Definition: primnodes.h:146
Definition: primnodes.h:141
bool resjunk
Definition: primnodes.h:1337
Index varno
Definition: primnodes.h:144
#define NULL
Definition: c.h:226
Expr * expr
Definition: primnodes.h:1330
static const char* view_cols_are_auto_updatable ( Query viewquery,
Bitmapset required_cols,
Bitmapset **  updatable_cols,
char **  non_updatable_col 
)
static

Definition at line 2309 of file rewriteHandler.c.

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

Referenced by relation_is_updatable(), and rewriteTargetView().

2313 {
2314  RangeTblRef *rtr;
2315  AttrNumber col;
2316  ListCell *cell;
2317 
2318  /*
2319  * The caller should have verified that this view is auto-updatable and so
2320  * there should be a single base relation.
2321  */
2322  Assert(list_length(viewquery->jointree->fromlist) == 1);
2323  rtr = castNode(RangeTblRef, linitial(viewquery->jointree->fromlist));
2324 
2325  /* Initialize the optional return values */
2326  if (updatable_cols != NULL)
2327  *updatable_cols = NULL;
2328  if (non_updatable_col != NULL)
2329  *non_updatable_col = NULL;
2330 
2331  /* Test each view column for updatability */
2333  foreach(cell, viewquery->targetList)
2334  {
2335  TargetEntry *tle = (TargetEntry *) lfirst(cell);
2336  const char *col_update_detail;
2337 
2338  col++;
2339  col_update_detail = view_col_is_auto_updatable(rtr, tle);
2340 
2341  if (col_update_detail == NULL)
2342  {
2343  /* The column is updatable */
2344  if (updatable_cols != NULL)
2345  *updatable_cols = bms_add_member(*updatable_cols, col);
2346  }
2347  else if (bms_is_member(col, required_cols))
2348  {
2349  /* The required column is not updatable */
2350  if (non_updatable_col != NULL)
2351  *non_updatable_col = tle->resname;
2352  return col_update_detail;
2353  }
2354  }
2355 
2356  return NULL; /* all the required view columns are updatable */
2357 }
FromExpr * jointree
Definition: parsenodes.h:129
#define castNode(_type_, nodeptr)
Definition: nodes.h:577
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:28
List * fromlist
Definition: primnodes.h:1433
char * resname
Definition: primnodes.h:1332
List * targetList
Definition: parsenodes.h:131
#define linitial(l)
Definition: pg_list.h:110
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:671
#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:668
static const char * view_col_is_auto_updatable(RangeTblRef *rtr, TargetEntry *tle)
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:419
int16 AttrNumber
Definition: attnum.h:21
static bool view_has_instead_trigger ( Relation  view,
CmdType  event 
)
static

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

2085 {
2086  TriggerDesc *trigDesc = view->trigdesc;
2087 
2088  switch (event)
2089  {
2090  case CMD_INSERT:
2091  if (trigDesc && trigDesc->trig_insert_instead_row)
2092  return true;
2093  break;
2094  case CMD_UPDATE:
2095  if (trigDesc && trigDesc->trig_update_instead_row)
2096  return true;
2097  break;
2098  case CMD_DELETE:
2099  if (trigDesc && trigDesc->trig_delete_instead_row)
2100  return true;
2101  break;
2102  default:
2103  elog(ERROR, "unrecognized CmdType: %d", (int) event);
2104  break;
2105  }
2106  return false;
2107 }
bool trig_insert_instead_row
Definition: reltrigger.h:57
#define ERROR
Definition: elog.h:43
TriggerDesc * trigdesc
Definition: rel.h:119
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 2164 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().

2165 {
2166  RangeTblRef *rtr;
2167  RangeTblEntry *base_rte;
2168 
2169  /*----------
2170  * Check if the view is simply updatable. According to SQL-92 this means:
2171  * - No DISTINCT clause.
2172  * - Each TLE is a column reference, and each column appears at most once.
2173  * - FROM contains exactly one base relation.
2174  * - No GROUP BY or HAVING clauses.
2175  * - No set operations (UNION, INTERSECT or EXCEPT).
2176  * - No sub-queries in the WHERE clause that reference the target table.
2177  *
2178  * We ignore that last restriction since it would be complex to enforce
2179  * and there isn't any actual benefit to disallowing sub-queries. (The
2180  * semantic issues that the standard is presumably concerned about don't
2181  * arise in Postgres, since any such sub-query will not see any updates
2182  * executed by the outer query anyway, thanks to MVCC snapshotting.)
2183  *
2184  * We also relax the second restriction by supporting part of SQL:1999
2185  * feature T111, which allows for a mix of updatable and non-updatable
2186  * columns, provided that an INSERT or UPDATE doesn't attempt to assign to
2187  * a non-updatable column.
2188  *
2189  * In addition we impose these constraints, involving features that are
2190  * not part of SQL-92:
2191  * - No CTEs (WITH clauses).
2192  * - No OFFSET or LIMIT clauses (this matches a SQL:2008 restriction).
2193  * - No system columns (including whole-row references) in the tlist.
2194  * - No window functions in the tlist.
2195  * - No set-returning functions in the tlist.
2196  *
2197  * Note that we do these checks without recursively expanding the view.
2198  * If the base relation is a view, we'll recursively deal with it later.
2199  *----------
2200  */
2201  if (viewquery->distinctClause != NIL)
2202  return gettext_noop("Views containing DISTINCT are not automatically updatable.");
2203 
2204  if (viewquery->groupClause != NIL || viewquery->groupingSets)
2205  return gettext_noop("Views containing GROUP BY are not automatically updatable.");
2206 
2207  if (viewquery->havingQual != NULL)
2208  return gettext_noop("Views containing HAVING are not automatically updatable.");
2209 
2210  if (viewquery->setOperations != NULL)
2211  return gettext_noop("Views containing UNION, INTERSECT, or EXCEPT are not automatically updatable.");
2212 
2213  if (viewquery->cteList != NIL)
2214  return gettext_noop("Views containing WITH are not automatically updatable.");
2215 
2216  if (viewquery->limitOffset != NULL || viewquery->limitCount != NULL)
2217  return gettext_noop("Views containing LIMIT or OFFSET are not automatically updatable.");
2218 
2219  /*
2220  * We must not allow window functions or set returning functions in the
2221  * targetlist. Otherwise we might end up inserting them into the quals of
2222  * the main query. We must also check for aggregates in the targetlist in
2223  * case they appear without a GROUP BY.
2224  *
2225  * These restrictions ensure that each row of the view corresponds to a
2226  * unique row in the underlying base relation.
2227  */
2228  if (viewquery->hasAggs)
2229  return gettext_noop("Views that return aggregate functions are not automatically updatable.");
2230 
2231  if (viewquery->hasWindowFuncs)
2232  return gettext_noop("Views that return window functions are not automatically updatable.");
2233 
2234  if (viewquery->hasTargetSRFs)
2235  return gettext_noop("Views that return set-returning functions are not automatically updatable.");
2236 
2237  /*
2238  * The view query should select from a single base relation, which must be
2239  * a table or another view.
2240  */
2241  if (list_length(viewquery->jointree->fromlist) != 1)
2242  return gettext_noop("Views that do not select from a single table or view are not automatically updatable.");
2243 
2244  rtr = (RangeTblRef *) linitial(viewquery->jointree->fromlist);
2245  if (!IsA(rtr, RangeTblRef))
2246  return gettext_noop("Views that do not select from a single table or view are not automatically updatable.");
2247 
2248  base_rte = rt_fetch(rtr->rtindex, viewquery->rtable);
2249  if (base_rte->rtekind != RTE_RELATION ||
2250  (base_rte->relkind != RELKIND_RELATION &&
2251  base_rte->relkind != RELKIND_FOREIGN_TABLE &&
2252  base_rte->relkind != RELKIND_VIEW &&
2253  base_rte->relkind != RELKIND_PARTITIONED_TABLE))
2254  return gettext_noop("Views that do not select from a single table or view are not automatically updatable.");
2255 
2256  if (base_rte->tablesample)
2257  return gettext_noop("Views containing TABLESAMPLE are not automatically updatable.");
2258 
2259  /*
2260  * Check that the view has at least one updatable column. This is required
2261  * for INSERT/UPDATE but not for DELETE.
2262  */
2263  if (check_cols)
2264  {
2265  ListCell *cell;
2266  bool found;
2267 
2268  found = false;
2269  foreach(cell, viewquery->targetList)
2270  {
2271  TargetEntry *tle = (TargetEntry *) lfirst(cell);
2272 
2273  if (view_col_is_auto_updatable(rtr, tle) == NULL)
2274  {
2275  found = true;
2276  break;
2277  }
2278  }
2279 
2280  if (!found)
2281  return gettext_noop("Views that have no updatable columns are not automatically updatable.");
2282  }
2283 
2284  return NULL; /* the view is updatable */
2285 }
Node * limitOffset
Definition: parsenodes.h:149
#define NIL
Definition: pg_list.h:69
#define IsA(nodeptr, _type_)
Definition: nodes.h:559
FromExpr * jointree
Definition: parsenodes.h:129
bool hasAggs
Definition: parsenodes.h:116
List * groupingSets
Definition: parsenodes.h:139
#define gettext_noop(x)
Definition: c.h:139
List * fromlist
Definition: primnodes.h:1433
List * targetList
Definition: parsenodes.h:131
#define linitial(l)
Definition: pg_list.h:110
List * rtable
Definition: parsenodes.h:128
List * distinctClause
Definition: parsenodes.h:145
Node * limitCount
Definition: parsenodes.h:150
#define RELKIND_FOREIGN_TABLE
Definition: pg_class.h:166
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
#define RELKIND_PARTITIONED_TABLE
Definition: pg_class.h:168
bool hasTargetSRFs
Definition: parsenodes.h:118
#define NULL
Definition: c.h:226
#define lfirst(lc)
Definition: pg_list.h:106
bool hasWindowFuncs
Definition: parsenodes.h:117
static int list_length(const List *l)
Definition: pg_list.h:89
RTEKind rtekind
Definition: parsenodes.h:882
List * cteList
Definition: parsenodes.h:126
Node * setOperations
Definition: parsenodes.h:154
List * groupClause
Definition: parsenodes.h:137
#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:141
#define RELKIND_RELATION
Definition: pg_class.h:160
struct TableSampleClause * tablesample
Definition: parsenodes.h:895