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 rewriteTargetListUD (Query *parsetree, RangeTblEntry *target_rte, Relation target_relation)
 
Queryget_view_query (Relation view)
 
const char * view_query_is_auto_updatable (Query *viewquery, bool check_cols)
 
int relation_is_updatable (Oid reloid, List *outer_reloids, bool include_triggers, Bitmapset *include_cols)
 

Function Documentation

◆ AcquireRewriteLocks()

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

Definition at line 133 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(), get_query_def(), make_ruledef(), refresh_matview_datafill(), and rewriteRuleAction().

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

◆ build_column_default()

Node* build_column_default ( Relation  rel,
int  attrno 
)

Definition at line 1121 of file rewriteHandler.c.

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

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

1122 {
1123  TupleDesc rd_att = rel->rd_att;
1124  Form_pg_attribute att_tup = TupleDescAttr(rd_att, attrno - 1);
1125  Oid atttype = att_tup->atttypid;
1126  int32 atttypmod = att_tup->atttypmod;
1127  Node *expr = NULL;
1128  Oid exprtype;
1129 
1130  if (att_tup->attidentity)
1131  {
1133 
1134  nve->seqid = getIdentitySequence(RelationGetRelid(rel), attrno, false);
1135  nve->typeId = att_tup->atttypid;
1136 
1137  return (Node *) nve;
1138  }
1139 
1140  /*
1141  * Scan to see if relation has a default for this column.
1142  */
1143  if (att_tup->atthasdef && rd_att->constr &&
1144  rd_att->constr->num_defval > 0)
1145  {
1146  AttrDefault *defval = rd_att->constr->defval;
1147  int ndef = rd_att->constr->num_defval;
1148 
1149  while (--ndef >= 0)
1150  {
1151  if (attrno == defval[ndef].adnum)
1152  {
1153  /*
1154  * Found it, convert string representation to node tree.
1155  */
1156  expr = stringToNode(defval[ndef].adbin);
1157  break;
1158  }
1159  }
1160  }
1161 
1162  /*
1163  * No per-column default, so look for a default for the type itself. But
1164  * not for generated columns.
1165  */
1166  if (expr == NULL && !att_tup->attgenerated)
1167  expr = get_typdefault(atttype);
1168 
1169  if (expr == NULL)
1170  return NULL; /* No default anywhere */
1171 
1172  /*
1173  * Make sure the value is coerced to the target column type; this will
1174  * generally be true already, but there seem to be some corner cases
1175  * involving domain defaults where it might not be true. This should match
1176  * the parser's processing of non-defaulted expressions --- see
1177  * transformAssignedExpr().
1178  */
1179  exprtype = exprType(expr);
1180 
1181  expr = coerce_to_target_type(NULL, /* no UNKNOWN params here */
1182  expr, exprtype,
1183  atttype, atttypmod,
1186  -1);
1187  if (expr == NULL)
1188  ereport(ERROR,
1189  (errcode(ERRCODE_DATATYPE_MISMATCH),
1190  errmsg("column \"%s\" is of type %s"
1191  " but default expression is of type %s",
1192  NameStr(att_tup->attname),
1193  format_type_be(atttype),
1194  format_type_be(exprtype)),
1195  errhint("You will need to rewrite or cast the expression.")));
1196 
1197  return expr;
1198 }
int errhint(const char *fmt,...)
Definition: elog.c:1069
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
Definition: nodes.h:525
int errcode(int sqlerrcode)
Definition: elog.c:608
void * stringToNode(const char *str)
Definition: read.c:89
char * format_type_be(Oid type_oid)
Definition: format_type.c:326
unsigned int Oid
Definition: postgres_ext.h:31
Oid getIdentitySequence(Oid relid, AttrNumber attnum, bool missing_ok)
Definition: pg_depend.c:780
signed int int32
Definition: c.h:347
AttrDefault * defval
Definition: tupdesc.h:39
#define ERROR
Definition: elog.h:43
Node * coerce_to_target_type(ParseState *pstate, Node *expr, Oid exprtype, Oid targettype, int32 targettypmod, CoercionContext ccontext, CoercionForm cformat, int location)
Definition: parse_coerce.c:78
TupleConstr * constr
Definition: tupdesc.h:85
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:200
#define ereport(elevel, rest)
Definition: elog.h:141
TupleDesc rd_att
Definition: rel.h:84
#define makeNode(_type_)
Definition: nodes.h:573
Node * get_typdefault(Oid typid)
Definition: lsyscache.c:2226
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:41
uint16 num_defval
Definition: tupdesc.h:42
int errmsg(const char *fmt,...)
Definition: elog.c:822
#define NameStr(name)
Definition: c.h:616
#define RelationGetRelid(relation)
Definition: rel.h:422

