PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
rewriteHandler.c File Reference
#include "postgres.h"
#include "access/sysattr.h"
#include "catalog/dependency.h"
#include "catalog/pg_type.h"
#include "commands/trigger.h"
#include "foreign/fdwapi.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "parser/analyze.h"
#include "parser/parse_coerce.h"
#include "parser/parsetree.h"
#include "rewrite/rewriteDefine.h"
#include "rewrite/rewriteHandler.h"
#include "rewrite/rewriteManip.h"
#include "rewrite/rowsecurity.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
Include dependency graph for rewriteHandler.c:

Go to the source code of this file.

Data Structures

struct  rewrite_event
 
struct  acquireLocksOnSubLinks_context
 

Macros

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

Typedefs

typedef struct rewrite_event rewrite_event
 
typedef struct
acquireLocksOnSubLinks_context 
acquireLocksOnSubLinks_context
 

Functions

static bool acquireLocksOnSubLinks (Node *node, acquireLocksOnSubLinks_context *context)
 
static QueryrewriteRuleAction (Query *parsetree, Query *rule_action, Node *rule_qual, int rt_index, CmdType event, bool *returning_flag)
 
static ListadjustJoinTreeList (Query *parsetree, bool removert, int rt_index)
 
static ListrewriteTargetListIU (List *targetList, CmdType commandType, OverridingKind override, Relation target_relation, int result_rti, List **attrno_list)
 
static TargetEntryprocess_matched_tle (TargetEntry *src_tle, TargetEntry *prior_tle, const char *attrName)
 
static Nodeget_assignment_input (Node *node)
 
static void rewriteValuesRTE (RangeTblEntry *rte, Relation target_relation, List *attrnos)
 
static void rewriteTargetListUD (Query *parsetree, RangeTblEntry *target_rte, Relation target_relation)
 
static void markQueryForLocking (Query *qry, Node *jtnode, LockClauseStrength strength, LockWaitPolicy waitPolicy, bool pushedDown)
 
static ListmatchLocks (CmdType event, RuleLock *rulelocks, int varno, Query *parsetree, bool *hasUpdate)
 
static QueryfireRIRrules (Query *parsetree, List *activeRIRs, bool forUpdatePushedDown)
 
static bool view_has_instead_trigger (Relation view, CmdType event)
 
static Bitmapsetadjust_view_column_set (Bitmapset *cols, List *targetlist)
 
void AcquireRewriteLocks (Query *parsetree, bool forExecute, bool forUpdatePushedDown)
 
Nodebuild_column_default (Relation rel, int attrno)
 
static bool searchForDefault (RangeTblEntry *rte)
 
static QueryApplyRetrieveRule (Query *parsetree, RewriteRule *rule, int rt_index, Relation relation, List *activeRIRs, bool forUpdatePushedDown)
 
static bool fireRIRonSubLink (Node *node, List *activeRIRs)
 
static QueryCopyAndAddInvertedQual (Query *parsetree, Node *rule_qual, int rt_index, CmdType event)
 
static ListfireRules (Query *parsetree, int rt_index, CmdType event, List *locks, bool *instead_flag, bool *returning_flag, Query **qual_product)
 
Queryget_view_query (Relation view)
 
static const char * view_col_is_auto_updatable (RangeTblRef *rtr, TargetEntry *tle)
 
const char * view_query_is_auto_updatable (Query *viewquery, bool check_cols)
 
static const char * view_cols_are_auto_updatable (Query *viewquery, Bitmapset *required_cols, Bitmapset **updatable_cols, char **non_updatable_col)
 
int relation_is_updatable (Oid reloid, bool include_triggers, Bitmapset *include_cols)
 
static QueryrewriteTargetView (Query *parsetree, Relation view)
 
static ListRewriteQuery (Query *parsetree, List *rewrite_events)
 
ListQueryRewrite (Query *parsetree)
 

Macro Definition Documentation

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

Referenced by relation_is_updatable().

Typedef Documentation

Function Documentation

static bool acquireLocksOnSubLinks ( Node node,
acquireLocksOnSubLinks_context context 
)
static

Definition at line 293 of file rewriteHandler.c.

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

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

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

Definition at line 134 of file rewriteHandler.c.

References AccessShareLock, acquireLocksOnSubLinks(), AcquireRewriteLocks(), Assert, Query::cteList, CommonTableExpr::ctequery, elog, ERROR, acquireLocksOnSubLinks_context::for_execute, get_parse_rowmark(), get_rte_attribute_is_dropped(), Query::hasSubLinks, heap_close, heap_open(), IsA, RangeTblEntry::joinaliasvars, lappend(), lfirst, NIL, NoLock, NULL, QTW_IGNORE_RC_SUBQUERIES, query_tree_walker(), RelationData::rd_rel, RangeTblEntry::relid, RangeTblEntry::relkind, Query::resultRelation, RowExclusiveLock, RowShareLock, rt_fetch, Query::rtable, RTE_JOIN, RTE_RELATION, RTE_SUBQUERY, RangeTblEntry::rtekind, strip_implicit_coercions(), RangeTblEntry::subquery, Var::varattno, Var::varlevelsup, and Var::varno.

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

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

