PostgreSQL Source Code  git master
rewriteHandler.c File Reference
Include dependency graph for rewriteHandler.c:

Go to the source code of this file.

Data Structures

struct  rewrite_event
 
struct  acquireLocksOnSubLinks_context
 

Macros

#define ALL_EVENTS   ((1 << CMD_INSERT) | (1 << CMD_UPDATE) | (1 << CMD_DELETE))
 

Typedefs

typedef struct rewrite_event rewrite_event
 
typedef struct acquireLocksOnSubLinks_context acquireLocksOnSubLinks_context
 

Functions

static bool acquireLocksOnSubLinks (Node *node, acquireLocksOnSubLinks_context *context)
 
static QueryrewriteRuleAction (Query *parsetree, Query *rule_action, Node *rule_qual, int rt_index, CmdType event, bool *returning_flag)
 
static ListadjustJoinTreeList (Query *parsetree, bool removert, int rt_index)
 
static ListrewriteTargetListIU (List *targetList, CmdType commandType, OverridingKind override, Relation target_relation, RangeTblEntry *values_rte, int values_rte_index, Bitmapset **unused_values_attrnos)
 
static TargetEntryprocess_matched_tle (TargetEntry *src_tle, TargetEntry *prior_tle, const char *attrName)
 
static Nodeget_assignment_input (Node *node)
 
static BitmapsetfindDefaultOnlyColumns (RangeTblEntry *rte)
 
static bool rewriteValuesRTE (Query *parsetree, RangeTblEntry *rte, int rti, Relation target_relation, Bitmapset *unused_cols)
 
static void rewriteValuesRTEToNulls (Query *parsetree, RangeTblEntry *rte)
 
static void markQueryForLocking (Query *qry, Node *jtnode, LockClauseStrength strength, LockWaitPolicy waitPolicy, bool pushedDown)
 
static ListmatchLocks (CmdType event, Relation relation, int varno, Query *parsetree, bool *hasUpdate)
 
static QueryfireRIRrules (Query *parsetree, List *activeRIRs)
 
static Bitmapsetadjust_view_column_set (Bitmapset *cols, List *targetlist)
 
void AcquireRewriteLocks (Query *parsetree, bool forExecute, bool forUpdatePushedDown)
 
Nodebuild_column_default (Relation rel, int attrno)
 
static bool searchForDefault (RangeTblEntry *rte)
 
static QueryApplyRetrieveRule (Query *parsetree, RewriteRule *rule, int rt_index, Relation relation, List *activeRIRs)
 
static bool fireRIRonSubLink (Node *node, List *activeRIRs)
 
static QueryCopyAndAddInvertedQual (Query *parsetree, Node *rule_qual, int rt_index, CmdType event)
 
static ListfireRules (Query *parsetree, int rt_index, CmdType event, List *locks, bool *instead_flag, bool *returning_flag, Query **qual_product)
 
Queryget_view_query (Relation view)
 
bool view_has_instead_trigger (Relation view, CmdType event, List *mergeActionList)
 
static const char * view_col_is_auto_updatable (RangeTblRef *rtr, TargetEntry *tle)
 
const char * view_query_is_auto_updatable (Query *viewquery, bool check_cols)
 
static const char * view_cols_are_auto_updatable (Query *viewquery, Bitmapset *required_cols, Bitmapset **updatable_cols, char **non_updatable_col)
 
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)
 
static QueryrewriteTargetView (Query *parsetree, Relation view)
 
static ListRewriteQuery (Query *parsetree, List *rewrite_events, int orig_rt_length)
 
ListQueryRewrite (Query *parsetree)
 

Macro Definition Documentation

◆ ALL_EVENTS

#define ALL_EVENTS   ((1 << CMD_INSERT) | (1 << CMD_UPDATE) | (1 << CMD_DELETE))

Typedef Documentation

◆ acquireLocksOnSubLinks_context

◆ rewrite_event

typedef struct rewrite_event rewrite_event

Function Documentation

◆ acquireLocksOnSubLinks()

static bool acquireLocksOnSubLinks ( Node node,
acquireLocksOnSubLinks_context context 
)
static

Definition at line 302 of file rewriteHandler.c.

303 {
304  if (node == NULL)
305  return false;
306  if (IsA(node, SubLink))
307  {
308  SubLink *sub = (SubLink *) node;
309 
310  /* Do what we came for */
312  context->for_execute,
313  false);
314  /* Fall through to process lefthand args of SubLink */
315  }
316 
317  /*
318  * Do NOT recurse into Query nodes, because AcquireRewriteLocks already
319  * processed subselects of subselects for us.
320  */
322 }
#define expression_tree_walker(n, w, c)
Definition: nodeFuncs.h:153
#define IsA(nodeptr, _type_)
Definition: nodes.h:158
tree context
Definition: radixtree.h:1835
void AcquireRewriteLocks(Query *parsetree, bool forExecute, bool forUpdatePushedDown)
static bool acquireLocksOnSubLinks(Node *node, acquireLocksOnSubLinks_context *context)

References AcquireRewriteLocks(), context, expression_tree_walker, IsA, and SubLink::subselect.

Referenced by AcquireRewriteLocks(), CopyAndAddInvertedQual(), fireRIRrules(), rewriteRuleAction(), and rewriteTargetView().

◆ 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)
296 }
#define Assert(condition)
Definition: c.h:858
unsigned int Index
Definition: c.h:614
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
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:700
#define query_tree_walker(q, w, c, f)
Definition: nodeFuncs.h:158
#define QTW_IGNORE_RC_SUBQUERIES
Definition: nodeFuncs.h:24
RowMarkClause * get_parse_rowmark(Query *qry, Index rtindex)
bool get_rte_attribute_is_dropped(RangeTblEntry *rte, AttrNumber attnum)
@ RTE_JOIN
Definition: parsenodes.h:1019
@ RTE_SUBQUERY
Definition: parsenodes.h:1018
@ RTE_RELATION
Definition: parsenodes.h:1017
#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
Definition: pg_list.h:54
Definition: nodes.h:129
List * cteList
Definition: parsenodes.h:168
List * rtable
Definition: parsenodes.h:170
Query * subquery
Definition: parsenodes.h:1104
RTEKind rtekind
Definition: parsenodes.h:1047
Form_pg_class rd_rel
Definition: rel.h:111
Definition: primnodes.h:248
AttrNumber varattno
Definition: primnodes.h:260
int varno
Definition: primnodes.h:255
Index varlevelsup
Definition: primnodes.h:280
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, context, Query::cteList, CommonTableExpr::ctequery, elog, ERROR, get_parse_rowmark(), get_rte_attribute_is_dropped(), IsA, lappend(), lfirst, NIL, NoLock, QTW_IGNORE_RC_SUBQUERIES, query_tree_walker, RelationData::rd_rel, RangeTblEntry::relid, 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().

◆ adjust_view_column_set()

static Bitmapset * adjust_view_column_set ( Bitmapset cols,
List targetlist 
)
static

Definition at line 3002 of file rewriteHandler.c.

3003 {
3004  Bitmapset *result = NULL;
3005  int col;
3006 
3007  col = -1;
3008  while ((col = bms_next_member(cols, col)) >= 0)
3009  {
3010  /* bit numbers are offset by FirstLowInvalidHeapAttributeNumber */
3012 
3013  if (attno == InvalidAttrNumber)
3014  {
3015  /*
3016  * There's a whole-row reference to the view. For permissions
3017  * purposes, treat it as a reference to each column available from
3018  * the view. (We should *not* convert this to a whole-row
3019  * reference to the base relation, since the view may not touch
3020  * all columns of the base relation.)
3021  */
3022  ListCell *lc;
3023 
3024  foreach(lc, targetlist)
3025  {
3026  TargetEntry *tle = lfirst_node(TargetEntry, lc);
3027  Var *var;
3028 
3029  if (tle->resjunk)
3030  continue;
3031  var = castNode(Var, tle->expr);
3032  result = bms_add_member(result,
3034  }
3035  }
3036  else
3037  {
3038  /*
3039  * Views do not have system columns, so we do not expect to see
3040  * any other system attnos here. If we do find one, the error
3041  * case will apply.
3042  */
3043  TargetEntry *tle = get_tle_by_resno(targetlist, attno);
3044 
3045  if (tle != NULL && !tle->resjunk && IsA(tle->expr, Var))
3046  {
3047  Var *var = (Var *) tle->expr;
3048 
3049  result = bms_add_member(result,
3051  }
3052  else
3053  elog(ERROR, "attribute number %d not found in view targetlist",
3054  attno);
3055  }
3056  }
3057 
3058  return result;
3059 }
int16 AttrNumber
Definition: attnum.h:21
#define InvalidAttrNumber
Definition: attnum.h:23
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1306
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:815
#define castNode(_type_, nodeptr)
Definition: nodes.h:176
TargetEntry * get_tle_by_resno(List *tlist, AttrNumber resno)
#define lfirst_node(type, lc)
Definition: pg_list.h:176
Expr * expr
Definition: primnodes.h:2186
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27

References bms_add_member(), bms_next_member(), castNode, elog, ERROR, TargetEntry::expr, FirstLowInvalidHeapAttributeNumber, get_tle_by_resno(), InvalidAttrNumber, IsA, lfirst_node, and Var::varattno.

Referenced by relation_is_updatable(), and rewriteTargetView().

◆ adjustJoinTreeList()

static List * adjustJoinTreeList ( Query parsetree,
bool  removert,
int  rt_index 
)
static

Definition at line 696 of file rewriteHandler.c.

697 {
698  List *newjointree = copyObject(parsetree->jointree->fromlist);
699  ListCell *l;
700 
701  if (removert)
702  {
703  foreach(l, newjointree)
704  {
705  RangeTblRef *rtr = lfirst(l);
706 
707  if (IsA(rtr, RangeTblRef) &&
708  rtr->rtindex == rt_index)
709  {
710  newjointree = foreach_delete_current(newjointree, l);
711  break;
712  }
713  }
714  }
715  return newjointree;
716 }
#define copyObject(obj)
Definition: nodes.h:224
#define foreach_delete_current(lst, var_or_cell)
Definition: pg_list.h:391
List * fromlist
Definition: primnodes.h:2304
FromExpr * jointree
Definition: parsenodes.h:177

References copyObject, foreach_delete_current, FromExpr::fromlist, IsA, Query::jointree, lfirst, and RangeTblRef::rtindex.

Referenced by rewriteRuleAction().

◆ ApplyRetrieveRule()

static Query* ApplyRetrieveRule ( Query parsetree,
RewriteRule rule,
int  rt_index,
Relation  relation,
List activeRIRs 
)
static

Definition at line 1717 of file rewriteHandler.c.

1722 {
1723  Query *rule_action;
1724  RangeTblEntry *rte;
1725  RowMarkClause *rc;
1726  int numCols;
1727 
1728  if (list_length(rule->actions) != 1)
1729  elog(ERROR, "expected just one rule action");
1730  if (rule->qual != NULL)
1731  elog(ERROR, "cannot handle qualified ON SELECT rule");
1732 
1733  /* Check if the expansion of non-system views are restricted */
1735  RelationGetRelid(relation) >= FirstNormalObjectId))
1736  ereport(ERROR,
1737  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1738  errmsg("access to non-system view \"%s\" is restricted",
1739  RelationGetRelationName(relation))));
1740 
1741  if (rt_index == parsetree->resultRelation)
1742  {
1743  /*
1744  * We have a view as the result relation of the query, and it wasn't
1745  * rewritten by any rule. This case is supported if there is an
1746  * INSTEAD OF trigger that will trap attempts to insert/update/delete
1747  * view rows. The executor will check that; for the moment just plow
1748  * ahead. We have two cases:
1749  *
1750  * For INSERT, we needn't do anything. The unmodified RTE will serve
1751  * fine as the result relation.
1752  *
1753  * For UPDATE/DELETE/MERGE, we need to expand the view so as to have
1754  * source data for the operation. But we also need an unmodified RTE
1755  * to serve as the target. So, copy the RTE and add the copy to the
1756  * rangetable. Note that the copy does not get added to the jointree.
1757  * Also note that there's a hack in fireRIRrules to avoid calling this
1758  * function again when it arrives at the copied RTE.
1759  */
1760  if (parsetree->commandType == CMD_INSERT)
1761  return parsetree;
1762  else if (parsetree->commandType == CMD_UPDATE ||
1763  parsetree->commandType == CMD_DELETE ||
1764  parsetree->commandType == CMD_MERGE)
1765  {
1766  RangeTblEntry *newrte;
1767  Var *var;
1768  TargetEntry *tle;
1769 
1770  rte = rt_fetch(rt_index, parsetree->rtable);
1771  newrte = copyObject(rte);
1772  parsetree->rtable = lappend(parsetree->rtable, newrte);
1773  parsetree->resultRelation = list_length(parsetree->rtable);
1774  /* parsetree->mergeTargetRelation unchanged (use expanded view) */
1775 
1776  /*
1777  * For the most part, Vars referencing the view should remain as
1778  * they are, meaning that they implicitly represent OLD values.
1779  * But in the RETURNING list if any, we want such Vars to
1780  * represent NEW values, so change them to reference the new RTE.
1781  *
1782  * Since ChangeVarNodes scribbles on the tree in-place, copy the
1783  * RETURNING list first for safety.
1784  */
1785  parsetree->returningList = copyObject(parsetree->returningList);
1786  ChangeVarNodes((Node *) parsetree->returningList, rt_index,
1787  parsetree->resultRelation, 0);
1788 
1789  /*
1790  * To allow the executor to compute the original view row to pass
1791  * to the INSTEAD OF trigger, we add a resjunk whole-row Var
1792  * referencing the original RTE. This will later get expanded
1793  * into a RowExpr computing all the OLD values of the view row.
1794  */
1795  var = makeWholeRowVar(rte, rt_index, 0, false);
1796  tle = makeTargetEntry((Expr *) var,
1797  list_length(parsetree->targetList) + 1,
1798  pstrdup("wholerow"),
1799  true);
1800 
1801  parsetree->targetList = lappend(parsetree->targetList, tle);
1802 
1803  /* Now, continue with expanding the original view RTE */
1804  }
1805  else
1806  elog(ERROR, "unrecognized commandType: %d",
1807  (int) parsetree->commandType);
1808  }
1809 
1810  /*
1811  * Check if there's a FOR [KEY] UPDATE/SHARE clause applying to this view.
1812  *
1813  * Note: we needn't explicitly consider any such clauses appearing in
1814  * ancestor query levels; their effects have already been pushed down to
1815  * here by markQueryForLocking, and will be reflected in "rc".
1816  */
1817  rc = get_parse_rowmark(parsetree, rt_index);
1818 
1819  /*
1820  * Make a modifiable copy of the view query, and acquire needed locks on
1821  * the relations it mentions. Force at least RowShareLock for all such
1822  * rels if there's a FOR [KEY] UPDATE/SHARE clause affecting this view.
1823  */
1824  rule_action = copyObject(linitial(rule->actions));
1825 
1826  AcquireRewriteLocks(rule_action, true, (rc != NULL));
1827 
1828  /*
1829  * If FOR [KEY] UPDATE/SHARE of view, mark all the contained tables as
1830  * implicit FOR [KEY] UPDATE/SHARE, the same as the parser would have done
1831  * if the view's subquery had been written out explicitly.
1832  */
1833  if (rc != NULL)
1834  markQueryForLocking(rule_action, (Node *) rule_action->jointree,
1835  rc->strength, rc->waitPolicy, true);
1836 
1837  /*
1838  * Recursively expand any view references inside the view.
1839  */
1840  rule_action = fireRIRrules(rule_action, activeRIRs);
1841 
1842  /*
1843  * Now, plug the view query in as a subselect, converting the relation's
1844  * original RTE to a subquery RTE.
1845  */
1846  rte = rt_fetch(rt_index, parsetree->rtable);
1847 
1848  rte->rtekind = RTE_SUBQUERY;
1849  rte->subquery = rule_action;
1850  rte->security_barrier = RelationIsSecurityView(relation);
1851 
1852  /*
1853  * Clear fields that should not be set in a subquery RTE. Note that we
1854  * leave the relid, relkind, rellockmode, and perminfoindex fields set, so
1855  * that the view relation can be appropriately locked before execution and
1856  * its permissions checked.
1857  */
1858  rte->tablesample = NULL;
1859  rte->inh = false; /* must not be set for a subquery */
1860 
1861  /*
1862  * Since we allow CREATE OR REPLACE VIEW to add columns to a view, the
1863  * rule_action might emit more columns than we expected when the current
1864  * query was parsed. Various places expect rte->eref->colnames to be
1865  * consistent with the non-junk output columns of the subquery, so patch
1866  * things up if necessary by adding some dummy column names.
1867  */
1868  numCols = ExecCleanTargetListLength(rule_action->targetList);
1869  while (list_length(rte->eref->colnames) < numCols)
1870  {
1871  rte->eref->colnames = lappend(rte->eref->colnames,
1872  makeString(pstrdup("?column?")));
1873  }
1874 
1875  return parsetree;
1876 }
#define unlikely(x)
Definition: c.h:311
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ereport(elevel,...)
Definition: elog.h:149
int ExecCleanTargetListLength(List *targetlist)
Definition: execUtils.c:1119
Var * makeWholeRowVar(RangeTblEntry *rte, int varno, Index varlevelsup, bool allowScalar)
Definition: makefuncs.c:135
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:240
char * pstrdup(const char *in)
Definition: mcxt.c:1696
@ CMD_MERGE
Definition: nodes.h:269
@ CMD_INSERT
Definition: nodes.h:267
@ CMD_DELETE
Definition: nodes.h:268
@ CMD_UPDATE
Definition: nodes.h:266
static int list_length(const List *l)
Definition: pg_list.h:152
#define linitial(l)
Definition: pg_list.h:178
int restrict_nonsystem_relation_kind
Definition: postgres.c:108
#define RelationGetRelid(relation)
Definition: rel.h:505
#define RelationGetRelationName(relation)
Definition: rel.h:539
#define RelationIsSecurityView(relation)
Definition: rel.h:426
static void markQueryForLocking(Query *qry, Node *jtnode, LockClauseStrength strength, LockWaitPolicy waitPolicy, bool pushedDown)
static Query * fireRIRrules(Query *parsetree, List *activeRIRs)
void ChangeVarNodes(Node *node, int rt_index, int new_index, int sublevels_up)
Definition: rewriteManip.c:674
List * returningList
Definition: parsenodes.h:200
CmdType commandType
Definition: parsenodes.h:121
List * targetList
Definition: parsenodes.h:193
struct TableSampleClause * tablesample
Definition: parsenodes.h:1098
LockClauseStrength strength
Definition: parsenodes.h:1579
LockWaitPolicy waitPolicy
Definition: parsenodes.h:1580
Definition: localtime.c:73
#define RESTRICT_RELKIND_VIEW
Definition: tcopprot.h:47
#define FirstNormalObjectId
Definition: transam.h:197
String * makeString(char *str)
Definition: value.c:63

