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, RuleLock *rulelocks, int varno, Query *parsetree, bool *hasUpdate)
 
static QueryfireRIRrules (Query *parsetree, List *activeRIRs)
 
static bool view_has_instead_trigger (Relation view, CmdType event)
 
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)
 
void fill_extraUpdatedCols (RangeTblEntry *target_rte, Relation target_relation)
 
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)
 
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)
 
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  */
321  return expression_tree_walker(node, acquireLocksOnSubLinks, context);
322 }
#define expression_tree_walker(n, w, c)
Definition: nodeFuncs.h:151
#define IsA(nodeptr, _type_)
Definition: nodes.h:168
void AcquireRewriteLocks(Query *parsetree, bool forExecute, bool forUpdatePushedDown)
static bool acquireLocksOnSubLinks(Node *node, acquireLocksOnSubLinks_context *context)

References AcquireRewriteLocks(), expression_tree_walker, acquireLocksOnSubLinks_context::for_execute, 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)
294  query_tree_walker(parsetree, acquireLocksOnSubLinks, &context,
296 }
unsigned int Index
Definition: c.h:550
#define ERROR
Definition: elog.h:35
Assert(fmt[strlen(fmt) - 1] !='\n')
List * lappend(List *list, void *datum)
Definition: list.c:338
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:648
#define query_tree_walker(q, w, c, f)
Definition: nodeFuncs.h:156
#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:1013
@ RTE_SUBQUERY
Definition: parsenodes.h:1012
@ RTE_RELATION
Definition: parsenodes.h:1011
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
#define lfirst(lc)
Definition: pg_list.h:170
#define NIL
Definition: pg_list.h:66
Definition: pg_list.h:52
Definition: nodes.h:118
List * cteList
Definition: parsenodes.h:153
List * rtable
Definition: parsenodes.h:155
bool hasSubLinks
Definition: parsenodes.h:144
Query * subquery
Definition: parsenodes.h:1065
List * joinaliasvars
Definition: parsenodes.h:1105
RTEKind rtekind
Definition: parsenodes.h:1030
Form_pg_class rd_rel
Definition: rel.h:110
Definition: primnodes.h:205
AttrNumber varattno
Definition: primnodes.h:217
int varno
Definition: primnodes.h:212
Index varlevelsup
Definition: primnodes.h:230
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40

References AccessShareLock, acquireLocksOnSubLinks(), Assert(), Query::cteList, CommonTableExpr::ctequery, elog(), ERROR, acquireLocksOnSubLinks_context::for_execute, get_parse_rowmark(), get_rte_attribute_is_dropped(), Query::hasSubLinks, IsA, RangeTblEntry::joinaliasvars, lappend(), lfirst, NIL, NoLock, QTW_IGNORE_RC_SUBQUERIES, query_tree_walker, RelationData::rd_rel, RangeTblEntry::relid, RangeTblEntry::relkind, RangeTblEntry::rellockmode, RowShareLock, rt_fetch, Query::rtable, RTE_JOIN, RTE_RELATION, RTE_SUBQUERY, RangeTblEntry::rtekind, strip_implicit_coercions(), RangeTblEntry::subquery, table_close(), table_open(), Var::varattno, Var::varlevelsup, and Var::varno.

Referenced by acquireLocksOnSubLinks(), 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 3000 of file rewriteHandler.c.

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

674 {
675  List *newjointree = copyObject(parsetree->jointree->fromlist);
676  ListCell *l;
677 
678  if (removert)
679  {
680  foreach(l, newjointree)
681  {
682  RangeTblRef *rtr = lfirst(l);
683 
684  if (IsA(rtr, RangeTblRef) &&
685  rtr->rtindex == rt_index)
686  {
687  newjointree = foreach_delete_current(newjointree, l);
688  break;
689  }
690  }
691  }
692  return newjointree;
693 }
#define copyObject(obj)
Definition: nodes.h:233
#define foreach_delete_current(lst, cell)
Definition: pg_list.h:388
List * fromlist
Definition: primnodes.h:1664
FromExpr * jointree
Definition: parsenodes.h:156

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

1746 {
1747  Query *rule_action;
1748  RangeTblEntry *rte,
1749  *subrte;
1750  RowMarkClause *rc;
1751 
1752  if (list_length(rule->actions) != 1)
1753  elog(ERROR, "expected just one rule action");
1754  if (rule->qual != NULL)
1755  elog(ERROR, "cannot handle qualified ON SELECT rule");
1756 
1757  if (rt_index == parsetree->resultRelation)
1758  {
1759  /*
1760  * We have a view as the result relation of the query, and it wasn't
1761  * rewritten by any rule. This case is supported if there is an
1762  * INSTEAD OF trigger that will trap attempts to insert/update/delete
1763  * view rows. The executor will check that; for the moment just plow
1764  * ahead. We have two cases:
1765  *
1766  * For INSERT, we needn't do anything. The unmodified RTE will serve
1767  * fine as the result relation.
1768  *
1769  * For UPDATE/DELETE, we need to expand the view so as to have source
1770  * data for the operation. But we also need an unmodified RTE to
1771  * serve as the target. So, copy the RTE and add the copy to the
1772  * rangetable. Note that the copy does not get added to the jointree.
1773  * Also note that there's a hack in fireRIRrules to avoid calling this
1774  * function again when it arrives at the copied RTE.
1775  */
1776  if (parsetree->commandType == CMD_INSERT)
1777  return parsetree;
1778  else if (parsetree->commandType == CMD_UPDATE ||
1779  parsetree->commandType == CMD_DELETE)
1780  {
1781  RangeTblEntry *newrte;
1782  Var *var;
1783  TargetEntry *tle;
1784 
1785  rte = rt_fetch(rt_index, parsetree->rtable);
1786  newrte = copyObject(rte);
1787  parsetree->rtable = lappend(parsetree->rtable, newrte);
1788  parsetree->resultRelation = list_length(parsetree->rtable);
1789 
1790  /*
1791  * There's no need to do permissions checks twice, so wipe out the
1792  * permissions info for the original RTE (we prefer to keep the
1793  * bits set on the result RTE).
1794  */
1795  rte->requiredPerms = 0;
1796  rte->checkAsUser = InvalidOid;
1797  rte->selectedCols = NULL;
1798  rte->insertedCols = NULL;
1799  rte->updatedCols = NULL;
1800  rte->extraUpdatedCols = NULL;
1801 
1802  /*
1803  * For the most part, Vars referencing the view should remain as
1804  * they are, meaning that they implicitly represent OLD values.
1805  * But in the RETURNING list if any, we want such Vars to
1806  * represent NEW values, so change them to reference the new RTE.
1807  *
1808  * Since ChangeVarNodes scribbles on the tree in-place, copy the
1809  * RETURNING list first for safety.
1810  */
1811  parsetree->returningList = copyObject(parsetree->returningList);
1812  ChangeVarNodes((Node *) parsetree->returningList, rt_index,
1813  parsetree->resultRelation, 0);
1814 
1815  /*
1816  * To allow the executor to compute the original view row to pass
1817  * to the INSTEAD OF trigger, we add a resjunk whole-row Var
1818  * referencing the original RTE. This will later get expanded
1819  * into a RowExpr computing all the OLD values of the view row.
1820  */
1821  var = makeWholeRowVar(rte, rt_index, 0, false);
1822  tle = makeTargetEntry((Expr *) var,
1823  list_length(parsetree->targetList) + 1,
1824  pstrdup("wholerow"),
1825  true);
1826 
1827  parsetree->targetList = lappend(parsetree->targetList, tle);
1828 
1829  /* Now, continue with expanding the original view RTE */
1830  }
1831  else
1832  elog(ERROR, "unrecognized commandType: %d",
1833  (int) parsetree->commandType);
1834  }
1835 
1836  /*
1837  * Check if there's a FOR [KEY] UPDATE/SHARE clause applying to this view.
1838  *
1839  * Note: we needn't explicitly consider any such clauses appearing in
1840  * ancestor query levels; their effects have already been pushed down to
1841  * here by markQueryForLocking, and will be reflected in "rc".
1842  */
1843  rc = get_parse_rowmark(parsetree, rt_index);
1844 
1845  /*
1846  * Make a modifiable copy of the view query, and acquire needed locks on
1847  * the relations it mentions. Force at least RowShareLock for all such
1848  * rels if there's a FOR [KEY] UPDATE/SHARE clause affecting this view.
1849  */
1850  rule_action = copyObject(linitial(rule->actions));
1851 
1852  AcquireRewriteLocks(rule_action, true, (rc != NULL));
1853 
1854  /*
1855  * If FOR [KEY] UPDATE/SHARE of view, mark all the contained tables as
1856  * implicit FOR [KEY] UPDATE/SHARE, the same as the parser would have done
1857  * if the view's subquery had been written out explicitly.
1858  */
1859  if (rc != NULL)
1860  markQueryForLocking(rule_action, (Node *) rule_action->jointree,
1861  rc->strength, rc->waitPolicy, true);
1862 
1863  /*
1864  * Recursively expand any view references inside the view.
1865  *
1866  * Note: this must happen after markQueryForLocking. That way, any UPDATE
1867  * permission bits needed for sub-views are initially applied to their
1868  * RTE_RELATION RTEs by markQueryForLocking, and then transferred to their
1869  * OLD rangetable entries by the action below (in a recursive call of this
1870  * routine).
1871  */
1872  rule_action = fireRIRrules(rule_action, activeRIRs);
1873 
1874  /*
1875  * Now, plug the view query in as a subselect, converting the relation's
1876  * original RTE to a subquery RTE.
1877  */
1878  rte = rt_fetch(rt_index, parsetree->rtable);
1879 
1880  rte->rtekind = RTE_SUBQUERY;
1881  rte->subquery = rule_action;
1882  rte->security_barrier = RelationIsSecurityView(relation);
1883  /* Clear fields that should not be set in a subquery RTE */
1884  rte->relid = InvalidOid;
1885  rte->relkind = 0;
1886  rte->rellockmode = 0;
1887  rte->tablesample = NULL;
1888  rte->inh = false; /* must not be set for a subquery */
1889 
1890  /*
1891  * We move the view's permission check data down to its rangetable. The
1892  * checks will actually be done against the OLD entry therein.
1893  */
1894  subrte = rt_fetch(PRS2_OLD_VARNO, rule_action->rtable);
1895  Assert(subrte->relid == relation->rd_id);
1896  subrte->requiredPerms = rte->requiredPerms;
1897  subrte->checkAsUser = rte->checkAsUser;
1898  subrte->selectedCols = rte->selectedCols;
1899  subrte->insertedCols = rte->insertedCols;
1900  subrte->updatedCols = rte->updatedCols;
1901  subrte->extraUpdatedCols = rte->extraUpdatedCols;
1902 
1903  rte->requiredPerms = 0; /* no permission check on subquery itself */
1904  rte->checkAsUser = InvalidOid;
1905  rte->selectedCols = NULL;
1906  rte->insertedCols = NULL;
1907  rte->updatedCols = NULL;
1908  rte->extraUpdatedCols = NULL;
1909 
1910  return parsetree;
1911 }
Var * makeWholeRowVar(RangeTblEntry *rte, int varno, Index varlevelsup, bool allowScalar)
Definition: makefuncs.c:133
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:238
char * pstrdup(const char *in)
Definition: mcxt.c:1483
@ 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:150
#define linitial(l)
Definition: pg_list.h:176
#define InvalidOid
Definition: postgres_ext.h:36
#define PRS2_OLD_VARNO
Definition: primnodes.h:201
#define RelationIsSecurityView(relation)
Definition: rel.h:422
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:610
List * returningList
Definition: parsenodes.h:168
int resultRelation
Definition: parsenodes.h:138
CmdType commandType
Definition: parsenodes.h:124
List * targetList
Definition: parsenodes.h:162
Bitmapset * extraUpdatedCols
Definition: parsenodes.h:1185
bool security_barrier
Definition: parsenodes.h:1066
AclMode requiredPerms
Definition: parsenodes.h:1180
struct TableSampleClause * tablesample
Definition: parsenodes.h:1060
Bitmapset * updatedCols
Definition: parsenodes.h:1184
Bitmapset * selectedCols
Definition: parsenodes.h:1182
Bitmapset * insertedCols
Definition: parsenodes.h:1183
Oid rd_id
Definition: rel.h:112
LockClauseStrength strength
Definition: parsenodes.h:1447
LockWaitPolicy waitPolicy
Definition: parsenodes.h:1448
Definition: localtime.c:73