◆ get_view_query()

Query* get_view_query ( Relation  view)

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

2296 {
2297  int i;
2298 
2299  Assert(view->rd_rel->relkind == RELKIND_VIEW);
2300 
2301  for (i = 0; i < view->rd_rules->numLocks; i++)
2302  {
2303  RewriteRule *rule = view->rd_rules->rules[i];
2304 
2305  if (rule->event == CMD_SELECT)
2306  {
2307  /* A _RETURN rule should have only one action */
2308  if (list_length(rule->actions) != 1)
2309  elog(ERROR, "invalid _RETURN rule action specification");
2310 
2311  return (Query *) linitial(rule->actions);
2312  }
2313  }
2314 
2315  elog(ERROR, "failed to find _RETURN rule for view");
2316  return NULL; /* keep compiler quiet */
2317 }
int numLocks
Definition: prs2lock.h:42
Form_pg_class rd_rel
Definition: rel.h:83
Definition: localtime.c:79
#define linitial(l)
Definition: pg_list.h:195
#define ERROR
Definition: elog.h:43
CmdType event
Definition: prs2lock.h:27
RewriteRule ** rules
Definition: prs2lock.h:43
List * actions
Definition: prs2lock.h:29
#define Assert(condition)
Definition: c.h:739
RuleLock * rd_rules
Definition: rel.h:87
static int list_length(const List *l)
Definition: pg_list.h:169
#define elog(elevel,...)
Definition: elog.h:228
int i

◆ QueryRewrite()

List* QueryRewrite ( Query parsetree)

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