References AcquireRewriteLocks(), ChangeVarNodes(), CMD_DELETE, CMD_INSERT, CMD_MERGE, CMD_UPDATE, Query::commandType, copyObject, elog, ereport, errcode(), errmsg(), ERROR, ExecCleanTargetListLength(), fireRIRrules(), FirstNormalObjectId, get_parse_rowmark(), RangeTblEntry::inh, Query::jointree, lappend(), linitial, list_length(), makeString(), makeTargetEntry(), makeWholeRowVar(), markQueryForLocking(), pstrdup(), RelationGetRelationName, RelationGetRelid, RelationIsSecurityView, restrict_nonsystem_relation_kind, RESTRICT_RELKIND_VIEW, Query::returningList, rt_fetch, Query::rtable, RTE_SUBQUERY, RangeTblEntry::rtekind, RowMarkClause::strength, RangeTblEntry::subquery, RangeTblEntry::tablesample, Query::targetList, unlikely, and RowMarkClause::waitPolicy.

Referenced by fireRIRrules().

◆ 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 
1237  nve->seqid = getIdentitySequence(rel, attrno, false);
1238  nve->typeId = att_tup->atttypid;
1239 
1240  return (Node *) nve;
1241  }
1242 
1243  /*
1244  * If relation has a default for this column, fetch that expression.
1245  */
1246  if (att_tup->atthasdef)
1247  {
1248  expr = TupleDescGetDefault(rd_att, attrno);
1249  if (expr == NULL)
1250  elog(ERROR, "default expression not found for attribute %d of relation \"%s\"",
1251  attrno, RelationGetRelationName(rel));
1252  }
1253 
1254  /*
1255  * No per-column default, so look for a default for the type itself. But
1256  * not for generated columns.
1257  */
1258  if (expr == NULL && !att_tup->attgenerated)
1259  expr = get_typdefault(atttype);
1260 
1261  if (expr == NULL)
1262  return NULL; /* No default anywhere */
1263 
1264  /*
1265  * Make sure the value is coerced to the target column type; this will
1266  * generally be true already, but there seem to be some corner cases
1267  * involving domain defaults where it might not be true. This should match
1268  * the parser's processing of non-defaulted expressions --- see
1269  * transformAssignedExpr().
1270  */
1271  exprtype = exprType(expr);
1272 
1273  expr = coerce_to_target_type(NULL, /* no UNKNOWN params here */
1274  expr, exprtype,
1275  atttype, atttypmod,
1278  -1);
1279  if (expr == NULL)
1280  ereport(ERROR,
1281  (errcode(ERRCODE_DATATYPE_MISMATCH),
1282  errmsg("column \"%s\" is of type %s"
1283  " but default expression is of type %s",
1284  NameStr(att_tup->attname),
1285  format_type_be(atttype),
1286  format_type_be(exprtype)),
1287  errhint("You will need to rewrite or cast the expression.")));
1288 
1289  return expr;
1290 }
#define NameStr(name)
Definition: c.h:746
signed int int32
Definition: c.h:494
int errhint(const char *fmt,...)
Definition: elog.c:1317
char * format_type_be(Oid type_oid)
Definition: format_type.c:343
Node * get_typdefault(Oid typid)
Definition: lsyscache.c:2448
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
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:209
Oid getIdentitySequence(Relation rel, AttrNumber attnum, bool missing_ok)
Definition: pg_depend.c:946
unsigned int Oid
Definition: postgres_ext.h:31
@ COERCE_IMPLICIT_CAST
Definition: primnodes.h:736
@ COERCION_ASSIGNMENT
Definition: primnodes.h:715
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_typdefault(), getIdentitySequence(), makeNode, NameStr, RelationData::rd_att, RelationGetRelationName, NextValueExpr::seqid, TupleDescAttr, TupleDescGetDefault(), and NextValueExpr::typeId.

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

◆ CopyAndAddInvertedQual()

static Query* CopyAndAddInvertedQual ( Query parsetree,
Node rule_qual,
int  rt_index,
CmdType  event 
)
static

Definition at line 2278 of file rewriteHandler.c.

2282 {
2283  /* Don't scribble on the passed qual (it's in the relcache!) */
2284  Node *new_qual = copyObject(rule_qual);
2286 
2287  context.for_execute = true;
2288 
2289  /*
2290  * In case there are subqueries in the qual, acquire necessary locks and
2291  * fix any deleted JOIN RTE entries. (This is somewhat redundant with
2292  * rewriteRuleAction, but not entirely ... consider restructuring so that
2293  * we only need to process the qual this way once.)
2294  */
2295  (void) acquireLocksOnSubLinks(new_qual, &context);
2296 
2297  /* Fix references to OLD */
2298  ChangeVarNodes(new_qual, PRS2_OLD_VARNO, rt_index, 0);
2299  /* Fix references to NEW */
2300  if (event == CMD_INSERT || event == CMD_UPDATE)
2301  new_qual = ReplaceVarsFromTargetList(new_qual,
2303  0,
2304  rt_fetch(rt_index,
2305  parsetree->rtable),
2306  parsetree->targetList,
2307  (event == CMD_UPDATE) ?
2310  rt_index,
2311  &parsetree->hasSubLinks);
2312  /* And attach the fixed qual */
2313  AddInvertedQual(parsetree, new_qual);
2314 
2315  return parsetree;
2316 }
#define PRS2_OLD_VARNO
Definition: primnodes.h:244
#define PRS2_NEW_VARNO
Definition: primnodes.h:245
Node * ReplaceVarsFromTargetList(Node *node, int target_varno, int sublevels_up, RangeTblEntry *target_rte, List *targetlist, ReplaceVarsNoMatchOption nomatch_option, int nomatch_varno, bool *outer_hasSubLinks)
void AddInvertedQual(Query *parsetree, Node *qual)
@ REPLACEVARS_SUBSTITUTE_NULL
Definition: rewriteManip.h:40
@ REPLACEVARS_CHANGE_VARNO
Definition: rewriteManip.h:39

References acquireLocksOnSubLinks(), AddInvertedQual(), ChangeVarNodes(), CMD_INSERT, CMD_UPDATE, context, copyObject, PRS2_NEW_VARNO, PRS2_OLD_VARNO, REPLACEVARS_CHANGE_VARNO, REPLACEVARS_SUBSTITUTE_NULL, ReplaceVarsFromTargetList(), rt_fetch, Query::rtable, and Query::targetList.

Referenced by fireRules().

◆ error_view_not_updatable()

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

Definition at line 3076 of file rewriteHandler.c.

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

◆ findDefaultOnlyColumns()

static Bitmapset * findDefaultOnlyColumns ( RangeTblEntry rte)
static

Definition at line 1321 of file rewriteHandler.c.

1322 {
1323  Bitmapset *default_only_cols = NULL;
1324  ListCell *lc;
1325 
1326  foreach(lc, rte->values_lists)
1327  {
1328  List *sublist = (List *) lfirst(lc);
1329  ListCell *lc2;
1330  int i;
1331 
1332  if (default_only_cols == NULL)
1333  {
1334  /* Populate the initial result bitmap from the first row */
1335  i = 0;
1336  foreach(lc2, sublist)
1337  {
1338  Node *col = (Node *) lfirst(lc2);
1339 
1340  i++;
1341  if (IsA(col, SetToDefault))
1342  default_only_cols = bms_add_member(default_only_cols, i);
1343  }
1344  }
1345  else
1346  {
1347  /* Update the result bitmap from this next row */
1348  i = 0;
1349  foreach(lc2, sublist)
1350  {
1351  Node *col = (Node *) lfirst(lc2);
1352 
1353  i++;
1354  if (!IsA(col, SetToDefault))
1355  default_only_cols = bms_del_member(default_only_cols, i);
1356  }
1357  }
1358 
1359  /*
1360  * If no column in the rows read so far contains only DEFAULT items,
1361  * we are done.
1362  */
1363  if (bms_is_empty(default_only_cols))
1364  break;
1365  }
1366 
1367  return default_only_cols;
1368 }
Bitmapset * bms_del_member(Bitmapset *a, int x)
Definition: bitmapset.c:868
#define bms_is_empty(a)
Definition: bitmapset.h:118
int i
Definition: isn.c:73
List * values_lists
Definition: parsenodes.h:1190

References bms_add_member(), bms_del_member(), bms_is_empty, i, IsA, lfirst, and RangeTblEntry::values_lists.

Referenced by rewriteTargetListIU().

◆ fireRIRonSubLink()

static bool fireRIRonSubLink ( Node node,
List activeRIRs 
)
static

Definition at line 1955 of file rewriteHandler.c.

1956 {
1957  if (node == NULL)
1958  return false;
1959  if (IsA(node, SubLink))
1960  {
1961  SubLink *sub = (SubLink *) node;
1962 
1963  /* Do what we came for */
1964  sub->subselect = (Node *) fireRIRrules((Query *) sub->subselect,
1965  activeRIRs);
1966  /* Fall through to process lefthand args of SubLink */
1967  }
1968 
1969  /*
1970  * Do NOT recurse into Query nodes, because fireRIRrules already processed
1971  * subselects of subselects for us.
1972  */
1974  (void *) activeRIRs);
1975 }
static bool fireRIRonSubLink(Node *node, List *activeRIRs)

References expression_tree_walker, fireRIRrules(), IsA, and SubLink::subselect.

Referenced by fireRIRrules().

◆ fireRIRrules()

static Query * fireRIRrules ( Query parsetree,
List activeRIRs 
)
static

Definition at line 1986 of file rewriteHandler.c.

1987 {
1988  int origResultRelation = parsetree->resultRelation;
1989  int rt_index;
1990  ListCell *lc;
1991 
1992  /*
1993  * Expand SEARCH and CYCLE clauses in CTEs.
1994  *
1995  * This is just a convenient place to do this, since we are already
1996  * looking at each Query.
1997  */
1998  foreach(lc, parsetree->cteList)
1999  {
2001 
2002  if (cte->search_clause || cte->cycle_clause)
2003  {
2004  cte = rewriteSearchAndCycle(cte);
2005  lfirst(lc) = cte;
2006  }
2007  }
2008 
2009  /*
2010  * don't try to convert this into a foreach loop, because rtable list can
2011  * get changed each time through...
2012  */
2013  rt_index = 0;
2014  while (rt_index < list_length(parsetree->rtable))
2015  {
2016  RangeTblEntry *rte;
2017  Relation rel;
2018  List *locks;
2019  RuleLock *rules;
2020  RewriteRule *rule;
2021  int i;
2022 
2023  ++rt_index;
2024 
2025  rte = rt_fetch(rt_index, parsetree->rtable);
2026 
2027  /*
2028  * A subquery RTE can't have associated rules, so there's nothing to
2029  * do to this level of the query, but we must recurse into the
2030  * subquery to expand any rule references in it.
2031  */
2032  if (rte->rtekind == RTE_SUBQUERY)
2033  {
2034  rte->subquery = fireRIRrules(rte->subquery, activeRIRs);
2035  continue;
2036  }
2037 
2038  /*
2039  * Joins and other non-relation RTEs can be ignored completely.
2040  */
2041  if (rte->rtekind != RTE_RELATION)
2042  continue;
2043 
2044  /*
2045  * Always ignore RIR rules for materialized views referenced in
2046  * queries. (This does not prevent refreshing MVs, since they aren't
2047  * referenced in their own query definitions.)
2048  *
2049  * Note: in the future we might want to allow MVs to be conditionally
2050  * expanded as if they were regular views, if they are not scannable.
2051  * In that case this test would need to be postponed till after we've
2052  * opened the rel, so that we could check its state.
2053  */
2054  if (rte->relkind == RELKIND_MATVIEW)
2055  continue;
2056 
2057  /*
2058  * In INSERT ... ON CONFLICT, ignore the EXCLUDED pseudo-relation;
2059  * even if it points to a view, we needn't expand it, and should not
2060  * because we want the RTE to remain of RTE_RELATION type. Otherwise,
2061  * it would get changed to RTE_SUBQUERY type, which is an
2062  * untested/unsupported situation.
2063  */
2064  if (parsetree->onConflict &&
2065  rt_index == parsetree->onConflict->exclRelIndex)
2066  continue;
2067 
2068  /*
2069  * If the table is not referenced in the query, then we ignore it.
2070  * This prevents infinite expansion loop due to new rtable entries
2071  * inserted by expansion of a rule. A table is referenced if it is
2072  * part of the join set (a source table), or is referenced by any Var
2073  * nodes, or is the result table.
2074  */
2075  if (rt_index != parsetree->resultRelation &&
2076  !rangeTableEntry_used((Node *) parsetree, rt_index, 0))
2077  continue;
2078 
2079  /*
2080  * Also, if this is a new result relation introduced by
2081  * ApplyRetrieveRule, we don't want to do anything more with it.
2082  */
2083  if (rt_index == parsetree->resultRelation &&
2084  rt_index != origResultRelation)
2085  continue;
2086 
2087  /*
2088  * We can use NoLock here since either the parser or
2089  * AcquireRewriteLocks should have locked the rel already.
2090  */
2091  rel = table_open(rte->relid, NoLock);
2092 
2093  /*
2094  * Collect the RIR rules that we must apply
2095  */
2096  rules = rel->rd_rules;
2097  if (rules != NULL)
2098  {
2099  locks = NIL;
2100  for (i = 0; i < rules->numLocks; i++)
2101  {
2102  rule = rules->rules[i];
2103  if (rule->event != CMD_SELECT)
2104  continue;
2105 
2106  locks = lappend(locks, rule);
2107  }
2108 
2109  /*
2110  * If we found any, apply them --- but first check for recursion!
2111  */
2112  if (locks != NIL)
2113  {
2114  ListCell *l;
2115 
2116  if (list_member_oid(activeRIRs, RelationGetRelid(rel)))
2117  ereport(ERROR,
2118  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2119  errmsg("infinite recursion detected in rules for relation \"%s\"",
2120  RelationGetRelationName(rel))));
2121  activeRIRs = lappend_oid(activeRIRs, RelationGetRelid(rel));
2122 
2123  foreach(l, locks)
2124  {
2125  rule = lfirst(l);
2126 
2127  parsetree = ApplyRetrieveRule(parsetree,
2128  rule,
2129  rt_index,
2130  rel,
2131  activeRIRs);
2132  }
2133 
2134  activeRIRs = list_delete_last(activeRIRs);
2135  }
2136  }
2137 
2138  table_close(rel, NoLock);
2139  }
2140 
2141  /* Recurse into subqueries in WITH */
2142  foreach(lc, parsetree->cteList)
2143  {
2144  CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
2145 
2146  cte->ctequery = (Node *)
2147  fireRIRrules((Query *) cte->ctequery, activeRIRs);
2148  }
2149 
2150  /*
2151  * Recurse into sublink subqueries, too. But we already did the ones in
2152  * the rtable and cteList.
2153  */
2154  if (parsetree->hasSubLinks)
2155  query_tree_walker(parsetree, fireRIRonSubLink, (void *) activeRIRs,
2157 
2158  /*
2159  * Apply any row-level security policies. We do this last because it
2160  * requires special recursion detection if the new quals have sublink
2161  * subqueries, and if we did it in the loop above query_tree_walker would
2162  * then recurse into those quals a second time.
2163  */
2164  rt_index = 0;
2165  foreach(lc, parsetree->rtable)
2166  {
2167  RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
2168  Relation rel;
2169  List *securityQuals;
2170  List *withCheckOptions;
2171  bool hasRowSecurity;
2172  bool hasSubLinks;
2173 
2174  ++rt_index;
2175 
2176  /* Only normal relations can have RLS policies */
2177  if (rte->rtekind != RTE_RELATION ||
2178  (rte->relkind != RELKIND_RELATION &&
2179  rte->relkind != RELKIND_PARTITIONED_TABLE))
2180  continue;
2181 
2182  rel = table_open(rte->relid, NoLock);
2183 
2184  /*
2185  * Fetch any new security quals that must be applied to this RTE.
2186  */
2187  get_row_security_policies(parsetree, rte, rt_index,
2188  &securityQuals, &withCheckOptions,
2189  &hasRowSecurity, &hasSubLinks);
2190 
2191  if (securityQuals != NIL || withCheckOptions != NIL)
2192  {
2193  if (hasSubLinks)
2194  {
2196 
2197  /*
2198  * Recursively process the new quals, checking for infinite
2199  * recursion.
2200  */
2201  if (list_member_oid(activeRIRs, RelationGetRelid(rel)))
2202  ereport(ERROR,
2203  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2204  errmsg("infinite recursion detected in policy for relation \"%s\"",
2205  RelationGetRelationName(rel))));
2206 
2207  activeRIRs = lappend_oid(activeRIRs, RelationGetRelid(rel));
2208 
2209  /*
2210  * get_row_security_policies just passed back securityQuals
2211  * and/or withCheckOptions, and there were SubLinks, make sure
2212  * we lock any relations which are referenced.
2213  *
2214  * These locks would normally be acquired by the parser, but
2215  * securityQuals and withCheckOptions are added post-parsing.
2216  */
2217  context.for_execute = true;
2218  (void) acquireLocksOnSubLinks((Node *) securityQuals, &context);
2219  (void) acquireLocksOnSubLinks((Node *) withCheckOptions,
2220  &context);
2221 
2222  /*
2223  * Now that we have the locks on anything added by
2224  * get_row_security_policies, fire any RIR rules for them.
2225  */
2226  expression_tree_walker((Node *) securityQuals,
2227  fireRIRonSubLink, (void *) activeRIRs);
2228 
2229  expression_tree_walker((Node *) withCheckOptions,
2230  fireRIRonSubLink, (void *) activeRIRs);
2231 
2232  activeRIRs = list_delete_last(activeRIRs);
2233  }
2234 
2235  /*
2236  * Add the new security barrier quals to the start of the RTE's
2237  * list so that they get applied before any existing barrier quals
2238  * (which would have come from a security-barrier view, and should
2239  * get lower priority than RLS conditions on the table itself).
2240  */
2241  rte->securityQuals = list_concat(securityQuals,
2242  rte->securityQuals);
2243 
2244  parsetree->withCheckOptions = list_concat(withCheckOptions,
2245  parsetree->withCheckOptions);
2246  }
2247 
2248  /*
2249  * Make sure the query is marked correctly if row-level security
2250  * applies, or if the new quals had sublinks.
2251  */
2252  if (hasRowSecurity)
2253  parsetree->hasRowSecurity = true;
2254  if (hasSubLinks)
2255  parsetree->hasSubLinks = true;
2256 
2257  table_close(rel, NoLock);
2258  }
2259 
2260  return parsetree;
2261 }
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_concat(List *list1, const List *list2)
Definition: list.c:561
List * list_delete_last(List *list)
Definition: list.c:957
@ CMD_SELECT
Definition: nodes.h:265
static Query * ApplyRetrieveRule(Query *parsetree, RewriteRule *rule, int rt_index, Relation relation, List *activeRIRs)
bool rangeTableEntry_used(Node *node, int rt_index, int sublevels_up)
Definition: rewriteManip.c:966
CommonTableExpr * rewriteSearchAndCycle(CommonTableExpr *cte)
void get_row_security_policies(Query *root, RangeTblEntry *rte, int rt_index, List **securityQuals, List **withCheckOptions, bool *hasRowSecurity, bool *hasSubLinks)
Definition: rowsecurity.c:98
OnConflictExpr * onConflict
Definition: parsenodes.h:198
RuleLock * rd_rules
Definition: rel.h:115
static struct rule * rules
Definition: zic.c:283