References AcquireRewriteLocks(), Assert(), ChangeVarNodes(), RangeTblEntry::checkAsUser, CMD_DELETE, CMD_INSERT, CMD_UPDATE, Query::commandType, copyObject, elog(), ERROR, RangeTblEntry::extraUpdatedCols, fireRIRrules(), get_parse_rowmark(), RangeTblEntry::inh, RangeTblEntry::insertedCols, InvalidOid, Query::jointree, lappend(), linitial, list_length(), makeTargetEntry(), makeWholeRowVar(), markQueryForLocking(), PRS2_OLD_VARNO, pstrdup(), RelationData::rd_id, RelationIsSecurityView, RangeTblEntry::relid, RangeTblEntry::relkind, RangeTblEntry::rellockmode, RangeTblEntry::requiredPerms, Query::resultRelation, Query::returningList, rt_fetch, Query::rtable, RTE_SUBQUERY, RangeTblEntry::rtekind, RangeTblEntry::security_barrier, RangeTblEntry::selectedCols, RowMarkClause::strength, RangeTblEntry::subquery, RangeTblEntry::tablesample, Query::targetList, RangeTblEntry::updatedCols, and RowMarkClause::waitPolicy.

Referenced by fireRIRrules().

◆ build_column_default()

Node* build_column_default ( Relation  rel,
int  attrno 
)

Definition at line 1201 of file rewriteHandler.c.

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

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

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

◆ CopyAndAddInvertedQual()

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

Definition at line 2308 of file rewriteHandler.c.

2312 {
2313  /* Don't scribble on the passed qual (it's in the relcache!) */
2314  Node *new_qual = copyObject(rule_qual);
2316 
2317  context.for_execute = true;
2318 
2319  /*
2320  * In case there are subqueries in the qual, acquire necessary locks and
2321  * fix any deleted JOIN RTE entries. (This is somewhat redundant with
2322  * rewriteRuleAction, but not entirely ... consider restructuring so that
2323  * we only need to process the qual this way once.)
2324  */
2325  (void) acquireLocksOnSubLinks(new_qual, &context);
2326 
2327  /* Fix references to OLD */
2328  ChangeVarNodes(new_qual, PRS2_OLD_VARNO, rt_index, 0);
2329  /* Fix references to NEW */
2330  if (event == CMD_INSERT || event == CMD_UPDATE)
2331  new_qual = ReplaceVarsFromTargetList(new_qual,
2333  0,
2334  rt_fetch(rt_index,
2335  parsetree->rtable),
2336  parsetree->targetList,
2337  (event == CMD_UPDATE) ?
2340  rt_index,
2341  &parsetree->hasSubLinks);
2342  /* And attach the fixed qual */
2343  AddInvertedQual(parsetree, new_qual);
2344 
2345  return parsetree;
2346 }
#define PRS2_NEW_VARNO
Definition: primnodes.h:202
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, copyObject, acquireLocksOnSubLinks_context::for_execute, Query::hasSubLinks, PRS2_NEW_VARNO, PRS2_OLD_VARNO, REPLACEVARS_CHANGE_VARNO, REPLACEVARS_SUBSTITUTE_NULL, ReplaceVarsFromTargetList(), rt_fetch, Query::rtable, and Query::targetList.

Referenced by fireRules().

◆ fill_extraUpdatedCols()

void fill_extraUpdatedCols ( RangeTblEntry target_rte,
Relation  target_relation 
)

Definition at line 1634 of file rewriteHandler.c.

1635 {
1636  TupleDesc tupdesc = RelationGetDescr(target_relation);
1637  TupleConstr *constr = tupdesc->constr;
1638 
1639  target_rte->extraUpdatedCols = NULL;
1640 
1641  if (constr && constr->has_generated_stored)
1642  {
1643  for (int i = 0; i < constr->num_defval; i++)
1644  {
1645  AttrDefault *defval = &constr->defval[i];
1646  Node *expr;
1647  Bitmapset *attrs_used = NULL;
1648 
1649  /* skip if not generated column */
1650  if (!TupleDescAttr(tupdesc, defval->adnum - 1)->attgenerated)
1651  continue;
1652 
1653  /* identify columns this generated column depends on */
1654  expr = stringToNode(defval->adbin);
1655  pull_varattnos(expr, 1, &attrs_used);
1656 
1657  if (bms_overlap(target_rte->updatedCols, attrs_used))
1658  target_rte->extraUpdatedCols =
1659  bms_add_member(target_rte->extraUpdatedCols,
1661  }
1662  }
1663 }
bool bms_overlap(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:495
int i
Definition: isn.c:73
#define RelationGetDescr(relation)
Definition: rel.h:527
AttrNumber adnum
Definition: tupdesc.h:24
char * adbin
Definition: tupdesc.h:25
bool has_generated_stored
Definition: tupdesc.h:45
void pull_varattnos(Node *node, Index varno, Bitmapset **varattnos)
Definition: var.c:281

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

Referenced by apply_handle_update(), and RewriteQuery().

◆ findDefaultOnlyColumns()

static Bitmapset * findDefaultOnlyColumns ( RangeTblEntry rte)
static

Definition at line 1312 of file rewriteHandler.c.

1313 {
1314  Bitmapset *default_only_cols = NULL;
1315  ListCell *lc;
1316 
1317  foreach(lc, rte->values_lists)
1318  {
1319  List *sublist = (List *) lfirst(lc);
1320  ListCell *lc2;
1321  int i;
1322 
1323  if (default_only_cols == NULL)
1324  {
1325  /* Populate the initial result bitmap from the first row */
1326  i = 0;
1327  foreach(lc2, sublist)
1328  {
1329  Node *col = (Node *) lfirst(lc2);
1330 
1331  i++;
1332  if (IsA(col, SetToDefault))
1333  default_only_cols = bms_add_member(default_only_cols, i);
1334  }
1335  }
1336  else
1337  {
1338  /* Update the result bitmap from this next row */
1339  i = 0;
1340  foreach(lc2, sublist)
1341  {
1342  Node *col = (Node *) lfirst(lc2);
1343 
1344  i++;
1345  if (!IsA(col, SetToDefault))
1346  default_only_cols = bms_del_member(default_only_cols, i);
1347  }
1348  }
1349 
1350  /*
1351  * If no column in the rows read so far contains only DEFAULT items,
1352  * we are done.
1353  */
1354  if (bms_is_empty(default_only_cols))
1355  break;
1356  }
1357 
1358  return default_only_cols;
1359 }
Bitmapset * bms_del_member(Bitmapset *a, int x)
Definition: bitmapset.c:776
bool bms_is_empty(const Bitmapset *a)
Definition: bitmapset.c:704
List * values_lists
Definition: parsenodes.h:1135

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

1986 {
1987  if (node == NULL)
1988  return false;
1989  if (IsA(node, SubLink))
1990  {
1991  SubLink *sub = (SubLink *) node;
1992 
1993  /* Do what we came for */
1994  sub->subselect = (Node *) fireRIRrules((Query *) sub->subselect,
1995  activeRIRs);
1996  /* Fall through to process lefthand args of SubLink */
1997  }
1998 
1999  /*
2000  * Do NOT recurse into Query nodes, because fireRIRrules already processed
2001  * subselects of subselects for us.
2002  */
2004  (void *) activeRIRs);
2005 }
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 2016 of file rewriteHandler.c.

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

References acquireLocksOnSubLinks(), ApplyRetrieveRule(), CMD_SELECT, Query::cteList, CommonTableExpr::ctequery, CommonTableExpr::cycle_clause, ereport, errcode(), errmsg(), ERROR, OnConflictExpr::exclRelIndex, expression_tree_walker, fireRIRonSubLink(), acquireLocksOnSubLinks_context::for_execute, get_row_security_policies(), Query::hasRowSecurity, Query::hasSubLinks, 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, RangeTblEntry::relkind, Query::resultRelation, rewriteSearchAndCycle(), rt_fetch, Query::rtable, RTE_RELATION, RTE_SUBQUERY, RangeTblEntry::rtekind, rules, CommonTableExpr::search_clause, RangeTblEntry::securityQuals, RangeTblEntry::subquery, table_close(), table_open(), and Query::withCheckOptions.

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

2385 {
2386  List *results = NIL;
2387  ListCell *l;
2388 
2389  foreach(l, locks)
2390  {
2391  RewriteRule *rule_lock = (RewriteRule *) lfirst(l);
2392  Node *event_qual = rule_lock->qual;
2393  List *actions = rule_lock->actions;
2394  QuerySource qsrc;
2395  ListCell *r;
2396 
2397  /* Determine correct QuerySource value for actions */
2398  if (rule_lock->isInstead)
2399  {
2400  if (event_qual != NULL)
2401  qsrc = QSRC_QUAL_INSTEAD_RULE;
2402  else
2403  {
2404  qsrc = QSRC_INSTEAD_RULE;
2405  *instead_flag = true; /* report unqualified INSTEAD */
2406  }
2407  }
2408  else
2409  qsrc = QSRC_NON_INSTEAD_RULE;
2410 
2411  if (qsrc == QSRC_QUAL_INSTEAD_RULE)
2412  {
2413  /*
2414  * If there are INSTEAD rules with qualifications, the original
2415  * query is still performed. But all the negated rule
2416  * qualifications of the INSTEAD rules are added so it does its
2417  * actions only in cases where the rule quals of all INSTEAD rules
2418  * are false. Think of it as the default action in a case. We save
2419  * this in *qual_product so RewriteQuery() can add it to the query
2420  * list after we mangled it up enough.
2421  *
2422  * If we have already found an unqualified INSTEAD rule, then
2423  * *qual_product won't be used, so don't bother building it.
2424  */
2425  if (!*instead_flag)
2426  {
2427  if (*qual_product == NULL)
2428  *qual_product = copyObject(parsetree);
2429  *qual_product = CopyAndAddInvertedQual(*qual_product,
2430  event_qual,
2431  rt_index,
2432  event);
2433  }
2434  }
2435 
2436  /* Now process the rule's actions and add them to the result list */
2437  foreach(r, actions)
2438  {
2439  Query *rule_action = lfirst(r);
2440 
2441  if (rule_action->commandType == CMD_NOTHING)
2442  continue;
2443 
2444  rule_action = rewriteRuleAction(parsetree, rule_action,
2445  event_qual, rt_index, event,
2446  returning_flag);
2447 
2448  rule_action->querySource = qsrc;
2449  rule_action->canSetTag = false; /* might change later */
2450 
2451  results = lappend(results, rule_action);
2452  }
2453  }
2454 
2455  return results;
2456 }
@ CMD_NOTHING
Definition: nodes.h:272
QuerySource
Definition: parsenodes.h:42
@ QSRC_NON_INSTEAD_RULE
Definition: parsenodes.h:47
@ QSRC_QUAL_INSTEAD_RULE
Definition: parsenodes.h:46
@ QSRC_INSTEAD_RULE
Definition: parsenodes.h:45
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)
bool canSetTag
Definition: parsenodes.h:134
QuerySource querySource
Definition: parsenodes.h:126
List * actions
Definition: prs2lock.h:29
bool isInstead
Definition: prs2lock.h:31
Node * qual
Definition: prs2lock.h:28

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

