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, bool force_nulls, Bitmapset *unused_cols)
 
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)
 
ListQueryRewrite (Query *parsetree)
 

Macro Definition Documentation

◆ ALL_EVENTS

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

Referenced by relation_is_updatable().

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

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

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

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

◆ AcquireRewriteLocks()

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

Definition at line 139 of file rewriteHandler.c.

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

Referenced by acquireLocksOnSubLinks(), AcquireRewriteLocks(), ApplyRetrieveRule(), fmgr_sql_validator(), get_query_def(), init_sql_fcache(), inline_set_returning_function(), make_ruledef(), print_function_sqlbody(), refresh_matview_datafill(), and rewriteRuleAction().

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

◆ adjust_view_column_set()

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

Definition at line 2958 of file rewriteHandler.c.

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

2959 {
2960  Bitmapset *result = NULL;
2961  int col;
2962 
2963  col = -1;
2964  while ((col = bms_next_member(cols, col)) >= 0)
2965  {
2966  /* bit numbers are offset by FirstLowInvalidHeapAttributeNumber */
2968 
2969  if (attno == InvalidAttrNumber)
2970  {
2971  /*
2972  * There's a whole-row reference to the view. For permissions
2973  * purposes, treat it as a reference to each column available from
2974  * the view. (We should *not* convert this to a whole-row
2975  * reference to the base relation, since the view may not touch
2976  * all columns of the base relation.)
2977  */
2978  ListCell *lc;
2979 
2980  foreach(lc, targetlist)
2981  {
2982  TargetEntry *tle = lfirst_node(TargetEntry, lc);
2983  Var *var;
2984 
2985  if (tle->resjunk)
2986  continue;
2987  var = castNode(Var, tle->expr);
2988  result = bms_add_member(result,
2989  var->varattno - FirstLowInvalidHeapAttributeNumber);
2990  }
2991  }
2992  else
2993  {
2994  /*
2995  * Views do not have system columns, so we do not expect to see
2996  * any other system attnos here. If we do find one, the error
2997  * case will apply.
2998  */
2999  TargetEntry *tle = get_tle_by_resno(targetlist, attno);
3000 
3001  if (tle != NULL && !tle->resjunk && IsA(tle->expr, Var))
3002  {
3003  Var *var = (Var *) tle->expr;
3004 
3005  result = bms_add_member(result,
3006  var->varattno - FirstLowInvalidHeapAttributeNumber);
3007  }
3008  else
3009  elog(ERROR, "attribute number %d not found in view targetlist",
3010  attno);
3011  }
3012  }
3013 
3014  return result;
3015 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:589
#define castNode(_type_, nodeptr)
Definition: nodes.h:607
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1043
AttrNumber varattno
Definition: primnodes.h:191
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
Definition: primnodes.h:186
bool resjunk
Definition: primnodes.h:1462
#define ERROR
Definition: elog.h:46
#define lfirst_node(type, lc)
Definition: pg_list.h:172
Expr * expr
Definition: primnodes.h:1455
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:736
#define InvalidAttrNumber
Definition: attnum.h:23
#define elog(elevel,...)
Definition: elog.h:232
TargetEntry * get_tle_by_resno(List *tlist, AttrNumber resno)
int16 AttrNumber
Definition: attnum.h:21

◆ adjustJoinTreeList()

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

Definition at line 668 of file rewriteHandler.c.

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

Referenced by rewriteRuleAction().

669 {
670  List *newjointree = copyObject(parsetree->jointree->fromlist);
671  ListCell *l;
672 
673  if (removert)
674  {
675  foreach(l, newjointree)
676  {
677  RangeTblRef *rtr = lfirst(l);
678 
679  if (IsA(rtr, RangeTblRef) &&
680  rtr->rtindex == rt_index)
681  {
682  newjointree = foreach_delete_current(newjointree, l);
683  break;
684  }
685  }
686  }
687  return newjointree;
688 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:589
FromExpr * jointree
Definition: parsenodes.h:148
List * fromlist
Definition: primnodes.h:1564
#define foreach_delete_current(lst, cell)
Definition: pg_list.h:369
#define lfirst(lc)
Definition: pg_list.h:169
#define copyObject(obj)
Definition: nodes.h:654
Definition: pg_list.h:50

◆ ApplyRetrieveRule()

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

Definition at line 1699 of file rewriteHandler.c.

References AcquireRewriteLocks(), RewriteRule::actions, 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(), RewriteRule::qual, 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().

1704 {
1705  Query *rule_action;
1706  RangeTblEntry *rte,
1707  *subrte;
1708  RowMarkClause *rc;
1709 
1710  if (list_length(rule->actions) != 1)
1711  elog(ERROR, "expected just one rule action");
1712  if (rule->qual != NULL)
1713  elog(ERROR, "cannot handle qualified ON SELECT rule");
1714 
1715  if (rt_index == parsetree->resultRelation)
1716  {
1717  /*
1718  * We have a view as the result relation of the query, and it wasn't
1719  * rewritten by any rule. This case is supported if there is an
1720  * INSTEAD OF trigger that will trap attempts to insert/update/delete
1721  * view rows. The executor will check that; for the moment just plow
1722  * ahead. We have two cases:
1723  *
1724  * For INSERT, we needn't do anything. The unmodified RTE will serve
1725  * fine as the result relation.
1726  *
1727  * For UPDATE/DELETE, we need to expand the view so as to have source
1728  * data for the operation. But we also need an unmodified RTE to
1729  * serve as the target. So, copy the RTE and add the copy to the
1730  * rangetable. Note that the copy does not get added to the jointree.
1731  * Also note that there's a hack in fireRIRrules to avoid calling this
1732  * function again when it arrives at the copied RTE.
1733  */
1734  if (parsetree->commandType == CMD_INSERT)
1735  return parsetree;
1736  else if (parsetree->commandType == CMD_UPDATE ||
1737  parsetree->commandType == CMD_DELETE)
1738  {
1739  RangeTblEntry *newrte;
1740  Var *var;
1741  TargetEntry *tle;
1742 
1743  rte = rt_fetch(rt_index, parsetree->rtable);
1744  newrte = copyObject(rte);
1745  parsetree->rtable = lappend(parsetree->rtable, newrte);
1746  parsetree->resultRelation = list_length(parsetree->rtable);
1747 
1748  /*
1749  * There's no need to do permissions checks twice, so wipe out the
1750  * permissions info for the original RTE (we prefer to keep the
1751  * bits set on the result RTE).
1752  */
1753  rte->requiredPerms = 0;
1754  rte->checkAsUser = InvalidOid;
1755  rte->selectedCols = NULL;
1756  rte->insertedCols = NULL;
1757  rte->updatedCols = NULL;
1758  rte->extraUpdatedCols = NULL;
1759 
1760  /*
1761  * For the most part, Vars referencing the view should remain as
1762  * they are, meaning that they implicitly represent OLD values.
1763  * But in the RETURNING list if any, we want such Vars to
1764  * represent NEW values, so change them to reference the new RTE.
1765  *
1766  * Since ChangeVarNodes scribbles on the tree in-place, copy the
1767  * RETURNING list first for safety.
1768  */
1769  parsetree->returningList = copyObject(parsetree->returningList);
1770  ChangeVarNodes((Node *) parsetree->returningList, rt_index,
1771  parsetree->resultRelation, 0);
1772 
1773  /*
1774  * To allow the executor to compute the original view row to pass
1775  * to the INSTEAD OF trigger, we add a resjunk whole-row Var
1776  * referencing the original RTE. This will later get expanded
1777  * into a RowExpr computing all the OLD values of the view row.
1778  */
1779  var = makeWholeRowVar(rte, rt_index, 0, false);
1780  tle = makeTargetEntry((Expr *) var,
1781  list_length(parsetree->targetList) + 1,
1782  pstrdup("wholerow"),
1783  true);
1784 
1785  parsetree->targetList = lappend(parsetree->targetList, tle);
1786 
1787  /* Now, continue with expanding the original view RTE */
1788  }
1789  else
1790  elog(ERROR, "unrecognized commandType: %d",
1791  (int) parsetree->commandType);
1792  }
1793 
1794  /*
1795  * Check if there's a FOR [KEY] UPDATE/SHARE clause applying to this view.
1796  *
1797  * Note: we needn't explicitly consider any such clauses appearing in
1798  * ancestor query levels; their effects have already been pushed down to
1799  * here by markQueryForLocking, and will be reflected in "rc".
1800  */
1801  rc = get_parse_rowmark(parsetree, rt_index);
1802 
1803  /*
1804  * Make a modifiable copy of the view query, and acquire needed locks on
1805  * the relations it mentions. Force at least RowShareLock for all such
1806  * rels if there's a FOR [KEY] UPDATE/SHARE clause affecting this view.
1807  */
1808  rule_action = copyObject(linitial(rule->actions));
1809 
1810  AcquireRewriteLocks(rule_action, true, (rc != NULL));
1811 
1812  /*
1813  * If FOR [KEY] UPDATE/SHARE of view, mark all the contained tables as
1814  * implicit FOR [KEY] UPDATE/SHARE, the same as the parser would have done
1815  * if the view's subquery had been written out explicitly.
1816  */
1817  if (rc != NULL)
1818  markQueryForLocking(rule_action, (Node *) rule_action->jointree,
1819  rc->strength, rc->waitPolicy, true);
1820 
1821  /*
1822  * Recursively expand any view references inside the view.
1823  *
1824  * Note: this must happen after markQueryForLocking. That way, any UPDATE
1825  * permission bits needed for sub-views are initially applied to their
1826  * RTE_RELATION RTEs by markQueryForLocking, and then transferred to their
1827  * OLD rangetable entries by the action below (in a recursive call of this
1828  * routine).
1829  */
1830  rule_action = fireRIRrules(rule_action, activeRIRs);
1831 
1832  /*
1833  * Now, plug the view query in as a subselect, converting the relation's
1834  * original RTE to a subquery RTE.
1835  */
1836  rte = rt_fetch(rt_index, parsetree->rtable);
1837 
1838  rte->rtekind = RTE_SUBQUERY;
1839  rte->subquery = rule_action;
1840  rte->security_barrier = RelationIsSecurityView(relation);
1841  /* Clear fields that should not be set in a subquery RTE */
1842  rte->relid = InvalidOid;
1843  rte->relkind = 0;
1844  rte->rellockmode = 0;
1845  rte->tablesample = NULL;
1846  rte->inh = false; /* must not be set for a subquery */
1847 
1848  /*
1849  * We move the view's permission check data down to its rangetable. The
1850  * checks will actually be done against the OLD entry therein.
1851  */
1852  subrte = rt_fetch(PRS2_OLD_VARNO, rule_action->rtable);
1853  Assert(subrte->relid == relation->rd_id);
1854  subrte->requiredPerms = rte->requiredPerms;
1855  subrte->checkAsUser = rte->checkAsUser;
1856  subrte->selectedCols = rte->selectedCols;
1857  subrte->insertedCols = rte->insertedCols;
1858  subrte->updatedCols = rte->updatedCols;
1859  subrte->extraUpdatedCols = rte->extraUpdatedCols;
1860 
1861  rte->requiredPerms = 0; /* no permission check on subquery itself */
1862  rte->checkAsUser = InvalidOid;
1863  rte->selectedCols = NULL;
1864  rte->insertedCols = NULL;
1865  rte->updatedCols = NULL;
1866  rte->extraUpdatedCols = NULL;
1867 
1868  return parsetree;
1869 }
static void markQueryForLocking(Query *qry, Node *jtnode, LockClauseStrength strength, LockWaitPolicy waitPolicy, bool pushedDown)
Node * qual
Definition: prs2lock.h:28
RowMarkClause * get_parse_rowmark(Query *qry, Index rtindex)
FromExpr * jointree
Definition: parsenodes.h:148
char * pstrdup(const char *in)
Definition: mcxt.c:1299
int resultRelation
Definition: parsenodes.h:130
Definition: nodes.h:538
AclMode requiredPerms
Definition: parsenodes.h:1157
Definition: primnodes.h:186
LockClauseStrength strength
Definition: parsenodes.h:1421
List * targetList
Definition: parsenodes.h:150
Bitmapset * extraUpdatedCols
Definition: parsenodes.h:1162
Bitmapset * selectedCols
Definition: parsenodes.h:1159
#define linitial(l)
Definition: pg_list.h:174
List * rtable
Definition: parsenodes.h:147
#define ERROR
Definition: elog.h:46
Var * makeWholeRowVar(RangeTblEntry *rte, int varno, Index varlevelsup, bool allowScalar)
Definition: makefuncs.c:133
void AcquireRewriteLocks(Query *parsetree, bool forExecute, bool forUpdatePushedDown)
List * actions
Definition: prs2lock.h:29
List * returningList
Definition: parsenodes.h:156
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:238
Oid rd_id
Definition: rel.h:111
List * lappend(List *list, void *datum)
Definition: list.c:336
#define PRS2_OLD_VARNO
Definition: primnodes.h:183
bool security_barrier
Definition: parsenodes.h:1043
#define InvalidOid
Definition: postgres_ext.h:36
Bitmapset * updatedCols
Definition: parsenodes.h:1161
CmdType commandType
Definition: parsenodes.h:120
#define Assert(condition)
Definition: c.h:804
static int list_length(const List *l)
Definition: pg_list.h:149
LockWaitPolicy waitPolicy
Definition: parsenodes.h:1422
RTEKind rtekind
Definition: parsenodes.h:1007
Query * subquery
Definition: parsenodes.h:1042
#define elog(elevel,...)
Definition: elog.h:232
Bitmapset * insertedCols
Definition: parsenodes.h:1160
#define RelationIsSecurityView(relation)
Definition: rel.h:408
void ChangeVarNodes(Node *node, int rt_index, int new_index, int sublevels_up)
Definition: rewriteManip.c:610
#define copyObject(obj)
Definition: nodes.h:654
static Query * fireRIRrules(Query *parsetree, List *activeRIRs)
struct TableSampleClause * tablesample
Definition: parsenodes.h:1037

◆ build_column_default()

Node* build_column_default ( Relation  rel,
int  attrno 
)

Definition at line 1196 of file rewriteHandler.c.

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

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

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

◆ CopyAndAddInvertedQual()

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

Definition at line 2266 of file rewriteHandler.c.

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

2270 {
2271  /* Don't scribble on the passed qual (it's in the relcache!) */
2272  Node *new_qual = copyObject(rule_qual);
2274 
2275  context.for_execute = true;
2276 
2277  /*
2278  * In case there are subqueries in the qual, acquire necessary locks and
2279  * fix any deleted JOIN RTE entries. (This is somewhat redundant with
2280  * rewriteRuleAction, but not entirely ... consider restructuring so that
2281  * we only need to process the qual this way once.)
2282  */
2283  (void) acquireLocksOnSubLinks(new_qual, &context);
2284 
2285  /* Fix references to OLD */
2286  ChangeVarNodes(new_qual, PRS2_OLD_VARNO, rt_index, 0);
2287  /* Fix references to NEW */
2288  if (event == CMD_INSERT || event == CMD_UPDATE)
2289  new_qual = ReplaceVarsFromTargetList(new_qual,
2291  0,
2292  rt_fetch(rt_index,
2293  parsetree->rtable),
2294  parsetree->targetList,
2295  (event == CMD_UPDATE) ?
2298  rt_index,
2299  &parsetree->hasSubLinks);
2300  /* And attach the fixed qual */
2301  AddInvertedQual(parsetree, new_qual);
2302 
2303  return parsetree;
2304 }
static bool acquireLocksOnSubLinks(Node *node, acquireLocksOnSubLinks_context *context)
void AddInvertedQual(Query *parsetree, Node *qual)
Definition: nodes.h:538
List * targetList
Definition: parsenodes.h:150
List * rtable
Definition: parsenodes.h:147
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
#define PRS2_OLD_VARNO
Definition: primnodes.h:183
Node * ReplaceVarsFromTargetList(Node *node, int target_varno, int sublevels_up, RangeTblEntry *target_rte, List *targetlist, ReplaceVarsNoMatchOption nomatch_option, int nomatch_varno, bool *outer_hasSubLinks)
bool hasSubLinks
Definition: parsenodes.h:136
void ChangeVarNodes(Node *node, int rt_index, int new_index, int sublevels_up)
Definition: rewriteManip.c:610
#define copyObject(obj)
Definition: nodes.h:654
#define PRS2_NEW_VARNO
Definition: primnodes.h:184

◆ fill_extraUpdatedCols()

void fill_extraUpdatedCols ( RangeTblEntry target_rte,
Relation  target_relation 
)

Definition at line 1596 of file rewriteHandler.c.

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

Referenced by apply_handle_update(), and RewriteQuery().

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

◆ findDefaultOnlyColumns()

static Bitmapset * findDefaultOnlyColumns ( RangeTblEntry rte)
static

Definition at line 1307 of file rewriteHandler.c.

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

Referenced by rewriteTargetListIU().

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

◆ fireRIRonSubLink()

static bool fireRIRonSubLink ( Node node,
List activeRIRs 
)
static

Definition at line 1943 of file rewriteHandler.c.

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

Referenced by fireRIRrules().

1944 {
1945  if (node == NULL)
1946  return false;
1947  if (IsA(node, SubLink))
1948  {
1949  SubLink *sub = (SubLink *) node;
1950 
1951  /* Do what we came for */
1952  sub->subselect = (Node *) fireRIRrules((Query *) sub->subselect,
1953  activeRIRs);
1954  /* Fall through to process lefthand args of SubLink */
1955  }
1956 
1957  /*
1958  * Do NOT recurse into Query nodes, because fireRIRrules already processed
1959  * subselects of subselects for us.
1960  */
1962  (void *) activeRIRs);
1963 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:589
Definition: nodes.h:538
static bool fireRIRonSubLink(Node *node, List *activeRIRs)
bool expression_tree_walker(Node *node, bool(*walker)(), void *context)
Definition: nodeFuncs.c:1904
static Query * fireRIRrules(Query *parsetree, List *activeRIRs)

◆ fireRIRrules()

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

Definition at line 1974 of file rewriteHandler.c.

References acquireLocksOnSubLinks(), ApplyRetrieveRule(), CMD_SELECT, Query::cteList, CommonTableExpr::ctequery, CommonTableExpr::cycle_clause, ereport, errcode(), errmsg(), ERROR, RewriteRule::event, 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, RuleLock::numLocks, 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, RuleLock::rules, rules, CommonTableExpr::search_clause, RangeTblEntry::securityQuals, RangeTblEntry::subquery, table_close(), table_open(), and Query::withCheckOptions.

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

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

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

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

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

◆ get_assignment_input()

static Node * get_assignment_input ( Node node)
static

Definition at line 1167 of file rewriteHandler.c.

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

Referenced by process_matched_tle().

1168 {
1169  if (node == NULL)
1170  return NULL;
1171  if (IsA(node, FieldStore))
1172  {
1173  FieldStore *fstore = (FieldStore *) node;
1174 
1175  return (Node *) fstore->arg;
1176  }
1177  else if (IsA(node, SubscriptingRef))
1178  {
1179  SubscriptingRef *sbsref = (SubscriptingRef *) node;
1180 
1181  if (sbsref->refassgnexpr == NULL)
1182  return NULL;
1183 
1184  return (Node *) sbsref->refexpr;
1185  }
1186 
1187  return NULL;
1188 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:589
Expr * arg
Definition: primnodes.h:837
Definition: nodes.h:538
Expr * refassgnexpr
Definition: primnodes.h:451
Expr * refexpr
Definition: primnodes.h:449

◆ get_view_query()

Query* get_view_query ( Relation  view)

Definition at line 2427 of file rewriteHandler.c.

References RewriteRule::actions, Assert, CMD_SELECT, elog, ERROR, RewriteRule::event, i, linitial, list_length(), RuleLock::numLocks, RelationData::rd_rel, RelationData::rd_rules, and RuleLock::rules.

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

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

◆ markQueryForLocking()

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

Definition at line 1883 of file rewriteHandler.c.

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

Referenced by ApplyRetrieveRule().

1886 {
1887  if (jtnode == NULL)
1888  return;
1889  if (IsA(jtnode, RangeTblRef))
1890  {
1891  int rti = ((RangeTblRef *) jtnode)->rtindex;
1892  RangeTblEntry *rte = rt_fetch(rti, qry->rtable);
1893 
1894  if (rte->rtekind == RTE_RELATION)
1895  {
1896  applyLockingClause(qry, rti, strength, waitPolicy, pushedDown);
1898  }
1899  else if (rte->rtekind == RTE_SUBQUERY)
1900  {
1901  applyLockingClause(qry, rti, strength, waitPolicy, pushedDown);
1902  /* FOR UPDATE/SHARE of subquery is propagated to subquery's rels */
1904  strength, waitPolicy, true);
1905  }
1906  /* other RTE types are unaffected by FOR UPDATE */
1907  }
1908  else if (IsA(jtnode, FromExpr))
1909  {
1910  FromExpr *f = (FromExpr *) jtnode;
1911  ListCell *l;
1912 
1913  foreach(l, f->fromlist)
1914  markQueryForLocking(qry, lfirst(l), strength, waitPolicy, pushedDown);
1915  }
1916  else if (IsA(jtnode, JoinExpr))
1917  {
1918  JoinExpr *j = (JoinExpr *) jtnode;
1919 
1920  markQueryForLocking(qry, j->larg, strength, waitPolicy, pushedDown);
1921  markQueryForLocking(qry, j->rarg, strength, waitPolicy, pushedDown);
1922  }
1923  else
1924  elog(ERROR, "unrecognized node type: %d",
1925  (int) nodeTag(jtnode));
1926 }
static void markQueryForLocking(Query *qry, Node *jtnode, LockClauseStrength strength, LockWaitPolicy waitPolicy, bool pushedDown)
#define IsA(nodeptr, _type_)
Definition: nodes.h:589
FromExpr * jointree
Definition: parsenodes.h:148
Definition: nodes.h:538
AclMode requiredPerms
Definition: parsenodes.h:1157
List * fromlist
Definition: primnodes.h:1564
Node * larg
Definition: primnodes.h:1543
List * rtable
Definition: parsenodes.h:147
#define ERROR
Definition: elog.h:46
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
Node * rarg
Definition: primnodes.h:1544
#define lfirst(lc)
Definition: pg_list.h:169
#define ACL_SELECT_FOR_UPDATE
Definition: parsenodes.h:98
#define nodeTag(nodeptr)
Definition: nodes.h:543
RTEKind rtekind
Definition: parsenodes.h:1007
Query * subquery
Definition: parsenodes.h:1042
#define elog(elevel,...)
Definition: elog.h:232
void applyLockingClause(Query *qry, Index rtindex, LockClauseStrength strength, LockWaitPolicy waitPolicy, bool pushedDown)
Definition: analyze.c:3356

◆ matchLocks()

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

Definition at line 1633 of file rewriteHandler.c.

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

1638 {
1639  List *matching_locks = NIL;
1640  int nlocks;
1641  int i;
1642 
1643  if (rulelocks == NULL)
1644  return NIL;
1645 
1646  if (parsetree->commandType != CMD_SELECT)
1647  {
1648  if (parsetree->resultRelation != varno)
1649  return NIL;
1650  }
1651 
1652  nlocks = rulelocks->numLocks;
1653 
1654  for (i = 0; i < nlocks; i++)
1655  {
1656  RewriteRule *oneLock = rulelocks->rules[i];
1657 
1658  if (oneLock->event == CMD_UPDATE)
1659  *hasUpdate = true;
1660 
1661  /*
1662  * Suppress ON INSERT/UPDATE/DELETE rules that are disabled or
1663  * configured to not fire during the current sessions replication
1664  * role. ON SELECT rules will always be applied in order to keep views
1665  * working even in LOCAL or REPLICA role.
1666  */
1667  if (oneLock->event != CMD_SELECT)
1668  {
1670  {
1671  if (oneLock->enabled == RULE_FIRES_ON_ORIGIN ||
1672  oneLock->enabled == RULE_DISABLED)
1673  continue;
1674  }
1675  else /* ORIGIN or LOCAL ROLE */
1676  {
1677  if (oneLock->enabled == RULE_FIRES_ON_REPLICA ||
1678  oneLock->enabled == RULE_DISABLED)
1679  continue;
1680  }
1681  }
1682 
1683  if (oneLock->event == event)
1684  {
1685  if (parsetree->commandType != CMD_SELECT ||
1686  rangeTableEntry_used((Node *) parsetree, varno, 0))
1687  matching_locks = lappend(matching_locks, oneLock);
1688  }
1689  }
1690 
1691  return matching_locks;
1692 }
#define NIL
Definition: pg_list.h:65
int numLocks
Definition: prs2lock.h:42
int resultRelation
Definition: parsenodes.h:130
Definition: nodes.h:538
int SessionReplicationRole
Definition: trigger.c:68
CmdType event
Definition: prs2lock.h:27
RewriteRule ** rules
Definition: prs2lock.h:43
#define RULE_DISABLED
Definition: rewriteDefine.h:24
List * lappend(List *list, void *datum)
Definition: list.c:336
#define RULE_FIRES_ON_ORIGIN
Definition: rewriteDefine.h:21
#define SESSION_REPLICATION_ROLE_REPLICA
Definition: trigger.h:140
#define RULE_FIRES_ON_REPLICA
Definition: rewriteDefine.h:23
CmdType commandType
Definition: parsenodes.h:120
int i
bool rangeTableEntry_used(Node *node, int rt_index, int sublevels_up)
Definition: rewriteManip.c:892
Definition: pg_list.h:50
char enabled
Definition: prs2lock.h:30

◆ process_matched_tle()

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

Definition at line 1014 of file rewriteHandler.c.

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

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

◆ QueryRewrite()

List* QueryRewrite ( Query parsetree)

Definition at line 4080 of file rewriteHandler.c.

References Assert, Query::canSetTag, Query::commandType, fireRIRrules(), lappend(), lfirst, NIL, QSRC_INSTEAD_RULE, QSRC_ORIGINAL, QSRC_QUAL_INSTEAD_RULE, Query::queryId, Query::querySource, and RewriteQuery().

Referenced by ExecCreateTableAs(), ExplainOneUtility(), ExplainQuery(), PerformCursorOpen(), pg_rewrite_query(), PrepareQuery(), and refresh_matview_datafill().

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

◆ relation_is_updatable()

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

Definition at line 2777 of file rewriteHandler.c.

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

Referenced by pg_column_is_updatable(), pg_relation_is_updatable(), and relation_is_updatable().

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

◆ RewriteQuery()

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

Definition at line 3583 of file rewriteHandler.c.

References OnConflictExpr::action, Assert, Query::canSetTag, castNode, CMD_DELETE, CMD_INSERT, 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, linitial_node, list_concat(), list_delete_last(), list_length(), matchLocks(), NIL, NoLock, Query::onConflict, ONCONFLICT_UPDATE, OnConflictExpr::onConflictSet, Query::override, 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(), 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().

3584 {
3585  CmdType event = parsetree->commandType;
3586  bool instead = false;
3587  bool returning = false;
3588  bool updatableview = false;
3589  Query *qual_product = NULL;
3590  List *rewritten = NIL;
3591  ListCell *lc1;
3592 
3593  /*
3594  * First, recursively process any insert/update/delete statements in WITH
3595  * clauses. (We have to do this first because the WITH clauses may get
3596  * copied into rule actions below.)
3597  */
3598  foreach(lc1, parsetree->cteList)
3599  {
3601  Query *ctequery = castNode(Query, cte->ctequery);
3602  List *newstuff;
3603 
3604  if (ctequery->commandType == CMD_SELECT)
3605  continue;
3606 
3607  newstuff = RewriteQuery(ctequery, rewrite_events);
3608 
3609  /*
3610  * Currently we can only handle unconditional, single-statement DO
3611  * INSTEAD rules correctly; we have to get exactly one non-utility
3612  * Query out of the rewrite operation to stuff back into the CTE node.
3613  */
3614  if (list_length(newstuff) == 1)
3615  {
3616  /* Must check it's not a utility command */
3617  ctequery = linitial_node(Query, newstuff);
3618  if (!(ctequery->commandType == CMD_SELECT ||
3619  ctequery->commandType == CMD_UPDATE ||
3620  ctequery->commandType == CMD_INSERT ||
3621  ctequery->commandType == CMD_DELETE))
3622  {
3623  /*
3624  * Currently it could only be NOTIFY; this error message will
3625  * need work if we ever allow other utility commands in rules.
3626  */
3627  ereport(ERROR,
3628  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3629  errmsg("DO INSTEAD NOTIFY rules are not supported for data-modifying statements in WITH")));
3630  }
3631  /* WITH queries should never be canSetTag */
3632  Assert(!ctequery->canSetTag);
3633  /* Push the single Query back into the CTE node */
3634  cte->ctequery = (Node *) ctequery;
3635  }
3636  else if (newstuff == NIL)
3637  {
3638  ereport(ERROR,
3639  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3640  errmsg("DO INSTEAD NOTHING rules are not supported for data-modifying statements in WITH")));
3641  }
3642  else
3643  {
3644  ListCell *lc2;
3645 
3646  /* examine queries to determine which error message to issue */
3647  foreach(lc2, newstuff)
3648  {
3649  Query *q = (Query *) lfirst(lc2);
3650 
3652  ereport(ERROR,
3653  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3654  errmsg("conditional DO INSTEAD rules are not supported for data-modifying statements in WITH")));
3656  ereport(ERROR,
3657  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3658  errmsg("DO ALSO rules are not supported for data-modifying statements in WITH")));
3659  }
3660 
3661  ereport(ERROR,
3662  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3663  errmsg("multi-statement DO INSTEAD rules are not supported for data-modifying statements in WITH")));
3664  }
3665  }
3666 
3667  /*
3668  * If the statement is an insert, update, or delete, adjust its targetlist
3669  * as needed, and then fire INSERT/UPDATE/DELETE rules on it.
3670  *
3671  * SELECT rules are handled later when we have all the queries that should
3672  * get executed. Also, utilities aren't rewritten at all (do we still
3673  * need that check?)
3674  */
3675  if (event != CMD_SELECT && event != CMD_UTILITY)
3676  {
3677  int result_relation;
3678  RangeTblEntry *rt_entry;
3679  Relation rt_entry_relation;
3680  List *locks;
3681  List *product_queries;
3682  bool hasUpdate = false;
3683  int values_rte_index = 0;
3684  bool defaults_remaining = false;
3685 
3686  result_relation = parsetree->resultRelation;
3687  Assert(result_relation != 0);
3688  rt_entry = rt_fetch(result_relation, parsetree->rtable);
3689  Assert(rt_entry->rtekind == RTE_RELATION);
3690 
3691  /*
3692  * We can use NoLock here since either the parser or
3693  * AcquireRewriteLocks should have locked the rel already.
3694  */
3695  rt_entry_relation = table_open(rt_entry->relid, NoLock);
3696 
3697  /*
3698  * Rewrite the targetlist as needed for the command type.
3699  */
3700  if (event == CMD_INSERT)
3701  {
3702  RangeTblEntry *values_rte = NULL;
3703 
3704  /*
3705  * If it's an INSERT ... VALUES (...), (...), ... there will be a
3706  * single RTE for the VALUES targetlists.
3707  */
3708  if (list_length(parsetree->jointree->fromlist) == 1)
3709  {
3710  RangeTblRef *rtr = (RangeTblRef *) linitial(parsetree->jointree->fromlist);
3711 
3712  if (IsA(rtr, RangeTblRef))
3713  {
3714  RangeTblEntry *rte = rt_fetch(rtr->rtindex,
3715  parsetree->rtable);
3716 
3717  if (rte->rtekind == RTE_VALUES)
3718  {
3719  values_rte = rte;
3720  values_rte_index = rtr->rtindex;
3721  }
3722  }
3723  }
3724 
3725  if (values_rte)
3726  {
3727  Bitmapset *unused_values_attrnos = NULL;
3728 
3729  /* Process the main targetlist ... */
3730  parsetree->targetList = rewriteTargetListIU(parsetree->targetList,
3731  parsetree->commandType,
3732  parsetree->override,
3733  rt_entry_relation,
3734  values_rte,
3735  values_rte_index,
3736  &unused_values_attrnos);
3737  /* ... and the VALUES expression lists */
3738  if (!rewriteValuesRTE(parsetree, values_rte, values_rte_index,
3739  rt_entry_relation, false,
3740  unused_values_attrnos))
3741  defaults_remaining = true;
3742  }
3743  else
3744  {
3745  /* Process just the main targetlist */
3746  parsetree->targetList =
3747  rewriteTargetListIU(parsetree->targetList,
3748  parsetree->commandType,
3749  parsetree->override,
3750  rt_entry_relation,
3751  NULL, 0, NULL);
3752  }
3753 
3754  if (parsetree->onConflict &&
3755  parsetree->onConflict->action == ONCONFLICT_UPDATE)
3756  {
3757  parsetree->onConflict->onConflictSet =
3759  CMD_UPDATE,
3760  parsetree->override,
3761  rt_entry_relation,
3762  NULL, 0, NULL);
3763  }
3764  }
3765  else if (event == CMD_UPDATE)
3766  {
3767  parsetree->targetList =
3768  rewriteTargetListIU(parsetree->targetList,
3769  parsetree->commandType,
3770  parsetree->override,
3771  rt_entry_relation,
3772  NULL, 0, NULL);
3773 
3774  /* Also populate extraUpdatedCols (for generated columns) */
3775  fill_extraUpdatedCols(rt_entry, rt_entry_relation);
3776  }
3777  else if (event == CMD_DELETE)
3778  {
3779  /* Nothing to do here */
3780  }
3781  else
3782  elog(ERROR, "unrecognized commandType: %d", (int) event);
3783 
3784  /*
3785  * Collect and apply the appropriate rules.
3786  */
3787  locks = matchLocks(event, rt_entry_relation->rd_rules,
3788  result_relation, parsetree, &hasUpdate);
3789 
3790  product_queries = fireRules(parsetree,
3791  result_relation,
3792  event,
3793  locks,
3794  &instead,
3795  &returning,
3796  &qual_product);
3797 
3798  /*
3799  * If we have a VALUES RTE with any remaining untouched DEFAULT items,
3800  * and we got any product queries, finalize the VALUES RTE for each
3801  * product query (replacing the remaining DEFAULT items with NULLs).
3802  * We don't do this for the original query, because we know that it
3803  * must be an auto-insert on a view, and so should use the base
3804  * relation's defaults for any remaining DEFAULT items.
3805  */
3806  if (defaults_remaining && product_queries != NIL)
3807  {
3808  ListCell *n;
3809 
3810  /*
3811  * Each product query has its own copy of the VALUES RTE at the
3812  * same index in the rangetable, so we must finalize each one.
3813  */
3814  foreach(n, product_queries)
3815  {
3816  Query *pt = (Query *) lfirst(n);
3817  RangeTblEntry *values_rte = rt_fetch(values_rte_index,
3818  pt->rtable);
3819 
3820  rewriteValuesRTE(pt, values_rte, values_rte_index,
3821  rt_entry_relation,
3822  true, /* Force remaining defaults to NULL */
3823  NULL);
3824  }
3825  }
3826 
3827  /*
3828  * If there was no unqualified INSTEAD rule, and the target relation
3829  * is a view without any INSTEAD OF triggers, see if the view can be
3830  * automatically updated. If so, we perform the necessary query
3831  * transformation here and add the resulting query to the
3832  * product_queries list, so that it gets recursively rewritten if
3833  * necessary.
3834  *
3835  * If the view cannot be automatically updated, we throw an error here
3836  * which is OK since the query would fail at runtime anyway. Throwing
3837  * the error here is preferable to the executor check since we have
3838  * more detailed information available about why the view isn't
3839  * updatable.
3840  */
3841  if (!instead &&
3842  rt_entry_relation->rd_rel->relkind == RELKIND_VIEW &&
3843  !view_has_instead_trigger(rt_entry_relation, event))
3844  {
3845  /*
3846  * If there were any qualified INSTEAD rules, don't allow the view
3847  * to be automatically updated (an unqualified INSTEAD rule or
3848  * INSTEAD OF trigger is required).
3849  *
3850  * The messages here should match execMain.c's CheckValidResultRel
3851  * and in principle make those checks in executor unnecessary, but
3852  * we keep them just in case.
3853  */
3854  if (qual_product != NULL)
3855  {
3856  switch (parsetree->commandType)
3857  {
3858  case CMD_INSERT:
3859  ereport(ERROR,
3860  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3861  errmsg("cannot insert into view \"%s\"",
3862  RelationGetRelationName(rt_entry_relation)),
3863  errdetail("Views with conditional DO INSTEAD rules are not automatically updatable."),
3864  errhint("To enable inserting into the view, provide an INSTEAD OF INSERT trigger or an unconditional ON INSERT DO INSTEAD rule.")));
3865  break;
3866  case CMD_UPDATE:
3867  ereport(ERROR,
3868  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3869  errmsg("cannot update view \"%s\"",
3870  RelationGetRelationName(rt_entry_relation)),
3871  errdetail("Views with conditional DO INSTEAD rules are not automatically updatable."),
3872  errhint("To enable updating the view, provide an INSTEAD OF UPDATE trigger or an unconditional ON UPDATE DO INSTEAD rule.")));
3873  break;
3874  case CMD_DELETE:
3875  ereport(ERROR,
3876  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3877  errmsg("cannot delete from view \"%s\"",
3878  RelationGetRelationName(rt_entry_relation)),
3879  errdetail("Views with conditional DO INSTEAD rules are not automatically updatable."),
3880  errhint("To enable deleting from the view, provide an INSTEAD OF DELETE trigger or an unconditional ON DELETE DO INSTEAD rule.")));
3881  break;
3882  default:
3883  elog(ERROR, "unrecognized CmdType: %d",
3884  (int) parsetree->commandType);
3885  break;
3886  }
3887  }
3888 
3889  /*
3890  * Attempt to rewrite the query to automatically update the view.
3891  * This throws an error if the view can't be automatically
3892  * updated.
3893  */
3894  parsetree = rewriteTargetView(parsetree, rt_entry_relation);
3895 
3896  /*
3897  * At this point product_queries contains any DO ALSO rule
3898  * actions. Add the rewritten query before or after those. This
3899  * must match the handling the original query would have gotten
3900  * below, if we allowed it to be included again.
3901  */
3902  if (parsetree->commandType == CMD_INSERT)
3903  product_queries = lcons(parsetree, product_queries);
3904  else
3905  product_queries = lappend(product_queries, parsetree);
3906 
3907  /*
3908  * Set the "instead" flag, as if there had been an unqualified
3909  * INSTEAD, to prevent the original query from being included a
3910  * second time below. The transformation will have rewritten any
3911  * RETURNING list, so we can also set "returning" to forestall
3912  * throwing an error below.
3913  */
3914  instead = true;
3915  returning = true;
3916  updatableview = true;
3917  }
3918 
3919  /*
3920  * If we got any product queries, recursively rewrite them --- but
3921  * first check for recursion!
3922  */
3923  if (product_queries != NIL)
3924  {
3925  ListCell *n;
3926  rewrite_event *rev;
3927 
3928  foreach(n, rewrite_events)
3929  {
3930  rev = (rewrite_event *) lfirst(n);
3931  if (rev->relation == RelationGetRelid(rt_entry_relation) &&
3932  rev->event == event)
3933  ereport(ERROR,
3934  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
3935  errmsg("infinite recursion detected in rules for relation \"%s\"",
3936  RelationGetRelationName(rt_entry_relation))));
3937  }
3938 
3939  rev = (rewrite_event *) palloc(sizeof(rewrite_event));
3940  rev->relation = RelationGetRelid(rt_entry_relation);
3941  rev->event = event;
3942  rewrite_events = lappend(rewrite_events, rev);
3943 
3944  foreach(n, product_queries)
3945  {
3946  Query *pt = (Query *) lfirst(n);
3947  List *newstuff;
3948 
3949  newstuff = RewriteQuery(pt, rewrite_events);
3950  rewritten = list_concat(rewritten, newstuff);
3951  }
3952 
3953  rewrite_events = list_delete_last(rewrite_events);
3954  }
3955 
3956  /*
3957  * If there is an INSTEAD, and the original query has a RETURNING, we
3958  * have to have found a RETURNING in the rule(s), else fail. (Because
3959  * DefineQueryRewrite only allows RETURNING in unconditional INSTEAD
3960  * rules, there's no need to worry whether the substituted RETURNING
3961  * will actually be executed --- it must be.)
3962  */
3963  if ((instead || qual_product != NULL) &&
3964  parsetree->returningList &&
3965  !returning)
3966  {
3967  switch (event)
3968  {
3969  case CMD_INSERT:
3970  ereport(ERROR,
3971  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3972  errmsg("cannot perform INSERT RETURNING on relation \"%s\"",
3973  RelationGetRelationName(rt_entry_relation)),
3974  errhint("You need an unconditional ON INSERT DO INSTEAD rule with a RETURNING clause.")));
3975  break;
3976  case CMD_UPDATE:
3977  ereport(ERROR,
3978  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3979  errmsg("cannot perform UPDATE RETURNING on relation \"%s\"",
3980  RelationGetRelationName(rt_entry_relation)),
3981  errhint("You need an unconditional ON UPDATE DO INSTEAD rule with a RETURNING clause.")));
3982  break;
3983  case CMD_DELETE:
3984  ereport(ERROR,
3985  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3986  errmsg("cannot perform DELETE RETURNING on relation \"%s\"",
3987  RelationGetRelationName(rt_entry_relation)),
3988  errhint("You need an unconditional ON DELETE DO INSTEAD rule with a RETURNING clause.")));
3989  break;
3990  default:
3991  elog(ERROR, "unrecognized commandType: %d",
3992  (int) event);
3993  break;
3994  }
3995  }
3996 
3997  /*
3998  * Updatable views are supported by ON CONFLICT, so don't prevent that
3999  * case from proceeding
4000  */
4001  if (parsetree->onConflict &&
4002  (product_queries != NIL || hasUpdate) &&
4003  !updatableview)
4004  ereport(ERROR,
4005  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4006  errmsg("INSERT with ON CONFLICT clause cannot be used with table that has INSERT or UPDATE rules")));
4007 
4008  table_close(rt_entry_relation, NoLock);
4009  }
4010 
4011  /*
4012  * For INSERTs, the original query is done first; for UPDATE/DELETE, it is
4013  * done last. This is needed because update and delete rule actions might
4014  * not do anything if they are invoked after the update or delete is
4015  * performed. The command counter increment between the query executions
4016  * makes the deleted (and maybe the updated) tuples disappear so the scans
4017  * for them in the rule actions cannot find them.
4018  *
4019  * If we found any unqualified INSTEAD, the original query is not done at
4020  * all, in any form. Otherwise, we add the modified form if qualified
4021  * INSTEADs were found, else the unmodified form.
4022  */
4023  if (!instead)
4024  {
4025  if (parsetree->commandType == CMD_INSERT)
4026  {
4027  if (qual_product != NULL)
4028  rewritten = lcons(qual_product, rewritten);
4029  else
4030  rewritten = lcons(parsetree, rewritten);
4031  }
4032  else
4033  {
4034  if (qual_product != NULL)
4035  rewritten = lappend(rewritten, qual_product);
4036  else
4037  rewritten = lappend(rewritten, parsetree);
4038  }
4039  }
4040 
4041  /*
4042  * If the original query has a CTE list, and we generated more than one
4043  * non-utility result query, we have to fail because we'll have copied the
4044  * CTE list into each result query. That would break the expectation of
4045  * single evaluation of CTEs. This could possibly be fixed by
4046  * restructuring so that a CTE list can be shared across multiple Query
4047  * and PlannableStatement nodes.
4048  */
4049  if (parsetree->cteList != NIL)
4050  {
4051  int qcount = 0;
4052 
4053  foreach(lc1, rewritten)
4054  {
4055  Query *q = (Query *) lfirst(lc1);
4056 
4057  if (q->commandType != CMD_UTILITY)
4058  qcount++;
4059  }
4060  if (qcount > 1)
4061  ereport(ERROR,
4062  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4063  errmsg("WITH cannot be used in a query that is rewritten by rules into multiple queries")));
4064  }
4065 
4066  return rewritten;
4067 }
#define NIL
Definition: pg_list.h:65
#define IsA(nodeptr, _type_)
Definition: nodes.h:589
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
int errhint(const char *fmt,...)
Definition: elog.c:1156
static bool view_has_instead_trigger(Relation view, CmdType event)
FromExpr * jointree
Definition: parsenodes.h:148
OnConflictExpr * onConflict
Definition: parsenodes.h:154
#define castNode(_type_, nodeptr)
Definition: nodes.h:607
int resultRelation
Definition: parsenodes.h:130
Definition: nodes.h:538
static List * RewriteQuery(Query *parsetree, List *rewrite_events)
List * list_concat(List *list1, const List *list2)
Definition: list.c:530
int errcode(int sqlerrcode)
Definition: elog.c:698
List * fromlist
Definition: primnodes.h:1564
Form_pg_class rd_rel
Definition: rel.h:109
#define linitial_node(type, l)
Definition: pg_list.h:177
List * targetList
Definition: parsenodes.h:150
#define linitial(l)
Definition: pg_list.h:174
List * rtable
Definition: parsenodes.h:147
#define ERROR
Definition: elog.h:46
void fill_extraUpdatedCols(RangeTblEntry *target_rte, Relation target_relation)
static bool rewriteValuesRTE(Query *parsetree, RangeTblEntry *rte, int rti, Relation target_relation, bool force_nulls, Bitmapset *unused_cols)
#define lfirst_node(type, lc)
Definition: pg_list.h:172
#define NoLock
Definition: lockdefs.h:34
int errdetail(const char *fmt,...)
Definition: elog.c:1042
static Query * rewriteTargetView(Query *parsetree, Relation view)
List * list_delete_last(List *list)
Definition: list.c:892
#define RelationGetRelationName(relation)
Definition: rel.h:511
List * returningList
Definition: parsenodes.h:156
static List * rewriteTargetListIU(List *targetList, CmdType commandType, OverridingKind override, Relation target_relation, RangeTblEntry *values_rte, int values_rte_index, Bitmapset **unused_values_attrnos)
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
List * lappend(List *list, void *datum)
Definition: list.c:336
OnConflictAction action
Definition: primnodes.h:1580
static List * fireRules(Query *parsetree, int rt_index, CmdType event, List *locks, bool *instead_flag, bool *returning_flag, Query **qual_product)
OverridingKind override
Definition: parsenodes.h:152
#define ereport(elevel,...)
Definition: elog.h:157
CmdType commandType
Definition: parsenodes.h:120
List * lcons(void *datum, List *list)
Definition: list.c:468
QuerySource querySource
Definition: parsenodes.h:122
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
RuleLock * rd_rules
Definition: rel.h:113
bool canSetTag
Definition: parsenodes.h:126
static int list_length(const List *l)
Definition: pg_list.h:149
RTEKind rtekind
Definition: parsenodes.h:1007
List * cteList
Definition: parsenodes.h:145
void * palloc(Size size)
Definition: mcxt.c:1062
int errmsg(const char *fmt,...)
Definition: elog.c:909
#define elog(elevel,...)
Definition: elog.h:232
List * onConflictSet
Definition: primnodes.h:1589
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: pg_list.h:50
static List * matchLocks(CmdType event, RuleLock *rulelocks, int varno, Query *parsetree, bool *hasUpdate)
#define RelationGetRelid(relation)
Definition: rel.h:477
CmdType
Definition: nodes.h:682