References acquireLocksOnSubLinks(), ApplyRetrieveRule(), CMD_SELECT, context, Query::cteList, CommonTableExpr::ctequery, ereport, errcode(), errmsg(), ERROR, OnConflictExpr::exclRelIndex, expression_tree_walker, fireRIRonSubLink(), get_row_security_policies(), i, lappend(), lappend_oid(), lfirst, lfirst_node, list_concat(), list_delete_last(), list_length(), list_member_oid(), NIL, NoLock, Query::onConflict, QTW_IGNORE_RC_SUBQUERIES, query_tree_walker, rangeTableEntry_used(), RelationData::rd_rules, RelationGetRelationName, RelationGetRelid, RangeTblEntry::relid, rewriteSearchAndCycle(), rt_fetch, Query::rtable, RTE_RELATION, RTE_SUBQUERY, RangeTblEntry::rtekind, rules, RangeTblEntry::subquery, table_close(), and table_open().

Referenced by ApplyRetrieveRule(), fireRIRonSubLink(), and QueryRewrite().

◆ fireRules()

static List* fireRules ( Query parsetree,
int  rt_index,
CmdType  event,
List locks,
bool instead_flag,
bool returning_flag,
Query **  qual_product 
)
static

Definition at line 2348 of file rewriteHandler.c.

2355 {
2356  List *results = NIL;
2357  ListCell *l;
2358 
2359  foreach(l, locks)
2360  {
2361  RewriteRule *rule_lock = (RewriteRule *) lfirst(l);
2362  Node *event_qual = rule_lock->qual;
2363  List *actions = rule_lock->actions;
2364  QuerySource qsrc;
2365  ListCell *r;
2366 
2367  /* Determine correct QuerySource value for actions */
2368  if (rule_lock->isInstead)
2369  {
2370  if (event_qual != NULL)
2371  qsrc = QSRC_QUAL_INSTEAD_RULE;
2372  else
2373  {
2374  qsrc = QSRC_INSTEAD_RULE;
2375  *instead_flag = true; /* report unqualified INSTEAD */
2376  }
2377  }
2378  else
2379  qsrc = QSRC_NON_INSTEAD_RULE;
2380 
2381  if (qsrc == QSRC_QUAL_INSTEAD_RULE)
2382  {
2383  /*
2384  * If there are INSTEAD rules with qualifications, the original
2385  * query is still performed. But all the negated rule
2386  * qualifications of the INSTEAD rules are added so it does its
2387  * actions only in cases where the rule quals of all INSTEAD rules
2388  * are false. Think of it as the default action in a case. We save
2389  * this in *qual_product so RewriteQuery() can add it to the query
2390  * list after we mangled it up enough.
2391  *
2392  * If we have already found an unqualified INSTEAD rule, then
2393  * *qual_product won't be used, so don't bother building it.
2394  */
2395  if (!*instead_flag)
2396  {
2397  if (*qual_product == NULL)
2398  *qual_product = copyObject(parsetree);
2399  *qual_product = CopyAndAddInvertedQual(*qual_product,
2400  event_qual,
2401  rt_index,
2402  event);
2403  }
2404  }
2405 
2406  /* Now process the rule's actions and add them to the result list */
2407  foreach(r, actions)
2408  {
2409  Query *rule_action = lfirst(r);
2410 
2411  if (rule_action->commandType == CMD_NOTHING)
2412  continue;
2413 
2414  rule_action = rewriteRuleAction(parsetree, rule_action,
2415  event_qual, rt_index, event,
2416  returning_flag);
2417 
2418  rule_action->querySource = qsrc;
2419  rule_action->canSetTag = false; /* might change later */
2420 
2421  results = lappend(results, rule_action);
2422  }
2423  }
2424 
2425  return results;
2426 }
QuerySource
Definition: parsenodes.h:35
@ QSRC_NON_INSTEAD_RULE
Definition: parsenodes.h:40
@ QSRC_QUAL_INSTEAD_RULE
Definition: parsenodes.h:39
@ QSRC_INSTEAD_RULE
Definition: parsenodes.h:38
static Query * rewriteRuleAction(Query *parsetree, Query *rule_action, Node *rule_qual, int rt_index, CmdType event, bool *returning_flag)
static Query * CopyAndAddInvertedQual(Query *parsetree, Node *rule_qual, int rt_index, CmdType event)
List * actions
Definition: prs2lock.h:29
bool isInstead
Definition: prs2lock.h:31
Node * qual
Definition: prs2lock.h:28

References RewriteRule::actions, CMD_NOTHING, Query::commandType, CopyAndAddInvertedQual(), copyObject, RewriteRule::isInstead, lappend(), lfirst, NIL, QSRC_INSTEAD_RULE, QSRC_NON_INSTEAD_RULE, QSRC_QUAL_INSTEAD_RULE, RewriteRule::qual, and rewriteRuleAction().

Referenced by RewriteQuery().

◆ get_assignment_input()

static Node * get_assignment_input ( Node node)
static

Definition at line 1195 of file rewriteHandler.c.

1196 {
1197  if (node == NULL)
1198  return NULL;
1199  if (IsA(node, FieldStore))
1200  {
1201  FieldStore *fstore = (FieldStore *) node;
1202 
1203  return (Node *) fstore->arg;
1204  }
1205  else if (IsA(node, SubscriptingRef))
1206  {
1207  SubscriptingRef *sbsref = (SubscriptingRef *) node;
1208 
1209  if (sbsref->refassgnexpr == NULL)
1210  return NULL;
1211 
1212  return (Node *) sbsref->refexpr;
1213  }
1214 
1215  return NULL;
1216 }
Expr * arg
Definition: primnodes.h:1159
Expr * refassgnexpr
Definition: primnodes.h:703
Expr * refexpr
Definition: primnodes.h:701

References FieldStore::arg, IsA, SubscriptingRef::refassgnexpr, and SubscriptingRef::refexpr.

Referenced by process_matched_tle().

◆ get_view_query()

Query* get_view_query ( Relation  view)

Definition at line 2439 of file rewriteHandler.c.

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

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

◆ markQueryForLocking()

static void markQueryForLocking ( Query qry,
Node jtnode,
LockClauseStrength  strength,
LockWaitPolicy  waitPolicy,
bool  pushedDown 
)
static

Definition at line 1891 of file rewriteHandler.c.

1894 {
1895  if (jtnode == NULL)
1896  return;
1897  if (IsA(jtnode, RangeTblRef))
1898  {
1899  int rti = ((RangeTblRef *) jtnode)->rtindex;
1900  RangeTblEntry *rte = rt_fetch(rti, qry->rtable);
1901 
1902  if (rte->rtekind == RTE_RELATION)
1903  {
1904  RTEPermissionInfo *perminfo;
1905 
1906  applyLockingClause(qry, rti, strength, waitPolicy, pushedDown);
1907 
1908  perminfo = getRTEPermissionInfo(qry->rteperminfos, rte);
1909  perminfo->requiredPerms |= ACL_SELECT_FOR_UPDATE;
1910  }
1911  else if (rte->rtekind == RTE_SUBQUERY)
1912  {
1913  applyLockingClause(qry, rti, strength, waitPolicy, pushedDown);
1914  /* FOR UPDATE/SHARE of subquery is propagated to subquery's rels */
1916  strength, waitPolicy, true);
1917  }
1918  /* other RTE types are unaffected by FOR UPDATE */
1919  }
1920  else if (IsA(jtnode, FromExpr))
1921  {
1922  FromExpr *f = (FromExpr *) jtnode;
1923  ListCell *l;
1924 
1925  foreach(l, f->fromlist)
1926  markQueryForLocking(qry, lfirst(l), strength, waitPolicy, pushedDown);
1927  }
1928  else if (IsA(jtnode, JoinExpr))
1929  {
1930  JoinExpr *j = (JoinExpr *) jtnode;
1931 
1932  markQueryForLocking(qry, j->larg, strength, waitPolicy, pushedDown);
1933  markQueryForLocking(qry, j->rarg, strength, waitPolicy, pushedDown);
1934  }
1935  else
1936  elog(ERROR, "unrecognized node type: %d",
1937  (int) nodeTag(jtnode));
1938 }
int j
Definition: isn.c:74
#define nodeTag(nodeptr)
Definition: nodes.h:133
RTEPermissionInfo * getRTEPermissionInfo(List *rteperminfos, RangeTblEntry *rte)
#define ACL_SELECT_FOR_UPDATE
Definition: parsenodes.h:94
void applyLockingClause(Query *qry, Index rtindex, LockClauseStrength strength, LockWaitPolicy waitPolicy, bool pushedDown)
Definition: analyze.c:3535
AclMode requiredPerms
Definition: parsenodes.h:1291

References ACL_SELECT_FOR_UPDATE, applyLockingClause(), elog, ERROR, FromExpr::fromlist, getRTEPermissionInfo(), IsA, j, Query::jointree, lfirst, nodeTag, RTEPermissionInfo::requiredPerms, rt_fetch, Query::rtable, RTE_RELATION, RTE_SUBQUERY, RangeTblEntry::rtekind, and RangeTblEntry::subquery.

Referenced by ApplyRetrieveRule().

◆ matchLocks()

static List * matchLocks ( CmdType  event,
Relation  relation,
int  varno,
Query parsetree,
bool hasUpdate 
)
static

Definition at line 1642 of file rewriteHandler.c.

1647 {
1648  RuleLock *rulelocks = relation->rd_rules;
1649  List *matching_locks = NIL;
1650  int nlocks;
1651  int i;
1652 
1653  if (rulelocks == NULL)
1654  return NIL;
1655 
1656  if (parsetree->commandType != CMD_SELECT)
1657  {
1658  if (parsetree->resultRelation != varno)
1659  return NIL;
1660  }
1661 
1662  nlocks = rulelocks->numLocks;
1663 
1664  for (i = 0; i < nlocks; i++)
1665  {
1666  RewriteRule *oneLock = rulelocks->rules[i];
1667 
1668  if (oneLock->event == CMD_UPDATE)
1669  *hasUpdate = true;
1670 
1671  /*
1672  * Suppress ON INSERT/UPDATE/DELETE rules that are disabled or
1673  * configured to not fire during the current session's replication
1674  * role. ON SELECT rules will always be applied in order to keep views
1675  * working even in LOCAL or REPLICA role.
1676  */
1677  if (oneLock->event != CMD_SELECT)
1678  {
1680  {
1681  if (oneLock->enabled == RULE_FIRES_ON_ORIGIN ||
1682  oneLock->enabled == RULE_DISABLED)
1683  continue;
1684  }
1685  else /* ORIGIN or LOCAL ROLE */
1686  {
1687  if (oneLock->enabled == RULE_FIRES_ON_REPLICA ||
1688  oneLock->enabled == RULE_DISABLED)
1689  continue;
1690  }
1691 
1692  /* Non-SELECT rules are not supported for MERGE */
1693  if (parsetree->commandType == CMD_MERGE)
1694  ereport(ERROR,
1695  errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1696  errmsg("cannot execute MERGE on relation \"%s\"",
1697  RelationGetRelationName(relation)),
1698  errdetail("MERGE is not supported for relations with rules."));
1699  }
1700 
1701  if (oneLock->event == event)
1702  {
1703  if (parsetree->commandType != CMD_SELECT ||
1704  rangeTableEntry_used((Node *) parsetree, varno, 0))
1705  matching_locks = lappend(matching_locks, oneLock);
1706  }
1707  }
1708 
1709  return matching_locks;
1710 }
int errdetail(const char *fmt,...)
Definition: elog.c:1203
#define RULE_FIRES_ON_ORIGIN
Definition: rewriteDefine.h:21
#define RULE_FIRES_ON_REPLICA
Definition: rewriteDefine.h:23
#define RULE_DISABLED
Definition: rewriteDefine.h:24
CmdType event
Definition: prs2lock.h:27
char enabled
Definition: prs2lock.h:30
int SessionReplicationRole
Definition: trigger.c:63
#define SESSION_REPLICATION_ROLE_REPLICA
Definition: trigger.h:141

References CMD_MERGE, CMD_SELECT, CMD_UPDATE, Query::commandType, RewriteRule::enabled, ereport, errcode(), errdetail(), errmsg(), ERROR, RewriteRule::event, i, lappend(), NIL, RuleLock::numLocks, rangeTableEntry_used(), RelationData::rd_rules, RelationGetRelationName, RULE_DISABLED, RULE_FIRES_ON_ORIGIN, RULE_FIRES_ON_REPLICA, RuleLock::rules, SESSION_REPLICATION_ROLE_REPLICA, and SessionReplicationRole.

Referenced by RewriteQuery(), and rewriteValuesRTE().

◆ process_matched_tle()

static TargetEntry * process_matched_tle ( TargetEntry src_tle,
TargetEntry prior_tle,
const char *  attrName 
)
static

Definition at line 1042 of file rewriteHandler.c.

1045 {
1046  TargetEntry *result;
1047  CoerceToDomain *coerce_expr = NULL;
1048  Node *src_expr;
1049  Node *prior_expr;
1050  Node *src_input;
1051  Node *prior_input;
1052  Node *priorbottom;
1053  Node *newexpr;
1054 
1055  if (prior_tle == NULL)
1056  {
1057  /*
1058  * Normal case where this is the first assignment to the attribute.
1059  */
1060  return src_tle;
1061  }
1062 
1063  /*----------
1064  * Multiple assignments to same attribute. Allow only if all are
1065  * FieldStore or SubscriptingRef assignment operations. This is a bit
1066  * tricky because what we may actually be looking at is a nest of
1067  * such nodes; consider
1068  * UPDATE tab SET col.fld1.subfld1 = x, col.fld2.subfld2 = y
1069  * The two expressions produced by the parser will look like
1070  * FieldStore(col, fld1, FieldStore(placeholder, subfld1, x))
1071  * FieldStore(col, fld2, FieldStore(placeholder, subfld2, y))
1072  * However, we can ignore the substructure and just consider the top
1073  * FieldStore or SubscriptingRef from each assignment, because it works to
1074  * combine these as
1075  * FieldStore(FieldStore(col, fld1,
1076  * FieldStore(placeholder, subfld1, x)),
1077  * fld2, FieldStore(placeholder, subfld2, y))
1078  * Note the leftmost expression goes on the inside so that the
1079  * assignments appear to occur left-to-right.
1080  *
1081  * For FieldStore, instead of nesting we can generate a single
1082  * FieldStore with multiple target fields. We must nest when
1083  * SubscriptingRefs are involved though.
1084  *
1085  * As a further complication, the destination column might be a domain,
1086  * resulting in each assignment containing a CoerceToDomain node over a
1087  * FieldStore or SubscriptingRef. These should have matching target
1088  * domains, so we strip them and reconstitute a single CoerceToDomain over
1089  * the combined FieldStore/SubscriptingRef nodes. (Notice that this has
1090  * the result that the domain's checks are applied only after we do all
1091  * the field or element updates, not after each one. This is desirable.)
1092  *----------
1093  */
1094  src_expr = (Node *) src_tle->expr;
1095  prior_expr = (Node *) prior_tle->expr;
1096 
1097  if (src_expr && IsA(src_expr, CoerceToDomain) &&
1098  prior_expr && IsA(prior_expr, CoerceToDomain) &&
1099  ((CoerceToDomain *) src_expr)->resulttype ==
1100  ((CoerceToDomain *) prior_expr)->resulttype)
1101  {
1102  /* we assume without checking that resulttypmod/resultcollid match */
1103  coerce_expr = (CoerceToDomain *) src_expr;
1104  src_expr = (Node *) ((CoerceToDomain *) src_expr)->arg;
1105  prior_expr = (Node *) ((CoerceToDomain *) prior_expr)->arg;
1106  }
1107 
1108  src_input = get_assignment_input(src_expr);
1109  prior_input = get_assignment_input(prior_expr);
1110  if (src_input == NULL ||
1111  prior_input == NULL ||
1112  exprType(src_expr) != exprType(prior_expr))
1113  ereport(ERROR,
1114  (errcode(ERRCODE_SYNTAX_ERROR),
1115  errmsg("multiple assignments to same column \"%s\"",
1116  attrName)));
1117 
1118  /*
1119  * Prior TLE could be a nest of assignments if we do this more than once.
1120  */
1121  priorbottom = prior_input;
1122  for (;;)
1123  {
1124  Node *newbottom = get_assignment_input(priorbottom);
1125 
1126  if (newbottom == NULL)
1127  break; /* found the original Var reference */
1128  priorbottom = newbottom;
1129  }
1130  if (!equal(priorbottom, src_input))
1131  ereport(ERROR,
1132  (errcode(ERRCODE_SYNTAX_ERROR),
1133  errmsg("multiple assignments to same column \"%s\"",
1134  attrName)));
1135 
1136  /*
1137  * Looks OK to nest 'em.
1138  */
1139  if (IsA(src_expr, FieldStore))
1140  {
1141  FieldStore *fstore = makeNode(FieldStore);
1142 
1143  if (IsA(prior_expr, FieldStore))
1144  {
1145  /* combine the two */
1146  memcpy(fstore, prior_expr, sizeof(FieldStore));
1147  fstore->newvals =
1148  list_concat_copy(((FieldStore *) prior_expr)->newvals,
1149  ((FieldStore *) src_expr)->newvals);
1150  fstore->fieldnums =
1151  list_concat_copy(((FieldStore *) prior_expr)->fieldnums,
1152  ((FieldStore *) src_expr)->fieldnums);
1153  }
1154  else
1155  {
1156  /* general case, just nest 'em */
1157  memcpy(fstore, src_expr, sizeof(FieldStore));
1158  fstore->arg = (Expr *) prior_expr;
1159  }
1160  newexpr = (Node *) fstore;
1161  }
1162  else if (IsA(src_expr, SubscriptingRef))
1163  {
1165 
1166  memcpy(sbsref, src_expr, sizeof(SubscriptingRef));
1167  sbsref->refexpr = (Expr *) prior_expr;
1168  newexpr = (Node *) sbsref;
1169  }
1170  else
1171  {
1172  elog(ERROR, "cannot happen");
1173  newexpr = NULL;
1174  }
1175 
1176  if (coerce_expr)
1177  {
1178  /* put back the CoerceToDomain */
1179  CoerceToDomain *newcoerce = makeNode(CoerceToDomain);
1180 
1181  memcpy(newcoerce, coerce_expr, sizeof(CoerceToDomain));
1182  newcoerce->arg = (Expr *) newexpr;
1183  newexpr = (Node *) newcoerce;
1184  }
1185 
1186  result = flatCopyTargetEntry(src_tle);
1187  result->expr = (Expr *) newexpr;
1188  return result;
1189 }
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:223
List * list_concat_copy(const List *list1, const List *list2)
Definition: list.c:598
TargetEntry * flatCopyTargetEntry(TargetEntry *src_tle)
Definition: makefuncs.c:273
void * arg
static Node * get_assignment_input(Node *node)
List * newvals
Definition: primnodes.h:1160

