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)
 
bool view_has_instead_trigger (Relation view, CmdType event, List *mergeActionList)
 
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)
 
void error_view_not_updatable (Relation view, CmdType command, List *mergeActionList, const char *detail)
 

Function Documentation

◆ AcquireRewriteLocks()

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

Definition at line 140 of file rewriteHandler.c.

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

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

◆ error_view_not_updatable()

void error_view_not_updatable ( Relation  view,
CmdType  command,
List mergeActionList,
const char *  detail 
)

Definition at line 3084 of file rewriteHandler.c.

3088 {
3089  TriggerDesc *trigDesc = view->trigdesc;
3090 
3091  switch (command)
3092  {
3093  case CMD_INSERT:
3094  ereport(ERROR,
3095  errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3096  errmsg("cannot insert into view \"%s\"",
3097  RelationGetRelationName(view)),
3098  detail ? errdetail_internal("%s", _(detail)) : 0,
3099  errhint("To enable inserting into the view, provide an INSTEAD OF INSERT trigger or an unconditional ON INSERT DO INSTEAD rule."));
3100  break;
3101  case CMD_UPDATE:
3102  ereport(ERROR,
3103  errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3104  errmsg("cannot update view \"%s\"",
3105  RelationGetRelationName(view)),
3106  detail ? errdetail_internal("%s", _(detail)) : 0,
3107  errhint("To enable updating the view, provide an INSTEAD OF UPDATE trigger or an unconditional ON UPDATE DO INSTEAD rule."));
3108  break;
3109  case CMD_DELETE:
3110  ereport(ERROR,
3111  errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3112  errmsg("cannot delete from view \"%s\"",
3113  RelationGetRelationName(view)),
3114  detail ? errdetail_internal("%s", _(detail)) : 0,
3115  errhint("To enable deleting from the view, provide an INSTEAD OF DELETE trigger or an unconditional ON DELETE DO INSTEAD rule."));
3116  break;
3117  case CMD_MERGE:
3118 
3119  /*
3120  * Note that the error hints here differ from above, since MERGE
3121  * doesn't support rules.
3122  */
3123  foreach_node(MergeAction, action, mergeActionList)
3124  {
3125  switch (action->commandType)
3126  {
3127  case CMD_INSERT:
3128  if (!trigDesc || !trigDesc->trig_insert_instead_row)
3129  ereport(ERROR,
3130  errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3131  errmsg("cannot insert into view \"%s\"",
3132  RelationGetRelationName(view)),
3133  detail ? errdetail_internal("%s", _(detail)) : 0,
3134  errhint("To enable inserting into the view using MERGE, provide an INSTEAD OF INSERT trigger."));
3135  break;
3136  case CMD_UPDATE:
3137  if (!trigDesc || !trigDesc->trig_update_instead_row)
3138  ereport(ERROR,
3139  errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3140  errmsg("cannot update view \"%s\"",
3141  RelationGetRelationName(view)),
3142  detail ? errdetail_internal("%s", _(detail)) : 0,
3143  errhint("To enable updating the view using MERGE, provide an INSTEAD OF UPDATE trigger."));
3144  break;
3145  case CMD_DELETE:
3146  if (!trigDesc || !trigDesc->trig_delete_instead_row)
3147  ereport(ERROR,
3148  errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3149  errmsg("cannot delete from view \"%s\"",
3150  RelationGetRelationName(view)),
3151  detail ? errdetail_internal("%s", _(detail)) : 0,
3152  errhint("To enable deleting from the view using MERGE, provide an INSTEAD OF DELETE trigger."));
3153  break;
3154  case CMD_NOTHING:
3155  break;
3156  default:
3157  elog(ERROR, "unrecognized commandType: %d", action->commandType);
3158  break;
3159  }
3160  }
3161  break;
3162  default:
3163  elog(ERROR, "unrecognized CmdType: %d", (int) command);
3164  break;
3165  }
3166 }
int errdetail_internal(const char *fmt,...)
Definition: elog.c:1232
#define _(x)
Definition: elog.c:90
@ CMD_MERGE
Definition: nodes.h:259
@ CMD_INSERT
Definition: nodes.h:257
@ CMD_DELETE
Definition: nodes.h:258
@ CMD_UPDATE
Definition: nodes.h:256
@ CMD_NOTHING
Definition: nodes.h:262
#define foreach_node(type, var, lst)
Definition: pg_list.h:496
TriggerDesc * trigdesc
Definition: rel.h:117
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 _, generate_unaccent_rules::action, CMD_DELETE, CMD_INSERT, CMD_MERGE, CMD_NOTHING, CMD_UPDATE, elog, ereport, errcode(), errdetail_internal(), errhint(), errmsg(), ERROR, foreach_node, RelationGetRelationName, TriggerDesc::trig_delete_instead_row, TriggerDesc::trig_insert_instead_row, TriggerDesc::trig_update_instead_row, and RelationData::trigdesc.