Referenced by RewriteQuery().

◆ get_assignment_input()

static Node * get_assignment_input ( Node node)
static

Definition at line 1172 of file rewriteHandler.c.

1173 {
1174  if (node == NULL)
1175  return NULL;
1176  if (IsA(node, FieldStore))
1177  {
1178  FieldStore *fstore = (FieldStore *) node;
1179 
1180  return (Node *) fstore->arg;
1181  }
1182  else if (IsA(node, SubscriptingRef))
1183  {
1184  SubscriptingRef *sbsref = (SubscriptingRef *) node;
1185 
1186  if (sbsref->refassgnexpr == NULL)
1187  return NULL;
1188 
1189  return (Node *) sbsref->refexpr;
1190  }
1191 
1192  return NULL;
1193 }
Expr * arg
Definition: primnodes.h:978
Expr * refassgnexpr
Definition: primnodes.h:554
Expr * refexpr
Definition: primnodes.h:552

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

2470 {
2471  int i;
2472 
2473  Assert(view->rd_rel->relkind == RELKIND_VIEW);
2474 
2475  for (i = 0; i < view->rd_rules->numLocks; i++)
2476  {
2477  RewriteRule *rule = view->rd_rules->rules[i];
2478 
2479  if (rule->event == CMD_SELECT)
2480  {
2481  /* A _RETURN rule should have only one action */
2482  if (list_length(rule->actions) != 1)
2483  elog(ERROR, "invalid _RETURN rule action specification");
2484 
2485  return (Query *) linitial(rule->actions);
2486  }
2487  }
2488 
2489  elog(ERROR, "failed to find _RETURN rule for view");
2490  return NULL; /* keep compiler quiet */
2491 }
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 1925 of file rewriteHandler.c.

1928 {
1929  if (jtnode == NULL)
1930  return;
1931  if (IsA(jtnode, RangeTblRef))
1932  {
1933  int rti = ((RangeTblRef *) jtnode)->rtindex;
1934  RangeTblEntry *rte = rt_fetch(rti, qry->rtable);
1935 
1936  if (rte->rtekind == RTE_RELATION)
1937  {
1938  applyLockingClause(qry, rti, strength, waitPolicy, pushedDown);
1940  }
1941  else if (rte->rtekind == RTE_SUBQUERY)
1942  {
1943  applyLockingClause(qry, rti, strength, waitPolicy, pushedDown);
1944  /* FOR UPDATE/SHARE of subquery is propagated to subquery's rels */
1946  strength, waitPolicy, true);
1947  }
1948  /* other RTE types are unaffected by FOR UPDATE */
1949  }
1950  else if (IsA(jtnode, FromExpr))
1951  {
1952  FromExpr *f = (FromExpr *) jtnode;
1953  ListCell *l;
1954 
1955  foreach(l, f->fromlist)
1956  markQueryForLocking(qry, lfirst(l), strength, waitPolicy, pushedDown);
1957  }
1958  else if (IsA(jtnode, JoinExpr))
1959  {
1960  JoinExpr *j = (JoinExpr *) jtnode;
1961 
1962  markQueryForLocking(qry, j->larg, strength, waitPolicy, pushedDown);
1963  markQueryForLocking(qry, j->rarg, strength, waitPolicy, pushedDown);
1964  }
1965  else
1966  elog(ERROR, "unrecognized node type: %d",
1967  (int) nodeTag(jtnode));
1968 }
int j
Definition: isn.c:74
#define nodeTag(nodeptr)
Definition: nodes.h:122
#define ACL_SELECT_FOR_UPDATE
Definition: parsenodes.h:102
void applyLockingClause(Query *qry, Index rtindex, LockClauseStrength strength, LockWaitPolicy waitPolicy, bool pushedDown)
Definition: analyze.c:3420

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

Referenced by ApplyRetrieveRule().

◆ matchLocks()

static List * matchLocks ( CmdType  event,
RuleLock rulelocks,
int  varno,
Query parsetree,
bool hasUpdate 
)
static

Definition at line 1671 of file rewriteHandler.c.

1676 {
1677  List *matching_locks = NIL;
1678  int nlocks;
1679  int i;
1680 
1681  if (rulelocks == NULL)
1682  return NIL;
1683 
1684  /* No rule support for MERGE */
1685  if (parsetree->commandType == CMD_MERGE)
1686  return NIL;
1687 
1688  if (parsetree->commandType != CMD_SELECT)
1689  {
1690  if (parsetree->resultRelation != varno)
1691  return NIL;
1692  }
1693 
1694  nlocks = rulelocks->numLocks;
1695 
1696  for (i = 0; i < nlocks; i++)
1697  {
1698  RewriteRule *oneLock = rulelocks->rules[i];
1699 
1700  if (oneLock->event == CMD_UPDATE)
1701  *hasUpdate = true;
1702 
1703  /*
1704  * Suppress ON INSERT/UPDATE/DELETE rules that are disabled or
1705  * configured to not fire during the current sessions replication
1706  * role. ON SELECT rules will always be applied in order to keep views
1707  * working even in LOCAL or REPLICA role.
1708  */
1709  if (oneLock->event != CMD_SELECT)
1710  {
1712  {
1713  if (oneLock->enabled == RULE_FIRES_ON_ORIGIN ||
1714  oneLock->enabled == RULE_DISABLED)
1715  continue;
1716  }
1717  else /* ORIGIN or LOCAL ROLE */
1718  {
1719  if (oneLock->enabled == RULE_FIRES_ON_REPLICA ||
1720  oneLock->enabled == RULE_DISABLED)
1721  continue;
1722  }
1723  }
1724 
1725  if (oneLock->event == event)
1726  {
1727  if (parsetree->commandType != CMD_SELECT ||
1728  rangeTableEntry_used((Node *) parsetree, varno, 0))
1729  matching_locks = lappend(matching_locks, oneLock);
1730  }
1731  }
1732 
1733  return matching_locks;
1734 }
@ CMD_MERGE
Definition: nodes.h:269
#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:70
#define SESSION_REPLICATION_ROLE_REPLICA
Definition: trigger.h:141

References CMD_MERGE, CMD_SELECT, CMD_UPDATE, Query::commandType, RewriteRule::enabled, RewriteRule::event, i, lappend(), NIL, RuleLock::numLocks, rangeTableEntry_used(), Query::resultRelation, 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 1019 of file rewriteHandler.c.

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

References arg, FieldStore::arg, CoerceToDomain::arg, elog(), equal(), ereport, errcode(), errmsg(), ERROR, TargetEntry::expr, exprType(), FieldStore::fieldnums, 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 4187 of file rewriteHandler.c.

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

References Assert(), Query::canSetTag, Query::commandType, fireRIRrules(), lappend(), lfirst, NIL, QSRC_INSTEAD_RULE, QSRC_ORIGINAL, QSRC_QUAL_INSTEAD_RULE, Query::querySource, 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 2819 of file rewriteHandler.c.

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

References AccessShareLock, adjust_view_column_set(), ALL_EVENTS, Assert(), bms_int_members(), bms_is_empty(), check_stack_depth(), CMD_DELETE, CMD_INSERT, CMD_UPDATE, RewriteRule::event, FdwRoutine::ExecForeignDelete, FdwRoutine::ExecForeignInsert, FdwRoutine::ExecForeignUpdate, FromExpr::fromlist, get_view_query(), GetFdwRoutineForRelation(), i, FdwRoutine::IsForeignRelUpdatable, RewriteRule::isInstead, Query::jointree, lappend_oid(), linitial, list_delete_last(), list_member_oid(), RuleLock::numLocks, RewriteRule::qual, RelationData::rd_rel, RelationData::rd_rules, relation_close(), RelationGetRelid, RangeTblEntry::relid, RangeTblEntry::relkind, rt_fetch, Query::rtable, RTE_RELATION, RangeTblEntry::rtekind, RangeTblRef::rtindex, RuleLock::rules, Query::targetList, TriggerDesc::trig_delete_instead_row, TriggerDesc::trig_insert_instead_row, TriggerDesc::trig_update_instead_row, RelationData::trigdesc, try_relation_open(), view_cols_are_auto_updatable(), and view_query_is_auto_updatable().