References arg, FieldStore::arg, CoerceToDomain::arg, elog, equal(), ereport, errcode(), errmsg(), ERROR, TargetEntry::expr, exprType(), flatCopyTargetEntry(), get_assignment_input(), IsA, list_concat_copy(), makeNode, FieldStore::newvals, and SubscriptingRef::refexpr.

Referenced by rewriteTargetListIU().

◆ QueryRewrite()

List* QueryRewrite ( Query parsetree)

Definition at line 4378 of file rewriteHandler.c.

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

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

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

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

◆ RewriteQuery()

static List* RewriteQuery ( Query parsetree,
List rewrite_events,
int  orig_rt_length 
)
static

Definition at line 3832 of file rewriteHandler.c.

3833 {
3834  CmdType event = parsetree->commandType;
3835  bool instead = false;
3836  bool returning = false;
3837  bool updatableview = false;
3838  Query *qual_product = NULL;
3839  List *rewritten = NIL;
3840  ListCell *lc1;
3841 
3842  /*
3843  * First, recursively process any insert/update/delete/merge statements in
3844  * WITH clauses. (We have to do this first because the WITH clauses may
3845  * get copied into rule actions below.)
3846  */
3847  foreach(lc1, parsetree->cteList)
3848  {
3850  Query *ctequery = castNode(Query, cte->ctequery);
3851  List *newstuff;
3852 
3853  if (ctequery->commandType == CMD_SELECT)
3854  continue;
3855 
3856  newstuff = RewriteQuery(ctequery, rewrite_events, 0);
3857 
3858  /*
3859  * Currently we can only handle unconditional, single-statement DO
3860  * INSTEAD rules correctly; we have to get exactly one non-utility
3861  * Query out of the rewrite operation to stuff back into the CTE node.
3862  */
3863  if (list_length(newstuff) == 1)
3864  {
3865  /* Must check it's not a utility command */
3866  ctequery = linitial_node(Query, newstuff);
3867  if (!(ctequery->commandType == CMD_SELECT ||
3868  ctequery->commandType == CMD_UPDATE ||
3869  ctequery->commandType == CMD_INSERT ||
3870  ctequery->commandType == CMD_DELETE ||
3871  ctequery->commandType == CMD_MERGE))
3872  {
3873  /*
3874  * Currently it could only be NOTIFY; this error message will
3875  * need work if we ever allow other utility commands in rules.
3876  */
3877  ereport(ERROR,
3878  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3879  errmsg("DO INSTEAD NOTIFY rules are not supported for data-modifying statements in WITH")));
3880  }
3881  /* WITH queries should never be canSetTag */
3882  Assert(!ctequery->canSetTag);
3883  /* Push the single Query back into the CTE node */
3884  cte->ctequery = (Node *) ctequery;
3885  }
3886  else if (newstuff == NIL)
3887  {
3888  ereport(ERROR,
3889  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3890  errmsg("DO INSTEAD NOTHING rules are not supported for data-modifying statements in WITH")));
3891  }
3892  else
3893  {
3894  ListCell *lc2;
3895 
3896  /* examine queries to determine which error message to issue */
3897  foreach(lc2, newstuff)
3898  {
3899  Query *q = (Query *) lfirst(lc2);
3900 
3901  if (q->querySource == QSRC_QUAL_INSTEAD_RULE)
3902  ereport(ERROR,
3903  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3904  errmsg("conditional DO INSTEAD rules are not supported for data-modifying statements in WITH")));
3905  if (q->querySource == QSRC_NON_INSTEAD_RULE)
3906  ereport(ERROR,
3907  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3908  errmsg("DO ALSO rules are not supported for data-modifying statements in WITH")));
3909  }
3910 
3911  ereport(ERROR,
3912  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3913  errmsg("multi-statement DO INSTEAD rules are not supported for data-modifying statements in WITH")));
3914  }
3915  }
3916 
3917  /*
3918  * If the statement is an insert, update, delete, or merge, adjust its
3919  * targetlist as needed, and then fire INSERT/UPDATE/DELETE rules on it.
3920  *
3921  * SELECT rules are handled later when we have all the queries that should
3922  * get executed. Also, utilities aren't rewritten at all (do we still
3923  * need that check?)
3924  */
3925  if (event != CMD_SELECT && event != CMD_UTILITY)
3926  {
3927  int result_relation;
3928  RangeTblEntry *rt_entry;
3929  Relation rt_entry_relation;
3930  List *locks;
3931  int product_orig_rt_length;
3932  List *product_queries;
3933  bool hasUpdate = false;
3934  int values_rte_index = 0;
3935  bool defaults_remaining = false;
3936 
3937  result_relation = parsetree->resultRelation;
3938  Assert(result_relation != 0);
3939  rt_entry = rt_fetch(result_relation, parsetree->rtable);
3940  Assert(rt_entry->rtekind == RTE_RELATION);
3941 
3942  /*
3943  * We can use NoLock here since either the parser or
3944  * AcquireRewriteLocks should have locked the rel already.
3945  */
3946  rt_entry_relation = table_open(rt_entry->relid, NoLock);
3947 
3948  /*
3949  * Rewrite the targetlist as needed for the command type.
3950  */
3951  if (event == CMD_INSERT)
3952  {
3953  ListCell *lc2;
3954  RangeTblEntry *values_rte = NULL;
3955 
3956  /*
3957  * Test if it's a multi-row INSERT ... VALUES (...), (...), ... by
3958  * looking for a VALUES RTE in the fromlist. For product queries,
3959  * we must ignore any already-processed VALUES RTEs from the
3960  * original query. These appear at the start of the rangetable.
3961  */
3962  foreach(lc2, parsetree->jointree->fromlist)
3963  {
3964  RangeTblRef *rtr = (RangeTblRef *) lfirst(lc2);
3965 
3966  if (IsA(rtr, RangeTblRef) && rtr->rtindex > orig_rt_length)
3967  {
3968  RangeTblEntry *rte = rt_fetch(rtr->rtindex,
3969  parsetree->rtable);
3970 
3971  if (rte->rtekind == RTE_VALUES)
3972  {
3973  /* should not find more than one VALUES RTE */
3974  if (values_rte != NULL)
3975  elog(ERROR, "more than one VALUES RTE found");
3976 
3977  values_rte = rte;
3978  values_rte_index = rtr->rtindex;
3979  }
3980  }
3981  }
3982 
3983  if (values_rte)
3984  {
3985  Bitmapset *unused_values_attrnos = NULL;
3986 
3987  /* Process the main targetlist ... */
3988  parsetree->targetList = rewriteTargetListIU(parsetree->targetList,
3989  parsetree->commandType,
3990  parsetree->override,
3991  rt_entry_relation,
3992  values_rte,
3993  values_rte_index,
3994  &unused_values_attrnos);
3995  /* ... and the VALUES expression lists */
3996  if (!rewriteValuesRTE(parsetree, values_rte, values_rte_index,
3997  rt_entry_relation,
3998  unused_values_attrnos))
3999  defaults_remaining = true;
4000  }
4001  else
4002  {
4003  /* Process just the main targetlist */
4004  parsetree->targetList =
4005  rewriteTargetListIU(parsetree->targetList,
4006  parsetree->commandType,
4007  parsetree->override,
4008  rt_entry_relation,
4009  NULL, 0, NULL);
4010  }
4011 
4012  if (parsetree->onConflict &&
4013  parsetree->onConflict->action == ONCONFLICT_UPDATE)
4014  {
4015  parsetree->onConflict->onConflictSet =
4017  CMD_UPDATE,
4018  parsetree->override,
4019  rt_entry_relation,
4020  NULL, 0, NULL);
4021  }
4022  }
4023  else if (event == CMD_UPDATE)
4024  {
4025  Assert(parsetree->override == OVERRIDING_NOT_SET);
4026  parsetree->targetList =
4027  rewriteTargetListIU(parsetree->targetList,
4028  parsetree->commandType,
4029  parsetree->override,
4030  rt_entry_relation,
4031  NULL, 0, NULL);
4032  }
4033  else if (event == CMD_MERGE)
4034  {
4035  Assert(parsetree->override == OVERRIDING_NOT_SET);
4036 
4037  /*
4038  * Rewrite each action targetlist separately
4039  */
4040  foreach(lc1, parsetree->mergeActionList)
4041  {
4042  MergeAction *action = (MergeAction *) lfirst(lc1);
4043 
4044  switch (action->commandType)
4045  {
4046  case CMD_NOTHING:
4047  case CMD_DELETE: /* Nothing to do here */
4048  break;
4049  case CMD_UPDATE:
4050  case CMD_INSERT:
4051 
4052  /*
4053  * MERGE actions do not permit multi-row INSERTs, so
4054  * there is no VALUES RTE to deal with here.
4055  */
4056  action->targetList =
4057  rewriteTargetListIU(action->targetList,
4058  action->commandType,
4059  action->override,
4060  rt_entry_relation,
4061  NULL, 0, NULL);
4062  break;
4063  default:
4064  elog(ERROR, "unrecognized commandType: %d", action->commandType);
4065  break;
4066  }
4067  }
4068  }
4069  else if (event == CMD_DELETE)
4070  {
4071  /* Nothing to do here */
4072  }
4073  else
4074  elog(ERROR, "unrecognized commandType: %d", (int) event);
4075 
4076  /*
4077  * Collect and apply the appropriate rules.
4078  */
4079  locks = matchLocks(event, rt_entry_relation,
4080  result_relation, parsetree, &hasUpdate);
4081 
4082  product_orig_rt_length = list_length(parsetree->rtable);
4083  product_queries = fireRules(parsetree,
4084  result_relation,
4085  event,
4086  locks,
4087  &instead,
4088  &returning,
4089  &qual_product);
4090 
4091  /*
4092  * If we have a VALUES RTE with any remaining untouched DEFAULT items,
4093  * and we got any product queries, finalize the VALUES RTE for each
4094  * product query (replacing the remaining DEFAULT items with NULLs).
4095  * We don't do this for the original query, because we know that it
4096  * must be an auto-insert on a view, and so should use the base
4097  * relation's defaults for any remaining DEFAULT items.
4098  */
4099  if (defaults_remaining && product_queries != NIL)
4100  {
4101  ListCell *n;
4102 
4103  /*
4104  * Each product query has its own copy of the VALUES RTE at the
4105  * same index in the rangetable, so we must finalize each one.
4106  *
4107  * Note that if the product query is an INSERT ... SELECT, then
4108  * the VALUES RTE will be at the same index in the SELECT part of
4109  * the product query rather than the top-level product query
4110  * itself.
4111  */
4112  foreach(n, product_queries)
4113  {
4114  Query *pt = (Query *) lfirst(n);
4115  RangeTblEntry *values_rte;
4116 
4117  if (pt->commandType == CMD_INSERT &&
4118  pt->jointree && IsA(pt->jointree, FromExpr) &&
4119  list_length(pt->jointree->fromlist) == 1)
4120  {
4121  Node *jtnode = (Node *) linitial(pt->jointree->fromlist);
4122 
4123  if (IsA(jtnode, RangeTblRef))
4124  {
4125  int rtindex = ((RangeTblRef *) jtnode)->rtindex;
4126  RangeTblEntry *src_rte = rt_fetch(rtindex, pt->rtable);
4127 
4128  if (src_rte->rtekind == RTE_SUBQUERY &&
4129  src_rte->subquery &&
4130  IsA(src_rte->subquery, Query) &&
4131  src_rte->subquery->commandType == CMD_SELECT)
4132  pt = src_rte->subquery;
4133  }
4134  }
4135 
4136  values_rte = rt_fetch(values_rte_index, pt->rtable);
4137  if (values_rte->rtekind != RTE_VALUES)
4138  elog(ERROR, "failed to find VALUES RTE in product query");
4139 
4140  rewriteValuesRTEToNulls(pt, values_rte);
4141  }
4142  }
4143 
4144  /*
4145  * If there was no unqualified INSTEAD rule, and the target relation
4146  * is a view without any INSTEAD OF triggers, see if the view can be
4147  * automatically updated. If so, we perform the necessary query
4148  * transformation here and add the resulting query to the
4149  * product_queries list, so that it gets recursively rewritten if
4150  * necessary. For MERGE, the view must be automatically updatable if
4151  * any of the merge actions lack a corresponding INSTEAD OF trigger.
4152  *
4153  * If the view cannot be automatically updated, we throw an error here
4154  * which is OK since the query would fail at runtime anyway. Throwing
4155  * the error here is preferable to the executor check since we have
4156  * more detailed information available about why the view isn't
4157  * updatable.
4158  */
4159  if (!instead &&
4160  rt_entry_relation->rd_rel->relkind == RELKIND_VIEW &&
4161  !view_has_instead_trigger(rt_entry_relation, event,
4162  parsetree->mergeActionList))
4163  {
4164  /*
4165  * If there were any qualified INSTEAD rules, don't allow the view
4166  * to be automatically updated (an unqualified INSTEAD rule or
4167  * INSTEAD OF trigger is required).
4168  */
4169  if (qual_product != NULL)
4170  error_view_not_updatable(rt_entry_relation,
4171  parsetree->commandType,
4172  parsetree->mergeActionList,
4173  gettext_noop("Views with conditional DO INSTEAD rules are not automatically updatable."));
4174 
4175  /*
4176  * Attempt to rewrite the query to automatically update the view.
4177  * This throws an error if the view can't be automatically
4178  * updated.
4179  */
4180  parsetree = rewriteTargetView(parsetree, rt_entry_relation);
4181 
4182  /*
4183  * At this point product_queries contains any DO ALSO rule
4184  * actions. Add the rewritten query before or after those. This
4185  * must match the handling the original query would have gotten
4186  * below, if we allowed it to be included again.
4187  */
4188  if (parsetree->commandType == CMD_INSERT)
4189  product_queries = lcons(parsetree, product_queries);
4190  else
4191  product_queries = lappend(product_queries, parsetree);
4192 
4193  /*
4194  * Set the "instead" flag, as if there had been an unqualified
4195  * INSTEAD, to prevent the original query from being included a
4196  * second time below. The transformation will have rewritten any
4197  * RETURNING list, so we can also set "returning" to forestall
4198  * throwing an error below.
4199  */
4200  instead = true;
4201  returning = true;
4202  updatableview = true;
4203  }
4204 
4205  /*
4206  * If we got any product queries, recursively rewrite them --- but
4207  * first check for recursion!
4208  */
4209  if (product_queries != NIL)
4210  {
4211  ListCell *n;
4212  rewrite_event *rev;
4213 
4214  foreach(n, rewrite_events)
4215  {
4216  rev = (rewrite_event *) lfirst(n);
4217  if (rev->relation == RelationGetRelid(rt_entry_relation) &&
4218  rev->event == event)
4219  ereport(ERROR,
4220  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
4221  errmsg("infinite recursion detected in rules for relation \"%s\"",
4222  RelationGetRelationName(rt_entry_relation))));
4223  }
4224 
4225  rev = (rewrite_event *) palloc(sizeof(rewrite_event));
4226  rev->relation = RelationGetRelid(rt_entry_relation);
4227  rev->event = event;
4228  rewrite_events = lappend(rewrite_events, rev);
4229 
4230  foreach(n, product_queries)
4231  {
4232  Query *pt = (Query *) lfirst(n);
4233  List *newstuff;
4234 
4235  /*
4236  * For an updatable view, pt might be the rewritten version of
4237  * the original query, in which case we pass on orig_rt_length
4238  * to finish processing any VALUES RTE it contained.
4239  *
4240  * Otherwise, we have a product query created by fireRules().
4241  * Any VALUES RTEs from the original query have been fully
4242  * processed, and must be skipped when we recurse.
4243  */
4244  newstuff = RewriteQuery(pt, rewrite_events,
4245  pt == parsetree ?
4246  orig_rt_length :
4247  product_orig_rt_length);
4248  rewritten = list_concat(rewritten, newstuff);
4249  }
4250 
4251  rewrite_events = list_delete_last(rewrite_events);
4252  }
4253 
4254  /*
4255  * If there is an INSTEAD, and the original query has a RETURNING, we
4256  * have to have found a RETURNING in the rule(s), else fail. (Because
4257  * DefineQueryRewrite only allows RETURNING in unconditional INSTEAD
4258  * rules, there's no need to worry whether the substituted RETURNING
4259  * will actually be executed --- it must be.)
4260  */
4261  if ((instead || qual_product != NULL) &&
4262  parsetree->returningList &&
4263  !returning)
4264  {
4265  switch (event)
4266  {
4267  case CMD_INSERT:
4268  ereport(ERROR,
4269  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4270  errmsg("cannot perform INSERT RETURNING on relation \"%s\"",
4271  RelationGetRelationName(rt_entry_relation)),
4272  errhint("You need an unconditional ON INSERT DO INSTEAD rule with a RETURNING clause.")));
4273  break;
4274  case CMD_UPDATE:
4275  ereport(ERROR,
4276  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4277  errmsg("cannot perform UPDATE RETURNING on relation \"%s\"",
4278  RelationGetRelationName(rt_entry_relation)),
4279  errhint("You need an unconditional ON UPDATE DO INSTEAD rule with a RETURNING clause.")));
4280  break;
4281  case CMD_DELETE:
4282  ereport(ERROR,
4283  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4284  errmsg("cannot perform DELETE RETURNING on relation \"%s\"",
4285  RelationGetRelationName(rt_entry_relation)),
4286  errhint("You need an unconditional ON DELETE DO INSTEAD rule with a RETURNING clause.")));
4287  break;
4288  default:
4289  elog(ERROR, "unrecognized commandType: %d",
4290  (int) event);
4291  break;
4292  }
4293  }
4294 
4295  /*
4296  * Updatable views are supported by ON CONFLICT, so don't prevent that
4297  * case from proceeding
4298  */
4299  if (parsetree->onConflict &&
4300  (product_queries != NIL || hasUpdate) &&
4301  !updatableview)
4302  ereport(ERROR,
4303  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4304  errmsg("INSERT with ON CONFLICT clause cannot be used with table that has INSERT or UPDATE rules")));
4305 
4306  table_close(rt_entry_relation, NoLock);
4307  }
4308 
4309  /*
4310  * For INSERTs, the original query is done first; for UPDATE/DELETE, it is
4311  * done last. This is needed because update and delete rule actions might
4312  * not do anything if they are invoked after the update or delete is
4313  * performed. The command counter increment between the query executions
4314  * makes the deleted (and maybe the updated) tuples disappear so the scans
4315  * for them in the rule actions cannot find them.
4316  *
4317  * If we found any unqualified INSTEAD, the original query is not done at
4318  * all, in any form. Otherwise, we add the modified form if qualified
4319  * INSTEADs were found, else the unmodified form.
4320  */
4321  if (!instead)
4322  {
4323  if (parsetree->commandType == CMD_INSERT)
4324  {
4325  if (qual_product != NULL)
4326  rewritten = lcons(qual_product, rewritten);
4327  else
4328  rewritten = lcons(parsetree, rewritten);
4329  }
4330  else
4331  {
4332  if (qual_product != NULL)
4333  rewritten = lappend(rewritten, qual_product);
4334  else
4335  rewritten = lappend(rewritten, parsetree);
4336  }
4337  }
4338 
4339  /*
4340  * If the original query has a CTE list, and we generated more than one
4341  * non-utility result query, we have to fail because we'll have copied the
4342  * CTE list into each result query. That would break the expectation of
4343  * single evaluation of CTEs. This could possibly be fixed by
4344  * restructuring so that a CTE list can be shared across multiple Query
4345  * and PlannableStatement nodes.
4346  */
4347  if (parsetree->cteList != NIL)
4348  {
4349  int qcount = 0;
4350 
4351  foreach(lc1, rewritten)
4352  {
4353  Query *q = (Query *) lfirst(lc1);
4354 
4355  if (q->commandType != CMD_UTILITY)
4356  qcount++;
4357  }
4358  if (qcount > 1)
4359  ereport(ERROR,
4360  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4361  errmsg("WITH cannot be used in a query that is rewritten by rules into multiple queries")));
4362  }
4363 
4364  return rewritten;
4365 }
#define gettext_noop(x)
Definition: c.h:1196
List * lcons(void *datum, List *list)
Definition: list.c:495
void * palloc(Size size)
Definition: mcxt.c:1317
@ ONCONFLICT_UPDATE
Definition: nodes.h:420
@ CMD_UTILITY
Definition: nodes.h:270
@ RTE_VALUES
Definition: parsenodes.h:1022
#define linitial_node(type, l)
Definition: pg_list.h:181
@ OVERRIDING_NOT_SET
Definition: primnodes.h:27
static List * fireRules(Query *parsetree, int rt_index, CmdType event, List *locks, bool *instead_flag, bool *returning_flag, Query **qual_product)
bool view_has_instead_trigger(Relation view, CmdType event, List *mergeActionList)
static bool rewriteValuesRTE(Query *parsetree, RangeTblEntry *rte, int rti, Relation target_relation, Bitmapset *unused_cols)
static void rewriteValuesRTEToNulls(Query *parsetree, RangeTblEntry *rte)
static List * matchLocks(CmdType event, Relation relation, int varno, Query *parsetree, bool *hasUpdate)
void error_view_not_updatable(Relation view, CmdType command, List *mergeActionList, const char *detail)
static List * rewriteTargetListIU(List *targetList, CmdType commandType, OverridingKind override, Relation target_relation, RangeTblEntry *values_rte, int values_rte_index, Bitmapset **unused_values_attrnos)
static Query * rewriteTargetView(Query *parsetree, Relation view)
OnConflictAction action
Definition: primnodes.h:2320
List * onConflictSet
Definition: primnodes.h:2329
List * mergeActionList
Definition: parsenodes.h:180