◆ rewriteRuleAction()

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

Definition at line 342 of file rewriteHandler.c.

References acquireLocksOnSubLinks(), AcquireRewriteLocks(), AddQual(), adjustJoinTreeList(), Assert, ChangeVarNodes(), checkExprHasSubLink(), CMD_INSERT, CMD_UPDATE, CMD_UTILITY, copyObject, Query::cteList, CommonTableExpr::ctename, ereport, errcode(), errmsg(), ERROR, acquireLocksOnSubLinks_context::for_execute, 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, RangeTblEntry::tablefunc, RangeTblEntry::tablesample, Query::targetList, and RangeTblEntry::values_lists.

Referenced by fireRules().

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

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

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

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

◆ rewriteTargetView()

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

Definition at line 3028 of file rewriteHandler.c.

References _, acquireLocksOnSubLinks(), 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, TargetEntry::expr, FirstLowInvalidHeapAttributeNumber, acquireLocksOnSubLinks_context::for_execute, FromExpr::fromlist, get_tle_by_resno(), get_view_query(), Query::hasSubLinks, RangeTblEntry::inh, RangeTblEntry::insertedCols, 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, 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(), and WCO_VIEW_CHECK.

Referenced by RewriteQuery().

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

◆ rewriteValuesRTE()

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