Referenced by pg_column_is_updatable(), and pg_relation_is_updatable().

◆ RewriteQuery()

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

Definition at line 3635 of file rewriteHandler.c.

3636 {
3637  CmdType event = parsetree->commandType;
3638  bool instead = false;
3639  bool returning = false;
3640  bool updatableview = false;
3641  Query *qual_product = NULL;
3642  List *rewritten = NIL;
3643  ListCell *lc1;
3644 
3645  /*
3646  * First, recursively process any insert/update/delete statements in WITH
3647  * clauses. (We have to do this first because the WITH clauses may get
3648  * copied into rule actions below.)
3649  */
3650  foreach(lc1, parsetree->cteList)
3651  {
3653  Query *ctequery = castNode(Query, cte->ctequery);
3654  List *newstuff;
3655 
3656  if (ctequery->commandType == CMD_SELECT)
3657  continue;
3658 
3659  newstuff = RewriteQuery(ctequery, rewrite_events, 0);
3660 
3661  /*
3662  * Currently we can only handle unconditional, single-statement DO
3663  * INSTEAD rules correctly; we have to get exactly one non-utility
3664  * Query out of the rewrite operation to stuff back into the CTE node.
3665  */
3666  if (list_length(newstuff) == 1)
3667  {
3668  /* Must check it's not a utility command */
3669  ctequery = linitial_node(Query, newstuff);
3670  if (!(ctequery->commandType == CMD_SELECT ||
3671  ctequery->commandType == CMD_UPDATE ||
3672  ctequery->commandType == CMD_INSERT ||
3673  ctequery->commandType == CMD_DELETE))
3674  {
3675  /*
3676  * Currently it could only be NOTIFY; this error message will
3677  * need work if we ever allow other utility commands in rules.
3678  */
3679  ereport(ERROR,
3680  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3681  errmsg("DO INSTEAD NOTIFY rules are not supported for data-modifying statements in WITH")));
3682  }
3683  /* WITH queries should never be canSetTag */
3684  Assert(!ctequery->canSetTag);
3685  /* Push the single Query back into the CTE node */
3686  cte->ctequery = (Node *) ctequery;
3687  }
3688  else if (newstuff == NIL)
3689  {
3690  ereport(ERROR,
3691  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3692  errmsg("DO INSTEAD NOTHING rules are not supported for data-modifying statements in WITH")));
3693  }
3694  else
3695  {
3696  ListCell *lc2;
3697 
3698  /* examine queries to determine which error message to issue */
3699  foreach(lc2, newstuff)
3700  {
3701  Query *q = (Query *) lfirst(lc2);
3702 
3704  ereport(ERROR,
3705  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3706  errmsg("conditional DO INSTEAD rules are not supported for data-modifying statements in WITH")));
3708  ereport(ERROR,
3709  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3710  errmsg("DO ALSO rules are not supported for data-modifying statements in WITH")));
3711  }
3712 
3713  ereport(ERROR,
3714  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3715  errmsg("multi-statement DO INSTEAD rules are not supported for data-modifying statements in WITH")));
3716  }
3717  }
3718 
3719  /*
3720  * If the statement is an insert, update, delete, or merge, adjust its
3721  * targetlist as needed, and then fire INSERT/UPDATE/DELETE rules on it.
3722  *
3723  * SELECT rules are handled later when we have all the queries that should
3724  * get executed. Also, utilities aren't rewritten at all (do we still
3725  * need that check?)
3726  */
3727  if (event != CMD_SELECT && event != CMD_UTILITY)
3728  {
3729  int result_relation;
3730  RangeTblEntry *rt_entry;
3731  Relation rt_entry_relation;
3732  List *locks;
3733  int product_orig_rt_length;
3734  List *product_queries;
3735  bool hasUpdate = false;
3736  int values_rte_index = 0;
3737  bool defaults_remaining = false;
3738 
3739  result_relation = parsetree->resultRelation;
3740  Assert(result_relation != 0);
3741  rt_entry = rt_fetch(result_relation, parsetree->rtable);
3742  Assert(rt_entry->rtekind == RTE_RELATION);
3743 
3744  /*
3745  * We can use NoLock here since either the parser or
3746  * AcquireRewriteLocks should have locked the rel already.
3747  */
3748  rt_entry_relation = table_open(rt_entry->relid, NoLock);
3749 
3750  /*
3751  * Rewrite the targetlist as needed for the command type.
3752  */
3753  if (event == CMD_INSERT)
3754  {
3755  ListCell *lc2;
3756  RangeTblEntry *values_rte = NULL;
3757 
3758  /*
3759  * Test if it's a multi-row INSERT ... VALUES (...), (...), ... by
3760  * looking for a VALUES RTE in the fromlist. For product queries,
3761  * we must ignore any already-processed VALUES RTEs from the
3762  * original query. These appear at the start of the rangetable.
3763  */
3764  foreach(lc2, parsetree->jointree->fromlist)
3765  {
3766  RangeTblRef *rtr = (RangeTblRef *) lfirst(lc2);
3767 
3768  if (IsA(rtr, RangeTblRef) && rtr->rtindex > orig_rt_length)
3769  {
3770  RangeTblEntry *rte = rt_fetch(rtr->rtindex,
3771  parsetree->rtable);
3772 
3773  if (rte->rtekind == RTE_VALUES)
3774  {
3775  /* should not find more than one VALUES RTE */
3776  if (values_rte != NULL)
3777  elog(ERROR, "more than one VALUES RTE found");
3778 
3779  values_rte = rte;
3780  values_rte_index = rtr->rtindex;
3781  }
3782  }
3783  }
3784 
3785  if (values_rte)
3786  {
3787  Bitmapset *unused_values_attrnos = NULL;
3788 
3789  /* Process the main targetlist ... */
3790  parsetree->targetList = rewriteTargetListIU(parsetree->targetList,
3791  parsetree->commandType,
3792  parsetree->override,
3793  rt_entry_relation,
3794  values_rte,
3795  values_rte_index,
3796  &unused_values_attrnos);
3797  /* ... and the VALUES expression lists */
3798  if (!rewriteValuesRTE(parsetree, values_rte, values_rte_index,
3799  rt_entry_relation,
3800  unused_values_attrnos))
3801  defaults_remaining = true;
3802  }
3803  else
3804  {
3805  /* Process just the main targetlist */
3806  parsetree->targetList =
3807  rewriteTargetListIU(parsetree->targetList,
3808  parsetree->commandType,
3809  parsetree->override,
3810  rt_entry_relation,
3811  NULL, 0, NULL);
3812  }
3813 
3814  if (parsetree->onConflict &&
3815  parsetree->onConflict->action == ONCONFLICT_UPDATE)
3816  {
3817  parsetree->onConflict->onConflictSet =
3819  CMD_UPDATE,
3820  parsetree->override,
3821  rt_entry_relation,
3822  NULL, 0, NULL);
3823  }
3824  }
3825  else if (event == CMD_UPDATE)
3826  {
3827  Assert(parsetree->override == OVERRIDING_NOT_SET);
3828  parsetree->targetList =
3829  rewriteTargetListIU(parsetree->targetList,
3830  parsetree->commandType,
3831  parsetree->override,
3832  rt_entry_relation,
3833  NULL, 0, NULL);
3834 
3835  /* Also populate extraUpdatedCols (for generated columns) */
3836  fill_extraUpdatedCols(rt_entry, rt_entry_relation);
3837  }
3838  else if (event == CMD_MERGE)
3839  {
3840  Assert(parsetree->override == OVERRIDING_NOT_SET);
3841 
3842  /*
3843  * Rewrite each action targetlist separately
3844  */
3845  foreach(lc1, parsetree->mergeActionList)
3846  {
3847  MergeAction *action = (MergeAction *) lfirst(lc1);
3848 
3849  switch (action->commandType)
3850  {
3851  case CMD_NOTHING:
3852  case CMD_DELETE: /* Nothing to do here */
3853  break;
3854  case CMD_UPDATE:
3855  case CMD_INSERT:
3856 
3857  /*
3858  * MERGE actions do not permit multi-row INSERTs, so
3859  * there is no VALUES RTE to deal with here.
3860  */
3861  action->targetList =
3862  rewriteTargetListIU(action->targetList,
3863  action->commandType,
3864  action->override,
3865  rt_entry_relation,
3866  NULL, 0, NULL);
3867  break;
3868  default:
3869  elog(ERROR, "unrecognized commandType: %d", action->commandType);
3870  break;
3871  }
3872  }
3873  }
3874  else if (event == CMD_DELETE)
3875  {
3876  /* Nothing to do here */
3877  }
3878  else
3879  elog(ERROR, "unrecognized commandType: %d", (int) event);
3880 
3881  /*
3882  * Collect and apply the appropriate rules.
3883  */
3884  locks = matchLocks(event, rt_entry_relation->rd_rules,
3885  result_relation, parsetree, &hasUpdate);
3886 
3887  product_orig_rt_length = list_length(parsetree->rtable);
3888  product_queries = fireRules(parsetree,
3889  result_relation,
3890  event,
3891  locks,
3892  &instead,
3893  &returning,
3894  &qual_product);
3895 
3896  /*
3897  * If we have a VALUES RTE with any remaining untouched DEFAULT items,
3898  * and we got any product queries, finalize the VALUES RTE for each
3899  * product query (replacing the remaining DEFAULT items with NULLs).
3900  * We don't do this for the original query, because we know that it
3901  * must be an auto-insert on a view, and so should use the base
3902  * relation's defaults for any remaining DEFAULT items.
3903  */
3904  if (defaults_remaining && product_queries != NIL)
3905  {
3906  ListCell *n;
3907 
3908  /*
3909  * Each product query has its own copy of the VALUES RTE at the
3910  * same index in the rangetable, so we must finalize each one.
3911  */
3912  foreach(n, product_queries)
3913  {
3914  Query *pt = (Query *) lfirst(n);
3915  RangeTblEntry *values_rte = rt_fetch(values_rte_index,
3916  pt->rtable);
3917 
3918  rewriteValuesRTEToNulls(pt, values_rte);
3919  }
3920  }
3921 
3922  /*
3923  * If there was no unqualified INSTEAD rule, and the target relation
3924  * is a view without any INSTEAD OF triggers, see if the view can be
3925  * automatically updated. If so, we perform the necessary query
3926  * transformation here and add the resulting query to the
3927  * product_queries list, so that it gets recursively rewritten if
3928  * necessary.
3929  *
3930  * If the view cannot be automatically updated, we throw an error here
3931  * which is OK since the query would fail at runtime anyway. Throwing
3932  * the error here is preferable to the executor check since we have
3933  * more detailed information available about why the view isn't
3934  * updatable.
3935  */
3936  if (!instead &&
3937  rt_entry_relation->rd_rel->relkind == RELKIND_VIEW &&
3938  !view_has_instead_trigger(rt_entry_relation, event))
3939  {
3940  /*
3941  * If there were any qualified INSTEAD rules, don't allow the view
3942  * to be automatically updated (an unqualified INSTEAD rule or
3943  * INSTEAD OF trigger is required).
3944  *
3945  * The messages here should match execMain.c's CheckValidResultRel
3946  * and in principle make those checks in executor unnecessary, but
3947  * we keep them just in case.
3948  */
3949  if (qual_product != NULL)
3950  {
3951  switch (parsetree->commandType)
3952  {
3953  case CMD_INSERT:
3954  ereport(ERROR,
3955  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3956  errmsg("cannot insert into view \"%s\"",
3957  RelationGetRelationName(rt_entry_relation)),
3958  errdetail("Views with conditional DO INSTEAD rules are not automatically updatable."),
3959  errhint("To enable inserting into the view, provide an INSTEAD OF INSERT trigger or an unconditional ON INSERT DO INSTEAD rule.")));
3960  break;
3961  case CMD_UPDATE:
3962  ereport(ERROR,
3963  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3964  errmsg("cannot update view \"%s\"",
3965  RelationGetRelationName(rt_entry_relation)),
3966  errdetail("Views with conditional DO INSTEAD rules are not automatically updatable."),
3967  errhint("To enable updating the view, provide an INSTEAD OF UPDATE trigger or an unconditional ON UPDATE DO INSTEAD rule.")));
3968  break;
3969  case CMD_DELETE:
3970  ereport(ERROR,
3971  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3972  errmsg("cannot delete from view \"%s\"",
3973  RelationGetRelationName(rt_entry_relation)),
3974  errdetail("Views with conditional DO INSTEAD rules are not automatically updatable."),
3975  errhint("To enable deleting from the view, provide an INSTEAD OF DELETE trigger or an unconditional ON DELETE DO INSTEAD rule.")));
3976  break;
3977  default:
3978  elog(ERROR, "unrecognized CmdType: %d",
3979  (int) parsetree->commandType);
3980  break;
3981  }
3982  }
3983 
3984  /*
3985  * Attempt to rewrite the query to automatically update the view.
3986  * This throws an error if the view can't be automatically
3987  * updated.
3988  */
3989  parsetree = rewriteTargetView(parsetree, rt_entry_relation);
3990 
3991  /*
3992  * At this point product_queries contains any DO ALSO rule
3993  * actions. Add the rewritten query before or after those. This
3994  * must match the handling the original query would have gotten
3995  * below, if we allowed it to be included again.
3996  */
3997  if (parsetree->commandType == CMD_INSERT)
3998  product_queries = lcons(parsetree, product_queries);
3999  else
4000  product_queries = lappend(product_queries, parsetree);
4001 
4002  /*
4003  * Set the "instead" flag, as if there had been an unqualified
4004  * INSTEAD, to prevent the original query from being included a
4005  * second time below. The transformation will have rewritten any
4006  * RETURNING list, so we can also set "returning" to forestall
4007  * throwing an error below.
4008  */
4009  instead = true;
4010  returning = true;
4011  updatableview = true;
4012  }
4013 
4014  /*
4015  * If we got any product queries, recursively rewrite them --- but
4016  * first check for recursion!
4017  */
4018  if (product_queries != NIL)
4019  {
4020  ListCell *n;
4021  rewrite_event *rev;
4022 
4023  foreach(n, rewrite_events)
4024  {
4025  rev = (rewrite_event *) lfirst(n);
4026  if (rev->relation == RelationGetRelid(rt_entry_relation) &&
4027  rev->event == event)
4028  ereport(ERROR,
4029  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
4030  errmsg("infinite recursion detected in rules for relation \"%s\"",
4031  RelationGetRelationName(rt_entry_relation))));
4032  }
4033 
4034  rev = (rewrite_event *) palloc(sizeof(rewrite_event));
4035  rev->relation = RelationGetRelid(rt_entry_relation);
4036  rev->event = event;
4037  rewrite_events = lappend(rewrite_events, rev);
4038 
4039  foreach(n, product_queries)
4040  {
4041  Query *pt = (Query *) lfirst(n);
4042  List *newstuff;
4043 
4044  /*
4045  * For an updatable view, pt might be the rewritten version of
4046  * the original query, in which case we pass on orig_rt_length
4047  * to finish processing any VALUES RTE it contained.
4048  *
4049  * Otherwise, we have a product query created by fireRules().
4050  * Any VALUES RTEs from the original query have been fully
4051  * processed, and must be skipped when we recurse.
4052  */
4053  newstuff = RewriteQuery(pt, rewrite_events,
4054  pt == parsetree ?
4055  orig_rt_length :
4056  product_orig_rt_length);
4057  rewritten = list_concat(rewritten, newstuff);
4058  }
4059 
4060  rewrite_events = list_delete_last(rewrite_events);
4061  }
4062 
4063  /*
4064  * If there is an INSTEAD, and the original query has a RETURNING, we
4065  * have to have found a RETURNING in the rule(s), else fail. (Because
4066  * DefineQueryRewrite only allows RETURNING in unconditional INSTEAD
4067  * rules, there's no need to worry whether the substituted RETURNING
4068  * will actually be executed --- it must be.)
4069  */
4070  if ((instead || qual_product != NULL) &&
4071  parsetree->returningList &&
4072  !returning)
4073  {
4074  switch (event)
4075  {
4076  case CMD_INSERT:
4077  ereport(ERROR,
4078  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4079  errmsg("cannot perform INSERT RETURNING on relation \"%s\"",
4080  RelationGetRelationName(rt_entry_relation)),
4081  errhint("You need an unconditional ON INSERT DO INSTEAD rule with a RETURNING clause.")));
4082  break;
4083  case CMD_UPDATE:
4084  ereport(ERROR,
4085  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4086  errmsg("cannot perform UPDATE RETURNING on relation \"%s\"",
4087  RelationGetRelationName(rt_entry_relation)),
4088  errhint("You need an unconditional ON UPDATE DO INSTEAD rule with a RETURNING clause.")));
4089  break;
4090  case CMD_DELETE:
4091  ereport(ERROR,
4092  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4093  errmsg("cannot perform DELETE RETURNING on relation \"%s\"",
4094  RelationGetRelationName(rt_entry_relation)),
4095  errhint("You need an unconditional ON DELETE DO INSTEAD rule with a RETURNING clause.")));
4096  break;
4097  default:
4098  elog(ERROR, "unrecognized commandType: %d",
4099  (int) event);
4100  break;
4101  }
4102  }
4103 
4104  /*
4105  * Updatable views are supported by ON CONFLICT, so don't prevent that
4106  * case from proceeding
4107  */
4108  if (parsetree->onConflict &&
4109  (product_queries != NIL || hasUpdate) &&
4110  !updatableview)
4111  ereport(ERROR,
4112  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4113  errmsg("INSERT with ON CONFLICT clause cannot be used with table that has INSERT or UPDATE rules")));
4114 
4115  table_close(rt_entry_relation, NoLock);
4116  }
4117 
4118  /*
4119  * For INSERTs, the original query is done first; for UPDATE/DELETE, it is
4120  * done last. This is needed because update and delete rule actions might
4121  * not do anything if they are invoked after the update or delete is
4122  * performed. The command counter increment between the query executions
4123  * makes the deleted (and maybe the updated) tuples disappear so the scans
4124  * for them in the rule actions cannot find them.
4125  *
4126  * If we found any unqualified INSTEAD, the original query is not done at
4127  * all, in any form. Otherwise, we add the modified form if qualified
4128  * INSTEADs were found, else the unmodified form.
4129  */
4130  if (!instead)
4131  {
4132  if (parsetree->commandType == CMD_INSERT)
4133  {
4134  if (qual_product != NULL)
4135  rewritten = lcons(qual_product, rewritten);
4136  else
4137  rewritten = lcons(parsetree, rewritten);
4138  }
4139  else
4140  {
4141  if (qual_product != NULL)
4142  rewritten = lappend(rewritten, qual_product);
4143  else
4144  rewritten = lappend(rewritten, parsetree);
4145  }
4146  }
4147 
4148  /*
4149  * If the original query has a CTE list, and we generated more than one
4150  * non-utility result query, we have to fail because we'll have copied the
4151  * CTE list into each result query. That would break the expectation of
4152  * single evaluation of CTEs. This could possibly be fixed by
4153  * restructuring so that a CTE list can be shared across multiple Query
4154  * and PlannableStatement nodes.
4155  */
4156  if (parsetree->cteList != NIL)
4157  {
4158  int qcount = 0;
4159 
4160  foreach(lc1, rewritten)
4161  {
4162  Query *q = (Query *) lfirst(lc1);
4163 
4164  if (q->commandType != CMD_UTILITY)
4165  qcount++;
4166  }
4167  if (qcount > 1)
4168  ereport(ERROR,
4169  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4170  errmsg("WITH cannot be used in a query that is rewritten by rules into multiple queries")));
4171  }
4172 
4173  return rewritten;
4174 }
int errdetail(const char *fmt,...)
Definition: elog.c:1039
List * lcons(void *datum, List *list)
Definition: list.c:494
void * palloc(Size size)
Definition: mcxt.c:1199
@ ONCONFLICT_UPDATE
Definition: nodes.h:417
@ CMD_UTILITY
Definition: nodes.h:270
@ RTE_VALUES
Definition: parsenodes.h:1016
@ OVERRIDING_NOT_SET
Definition: parsenodes.h:35
#define linitial_node(type, l)
Definition: pg_list.h:179
static List * fireRules(Query *parsetree, int rt_index, CmdType event, List *locks, bool *instead_flag, bool *returning_flag, Query **qual_product)
void fill_extraUpdatedCols(RangeTblEntry *target_rte, Relation target_relation)
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, RuleLock *rulelocks, int varno, Query *parsetree, bool *hasUpdate)
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)
static bool view_has_instead_trigger(Relation view, CmdType event)
OnConflictAction action
Definition: primnodes.h:1680
List * onConflictSet
Definition: primnodes.h:1689
List * mergeActionList
Definition: parsenodes.h:159
OverridingKind override
Definition: parsenodes.h:164

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