References generate_unaccent_rules::action, OnConflictExpr::action, Assert, castNode, CMD_DELETE, CMD_INSERT, CMD_MERGE, CMD_NOTHING, CMD_SELECT, CMD_UPDATE, CMD_UTILITY, Query::commandType, Query::cteList, CommonTableExpr::ctequery, elog, ereport, errcode(), errhint(), errmsg(), ERROR, error_view_not_updatable(), rewrite_event::event, fireRules(), FromExpr::fromlist, gettext_noop, IsA, Query::jointree, lappend(), lcons(), lfirst, lfirst_node, linitial, linitial_node, list_concat(), list_delete_last(), list_length(), matchLocks(), Query::mergeActionList, NIL, NoLock, Query::onConflict, ONCONFLICT_UPDATE, OnConflictExpr::onConflictSet, OVERRIDING_NOT_SET, palloc(), QSRC_NON_INSTEAD_RULE, QSRC_QUAL_INSTEAD_RULE, RelationData::rd_rel, rewrite_event::relation, RelationGetRelationName, RelationGetRelid, RangeTblEntry::relid, Query::returningList, rewriteTargetListIU(), rewriteTargetView(), rewriteValuesRTE(), rewriteValuesRTEToNulls(), rt_fetch, Query::rtable, RTE_RELATION, RTE_SUBQUERY, RTE_VALUES, RangeTblEntry::rtekind, RangeTblRef::rtindex, RangeTblEntry::subquery, table_close(), table_open(), Query::targetList, and view_has_instead_trigger().

Referenced by QueryRewrite().

◆ rewriteRuleAction()

static Query * rewriteRuleAction ( Query parsetree,
Query rule_action,
Node rule_qual,
int  rt_index,
CmdType  event,
bool returning_flag 
)
static

Definition at line 343 of file rewriteHandler.c.

349 {
350  int current_varno,
351  new_varno;
352  int rt_length;
353  Query *sub_action;
354  Query **sub_action_ptr;
356  ListCell *lc;
357 
358  context.for_execute = true;
359 
360  /*
361  * Make modifiable copies of rule action and qual (what we're passed are
362  * the stored versions in the relcache; don't touch 'em!).
363  */
364  rule_action = copyObject(rule_action);
365  rule_qual = copyObject(rule_qual);
366 
367  /*
368  * Acquire necessary locks and fix any deleted JOIN RTE entries.
369  */
370  AcquireRewriteLocks(rule_action, true, false);
371  (void) acquireLocksOnSubLinks(rule_qual, &context);
372 
373  current_varno = rt_index;
374  rt_length = list_length(parsetree->rtable);
375  new_varno = PRS2_NEW_VARNO + rt_length;
376 
377  /*
378  * Adjust rule action and qual to offset its varnos, so that we can merge
379  * its rtable with the main parsetree's rtable.
380  *
381  * If the rule action is an INSERT...SELECT, the OLD/NEW rtable entries
382  * will be in the SELECT part, and we have to modify that rather than the
383  * top-level INSERT (kluge!).
384  */
385  sub_action = getInsertSelectQuery(rule_action, &sub_action_ptr);
386 
387  OffsetVarNodes((Node *) sub_action, rt_length, 0);
388  OffsetVarNodes(rule_qual, rt_length, 0);
389  /* but references to OLD should point at original rt_index */
390  ChangeVarNodes((Node *) sub_action,
391  PRS2_OLD_VARNO + rt_length, rt_index, 0);
392  ChangeVarNodes(rule_qual,
393  PRS2_OLD_VARNO + rt_length, rt_index, 0);
394 
395  /*
396  * Mark any subquery RTEs in the rule action as LATERAL if they contain
397  * Vars referring to the current query level (references to NEW/OLD).
398  * Those really are lateral references, but we've historically not
399  * required users to mark such subqueries with LATERAL explicitly. But
400  * the planner will complain if such Vars exist in a non-LATERAL subquery,
401  * so we have to fix things up here.
402  */
403  foreach(lc, sub_action->rtable)
404  {
405  RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
406 
407  if (rte->rtekind == RTE_SUBQUERY && !rte->lateral &&
408  contain_vars_of_level((Node *) rte->subquery, 1))
409  rte->lateral = true;
410  }
411 
412  /*
413  * Generate expanded rtable consisting of main parsetree's rtable plus
414  * rule action's rtable; this becomes the complete rtable for the rule
415  * action. Some of the entries may be unused after we finish rewriting,
416  * but we leave them all in place to avoid having to adjust the query's
417  * varnos. RT entries that are not referenced in the completed jointree
418  * will be ignored by the planner, so they do not affect query semantics.
419  *
420  * Also merge RTEPermissionInfo lists to ensure that all permissions are
421  * checked correctly.
422  *
423  * If the rule is INSTEAD, then the original query won't be executed at
424  * all, and so its rteperminfos must be preserved so that the executor
425  * will do the correct permissions checks on the relations referenced in
426  * it. This allows us to check that the caller has, say, insert-permission
427  * on a view, when the view is not semantically referenced at all in the
428  * resulting query.
429  *
430  * When a rule is not INSTEAD, the permissions checks done using the
431  * copied entries will be redundant with those done during execution of
432  * the original query, but we don't bother to treat that case differently.
433  *
434  * NOTE: because planner will destructively alter rtable and rteperminfos,
435  * we must ensure that rule action's lists are separate and shares no
436  * substructure with the main query's lists. Hence do a deep copy here
437  * for both.
438  */
439  {
440  List *rtable_tail = sub_action->rtable;
441  List *perminfos_tail = sub_action->rteperminfos;
442 
443  /*
444  * RewriteQuery relies on the fact that RT entries from the original
445  * query appear at the start of the expanded rtable, so we put the
446  * action's original table at the end of the list.
447  */
448  sub_action->rtable = copyObject(parsetree->rtable);
449  sub_action->rteperminfos = copyObject(parsetree->rteperminfos);
450  CombineRangeTables(&sub_action->rtable, &sub_action->rteperminfos,
451  rtable_tail, perminfos_tail);
452  }
453 
454  /*
455  * There could have been some SubLinks in parsetree's rtable, in which
456  * case we'd better mark the sub_action correctly.
457  */
458  if (parsetree->hasSubLinks && !sub_action->hasSubLinks)
459  {
460  foreach(lc, parsetree->rtable)
461  {
462  RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
463 
464  switch (rte->rtekind)
465  {
466  case RTE_RELATION:
467  sub_action->hasSubLinks =
469  break;
470  case RTE_FUNCTION:
471  sub_action->hasSubLinks =
473  break;
474  case RTE_TABLEFUNC:
475  sub_action->hasSubLinks =
477  break;
478  case RTE_VALUES:
479  sub_action->hasSubLinks =
481  break;
482  default:
483  /* other RTE types don't contain bare expressions */
484  break;
485  }
486  sub_action->hasSubLinks |=
487  checkExprHasSubLink((Node *) rte->securityQuals);
488  if (sub_action->hasSubLinks)
489  break; /* no need to keep scanning rtable */
490  }
491  }
492 
493  /*
494  * Also, we might have absorbed some RTEs with RLS conditions into the
495  * sub_action. If so, mark it as hasRowSecurity, whether or not those
496  * RTEs will be referenced after we finish rewriting. (Note: currently
497  * this is a no-op because RLS conditions aren't added till later, but it
498  * seems like good future-proofing to do this anyway.)
499  */
500  sub_action->hasRowSecurity |= parsetree->hasRowSecurity;
501 
502  /*
503  * Each rule action's jointree should be the main parsetree's jointree
504  * plus that rule's jointree, but usually *without* the original rtindex
505  * that we're replacing (if present, which it won't be for INSERT). Note
506  * that if the rule action refers to OLD, its jointree will add a
507  * reference to rt_index. If the rule action doesn't refer to OLD, but
508  * either the rule_qual or the user query quals do, then we need to keep
509  * the original rtindex in the jointree to provide data for the quals. We
510  * don't want the original rtindex to be joined twice, however, so avoid
511  * keeping it if the rule action mentions it.
512  *
513  * As above, the action's jointree must not share substructure with the
514  * main parsetree's.
515  */
516  if (sub_action->commandType != CMD_UTILITY)
517  {
518  bool keeporig;
519  List *newjointree;
520 
521  Assert(sub_action->jointree != NULL);
522  keeporig = (!rangeTableEntry_used((Node *) sub_action->jointree,
523  rt_index, 0)) &&
524  (rangeTableEntry_used(rule_qual, rt_index, 0) ||
525  rangeTableEntry_used(parsetree->jointree->quals, rt_index, 0));
526  newjointree = adjustJoinTreeList(parsetree, !keeporig, rt_index);
527  if (newjointree != NIL)
528  {
529  /*
530  * If sub_action is a setop, manipulating its jointree will do no
531  * good at all, because the jointree is dummy. (Perhaps someday
532  * we could push the joining and quals down to the member
533  * statements of the setop?)
534  */
535  if (sub_action->setOperations != NULL)
536  ereport(ERROR,
537  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
538  errmsg("conditional UNION/INTERSECT/EXCEPT statements are not implemented")));
539 
540  sub_action->jointree->fromlist =
541  list_concat(newjointree, sub_action->jointree->fromlist);
542 
543  /*
544  * There could have been some SubLinks in newjointree, in which
545  * case we'd better mark the sub_action correctly.
546  */
547  if (parsetree->hasSubLinks && !sub_action->hasSubLinks)
548  sub_action->hasSubLinks =
549  checkExprHasSubLink((Node *) newjointree);
550  }
551  }
552 
553  /*
554  * If the original query has any CTEs, copy them into the rule action. But
555  * we don't need them for a utility action.
556  */
557  if (parsetree->cteList != NIL && sub_action->commandType != CMD_UTILITY)
558  {
559  /*
560  * Annoying implementation restriction: because CTEs are identified by
561  * name within a cteList, we can't merge a CTE from the original query
562  * if it has the same name as any CTE in the rule action.
563  *
564  * This could possibly be fixed by using some sort of internally
565  * generated ID, instead of names, to link CTE RTEs to their CTEs.
566  * However, decompiling the results would be quite confusing; note the
567  * merge of hasRecursive flags below, which could change the apparent
568  * semantics of such redundantly-named CTEs.
569  */
570  foreach(lc, parsetree->cteList)
571  {
572  CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
573  ListCell *lc2;
574 
575  foreach(lc2, sub_action->cteList)
576  {
577  CommonTableExpr *cte2 = (CommonTableExpr *) lfirst(lc2);
578 
579  if (strcmp(cte->ctename, cte2->ctename) == 0)
580  ereport(ERROR,
581  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
582  errmsg("WITH query name \"%s\" appears in both a rule action and the query being rewritten",
583  cte->ctename)));
584  }
585  }
586 
587  /* OK, it's safe to combine the CTE lists */
588  sub_action->cteList = list_concat(sub_action->cteList,
589  copyObject(parsetree->cteList));
590  /* ... and don't forget about the associated flags */
591  sub_action->hasRecursive |= parsetree->hasRecursive;
592  sub_action->hasModifyingCTE |= parsetree->hasModifyingCTE;
593 
594  /*
595  * If rule_action is different from sub_action (i.e., the rule action
596  * is an INSERT...SELECT), then we might have just added some
597  * data-modifying CTEs that are not at the top query level. This is
598  * disallowed by the parser and we mustn't generate such trees here
599  * either, so throw an error.
600  *
601  * Conceivably such cases could be supported by attaching the original
602  * query's CTEs to rule_action not sub_action. But to do that, we'd
603  * have to increment ctelevelsup in RTEs and SubLinks copied from the
604  * original query. For now, it doesn't seem worth the trouble.
605  */
606  if (sub_action->hasModifyingCTE && rule_action != sub_action)
607  ereport(ERROR,
608  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
609  errmsg("INSERT ... SELECT rule actions are not supported for queries having data-modifying statements in WITH")));
610  }
611 
612  /*
613  * Event Qualification forces copying of parsetree and splitting into two
614  * queries one w/rule_qual, one w/NOT rule_qual. Also add user query qual
615  * onto rule action
616  */
617  AddQual(sub_action, rule_qual);
618 
619  AddQual(sub_action, parsetree->jointree->quals);
620 
621  /*
622  * Rewrite new.attribute with right hand side of target-list entry for
623  * appropriate field name in insert/update.
624  *
625  * KLUGE ALERT: since ReplaceVarsFromTargetList returns a mutated copy, we
626  * can't just apply it to sub_action; we have to remember to update the
627  * sublink inside rule_action, too.
628  */
629  if ((event == CMD_INSERT || event == CMD_UPDATE) &&
630  sub_action->commandType != CMD_UTILITY)
631  {
632  sub_action = (Query *)
633  ReplaceVarsFromTargetList((Node *) sub_action,
634  new_varno,
635  0,
636  rt_fetch(new_varno, sub_action->rtable),
637  parsetree->targetList,
638  (event == CMD_UPDATE) ?
641  current_varno,
642  NULL);
643  if (sub_action_ptr)
644  *sub_action_ptr = sub_action;
645  else
646  rule_action = sub_action;
647  }
648 
649  /*
650  * If rule_action has a RETURNING clause, then either throw it away if the
651  * triggering query has no RETURNING clause, or rewrite it to emit what
652  * the triggering query's RETURNING clause asks for. Throw an error if
653  * more than one rule has a RETURNING clause.
654  */
655  if (!parsetree->returningList)
656  rule_action->returningList = NIL;
657  else if (rule_action->returningList)
658  {
659  if (*returning_flag)
660  ereport(ERROR,
661  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
662  errmsg("cannot have RETURNING lists in multiple rules")));
663  *returning_flag = true;
664  rule_action->returningList = (List *)
666  parsetree->resultRelation,
667  0,
668  rt_fetch(parsetree->resultRelation,
669  parsetree->rtable),
670  rule_action->returningList,
672  0,
673  &rule_action->hasSubLinks);
674 
675  /*
676  * There could have been some SubLinks in parsetree's returningList,
677  * in which case we'd better mark the rule_action correctly.
678  */
679  if (parsetree->hasSubLinks && !rule_action->hasSubLinks)
680  rule_action->hasSubLinks =
681  checkExprHasSubLink((Node *) rule_action->returningList);
682  }
683 
684  return rule_action;
685 }
@ RTE_FUNCTION
Definition: parsenodes.h:1020
@ RTE_TABLEFUNC
Definition: parsenodes.h:1021
static List * adjustJoinTreeList(Query *parsetree, bool removert, int rt_index)
void OffsetVarNodes(Node *node, int offset, int sublevels_up)
Definition: rewriteManip.c:480
bool checkExprHasSubLink(Node *node)
Definition: rewriteManip.c:295
Query * getInsertSelectQuery(Query *parsetree, Query ***subquery_ptr)
Definition: rewriteManip.c:998
void CombineRangeTables(List **dst_rtable, List **dst_perminfos, List *src_rtable, List *src_perminfos)
Definition: rewriteManip.c:350
void AddQual(Query *parsetree, Node *qual)
@ REPLACEVARS_REPORT_ERROR
Definition: rewriteManip.h:38
Node * quals
Definition: primnodes.h:2305
Node * setOperations
Definition: parsenodes.h:221
TableFunc * tablefunc
Definition: parsenodes.h:1184
List * functions
Definition: parsenodes.h:1177
bool contain_vars_of_level(Node *node, int levelsup)
Definition: var.c:446

