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)
 
void fill_extraUpdatedCols (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, List *outer_reloids, bool include_triggers, Bitmapset *include_cols)
 

Function Documentation

◆ AcquireRewriteLocks()

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

Definition at line 139 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, 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(), AcquireRewriteLocks(), ApplyRetrieveRule(), fmgr_sql_validator(), get_query_def(), init_sql_fcache(), inline_set_returning_function(), make_ruledef(), print_function_sqlbody(), refresh_matview_datafill(), and rewriteRuleAction().

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

◆ build_column_default()

Node* build_column_default ( Relation  rel,
int  attrno 
)

Definition at line 1196 of file rewriteHandler.c.

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(), ExecComputeStoredGenerated(), rewriteTargetListIU(), rewriteValuesRTE(), and slot_fill_defaults().

1197 {
1198  TupleDesc rd_att = rel->rd_att;
1199  Form_pg_attribute att_tup = TupleDescAttr(rd_att, attrno - 1);
1200  Oid atttype = att_tup->atttypid;
1201  int32 atttypmod = att_tup->atttypmod;
1202  Node *expr = NULL;
1203  Oid exprtype;
1204 
1205  if (att_tup->attidentity)
1206  {
1208 
1209  nve->seqid = getIdentitySequence(RelationGetRelid(rel), attrno, false);
1210  nve->typeId = att_tup->atttypid;
1211 
1212  return (Node *) nve;
1213  }
1214 
1215  /*
1216  * If relation has a default for this column, fetch that expression.
1217  */
1218  if (att_tup->atthasdef)
1219  {
1220  if (rd_att->constr && rd_att->constr->num_defval > 0)
1221  {
1222  AttrDefault *defval = rd_att->constr->defval;
1223  int ndef = rd_att->constr->num_defval;
1224 
1225  while (--ndef >= 0)
1226  {
1227  if (attrno == defval[ndef].adnum)
1228  {
1229  /* Found it, convert string representation to node tree. */
1230  expr = stringToNode(defval[ndef].adbin);
1231  break;
1232  }
1233  }
1234  }
1235  if (expr == NULL)
1236  elog(ERROR, "default expression not found for attribute %d of relation \"%s\"",
1237  attrno, RelationGetRelationName(rel));
1238  }
1239 
1240  /*
1241  * No per-column default, so look for a default for the type itself. But
1242  * not for generated columns.
1243  */
1244  if (expr == NULL && !att_tup->attgenerated)
1245  expr = get_typdefault(atttype);
1246 
1247  if (expr == NULL)
1248  return NULL; /* No default anywhere */
1249 
1250  /*
1251  * Make sure the value is coerced to the target column type; this will
1252  * generally be true already, but there seem to be some corner cases
1253  * involving domain defaults where it might not be true. This should match
1254  * the parser's processing of non-defaulted expressions --- see
1255  * transformAssignedExpr().
1256  */
1257  exprtype = exprType(expr);
1258 
1259  expr = coerce_to_target_type(NULL, /* no UNKNOWN params here */
1260  expr, exprtype,
1261  atttype, atttypmod,
1264  -1);
1265  if (expr == NULL)
1266  ereport(ERROR,
1267  (errcode(ERRCODE_DATATYPE_MISMATCH),
1268  errmsg("column \"%s\" is of type %s"
1269  " but default expression is of type %s",
1270  NameStr(att_tup->attname),
1271  format_type_be(atttype),
1272  format_type_be(exprtype)),
1273  errhint("You will need to rewrite or cast the expression.")));
1274 
1275  return expr;
1276 }
int errhint(const char *fmt,...)
Definition: elog.c:1156
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
Definition: nodes.h:536
int errcode(int sqlerrcode)
Definition: elog.c:698
void * stringToNode(const char *str)
Definition: read.c:89
char * format_type_be(Oid type_oid)
Definition: format_type.c:339
unsigned int Oid
Definition: postgres_ext.h:31
Oid getIdentitySequence(Oid relid, AttrNumber attnum, bool missing_ok)
Definition: pg_depend.c:887
signed int int32
Definition: c.h:429
AttrDefault * defval
Definition: tupdesc.h:39
#define ERROR
Definition: elog.h:46
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
TupleConstr * constr
Definition: tupdesc.h:85
#define RelationGetRelationName(relation)
Definition: rel.h:511
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:207
TupleDesc rd_att
Definition: rel.h:110
#define ereport(elevel,...)
Definition: elog.h:157
#define makeNode(_type_)
Definition: nodes.h:584
Node * get_typdefault(Oid typid)
Definition: lsyscache.c:2395
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:41
uint16 num_defval
Definition: tupdesc.h:42
int errmsg(const char *fmt,...)
Definition: elog.c:909
#define elog(elevel,...)
Definition: elog.h:232
#define NameStr(name)
Definition: c.h:681
#define RelationGetRelid(relation)
Definition: rel.h:477