References acquireLocksOnSubLinks(), AcquireRewriteLocks(), AddQual(), adjustJoinTreeList(), Assert(), ChangeVarNodes(), checkExprHasSubLink(), CMD_INSERT, CMD_UPDATE, CMD_UTILITY, Query::commandType, copyObject, Query::cteList, CommonTableExpr::ctename, ereport, errcode(), errmsg(), ERROR, acquireLocksOnSubLinks_context::for_execute, FromExpr::fromlist, RangeTblEntry::functions, getInsertSelectQuery(), Query::hasModifyingCTE, Query::hasRecursive, Query::hasRowSecurity, Query::hasSubLinks, 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::resultRelation, Query::returningList, rt_fetch, Query::rtable, RTE_FUNCTION, RTE_RELATION, RTE_TABLEFUNC, RTE_VALUES, RangeTblEntry::rtekind, Query::setOperations, 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 735 of file rewriteHandler.c.

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

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::resjunk, TargetEntry::resno, TupleDescAttr, Var::varattno, and Var::varno.

Referenced by RewriteQuery().

◆ rewriteTargetView()

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

Definition at line 3070 of file rewriteHandler.c.

3071 {
3072  Query *viewquery;
3073  const char *auto_update_detail;
3074  RangeTblRef *rtr;
3075  int base_rt_index;
3076  int new_rt_index;
3077  RangeTblEntry *base_rte;
3078  RangeTblEntry *view_rte;
3079  RangeTblEntry *new_rte;
3080  Relation base_rel;
3081  List *view_targetlist;
3082  ListCell *lc;
3083 
3084  /*
3085  * Get the Query from the view's ON SELECT rule. We're going to munge the
3086  * Query to change the view's base relation into the target relation,
3087  * along with various other changes along the way, so we need to make a
3088  * copy of it (get_view_query() returns a pointer into the relcache, so we
3089  * have to treat it as read-only).
3090  */
3091  viewquery = copyObject(get_view_query(view));
3092 
3093  /* The view must be updatable, else fail */
3094  auto_update_detail =
3095  view_query_is_auto_updatable(viewquery,
3096  parsetree->commandType != CMD_DELETE);
3097 
3098  if (auto_update_detail)
3099  {
3100  /* messages here should match execMain.c's CheckValidResultRel */
3101  switch (parsetree->commandType)
3102  {
3103  case CMD_INSERT:
3104  ereport(ERROR,
3105  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3106  errmsg("cannot insert into view \"%s\"",
3107  RelationGetRelationName(view)),
3108  errdetail_internal("%s", _(auto_update_detail)),
3109  errhint("To enable inserting into the view, provide an INSTEAD OF INSERT trigger or an unconditional ON INSERT DO INSTEAD rule.")));
3110  break;
3111  case CMD_UPDATE:
3112  ereport(ERROR,
3113  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3114  errmsg("cannot update view \"%s\"",
3115  RelationGetRelationName(view)),
3116  errdetail_internal("%s", _(auto_update_detail)),
3117  errhint("To enable updating the view, provide an INSTEAD OF UPDATE trigger or an unconditional ON UPDATE DO INSTEAD rule.")));
3118  break;
3119  case CMD_DELETE:
3120  ereport(ERROR,
3121  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3122  errmsg("cannot delete from view \"%s\"",
3123  RelationGetRelationName(view)),
3124  errdetail_internal("%s", _(auto_update_detail)),
3125  errhint("To enable deleting from the view, provide an INSTEAD OF DELETE trigger or an unconditional ON DELETE DO INSTEAD rule.")));
3126  break;
3127  default:
3128  elog(ERROR, "unrecognized CmdType: %d",
3129  (int) parsetree->commandType);
3130  break;
3131  }
3132  }
3133 
3134  /*
3135  * For INSERT/UPDATE the modified columns must all be updatable. Note that
3136  * we get the modified columns from the query's targetlist, not from the
3137  * result RTE's insertedCols and/or updatedCols set, since
3138  * rewriteTargetListIU may have added additional targetlist entries for
3139  * view defaults, and these must also be updatable.
3140  */
3141  if (parsetree->commandType != CMD_DELETE)
3142  {
3143  Bitmapset *modified_cols = NULL;
3144  char *non_updatable_col;
3145 
3146  foreach(lc, parsetree->targetList)
3147  {
3148  TargetEntry *tle = (TargetEntry *) lfirst(lc);
3149 
3150  if (!tle->resjunk)
3151  modified_cols = bms_add_member(modified_cols,
3153  }
3154 
3155  if (parsetree->onConflict)
3156  {
3157  foreach(lc, parsetree->onConflict->onConflictSet)
3158  {
3159  TargetEntry *tle = (TargetEntry *) lfirst(lc);
3160 
3161  if (!tle->resjunk)
3162  modified_cols = bms_add_member(modified_cols,
3164  }
3165  }
3166 
3167  auto_update_detail = view_cols_are_auto_updatable(viewquery,
3168  modified_cols,
3169  NULL,
3170  &non_updatable_col);
3171  if (auto_update_detail)
3172  {
3173  /*
3174  * This is a different error, caused by an attempt to update a
3175  * non-updatable column in an otherwise updatable view.
3176  */
3177  switch (parsetree->commandType)
3178  {
3179  case CMD_INSERT:
3180  ereport(ERROR,
3181  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3182  errmsg("cannot insert into column \"%s\" of view \"%s\"",
3183  non_updatable_col,
3184  RelationGetRelationName(view)),
3185  errdetail_internal("%s", _(auto_update_detail))));
3186  break;
3187  case CMD_UPDATE:
3188  ereport(ERROR,
3189  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3190  errmsg("cannot update column \"%s\" of view \"%s\"",
3191  non_updatable_col,
3192  RelationGetRelationName(view)),
3193  errdetail_internal("%s", _(auto_update_detail))));
3194  break;
3195  default:
3196  elog(ERROR, "unrecognized CmdType: %d",
3197  (int) parsetree->commandType);
3198  break;
3199  }
3200  }
3201  }
3202 
3203  /* Locate RTE describing the view in the outer query */
3204  view_rte = rt_fetch(parsetree->resultRelation, parsetree->rtable);
3205 
3206  /*
3207  * If we get here, view_query_is_auto_updatable() has verified that the
3208  * view contains a single base relation.
3209  */
3210  Assert(list_length(viewquery->jointree->fromlist) == 1);
3211  rtr = linitial_node(RangeTblRef, viewquery->jointree->fromlist);
3212 
3213  base_rt_index = rtr->rtindex;
3214  base_rte = rt_fetch(base_rt_index, viewquery->rtable);
3215  Assert(base_rte->rtekind == RTE_RELATION);
3216 
3217  /*
3218  * Up to now, the base relation hasn't been touched at all in our query.
3219  * We need to acquire lock on it before we try to do anything with it.
3220  * (The subsequent recursive call of RewriteQuery will suppose that we
3221  * already have the right lock!) Since it will become the query target
3222  * relation, RowExclusiveLock is always the right thing.
3223  */
3224  base_rel = table_open(base_rte->relid, RowExclusiveLock);
3225 
3226  /*
3227  * While we have the relation open, update the RTE's relkind, just in case
3228  * it changed since this view was made (cf. AcquireRewriteLocks).
3229  */
3230  base_rte->relkind = base_rel->rd_rel->relkind;
3231 
3232  /*
3233  * If the view query contains any sublink subqueries then we need to also
3234  * acquire locks on any relations they refer to. We know that there won't
3235  * be any subqueries in the range table or CTEs, so we can skip those, as
3236  * in AcquireRewriteLocks.
3237  */
3238  if (viewquery->hasSubLinks)
3239  {
3241 
3242  context.for_execute = true;
3243  query_tree_walker(viewquery, acquireLocksOnSubLinks, &context,
3245  }
3246 
3247  /*
3248  * Create a new target RTE describing the base relation, and add it to the
3249  * outer query's rangetable. (What's happening in the next few steps is
3250  * very much like what the planner would do to "pull up" the view into the
3251  * outer query. Perhaps someday we should refactor things enough so that
3252  * we can share code with the planner.)
3253  *
3254  * Be sure to set rellockmode to the correct thing for the target table.
3255  * Since we copied the whole viewquery above, we can just scribble on
3256  * base_rte instead of copying it.
3257  */
3258  new_rte = base_rte;
3259  new_rte->rellockmode = RowExclusiveLock;
3260 
3261  parsetree->rtable = lappend(parsetree->rtable, new_rte);
3262  new_rt_index = list_length(parsetree->rtable);
3263 
3264  /*
3265  * INSERTs never inherit. For UPDATE/DELETE, we use the view query's
3266  * inheritance flag for the base relation.
3267  */
3268  if (parsetree->commandType == CMD_INSERT)
3269  new_rte->inh = false;
3270 
3271  /*
3272  * Adjust the view's targetlist Vars to reference the new target RTE, ie
3273  * make their varnos be new_rt_index instead of base_rt_index. There can
3274  * be no Vars for other rels in the tlist, so this is sufficient to pull
3275  * up the tlist expressions for use in the outer query. The tlist will
3276  * provide the replacement expressions used by ReplaceVarsFromTargetList
3277  * below.
3278  */
3279  view_targetlist = viewquery->targetList;
3280 
3281  ChangeVarNodes((Node *) view_targetlist,
3282  base_rt_index,
3283  new_rt_index,
3284  0);
3285 
3286  /*
3287  * If the view has "security_invoker" set, mark the new target RTE for the
3288  * permissions checks that we want to enforce against the query caller.
3289  * Otherwise we want to enforce them against the view owner.
3290  *
3291  * At the relation level, require the same INSERT/UPDATE/DELETE
3292  * permissions that the query caller needs against the view. We drop the
3293  * ACL_SELECT bit that is presumably in new_rte->requiredPerms initially.
3294  *
3295  * Note: the original view RTE remains in the query's rangetable list.
3296  * Although it will be unused in the query plan, we need it there so that
3297  * the executor still performs appropriate permissions checks for the
3298  * query caller's use of the view.
3299  */
3300  if (RelationHasSecurityInvoker(view))
3301  new_rte->checkAsUser = InvalidOid;
3302  else
3303  new_rte->checkAsUser = view->rd_rel->relowner;
3304 
3305  new_rte->requiredPerms = view_rte->requiredPerms;
3306 
3307  /*
3308  * Now for the per-column permissions bits.
3309  *
3310  * Initially, new_rte contains selectedCols permission check bits for all
3311  * base-rel columns referenced by the view, but since the view is a SELECT
3312  * query its insertedCols/updatedCols is empty. We set insertedCols and
3313  * updatedCols to include all the columns the outer query is trying to
3314  * modify, adjusting the column numbers as needed. But we leave
3315  * selectedCols as-is, so the view owner must have read permission for all
3316  * columns used in the view definition, even if some of them are not read
3317  * by the outer query. We could try to limit selectedCols to only columns
3318  * used in the transformed query, but that does not correspond to what
3319  * happens in ordinary SELECT usage of a view: all referenced columns must
3320  * have read permission, even if optimization finds that some of them can
3321  * be discarded during query transformation. The flattening we're doing
3322  * here is an optional optimization, too. (If you are unpersuaded and
3323  * want to change this, note that applying adjust_view_column_set to
3324  * view_rte->selectedCols is clearly *not* the right answer, since that
3325  * neglects base-rel columns used in the view's WHERE quals.)
3326  *
3327  * This step needs the modified view targetlist, so we have to do things
3328  * in this order.
3329  */
3330  Assert(bms_is_empty(new_rte->insertedCols) &&
3331  bms_is_empty(new_rte->updatedCols));
3332 
3333  new_rte->insertedCols = adjust_view_column_set(view_rte->insertedCols,
3334  view_targetlist);
3335 
3336  new_rte->updatedCols = adjust_view_column_set(view_rte->updatedCols,
3337  view_targetlist);
3338 
3339  /*
3340  * Move any security barrier quals from the view RTE onto the new target
3341  * RTE. Any such quals should now apply to the new target RTE and will
3342  * not reference the original view RTE in the rewritten query.
3343  */
3344  new_rte->securityQuals = view_rte->securityQuals;
3345  view_rte->securityQuals = NIL;
3346 
3347  /*
3348  * Now update all Vars in the outer query that reference the view to
3349  * reference the appropriate column of the base relation instead.
3350  */
3351  parsetree = (Query *)
3352  ReplaceVarsFromTargetList((Node *) parsetree,
3353  parsetree->resultRelation,
3354  0,
3355  view_rte,
3356  view_targetlist,
3358  0,
3359  &parsetree->hasSubLinks);
3360 
3361  /*
3362  * Update all other RTI references in the query that point to the view
3363  * (for example, parsetree->resultRelation itself) to point to the new
3364  * base relation instead. Vars will not be affected since none of them
3365  * reference parsetree->resultRelation any longer.
3366  */
3367  ChangeVarNodes((Node *) parsetree,
3368  parsetree->resultRelation,
3369  new_rt_index,
3370  0);
3371  Assert(parsetree->resultRelation == new_rt_index);
3372 
3373  /*
3374  * For INSERT/UPDATE we must also update resnos in the targetlist to refer
3375  * to columns of the base relation, since those indicate the target
3376  * columns to be affected.
3377  *
3378  * Note that this destroys the resno ordering of the targetlist, but that
3379  * will be fixed when we recurse through rewriteQuery, which will invoke
3380  * rewriteTargetListIU again on the updated targetlist.
3381  */
3382  if (parsetree->commandType != CMD_DELETE)
3383  {
3384  foreach(lc, parsetree->targetList)
3385  {
3386  TargetEntry *tle = (TargetEntry *) lfirst(lc);
3387  TargetEntry *view_tle;
3388 
3389  if (tle->resjunk)
3390  continue;
3391 
3392  view_tle = get_tle_by_resno(view_targetlist, tle->resno);
3393  if (view_tle != NULL && !view_tle->resjunk && IsA(view_tle->expr, Var))
3394  tle->resno = ((Var *) view_tle->expr)->varattno;
3395  else
3396  elog(ERROR, "attribute number %d not found in view targetlist",
3397  tle->resno);
3398  }
3399  }
3400 
3401  /*
3402  * For INSERT .. ON CONFLICT .. DO UPDATE, we must also update assorted
3403  * stuff in the onConflict data structure.
3404  */
3405  if (parsetree->onConflict &&
3406  parsetree->onConflict->action == ONCONFLICT_UPDATE)
3407  {
3408  Index old_exclRelIndex,
3409  new_exclRelIndex;
3410  ParseNamespaceItem *new_exclNSItem;
3411  RangeTblEntry *new_exclRte;
3412  List *tmp_tlist;
3413 
3414  /*
3415  * Like the INSERT/UPDATE code above, update the resnos in the
3416  * auxiliary UPDATE targetlist to refer to columns of the base
3417  * relation.
3418  */
3419  foreach(lc, parsetree->onConflict->onConflictSet)
3420  {
3421  TargetEntry *tle = (TargetEntry *) lfirst(lc);
3422  TargetEntry *view_tle;
3423 
3424  if (tle->resjunk)
3425  continue;
3426 
3427  view_tle = get_tle_by_resno(view_targetlist, tle->resno);
3428  if (view_tle != NULL && !view_tle->resjunk && IsA(view_tle->expr, Var))
3429  tle->resno = ((Var *) view_tle->expr)->varattno;
3430  else
3431  elog(ERROR, "attribute number %d not found in view targetlist",
3432  tle->resno);
3433  }
3434 
3435  /*
3436  * Also, create a new RTE for the EXCLUDED pseudo-relation, using the
3437  * query's new base rel (which may well have a different column list
3438  * from the view, hence we need a new column alias list). This should
3439  * match transformOnConflictClause. In particular, note that the
3440  * relkind is set to composite to signal that we're not dealing with
3441  * an actual relation, and no permissions checks are wanted.
3442  */
3443  old_exclRelIndex = parsetree->onConflict->exclRelIndex;
3444 
3445  new_exclNSItem = addRangeTableEntryForRelation(make_parsestate(NULL),
3446  base_rel,
3448  makeAlias("excluded", NIL),
3449  false, false);
3450  new_exclRte = new_exclNSItem->p_rte;
3451  new_exclRte->relkind = RELKIND_COMPOSITE_TYPE;
3452  new_exclRte->requiredPerms = 0;
3453  /* other permissions fields in new_exclRte are already empty */
3454 
3455  parsetree->rtable = lappend(parsetree->rtable, new_exclRte);
3456  new_exclRelIndex = parsetree->onConflict->exclRelIndex =
3457  list_length(parsetree->rtable);
3458 
3459  /*
3460  * Replace the targetlist for the EXCLUDED pseudo-relation with a new
3461  * one, representing the columns from the new base relation.
3462  */
3463  parsetree->onConflict->exclRelTlist =
3464  BuildOnConflictExcludedTargetlist(base_rel, new_exclRelIndex);
3465 
3466  /*
3467  * Update all Vars in the ON CONFLICT clause that refer to the old
3468  * EXCLUDED pseudo-relation. We want to use the column mappings
3469  * defined in the view targetlist, but we need the outputs to refer to
3470  * the new EXCLUDED pseudo-relation rather than the new target RTE.
3471  * Also notice that "EXCLUDED.*" will be expanded using the view's
3472  * rowtype, which seems correct.
3473  */
3474  tmp_tlist = copyObject(view_targetlist);
3475 
3476  ChangeVarNodes((Node *) tmp_tlist, new_rt_index,
3477  new_exclRelIndex, 0);
3478 
3479  parsetree->onConflict = (OnConflictExpr *)
3480  ReplaceVarsFromTargetList((Node *) parsetree->onConflict,
3481  old_exclRelIndex,
3482  0,
3483  view_rte,
3484  tmp_tlist,
3486  0,
3487  &parsetree->hasSubLinks);
3488  }
3489 
3490  /*
3491  * For UPDATE/DELETE, pull up any WHERE quals from the view. We know that
3492  * any Vars in the quals must reference the one base relation, so we need
3493  * only adjust their varnos to reference the new target (just the same as
3494  * we did with the view targetlist).
3495  *
3496  * If it's a security-barrier view, its WHERE quals must be applied before
3497  * quals from the outer query, so we attach them to the RTE as security
3498  * barrier quals rather than adding them to the main WHERE clause.
3499  *
3500  * For INSERT, the view's quals can be ignored in the main query.
3501  */
3502  if (parsetree->commandType != CMD_INSERT &&
3503  viewquery->jointree->quals != NULL)
3504  {
3505  Node *viewqual = (Node *) viewquery->jointree->quals;
3506 
3507  /*
3508  * Even though we copied viewquery already at the top of this
3509  * function, we must duplicate the viewqual again here, because we may
3510  * need to use the quals again below for a WithCheckOption clause.
3511  */
3512  viewqual = copyObject(viewqual);
3513 
3514  ChangeVarNodes(viewqual, base_rt_index, new_rt_index, 0);
3515 
3516  if (RelationIsSecurityView(view))
3517  {
3518  /*
3519  * The view's quals go in front of existing barrier quals: those
3520  * would have come from an outer level of security-barrier view,
3521  * and so must get evaluated later.
3522  *
3523  * Note: the parsetree has been mutated, so the new_rte pointer is
3524  * stale and needs to be re-computed.
3525  */
3526  new_rte = rt_fetch(new_rt_index, parsetree->rtable);
3527  new_rte->securityQuals = lcons(viewqual, new_rte->securityQuals);
3528 
3529  /*
3530  * Do not set parsetree->hasRowSecurity, because these aren't RLS
3531  * conditions (they aren't affected by enabling/disabling RLS).
3532  */
3533 
3534  /*
3535  * Make sure that the query is marked correctly if the added qual
3536  * has sublinks.
3537  */
3538  if (!parsetree->hasSubLinks)
3539  parsetree->hasSubLinks = checkExprHasSubLink(viewqual);
3540  }
3541  else
3542  AddQual(parsetree, (Node *) viewqual);
3543  }
3544 
3545  /*
3546  * For INSERT/UPDATE, if the view has the WITH CHECK OPTION, or any parent
3547  * view specified WITH CASCADED CHECK OPTION, add the quals from the view
3548  * to the query's withCheckOptions list.
3549  */
3550  if (parsetree->commandType != CMD_DELETE)
3551  {
3552  bool has_wco = RelationHasCheckOption(view);
3553  bool cascaded = RelationHasCascadedCheckOption(view);
3554 
3555  /*
3556  * If the parent view has a cascaded check option, treat this view as
3557  * if it also had a cascaded check option.
3558  *
3559  * New WithCheckOptions are added to the start of the list, so if
3560  * there is a cascaded check option, it will be the first item in the
3561  * list.
3562  */
3563  if (parsetree->withCheckOptions != NIL)
3564  {
3565  WithCheckOption *parent_wco =
3566  (WithCheckOption *) linitial(parsetree->withCheckOptions);
3567 
3568  if (parent_wco->cascaded)
3569  {
3570  has_wco = true;
3571  cascaded = true;
3572  }
3573  }
3574 
3575  /*
3576  * Add the new WithCheckOption to the start of the list, so that
3577  * checks on inner views are run before checks on outer views, as
3578  * required by the SQL standard.
3579  *
3580  * If the new check is CASCADED, we need to add it even if this view
3581  * has no quals, since there may be quals on child views. A LOCAL
3582  * check can be omitted if this view has no quals.
3583  */
3584  if (has_wco && (cascaded || viewquery->jointree->quals != NULL))
3585  {
3586  WithCheckOption *wco;
3587 
3588  wco = makeNode(WithCheckOption);
3589  wco->kind = WCO_VIEW_CHECK;
3590  wco->relname = pstrdup(RelationGetRelationName(view));
3591  wco->polname = NULL;
3592  wco->qual = NULL;
3593  wco->cascaded = cascaded;
3594 
3595  parsetree->withCheckOptions = lcons(wco,
3596  parsetree->withCheckOptions);
3597 
3598  if (viewquery->jointree->quals != NULL)
3599  {
3600  wco->qual = (Node *) viewquery->jointree->quals;
3601  ChangeVarNodes(wco->qual, base_rt_index, new_rt_index, 0);
3602 
3603  /*
3604  * Make sure that the query is marked correctly if the added
3605  * qual has sublinks. We can skip this check if the query is
3606  * already marked, or if the command is an UPDATE, in which
3607  * case the same qual will have already been added, and this
3608  * check will already have been done.
3609  */
3610  if (!parsetree->hasSubLinks &&
3611  parsetree->commandType != CMD_UPDATE)
3612  parsetree->hasSubLinks = checkExprHasSubLink(wco->qual);
3613  }
3614  }
3615  }
3616 
3617  table_close(base_rel, NoLock);
3618 
3619  return parsetree;
3620 }
int errdetail_internal(const char *fmt,...)
Definition: elog.c:1066
#define _(x)
Definition: elog.c:90
#define RowExclusiveLock
Definition: lockdefs.h:38
Alias * makeAlias(const char *aliasname, List *colnames)
Definition: makefuncs.c:387
ParseState * make_parsestate(ParseState *parentParseState)
Definition: parse_node.c:43
ParseNamespaceItem * addRangeTableEntryForRelation(ParseState *pstate, Relation rel, int lockmode, Alias *alias, bool inh, bool inFromCl)
@ WCO_VIEW_CHECK
Definition: parsenodes.h:1241
List * BuildOnConflictExcludedTargetlist(Relation targetrel, Index exclRelIndex)
Definition: analyze.c:1170
#define RelationHasCheckOption(relation)
Definition: rel.h:442
#define RelationHasSecurityInvoker(relation)
Definition: rel.h:432
#define RelationHasCascadedCheckOption(relation)
Definition: rel.h:464
List * exclRelTlist
Definition: primnodes.h:1692
RangeTblEntry * p_rte
Definition: parse_node.h:272
List * withCheckOptions
Definition: parsenodes.h:195