Definition at line 1406 of file rewriteHandler.c.

References Assert, bms_is_member(), build_column_default(), CMD_INSERT, COERCE_IMPLICIT_CAST, coerce_to_domain(), COERCION_IMPLICIT, SetToDefault::collation, elog, ERROR, TargetEntry::expr, i, 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, searchForDefault(), Query::targetList, TupleDescAttr, SetToDefault::typeId, SetToDefault::typeMod, RangeTblEntry::values_lists, Var::varattno, Var::varno, and view_has_instead_trigger().

Referenced by RewriteQuery().

1409 {
1410  List *newValues;
1411  ListCell *lc;
1412  bool isAutoUpdatableView;
1413  bool allReplaced;
1414  int numattrs;
1415  int *attrnos;
1416 
1417  /*
1418  * Rebuilding all the lists is a pretty expensive proposition in a big
1419  * VALUES list, and it's a waste of time if there aren't any DEFAULT
1420  * placeholders. So first scan to see if there are any.
1421  *
1422  * We skip this check if force_nulls is true, because we know that there
1423  * are DEFAULT items present in that case.
1424  */
1425  if (!force_nulls && !searchForDefault(rte))
1426  return true; /* nothing to do */
1427 
1428  /*
1429  * Scan the targetlist for entries referring to the VALUES RTE, and note
1430  * the target attributes. As noted above, we should only need to do this
1431  * for targetlist entries containing simple Vars --- nothing else in the
1432  * VALUES RTE should contain DEFAULT items (except possibly for unused
1433  * columns), and we complain if such a thing does occur.
1434  */
1435  numattrs = list_length(linitial(rte->values_lists));
1436  attrnos = (int *) palloc0(numattrs * sizeof(int));
1437 
1438  foreach(lc, parsetree->targetList)
1439  {
1440  TargetEntry *tle = (TargetEntry *) lfirst(lc);
1441 
1442  if (IsA(tle->expr, Var))
1443  {
1444  Var *var = (Var *) tle->expr;
1445 
1446  if (var->varno == rti)
1447  {
1448  int attrno = var->varattno;
1449 
1450  Assert(attrno >= 1 && attrno <= numattrs);
1451  attrnos[attrno - 1] = tle->resno;
1452  }
1453  }
1454  }
1455 
1456  /*
1457  * Check if the target relation is an auto-updatable view, in which case
1458  * unresolved defaults will be left untouched rather than being set to
1459  * NULL. If force_nulls is true, we always set DEFAULT items to NULL, so
1460  * skip this check in that case --- it isn't an auto-updatable view.
1461  */
1462  isAutoUpdatableView = false;
1463  if (!force_nulls &&
1464  target_relation->rd_rel->relkind == RELKIND_VIEW &&
1465  !view_has_instead_trigger(target_relation, CMD_INSERT))
1466  {
1467  List *locks;
1468  bool hasUpdate;
1469  bool found;
1470  ListCell *l;
1471 
1472  /* Look for an unconditional DO INSTEAD rule */
1473  locks = matchLocks(CMD_INSERT, target_relation->rd_rules,
1474  parsetree->resultRelation, parsetree, &hasUpdate);
1475 
1476  found = false;
1477  foreach(l, locks)
1478  {
1479  RewriteRule *rule_lock = (RewriteRule *) lfirst(l);
1480 
1481  if (rule_lock->isInstead &&
1482  rule_lock->qual == NULL)
1483  {
1484  found = true;
1485  break;
1486  }
1487  }
1488 
1489  /*
1490  * If we didn't find an unconditional DO INSTEAD rule, assume that the
1491  * view is auto-updatable. If it isn't, rewriteTargetView() will
1492  * throw an error.
1493  */
1494  if (!found)
1495  isAutoUpdatableView = true;
1496  }
1497 
1498  newValues = NIL;
1499  allReplaced = true;
1500  foreach(lc, rte->values_lists)
1501  {
1502  List *sublist = (List *) lfirst(lc);
1503  List *newList = NIL;
1504  ListCell *lc2;
1505  int i;
1506 
1507  Assert(list_length(sublist) == numattrs);
1508 
1509  i = 0;
1510  foreach(lc2, sublist)
1511  {
1512  Node *col = (Node *) lfirst(lc2);
1513  int attrno = attrnos[i++];
1514 
1515  if (IsA(col, SetToDefault))
1516  {
1517  Form_pg_attribute att_tup;
1518  Node *new_expr;
1519 
1520  /*
1521  * If this column isn't used, just replace the DEFAULT with
1522  * NULL (attrno will be 0 in this case because the targetlist
1523  * entry will have been replaced by the default expression).
1524  */
1525  if (bms_is_member(i, unused_cols))
1526  {
1527  SetToDefault *def = (SetToDefault *) col;
1528 
1529  newList = lappend(newList,
1530  makeNullConst(def->typeId,
1531  def->typeMod,
1532  def->collation));
1533  continue;
1534  }
1535 
1536  if (attrno == 0)
1537  elog(ERROR, "cannot set value in column %d to DEFAULT", i);
1538  att_tup = TupleDescAttr(target_relation->rd_att, attrno - 1);
1539 
1540  if (!force_nulls && !att_tup->attisdropped)
1541  new_expr = build_column_default(target_relation, attrno);
1542  else
1543  new_expr = NULL; /* force a NULL if dropped */
1544 
1545  /*
1546  * If there is no default (ie, default is effectively NULL),
1547  * we've got to explicitly set the column to NULL, unless the
1548  * target relation is an auto-updatable view.
1549  */
1550  if (!new_expr)
1551  {
1552  if (isAutoUpdatableView)
1553  {
1554  /* Leave the value untouched */
1555  newList = lappend(newList, col);
1556  allReplaced = false;
1557  continue;
1558  }
1559 
1560  new_expr = (Node *) makeConst(att_tup->atttypid,
1561  -1,
1562  att_tup->attcollation,
1563  att_tup->attlen,
1564  (Datum) 0,
1565  true, /* isnull */
1566  att_tup->attbyval);
1567  /* this is to catch a NOT NULL domain constraint */
1568  new_expr = coerce_to_domain(new_expr,
1569  InvalidOid, -1,
1570  att_tup->atttypid,
1573  -1,
1574  false);
1575  }
1576  newList = lappend(newList, new_expr);
1577  }
1578  else
1579  newList = lappend(newList, col);
1580  }
1581  newValues = lappend(newValues, newList);
1582  }
1583  rte->values_lists = newValues;
1584 
1585  pfree(attrnos);
1586 
1587  return allReplaced;
1588 }
int varno
Definition: primnodes.h:189
#define NIL
Definition: pg_list.h:65
Node * qual
Definition: prs2lock.h:28
#define IsA(nodeptr, _type_)
Definition: nodes.h:589
static bool view_has_instead_trigger(Relation view, CmdType event)
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
int resultRelation
Definition: parsenodes.h:130
Definition: nodes.h:538
AttrNumber varattno
Definition: primnodes.h:191
Form_pg_class rd_rel
Definition: rel.h:109
Definition: primnodes.h:186
Const * makeConst(Oid consttype, int32 consttypmod, Oid constcollid, int constlen, Datum constvalue, bool constisnull, bool constbyval)
Definition: makefuncs.c:299
bool isInstead
Definition: prs2lock.h:31
List * values_lists
Definition: parsenodes.h:1112
List * targetList
Definition: parsenodes.h:150
Const * makeNullConst(Oid consttype, int32 consttypmod, Oid constcollid)
Definition: makefuncs.c:337
void pfree(void *pointer)
Definition: mcxt.c:1169
#define linitial(l)
Definition: pg_list.h:174
#define ERROR
Definition: elog.h:46
static bool searchForDefault(RangeTblEntry *rte)
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
int32 typeMod
Definition: primnodes.h:1342
AttrNumber resno
Definition: primnodes.h:1456
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:207
List * lappend(List *list, void *datum)
Definition: list.c:336
Node * build_column_default(Relation rel, int attrno)
void * palloc0(Size size)
Definition: mcxt.c:1093
uintptr_t Datum
Definition: postgres.h:411
TupleDesc rd_att
Definition: rel.h:110
#define InvalidOid
Definition: postgres_ext.h:36
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
Expr * expr
Definition: primnodes.h:1455
RuleLock * rd_rules
Definition: rel.h:113
static int list_length(const List *l)
Definition: pg_list.h:149
#define elog(elevel,...)
Definition: elog.h:232
int i
Definition: pg_list.h:50
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:427
static List * matchLocks(CmdType event, RuleLock *rulelocks, int varno, Query *parsetree, bool *hasUpdate)