◆ fill_extraUpdatedCols()

void fill_extraUpdatedCols ( RangeTblEntry target_rte,
Relation  target_relation 
)

Definition at line 1596 of file rewriteHandler.c.

References AttrDefault::adbin, AttrDefault::adnum, bms_add_member(), bms_overlap(), TupleDescData::constr, TupleConstr::defval, RangeTblEntry::extraUpdatedCols, FirstLowInvalidHeapAttributeNumber, TupleConstr::has_generated_stored, i, TupleConstr::num_defval, pull_varattnos(), RelationGetDescr, stringToNode(), TupleDescAttr, and RangeTblEntry::updatedCols.

Referenced by apply_handle_update(), and RewriteQuery().

1597 {
1598  TupleDesc tupdesc = RelationGetDescr(target_relation);
1599  TupleConstr *constr = tupdesc->constr;
1600 
1601  target_rte->extraUpdatedCols = NULL;
1602 
1603  if (constr && constr->has_generated_stored)
1604  {
1605  for (int i = 0; i < constr->num_defval; i++)
1606  {
1607  AttrDefault *defval = &constr->defval[i];
1608  Node *expr;
1609  Bitmapset *attrs_used = NULL;
1610 
1611  /* skip if not generated column */
1612  if (!TupleDescAttr(tupdesc, defval->adnum - 1)->attgenerated)
1613  continue;
1614 
1615  /* identify columns this generated column depends on */
1616  expr = stringToNode(defval->adbin);
1617  pull_varattnos(expr, 1, &attrs_used);
1618 
1619  if (bms_overlap(target_rte->updatedCols, attrs_used))
1620  target_rte->extraUpdatedCols =
1621  bms_add_member(target_rte->extraUpdatedCols,
1623  }
1624  }
1625 }
#define RelationGetDescr(relation)
Definition: rel.h:503
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
Definition: nodes.h:536
void * stringToNode(const char *str)
Definition: read.c:89
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
void pull_varattnos(Node *node, Index varno, Bitmapset **varattnos)
Definition: var.c:281
AttrDefault * defval
Definition: tupdesc.h:39
bool has_generated_stored
Definition: tupdesc.h:45
Bitmapset * extraUpdatedCols
Definition: parsenodes.h:1162
TupleConstr * constr
Definition: tupdesc.h:85
Bitmapset * updatedCols
Definition: parsenodes.h:1161
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:736
bool bms_overlap(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:494
uint16 num_defval
Definition: tupdesc.h:42
int i
AttrNumber adnum
Definition: tupdesc.h:24
char * adbin
Definition: tupdesc.h:25

◆ get_view_query()

Query* get_view_query ( Relation  view)

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

2428 {
2429  int i;
2430 
2431  Assert(view->rd_rel->relkind == RELKIND_VIEW);
2432 
2433  for (i = 0; i < view->rd_rules->numLocks; i++)
2434  {
2435  RewriteRule *rule = view->rd_rules->rules[i];
2436 
2437  if (rule->event == CMD_SELECT)
2438  {
2439  /* A _RETURN rule should have only one action */
2440  if (list_length(rule->actions) != 1)
2441  elog(ERROR, "invalid _RETURN rule action specification");
2442 
2443  return (Query *) linitial(rule->actions);
2444  }
2445  }
2446 
2447  elog(ERROR, "failed to find _RETURN rule for view");
2448  return NULL; /* keep compiler quiet */
2449 }
int numLocks
Definition: prs2lock.h:42
Form_pg_class rd_rel
Definition: rel.h:109
Definition: localtime.c:72
#define linitial(l)
Definition: pg_list.h:174
#define ERROR
Definition: elog.h:46
CmdType event
Definition: prs2lock.h:27
RewriteRule ** rules
Definition: prs2lock.h:43
List * actions
Definition: prs2lock.h:29
#define Assert(condition)
Definition: c.h:804
RuleLock * rd_rules
Definition: rel.h:113
static int list_length(const List *l)
Definition: pg_list.h:149
#define elog(elevel,...)
Definition: elog.h:232
int i

◆ QueryRewrite()

List* QueryRewrite ( Query parsetree)

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

4081 {
4082  uint64 input_query_id = parsetree->queryId;
4083  List *querylist;
4084  List *results;
4085  ListCell *l;
4086  CmdType origCmdType;
4087  bool foundOriginalQuery;
4088  Query *lastInstead;
4089 
4090  /*
4091  * This function is only applied to top-level original queries
4092  */
4093  Assert(parsetree->querySource == QSRC_ORIGINAL);
4094  Assert(parsetree->canSetTag);
4095 
4096  /*
4097  * Step 1
4098  *
4099  * Apply all non-SELECT rules possibly getting 0 or many queries
4100  */
4101  querylist = RewriteQuery(parsetree, NIL);
4102 
4103  /*
4104  * Step 2
4105  *
4106  * Apply all the RIR rules on each query
4107  *
4108  * This is also a handy place to mark each query with the original queryId
4109  */
4110  results = NIL;
4111  foreach(l, querylist)
4112  {
4113  Query *query = (Query *) lfirst(l);
4114 
4115  query = fireRIRrules(query, NIL);
4116 
4117  query->queryId = input_query_id;
4118 
4119  results = lappend(results, query);
4120  }
4121 
4122  /*
4123  * Step 3
4124  *
4125  * Determine which, if any, of the resulting queries is supposed to set
4126  * the command-result tag; and update the canSetTag fields accordingly.
4127  *
4128  * If the original query is still in the list, it sets the command tag.
4129  * Otherwise, the last INSTEAD query of the same kind as the original is
4130  * allowed to set the tag. (Note these rules can leave us with no query
4131  * setting the tag. The tcop code has to cope with this by setting up a
4132  * default tag based on the original un-rewritten query.)
4133  *
4134  * The Asserts verify that at most one query in the result list is marked
4135  * canSetTag. If we aren't checking asserts, we can fall out of the loop
4136  * as soon as we find the original query.
4137  */
4138  origCmdType = parsetree->commandType;
4139  foundOriginalQuery = false;
4140  lastInstead = NULL;
4141 
4142  foreach(l, results)
4143  {
4144  Query *query = (Query *) lfirst(l);
4145 
4146  if (query->querySource == QSRC_ORIGINAL)
4147  {
4148  Assert(query->canSetTag);
4149  Assert(!foundOriginalQuery);
4150  foundOriginalQuery = true;
4151 #ifndef USE_ASSERT_CHECKING
4152  break;
4153 #endif
4154  }
4155  else
4156  {
4157  Assert(!query->canSetTag);
4158  if (query->commandType == origCmdType &&
4159  (query->querySource == QSRC_INSTEAD_RULE ||
4161  lastInstead = query;
4162  }
4163  }
4164 
4165  if (!foundOriginalQuery && lastInstead != NULL)
4166  lastInstead->canSetTag = true;
4167 
4168  return results;
4169 }
#define NIL
Definition: pg_list.h:65
static List * RewriteQuery(Query *parsetree, List *rewrite_events)
List * lappend(List *list, void *datum)
Definition: list.c:336
uint64 queryId
Definition: parsenodes.h:124
CmdType commandType
Definition: parsenodes.h:120
QuerySource querySource
Definition: parsenodes.h:122
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
bool canSetTag
Definition: parsenodes.h:126
static Query * fireRIRrules(Query *parsetree, List *activeRIRs)
Definition: pg_list.h:50
CmdType
Definition: nodes.h:680

◆ relation_is_updatable()

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

Definition at line 2777 of file rewriteHandler.c.

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(), relation_is_updatable(), 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(), pg_relation_is_updatable(), and relation_is_updatable().

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

◆ view_query_is_auto_updatable()

const char* view_query_is_auto_updatable ( Query viewquery,
bool  check_cols 
)

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

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