PostgreSQL Source Code  git master
rewriteHandler.h File Reference
#include "nodes/parsenodes.h"
#include "utils/relcache.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)
 
Queryget_view_query (Relation view)
 
const char * view_query_is_auto_updatable (Query *viewquery, bool check_cols)
 
int relation_is_updatable (Oid reloid, List *outer_reloids, bool include_triggers, Bitmapset *include_cols)
 

Function Documentation

◆ AcquireRewriteLocks()

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

Definition at line 141 of file rewriteHandler.c.

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

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

Referenced by acquireLocksOnSubLinks(), ApplyRetrieveRule(), fmgr_sql_validator(), get_query_def(), init_sql_fcache(), inline_set_returning_function(), make_ruledef(), print_function_sqlbody(), refresh_matview_datafill(), and rewriteRuleAction().

◆ build_column_default()

Node* build_column_default ( Relation  rel,
int  attrno 
)

Definition at line 1223 of file rewriteHandler.c.

1224 {
1225  TupleDesc rd_att = rel->rd_att;
1226  Form_pg_attribute att_tup = TupleDescAttr(rd_att, attrno - 1);
1227  Oid atttype = att_tup->atttypid;
1228  int32 atttypmod = att_tup->atttypmod;
1229  Node *expr = NULL;
1230  Oid exprtype;
1231 
1232  if (att_tup->attidentity)
1233  {
1235 
1236  nve->seqid = getIdentitySequence(RelationGetRelid(rel), attrno, false);
1237  nve->typeId = att_tup->atttypid;
1238 
1239  return (Node *) nve;
1240  }
1241 
1242  /*
1243  * If relation has a default for this column, fetch that expression.
1244  */
1245  if (att_tup->atthasdef)
1246  {
1247  if (rd_att->constr && rd_att->constr->num_defval > 0)
1248  {
1249  AttrDefault *defval = rd_att->constr->defval;
1250  int ndef = rd_att->constr->num_defval;
1251 
1252  while (--ndef >= 0)
1253  {
1254  if (attrno == defval[ndef].adnum)
1255  {
1256  /* Found it, convert string representation to node tree. */
1257  expr = stringToNode(defval[ndef].adbin);
1258  break;
1259  }
1260  }
1261  }
1262  if (expr == NULL)
1263  elog(ERROR, "default expression not found for attribute %d of relation \"%s\"",
1264  attrno, RelationGetRelationName(rel));
1265  }
1266 
1267  /*
1268  * No per-column default, so look for a default for the type itself. But
1269  * not for generated columns.
1270  */
1271  if (expr == NULL && !att_tup->attgenerated)
1272  expr = get_typdefault(atttype);
1273 
1274  if (expr == NULL)
1275  return NULL; /* No default anywhere */
1276 
1277  /*
1278  * Make sure the value is coerced to the target column type; this will
1279  * generally be true already, but there seem to be some corner cases
1280  * involving domain defaults where it might not be true. This should match
1281  * the parser's processing of non-defaulted expressions --- see
1282  * transformAssignedExpr().
1283  */
1284  exprtype = exprType(expr);
1285 
1286  expr = coerce_to_target_type(NULL, /* no UNKNOWN params here */
1287  expr, exprtype,
1288  atttype, atttypmod,
1291  -1);
1292  if (expr == NULL)
1293  ereport(ERROR,
1294  (errcode(ERRCODE_DATATYPE_MISMATCH),
1295  errmsg("column \"%s\" is of type %s"
1296  " but default expression is of type %s",
1297  NameStr(att_tup->attname),
1298  format_type_be(atttype),
1299  format_type_be(exprtype)),
1300  errhint("You will need to rewrite or cast the expression.")));
1301 
1302  return expr;
1303 }
#define NameStr(name)
Definition: c.h:730
signed int int32
Definition: c.h:478
int errhint(const char *fmt,...)
Definition: elog.c:1316
int errcode(int sqlerrcode)
Definition: elog.c:858
int errmsg(const char *fmt,...)
Definition: elog.c:1069
#define ereport(elevel,...)
Definition: elog.h:149
char * format_type_be(Oid type_oid)
Definition: format_type.c:339
Node * get_typdefault(Oid typid)
Definition: lsyscache.c:2406
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:43
#define makeNode(_type_)
Definition: nodes.h:176
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:209
Oid getIdentitySequence(Oid relid, AttrNumber attnum, bool missing_ok)
Definition: pg_depend.c:944
unsigned int Oid
Definition: postgres_ext.h:31
@ COERCE_IMPLICIT_CAST
Definition: primnodes.h:663
@ COERCION_ASSIGNMENT
Definition: primnodes.h:642
void * stringToNode(const char *str)
Definition: read.c:90
#define RelationGetRelid(relation)
Definition: rel.h:504
#define RelationGetRelationName(relation)
Definition: rel.h:538
TupleDesc rd_att
Definition: rel.h:112
AttrDefault * defval
Definition: tupdesc.h:39
uint16 num_defval
Definition: tupdesc.h:42
TupleConstr * constr
Definition: tupdesc.h:85
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92

