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 142 of file rewriteHandler.c.

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

1227 {
1228  TupleDesc rd_att = rel->rd_att;
1229  Form_pg_attribute att_tup = TupleDescAttr(rd_att, attrno - 1);
1230  Oid atttype = att_tup->atttypid;
1231  int32 atttypmod = att_tup->atttypmod;
1232  Node *expr = NULL;
1233  Oid exprtype;
1234 
1235  if (att_tup->attidentity)
1236  {
1238  Oid reloid;
1239 
1240  /*
1241  * The identity sequence is associated with the topmost partitioned
1242  * table.
1243  */
1244  if (rel->rd_rel->relispartition)
1245  {
1246  List *ancestors =
1248 
1249  reloid = llast_oid(ancestors);
1250  list_free(ancestors);
1251  }
1252  else
1253  reloid = RelationGetRelid(rel);
1254 
1255  nve->seqid = getIdentitySequence(reloid, attrno, false);
1256  nve->typeId = att_tup->atttypid;
1257 
1258  return (Node *) nve;
1259  }
1260 
1261  /*
1262  * If relation has a default for this column, fetch that expression.
1263  */
1264  if (att_tup->atthasdef)
1265  {
1266  expr = TupleDescGetDefault(rd_att, attrno);
1267  if (expr == NULL)
1268  elog(ERROR, "default expression not found for attribute %d of relation \"%s\"",
1269  attrno, RelationGetRelationName(rel));
1270  }
1271 
1272  /*
1273  * No per-column default, so look for a default for the type itself. But
1274  * not for generated columns.
1275  */
1276  if (expr == NULL && !att_tup->attgenerated)
1277  expr = get_typdefault(atttype);
1278 
1279  if (expr == NULL)
1280  return NULL; /* No default anywhere */
1281 
1282  /*
1283  * Make sure the value is coerced to the target column type; this will
1284  * generally be true already, but there seem to be some corner cases
1285  * involving domain defaults where it might not be true. This should match
1286  * the parser's processing of non-defaulted expressions --- see
1287  * transformAssignedExpr().
1288  */
1289  exprtype = exprType(expr);
1290 
1291  expr = coerce_to_target_type(NULL, /* no UNKNOWN params here */
1292  expr, exprtype,
1293  atttype, atttypmod,
1296  -1);
1297  if (expr == NULL)
1298  ereport(ERROR,
1299  (errcode(ERRCODE_DATATYPE_MISMATCH),
1300  errmsg("column \"%s\" is of type %s"
1301  " but default expression is of type %s",
1302  NameStr(att_tup->attname),
1303  format_type_be(atttype),
1304  format_type_be(exprtype)),
1305  errhint("You will need to rewrite or cast the expression.")));
1306 
1307  return expr;
1308 }
#define NameStr(name)
Definition: c.h:735
signed int int32
Definition: c.h:483
int errhint(const char *fmt,...)
Definition: elog.c:1322
int errcode(int sqlerrcode)
Definition: elog.c:860
int errmsg(const char *fmt,...)
Definition: elog.c:1075
#define ereport(elevel,...)
Definition: elog.h:149
char * format_type_be(Oid type_oid)
Definition: format_type.c:343
void list_free(List *list)
Definition: list.c:1546
Node * get_typdefault(Oid typid)
Definition: lsyscache.c:2403
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:43
#define makeNode(_type_)
Definition: nodes.h:155
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
List * get_partition_ancestors(Oid relid)
Definition: partition.c:135
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
#define llast_oid(l)
Definition: pg_list.h:200
unsigned int Oid
Definition: postgres_ext.h:31
@ COERCE_IMPLICIT_CAST
Definition: primnodes.h:671
@ COERCION_ASSIGNMENT
Definition: primnodes.h:650
#define RelationGetRelid(relation)
Definition: rel.h:504
#define RelationGetRelationName(relation)
Definition: rel.h:538
TupleDesc rd_att
Definition: rel.h:112
Node * TupleDescGetDefault(TupleDesc tupdesc, AttrNumber attnum)
Definition: tupdesc.c:851
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92

References COERCE_IMPLICIT_CAST, coerce_to_target_type(), COERCION_ASSIGNMENT, elog(), ereport, errcode(), errhint(), errmsg(), ERROR, exprType(), format_type_be(), get_partition_ancestors(), get_typdefault(), getIdentitySequence(), list_free(), llast_oid, makeNode, NameStr, RelationData::rd_att, RelationData::rd_rel, RelationGetRelationName, RelationGetRelid, NextValueExpr::seqid, TupleDescAttr, TupleDescGetDefault(), and NextValueExpr::typeId.

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

◆ get_view_query()

Query* get_view_query ( Relation  view)

Definition at line 2442 of file rewriteHandler.c.

2443 {
2444  int i;
2445 
2446  Assert(view->rd_rel->relkind == RELKIND_VIEW);
2447 
2448  for (i = 0; i < view->rd_rules->numLocks; i++)
2449  {
2450  RewriteRule *rule = view->rd_rules->rules[i];
2451 
2452  if (rule->event == CMD_SELECT)
2453  {
2454  /* A _RETURN rule should have only one action */
2455  if (list_length(rule->actions) != 1)
2456  elog(ERROR, "invalid _RETURN rule action specification");
2457 
2458  return (Query *) linitial(rule->actions);
2459  }
2460  }
2461 
2462  elog(ERROR, "failed to find _RETURN rule for view");
2463  return NULL; /* keep compiler quiet */
2464 }
int i
Definition: isn.c:73
@ CMD_SELECT
Definition: nodes.h:255
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 4200 of file rewriteHandler.c.

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

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 2792 of file rewriteHandler.c.

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

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

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().