◆ searchForDefault()

static bool searchForDefault ( RangeTblEntry rte)
static

Definition at line 1281 of file rewriteHandler.c.

References IsA, lfirst, and RangeTblEntry::values_lists.

Referenced by rewriteValuesRTE().

1282 {
1283  ListCell *lc;
1284 
1285  foreach(lc, rte->values_lists)
1286  {
1287  List *sublist = (List *) lfirst(lc);
1288  ListCell *lc2;
1289 
1290  foreach(lc2, sublist)
1291  {
1292  Node *col = (Node *) lfirst(lc2);
1293 
1294  if (IsA(col, SetToDefault))
1295  return true;
1296  }
1297  }
1298  return false;
1299 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:589
Definition: nodes.h:538
List * values_lists
Definition: parsenodes.h:1112
#define lfirst(lc)
Definition: pg_list.h:169
Definition: pg_list.h:50

◆ view_col_is_auto_updatable()

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

Definition at line 2498 of file rewriteHandler.c.

References TargetEntry::expr, gettext_noop, 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().

2499 {
2500  Var *var = (Var *) tle->expr;
2501 
2502  /*
2503  * For now, the only updatable columns we support are those that are Vars
2504  * referring to user columns of the underlying base relation.
2505  *
2506  * The view targetlist may contain resjunk columns (e.g., a view defined
2507  * like "SELECT * FROM t ORDER BY a+b" is auto-updatable) but such columns
2508  * are not auto-updatable, and in fact should never appear in the outer
2509  * query's targetlist.
2510  */
2511  if (tle->resjunk)
2512  return gettext_noop("Junk view columns are not updatable.");
2513 
2514  if (!IsA(var, Var) ||
2515  var->varno != rtr->rtindex ||
2516  var->varlevelsup != 0)
2517  return gettext_noop("View columns that are not columns of their base relation are not updatable.");
2518 
2519  if (var->varattno < 0)
2520  return gettext_noop("View columns that refer to system columns are not updatable.");
2521 
2522  if (var->varattno == 0)
2523  return gettext_noop("View columns that return whole-row references are not updatable.");
2524 
2525  return NULL; /* the view column is updatable */
2526 }
int varno
Definition: primnodes.h:189
#define IsA(nodeptr, _type_)
Definition: nodes.h:589
Index varlevelsup
Definition: primnodes.h:196
#define gettext_noop(x)
Definition: c.h:1197
AttrNumber varattno
Definition: primnodes.h:191
Definition: primnodes.h:186
bool resjunk
Definition: primnodes.h:1462
Expr * expr
Definition: primnodes.h:1455

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

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

2698 {
2699  RangeTblRef *rtr;
2700  AttrNumber col;
2701  ListCell *cell;
2702 
2703  /*
2704  * The caller should have verified that this view is auto-updatable and so
2705  * there should be a single base relation.
2706  */
2707  Assert(list_length(viewquery->jointree->fromlist) == 1);
2708  rtr = linitial_node(RangeTblRef, viewquery->jointree->fromlist);
2709 
2710  /* Initialize the optional return values */
2711  if (updatable_cols != NULL)
2712  *updatable_cols = NULL;
2713  if (non_updatable_col != NULL)
2714  *non_updatable_col = NULL;
2715 
2716  /* Test each view column for updatability */
2718  foreach(cell, viewquery->targetList)
2719  {
2720  TargetEntry *tle = (TargetEntry *) lfirst(cell);
2721  const char *col_update_detail;
2722 
2723  col++;
2724  col_update_detail = view_col_is_auto_updatable(rtr, tle);
2725 
2726  if (col_update_detail == NULL)
2727  {
2728  /* The column is updatable */
2729  if (updatable_cols != NULL)
2730  *updatable_cols = bms_add_member(*updatable_cols, col);
2731  }
2732  else if (bms_is_member(col, required_cols))
2733  {
2734  /* The required column is not updatable */
2735  if (non_updatable_col != NULL)
2736  *non_updatable_col = tle->resname;
2737  return col_update_detail;
2738  }
2739  }
2740 
2741  return NULL; /* all the required view columns are updatable */
2742 }
FromExpr * jointree
Definition: parsenodes.h:148
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
List * fromlist
Definition: primnodes.h:1564
char * resname
Definition: primnodes.h:1457
#define linitial_node(type, l)
Definition: pg_list.h:177
List * targetList
Definition: parsenodes.h:150
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
static int list_length(const List *l)
Definition: pg_list.h:149
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:736
static const char * view_col_is_auto_updatable(RangeTblRef *rtr, TargetEntry *tle)
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:427
int16 AttrNumber
Definition: attnum.h:21

◆ view_has_instead_trigger()

static bool view_has_instead_trigger ( Relation  view,
CmdType  event 
)
static

Definition at line 2460 of file rewriteHandler.c.

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

2461 {
2462  TriggerDesc *trigDesc = view->trigdesc;
2463 
2464  switch (event)
2465  {
2466  case CMD_INSERT:
2467  if (trigDesc && trigDesc->trig_insert_instead_row)
2468  return true;
2469  break;
2470  case CMD_UPDATE:
2471  if (trigDesc && trigDesc->trig_update_instead_row)
2472  return true;
2473  break;
2474  case CMD_DELETE:
2475  if (trigDesc && trigDesc->trig_delete_instead_row)
2476  return true;
2477  break;
2478  default:
2479  elog(ERROR, "unrecognized CmdType: %d", (int) event);
2480  break;
2481  }
2482  return false;
2483 }
bool trig_insert_instead_row
Definition: reltrigger.h:58
#define ERROR
Definition: elog.h:46
TriggerDesc * trigdesc
Definition: rel.h:115
bool trig_update_instead_row
Definition: reltrigger.h:63
bool trig_delete_instead_row
Definition: reltrigger.h:68
#define elog(elevel,...)
Definition: elog.h:232

◆ view_query_is_auto_updatable()

const char* view_query_is_auto_updatable ( Query viewquery,
bool  check_cols 
)

Definition at line 2546 of file rewriteHandler.c.

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

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

2547 {
2548  RangeTblRef *rtr;
2549  RangeTblEntry *base_rte;
2550 
2551  /*----------
2552  * Check if the view is simply updatable. According to SQL-92 this means:
2553  * - No DISTINCT clause.
2554  * - Each TLE is a column reference, and each column appears at most once.
2555  * - FROM contains exactly one base relation.
2556  * - No GROUP BY or HAVING clauses.
2557  * - No set operations (UNION, INTERSECT or EXCEPT).
2558  * - No sub-queries in the WHERE clause that reference the target table.
2559  *
2560  * We ignore that last restriction since it would be complex to enforce
2561  * and there isn't any actual benefit to disallowing sub-queries. (The
2562  * semantic issues that the standard is presumably concerned about don't
2563  * arise in Postgres, since any such sub-query will not see any updates
2564  * executed by the outer query anyway, thanks to MVCC snapshotting.)
2565  *
2566  * We also relax the second restriction by supporting part of SQL:1999
2567  * feature T111, which allows for a mix of updatable and non-updatable
2568  * columns, provided that an INSERT or UPDATE doesn't attempt to assign to
2569  * a non-updatable column.
2570  *
2571  * In addition we impose these constraints, involving features that are
2572  * not part of SQL-92:
2573  * - No CTEs (WITH clauses).
2574  * - No OFFSET or LIMIT clauses (this matches a SQL:2008 restriction).
2575  * - No system columns (including whole-row references) in the tlist.
2576  * - No window functions in the tlist.
2577  * - No set-returning functions in the tlist.
2578  *
2579  * Note that we do these checks without recursively expanding the view.
2580  * If the base relation is a view, we'll recursively deal with it later.
2581  *----------
2582  */
2583  if (viewquery->distinctClause != NIL)
2584  return gettext_noop("Views containing DISTINCT are not automatically updatable.");
2585 
2586  if (viewquery->groupClause != NIL || viewquery->groupingSets)
2587  return gettext_noop("Views containing GROUP BY are not automatically updatable.");
2588 
2589  if (viewquery->havingQual != NULL)
2590  return gettext_noop("Views containing HAVING are not automatically updatable.");
2591 
2592  if (viewquery->setOperations != NULL)
2593  return gettext_noop("Views containing UNION, INTERSECT, or EXCEPT are not automatically updatable.");
2594 
2595  if (viewquery->cteList != NIL)
2596  return