References COERCE_IMPLICIT_CAST, coerce_to_target_type(), COERCION_ASSIGNMENT, TupleDescData::constr, TupleConstr::defval, elog(), ereport, errcode(), errhint(), errmsg(), ERROR, exprType(), format_type_be(), get_typdefault(), getIdentitySequence(), makeNode, NameStr, TupleConstr::num_defval, RelationData::rd_att, RelationGetRelationName, RelationGetRelid, NextValueExpr::seqid, stringToNode(), TupleDescAttr, and NextValueExpr::typeId.

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

◆ get_view_query()

Query* get_view_query ( Relation  view)

Definition at line 2438 of file rewriteHandler.c.

2439 {
2440  int i;
2441 
2442  Assert(view->rd_rel->relkind == RELKIND_VIEW);
2443 
2444  for (i = 0; i < view->rd_rules->numLocks; i++)
2445  {
2446  RewriteRule *rule = view->rd_rules->rules[i];
2447 
2448  if (rule->event == CMD_SELECT)
2449  {
2450  /* A _RETURN rule should have only one action */
2451  if (list_length(rule->actions) != 1)
2452  elog(ERROR, "invalid _RETURN rule action specification");
2453 
2454  return (Query *) linitial(rule->actions);
2455  }
2456  }
2457 
2458  elog(ERROR, "failed to find _RETURN rule for view");
2459  return NULL; /* keep compiler quiet */
2460 }
int i
Definition: isn.c:73
@ CMD_SELECT
Definition: nodes.h:276
static int list_length(const List *l)
Definition: pg_list.h:152
#define linitial(l)
Definition: pg_list.h:178
RuleLock * rd_rules
Definition: rel.h:115
RewriteRule ** rules
Definition: prs2lock.h:43
int numLocks
Definition: prs2lock.h:42
Definition: localtime.c:73

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

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

◆ QueryRewrite()

List* QueryRewrite ( Query parsetree)

Definition at line 4196 of file rewriteHandler.c.