Referenced by CheckValidResultRel(), RewriteQuery(), and rewriteTargetView().

◆ get_view_query()

Query* get_view_query ( Relation  view)

Definition at line 2447 of file rewriteHandler.c.

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

4372 {
4373  uint64 input_query_id = parsetree->queryId;
4374  List *querylist;
4375  List *results;
4376  ListCell *l;
4377  CmdType origCmdType;
4378  bool foundOriginalQuery;
4379  Query *lastInstead;
4380 
4381  /*
4382  * This function is only applied to top-level original queries
4383  */
4384  Assert(parsetree->querySource == QSRC_ORIGINAL);
4385  Assert(parsetree->canSetTag);
4386 
4387  /*
4388  * Step 1
4389  *
4390  * Apply all non-SELECT rules possibly getting 0 or many queries
4391  */
4392  querylist = RewriteQuery(parsetree, NIL, 0);
4393 
4394  /*
4395  * Step 2
4396  *
4397  * Apply all the RIR rules on each query
4398  *
4399  * This is also a handy place to mark each query with the original queryId
4400  */
4401  results = NIL;
4402  foreach(l, querylist)
4403  {
4404  Query *query = (Query *) lfirst(l);
4405 
4406  query = fireRIRrules(query, NIL);
4407 
4408  query->queryId = input_query_id;
4409 
4410  results = lappend(results, query);
4411  }
4412 
4413  /*
4414  * Step 3
4415  *
4416  * Determine which, if any, of the resulting queries is supposed to set
4417  * the command-result tag; and update the canSetTag fields accordingly.
4418  *
4419  * If the original query is still in the list, it sets the command tag.
4420  * Otherwise, the last INSTEAD query of the same kind as the original is
4421  * allowed to set the tag. (Note these rules can leave us with no query
4422  * setting the tag. The tcop code has to cope with this by setting up a
4423  * default tag based on the original un-rewritten query.)
4424  *
4425  * The Asserts verify that at most one query in the result list is marked
4426  * canSetTag. If we aren't checking asserts, we can fall out of the loop
4427  * as soon as we find the original query.
4428  */
4429  origCmdType = parsetree->commandType;
4430  foundOriginalQuery = false;
4431  lastInstead = NULL;
4432 
4433  foreach(l, results)
4434  {
4435  Query *query = (Query *) lfirst(l);
4436 
4437  if (query->querySource == QSRC_ORIGINAL)
4438  {
4439  Assert(query->canSetTag);
4440  Assert(!foundOriginalQuery);
4441  foundOriginalQuery = true;
4442 #ifndef USE_ASSERT_CHECKING
4443  break;
4444 #endif
4445  }
4446  else
4447  {
4448  Assert(!query->canSetTag);
4449  if (query->commandType == origCmdType &&
4450  (query->querySource == QSRC_INSTEAD_RULE ||
4451  query->querySource == QSRC_QUAL_INSTEAD_RULE))
4452  lastInstead = query;
4453  }
4454  }
4455 
4456  if (!foundOriginalQuery && lastInstead != NULL)
4457  lastInstead->canSetTag = true;
4458 
4459  return results;
4460 }
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:121

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