References _, acquireLocksOnSubLinks(), OnConflictExpr::action, AddQual(), addRangeTableEntryForRelation(), adjust_view_column_set(), Assert(), bms_add_member(), bms_is_empty(), BuildOnConflictExcludedTargetlist(), WithCheckOption::cascaded, ChangeVarNodes(), RangeTblEntry::checkAsUser, checkExprHasSubLink(), CMD_DELETE, CMD_INSERT, CMD_UPDATE, Query::commandType, copyObject, elog(), ereport, errcode(), errdetail_internal(), errhint(), errmsg(), ERROR, OnConflictExpr::exclRelIndex, OnConflictExpr::exclRelTlist, TargetEntry::expr, FirstLowInvalidHeapAttributeNumber, acquireLocksOnSubLinks_context::for_execute, FromExpr::fromlist, get_tle_by_resno(), get_view_query(), Query::hasSubLinks, RangeTblEntry::inh, RangeTblEntry::insertedCols, InvalidOid, IsA, Query::jointree, WithCheckOption::kind, lappend(), lcons(), lfirst, linitial, linitial_node, list_length(), make_parsestate(), makeAlias(), makeNode, 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, RelationHasCascadedCheckOption, RelationHasCheckOption, RelationHasSecurityInvoker, RelationIsSecurityView, RangeTblEntry::relid, RangeTblEntry::relkind, RangeTblEntry::rellockmode, WithCheckOption::relname, REPLACEVARS_REPORT_ERROR, ReplaceVarsFromTargetList(), RangeTblEntry::requiredPerms, TargetEntry::resjunk, TargetEntry::resno, Query::resultRelation, RowExclusiveLock, rt_fetch, Query::rtable, RTE_RELATION, RangeTblEntry::rtekind, RangeTblRef::rtindex, RangeTblEntry::securityQuals, table_close(), table_open(), Query::targetList, RangeTblEntry::updatedCols, view_cols_are_auto_updatable(), view_query_is_auto_updatable(), WCO_VIEW_CHECK, and Query::withCheckOptions.