4197 {
4198  uint64 input_query_id = parsetree->queryId;
4199  List *querylist;
4200  List *results;
4201  ListCell *l;
4202  CmdType origCmdType;
4203  bool foundOriginalQuery;
4204  Query *lastInstead;
4205 
4206  /*
4207  * This function is only applied to top-level original queries
4208  */
4209  Assert(parsetree->querySource == QSRC_ORIGINAL);
4210  Assert(parsetree->canSetTag);
4211 
4212  /*
4213  * Step 1
4214  *
4215  * Apply all non-SELECT rules possibly getting 0 or many queries
4216  */
4217  querylist = RewriteQuery(parsetree, NIL, 0);
4218 
4219  /*
4220  * Step 2
4221  *
4222  * Apply all the RIR rules on each query
4223  *
4224  * This is also a handy place to mark each query with the original queryId
4225  */
4226  results = NIL;
4227  foreach(l, querylist)
4228  {
4229  Query *query = (Query *) lfirst(l);
4230 
4231  query = fireRIRrules(query, NIL);
4232 
4233  query->queryId = input_query_id;
4234 
4235  results = lappend(results, query);
4236  }
4237 
4238  /*
4239  * Step 3
4240  *
4241  * Determine which, if any, of the resulting queries is supposed to set
4242  * the command-result tag; and update the canSetTag fields accordingly.
4243  *
4244  * If the original query is still in the list, it sets the command tag.
4245  * Otherwise, the last INSTEAD query of the same kind as the original is
4246  * allowed to set the tag. (Note these rules can leave us with no query
4247  * setting the tag. The tcop code has to cope with this by setting up a
4248  * default tag based on the original un-rewritten query.)
4249  *
4250  * The Asserts verify that at most one query in the result list is marked
4251  * canSetTag. If we aren't checking asserts, we can fall out of the loop
4252  * as soon as we find the original query.
4253  */
4254  origCmdType = parsetree->commandType;
4255  foundOriginalQuery = false;
4256  lastInstead = NULL;
4257 
4258  foreach(l, results)
4259  {
4260  Query *query = (Query *) lfirst(l);
4261 
4262  if (query->querySource == QSRC_ORIGINAL)
4263  {
4264  Assert(query->canSetTag);
4265  Assert(!foundOriginalQuery);
4266  foundOriginalQuery = true;
4267 #ifndef USE_ASSERT_CHECKING
4268  break;
4269 #endif
4270  }
4271  else
4272  {
4273  Assert(!query->canSetTag);
4274  if (query->commandType == origCmdType &&
4275  (query->querySource == QSRC_INSTEAD_RULE ||
4276  query->querySource == QSRC_QUAL_INSTEAD_RULE))
4277  lastInstead = query;
4278  }
4279  }
4280 
4281  if (!foundOriginalQuery && lastInstead != NULL)
4282  lastInstead->canSetTag = true;
4283 
4284  return results;
4285 }
CmdType
Definition: nodes.h:274
@ QSRC_QUAL_INSTEAD_RULE
Definition: parsenodes.h:46
@ QSRC_ORIGINAL
Definition: parsenodes.h:43
@ QSRC_INSTEAD_RULE
Definition: parsenodes.h:45
static List * RewriteQuery(Query *parsetree, List *rewrite_events, int orig_rt_length)
static Query * fireRIRrules(Query *parsetree, List *activeRIRs)
CmdType commandType
Definition: parsenodes.h:128

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

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

◆ relation_is_updatable()

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

Definition at line 2788 of file rewriteHandler.c.