2833 {
2834  int events = 0;
2835  Relation rel;
2836  RuleLock *rulelocks;
2837 
2838 #define ALL_EVENTS ((1 << CMD_INSERT) | (1 << CMD_UPDATE) | (1 << CMD_DELETE))
2839 
2840  /* Since this function recurses, it could be driven to stack overflow */
2842 
2843  rel = try_relation_open(reloid, AccessShareLock);
2844 
2845  /*
2846  * If the relation doesn't exist, return zero rather than throwing an
2847  * error. This is helpful since scanning an information_schema view under
2848  * MVCC rules can result in referencing rels that have actually been
2849  * deleted already.
2850  */
2851  if (rel == NULL)
2852  return 0;
2853 
2854  /* If we detect a recursive view, report that it is not updatable */
2855  if (list_member_oid(outer_reloids, RelationGetRelid(rel)))
2856  {
2858  return 0;
2859  }
2860 
2861  /* If the relation is a table, it is always updatable */
2862  if (rel->rd_rel->relkind == RELKIND_RELATION ||
2863  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
2864  {
2866  return ALL_EVENTS;
2867  }
2868 
2869  /* Look for unconditional DO INSTEAD rules, and note supported events */
2870  rulelocks = rel->rd_rules;
2871  if (rulelocks != NULL)
2872  {
2873  int i;
2874 
2875  for (i = 0; i < rulelocks->numLocks; i++)
2876  {
2877  if (rulelocks->rules[i]->isInstead &&
2878  rulelocks->rules[i]->qual == NULL)
2879  {
2880  events |= ((1 << rulelocks->rules[i]->event) & ALL_EVENTS);
2881  }
2882  }
2883 
2884  /* If we have rules for all events, we're done */
2885  if (events == ALL_EVENTS)
2886  {
2888  return events;
2889  }
2890  }
2891 
2892  /* Similarly look for INSTEAD OF triggers, if they are to be included */
2893  if (include_triggers)
2894  {
2895  TriggerDesc *trigDesc = rel->trigdesc;
2896 
2897  if (trigDesc)
2898  {
2899  if (trigDesc->trig_insert_instead_row)
2900  events |= (1 << CMD_INSERT);
2901  if (trigDesc->trig_update_instead_row)
2902  events |= (1 << CMD_UPDATE);
2903  if (trigDesc->trig_delete_instead_row)
2904  events |= (1 << CMD_DELETE);
2905 
2906  /* If we have triggers for all events, we're done */
2907  if (events == ALL_EVENTS)
2908  {
2910  return events;
2911  }
2912  }
2913  }
2914 
2915  /* If this is a foreign table, check which update events it supports */
2916  if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
2917  {
2918  FdwRoutine *fdwroutine = GetFdwRoutineForRelation(rel, false);
2919 
2920  if (fdwroutine->IsForeignRelUpdatable != NULL)
2921  events |= fdwroutine->IsForeignRelUpdatable(rel);
2922  else
2923  {
2924  /* Assume presence of executor functions is sufficient */
2925  if (fdwroutine->ExecForeignInsert != NULL)
2926  events |= (1 << CMD_INSERT);
2927  if (fdwroutine->ExecForeignUpdate != NULL)
2928  events |= (1 << CMD_UPDATE);
2929  if (fdwroutine->ExecForeignDelete != NULL)
2930  events |= (1 << CMD_DELETE);
2931  }
2932 
2934  return events;
2935  }
2936 
2937  /* Check if this is an automatically updatable view */
2938  if (rel->rd_rel->relkind == RELKIND_VIEW)
2939  {
2940  Query *viewquery = get_view_query(rel);
2941 
2942  if (view_query_is_auto_updatable(viewquery, false) == NULL)
2943  {
2944  Bitmapset *updatable_cols;
2945  int auto_events;
2946  RangeTblRef *rtr;
2947  RangeTblEntry *base_rte;
2948  Oid baseoid;
2949 
2950  /*
2951  * Determine which of the view's columns are updatable. If there
2952  * are none within the set of columns we are looking at, then the
2953  * view doesn't support INSERT/UPDATE, but it may still support
2954  * DELETE.
2955  */
2956  view_cols_are_auto_updatable(viewquery, NULL,
2957  &updatable_cols, NULL);
2958 
2959  if (include_cols != NULL)
2960  updatable_cols = bms_int_members(updatable_cols, include_cols);
2961 
2962  if (bms_is_empty(updatable_cols))
2963  auto_events = (1 << CMD_DELETE); /* May support DELETE */
2964  else
2965  auto_events = ALL_EVENTS; /* May support all events */
2966 
2967  /*
2968  * The base relation must also support these update commands.
2969  * Tables are always updatable, but for any other kind of base
2970  * relation we must do a recursive check limited to the columns
2971  * referenced by the locally updatable columns in this view.
2972  */
2973  rtr = (RangeTblRef *) linitial(viewquery->jointree->fromlist);
2974  base_rte = rt_fetch(rtr->rtindex, viewquery->rtable);
2975  Assert(base_rte->rtekind == RTE_RELATION);
2976 
2977  if (base_rte->relkind != RELKIND_RELATION &&
2978  base_rte->relkind != RELKIND_PARTITIONED_TABLE)
2979  {
2980  baseoid = base_rte->relid;
2981  outer_reloids = lappend_oid(outer_reloids,
2982  RelationGetRelid(rel));
2983  include_cols = adjust_view_column_set(updatable_cols,
2984  viewquery->targetList);
2985  auto_events &= relation_is_updatable(baseoid,
2986  outer_reloids,
2987  include_triggers,
2988  include_cols);
2989  outer_reloids = list_delete_last(outer_reloids);
2990  }
2991  events |= auto_events;
2992  }
2993  }
2994 
2995  /* If we reach here, the relation may support some update commands */
2997  return events;
2998 }
Bitmapset * bms_int_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:1109
#define bms_is_empty(a)
Definition: bitmapset.h:118
FdwRoutine * GetFdwRoutineForRelation(Relation relation, bool makecopy)
Definition: foreign.c:432
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
void check_stack_depth(void)
Definition: postgres.c:3531
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:205
Relation try_relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:88
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:2061
FromExpr * jointree
Definition: parsenodes.h:175
List * targetList
Definition: parsenodes.h:190
CmdType event
Definition: prs2lock.h:27
bool isInstead
Definition: prs2lock.h:31
Node * qual
Definition: prs2lock.h:28

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

bool view_has_instead_trigger ( Relation  view,
CmdType  event,
List mergeActionList 
)

Definition at line 2486 of file rewriteHandler.c.

2487 {
2488  TriggerDesc *trigDesc = view->trigdesc;
2489 
2490  switch (event)
2491  {
2492  case CMD_INSERT:
2493  if (trigDesc && trigDesc->trig_insert_instead_row)
2494  return true;
2495  break;
2496  case CMD_UPDATE:
2497  if (trigDesc && trigDesc->trig_update_instead_row)
2498  return true;
2499  break;
2500  case CMD_DELETE:
2501  if (trigDesc && trigDesc->trig_delete_instead_row)
2502  return true;
2503  break;
2504  case CMD_MERGE:
2505  foreach_node(MergeAction, action, mergeActionList)
2506  {
2507  switch (action->commandType)
2508  {
2509  case CMD_INSERT:
2510  if (!trigDesc || !trigDesc->trig_insert_instead_row)
2511  return false;
2512  break;
2513  case CMD_UPDATE:
2514  if (!trigDesc || !trigDesc->trig_update_instead_row)
2515  return false;
2516  break;
2517  case CMD_DELETE:
2518  if (!trigDesc || !trigDesc->trig_delete_instead_row)
2519  return false;
2520  break;
2521  case CMD_NOTHING:
2522  /* No trigger required */
2523  break;
2524  default:
2525  elog(ERROR, "unrecognized commandType: %d", action->commandType);
2526  break;
2527  }
2528  }
2529  return true; /* no actions without an INSTEAD OF trigger */
2530  default:
2531  elog(ERROR, "unrecognized CmdType: %d", (int) event);
2532  break;
2533  }
2534  return false;
2535 }

References generate_unaccent_rules::action, CMD_DELETE, CMD_INSERT, CMD_MERGE, CMD_NOTHING, CMD_UPDATE, elog, ERROR, foreach_node, TriggerDesc::trig_delete_instead_row, TriggerDesc::trig_insert_instead_row, TriggerDesc::trig_update_instead_row, and RelationData::trigdesc.

Referenced by CheckValidResultRel(), RewriteQuery(), rewriteTargetView(), and rewriteValuesRTE().

◆ view_query_is_auto_updatable()

const char* view_query_is_auto_updatable ( Query viewquery,
bool  check_cols 
)

Definition at line 2598 of file rewriteHandler.c.

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

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