References acquireLocksOnSubLinks(), AcquireRewriteLocks(), AddQual(), adjustJoinTreeList(), Assert, ChangeVarNodes(), checkExprHasSubLink(), CMD_INSERT, CMD_UPDATE, CMD_UTILITY, CombineRangeTables(), Query::commandType, contain_vars_of_level(), context, copyObject, Query::cteList, CommonTableExpr::ctename, ereport, errcode(), errmsg(), ERROR, FromExpr::fromlist, RangeTblEntry::functions, getInsertSelectQuery(), Query::jointree, lfirst, list_concat(), list_length(), NIL, OffsetVarNodes(), PRS2_NEW_VARNO, PRS2_OLD_VARNO, FromExpr::quals, rangeTableEntry_used(), REPLACEVARS_CHANGE_VARNO, REPLACEVARS_REPORT_ERROR, REPLACEVARS_SUBSTITUTE_NULL, ReplaceVarsFromTargetList(), Query::returningList, rt_fetch, Query::rtable, RTE_FUNCTION, RTE_RELATION, RTE_SUBQUERY, RTE_TABLEFUNC, RTE_VALUES, RangeTblEntry::rtekind, Query::setOperations, RangeTblEntry::subquery, RangeTblEntry::tablefunc, RangeTblEntry::tablesample, Query::targetList, and RangeTblEntry::values_lists.

Referenced by fireRules().

◆ rewriteTargetListIU()

static List * rewriteTargetListIU ( List targetList,
CmdType  commandType,
OverridingKind  override,
Relation  target_relation,
RangeTblEntry values_rte,
int  values_rte_index,
Bitmapset **  unused_values_attrnos 
)
static

Definition at line 758 of file rewriteHandler.c.

765 {
766  TargetEntry **new_tles;
767  List *new_tlist = NIL;
768  List *junk_tlist = NIL;
769  Form_pg_attribute att_tup;
770  int attrno,
771  next_junk_attrno,
772  numattrs;
773  ListCell *temp;
774  Bitmapset *default_only_cols = NULL;
775 
776  /*
777  * We process the normal (non-junk) attributes by scanning the input tlist
778  * once and transferring TLEs into an array, then scanning the array to
779  * build an output tlist. This avoids O(N^2) behavior for large numbers
780  * of attributes.
781  *
782  * Junk attributes are tossed into a separate list during the same tlist
783  * scan, then appended to the reconstructed tlist.
784  */
785  numattrs = RelationGetNumberOfAttributes(target_relation);
786  new_tles = (TargetEntry **) palloc0(numattrs * sizeof(TargetEntry *));
787  next_junk_attrno = numattrs + 1;
788 
789  foreach(temp, targetList)
790  {
791  TargetEntry *old_tle = (TargetEntry *) lfirst(temp);
792 
793  if (!old_tle->resjunk)
794  {
795  /* Normal attr: stash it into new_tles[] */
796  attrno = old_tle->resno;
797  if (attrno < 1 || attrno > numattrs)
798  elog(ERROR, "bogus resno %d in targetlist", attrno);
799  att_tup = TupleDescAttr(target_relation->rd_att, attrno - 1);
800 
801  /* We can (and must) ignore deleted attributes */
802  if (att_tup->attisdropped)
803  continue;
804 
805  /* Merge with any prior assignment to same attribute */
806  new_tles[attrno - 1] =
807  process_matched_tle(old_tle,
808  new_tles[attrno - 1],
809  NameStr(att_tup->attname));
810  }
811  else
812  {
813  /*
814  * Copy all resjunk tlist entries to junk_tlist, and assign them
815  * resnos above the last real resno.
816  *
817  * Typical junk entries include ORDER BY or GROUP BY expressions
818  * (are these actually possible in an INSERT or UPDATE?), system
819  * attribute references, etc.
820  */
821 
822  /* Get the resno right, but don't copy unnecessarily */
823  if (old_tle->resno != next_junk_attrno)
824  {
825  old_tle = flatCopyTargetEntry(old_tle);
826  old_tle->resno = next_junk_attrno;
827  }
828  junk_tlist = lappend(junk_tlist, old_tle);
829  next_junk_attrno++;
830  }
831  }
832 
833  for (attrno = 1; attrno <= numattrs; attrno++)
834  {
835  TargetEntry *new_tle = new_tles[attrno - 1];
836  bool apply_default;
837 
838  att_tup = TupleDescAttr(target_relation->rd_att, attrno - 1);
839 
840  /* We can (and must) ignore deleted attributes */
841  if (att_tup->attisdropped)
842  continue;
843 
844  /*
845  * Handle the two cases where we need to insert a default expression:
846  * it's an INSERT and there's no tlist entry for the column, or the
847  * tlist entry is a DEFAULT placeholder node.
848  */
849  apply_default = ((new_tle == NULL && commandType == CMD_INSERT) ||
850  (new_tle && new_tle->expr && IsA(new_tle->expr, SetToDefault)));
851 
852  if (commandType == CMD_INSERT)
853  {
854  int values_attrno = 0;
855 
856  /* Source attribute number for values that come from a VALUES RTE */
857  if (values_rte && new_tle && IsA(new_tle->expr, Var))
858  {
859  Var *var = (Var *) new_tle->expr;
860 
861  if (var->varno == values_rte_index)
862  values_attrno = var->varattno;
863  }
864 
865  /*
866  * Can only insert DEFAULT into GENERATED ALWAYS identity columns,
867  * unless either OVERRIDING USER VALUE or OVERRIDING SYSTEM VALUE
868  * is specified.
869  */
870  if (att_tup->attidentity == ATTRIBUTE_IDENTITY_ALWAYS && !apply_default)
871  {
872  if (override == OVERRIDING_USER_VALUE)
873  apply_default = true;
874  else if (override != OVERRIDING_SYSTEM_VALUE)
875  {
876  /*
877  * If this column's values come from a VALUES RTE, test
878  * whether it contains only SetToDefault items. Since the
879  * VALUES list might be quite large, we arrange to only
880  * scan it once.
881  */
882  if (values_attrno != 0)
883  {
884  if (default_only_cols == NULL)
885  default_only_cols = findDefaultOnlyColumns(values_rte);
886 
887  if (bms_is_member(values_attrno, default_only_cols))
888  apply_default = true;
889  }
890 
891  if (!apply_default)
892  ereport(ERROR,
893  (errcode(ERRCODE_GENERATED_ALWAYS),
894  errmsg("cannot insert a non-DEFAULT value into column \"%s\"",
895  NameStr(att_tup->attname)),
896  errdetail("Column \"%s\" is an identity column defined as GENERATED ALWAYS.",
897  NameStr(att_tup->attname)),
898  errhint("Use OVERRIDING SYSTEM VALUE to override.")));
899  }
900  }
901 
902  /*
903  * Although inserting into a GENERATED BY DEFAULT identity column
904  * is allowed, apply the default if OVERRIDING USER VALUE is
905  * specified.
906  */
907  if (att_tup->attidentity == ATTRIBUTE_IDENTITY_BY_DEFAULT &&
908  override == OVERRIDING_USER_VALUE)
909  apply_default = true;
910 
911  /*
912  * Can only insert DEFAULT into generated columns, regardless of
913  * any OVERRIDING clauses.
914  */
915  if (att_tup->attgenerated && !apply_default)
916  {
917  /*
918  * If this column's values come from a VALUES RTE, test
919  * whether it contains only SetToDefault items, as above.
920  */
921  if (values_attrno != 0)
922  {
923  if (default_only_cols == NULL)
924  default_only_cols = findDefaultOnlyColumns(values_rte);
925 
926  if (bms_is_member(values_attrno, default_only_cols))
927  apply_default = true;
928  }
929 
930  if (!apply_default)
931  ereport(ERROR,
932  (errcode(ERRCODE_GENERATED_ALWAYS),
933  errmsg("cannot insert a non-DEFAULT value into column \"%s\"",
934  NameStr(att_tup->attname)),
935  errdetail("Column \"%s\" is a generated column.",
936  NameStr(att_tup->attname))));
937  }
938 
939  /*
940  * For an INSERT from a VALUES RTE, return the attribute numbers
941  * of any VALUES columns that will no longer be used (due to the
942  * targetlist entry being replaced by a default expression).
943  */
944  if (values_attrno != 0 && apply_default && unused_values_attrnos)
945  *unused_values_attrnos = bms_add_member(*unused_values_attrnos,
946  values_attrno);
947  }
948 
949  /*
950  * Updates to identity and generated columns follow the same rules as
951  * above, except that UPDATE doesn't admit OVERRIDING clauses. Also,
952  * the source can't be a VALUES RTE, so we needn't consider that.
953  */
954  if (commandType == CMD_UPDATE)
955  {
956  if (att_tup->attidentity == ATTRIBUTE_IDENTITY_ALWAYS &&
957  new_tle && !apply_default)
958  ereport(ERROR,
959  (errcode(ERRCODE_GENERATED_ALWAYS),
960  errmsg("column \"%s\" can only be updated to DEFAULT",
961  NameStr(att_tup->attname)),
962  errdetail("Column \"%s\" is an identity column defined as GENERATED ALWAYS.",
963  NameStr(att_tup->attname))));
964 
965  if (att_tup->attgenerated && new_tle && !apply_default)
966  ereport(ERROR,
967  (errcode(ERRCODE_GENERATED_ALWAYS),
968  errmsg("column \"%s\" can only be updated to DEFAULT",
969  NameStr(att_tup->attname)),
970  errdetail("Column \"%s\" is a generated column.",
971  NameStr(att_tup->attname))));
972  }
973 
974  if (att_tup->attgenerated)
975  {
976  /*
977  * stored generated column will be fixed in executor
978  */
979  new_tle = NULL;
980  }
981  else if (apply_default)
982  {
983  Node *new_expr;
984 
985  new_expr = build_column_default(target_relation, attrno);
986 
987  /*
988  * If there is no default (ie, default is effectively NULL), we
989  * can omit the tlist entry in the INSERT case, since the planner
990  * can insert a NULL for itself, and there's no point in spending
991  * any more rewriter cycles on the entry. But in the UPDATE case
992  * we've got to explicitly set the column to NULL.
993  */
994  if (!new_expr)
995  {
996  if (commandType == CMD_INSERT)
997  new_tle = NULL;
998  else
999  {
1000  new_expr = (Node *) makeConst(att_tup->atttypid,
1001  -1,
1002  att_tup->attcollation,
1003  att_tup->attlen,
1004  (Datum) 0,
1005  true, /* isnull */
1006  att_tup->attbyval);
1007  /* this is to catch a NOT NULL domain constraint */
1008  new_expr = coerce_to_domain(new_expr,
1009  InvalidOid, -1,
1010  att_tup->atttypid,
1013  -1,
1014  false);
1015  }
1016  }
1017 
1018  if (new_expr)
1019  new_tle = makeTargetEntry((Expr *) new_expr,
1020  attrno,
1021  pstrdup(NameStr(att_tup->attname)),
1022  false);
1023  }
1024 
1025  if (new_tle)
1026  new_tlist = lappend(new_tlist, new_tle);
1027  }
1028 
1029  pfree(new_tles);
1030 
1031  return list_concat(new_tlist, junk_tlist);
1032 }
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:510
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77
Const * makeConst(Oid consttype, int32 consttypmod, Oid constcollid, int constlen, Datum constvalue, bool constisnull, bool constbyval)
Definition: makefuncs.c:301
void pfree(void *pointer)
Definition: mcxt.c:1521
void * palloc0(Size size)
Definition: mcxt.c:1347
Node * coerce_to_domain(Node *arg, Oid baseTypeId, int32 baseTypeMod, Oid typeId, CoercionContext ccontext, CoercionForm cformat, int location, bool hideInputCoercion)
Definition: parse_coerce.c:676
uintptr_t Datum
Definition: postgres.h:64
#define InvalidOid
Definition: postgres_ext.h:36
@ OVERRIDING_SYSTEM_VALUE
Definition: primnodes.h:29
@ OVERRIDING_USER_VALUE
Definition: primnodes.h:28
@ COERCION_IMPLICIT
Definition: primnodes.h:714
#define RelationGetNumberOfAttributes(relation)
Definition: rel.h:511
static TargetEntry * process_matched_tle(TargetEntry *src_tle, TargetEntry *prior_tle, const char *attrName)
static Bitmapset * findDefaultOnlyColumns(RangeTblEntry *rte)
Node * build_column_default(Relation rel, int attrno)
AttrNumber resno
Definition: primnodes.h:2188

References bms_add_member(), bms_is_member(), build_column_default(), CMD_INSERT, CMD_UPDATE, COERCE_IMPLICIT_CAST, coerce_to_domain(), COERCION_IMPLICIT, elog, ereport, errcode(), errdetail(), errhint(), errmsg(), ERROR, TargetEntry::expr, findDefaultOnlyColumns(), flatCopyTargetEntry(), if(), InvalidOid, IsA, lappend(), lfirst, list_concat(), makeConst(), makeTargetEntry(), NameStr, NIL, OVERRIDING_SYSTEM_VALUE, OVERRIDING_USER_VALUE, palloc0(), pfree(), process_matched_tle(), pstrdup(), RelationData::rd_att, RelationGetNumberOfAttributes, TargetEntry::resno, TupleDescAttr, Var::varattno, and Var::varno.

Referenced by RewriteQuery().

◆ rewriteTargetView()

static Query* rewriteTargetView ( Query parsetree,
Relation  view 
)
static

Definition at line 3171 of file rewriteHandler.c.