Definition at line 2632 of file rewriteHandler.c.

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

Referenced by relation_is_updatable(), and rewriteTargetView().

2633 {
2634  Bitmapset *result = NULL;
2635  int col;
2636 
2637  col = -1;
2638  while ((col = bms_next_member(cols, col)) >= 0)
2639  {
2640  /* bit numbers are offset by FirstLowInvalidHeapAttributeNumber */
2642 
2643  if (attno == InvalidAttrNumber)
2644  {
2645  /*
2646  * There's a whole-row reference to the view. For permissions
2647  * purposes, treat it as a reference to each column available from
2648  * the view. (We should *not* convert this to a whole-row
2649  * reference to the base relation, since the view may not touch
2650  * all columns of the base relation.)
2651  */
2652  ListCell *lc;
2653 
2654  foreach(lc, targetlist)
2655  {
2656  TargetEntry *tle = lfirst_node(TargetEntry, lc);
2657  Var *var;
2658 
2659  if (tle->resjunk)
2660  continue;
2661  var = castNode(Var, tle->expr);
2662  result = bms_add_member(result,
2663  var->varattno - FirstLowInvalidHeapAttributeNumber);
2664  }
2665  }
2666  else
2667  {
2668  /*
2669  * Views do not have system columns, so we do not expect to see
2670  * any other system attnos here. If we do find one, the error
2671  * case will apply.
2672  */
2673  TargetEntry *tle = get_tle_by_resno(targetlist, attno);
2674 
2675  if (tle != NULL && !tle->resjunk && IsA(tle->expr, Var))
2676  {
2677  Var *var = (Var *) tle->expr;
2678 
2679  result = bms_add_member(result,
2680  var->varattno - FirstLowInvalidHeapAttributeNumber);
2681  }
2682  else
2683  elog(ERROR, "attribute number %d not found in view targetlist",
2684  attno);
2685  }
2686  }
2687 
2688  return result;
2689 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:560
#define castNode(_type_, nodeptr)
Definition: nodes.h:578
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:937
AttrNumber varattno
Definition: primnodes.h:168
return result
Definition: formatting.c:1633
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:28
Definition: primnodes.h:163
bool resjunk
Definition: primnodes.h:1375
#define ERROR
Definition: elog.h:43
#define lfirst_node(type, lc)
Definition: pg_list.h:109
#define NULL
Definition: c.h:229
Expr * expr
Definition: primnodes.h:1368
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:698
#define InvalidAttrNumber
Definition: attnum.h:23
TargetEntry * get_tle_by_resno(List *tlist, AttrNumber resno)
#define elog
Definition: elog.h:219
int16 AttrNumber
Definition: attnum.h:21
static List * adjustJoinTreeList ( Query parsetree,
bool  removert,
int  rt_index 
)
static

Definition at line 637 of file rewriteHandler.c.

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

Referenced by rewriteRuleAction().

638 {
639  List *newjointree = copyObject(parsetree->jointree->fromlist);
640  ListCell *l;
641 
642  if (removert)
643  {
644  foreach(l, newjointree)
645  {
646  RangeTblRef *rtr = lfirst(l);
647 
648  if (IsA(rtr, RangeTblRef) &&
649  rtr->rtindex == rt_index)
650  {
651  newjointree = list_delete_ptr(newjointree, rtr);
652 
653  /*
654  * foreach is safe because we exit loop after list_delete...
655  */
656  break;
657  }
658  }
659  }
660  return newjointree;
661 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:560
FromExpr * jointree
Definition: parsenodes.h:136
List * fromlist
Definition: primnodes.h:1471
List * list_delete_ptr(List *list, void *datum)
Definition: list.c:590
#define lfirst(lc)
Definition: pg_list.h:106
#define copyObject(obj)
Definition: nodes.h:622
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 1458 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().

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

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

1113 {
1114  TupleDesc rd_att = rel->rd_att;
1115  Form_pg_attribute att_tup = rd_att->attrs[attrno - 1];
1116  Oid atttype = att_tup->atttypid;
1117  int32 atttypmod = att_tup->atttypmod;
1118  Node *expr = NULL;
1119  Oid exprtype;
1120 
1121  /*
1122  * Scan to see if relation has a default for this column.
1123  */
1124  if (rd_att->constr && rd_att->constr->num_defval > 0)
1125  {
1126  AttrDefault *defval = rd_att->constr->defval;
1127  int ndef = rd_att->constr->num_defval;
1128 
1129  while (--ndef >= 0)
1130  {
1131  if (attrno == defval[ndef].adnum)
1132  {
1133  /*
1134  * Found it, convert string representation to node tree.
1135  */
1136  expr = stringToNode(defval[ndef].adbin);
1137  break;
1138  }
1139  }
1140  }
1141 
1142  if (expr == NULL)
1143  {
1144  /*
1145  * No per-column default, so look for a default for the type itself.
1146  */
1147  expr = get_typdefault(atttype);
1148  }
1149 
1150  if (expr == NULL)
1151  return NULL; /* No default anywhere */
1152 
1153  /*
1154  * Make sure the value is coerced to the target column type; this will
1155  * generally be true already, but there seem to be some corner cases
1156  * involving domain defaults where it might not be true. This should match
1157  * the parser's processing of non-defaulted expressions --- see
1158  * transformAssignedExpr().
1159  */
1160  exprtype = exprType(expr);
1161 
1162  expr = coerce_to_target_type(NULL, /* no UNKNOWN params here */
1163  expr, exprtype,
1164  atttype, atttypmod,
1167  -1);
1168  if (expr == NULL)
1169  ereport(ERROR,
1170  (errcode(ERRCODE_DATATYPE_MISMATCH),
1171  errmsg("column \"%s\" is of type %s"
1172  " but default expression is of type %s",
1173  NameStr(att_tup->attname),
1174  format_type_be(atttype),
1175  format_type_be(exprtype)),
1176  errhint("You will need to rewrite or cast the expression.")));
1177 
1178  return expr;
1179 }
void * stringToNode(char *str)
Definition: read.c:38
int errhint(const char *fmt,...)
Definition: elog.c:987
Form_pg_attribute * attrs
Definition: tupdesc.h:74
Definition: nodes.h:509
int errcode(int sqlerrcode)
Definition: elog.c:575
char * format_type_be(Oid type_oid)
Definition: format_type.c:94
unsigned int Oid
Definition: postgres_ext.h:31
signed int int32
Definition: c.h:256
AttrDefault * defval
Definition: tupdesc.h:39
#define ERROR
Definition: elog.h:43
Node * coerce_to_target_type(ParseState *pstate, Node *expr, Oid exprtype, Oid targettype, int32 targettypmod, CoercionContext ccontext, CoercionForm cformat, int location)
Definition: parse_coerce.c:77
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:187
#define ereport(elevel, rest)
Definition: elog.h:122
TupleDesc rd_att
Definition: rel.h:115
uint16 num_defval
Definition: tupdesc.h:41
#define NULL
Definition: c.h:229
Node * get_typdefault(Oid typid)
Definition: lsyscache.c:2198
TupleConstr * constr
Definition: tupdesc.h:76
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define NameStr(name)
Definition: c.h:499
static Query* CopyAndAddInvertedQual ( Query parsetree,
Node rule_qual,
int  rt_index,
CmdType  event 
)
static

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

1973 {
1974  /* Don't scribble on the passed qual (it's in the relcache!) */
1975  Node *new_qual = copyObject(rule_qual);
1977 
1978  context.for_execute = true;
1979 
1980  /*
1981  * In case there are subqueries in the qual, acquire necessary locks and
1982  * fix any deleted JOIN RTE entries. (This is somewhat redundant with
1983  * rewriteRuleAction, but not entirely ... consider restructuring so that
1984  * we only need to process the qual this way once.)
1985  */
1986  (void) acquireLocksOnSubLinks(new_qual, &context);
1987 
1988  /* Fix references to OLD */
1989  ChangeVarNodes(new_qual, PRS2_OLD_VARNO, rt_index, 0);
1990  /* Fix references to NEW */
1991  if (event == CMD_INSERT || event == CMD_UPDATE)
1992  new_qual = ReplaceVarsFromTargetList(new_qual,
1994  0,
1995  rt_fetch(rt_index,
1996  parsetree->rtable),
1997  parsetree->targetList,
1998  (event == CMD_UPDATE) ?
2001  rt_index,
2002  &parsetree->hasSubLinks);
2003  /* And attach the fixed qual */
2004  AddInvertedQual(parsetree, new_qual);
2005 
2006  return parsetree;
2007 }
static bool acquireLocksOnSubLinks(Node *node, acquireLocksOnSubLinks_context *context)
void AddInvertedQual(Query *parsetree, Node *qual)
Definition: nodes.h:509
List * targetList
Definition: parsenodes.h:138
List * rtable
Definition: parsenodes.h:135
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
#define PRS2_OLD_VARNO
Definition: primnodes.h:160
Node * ReplaceVarsFromTargetList(Node *node, int target_varno, int sublevels_up, RangeTblEntry *target_rte, List *targetlist, ReplaceVarsNoMatchOption nomatch_option, int nomatch_varno, bool *outer_hasSubLinks)
bool hasSubLinks
Definition: parsenodes.h:126
void ChangeVarNodes(Node *node, int rt_index, int new_index, int sublevels_up)
Definition: rewriteManip.c:607
#define copyObject(obj)
Definition: nodes.h:622
#define PRS2_NEW_VARNO
Definition: primnodes.h:161
static bool fireRIRonSubLink ( Node node,
List activeRIRs 
)
static

Definition at line 1674 of file rewriteHandler.c.

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

Referenced by fireRIRrules().

1675 {
1676  if (node == NULL)
1677  return false;
1678  if (IsA(node, SubLink))
1679  {
1680  SubLink *sub = (SubLink *) node;
1681 
1682  /* Do what we came for */
1683  sub->subselect = (Node *) fireRIRrules((Query *) sub->subselect,
1684  activeRIRs, false);
1685  /* Fall through to process lefthand args of SubLink */
1686  }
1687 
1688  /*
1689  * Do NOT recurse into Query nodes, because fireRIRrules already processed
1690  * subselects of subselects for us.
1691  */
1693  (void *) activeRIRs);
1694 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:560
Definition: nodes.h:509
static bool fireRIRonSubLink(Node *node, List *activeRIRs)
#define NULL
Definition: c.h:229
static Query * fireRIRrules(Query *parsetree, List *activeRIRs, bool forUpdatePushedDown)
bool expression_tree_walker(Node *node, bool(*walker)(), void *context)
Definition: nodeFuncs.c:1843
static Query * fireRIRrules ( Query parsetree,
List activeRIRs,
bool  forUpdatePushedDown 
)
static

Definition at line 1702 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_PARTITIONED_TABLE, 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().

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

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

2046 {
2047  List *results = NIL;
2048  ListCell *l;
2049 
2050  foreach(l, locks)
2051  {
2052  RewriteRule *rule_lock = (RewriteRule *) lfirst(l);
2053  Node *event_qual = rule_lock->qual;
2054  List *actions = rule_lock->actions;
2055  QuerySource qsrc;
2056  ListCell *r;
2057 
2058  /* Determine correct QuerySource value for actions */
2059  if (rule_lock->isInstead)
2060  {
2061  if (event_qual != NULL)
2062  qsrc = QSRC_QUAL_INSTEAD_RULE;
2063  else
2064  {
2065  qsrc = QSRC_INSTEAD_RULE;
2066  *instead_flag = true; /* report unqualified INSTEAD */
2067  }
2068  }
2069  else
2070  qsrc = QSRC_NON_INSTEAD_RULE;
2071 
2072  if (qsrc == QSRC_QUAL_INSTEAD_RULE)
2073  {
2074  /*
2075  * If there are INSTEAD rules with qualifications, the original
2076  * query is still performed. But all the negated rule
2077  * qualifications of the INSTEAD rules are added so it does its
2078  * actions only in cases where the rule quals of all INSTEAD rules
2079  * are false. Think of it as the default action in a case. We save
2080  * this in *qual_product so RewriteQuery() can add it to the query
2081  * list after we mangled it up enough.
2082  *
2083  * If we have already found an unqualified INSTEAD rule, then
2084  * *qual_product won't be used, so don't bother building it.
2085  */
2086  if (!*instead_flag)
2087  {
2088  if (*qual_product == NULL)
2089  *qual_product = copyObject(parsetree);
2090  *qual_product = CopyAndAddInvertedQual(*qual_product,
2091  event_qual,
2092  rt_index,
2093  event);
2094  }
2095  }
2096 
2097  /* Now process the rule's actions and add them to the result list */
2098  foreach(r, actions)
2099  {
2100  Query *rule_action = lfirst(r);
2101 
2102  if (rule_action->commandType == CMD_NOTHING)
2103  continue;
2104 
2105  rule_action = rewriteRuleAction(parsetree, rule_action,
2106  event_qual, rt_index, event,
2107  returning_flag);
2108 
2109  rule_action->querySource = qsrc;
2110  rule_action->canSetTag = false; /* might change later */
2111 
2112  results = lappend(results, rule_action);
2113  }
2114  }
2115 
2116  return results;
2117 }
#define NIL
Definition: pg_list.h:69
Node * qual
Definition: prs2lock.h:28
QuerySource
Definition: parsenodes.h:38
Definition: nodes.h:509
bool isInstead
Definition: prs2lock.h:31
static Query * CopyAndAddInvertedQual(Query *parsetree, Node *rule_qual, int rt_index, CmdType event)
List * actions
Definition: prs2lock.h:29
List * lappend(List *list, void *datum)
Definition: list.c:128
CmdType commandType
Definition: parsenodes.h:110
#define NULL
Definition: c.h:229
QuerySource querySource
Definition: parsenodes.h:112
#define lfirst(lc)
Definition: pg_list.h:106
bool canSetTag
Definition: parsenodes.h:116
static Query * rewriteRuleAction(Query *parsetree, Query *rule_action, Node *rule_qual, int rt_index, CmdType event, bool *returning_flag)
#define copyObject(obj)
Definition: nodes.h:622
Definition: pg_list.h:45
static Node * get_assignment_input ( Node node)
static

Definition at line 1085 of file rewriteHandler.c.

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

Referenced by process_matched_tle().

1086 {
1087  if (node == NULL)
1088  return NULL;
1089  if (IsA(node, FieldStore))
1090  {
1091  FieldStore *fstore = (FieldStore *) node;
1092 
1093  return (Node *) fstore->arg;
1094  }
1095  else if (IsA(node, ArrayRef))
1096  {
1097  ArrayRef *aref = (ArrayRef *) node;
1098 
1099  if (aref->refassgnexpr == NULL)
1100  return NULL;
1101  return (Node *) aref->refexpr;
1102  }
1103  return NULL;
1104 }
Expr * refassgnexpr
Definition: primnodes.h:410
#define IsA(nodeptr, _type_)
Definition: nodes.h:560
Expr * arg
Definition: primnodes.h:768
Definition: nodes.h:509
#define NULL
Definition: c.h:229
Expr * refexpr
Definition: primnodes.h:408
Query* get_view_query ( Relation  view)

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

2131 {
2132  int i;
2133 
2134  Assert(view->rd_rel->relkind == RELKIND_VIEW);
2135 
2136  for (i = 0; i < view->rd_rules->numLocks; i++)
2137  {
2138  RewriteRule *rule = view->rd_rules->rules[i];
2139 
2140  if (rule->event == CMD_SELECT)
2141  {
2142  /* A _RETURN rule should have only one action */
2143  if (list_length(rule->actions) != 1)
2144  elog(ERROR, "invalid _RETURN rule action specification");
2145 
2146  return (Query *) linitial(rule->actions);
2147  }
2148  }
2149 
2150  elog(ERROR, "failed to find _RETURN rule for view");
2151  return NULL; /* keep compiler quiet */
2152 }
int numLocks
Definition: prs2lock.h:42
Form_pg_class rd_rel
Definition: rel.h:114
Definition: localtime.c:82
#define linitial(l)
Definition: pg_list.h:111
#define ERROR
Definition: elog.h:43
CmdType event
Definition: prs2lock.h:27
RewriteRule ** rules
Definition: prs2lock.h:43
List * actions
Definition: prs2lock.h:29
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
RuleLock * rd_rules
Definition: rel.h:118
static int list_length(const List *l)
Definition: pg_list.h:89
#define RELKIND_VIEW
Definition: pg_class.h:164
int i
#define elog
Definition: elog.h:219
static void markQueryForLocking ( Query qry,
Node jtnode,
LockClauseStrength  strength,
LockWaitPolicy  waitPolicy,
bool  pushedDown 
)
static

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

1617 {
1618  if (jtnode == NULL)
1619  return;
1620  if (IsA(jtnode, RangeTblRef))
1621  {
1622  int rti = ((RangeTblRef *) jtnode)->rtindex;
1623  RangeTblEntry *rte = rt_fetch(rti, qry->rtable);
1624 
1625  if (rte->rtekind == RTE_RELATION)
1626  {
1627  applyLockingClause(qry, rti, strength, waitPolicy, pushedDown);
1629  }
1630  else if (rte->rtekind == RTE_SUBQUERY)
1631  {
1632  applyLockingClause(qry, rti, strength, waitPolicy, pushedDown);
1633  /* FOR UPDATE/SHARE of subquery is propagated to subquery's rels */
1635  strength, waitPolicy, true);
1636  }
1637  /* other RTE types are unaffected by FOR UPDATE */
1638  }
1639  else if (IsA(jtnode, FromExpr))
1640  {
1641  FromExpr *f = (FromExpr *) jtnode;
1642  ListCell *l;
1643 
1644  foreach(l, f->fromlist)
1645  markQueryForLocking(qry, lfirst(l), strength, waitPolicy, pushedDown);
1646  }
1647  else if (IsA(jtnode, JoinExpr))
1648  {
1649  JoinExpr *j = (JoinExpr *) jtnode;
1650 
1651  markQueryForLocking(qry, j->larg, strength, waitPolicy, pushedDown);
1652  markQueryForLocking(qry, j->rarg, strength, waitPolicy, pushedDown);
1653  }
1654  else
1655  elog(ERROR, "unrecognized node type: %d",
1656  (int) nodeTag(jtnode));
1657 }
static void markQueryForLocking(Query *qry, Node *jtnode, LockClauseStrength strength, LockWaitPolicy waitPolicy, bool pushedDown)
#define IsA(nodeptr, _type_)
Definition: nodes.h:560
FromExpr * jointree
Definition: parsenodes.h:136
Definition: nodes.h:509
AclMode requiredPerms
Definition: parsenodes.h:1047
List * fromlist
Definition: primnodes.h:1471
Node * larg
Definition: primnodes.h:1451
List * rtable
Definition: parsenodes.h:135
#define ERROR
Definition: elog.h:43
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
Node * rarg
Definition: primnodes.h:1452
#define NULL
Definition: c.h:229
#define lfirst(lc)
Definition: pg_list.h:106
#define ACL_SELECT_FOR_UPDATE
Definition: parsenodes.h:88
#define nodeTag(nodeptr)
Definition: nodes.h:514
RTEKind rtekind
Definition: parsenodes.h:944
Query * subquery
Definition: parsenodes.h:967
#define elog
Definition: elog.h:219
void applyLockingClause(Query *qry, Index rtindex, LockClauseStrength strength, LockWaitPolicy waitPolicy, bool pushedDown)
Definition: analyze.c:2841
static List * matchLocks ( CmdType  event,
RuleLock rulelocks,
int  varno,
Query parsetree,
bool hasUpdate 
)
static

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

1397 {
1398  List *matching_locks = NIL;
1399  int nlocks;
1400  int i;
1401 
1402  if (rulelocks == NULL)
1403  return NIL;
1404 
1405  if (parsetree->commandType != CMD_SELECT)
1406  {
1407  if (parsetree->resultRelation != varno)
1408  return NIL;
1409  }
1410 
1411  nlocks = rulelocks->numLocks;
1412 
1413  for (i = 0; i < nlocks; i++)
1414  {
1415  RewriteRule *oneLock = rulelocks->rules[i];
1416 
1417  if (oneLock->event == CMD_UPDATE)
1418  *hasUpdate = true;
1419 
1420  /*
1421  * Suppress ON INSERT/UPDATE/DELETE rules that are disabled or
1422  * configured to not fire during the current sessions replication
1423  * role. ON SELECT rules will always be applied in order to keep views
1424  * working even in LOCAL or REPLICA role.
1425  */
1426  if (oneLock->event != CMD_SELECT)
1427  {
1429  {
1430  if (oneLock->enabled == RULE_FIRES_ON_ORIGIN ||
1431  oneLock->enabled == RULE_DISABLED)
1432  continue;
1433  }
1434  else /* ORIGIN or LOCAL ROLE */
1435  {
1436  if (oneLock->enabled == RULE_FIRES_ON_REPLICA ||
1437  oneLock->enabled == RULE_DISABLED)
1438  continue;
1439  }
1440  }
1441 
1442  if (oneLock->event == event)
1443  {
1444  if (parsetree->commandType != CMD_SELECT ||
1445  rangeTableEntry_used((Node *) parsetree, varno, 0))
1446  matching_locks = lappend(matching_locks, oneLock);
1447  }
1448  }
1449 
1450  return matching_locks;
1451 }
#define NIL
Definition: pg_list.h:69
int numLocks
Definition: prs2lock.h:42
int resultRelation
Definition: parsenodes.h:120
Definition: nodes.h:509
int SessionReplicationRole
Definition: trigger.c:65
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:146
#define RULE_FIRES_ON_REPLICA
Definition: rewriteDefine.h:23
CmdType commandType
Definition: parsenodes.h:110
#define NULL
Definition: c.h:229
int i
bool rangeTableEntry_used(Node *node, int rt_index, int sublevels_up)
Definition: rewriteManip.c:889
Definition: pg_list.h:45
char enabled
Definition: prs2lock.h:30
static TargetEntry * process_matched_tle ( TargetEntry src_tle,
TargetEntry prior_tle,
const char *  attrName 
)
static

Definition at line 932 of file rewriteHandler.c.

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

Referenced by rewriteTargetListIU().

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

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

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

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

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

Definition at line 3182 of file rewriteHandler.c.

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

Referenced by QueryRewrite().

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

Definition at line 334 of file rewriteHandler.c.

References acquireLocksOnSubLinks(), AcquireRewriteLocks(), AddQual(), adjustJoinTreeList(), Assert, ChangeVarNodes(), checkExprHasSubLink(), CMD_INSERT, CMD_UPDATE, CMD_UTILITY, Query::commandType, copyObject, Query::cteList, CommonTableExpr::ctename, ereport, errcode(), errmsg(), ERROR, acquireLocksOnSubLinks_context::for_execute, FromExpr::fromlist, RangeTblEntry::functions, getInsertSelectQuery(), Query::hasRowSecurity, Query::hasSubLinks, Query::jointree, lfirst, list_concat(), list_length(), NIL, NULL, OffsetVarNodes(), PRS2_NEW_VARNO, PRS2_OLD_VARNO, FromExpr::quals, rangeTableEntry_used(), REPLACEVARS_CHANGE_VARNO, REPLACEVARS_REPORT_ERROR, REPLACEVARS_SUBSTITUTE_NULL, ReplaceVarsFromTargetList(), Query::resultRelation, Query::returningList, rt_fetch, Query::rtable, RTE_FUNCTION, RTE_RELATION, RTE_TABLEFUNC, RTE_VALUES, RangeTblEntry::rtekind, Query::setOperations, RangeTblEntry::tablefunc, RangeTblEntry::tablesample, Query::targetList, and RangeTblEntry::values_lists.

Referenced by fireRules().

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

Definition at line 712 of file rewriteHandler.c.

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

Referenced by RewriteQuery().

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

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

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

Definition at line 2702 of file rewriteHandler.c.

References _, acquireLocksOnSubLinks(), AddQual(), adjust_view_column_set(), Assert, bms_add_member(), bms_is_empty(), WithCheckOption::cascaded, ChangeVarNodes(), RangeTblEntry::checkAsUser, checkExprHasSubLink(), CMD_DELETE, CMD_INSERT, CMD_UPDATE, Query::commandType, copyObject, elog, ereport, errcode(), errdetail_internal(), errhint(), errmsg(), ERROR, TargetEntry::expr, FirstLowInvalidHeapAttributeNumber, acquireLocksOnSubLinks_context::for_execute, FromExpr::fromlist, get_tle_by_resno(), get_view_query(), Query::hasSubLinks, heap_close, heap_open(), RangeTblEntry::inh, RangeTblEntry::insertedCols, IsA, Query::jointree, WithCheckOption::kind, lappend(), lcons(), lfirst, linitial, linitial_node, list_delete_ptr(), list_length(), llast, makeNode, NIL, NoLock, NULL, Query::onConflict, OnConflictExpr::onConflictSet, WithCheckOption::polname, pstrdup(), QTW_IGNORE_RC_SUBQUERIES, WithCheckOption::qual, FromExpr::quals, query_tree_walker(), RelationData::rd_rel, RelationGetRelationName, RelationHasCascadedCheckOption, RelationHasCheckOption, RelationIsSecurityView, RangeTblEntry::relid, RangeTblEntry::relkind, WithCheckOption::relname, REPLACEVARS_REPORT_ERROR, ReplaceVarsFromTargetList(), RangeTblEntry::requiredPerms, TargetEntry::resjunk, TargetEntry::resno, Query::resultRelation, RowExclusiveLock, rt_fetch, Query::rtable, RTE_RELATION, RangeTblEntry::rtekind, RangeTblRef::rtindex, RangeTblEntry::securityQuals, Query::targetList, RangeTblEntry::updatedCols, view_cols_are_auto_updatable(), view_query_is_auto_updatable(), WCO_VIEW_CHECK, and Query::withCheckOptions.

Referenced by RewriteQuery().

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

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

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

Definition at line 1184 of file rewriteHandler.c.

References IsA, lfirst, and RangeTblEntry::values_lists.

Referenced by rewriteValuesRTE().

1185 {
1186  ListCell *lc;
1187 
1188  foreach(lc, rte->values_lists)
1189  {
1190  List *sublist = (List *) lfirst(lc);
1191  ListCell *lc2;
1192 
1193  foreach(lc2, sublist)
1194  {
1195  Node *col = (Node *) lfirst(lc2);
1196 
1197  if (IsA(col, SetToDefault))
1198  return true;
1199  }
1200  }
1201  return false;
1202 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:560
Definition: nodes.h:509
List * values_lists
Definition: parsenodes.h:1009
#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 2198 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().

2199 {
2200  Var *var = (Var *) tle->expr;
2201 
2202  /*
2203  * For now, the only updatable columns we support are those that are Vars
2204  * referring to user columns of the underlying base relation.
2205  *
2206  * The view targetlist may contain resjunk columns (e.g., a view defined
2207  * like "SELECT * FROM t ORDER BY a+b" is auto-updatable) but such columns
2208  * are not auto-updatable, and in fact should never appear in the outer
2209  * query's targetlist.
2210  */
2211  if (tle->resjunk)
2212  return gettext_noop("Junk view columns are not updatable.");
2213 
2214  if (!IsA(var, Var) ||
2215  var->varno != rtr->rtindex ||
2216  var->varlevelsup != 0)
2217  return gettext_noop("View columns that are not columns of their base relation are not updatable.");
2218 
2219  if (var->varattno < 0)
2220  return gettext_noop("View columns that refer to system columns are not updatable.");
2221 
2222  if (var->varattno == 0)
2223  return gettext_noop("View columns that return whole-row references are not updatable.");
2224 
2225  return NULL; /* the view column is updatable */
2226 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:560
Index varlevelsup
Definition: primnodes.h:173
#define gettext_noop(x)
Definition: c.h:139
AttrNumber varattno
Definition: primnodes.h:168
Definition: primnodes.h:163
bool resjunk
Definition: primnodes.h:1375
Index varno
Definition: primnodes.h:166
#define NULL
Definition: c.h:229
Expr * expr
Definition: primnodes.h:1368
static const char* view_cols_are_auto_updatable ( Query viewquery,
Bitmapset required_cols,
Bitmapset **  updatable_cols,
char **  non_updatable_col 
)
static

Definition at line 2388 of file rewriteHandler.c.

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

Referenced by relation_is_updatable(), and rewriteTargetView().

2392 {
2393  RangeTblRef *rtr;
2394  AttrNumber col;
2395  ListCell *cell;
2396 
2397  /*
2398  * The caller should have verified that this view is auto-updatable and so
2399  * there should be a single base relation.
2400  */
2401  Assert(list_length(viewquery->jointree->fromlist) == 1);
2402  rtr = linitial_node(RangeTblRef, viewquery->jointree->fromlist);
2403 
2404  /* Initialize the optional return values */
2405  if (updatable_cols != NULL)
2406  *updatable_cols = NULL;
2407  if (non_updatable_col != NULL)
2408  *non_updatable_col = NULL;
2409 
2410  /* Test each view column for updatability */
2412  foreach(cell, viewquery->targetList)
2413  {
2414  TargetEntry *tle = (TargetEntry *) lfirst(cell);
2415  const char *col_update_detail;
2416 
2417  col++;
2418  col_update_detail = view_col_is_auto_updatable(rtr, tle);
2419 
2420  if (col_update_detail == NULL)
2421  {
2422  /* The column is updatable */
2423  if (updatable_cols != NULL)
2424  *updatable_cols = bms_add_member(*updatable_cols, col);
2425  }
2426  else if (bms_is_member(col, required_cols))
2427  {
2428  /* The required column is not updatable */
2429  if (non_updatable_col != NULL)
2430  *non_updatable_col = tle->resname;
2431  return col_update_detail;
2432  }
2433  }
2434 
2435  return NULL; /* all the required view columns are updatable */
2436 }
FromExpr * jointree
Definition: parsenodes.h:136
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:28
List * fromlist
Definition: primnodes.h:1471
char * resname
Definition: primnodes.h:1370
#define linitial_node(type, l)
Definition: pg_list.h:114
List * targetList
Definition: parsenodes.h:138
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
#define lfirst(lc)
Definition: pg_list.h:106
static int list_length(const List *l)
Definition: pg_list.h:89
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:698
static const char * view_col_is_auto_updatable(RangeTblRef *rtr, TargetEntry *tle)
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:420
int16 AttrNumber
Definition: attnum.h:21
static bool view_has_instead_trigger ( Relation  view,
CmdType  event 
)
static

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

2164 {
2165  TriggerDesc *trigDesc = view->trigdesc;
2166 
2167  switch (event)
2168  {
2169  case CMD_INSERT:
2170  if (trigDesc && trigDesc->trig_insert_instead_row)
2171  return true;
2172  break;
2173  case CMD_UPDATE:
2174  if (trigDesc && trigDesc->trig_update_instead_row)
2175  return true;
2176  break;
2177  case CMD_DELETE:
2178  if (trigDesc && trigDesc->trig_delete_instead_row)
2179  return true;
2180  break;
2181  default:
2182  elog(ERROR, "unrecognized CmdType: %d", (int) event);
2183  break;
2184  }
2185  return false;
2186 }
bool trig_insert_instead_row
Definition: reltrigger.h:57
#define ERROR
Definition: elog.h:43
TriggerDesc * trigdesc
Definition: rel.h:120
bool trig_update_instead_row
Definition: reltrigger.h:62
bool trig_delete_instead_row
Definition: reltrigger.h:67
#define elog
Definition: elog.h:219
const char* view_query_is_auto_updatable ( Query viewquery,
bool  check_cols 
)

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

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