Referenced by RewriteQuery().

◆ rewriteValuesRTE()

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

Definition at line 1400 of file rewriteHandler.c.

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

References Assert(), bms_is_member(), build_column_default(), CMD_INSERT, COERCE_IMPLICIT_CAST, coerce_to_domain(), COERCION_IMPLICIT, SetToDefault::collation, 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, RelationData::rd_rules, TargetEntry::resno, Query::resultRelation, RTE_VALUES, RangeTblEntry::rtekind, searchForDefault(), Query::targetList, TupleDescAttr, SetToDefault::typeId, SetToDefault::typeMod, 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 1595 of file rewriteHandler.c.

1596 {
1597  List *newValues;
1598  ListCell *lc;
1599 
1600  Assert(rte->rtekind == RTE_VALUES);
1601  newValues = NIL;
1602  foreach(lc, rte->values_lists)
1603  {
1604  List *sublist = (List *) lfirst(lc);
1605  List *newList = NIL;
1606  ListCell *lc2;
1607 
1608  foreach(lc2, sublist)
1609  {
1610  Node *col = (Node *) lfirst(lc2);
1611 
1612  if (IsA(col, SetToDefault))
1613  {
1614  SetToDefault *def = (SetToDefault *) col;
1615 
1616  newList = lappend(newList, makeNullConst(def->typeId,
1617  def->typeMod,
1618  def->collation));
1619  }
1620  else
1621  newList = lappend(newList, col);
1622  }
1623  newValues = lappend(newValues, newList);
1624  }
1625  rte->values_lists = newValues;
1626 }