3874 {
3875  uint64 input_query_id = parsetree->queryId;
3876  List *querylist;
3877  List *results;
3878  ListCell *l;
3879  CmdType origCmdType;
3880  bool foundOriginalQuery;
3881  Query *lastInstead;
3882 
3883  /*
3884  * This function is only applied to top-level original queries
3885  */
3886  Assert(parsetree->querySource == QSRC_ORIGINAL);
3887  Assert(parsetree->canSetTag);
3888 
3889  /*
3890  * Step 1
3891  *
3892  * Apply all non-SELECT rules possibly getting 0 or many queries
3893  */
3894  querylist = RewriteQuery(parsetree, NIL);
3895 
3896  /*
3897  * Step 2
3898  *
3899  * Apply all the RIR rules on each query
3900  *
3901  * This is also a handy place to mark each query with the original queryId
3902  */
3903  results = NIL;
3904  foreach(l, querylist)
3905  {
3906  Query *query = (Query *) lfirst(l);
3907 
3908  query = fireRIRrules(query, NIL);
3909 
3910  query->queryId = input_query_id;
3911 
3912  results = lappend(results, query);
3913  }
3914 
3915  /*
3916  * Step 3
3917  *
3918  * Determine which, if any, of the resulting queries is supposed to set
3919  * the command-result tag; and update the canSetTag fields accordingly.
3920  *
3921  * If the original query is still in the list, it sets the command tag.
3922  * Otherwise, the last INSTEAD query of the same kind as the original is
3923  * allowed to set the tag. (Note these rules can leave us with no query
3924  * setting the tag. The tcop code has to cope with this by setting up a
3925  * default tag based on the original un-rewritten query.)
3926  *
3927  * The Asserts verify that at most one query in the result list is marked
3928  * canSetTag. If we aren't checking asserts, we can fall out of the loop
3929  * as soon as we find the original query.
3930  */
3931  origCmdType = parsetree->commandType;
3932  foundOriginalQuery = false;
3933  lastInstead = NULL;
3934 
3935  foreach(l, results)
3936  {
3937  Query *query = (Query *) lfirst(l);
3938 
3939  if (query->querySource == QSRC_ORIGINAL)
3940  {
3941  Assert(query->canSetTag);
3942  Assert(!foundOriginalQuery);
3943  foundOriginalQuery = true;
3944 #ifndef USE_ASSERT_CHECKING
3945  break;
3946 #endif
3947  }
3948  else
3949  {
3950  Assert(!query->canSetTag);
3951  if (query->commandType == origCmdType &&
3952  (query->querySource == QSRC_INSTEAD_RULE ||
3954  lastInstead = query;
3955  }
3956  }
3957 
3958  if (!foundOriginalQuery && lastInstead != NULL)
3959  lastInstead->canSetTag = true;
3960 
3961  return results;
3962 }
#define NIL
Definition: pg_list.h:65
static List * RewriteQuery(Query *parsetree, List *rewrite_events)
List * lappend(List *list, void *datum)
Definition: list.c:322
uint64 queryId
Definition: parsenodes.h:116
CmdType commandType
Definition: parsenodes.h:112
QuerySource querySource
Definition: parsenodes.h:114
#define Assert(condition)
Definition: c.h:739
#define lfirst(lc)
Definition: pg_list.h:190
bool canSetTag
Definition: parsenodes.h:118
static Query * fireRIRrules(Query *parsetree, List *activeRIRs)
Definition: pg_list.h:50
CmdType
Definition: nodes.h:668

◆ relation_is_updatable()

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

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

2649 {
2650  int events = 0;
2651  Relation rel;
2652  RuleLock *rulelocks;
2653 
2654 #define ALL_EVENTS ((1 << CMD_INSERT) | (1 << CMD_UPDATE) | (1 << CMD_DELETE))
2655 
2656  /* Since this function recurses, it could be driven to stack overflow */
2658 
2659  rel = try_relation_open(reloid, AccessShareLock);
2660 
2661  /*
2662  * If the relation doesn't exist, return zero rather than throwing an
2663  * error. This is helpful since scanning an information_schema view under
2664  * MVCC rules can result in referencing rels that have actually been
2665  * deleted already.
2666  */
2667  if (rel == NULL)
2668  return 0;
2669 
2670  /* If we detect a recursive view, report that it is not updatable */
2671  if (list_member_oid(outer_reloids, RelationGetRelid(rel)))
2672  {
2674  return 0;
2675  }
2676 
2677  /* If the relation is a table, it is always updatable */
2678  if (rel->rd_rel->relkind == RELKIND_RELATION ||
2679  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
2680  {
2682  return ALL_EVENTS;
2683  }
2684 
2685  /* Look for unconditional DO INSTEAD rules, and note supported events */
2686  rulelocks = rel->rd_rules;
2687  if (rulelocks != NULL)
2688  {
2689  int i;
2690 
2691  for (i = 0; i < rulelocks->numLocks; i++)
2692  {
2693  if (rulelocks->rules[i]->isInstead &&
2694  rulelocks->rules[i]->qual == NULL)
2695  {
2696  events |= ((1 << rulelocks->rules[i]->event) & ALL_EVENTS);
2697  }
2698  }
2699 
2700  /* If we have rules for all events, we're done */
2701  if (events == ALL_EVENTS)
2702  {
2704  return events;
2705  }
2706  }
2707 
2708  /* Similarly look for INSTEAD OF triggers, if they are to be included */
2709  if (include_triggers)
2710  {
2711  TriggerDesc *trigDesc = rel->trigdesc;
2712 
2713  if (trigDesc)
2714  {
2715  if (trigDesc->trig_insert_instead_row)
2716  events |= (1 << CMD_INSERT);
2717  if (trigDesc->trig_update_instead_row)
2718  events |= (1 << CMD_UPDATE);
2719  if (trigDesc->trig_delete_instead_row)
2720  events |= (1 << CMD_DELETE);
2721 
2722  /* If we have triggers for all events, we're done */
2723  if (events == ALL_EVENTS)
2724  {
2726  return events;
2727  }
2728  }
2729  }
2730 
2731  /* If this is a foreign table, check which update events it supports */
2732  if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
2733  {
2734  FdwRoutine *fdwroutine = GetFdwRoutineForRelation(rel, false);
2735 
2736  if (fdwroutine->IsForeignRelUpdatable != NULL)
2737  events |= fdwroutine->IsForeignRelUpdatable(rel);
2738  else
2739  {
2740  /* Assume presence of executor functions is sufficient */
2741  if (fdwroutine->ExecForeignInsert != NULL)
2742  events |= (1 << CMD_INSERT);
2743  if (fdwroutine->ExecForeignUpdate != NULL)
2744  events |= (1 << CMD_UPDATE);
2745  if (fdwroutine->ExecForeignDelete != NULL)
2746  events |= (1 << CMD_DELETE);
2747  }
2748 
2750  return events;
2751  }
2752 
2753  /* Check if this is an automatically updatable view */
2754  if (rel->rd_rel->relkind == RELKIND_VIEW)
2755  {
2756  Query *viewquery = get_view_query(rel);
2757 
2758  if (view_query_is_auto_updatable(viewquery, false) == NULL)
2759  {
2760  Bitmapset *updatable_cols;
2761  int auto_events;
2762  RangeTblRef *rtr;
2763  RangeTblEntry *base_rte;
2764  Oid baseoid;
2765 
2766  /*
2767  * Determine which of the view's columns are updatable. If there
2768  * are none within the set of columns we are looking at, then the
2769  * view doesn't support INSERT/UPDATE, but it may still support
2770  * DELETE.
2771  */
2772  view_cols_are_auto_updatable(viewquery, NULL,
2773  &updatable_cols, NULL);
2774 
2775  if (include_cols != NULL)
2776  updatable_cols = bms_int_members(updatable_cols, include_cols);
2777 
2778  if (bms_is_empty(updatable_cols))
2779  auto_events = (1 << CMD_DELETE); /* May support DELETE */
2780  else
2781  auto_events = ALL_EVENTS; /* May support all events */
2782 
2783  /*
2784  * The base relation must also support these update commands.
2785  * Tables are always updatable, but for any other kind of base
2786  * relation we must do a recursive check limited to the columns
2787  * referenced by the locally updatable columns in this view.
2788  */
2789  rtr = (RangeTblRef *) linitial(viewquery->jointree->fromlist);
2790  base_rte = rt_fetch(rtr->rtindex, viewquery->rtable);
2791  Assert(base_rte->rtekind == RTE_RELATION);
2792 
2793  if (base_rte->relkind != RELKIND_RELATION &&
2794  base_rte->relkind != RELKIND_PARTITIONED_TABLE)
2795  {
2796  baseoid = base_rte->relid;
2797  outer_reloids = lappend_oid(outer_reloids,
2798  RelationGetRelid(rel));
2799  include_cols = adjust_view_column_set(updatable_cols,
2800  viewquery->targetList);
2801  auto_events &= relation_is_updatable(baseoid,
2802  outer_reloids,
2803  include_triggers,
2804  include_cols);
2805  outer_reloids = list_delete_last(outer_reloids);
2806  }
2807  events |= auto_events;
2808  }
2809  }
2810 
2811  /* If we reach here, the relation may support some update commands */
2813  return events;
2814 }
ExecForeignDelete_function ExecForeignDelete
Definition: fdwapi.h:213
Node * qual
Definition: prs2lock.h:28
int numLocks
Definition: prs2lock.h:42
FromExpr * jointree
Definition: parsenodes.h:138
ExecForeignInsert_function ExecForeignInsert
Definition: fdwapi.h:211
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:1496
Form_pg_class rd_rel
Definition: rel.h:83
unsigned int Oid
Definition: postgres_ext.h:31
List * lappend_oid(List *list, Oid datum)
Definition: list.c:358
bool isInstead
Definition: prs2lock.h:31
Relation try_relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:89
List * targetList
Definition: parsenodes.h:140
bool trig_insert_instead_row
Definition: reltrigger.h:57
#define linitial(l)
Definition: pg_list.h:195
List * rtable
Definition: parsenodes.h:137
#define ALL_EVENTS
TriggerDesc * trigdesc
Definition: rel.h:89
void check_stack_depth(void)
Definition: postgres.c:3302
CmdType event
Definition: prs2lock.h:27
List * list_delete_last(List *list)
Definition: list.c:878
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:62
bool bms_is_empty(const Bitmapset *a)
Definition: bitmapset.c:701
bool trig_delete_instead_row
Definition: reltrigger.h:67
static Bitmapset * adjust_view_column_set(Bitmapset *cols, List *targetlist)
ExecForeignUpdate_function ExecForeignUpdate
Definition: fdwapi.h:212
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:675
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
#define Assert(condition)
Definition: c.h:739
RuleLock * rd_rules
Definition: rel.h:87
RTEKind rtekind
Definition: parsenodes.h:974
FdwRoutine * GetFdwRoutineForRelation(Relation relation, bool makecopy)
Definition: foreign.c:427
Query * get_view_query(Relation view)
int i
IsForeignRelUpdatable_function IsForeignRelUpdatable
Definition: fdwapi.h:217
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:422

◆ rewriteTargetListUD()

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

Definition at line 1444 of file rewriteHandler.c.

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

Referenced by preprocess_targetlist().

1446 {
1447  Var *var = NULL;
1448  const char *attrname;
1449  TargetEntry *tle;
1450 
1451  if (target_relation->rd_rel->relkind == RELKIND_RELATION ||
1452  target_relation->rd_rel->relkind == RELKIND_MATVIEW ||
1453  target_relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1454  {
1455  /*
1456  * Emit CTID so that executor can find the row to update or delete.
1457  */
1458  var = makeVar(parsetree->resultRelation,
1460  TIDOID,
1461  -1,
1462  InvalidOid,
1463  0);
1464 
1465  attrname = "ctid";
1466  }
1467  else if (target_relation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
1468  {
1469  /*
1470  * Let the foreign table's FDW add whatever junk TLEs it wants.
1471  */
1472  FdwRoutine *fdwroutine;
1473 
1474  fdwroutine = GetFdwRoutineForRelation(target_relation, false);
1475 
1476  if (fdwroutine->AddForeignUpdateTargets != NULL)
1477  fdwroutine->AddForeignUpdateTargets(parsetree, target_rte,
1478  target_relation);
1479 
1480  /*
1481  * If we have a row-level trigger corresponding to the operation, emit
1482  * a whole-row Var so that executor will have the "old" row to pass to
1483  * the trigger. Alas, this misses system columns.
1484  */
1485  if (target_relation->trigdesc &&
1486  ((parsetree->commandType == CMD_UPDATE &&
1487  (target_relation->trigdesc->trig_update_after_row ||
1488  target_relation->trigdesc->trig_update_before_row)) ||
1489  (parsetree->commandType == CMD_DELETE &&
1490  (target_relation->trigdesc->trig_delete_after_row ||
1491  target_relation->trigdesc->trig_delete_before_row))))
1492  {
1493  var = makeWholeRowVar(target_rte,
1494  parsetree->resultRelation,
1495  0,
1496  false);
1497 
1498  attrname = "wholerow";
1499  }
1500  }
1501 
1502  if (var != NULL)
1503  {
1504  tle = makeTargetEntry((Expr *) var,
1505  list_length(parsetree->targetList) + 1,
1506  pstrdup(attrname),
1507  true);
1508 
1509  parsetree->targetList = lappend(parsetree->targetList, tle);
1510  }
1511 }
char * pstrdup(const char *in)
Definition: mcxt.c:1186
int resultRelation
Definition: parsenodes.h:122
Var * makeWholeRowVar(RangeTblEntry *rte, Index varno, Index varlevelsup, bool allowScalar)
Definition: makefuncs.c:133
Form_pg_class rd_rel
Definition: rel.h:83
Definition: primnodes.h:167
AddForeignUpdateTargets_function AddForeignUpdateTargets
Definition: fdwapi.h:208
List * targetList
Definition: parsenodes.h:140
TriggerDesc * trigdesc
Definition: rel.h:89
bool trig_delete_after_row
Definition: reltrigger.h:66
bool trig_update_before_row
Definition: reltrigger.h:60
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:236
Var * makeVar(Index varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:66
bool trig_update_after_row
Definition: reltrigger.h:61
List * lappend(List *list, void *datum)
Definition: list.c:322
#define InvalidOid
Definition: postgres_ext.h:36
CmdType commandType
Definition: parsenodes.h:112
static int list_length(const List *l)
Definition: pg_list.h:169
FdwRoutine * GetFdwRoutineForRelation(Relation relation, bool makecopy)
Definition: foreign.c:427
#define SelfItemPointerAttributeNumber
Definition: sysattr.h:21
bool trig_delete_before_row
Definition: reltrigger.h:65

◆ view_query_is_auto_updatable()

const char* view_query_is_auto_updatable ( Query viewquery,
bool  check_cols 
)

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

2415 {
2416  RangeTblRef *rtr;
2417  RangeTblEntry *base_rte;
2418 
2419  /*----------
2420  * Check if the view is simply updatable. According to SQL-92 this means:
2421  * - No DISTINCT clause.
2422  * - Each TLE is a column reference, and each column appears at most once.
2423  * - FROM contains exactly one base relation.
2424  * - No GROUP BY or HAVING clauses.
2425  * - No set operations (UNION, INTERSECT or EXCEPT).
2426  * - No sub-queries in the WHERE clause that reference the target table.
2427  *
2428  * We ignore that last restriction since it would be complex to enforce
2429  * and there isn't any actual benefit to disallowing sub-queries. (The
2430  * semantic issues that the standard is presumably concerned about don't
2431  * arise in Postgres, since any such sub-query will not see any updates
2432  * executed by the outer query anyway, thanks to MVCC snapshotting.)
2433  *
2434  * We also relax the second restriction by supporting part of SQL:1999
2435  * feature T111, which allows for a mix of updatable and non-updatable
2436  * columns, provided that an INSERT or UPDATE doesn't attempt to assign to
2437  * a non-updatable column.
2438  *
2439  * In addition we impose these constraints, involving features that are
2440  * not part of SQL-92:
2441  * - No CTEs (WITH clauses).
2442  * - No OFFSET or LIMIT clauses (this matches a SQL:2008 restriction).
2443  * - No system columns (including whole-row references) in the tlist.
2444  * - No window functions in the tlist.
2445  * - No set-returning functions in the tlist.
2446  *
2447  * Note that we do these checks without recursively expanding the view.
2448  * If the base relation is a view, we'll recursively deal with it later.
2449  *----------
2450  */
2451  if (viewquery->distinctClause != NIL)
2452  return gettext_noop("Views containing DISTINCT are not automatically updatable.");
2453 
2454  if (viewquery->groupClause != NIL || viewquery->groupingSets)
2455  return gettext_noop("Views containing GROUP BY are not automatically updatable.");
2456 
2457  if (viewquery->havingQual != NULL)
2458  return gettext_noop("Views containing HAVING are not automatically updatable.");
2459 
2460  if (viewquery->setOperations != NULL)
2461  return gettext_noop("Views containing UNION, INTERSECT, or EXCEPT are not automatically updatable.");
2462 
2463  if (viewquery->cteList != NIL)
2464  return gettext_noop("Views containing WITH are not automatically updatable.");
2465 
2466  if (viewquery->limitOffset != NULL || viewquery->limitCount != NULL)
2467  return gettext_noop("Views containing LIMIT or OFFSET are not automatically updatable.");
2468 
2469  /*
2470  * We must not allow window functions or set returning functions in the
2471  * targetlist. Otherwise we might end up inserting them into the quals of
2472  * the main query. We must also check for aggregates in the targetlist in
2473  * case they appear without a GROUP BY.
2474  *
2475  * These restrictions ensure that each row of the view corresponds to a
2476  * unique row in the underlying base relation.
2477  */
2478  if (viewquery->hasAggs)
2479  return gettext_noop("Views that return aggregate functions are not automatically updatable.");
2480 
2481  if (viewquery->hasWindowFuncs)
2482  return gettext_noop("Views that return window functions are not automatically updatable.");
2483 
2484  if (viewquery->hasTargetSRFs)
2485  return gettext_noop("Views that return set-returning functions are not automatically updatable.");
2486 
2487  /*
2488  * The view query should select from a single base relation, which must be
2489  * a table or another view.
2490  */
2491  if (list_length(viewquery->jointree->fromlist) != 1)
2492  return gettext_noop("Views that do not select from a single table or view are not automatically updatable.");
2493 
2494  rtr = (RangeTblRef *) linitial(viewquery->jointree->fromlist);
2495  if (!IsA(rtr, RangeTblRef))
2496  return gettext_noop("Views that do not select from a single table or view are not automatically updatable.");
2497 
2498  base_rte = rt_fetch(rtr->rtindex, viewquery->rtable);
2499  if (base_rte->rtekind != RTE_RELATION ||
2500  (base_rte->relkind != RELKIND_RELATION &&
2501  base_rte->relkind != RELKIND_FOREIGN_TABLE &&
2502  base_rte->relkind != RELKIND_VIEW &&
2503  base_rte->relkind != RELKIND_PARTITIONED_TABLE))
2504  return gettext_noop("Views that do not select from a single table or view are not automatically updatable.");
2505 
2506  if (base_rte->tablesample)
2507  return gettext_noop("Views containing TABLESAMPLE are not automatically updatable.");
2508 
2509  /*
2510  * Check that the view has at least one updatable column. This is required
2511  * for INSERT/UPDATE but not for DELETE.
2512  */
2513  if (check_cols)
2514  {
2515  ListCell *cell;
2516  bool found;
2517 
2518  found = false;
2519  foreach(cell, viewquery->targetList)
2520  {
2521  TargetEntry *tle = (TargetEntry *) lfirst(cell);
2522 
2523  if (view_col_is_auto_updatable(rtr, tle) == NULL)
2524  {
2525  found = true;
2526  break;
2527  }
2528  }
2529 
2530  if (!found)
2531  return gettext_noop("Views that have no updatable columns are not automatically updatable.");
2532  }
2533 
2534  return NULL; /* the view is updatable */
2535 }
Node * limitOffset
Definition: parsenodes.h:160
#define NIL
Definition: pg_list.h:65
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
FromExpr * jointree
Definition: parsenodes.h:138
bool hasAggs
Definition: parsenodes.h:125
List * groupingSets
Definition: parsenodes.h:150
#define gettext_noop(x)
Definition: c.h:1148
List * fromlist
Definition: primnodes.h:1496
List * targetList
Definition: parsenodes.h:140
#define linitial(l)
Definition: pg_list.h:195
List * rtable
Definition: parsenodes.h:137
List * distinctClause
Definition: parsenodes.h:156
Node * limitCount
Definition: parsenodes.h:161
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
bool hasTargetSRFs
Definition: parsenodes.h:127
#define lfirst(lc)
Definition: pg_list.h:190
bool hasWindowFuncs
Definition: parsenodes.h:126
static int list_length(const List *l)
Definition: pg_list.h:169
RTEKind rtekind
Definition: parsenodes.h:974
List * cteList
Definition: parsenodes.h:135
Node * setOperations
Definition: parsenodes.h:165
List * groupClause
Definition: parsenodes.h:148
static const char * view_col_is_auto_updatable(RangeTblRef *rtr, TargetEntry *tle)
Node * havingQual
Definition: parsenodes.h:152
struct TableSampleClause * tablesample
Definition: parsenodes.h:1004