3172 {
3173  Query *viewquery;
3174  bool insert_or_update;
3175  const char *auto_update_detail;
3176  RangeTblRef *rtr;
3177  int base_rt_index;
3178  int new_rt_index;
3179  RangeTblEntry *base_rte;
3180  RangeTblEntry *view_rte;
3181  RangeTblEntry *new_rte;
3182  RTEPermissionInfo *base_perminfo;
3183  RTEPermissionInfo *view_perminfo;
3184  RTEPermissionInfo *new_perminfo;
3185  Relation base_rel;
3186  List *view_targetlist;
3187  ListCell *lc;
3188 
3189  /*
3190  * Get the Query from the view's ON SELECT rule. We're going to munge the
3191  * Query to change the view's base relation into the target relation,
3192  * along with various other changes along the way, so we need to make a
3193  * copy of it (get_view_query() returns a pointer into the relcache, so we
3194  * have to treat it as read-only).
3195  */
3196  viewquery = copyObject(get_view_query(view));
3197 
3198  /* Locate RTE and perminfo describing the view in the outer query */
3199  view_rte = rt_fetch(parsetree->resultRelation, parsetree->rtable);
3200  view_perminfo = getRTEPermissionInfo(parsetree->rteperminfos, view_rte);
3201 
3202  /*
3203  * Are we doing INSERT/UPDATE, or MERGE containing INSERT/UPDATE? If so,
3204  * various additional checks on the view columns need to be applied, and
3205  * any view CHECK OPTIONs need to be enforced.
3206  */
3207  insert_or_update =
3208  (parsetree->commandType == CMD_INSERT ||
3209  parsetree->commandType == CMD_UPDATE);
3210 
3211  if (parsetree->commandType == CMD_MERGE)
3212  {
3214  {
3215  if (action->commandType == CMD_INSERT ||
3216  action->commandType == CMD_UPDATE)
3217  {
3218  insert_or_update = true;
3219  break;
3220  }
3221  }
3222  }
3223 
3224  /* Check if the expansion of non-system views are restricted */
3227  ereport(ERROR,
3228  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3229  errmsg("access to non-system view \"%s\" is restricted",
3230  RelationGetRelationName(view))));
3231 
3232  /*
3233  * The view must be updatable, else fail.
3234  *
3235  * If we are doing INSERT/UPDATE (or MERGE containing INSERT/UPDATE), we
3236  * also check that there is at least one updatable column.
3237  */
3238  auto_update_detail =
3239  view_query_is_auto_updatable(viewquery, insert_or_update);
3240 
3241  if (auto_update_detail)
3243  parsetree->commandType,
3244  parsetree->mergeActionList,
3245  auto_update_detail);
3246 
3247  /*
3248  * For INSERT/UPDATE (or MERGE containing INSERT/UPDATE) the modified
3249  * columns must all be updatable.
3250  */
3251  if (insert_or_update)
3252  {
3253  Bitmapset *modified_cols;
3254  char *non_updatable_col;
3255 
3256  /*
3257  * Compute the set of modified columns as those listed in the result
3258  * RTE's insertedCols and/or updatedCols sets plus those that are
3259  * targets of the query's targetlist(s). We must consider the query's
3260  * targetlist because rewriteTargetListIU may have added additional
3261  * targetlist entries for view defaults, and these must also be
3262  * updatable. But rewriteTargetListIU can also remove entries if they
3263  * are DEFAULT markers and the column's default is NULL, so
3264  * considering only the targetlist would also be wrong.
3265  */
3266  modified_cols = bms_union(view_perminfo->insertedCols,
3267  view_perminfo->updatedCols);
3268 
3269  foreach(lc, parsetree->targetList)
3270  {
3271  TargetEntry *tle = (TargetEntry *) lfirst(lc);
3272 
3273  if (!tle->resjunk)
3274  modified_cols = bms_add_member(modified_cols,
3276  }
3277 
3278  if (parsetree->onConflict)
3279  {
3280  foreach(lc, parsetree->onConflict->onConflictSet)
3281  {
3282  TargetEntry *tle = (TargetEntry *) lfirst(lc);
3283 
3284  if (!tle->resjunk)
3285  modified_cols = bms_add_member(modified_cols,
3287  }
3288  }
3289 
3291  {
3292  if (action->commandType == CMD_INSERT ||
3293  action->commandType == CMD_UPDATE)
3294  {
3295  foreach_node(TargetEntry, tle, action->targetList)
3296  {
3297  if (!tle->resjunk)
3298  modified_cols = bms_add_member(modified_cols,
3300  }
3301  }
3302  }
3303 
3304  auto_update_detail = view_cols_are_auto_updatable(viewquery,
3305  modified_cols,
3306  NULL,
3307  &non_updatable_col);
3308  if (auto_update_detail)
3309  {
3310  /*
3311  * This is a different error, caused by an attempt to update a
3312  * non-updatable column in an otherwise updatable view.
3313  */
3314  switch (parsetree->commandType)
3315  {
3316  case CMD_INSERT:
3317  ereport(ERROR,
3318  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3319  errmsg("cannot insert into column \"%s\" of view \"%s\"",
3320  non_updatable_col,
3321  RelationGetRelationName(view)),
3322  errdetail_internal("%s", _(auto_update_detail))));
3323  break;
3324  case CMD_UPDATE:
3325  ereport(ERROR,
3326  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3327  errmsg("cannot update column \"%s\" of view \"%s\"",
3328  non_updatable_col,
3329  RelationGetRelationName(view)),
3330  errdetail_internal("%s", _(auto_update_detail))));
3331  break;
3332  case CMD_MERGE:
3333  ereport(ERROR,
3334  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3335  errmsg("cannot merge into column \"%s\" of view \"%s\"",
3336  non_updatable_col,
3337  RelationGetRelationName(view)),
3338  errdetail_internal("%s", _(auto_update_detail))));
3339  break;
3340  default:
3341  elog(ERROR, "unrecognized CmdType: %d",
3342  (int) parsetree->commandType);
3343  break;
3344  }
3345  }
3346  }
3347 
3348  /*
3349  * For MERGE, there must not be any INSTEAD OF triggers on an otherwise
3350  * updatable view. The caller already checked that there isn't a full set
3351  * of INSTEAD OF triggers, so this is to guard against having a partial
3352  * set (mixing auto-update and trigger-update actions in a single command
3353  * isn't supported).
3354  */
3355  if (parsetree->commandType == CMD_MERGE)
3356  {
3358  {
3359  if (action->commandType != CMD_NOTHING &&
3360  view_has_instead_trigger(view, action->commandType, NIL))
3361  ereport(ERROR,
3362  errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3363  errmsg("cannot merge into view \"%s\"",
3364  RelationGetRelationName(view)),
3365  errdetail("MERGE is not supported for views with INSTEAD OF triggers for some actions but not all."),
3366  errhint("To enable merging into the view, either provide a full set of INSTEAD OF triggers or drop the existing INSTEAD OF triggers."));
3367  }
3368  }
3369 
3370  /*
3371  * If we get here, view_query_is_auto_updatable() has verified that the
3372  * view contains a single base relation.
3373  */
3374  Assert(list_length(viewquery->jointree->fromlist) == 1);
3375  rtr = linitial_node(RangeTblRef, viewquery->jointree->fromlist);
3376 
3377  base_rt_index = rtr->rtindex;
3378  base_rte = rt_fetch(base_rt_index, viewquery->rtable);
3379  Assert(base_rte->rtekind == RTE_RELATION);
3380  base_perminfo = getRTEPermissionInfo(viewquery->rteperminfos, base_rte);
3381 
3382  /*
3383  * Up to now, the base relation hasn't been touched at all in our query.
3384  * We need to acquire lock on it before we try to do anything with it.
3385  * (The subsequent recursive call of RewriteQuery will suppose that we
3386  * already have the right lock!) Since it will become the query target
3387  * relation, RowExclusiveLock is always the right thing.
3388  */
3389  base_rel = table_open(base_rte->relid, RowExclusiveLock);
3390 
3391  /*
3392  * While we have the relation open, update the RTE's relkind, just in case
3393  * it changed since this view was made (cf. AcquireRewriteLocks).
3394  */
3395  base_rte->relkind = base_rel->rd_rel->relkind;
3396 
3397  /*
3398  * If the view query contains any sublink subqueries then we need to also
3399  * acquire locks on any relations they refer to. We know that there won't
3400  * be any subqueries in the range table or CTEs, so we can skip those, as
3401  * in AcquireRewriteLocks.
3402  */
3403  if (viewquery->hasSubLinks)
3404  {
3406 
3407  context.for_execute = true;
3410  }
3411 
3412  /*
3413  * Create a new target RTE describing the base relation, and add it to the
3414  * outer query's rangetable. (What's happening in the next few steps is
3415  * very much like what the planner would do to "pull up" the view into the
3416  * outer query. Perhaps someday we should refactor things enough so that
3417  * we can share code with the planner.)
3418  *
3419  * Be sure to set rellockmode to the correct thing for the target table.
3420  * Since we copied the whole viewquery above, we can just scribble on
3421  * base_rte instead of copying it.
3422  */
3423  new_rte = base_rte;
3424  new_rte->rellockmode = RowExclusiveLock;
3425 
3426  parsetree->rtable = lappend(parsetree->rtable, new_rte);
3427  new_rt_index = list_length(parsetree->rtable);
3428 
3429  /*
3430  * INSERTs never inherit. For UPDATE/DELETE/MERGE, we use the view
3431  * query's inheritance flag for the base relation.
3432  */
3433  if (parsetree->commandType == CMD_INSERT)
3434  new_rte->inh = false;
3435 
3436  /*
3437  * Adjust the view's targetlist Vars to reference the new target RTE, ie
3438  * make their varnos be new_rt_index instead of base_rt_index. There can
3439  * be no Vars for other rels in the tlist, so this is sufficient to pull
3440  * up the tlist expressions for use in the outer query. The tlist will
3441  * provide the replacement expressions used by ReplaceVarsFromTargetList
3442  * below.
3443  */
3444  view_targetlist = viewquery->targetList;
3445 
3446  ChangeVarNodes((Node *) view_targetlist,
3447  base_rt_index,
3448  new_rt_index,
3449  0);
3450 
3451  /*
3452  * If the view has "security_invoker" set, mark the new target relation
3453  * for the permissions checks that we want to enforce against the query
3454  * caller. Otherwise we want to enforce them against the view owner.
3455  *
3456  * At the relation level, require the same INSERT/UPDATE/DELETE
3457  * permissions that the query caller needs against the view. We drop the
3458  * ACL_SELECT bit that is presumably in new_perminfo->requiredPerms
3459  * initially.
3460  *
3461  * Note: the original view's RTEPermissionInfo remains in the query's
3462  * rteperminfos so that the executor still performs appropriate
3463  * permissions checks for the query caller's use of the view.
3464  *
3465  * Disregard the perminfo in viewquery->rteperminfos that the base_rte
3466  * would currently be pointing at, because we'd like it to point now to a
3467  * new one that will be filled below. Must set perminfoindex to 0 to not
3468  * trip over the Assert in addRTEPermissionInfo().
3469  */
3470  new_rte->perminfoindex = 0;
3471  new_perminfo = addRTEPermissionInfo(&parsetree->rteperminfos, new_rte);
3472  if (RelationHasSecurityInvoker(view))
3473  new_perminfo->checkAsUser = InvalidOid;
3474  else
3475  new_perminfo->checkAsUser = view->rd_rel->relowner;
3476  new_perminfo->requiredPerms = view_perminfo->requiredPerms;
3477 
3478  /*
3479  * Now for the per-column permissions bits.
3480  *
3481  * Initially, new_perminfo (base_perminfo) contains selectedCols
3482  * permission check bits for all base-rel columns referenced by the view,
3483  * but since the view is a SELECT query its insertedCols/updatedCols is
3484  * empty. We set insertedCols and updatedCols to include all the columns
3485  * the outer query is trying to modify, adjusting the column numbers as
3486  * needed. But we leave selectedCols as-is, so the view owner must have
3487  * read permission for all columns used in the view definition, even if
3488  * some of them are not read by the outer query. We could try to limit
3489  * selectedCols to only columns used in the transformed query, but that
3490  * does not correspond to what happens in ordinary SELECT usage of a view:
3491  * all referenced columns must have read permission, even if optimization
3492  * finds that some of them can be discarded during query transformation.
3493  * The flattening we're doing here is an optional optimization, too. (If
3494  * you are unpersuaded and want to change this, note that applying
3495  * adjust_view_column_set to view_perminfo->selectedCols is clearly *not*
3496  * the right answer, since that neglects base-rel columns used in the
3497  * view's WHERE quals.)
3498  *
3499  * This step needs the modified view targetlist, so we have to do things
3500  * in this order.
3501  */
3502  Assert(bms_is_empty(new_perminfo->insertedCols) &&
3503  bms_is_empty(new_perminfo->updatedCols));
3504 
3505  new_perminfo->selectedCols = base_perminfo->selectedCols;
3506 
3507  new_perminfo->insertedCols =
3508  adjust_view_column_set(view_perminfo->insertedCols, view_targetlist);
3509 
3510  new_perminfo->updatedCols =
3511  adjust_view_column_set(view_perminfo->updatedCols, view_targetlist);
3512 
3513  /*
3514  * Move any security barrier quals from the view RTE onto the new target
3515  * RTE. Any such quals should now apply to the new target RTE and will
3516  * not reference the original view RTE in the rewritten query.
3517  */
3518  new_rte->securityQuals = view_rte->securityQuals;
3519  view_rte->securityQuals = NIL;
3520 
3521  /*
3522  * Now update all Vars in the outer query that reference the view to
3523  * reference the appropriate column of the base relation instead.
3524  */
3525  parsetree = (Query *)
3526  ReplaceVarsFromTargetList((Node *) parsetree,
3527  parsetree->resultRelation,
3528  0,
3529  view_rte,
3530  view_targetlist,
3532  0,
3533  NULL);
3534 
3535  /*
3536  * Update all other RTI references in the query that point to the view
3537  * (for example, parsetree->resultRelation itself) to point to the new
3538  * base relation instead. Vars will not be affected since none of them
3539  * reference parsetree->resultRelation any longer.
3540  */
3541  ChangeVarNodes((Node *) parsetree,
3542  parsetree->resultRelation,
3543  new_rt_index,
3544  0);
3545  Assert(parsetree->resultRelation == new_rt_index);
3546 
3547  /*
3548  * For INSERT/UPDATE we must also update resnos in the targetlist to refer
3549  * to columns of the base relation, since those indicate the target
3550  * columns to be affected. Similarly, for MERGE we must update the resnos
3551  * in the merge action targetlists of any INSERT/UPDATE actions.
3552  *
3553  * Note that this destroys the resno ordering of the targetlists, but that
3554  * will be fixed when we recurse through RewriteQuery, which will invoke
3555  * rewriteTargetListIU again on the updated targetlists.
3556  */
3557  if (parsetree->commandType != CMD_DELETE)
3558  {
3559  foreach(lc, parsetree->targetList)
3560  {
3561  TargetEntry *tle = (TargetEntry *) lfirst(lc);
3562  TargetEntry *view_tle;
3563 
3564  if (tle->resjunk)
3565  continue;
3566 
3567  view_tle = get_tle_by_resno(view_targetlist, tle->resno);
3568  if (view_tle != NULL && !view_tle->resjunk && IsA(view_tle->expr, Var))
3569  tle->resno = ((Var *) view_tle->expr)->varattno;
3570  else
3571  elog(ERROR, "attribute number %d not found in view targetlist",
3572  tle->resno);
3573  }
3574 
3576  {
3577  if (action->commandType == CMD_INSERT ||
3578  action->commandType == CMD_UPDATE)
3579  {
3580  foreach_node(TargetEntry, tle, action->targetList)
3581  {
3582  TargetEntry *view_tle;
3583 
3584  if (tle->resjunk)
3585  continue;
3586 
3587  view_tle = get_tle_by_resno(view_targetlist, tle->resno);
3588  if (view_tle != NULL && !view_tle->resjunk && IsA(view_tle->expr, Var))
3589  tle->resno = ((Var *) view_tle->expr)->varattno;
3590  else
3591  elog(ERROR, "attribute number %d not found in view targetlist",
3592  tle->resno);
3593  }
3594  }
3595  }
3596  }
3597 
3598  /*
3599  * For INSERT .. ON CONFLICT .. DO UPDATE, we must also update assorted
3600  * stuff in the onConflict data structure.
3601  */
3602  if (parsetree->onConflict &&
3603  parsetree->onConflict->action == ONCONFLICT_UPDATE)
3604  {
3605  Index old_exclRelIndex,
3606  new_exclRelIndex;
3607  ParseNamespaceItem *new_exclNSItem;
3608  RangeTblEntry *new_exclRte;
3609  List *tmp_tlist;
3610 
3611  /*
3612  * Like the INSERT/UPDATE code above, update the resnos in the
3613  * auxiliary UPDATE targetlist to refer to columns of the base
3614  * relation.
3615  */
3616  foreach(lc, parsetree->onConflict->onConflictSet)
3617  {
3618  TargetEntry *tle = (TargetEntry *) lfirst(lc);
3619  TargetEntry *view_tle;
3620 
3621  if (tle->resjunk)
3622  continue;
3623 
3624  view_tle = get_tle_by_resno(view_targetlist, tle->resno);
3625  if (view_tle != NULL && !view_tle->resjunk && IsA(view_tle->expr, Var))
3626  tle->resno = ((Var *) view_tle->expr)->varattno;
3627  else
3628  elog(ERROR, "attribute number %d not found in view targetlist",
3629  tle->resno);
3630  }
3631 
3632  /*
3633  * Also, create a new RTE for the EXCLUDED pseudo-relation, using the
3634  * query's new base rel (which may well have a different column list
3635  * from the view, hence we need a new column alias list). This should
3636  * match transformOnConflictClause. In particular, note that the
3637  * relkind is set to composite to signal that we're not dealing with
3638  * an actual relation.
3639  */
3640  old_exclRelIndex = parsetree->onConflict->exclRelIndex;
3641 
3642  new_exclNSItem = addRangeTableEntryForRelation(make_parsestate(NULL),
3643  base_rel,
3645  makeAlias("excluded", NIL),
3646  false, false);
3647  new_exclRte = new_exclNSItem->p_rte;
3648  new_exclRte->relkind = RELKIND_COMPOSITE_TYPE;
3649  /* Ignore the RTEPermissionInfo that would've been added. */
3650  new_exclRte->perminfoindex = 0;
3651 
3652  parsetree->rtable = lappend(parsetree->rtable, new_exclRte);
3653  new_exclRelIndex = parsetree->onConflict->exclRelIndex =
3654  list_length(parsetree->rtable);
3655 
3656  /*
3657  * Replace the targetlist for the EXCLUDED pseudo-relation with a new
3658  * one, representing the columns from the new base relation.
3659  */
3660  parsetree->onConflict->exclRelTlist =
3661  BuildOnConflictExcludedTargetlist(base_rel, new_exclRelIndex);
3662 
3663  /*
3664  * Update all Vars in the ON CONFLICT clause that refer to the old
3665  * EXCLUDED pseudo-relation. We want to use the column mappings
3666  * defined in the view targetlist, but we need the outputs to refer to
3667  * the new EXCLUDED pseudo-relation rather than the new target RTE.
3668  * Also notice that "EXCLUDED.*" will be expanded using the view's
3669  * rowtype, which seems correct.
3670  */
3671  tmp_tlist = copyObject(view_targetlist);
3672 
3673  ChangeVarNodes((Node *) tmp_tlist, new_rt_index,
3674  new_exclRelIndex, 0);
3675 
3676  parsetree->onConflict = (OnConflictExpr *)
3677  ReplaceVarsFromTargetList((Node *) parsetree->onConflict,
3678  old_exclRelIndex,
3679  0,
3680  view_rte,
3681  tmp_tlist,
3683  0,
3684  &parsetree->hasSubLinks);
3685  }
3686 
3687  /*
3688  * For UPDATE/DELETE/MERGE, pull up any WHERE quals from the view. We
3689  * know that any Vars in the quals must reference the one base relation,
3690  * so we need only adjust their varnos to reference the new target (just
3691  * the same as we did with the view targetlist).
3692  *
3693  * If it's a security-barrier view, its WHERE quals must be applied before
3694  * quals from the outer query, so we attach them to the RTE as security
3695  * barrier quals rather than adding them to the main WHERE clause.
3696  *
3697  * For INSERT, the view's quals can be ignored in the main query.
3698  */
3699  if (parsetree->commandType != CMD_INSERT &&
3700  viewquery->jointree->quals != NULL)
3701  {
3702  Node *viewqual = (Node *) viewquery->jointree->quals;
3703 
3704  /*
3705  * Even though we copied viewquery already at the top of this
3706  * function, we must duplicate the viewqual again here, because we may
3707  * need to use the quals again below for a WithCheckOption clause.
3708  */
3709  viewqual = copyObject(viewqual);
3710 
3711  ChangeVarNodes(viewqual, base_rt_index, new_rt_index, 0);
3712 
3713  if (RelationIsSecurityView(view))
3714  {
3715  /*
3716  * The view's quals go in front of existing barrier quals: those
3717  * would have come from an outer level of security-barrier view,
3718  * and so must get evaluated later.
3719  *
3720  * Note: the parsetree has been mutated, so the new_rte pointer is
3721  * stale and needs to be re-computed.
3722  */
3723  new_rte = rt_fetch(new_rt_index, parsetree->rtable);
3724  new_rte->securityQuals = lcons(viewqual, new_rte->securityQuals);
3725 
3726  /*
3727  * Do not set parsetree->hasRowSecurity, because these aren't RLS
3728  * conditions (they aren't affected by enabling/disabling RLS).
3729  */
3730 
3731  /*
3732  * Make sure that the query is marked correctly if the added qual
3733  * has sublinks.
3734  */
3735  if (!parsetree->hasSubLinks)
3736  parsetree->hasSubLinks = checkExprHasSubLink(viewqual);
3737  }
3738  else
3739  AddQual(parsetree, (Node *) viewqual);
3740  }
3741 
3742  /*
3743  * For INSERT/UPDATE (or MERGE containing INSERT/UPDATE), if the view has
3744  * the WITH CHECK OPTION, or any parent view specified WITH CASCADED CHECK
3745  * OPTION, add the quals from the view to the query's withCheckOptions
3746  * list.
3747  */
3748  if (insert_or_update)
3749  {
3750  bool has_wco = RelationHasCheckOption(view);
3751  bool cascaded = RelationHasCascadedCheckOption(view);
3752 
3753  /*
3754  * If the parent view has a cascaded check option, treat this view as
3755  * if it also had a cascaded check option.
3756  *
3757  * New WithCheckOptions are added to the start of the list, so if
3758  * there is a cascaded check option, it will be the first item in the
3759  * list.
3760  */
3761  if (parsetree->withCheckOptions != NIL)
3762  {
3763  WithCheckOption *parent_wco =
3764  (WithCheckOption *) linitial(parsetree->withCheckOptions);
3765 
3766  if (parent_wco->cascaded)
3767  {
3768  has_wco = true;
3769  cascaded = true;
3770  }
3771  }
3772 
3773  /*
3774  * Add the new WithCheckOption to the start of the list, so that
3775  * checks on inner views are run before checks on outer views, as
3776  * required by the SQL standard.
3777  *
3778  * If the new check is CASCADED, we need to add it even if this view
3779  * has no quals, since there may be quals on child views. A LOCAL
3780  * check can be omitted if this view has no quals.
3781  */
3782  if (has_wco && (cascaded || viewquery->jointree->quals != NULL))
3783  {
3784  WithCheckOption *wco;
3785 
3786  wco = makeNode(WithCheckOption);
3787  wco->kind = WCO_VIEW_CHECK;
3788  wco->relname = pstrdup(RelationGetRelationName(view));
3789  wco->polname = NULL;
3790  wco->qual = NULL;
3791  wco->cascaded = cascaded;
3792 
3793  parsetree->withCheckOptions = lcons(wco,
3794  parsetree->withCheckOptions);
3795 
3796  if (viewquery->jointree->quals != NULL)
3797  {
3798  wco->qual = (Node *) viewquery->jointree->quals;
3799  ChangeVarNodes(wco->qual, base_rt_index, new_rt_index, 0);
3800 
3801  /*
3802  * For INSERT, make sure that the query is marked correctly if
3803  * the added qual has sublinks. This can be skipped for
3804  * UPDATE/MERGE, since the same qual will have already been
3805  * added above, and the check will already have been done.
3806  */
3807  if (!parsetree->hasSubLinks &&
3808  parsetree->commandType == CMD_INSERT)
3809  parsetree->hasSubLinks = checkExprHasSubLink(wco->qual);
3810  }
3811  }
3812  }
3813 
3814  table_close(base_rel, NoLock);
3815 
3816  return parsetree;
3817 }
Bitmapset * bms_union(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:251
#define RowExclusiveLock
Definition: lockdefs.h:38
Alias * makeAlias(const char *aliasname, List *colnames)
Definition: makefuncs.c:389
ParseState * make_parsestate(ParseState *parentParseState)
Definition: parse_node.c:39
RTEPermissionInfo * addRTEPermissionInfo(List **rteperminfos, RangeTblEntry *rte)
ParseNamespaceItem * addRangeTableEntryForRelation(ParseState *pstate, Relation rel, int lockmode, Alias *alias, bool inh, bool inFromCl)
@ WCO_VIEW_CHECK
Definition: parsenodes.h:1359
List * BuildOnConflictExcludedTargetlist(Relation targetrel, Index exclRelIndex)
Definition: analyze.c:1231
#define RelationHasCheckOption(relation)
Definition: rel.h:446
#define RelationHasSecurityInvoker(relation)
Definition: rel.h:436
#define RelationHasCascadedCheckOption(relation)
Definition: rel.h:468
List * exclRelTlist
Definition: primnodes.h:2332
RangeTblEntry * p_rte
Definition: parse_node.h:290
Bitmapset * selectedCols
Definition: parsenodes.h:1293
Bitmapset * insertedCols
Definition: parsenodes.h:1294
Bitmapset * updatedCols
Definition: parsenodes.h:1295

References _, acquireLocksOnSubLinks(), generate_unaccent_rules::action, OnConflictExpr::action, AddQual(), addRangeTableEntryForRelation(), addRTEPermissionInfo(), adjust_view_column_set(), Assert, bms_add_member(), bms_is_empty, bms_union(), BuildOnConflictExcludedTargetlist(), WithCheckOption::cascaded, ChangeVarNodes(), RTEPermissionInfo::checkAsUser, checkExprHasSubLink(), CMD_DELETE, CMD_INSERT, CMD_MERGE, CMD_NOTHING, CMD_UPDATE, Query::commandType, context, copyObject, elog, ereport, errcode(), errdetail(), errdetail_internal(), errhint(), errmsg(), ERROR, error_view_not_updatable(), OnConflictExpr::exclRelIndex, OnConflictExpr::exclRelTlist, TargetEntry::expr, FirstLowInvalidHeapAttributeNumber, FirstNormalObjectId, foreach_node, FromExpr::fromlist, get_tle_by_resno(), get_view_query(), getRTEPermissionInfo(), RangeTblEntry::inh, RTEPermissionInfo::insertedCols, InvalidOid, IsA, Query::jointree, WithCheckOption::kind, lappend(), lcons(), lfirst, linitial, linitial_node, list_length(), make_parsestate(), makeAlias(), makeNode, Query::mergeActionList, NIL, NoLock, Query::onConflict, ONCONFLICT_UPDATE, OnConflictExpr::onConflictSet, ParseNamespaceItem::p_rte, WithCheckOption::polname, pstrdup(), QTW_IGNORE_RC_SUBQUERIES, WithCheckOption::qual, FromExpr::quals, query_tree_walker, RelationData::rd_rel, RelationGetRelationName, RelationGetRelid, RelationHasCascadedCheckOption, RelationHasCheckOption, RelationHasSecurityInvoker, RelationIsSecurityView, RangeTblEntry::relid, WithCheckOption::relname, REPLACEVARS_REPORT_ERROR, ReplaceVarsFromTargetList(), RTEPermissionInfo::requiredPerms, TargetEntry::resno, restrict_nonsystem_relation_kind, RESTRICT_RELKIND_VIEW, RowExclusiveLock, rt_fetch, Query::rtable, RTE_RELATION, RangeTblEntry::rtekind, RangeTblRef::rtindex, RTEPermissionInfo::selectedCols, table_close(), table_open(), Query::targetList, unlikely, RTEPermissionInfo::updatedCols, view_cols_are_auto_updatable(), view_has_instead_trigger(), view_query_is_auto_updatable(), and WCO_VIEW_CHECK.

Referenced by RewriteQuery().

◆ rewriteValuesRTE()

static bool rewriteValuesRTE ( Query parsetree,
RangeTblEntry rte,
int  rti,
Relation  target_relation,
Bitmapset unused_cols 
)
static

Definition at line 1409 of file rewriteHandler.c.

1412 {
1413  List *newValues;
1414  ListCell *lc;
1415  bool isAutoUpdatableView;
1416  bool allReplaced;
1417  int numattrs;
1418  int *attrnos;
1419 
1420  /* Steps below are not sensible for non-INSERT queries */
1421  Assert(parsetree->commandType == CMD_INSERT);
1422  Assert(rte->rtekind == RTE_VALUES);
1423 
1424  /*
1425  * Rebuilding all the lists is a pretty expensive proposition in a big
1426  * VALUES list, and it's a waste of time if there aren't any DEFAULT
1427  * placeholders. So first scan to see if there are any.
1428  */
1429  if (!searchForDefault(rte))
1430  return true; /* nothing to do */
1431 
1432  /*
1433  * Scan the targetlist for entries referring to the VALUES RTE, and note
1434  * the target attributes. As noted above, we should only need to do this
1435  * for targetlist entries containing simple Vars --- nothing else in the
1436  * VALUES RTE should contain DEFAULT items (except possibly for unused
1437  * columns), and we complain if such a thing does occur.
1438  */
1439  numattrs = list_length(linitial(rte->values_lists));
1440  attrnos = (int *) palloc0(numattrs * sizeof(int));
1441 
1442  foreach(lc, parsetree->targetList)
1443  {
1444  TargetEntry *tle = (TargetEntry *) lfirst(lc);
1445 
1446  if (IsA(tle->expr, Var))
1447  {
1448  Var *var = (Var *) tle->expr;
1449 
1450  if (var->varno == rti)
1451  {
1452  int attrno = var->varattno;
1453 
1454  Assert(attrno >= 1 && attrno <= numattrs);
1455  attrnos[attrno - 1] = tle->resno;
1456  }
1457  }
1458  }
1459 
1460  /*
1461  * Check if the target relation is an auto-updatable view, in which case
1462  * unresolved defaults will be left untouched rather than being set to
1463  * NULL.
1464  */
1465  isAutoUpdatableView = false;
1466  if (target_relation->rd_rel->relkind == RELKIND_VIEW &&
1467  !view_has_instead_trigger(target_relation, CMD_INSERT, NIL))
1468  {
1469  List *locks;
1470  bool hasUpdate;
1471  bool found;
1472  ListCell *l;
1473 
1474  /* Look for an unconditional DO INSTEAD rule */
1475  locks = matchLocks(CMD_INSERT, target_relation,
1476  parsetree->resultRelation, parsetree, &hasUpdate);
1477 
1478  found = false;
1479  foreach(l, locks)
1480  {
1481  RewriteRule *rule_lock = (RewriteRule *) lfirst(l);
1482 
1483  if (rule_lock->isInstead &&
1484  rule_lock->qual == NULL)
1485  {
1486  found = true;
1487  break;
1488  }
1489  }
1490 
1491  /*
1492  * If we didn't find an unconditional DO INSTEAD rule, assume that the
1493  * view is auto-updatable. If it isn't, rewriteTargetView() will
1494  * throw an error.
1495  */
1496  if (!found)
1497  isAutoUpdatableView = true;
1498  }
1499 
1500  newValues = NIL;
1501  allReplaced = true;
1502  foreach(lc, rte->values_lists)
1503  {
1504  List *sublist = (List *) lfirst(lc);
1505  List *newList = NIL;
1506  ListCell *lc2;
1507  int i;
1508 
1509  Assert(list_length(sublist) == numattrs);
1510 
1511  i = 0;
1512  foreach(lc2, sublist)
1513  {
1514  Node *col = (Node *) lfirst(lc2);
1515  int attrno = attrnos[i++];
1516 
1517  if (IsA(col, SetToDefault))
1518  {
1519  Form_pg_attribute att_tup;
1520  Node *new_expr;
1521 
1522  /*
1523  * If this column isn't used, just replace the DEFAULT with
1524  * NULL (attrno will be 0 in this case because the targetlist
1525  * entry will have been replaced by the default expression).
1526  */
1527  if (bms_is_member(i, unused_cols))
1528  {
1529  SetToDefault *def = (SetToDefault *) col;
1530 
1531  newList = lappend(newList,
1532  makeNullConst(def->typeId,
1533  def->typeMod,
1534  def->collation));
1535  continue;
1536  }
1537 
1538  if (attrno == 0)
1539  elog(ERROR, "cannot set value in column %d to DEFAULT", i);
1540  Assert(attrno > 0 && attrno <= target_relation->rd_att->natts);
1541  att_tup = TupleDescAttr(target_relation->rd_att, attrno - 1);
1542 
1543  if (!att_tup->attisdropped)
1544  new_expr = build_column_default(target_relation, attrno);
1545  else
1546  new_expr = NULL; /* force a NULL if dropped */
1547 
1548  /*
1549  * If there is no default (ie, default is effectively NULL),
1550  * we've got to explicitly set the column to NULL, unless the
1551  * target relation is an auto-updatable view.
1552  */
1553  if (!new_expr)
1554  {
1555  if (isAutoUpdatableView)
1556  {
1557  /* Leave the value untouched */
1558  newList = lappend(newList, col);
1559  allReplaced = false;
1560  continue;
1561  }
1562 
1563  new_expr = (Node *) makeConst(att_tup->atttypid,
1564  -1,
1565  att_tup->attcollation,
1566  att_tup->attlen,
1567  (Datum) 0,
1568  true, /* isnull */
1569  att_tup->attbyval);
1570  /* this is to catch a NOT NULL domain constraint */
1571  new_expr = coerce_to_domain(new_expr,
1572  InvalidOid, -1,
1573  att_tup->atttypid,
1576  -1,
1577  false);
1578  }
1579  newList = lappend(newList, new_expr);
1580  }
1581  else
1582  newList = lappend(newList, col);
1583  }
1584  newValues = lappend(newValues, newList);
1585  }
1586  rte->values_lists = newValues;
1587 
1588  pfree(attrnos);
1589 
1590  return allReplaced;
1591 }
Const * makeNullConst(Oid consttype, int32 consttypmod, Oid constcollid)
Definition: makefuncs.c:339
static bool searchForDefault(RangeTblEntry *rte)

References Assert, bms_is_member(), build_column_default(), CMD_INSERT, COERCE_IMPLICIT_CAST, coerce_to_domain(), COERCION_IMPLICIT, Query::commandType, elog, ERROR, TargetEntry::expr, i, if(), InvalidOid, IsA, RewriteRule::isInstead, lappend(), lfirst, linitial, list_length(), makeConst(), makeNullConst(), matchLocks(), NIL, palloc0(), pfree(), RewriteRule::qual, RelationData::rd_att, RelationData::rd_rel, TargetEntry::resno, RTE_VALUES, RangeTblEntry::rtekind, searchForDefault(), Query::targetList, TupleDescAttr, SetToDefault::typeId, RangeTblEntry::values_lists, Var::varattno, Var::varno, and view_has_instead_trigger().

Referenced by RewriteQuery().

◆ rewriteValuesRTEToNulls()

static void rewriteValuesRTEToNulls ( Query parsetree,
RangeTblEntry rte 
)
static

Definition at line 1604 of file rewriteHandler.c.

1605 {
1606  List *newValues;
1607  ListCell *lc;
1608 
1609  newValues = NIL;
1610  foreach(lc, rte->values_lists)
1611  {
1612  List *sublist = (List *) lfirst(lc);
1613  List *newList = NIL;
1614  ListCell *lc2;
1615 
1616  foreach(lc2, sublist)
1617  {
1618  Node *col = (Node *) lfirst(lc2);
1619 
1620  if (IsA(col, SetToDefault))
1621  {
1622  SetToDefault *def = (SetToDefault *) col;
1623 
1624  newList = lappend(newList, makeNullConst(def->typeId,
1625  def->typeMod,
1626  def->collation));
1627  }
1628  else
1629  newList = lappend(newList, col);
1630  }
1631  newValues = lappend(newValues, newList);
1632  }
1633  rte->values_lists = newValues;
1634 }

References IsA, lappend(), lfirst, makeNullConst(), NIL, SetToDefault::typeId, and RangeTblEntry::values_lists.

Referenced by RewriteQuery().

◆ searchForDefault()

static bool searchForDefault ( RangeTblEntry rte)
static

Definition at line 1295 of file rewriteHandler.c.

1296 {
1297  ListCell *lc;
1298 
1299  foreach(lc, rte->values_lists)
1300  {
1301  List *sublist = (List *) lfirst(lc);
1302  ListCell *lc2;
1303 
1304  foreach(lc2, sublist)
1305  {
1306  Node *col = (Node *) lfirst(lc2);
1307 
1308  if (IsA(col, SetToDefault))
1309  return true;
1310  }
1311  }
1312  return false;
1313 }

References IsA, lfirst, and RangeTblEntry::values_lists.

Referenced by rewriteValuesRTE().

◆ view_col_is_auto_updatable()

static const char* view_col_is_auto_updatable ( RangeTblRef rtr,
TargetEntry tle 
)
static

Definition at line 2542 of file rewriteHandler.c.

2543 {
2544  Var *var = (Var *) tle->expr;
2545 
2546  /*
2547  * For now, the only updatable columns we support are those that are Vars
2548  * referring to user columns of the underlying base relation.
2549  *
2550  * The view targetlist may contain resjunk columns (e.g., a view defined
2551  * like "SELECT * FROM t ORDER BY a+b" is auto-updatable) but such columns
2552  * are not auto-updatable, and in fact should never appear in the outer
2553  * query's targetlist.
2554  */
2555  if (tle->resjunk)
2556  return gettext_noop("Junk view columns are not updatable.");
2557 
2558  if (!IsA(var, Var) ||
2559  var->varno != rtr->rtindex ||
2560  var->varlevelsup != 0)
2561  return gettext_noop("View columns that are not columns of their base relation are not updatable.");
2562 
2563  if (var->varattno < 0)
2564  return gettext_noop("View columns that refer to system columns are not updatable.");
2565 
2566  if (var->varattno == 0)
2567  return gettext_noop("View columns that return whole-row references are not updatable.");
2568 
2569  return NULL; /* the view column is updatable */
2570 }

References TargetEntry::expr, gettext_noop, if(), IsA, RangeTblRef::rtindex, Var::varattno, Var::varlevelsup, and Var::varno.

Referenced by view_cols_are_auto_updatable(), and view_query_is_auto_updatable().

◆ view_cols_are_auto_updatable()

static const char* view_cols_are_auto_updatable ( Query viewquery,
Bitmapset required_cols,
Bitmapset **  updatable_cols,
char **  non_updatable_col 
)
static

Definition at line 2738 of file rewriteHandler.c.

2742 {
2743  RangeTblRef *rtr;
2744  AttrNumber col;
2745  ListCell *cell;
2746 
2747  /*
2748  * The caller should have verified that this view is auto-updatable and so
2749  * there should be a single base relation.
2750  */
2751  Assert(list_length(viewquery->jointree->fromlist) == 1);
2752  rtr = linitial_node(RangeTblRef, viewquery->jointree->fromlist);
2753 
2754  /* Initialize the optional return values */
2755  if (updatable_cols != NULL)
2756  *updatable_cols = NULL;
2757  if (non_updatable_col != NULL)
2758  *non_updatable_col = NULL;
2759 
2760  /* Test each view column for updatability */
2762  foreach(cell, viewquery->targetList)
2763  {
2764  TargetEntry *tle = (TargetEntry *) lfirst(cell);
2765  const char *col_update_detail;
2766 
2767  col++;
2768  col_update_detail = view_col_is_auto_updatable(rtr, tle);
2769 
2770  if (col_update_detail == NULL)
2771  {
2772  /* The column is updatable */
2773  if (updatable_cols != NULL)
2774  *updatable_cols = bms_add_member(*updatable_cols, col);
2775  }
2776  else if (bms_is_member(col, required_cols))
2777  {
2778  /* The required column is not updatable */
2779  if (non_updatable_col != NULL)
2780  *non_updatable_col = tle->resname;
2781  return col_update_detail;
2782  }
2783  }
2784 
2785  return NULL; /* all the required view columns are updatable */
2786 }
static const char * view_col_is_auto_updatable(RangeTblRef *rtr, TargetEntry *tle)

References Assert, bms_add_member(), bms_is_member(), FirstLowInvalidHeapAttributeNumber, FromExpr::fromlist, Query::jointree, lfirst, linitial_node, list_length(), Query::targetList, and view_col_is_auto_updatable().

Referenced by relation_is_updatable(), and rewriteTargetView().

◆ view_has_instead_trigger()

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

Definition at line 2478 of file rewriteHandler.c.

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

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

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

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