References Assert(), SetToDefault::collation, IsA, lappend(), lfirst, makeNullConst(), NIL, RTE_VALUES, RangeTblEntry::rtekind, SetToDefault::typeId, SetToDefault::typeMod, and RangeTblEntry::values_lists.

Referenced by RewriteQuery().

◆ searchForDefault()

static bool searchForDefault ( RangeTblEntry rte)
static

Definition at line 1286 of file rewriteHandler.c.

1287 {
1288  ListCell *lc;
1289 
1290  foreach(lc, rte->values_lists)
1291  {
1292  List *sublist = (List *) lfirst(lc);
1293  ListCell *lc2;
1294 
1295  foreach(lc2, sublist)
1296  {
1297  Node *col = (Node *) lfirst(lc2);
1298 
1299  if (IsA(col, SetToDefault))
1300  return true;
1301  }
1302  }
1303  return false;
1304 }

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

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

References TargetEntry::expr, gettext_noop, if(), IsA, TargetEntry::resjunk, 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 2736 of file rewriteHandler.c.

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

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

Referenced by relation_is_updatable(), and rewriteTargetView().

◆ view_has_instead_trigger()

static bool view_has_instead_trigger ( Relation  view,
CmdType  event 
)
static

Definition at line 2502 of file rewriteHandler.c.

2503 {
2504  TriggerDesc *trigDesc = view->trigdesc;
2505 
2506  switch (event)
2507  {
2508  case CMD_INSERT:
2509  if (trigDesc && trigDesc->trig_insert_instead_row)
2510  return true;
2511  break;
2512  case CMD_UPDATE:
2513  if (trigDesc && trigDesc->trig_update_instead_row)
2514  return true;
2515  break;
2516  case CMD_DELETE:
2517  if (trigDesc && trigDesc->trig_delete_instead_row)
2518  return true;
2519  break;
2520  default:
2521  elog(ERROR, "unrecognized CmdType: %d", (int) event);
2522  break;
2523  }
2524  return false;
2525 }

References CMD_DELETE, CMD_INSERT, CMD_UPDATE, elog(), ERROR, TriggerDesc::trig_delete_instead_row, TriggerDesc::trig_insert_instead_row, TriggerDesc::trig_update_instead_row, and RelationData::trigdesc.

Referenced by RewriteQuery(), and rewriteValuesRTE().

◆ view_query_is_auto_updatable()

const char* view_query_is_auto_updatable ( Query viewquery,
bool  check_cols 
)

Definition at line 2588 of file rewriteHandler.c.

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

References Query::cteList, Query::distinctClause, FromExpr::fromlist, gettext_noop, Query::groupClause, Query::groupingSets, Query::hasAggs, Query::hasTargetSRFs, Query::hasWindowFuncs, Query::havingQual, IsA, Query::jointree, lfirst, Query::limitCount, Query::limitOffset, linitial, list_length(), NIL, RangeTblEntry::relkind, rt_fetch, Query::rtable, RTE_RELATION, RangeTblEntry::rtekind, RangeTblRef::rtindex, Query::setOperations, RangeTblEntry::tablesample, Query::targetList, and view_col_is_auto_updatable().

Referenced by ATExecSetRelOptions(), DefineView(), relation_is_updatable(), and rewriteTargetView().