PostgreSQL Source Code  git master
rewriteHandler.h File Reference
#include "utils/relcache.h"
#include "nodes/parsenodes.h"
Include dependency graph for rewriteHandler.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

ListQueryRewrite (Query *parsetree)
 
void AcquireRewriteLocks (Query *parsetree, bool forExecute, bool forUpdatePushedDown)
 
Nodebuild_column_default (Relation rel, int attrno)
 
void rewriteTargetListUD (Query *parsetree, RangeTblEntry *target_rte, Relation target_relation)
 
Queryget_view_query (Relation view)
 
const char * view_query_is_auto_updatable (Query *viewquery, bool check_cols)
 
int relation_is_updatable (Oid reloid, bool include_triggers, Bitmapset *include_cols)
 

Function Documentation

◆ AcquireRewriteLocks()

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

Definition at line 131 of file rewriteHandler.c.

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

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

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

◆ build_column_default()

Node* build_column_default ( Relation  rel,
int  attrno 
)

Definition at line 1106 of file rewriteHandler.c.

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

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

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

◆ get_view_query()

Query* get_view_query ( Relation  view)

Definition at line 2144 of file rewriteHandler.c.

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

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

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

◆ QueryRewrite()

List* QueryRewrite ( Query parsetree)

Definition at line 3569 of file rewriteHandler.c.

References Assert, Query::canSetTag, Query::commandType, fireRIRrules(), lappend(), lfirst, NIL, QSRC_INSTEAD_RULE, QSRC_ORIGINAL, QSRC_QUAL_INSTEAD_RULE, Query::queryId, Query::querySource, and RewriteQuery().

Referenced by ExecCreateTableAs(), ExplainOneUtility(), ExplainQuery(), PerformCursorOpen(), pg_rewrite_query(), PrepareQuery(), and refresh_matview_datafill().

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

◆ relation_is_updatable()

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

Definition at line 2480 of file rewriteHandler.c.

References AccessShareLock, adjust_view_column_set(), ALL_EVENTS, Assert, bms_int_members(), bms_is_empty(), CMD_DELETE, CMD_INSERT, CMD_UPDATE, RewriteRule::event, FdwRoutine::ExecForeignDelete, FdwRoutine::ExecForeignInsert, FdwRoutine::ExecForeignUpdate, FromExpr::fromlist, get_view_query(), GetFdwRoutineForRelation(), i, FdwRoutine::IsForeignRelUpdatable, RewriteRule::isInstead, Query::jointree, linitial, RuleLock::numLocks, RewriteRule::qual, RelationData::rd_rel, RelationData::rd_rules, relation_close(), relation_is_updatable(), RangeTblEntry::relid, RangeTblEntry::relkind, rt_fetch, Query::rtable, RTE_RELATION, RangeTblEntry::rtekind, RangeTblRef::rtindex, RuleLock::rules, Query::targetList, TriggerDesc::trig_delete_instead_row, TriggerDesc::trig_insert_instead_row, TriggerDesc::trig_update_instead_row, RelationData::trigdesc, try_relation_open(), view_cols_are_auto_updatable(), and view_query_is_auto_updatable().

Referenced by pg_column_is_updatable(), pg_relation_is_updatable(), and relation_is_updatable().

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

◆ rewriteTargetListUD()

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

Definition at line 1310 of file rewriteHandler.c.

References FdwRoutine::AddForeignUpdateTargets, CMD_DELETE, CMD_UPDATE, Query::commandType, GetFdwRoutineForRelation(), InvalidOid, lappend(), list_length(), makeTargetEntry(), makeVar(), makeWholeRowVar(), pstrdup(), RelationData::rd_rel, Query::resultRelation, SelfItemPointerAttributeNumber, Query::targetList, TriggerDesc::trig_delete_after_row, TriggerDesc::trig_delete_before_row, TriggerDesc::trig_update_after_row, TriggerDesc::trig_update_before_row, and RelationData::trigdesc.

Referenced by preprocess_targetlist().

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

◆ view_query_is_auto_updatable()

const char* view_query_is_auto_updatable ( Query viewquery,
bool  check_cols 
)

Definition at line 2257 of file rewriteHandler.c.

References Query::cteList, Query::distinctClause, FromExpr::fromlist, gettext_noop, Query::groupClause, Query::groupingSets, Query::hasAggs, Query::hasTargetSRFs, Query::hasWindowFuncs, Query::havingQual, IsA, Query::jointree, lfirst, Query::limitCount, Query::limitOffset, linitial, list_length(), NIL, RangeTblEntry::relkind, rt_fetch, Query::rtable, RTE_RELATION, RangeTblEntry::rtekind, RangeTblRef::rtindex, Query::setOperations, RangeTblEntry::tablesample, Query::targetList, and view_col_is_auto_updatable().

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

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