2792 {
2793  int events = 0;
2794  Relation rel;
2795  RuleLock *rulelocks;
2796 
2797 #define ALL_EVENTS ((1 << CMD_INSERT) | (1 << CMD_UPDATE) | (1 << CMD_DELETE))
2798 
2799  /* Since this function recurses, it could be driven to stack overflow */
2801 
2802  rel = try_relation_open(reloid, AccessShareLock);
2803 
2804  /*
2805  * If the relation doesn't exist, return zero rather than throwing an
2806  * error. This is helpful since scanning an information_schema view under
2807  * MVCC rules can result in referencing rels that have actually been
2808  * deleted already.
2809  */
2810  if (rel == NULL)
2811  return 0;
2812 
2813  /* If we detect a recursive view, report that it is not updatable */
2814  if (list_member_oid(outer_reloids, RelationGetRelid(rel)))
2815  {
2817  return 0;
2818  }
2819 
2820  /* If the relation is a table, it is always updatable */
2821  if (rel->rd_rel->relkind == RELKIND_RELATION ||
2822  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
2823  {
2825  return ALL_EVENTS;
2826  }
2827 
2828  /* Look for unconditional DO INSTEAD rules, and note supported events */
2829  rulelocks = rel->rd_rules;
2830  if (rulelocks != NULL)
2831  {
2832  int i;
2833 
2834  for (i = 0; i < rulelocks->numLocks; i++)
2835  {
2836  if (rulelocks->rules[i]->isInstead &&
2837  rulelocks->rules[i]->qual == NULL)
2838  {
2839  events |= ((1 << rulelocks->rules[i]->event) & ALL_EVENTS);
2840  }
2841  }
2842 
2843  /* If we have rules for all events, we're done */
2844  if (events == ALL_EVENTS)
2845  {
2847  return events;
2848  }
2849  }
2850 
2851  /* Similarly look for INSTEAD OF triggers, if they are to be included */
2852  if (include_triggers)
2853  {
2854  TriggerDesc *trigDesc = rel->trigdesc;
2855 
2856  if (trigDesc)
2857  {
2858  if (trigDesc->trig_insert_instead_row)
2859  events |= (1 << CMD_INSERT);
2860  if (trigDesc->trig_update_instead_row)
2861  events |= (1 << CMD_UPDATE);
2862  if (trigDesc->trig_delete_instead_row)
2863  events |= (1 << CMD_DELETE);
2864 
2865  /* If we have triggers for all events, we're done */
2866  if (events == ALL_EVENTS)
2867  {
2869  return events;
2870  }
2871  }
2872  }
2873 
2874  /* If this is a foreign table, check which update events it supports */
2875  if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
2876  {
2877  FdwRoutine *fdwroutine = GetFdwRoutineForRelation(rel, false);
2878 
2879  if (fdwroutine->IsForeignRelUpdatable != NULL)
2880  events |= fdwroutine->IsForeignRelUpdatable(rel);
2881  else
2882  {
2883  /* Assume presence of executor functions is sufficient */
2884  if (fdwroutine->ExecForeignInsert != NULL)
2885  events |= (1 << CMD_INSERT);
2886  if (fdwroutine->ExecForeignUpdate != NULL)
2887  events |= (1 << CMD_UPDATE);
2888  if (fdwroutine->ExecForeignDelete != NULL)
2889  events |= (1 << CMD_DELETE);
2890  }
2891 
2893  return events;
2894  }
2895 
2896  /* Check if this is an automatically updatable view */
2897  if (rel->rd_rel->relkind == RELKIND_VIEW)
2898  {
2899  Query *viewquery = get_view_query(rel);
2900 
2901  if (view_query_is_auto_updatable(viewquery, false) == NULL)
2902  {
2903  Bitmapset *updatable_cols;
2904  int auto_events;
2905  RangeTblRef *rtr;
2906  RangeTblEntry *base_rte;
2907  Oid baseoid;
2908 
2909  /*
2910  * Determine which of the view's columns are updatable. If there
2911  * are none within the set of columns we are looking at, then the
2912  * view doesn't support INSERT/UPDATE, but it may still support
2913  * DELETE.
2914  */
2915  view_cols_are_auto_updatable(viewquery, NULL,
2916  &updatable_cols, NULL);
2917 
2918  if (include_cols != NULL)
2919  updatable_cols = bms_int_members(updatable_cols, include_cols);
2920 
2921  if (bms_is_empty(updatable_cols))
2922  auto_events = (1 << CMD_DELETE); /* May support DELETE */
2923  else
2924  auto_events = ALL_EVENTS; /* May support all events */
2925 
2926  /*
2927  * The base relation must also support these update commands.
2928  * Tables are always updatable, but for any other kind of base
2929  * relation we must do a recursive check limited to the columns
2930  * referenced by the locally updatable columns in this view.
2931  */
2932  rtr = (RangeTblRef *) linitial(viewquery->jointree->fromlist);
2933  base_rte = rt_fetch(rtr->rtindex, viewquery->rtable);
2934  Assert(base_rte->rtekind == RTE_RELATION);
2935 
2936  if (base_rte->relkind != RELKIND_RELATION &&
2937  base_rte->relkind != RELKIND_PARTITIONED_TABLE)
2938  {
2939  baseoid = base_rte->relid;
2940  outer_reloids = lappend_oid(outer_reloids,
2941  RelationGetRelid(rel));
2942  include_cols = adjust_view_column_set(updatable_cols,
2943  viewquery->targetList);
2944  auto_events &= relation_is_updatable(baseoid,
2945  outer_reloids,
2946  include_triggers,
2947  include_cols);
2948  outer_reloids = list_delete_last(outer_reloids);
2949  }
2950  events |= auto_events;
2951  }
2952  }
2953 
2954  /* If we reach here, the relation may support some update commands */
2956  return events;
2957 }
Bitmapset * bms_int_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:928
#define bms_is_empty(a)
Definition: bitmapset.h:105
FdwRoutine * GetFdwRoutineForRelation(Relation relation, bool makecopy)
Definition: foreign.c:429
List * lappend_oid(List *list, Oid datum)
Definition: list.c:374
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:721
List * list_delete_last(List *list)
Definition: list.c:956
@ CMD_INSERT
Definition: nodes.h:278
@ CMD_DELETE
Definition: nodes.h:279
@ CMD_UPDATE
Definition: nodes.h:277
void check_stack_depth(void)
Definition: postgres.c:3508
const char * view_query_is_auto_updatable(Query *viewquery, bool check_cols)
int relation_is_updatable(Oid reloid, List *outer_reloids, bool include_triggers, Bitmapset *include_cols)
static Bitmapset * adjust_view_column_set(Bitmapset *cols, List *targetlist)
static const char * view_cols_are_auto_updatable(Query *viewquery, Bitmapset *required_cols, Bitmapset **updatable_cols, char **non_updatable_col)
Query * get_view_query(Relation view)
#define ALL_EVENTS
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
Relation try_relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:89
ExecForeignInsert_function ExecForeignInsert
Definition: fdwapi.h:232
ExecForeignUpdate_function ExecForeignUpdate
Definition: fdwapi.h:235
ExecForeignDelete_function ExecForeignDelete
Definition: fdwapi.h:236
IsForeignRelUpdatable_function IsForeignRelUpdatable
Definition: fdwapi.h:240
List * fromlist
Definition: primnodes.h:2004
FromExpr * jointree
Definition: parsenodes.h:182
List * targetList
Definition: parsenodes.h:189
TriggerDesc * trigdesc
Definition: rel.h:117
CmdType event
Definition: prs2lock.h:27
bool isInstead
Definition: prs2lock.h:31
Node * qual
Definition: prs2lock.h:28
bool trig_update_instead_row
Definition: reltrigger.h:63
bool trig_delete_instead_row
Definition: reltrigger.h:68
bool trig_insert_instead_row
Definition: reltrigger.h:58

References AccessShareLock, adjust_view_column_set(), ALL_EVENTS, Assert(), bms_int_members(), bms_is_empty, check_stack_depth(), 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, lappend_oid(), linitial, list_delete_last(), list_member_oid(), RuleLock::numLocks, RewriteRule::qual, RelationData::rd_rel, RelationData::rd_rules, relation_close(), RelationGetRelid, 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(), and pg_relation_is_updatable().

◆ view_query_is_auto_updatable()

const char* view_query_is_auto_updatable ( Query viewquery,
bool  check_cols 
)

Definition at line 2557 of file rewriteHandler.c.

2558 {
2559  RangeTblRef *rtr;
2560  RangeTblEntry *base_rte;
2561 
2562  /*----------
2563  * Check if the view is simply updatable. According to SQL-92 this means:
2564  * - No DISTINCT clause.
2565  * - Each TLE is a column reference, and each column appears at most once.
2566  * - FROM contains exactly one base relation.
2567  * - No GROUP BY or HAVING clauses.
2568  * - No set operations (UNION, INTERSECT or EXCEPT).
2569  * - No sub-queries in the WHERE clause that reference the target table.
2570  *
2571  * We ignore that last restriction since it would be complex to enforce
2572  * and there isn't any actual benefit to disallowing sub-queries. (The
2573  * semantic issues that the standard is presumably concerned about don't
2574  * arise in Postgres, since any such sub-query will not see any updates
2575  * executed by the outer query anyway, thanks to MVCC snapshotting.)
2576  *
2577  * We also relax the second restriction by supporting part of SQL:1999
2578  * feature T111, which allows for a mix of updatable and non-updatable
2579  * columns, provided that an INSERT or UPDATE doesn't attempt to assign to
2580  * a non-updatable column.
2581  *
2582  * In addition we impose these constraints, involving features that are
2583  * not part of SQL-92:
2584  * - No CTEs (WITH clauses).
2585  * - No OFFSET or LIMIT clauses (this matches a SQL:2008 restriction).
2586  * - No system columns (including whole-row references) in the tlist.
2587  * - No window functions in the tlist.
2588  * - No set-returning functions in the tlist.
2589  *
2590  * Note that we do these checks without recursively expanding the view.
2591  * If the base relation is a view, we'll recursively deal with it later.
2592  *----------
2593  */
2594  if (viewquery->distinctClause != NIL)
2595  return gettext_noop("Views containing DISTINCT are not automatically updatable.");
2596 
2597  if (viewquery->groupClause != NIL || viewquery->groupingSets)
2598  return gettext_noop("Views containing GROUP BY are not automatically updatable.");
2599 
2600  if (viewquery->havingQual != NULL)
2601  return gettext_noop("Views containing HAVING are not automatically updatable.");
2602 
2603  if (viewquery->setOperations != NULL)
2604  return gettext_noop("Views containing UNION, INTERSECT, or EXCEPT are not automatically updatable.");
2605 
2606  if (viewquery->cteList != NIL)
2607  return gettext_noop("Views containing WITH are not automatically updatable.");
2608 
2609  if (viewquery->limitOffset != NULL || viewquery->limitCount != NULL)
2610  return gettext_noop("Views containing LIMIT or OFFSET are not automatically updatable.");
2611 
2612  /*
2613  * We must not allow window functions or set returning functions in the
2614  * targetlist. Otherwise we might end up inserting them into the quals of
2615  * the main query. We must also check for aggregates in the targetlist in
2616  * case they appear without a GROUP BY.
2617  *
2618  * These restrictions ensure that each row of the view corresponds to a
2619  * unique row in the underlying base relation.
2620  */
2621  if (viewquery->hasAggs)
2622  return gettext_noop("Views that return aggregate functions are not automatically updatable.");
2623 
2624  if (viewquery->hasWindowFuncs)
2625  return gettext_noop("Views that return window functions are not automatically updatable.");
2626 
2627  if (viewquery->hasTargetSRFs)
2628  return gettext_noop("Views that return set-returning functions are not automatically updatable.");
2629 
2630  /*
2631  * The view query should select from a single base relation, which must be
2632  * a table or another view.
2633  */
2634  if (list_length(viewquery->jointree->fromlist) != 1)
2635  return gettext_noop("Views that do not select from a single table or view are not automatically updatable.");
2636 
2637  rtr = (RangeTblRef *) linitial(viewquery->jointree->fromlist);
2638  if (!IsA(rtr, RangeTblRef))
2639  return gettext_noop("Views that do not select from a single table or view are not automatically updatable.");
2640 
2641  base_rte = rt_fetch(rtr->rtindex, viewquery->rtable);
2642  if (base_rte->rtekind != RTE_RELATION ||
2643  (base_rte->relkind != RELKIND_RELATION &&
2644  base_rte->relkind != RELKIND_FOREIGN_TABLE &&
2645  base_rte->relkind != RELKIND_VIEW &&
2646  base_rte->relkind != RELKIND_PARTITIONED_TABLE))
2647  return gettext_noop("Views that do not select from a single table or view are not automatically updatable.");
2648 
2649  if (base_rte->tablesample)
2650  return gettext_noop("Views containing TABLESAMPLE are not automatically updatable.");
2651 
2652  /*
2653  * Check that the view has at least one updatable column. This is required
2654  * for INSERT/UPDATE but not for DELETE.
2655  */
2656  if (check_cols)
2657  {
2658  ListCell *cell;
2659  bool found;
2660 
2661  found = false;
2662  foreach(cell, viewquery->targetList)
2663  {
2664  TargetEntry *tle = (TargetEntry *) lfirst(cell);
2665 
2666  if (view_col_is_auto_updatable(rtr, tle) == NULL)
2667  {
2668  found = true;
2669  break;
2670  }
2671  }
2672 
2673  if (!found)
2674  return gettext_noop("Views that have no updatable columns are not automatically updatable.");
2675  }
2676 
2677  return NULL; /* the view is updatable */
2678 }
#define gettext_noop(x)
Definition: c.h:1204
static const char * view_col_is_auto_updatable(RangeTblRef *rtr, TargetEntry *tle)
Node * limitCount
Definition: parsenodes.h:212
Node * setOperations
Definition: parsenodes.h:217
List * groupClause
Definition: parsenodes.h:198
Node * havingQual
Definition: parsenodes.h:203
Node * limitOffset
Definition: parsenodes.h:211
List * groupingSets
Definition: parsenodes.h:201
List * distinctClause
Definition: parsenodes.h:207
struct TableSampleClause * tablesample
Definition: parsenodes.h:1075

References Query::cteList, Query::distinctClause, FromExpr::fromlist, gettext_noop, Query::groupClause, Query::groupingSets, 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().