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:590
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(), get_query_def(), init_sql_fcache(), make_ruledef(), 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 }
#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:590
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
List * joinaliasvars
Definition: parsenodes.h:1070
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:539
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
Index varno
Definition: primnodes.h:189
#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:995
List * cteList
Definition: parsenodes.h:145
Query * subquery
Definition: parsenodes.h:1030
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 2935 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().

2936 {
2937  Bitmapset *result = NULL;
2938  int col;
2939 
2940  col = -1;
2941  while ((col = bms_next_member(cols, col)) >= 0)
2942  {
2943  /* bit numbers are offset by FirstLowInvalidHeapAttributeNumber */
2945 
2946  if (attno == InvalidAttrNumber)
2947  {
2948  /*
2949  * There's a whole-row reference to the view. For permissions
2950  * purposes, treat it as a reference to each column available from
2951  * the view. (We should *not* convert this to a whole-row
2952  * reference to the base relation, since the view may not touch
2953  * all columns of the base relation.)
2954  */
2955  ListCell *lc;
2956 
2957  foreach(lc, targetlist)
2958  {
2959  TargetEntry *tle = lfirst_node(TargetEntry, lc);
2960  Var *var;
2961 
2962  if (tle->resjunk)
2963  continue;
2964  var = castNode(Var, tle->expr);
2965  result = bms_add_member(result,
2966  var->varattno - FirstLowInvalidHeapAttributeNumber);
2967  }
2968  }
2969  else
2970  {
2971  /*
2972  * Views do not have system columns, so we do not expect to see
2973  * any other system attnos here. If we do find one, the error
2974  * case will apply.
2975  */
2976  TargetEntry *tle = get_tle_by_resno(targetlist, attno);
2977 
2978  if (tle != NULL && !tle->resjunk && IsA(tle->expr, Var))
2979  {
2980  Var *var = (Var *) tle->expr;
2981 
2982  result = bms_add_member(result,
2983  var->varattno - FirstLowInvalidHeapAttributeNumber);
2984  }
2985  else
2986  elog(ERROR, "attribute number %d not found in view targetlist",
2987  attno);
2988  }
2989  }
2990 
2991  return result;
2992 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
#define castNode(_type_, nodeptr)
Definition: nodes.h:608
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:1461
#define ERROR
Definition: elog.h:46
#define lfirst_node(type, lc)
Definition: pg_list.h:172
Expr * expr
Definition: primnodes.h:1454
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 645 of file rewriteHandler.c.

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

Referenced by rewriteRuleAction().

646 {
647  List *newjointree = copyObject(parsetree->jointree->fromlist);
648  ListCell *l;
649 
650  if (removert)
651  {
652  foreach(l, newjointree)
653  {
654  RangeTblRef *rtr = lfirst(l);
655 
656  if (IsA(rtr, RangeTblRef) &&
657  rtr->rtindex == rt_index)
658  {
659  newjointree = foreach_delete_current(newjointree, l);
660  break;
661  }
662  }
663  }
664  return newjointree;
665 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
FromExpr * jointree
Definition: parsenodes.h:148
List * fromlist
Definition: primnodes.h:1563
#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:655
Definition: pg_list.h:50

◆ ApplyRetrieveRule()

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

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

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

◆ build_column_default()

Node* build_column_default ( Relation  rel,
int  attrno 
)

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

1174 {
1175  TupleDesc rd_att = rel->rd_att;
1176  Form_pg_attribute att_tup = TupleDescAttr(rd_att, attrno - 1);
1177  Oid atttype = att_tup->atttypid;
1178  int32 atttypmod = att_tup->atttypmod;
1179  Node *expr = NULL;
1180  Oid exprtype;
1181 
1182  if (att_tup->attidentity)
1183  {
1185 
1186  nve->seqid = getIdentitySequence(RelationGetRelid(rel), attrno, false);
1187  nve->typeId = att_tup->atttypid;
1188 
1189  return (Node *) nve;
1190  }
1191 
1192  /*
1193  * If relation has a default for this column, fetch that expression.
1194  */
1195  if (att_tup->atthasdef)
1196  {
1197  if (rd_att->constr && rd_att->constr->num_defval > 0)
1198  {
1199  AttrDefault *defval = rd_att->constr->defval;
1200  int ndef = rd_att->constr->num_defval;
1201 
1202  while (--ndef >= 0)
1203  {
1204  if (attrno == defval[ndef].adnum)
1205  {
1206  /* Found it, convert string representation to node tree. */
1207  expr = stringToNode(defval[ndef].adbin);
1208  break;
1209  }
1210  }
1211  }
1212  if (expr == NULL)
1213  elog(ERROR, "default expression not found for attribute %d of relation \"%s\"",
1214  attrno, RelationGetRelationName(rel));
1215  }
1216 
1217  /*
1218  * No per-column default, so look for a default for the type itself. But
1219  * not for generated columns.
1220  */
1221  if (expr == NULL && !att_tup->attgenerated)
1222  expr = get_typdefault(atttype);
1223 
1224  if (expr == NULL)
1225  return NULL; /* No default anywhere */
1226 
1227  /*
1228  * Make sure the value is coerced to the target column type; this will
1229  * generally be true already, but there seem to be some corner cases
1230  * involving domain defaults where it might not be true. This should match
1231  * the parser's processing of non-defaulted expressions --- see
1232  * transformAssignedExpr().
1233  */
1234  exprtype = exprType(expr);
1235 
1236  expr = coerce_to_target_type(NULL, /* no UNKNOWN params here */
1237  expr, exprtype,
1238  atttype, atttypmod,
1241  -1);
1242  if (expr == NULL)
1243  ereport(ERROR,
1244  (errcode(ERRCODE_DATATYPE_MISMATCH),
1245  errmsg("column \"%s\" is of type %s"
1246  " but default expression is of type %s",
1247  NameStr(att_tup->attname),
1248  format_type_be(atttype),
1249  format_type_be(exprtype)),
1250  errhint("You will need to rewrite or cast the expression.")));
1251 
1252  return expr;
1253 }
int errhint(const char *fmt,...)
Definition: elog.c:1156
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
Definition: nodes.h:539
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:880
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:587
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 2243 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().

2247 {
2248  /* Don't scribble on the passed qual (it's in the relcache!) */
2249  Node *new_qual = copyObject(rule_qual);
2251 
2252  context.for_execute = true;
2253 
2254  /*
2255  * In case there are subqueries in the qual, acquire necessary locks and
2256  * fix any deleted JOIN RTE entries. (This is somewhat redundant with
2257  * rewriteRuleAction, but not entirely ... consider restructuring so that
2258  * we only need to process the qual this way once.)
2259  */
2260  (void) acquireLocksOnSubLinks(new_qual, &context);
2261 
2262  /* Fix references to OLD */
2263  ChangeVarNodes(new_qual, PRS2_OLD_VARNO, rt_index, 0);
2264  /* Fix references to NEW */
2265  if (event == CMD_INSERT || event == CMD_UPDATE)
2266  new_qual = ReplaceVarsFromTargetList(new_qual,
2268  0,
2269  rt_fetch(rt_index,
2270  parsetree->rtable),
2271  parsetree->targetList,
2272  (event == CMD_UPDATE) ?
2275  rt_index,
2276  &parsetree->hasSubLinks);
2277  /* And attach the fixed qual */
2278  AddInvertedQual(parsetree, new_qual);
2279 
2280  return parsetree;
2281 }
static bool acquireLocksOnSubLinks(Node *node, acquireLocksOnSubLinks_context *context)
void AddInvertedQual(Query *parsetree, Node *qual)
Definition: nodes.h:539
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:655
#define PRS2_NEW_VARNO
Definition: primnodes.h:184

◆ fill_extraUpdatedCols()

void fill_extraUpdatedCols ( RangeTblEntry target_rte,
Relation  target_relation 
)

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

1574 {
1575  TupleDesc tupdesc = RelationGetDescr(target_relation);
1576  TupleConstr *constr = tupdesc->constr;
1577 
1578  target_rte->extraUpdatedCols = NULL;
1579 
1580  if (constr && constr->has_generated_stored)
1581  {
1582  for (int i = 0; i < constr->num_defval; i++)
1583  {
1584  AttrDefault *defval = &constr->defval[i];
1585  Node *expr;
1586  Bitmapset *attrs_used = NULL;
1587 
1588  /* skip if not generated column */
1589  if (!TupleDescAttr(tupdesc, defval->adnum - 1)->attgenerated)
1590  continue;
1591 
1592  /* identify columns this generated column depends on */
1593  expr = stringToNode(defval->adbin);
1594  pull_varattnos(expr, 1, &attrs_used);
1595 
1596  if (bms_overlap(target_rte->updatedCols, attrs_used))
1597  target_rte->extraUpdatedCols =
1598  bms_add_member(target_rte->extraUpdatedCols,
1600  }
1601  }
1602 }
#define RelationGetDescr(relation)
Definition: rel.h:503
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
Definition: nodes.h:539
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:246
AttrDefault * defval
Definition: tupdesc.h:39
bool has_generated_stored
Definition: tupdesc.h:45
Bitmapset * extraUpdatedCols
Definition: parsenodes.h:1150
TupleConstr * constr
Definition: tupdesc.h:85
Bitmapset * updatedCols
Definition: parsenodes.h:1149
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 1284 of file rewriteHandler.c.

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

Referenced by rewriteTargetListIU().

1285 {
1286  Bitmapset *default_only_cols = NULL;
1287  ListCell *lc;
1288 
1289  foreach(lc, rte->values_lists)
1290  {
1291  List *sublist = (List *) lfirst(lc);
1292  ListCell *lc2;
1293  int i;
1294 
1295  if (default_only_cols == NULL)
1296  {
1297  /* Populate the initial result bitmap from the first row */
1298  i = 0;
1299  foreach(lc2, sublist)
1300  {
1301  Node *col = (Node *) lfirst(lc2);
1302 
1303  i++;
1304  if (IsA(col, SetToDefault))
1305  default_only_cols = bms_add_member(default_only_cols, i);
1306  }
1307  }
1308  else
1309  {
1310  /* Update the result bitmap from this next row */
1311  i = 0;
1312  foreach(lc2, sublist)
1313  {
1314  Node *col = (Node *) lfirst(lc2);
1315 
1316  i++;
1317  if (!IsA(col, SetToDefault))
1318  default_only_cols = bms_del_member(default_only_cols, i);
1319  }
1320  }
1321 
1322  /*
1323  * If no column in the rows read so far contains only DEFAULT items,
1324  * we are done.
1325  */
1326  if (bms_is_empty(default_only_cols))
1327  break;
1328  }
1329 
1330  return default_only_cols;
1331 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
Definition: nodes.h:539
List * values_lists
Definition: parsenodes.h:1100
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 1920 of file rewriteHandler.c.

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

Referenced by fireRIRrules().

1921 {
1922  if (node == NULL)
1923  return false;
1924  if (IsA(node, SubLink))
1925  {
1926  SubLink *sub = (SubLink *) node;
1927 
1928  /* Do what we came for */
1929  sub->subselect = (Node *) fireRIRrules((Query *) sub->subselect,
1930  activeRIRs);
1931  /* Fall through to process lefthand args of SubLink */
1932  }
1933 
1934  /*
1935  * Do NOT recurse into Query nodes, because fireRIRrules already processed
1936  * subselects of subselects for us.
1937  */
1939  (void *) activeRIRs);
1940 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
Definition: nodes.h:539
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 1951 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().

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

2320 {
2321  List *results = NIL;
2322  ListCell *l;
2323 
2324  foreach(l, locks)
2325  {
2326  RewriteRule *rule_lock = (RewriteRule *) lfirst(l);
2327  Node *event_qual = rule_lock->qual;
2328  List *actions = rule_lock->actions;
2329  QuerySource qsrc;
2330  ListCell *r;
2331 
2332  /* Determine correct QuerySource value for actions */
2333  if (rule_lock->isInstead)
2334  {
2335  if (event_qual != NULL)
2336  qsrc = QSRC_QUAL_INSTEAD_RULE;
2337  else
2338  {
2339  qsrc = QSRC_INSTEAD_RULE;
2340  *instead_flag = true; /* report unqualified INSTEAD */
2341  }
2342  }
2343  else
2344  qsrc = QSRC_NON_INSTEAD_RULE;
2345 
2346  if (qsrc == QSRC_QUAL_INSTEAD_RULE)
2347  {
2348  /*
2349  * If there are INSTEAD rules with qualifications, the original
2350  * query is still performed. But all the negated rule
2351  * qualifications of the INSTEAD rules are added so it does its
2352  * actions only in cases where the rule quals of all INSTEAD rules
2353  * are false. Think of it as the default action in a case. We save
2354  * this in *qual_product so RewriteQuery() can add it to the query
2355  * list after we mangled it up enough.
2356  *
2357  * If we have already found an unqualified INSTEAD rule, then
2358  * *qual_product won't be used, so don't bother building it.
2359  */
2360  if (!*instead_flag)
2361  {
2362  if (*qual_product == NULL)
2363  *qual_product = copyObject(parsetree);
2364  *qual_product = CopyAndAddInvertedQual(*qual_product,
2365  event_qual,
2366  rt_index,
2367  event);
2368  }
2369  }
2370 
2371  /* Now process the rule's actions and add them to the result list */
2372  foreach(r, actions)
2373  {
2374  Query *rule_action = lfirst(r);
2375 
2376  if (rule_action->commandType == CMD_NOTHING)
2377  continue;
2378 
2379  rule_action = rewriteRuleAction(parsetree, rule_action,
2380  event_qual, rt_index, event,
2381  returning_flag);
2382 
2383  rule_action->querySource = qsrc;
2384  rule_action->canSetTag = false; /* might change later */
2385 
2386  results = lappend(results, rule_action);
2387  }
2388  }
2389 
2390  return results;
2391 }
#define NIL
Definition: pg_list.h:65
Node * qual
Definition: prs2lock.h:28
QuerySource
Definition: parsenodes.h:40
Definition: nodes.h:539
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:655
Definition: pg_list.h:50

◆ get_assignment_input()

static Node * get_assignment_input ( Node node)
static

Definition at line 1144 of file rewriteHandler.c.

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

Referenced by process_matched_tle().

1145 {
1146  if (node == NULL)
1147  return NULL;
1148  if (IsA(node, FieldStore))
1149  {
1150  FieldStore *fstore = (FieldStore *) node;
1151 
1152  return (Node *) fstore->arg;
1153  }
1154  else if (IsA(node, SubscriptingRef))
1155  {
1156  SubscriptingRef *sbsref = (SubscriptingRef *) node;
1157 
1158  if (sbsref->refassgnexpr == NULL)
1159  return NULL;
1160 
1161  return (Node *) sbsref->refexpr;
1162  }
1163 
1164  return NULL;
1165 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
Expr * arg
Definition: primnodes.h:837
Definition: nodes.h:539
Expr * refassgnexpr
Definition: primnodes.h:451
Expr * refexpr
Definition: primnodes.h:449

◆ get_view_query()

Query* get_view_query ( Relation  view)

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

2405 {
2406  int i;
2407 
2408  Assert(view->rd_rel->relkind == RELKIND_VIEW);
2409 
2410  for (i = 0; i < view->rd_rules->numLocks; i++)
2411  {
2412  RewriteRule *rule = view->rd_rules->rules[i];
2413 
2414  if (rule->event == CMD_SELECT)
2415  {
2416  /* A _RETURN rule should have only one action */
2417  if (list_length(rule->actions) != 1)
2418  elog(ERROR, "invalid _RETURN rule action specification");
2419 
2420  return (Query *) linitial(rule->actions);
2421  }
2422  }
2423 
2424  elog(ERROR, "failed to find _RETURN rule for view");
2425  return NULL; /* keep compiler quiet */
2426 }
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 1860 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().

1863 {
1864  if (jtnode == NULL)
1865  return;
1866  if (IsA(jtnode, RangeTblRef))
1867  {
1868  int rti = ((RangeTblRef *) jtnode)->rtindex;
1869  RangeTblEntry *rte = rt_fetch(rti, qry->rtable);
1870 
1871  if (rte->rtekind == RTE_RELATION)
1872  {
1873  applyLockingClause(qry, rti, strength, waitPolicy, pushedDown);
1875  }
1876  else if (rte->rtekind == RTE_SUBQUERY)
1877  {
1878  applyLockingClause(qry, rti, strength, waitPolicy, pushedDown);
1879  /* FOR UPDATE/SHARE of subquery is propagated to subquery's rels */
1881  strength, waitPolicy, true);
1882  }
1883  /* other RTE types are unaffected by FOR UPDATE */
1884  }
1885  else if (IsA(jtnode, FromExpr))
1886  {
1887  FromExpr *f = (FromExpr *) jtnode;
1888  ListCell *l;
1889 
1890  foreach(l, f->fromlist)
1891  markQueryForLocking(qry, lfirst(l), strength, waitPolicy, pushedDown);
1892  }
1893  else if (IsA(jtnode, JoinExpr))
1894  {
1895  JoinExpr *j = (JoinExpr *) jtnode;
1896 
1897  markQueryForLocking(qry, j->larg, strength, waitPolicy, pushedDown);
1898  markQueryForLocking(qry, j->rarg, strength, waitPolicy, pushedDown);
1899  }
1900  else
1901  elog(ERROR, "unrecognized node type: %d",
1902  (int) nodeTag(jtnode));
1903 }
static void markQueryForLocking(Query *qry, Node *jtnode, LockClauseStrength strength, LockWaitPolicy waitPolicy, bool pushedDown)
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
FromExpr * jointree
Definition: parsenodes.h:148
Definition: nodes.h:539
AclMode requiredPerms
Definition: parsenodes.h:1145
List * fromlist
Definition: primnodes.h:1563
Node * larg
Definition: primnodes.h:1542
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:1543
#define lfirst(lc)
Definition: pg_list.h:169
#define ACL_SELECT_FOR_UPDATE
Definition: parsenodes.h:98
#define nodeTag(nodeptr)
Definition: nodes.h:544
RTEKind rtekind
Definition: parsenodes.h:995
Query * subquery
Definition: parsenodes.h:1030
#define elog(elevel,...)
Definition: elog.h:232
void applyLockingClause(Query *qry, Index rtindex, LockClauseStrength strength, LockWaitPolicy waitPolicy, bool pushedDown)
Definition: analyze.c:3328

◆ matchLocks()

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

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

1615 {
1616  List *matching_locks = NIL;
1617  int nlocks;
1618  int i;
1619 
1620  if (rulelocks == NULL)
1621  return NIL;
1622 
1623  if (parsetree->commandType != CMD_SELECT)
1624  {
1625  if (parsetree->resultRelation != varno)
1626  return NIL;
1627  }
1628 
1629  nlocks = rulelocks->numLocks;
1630 
1631  for (i = 0; i < nlocks; i++)
1632  {
1633  RewriteRule *oneLock = rulelocks->rules[i];
1634 
1635  if (oneLock->event == CMD_UPDATE)
1636  *hasUpdate = true;
1637 
1638  /*
1639  * Suppress ON INSERT/UPDATE/DELETE rules that are disabled or
1640  * configured to not fire during the current sessions replication
1641  * role. ON SELECT rules will always be applied in order to keep views
1642  * working even in LOCAL or REPLICA role.
1643  */
1644  if (oneLock->event != CMD_SELECT)
1645  {
1647  {
1648  if (oneLock->enabled == RULE_FIRES_ON_ORIGIN ||
1649  oneLock->enabled == RULE_DISABLED)
1650  continue;
1651  }
1652  else /* ORIGIN or LOCAL ROLE */
1653  {
1654  if (oneLock->enabled == RULE_FIRES_ON_REPLICA ||
1655  oneLock->enabled == RULE_DISABLED)
1656  continue;
1657  }
1658  }
1659 
1660  if (oneLock->event == event)
1661  {
1662  if (parsetree->commandType != CMD_SELECT ||
1663  rangeTableEntry_used((Node *) parsetree, varno, 0))
1664  matching_locks = lappend(matching_locks, oneLock);
1665  }
1666  }
1667 
1668  return matching_locks;
1669 }
#define NIL
Definition: pg_list.h:65
int numLocks
Definition: prs2lock.h:42
int resultRelation
Definition: parsenodes.h:130
Definition: nodes.h:539
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 991 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().

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

4058 {
4059  uint64 input_query_id = parsetree->queryId;
4060  List *querylist;
4061  List *results;
4062  ListCell *l;
4063  CmdType origCmdType;
4064  bool foundOriginalQuery;
4065  Query *lastInstead;
4066 
4067  /*
4068  * This function is only applied to top-level original queries
4069  */
4070  Assert(parsetree->querySource == QSRC_ORIGINAL);
4071  Assert(parsetree->canSetTag);
4072 
4073  /*
4074  * Step 1
4075  *
4076  * Apply all non-SELECT rules possibly getting 0 or many queries
4077  */
4078  querylist = RewriteQuery(parsetree, NIL);
4079 
4080  /*
4081  * Step 2
4082  *
4083  * Apply all the RIR rules on each query
4084  *
4085  * This is also a handy place to mark each query with the original queryId
4086  */
4087  results = NIL;
4088  foreach(l, querylist)
4089  {
4090  Query *query = (Query *) lfirst(l);
4091 
4092  query = fireRIRrules(query, NIL);
4093 
4094  query->queryId = input_query_id;
4095 
4096  results = lappend(results, query);
4097  }
4098 
4099  /*
4100  * Step 3
4101  *
4102  * Determine which, if any, of the resulting queries is supposed to set
4103  * the command-result tag; and update the canSetTag fields accordingly.
4104  *
4105  * If the original query is still in the list, it sets the command tag.
4106  * Otherwise, the last INSTEAD query of the same kind as the original is
4107  * allowed to set the tag. (Note these rules can leave us with no query
4108  * setting the tag. The tcop code has to cope with this by setting up a
4109  * default tag based on the original un-rewritten query.)
4110  *
4111  * The Asserts verify that at most one query in the result list is marked
4112  * canSetTag. If we aren't checking asserts, we can fall out of the loop
4113  * as soon as we find the original query.
4114  */
4115  origCmdType = parsetree->commandType;
4116  foundOriginalQuery = false;
4117  lastInstead = NULL;
4118 
4119  foreach(l, results)
4120  {
4121  Query *query = (Query *) lfirst(l);
4122 
4123  if (query->querySource == QSRC_ORIGINAL)
4124  {
4125  Assert(query->canSetTag);
4126  Assert(!foundOriginalQuery);
4127  foundOriginalQuery = true;
4128 #ifndef USE_ASSERT_CHECKING
4129  break;
4130 #endif
4131  }
4132  else
4133  {
4134  Assert(!query->canSetTag);
4135  if (query->commandType == origCmdType &&
4136  (query->querySource == QSRC_INSTEAD_RULE ||
4138  lastInstead = query;
4139  }
4140  }
4141 
4142  if (!foundOriginalQuery && lastInstead != NULL)
4143  lastInstead->canSetTag = true;
4144 
4145  return results;
4146 }
#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 2754 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().

2758 {
2759  int events = 0;
2760  Relation rel;
2761  RuleLock *rulelocks;
2762 
2763 #define ALL_EVENTS ((1 << CMD_INSERT) | (1 << CMD_UPDATE) | (1 << CMD_DELETE))
2764 
2765  /* Since this function recurses, it could be driven to stack overflow */
2767 
2768  rel = try_relation_open(reloid, AccessShareLock);
2769 
2770  /*
2771  * If the relation doesn't exist, return zero rather than throwing an
2772  * error. This is helpful since scanning an information_schema view under
2773  * MVCC rules can result in referencing rels that have actually been
2774  * deleted already.
2775  */
2776  if (rel == NULL)
2777  return 0;
2778 
2779  /* If we detect a recursive view, report that it is not updatable */
2780  if (list_member_oid(outer_reloids, RelationGetRelid(rel)))
2781  {
2783  return 0;
2784  }
2785 
2786  /* If the relation is a table, it is always updatable */
2787  if (rel->rd_rel->relkind == RELKIND_RELATION ||
2788  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
2789  {
2791  return ALL_EVENTS;
2792  }
2793 
2794  /* Look for unconditional DO INSTEAD rules, and note supported events */
2795  rulelocks = rel->rd_rules;
2796  if (rulelocks != NULL)
2797  {
2798  int i;
2799 
2800  for (i = 0; i < rulelocks->numLocks; i++)
2801  {
2802  if (rulelocks->rules[i]->isInstead &&
2803  rulelocks->rules[i]->qual == NULL)
2804  {
2805  events |= ((1 << rulelocks->rules[i]->event) & ALL_EVENTS);
2806  }
2807  }
2808 
2809  /* If we have rules for all events, we're done */
2810  if (events == ALL_EVENTS)
2811  {
2813  return events;
2814  }
2815  }
2816 
2817  /* Similarly look for INSTEAD OF triggers, if they are to be included */
2818  if (include_triggers)
2819  {
2820  TriggerDesc *trigDesc = rel->trigdesc;
2821 
2822  if (trigDesc)
2823  {
2824  if (trigDesc->trig_insert_instead_row)
2825  events |= (1 << CMD_INSERT);
2826  if (trigDesc->trig_update_instead_row)
2827  events |= (1 << CMD_UPDATE);
2828  if (trigDesc->trig_delete_instead_row)
2829  events |= (1 << CMD_DELETE);
2830 
2831  /* If we have triggers for all events, we're done */
2832  if (events == ALL_EVENTS)
2833  {
2835  return events;
2836  }
2837  }
2838  }
2839 
2840  /* If this is a foreign table, check which update events it supports */
2841  if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
2842  {
2843  FdwRoutine *fdwroutine = GetFdwRoutineForRelation(rel, false);
2844 
2845  if (fdwroutine->IsForeignRelUpdatable != NULL)
2846  events |= fdwroutine->IsForeignRelUpdatable(rel);
2847  else
2848  {
2849  /* Assume presence of executor functions is sufficient */
2850  if (fdwroutine->ExecForeignInsert != NULL)
2851  events |= (1 << CMD_INSERT);
2852  if (fdwroutine->ExecForeignUpdate != NULL)
2853  events |= (1 << CMD_UPDATE);
2854  if (fdwroutine->ExecForeignDelete != NULL)
2855  events |= (1 << CMD_DELETE);
2856  }
2857 
2859  return events;
2860  }
2861 
2862  /* Check if this is an automatically updatable view */
2863  if (rel->rd_rel->relkind == RELKIND_VIEW)
2864  {
2865  Query *viewquery = get_view_query(rel);
2866 
2867  if (view_query_is_auto_updatable(viewquery, false) == NULL)
2868  {
2869  Bitmapset *updatable_cols;
2870  int auto_events;
2871  RangeTblRef *rtr;
2872  RangeTblEntry *base_rte;
2873  Oid baseoid;
2874 
2875  /*
2876  * Determine which of the view's columns are updatable. If there
2877  * are none within the set of columns we are looking at, then the
2878  * view doesn't support INSERT/UPDATE, but it may still support
2879  * DELETE.
2880  */
2881  view_cols_are_auto_updatable(viewquery, NULL,
2882  &updatable_cols, NULL);
2883 
2884  if (include_cols != NULL)
2885  updatable_cols = bms_int_members(updatable_cols, include_cols);
2886 
2887  if (bms_is_empty(updatable_cols))
2888  auto_events = (1 << CMD_DELETE); /* May support DELETE */
2889  else
2890  auto_events = ALL_EVENTS; /* May support all events */
2891 
2892  /*
2893  * The base relation must also support these update commands.
2894  * Tables are always updatable, but for any other kind of base
2895  * relation we must do a recursive check limited to the columns
2896  * referenced by the locally updatable columns in this view.
2897  */
2898  rtr = (RangeTblRef *) linitial(viewquery->jointree->fromlist);
2899  base_rte = rt_fetch(rtr->rtindex, viewquery->rtable);
2900  Assert(base_rte->rtekind == RTE_RELATION);
2901 
2902  if (base_rte->relkind != RELKIND_RELATION &&
2903  base_rte->relkind != RELKIND_PARTITIONED_TABLE)
2904  {
2905  baseoid = base_rte->relid;
2906  outer_reloids = lappend_oid(outer_reloids,
2907  RelationGetRelid(rel));
2908  include_cols = adjust_view_column_set(updatable_cols,
2909  viewquery->targetList);
2910  auto_events &= relation_is_updatable(baseoid,
2911  outer_reloids,
2912  include_triggers,
2913  include_cols);
2914  outer_reloids = list_delete_last(outer_reloids);
2915  }
2916  events |= auto_events;
2917  }
2918  }
2919 
2920  /* If we reach here, the relation may support some update commands */
2922  return events;
2923 }
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:1563
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:995
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 3560 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().

3561 {
3562  CmdType event = parsetree->commandType;
3563  bool instead = false;
3564  bool returning = false;
3565  bool updatableview = false;
3566  Query *qual_product = NULL;
3567  List *rewritten = NIL;
3568  ListCell *lc1;
3569 
3570  /*
3571  * First, recursively process any insert/update/delete statements in WITH
3572  * clauses. (We have to do this first because the WITH clauses may get
3573  * copied into rule actions below.)
3574  */
3575  foreach(lc1, parsetree->cteList)
3576  {
3578  Query *ctequery = castNode(Query, cte->ctequery);
3579  List *newstuff;
3580 
3581  if (ctequery->commandType == CMD_SELECT)
3582  continue;
3583 
3584  newstuff = RewriteQuery(ctequery, rewrite_events);
3585 
3586  /*
3587  * Currently we can only handle unconditional, single-statement DO
3588  * INSTEAD rules correctly; we have to get exactly one non-utility
3589  * Query out of the rewrite operation to stuff back into the CTE node.
3590  */
3591  if (list_length(newstuff) == 1)
3592  {
3593  /* Must check it's not a utility command */
3594  ctequery = linitial_node(Query, newstuff);
3595  if (!(ctequery->commandType == CMD_SELECT ||
3596  ctequery->commandType == CMD_UPDATE ||
3597  ctequery->commandType == CMD_INSERT ||
3598  ctequery->commandType == CMD_DELETE))
3599  {
3600  /*
3601  * Currently it could only be NOTIFY; this error message will
3602  * need work if we ever allow other utility commands in rules.
3603  */
3604  ereport(ERROR,
3605  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3606  errmsg("DO INSTEAD NOTIFY rules are not supported for data-modifying statements in WITH")));
3607  }
3608  /* WITH queries should never be canSetTag */
3609  Assert(!ctequery->canSetTag);
3610  /* Push the single Query back into the CTE node */
3611  cte->ctequery = (Node *) ctequery;
3612  }
3613  else if (newstuff == NIL)
3614  {
3615  ereport(ERROR,
3616  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3617  errmsg("DO INSTEAD NOTHING rules are not supported for data-modifying statements in WITH")));
3618  }
3619  else
3620  {
3621  ListCell *lc2;
3622 
3623  /* examine queries to determine which error message to issue */
3624  foreach(lc2, newstuff)
3625  {
3626  Query *q = (Query *) lfirst(lc2);
3627 
3629  ereport(ERROR,
3630  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3631  errmsg("conditional DO INSTEAD rules are not supported for data-modifying statements in WITH")));
3633  ereport(ERROR,
3634  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3635  errmsg("DO ALSO rules are not supported for data-modifying statements in WITH")));
3636  }
3637 
3638  ereport(ERROR,
3639  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3640  errmsg("multi-statement DO INSTEAD rules are not supported for data-modifying statements in WITH")));
3641  }
3642  }
3643 
3644  /*
3645  * If the statement is an insert, update, or delete, adjust its targetlist
3646  * as needed, and then fire INSERT/UPDATE/DELETE rules on it.
3647  *
3648  * SELECT rules are handled later when we have all the queries that should
3649  * get executed. Also, utilities aren't rewritten at all (do we still
3650  * need that check?)
3651  */
3652  if (event != CMD_SELECT && event != CMD_UTILITY)
3653  {
3654  int result_relation;
3655  RangeTblEntry *rt_entry;
3656  Relation rt_entry_relation;
3657  List *locks;
3658  List *product_queries;
3659  bool hasUpdate = false;
3660  int values_rte_index = 0;
3661  bool defaults_remaining = false;
3662 
3663  result_relation = parsetree->resultRelation;
3664  Assert(result_relation != 0);
3665  rt_entry = rt_fetch(result_relation, parsetree->rtable);
3666  Assert(rt_entry->rtekind == RTE_RELATION);
3667 
3668  /*
3669  * We can use NoLock here since either the parser or
3670  * AcquireRewriteLocks should have locked the rel already.
3671  */
3672  rt_entry_relation = table_open(rt_entry->relid, NoLock);
3673 
3674  /*
3675  * Rewrite the targetlist as needed for the command type.
3676  */
3677  if (event == CMD_INSERT)
3678  {
3679  RangeTblEntry *values_rte = NULL;
3680 
3681  /*
3682  * If it's an INSERT ... VALUES (...), (...), ... there will be a
3683  * single RTE for the VALUES targetlists.
3684  */
3685  if (list_length(parsetree->jointree->fromlist) == 1)
3686  {
3687  RangeTblRef *rtr = (RangeTblRef *) linitial(parsetree->jointree->fromlist);
3688 
3689  if (IsA(rtr, RangeTblRef))
3690  {
3691  RangeTblEntry *rte = rt_fetch(rtr->rtindex,
3692  parsetree->rtable);
3693 
3694  if (rte->rtekind == RTE_VALUES)
3695  {
3696  values_rte = rte;
3697  values_rte_index = rtr->rtindex;
3698  }
3699  }
3700  }
3701 
3702  if (values_rte)
3703  {
3704  Bitmapset *unused_values_attrnos = NULL;
3705 
3706  /* Process the main targetlist ... */
3707  parsetree->targetList = rewriteTargetListIU(parsetree->targetList,
3708  parsetree->commandType,
3709  parsetree->override,
3710  rt_entry_relation,
3711  values_rte,
3712  values_rte_index,
3713  &unused_values_attrnos);
3714  /* ... and the VALUES expression lists */
3715  if (!rewriteValuesRTE(parsetree, values_rte, values_rte_index,
3716  rt_entry_relation, false,
3717  unused_values_attrnos))
3718  defaults_remaining = true;
3719  }
3720  else
3721  {
3722  /* Process just the main targetlist */
3723  parsetree->targetList =
3724  rewriteTargetListIU(parsetree->targetList,
3725  parsetree->commandType,
3726  parsetree->override,
3727  rt_entry_relation,
3728  NULL, 0, NULL);
3729  }
3730 
3731  if (parsetree->onConflict &&
3732  parsetree->onConflict->action == ONCONFLICT_UPDATE)
3733  {
3734  parsetree->onConflict->onConflictSet =
3736  CMD_UPDATE,
3737  parsetree->override,
3738  rt_entry_relation,
3739  NULL, 0, NULL);
3740  }
3741  }
3742  else if (event == CMD_UPDATE)
3743  {
3744  parsetree->targetList =
3745  rewriteTargetListIU(parsetree->targetList,
3746  parsetree->commandType,
3747  parsetree->override,
3748  rt_entry_relation,
3749  NULL, 0, NULL);
3750 
3751  /* Also populate extraUpdatedCols (for generated columns) */
3752  fill_extraUpdatedCols(rt_entry, rt_entry_relation);
3753  }
3754  else if (event == CMD_DELETE)
3755  {
3756  /* Nothing to do here */
3757  }
3758  else
3759  elog(ERROR, "unrecognized commandType: %d", (int) event);
3760 
3761  /*
3762  * Collect and apply the appropriate rules.
3763  */
3764  locks = matchLocks(event, rt_entry_relation->rd_rules,
3765  result_relation, parsetree, &hasUpdate);
3766 
3767  product_queries = fireRules(parsetree,
3768  result_relation,
3769  event,
3770  locks,
3771  &instead,
3772  &returning,
3773  &qual_product);
3774 
3775  /*
3776  * If we have a VALUES RTE with any remaining untouched DEFAULT items,
3777  * and we got any product queries, finalize the VALUES RTE for each
3778  * product query (replacing the remaining DEFAULT items with NULLs).
3779  * We don't do this for the original query, because we know that it
3780  * must be an auto-insert on a view, and so should use the base
3781  * relation's defaults for any remaining DEFAULT items.
3782  */
3783  if (defaults_remaining && product_queries != NIL)
3784  {
3785  ListCell *n;
3786 
3787  /*
3788  * Each product query has its own copy of the VALUES RTE at the
3789  * same index in the rangetable, so we must finalize each one.
3790  */
3791  foreach(n, product_queries)
3792  {
3793  Query *pt = (Query *) lfirst(n);
3794  RangeTblEntry *values_rte = rt_fetch(values_rte_index,
3795  pt->rtable);
3796 
3797  rewriteValuesRTE(pt, values_rte, values_rte_index,
3798  rt_entry_relation,
3799  true, /* Force remaining defaults to NULL */
3800  NULL);
3801  }
3802  }
3803 
3804  /*
3805  * If there was no unqualified INSTEAD rule, and the target relation
3806  * is a view without any INSTEAD OF triggers, see if the view can be
3807  * automatically updated. If so, we perform the necessary query
3808  * transformation here and add the resulting query to the
3809  * product_queries list, so that it gets recursively rewritten if
3810  * necessary.
3811  *
3812  * If the view cannot be automatically updated, we throw an error here
3813  * which is OK since the query would fail at runtime anyway. Throwing
3814  * the error here is preferable to the executor check since we have
3815  * more detailed information available about why the view isn't
3816  * updatable.
3817  */
3818  if (!instead &&
3819  rt_entry_relation->rd_rel->relkind == RELKIND_VIEW &&
3820  !view_has_instead_trigger(rt_entry_relation, event))
3821  {
3822  /*
3823  * If there were any qualified INSTEAD rules, don't allow the view
3824  * to be automatically updated (an unqualified INSTEAD rule or
3825  * INSTEAD OF trigger is required).
3826  *
3827  * The messages here should match execMain.c's CheckValidResultRel
3828  * and in principle make those checks in executor unnecessary, but
3829  * we keep them just in case.
3830  */
3831  if (qual_product != NULL)
3832  {
3833  switch (parsetree->commandType)
3834  {
3835  case CMD_INSERT:
3836  ereport(ERROR,
3837  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3838  errmsg("cannot insert into view \"%s\"",
3839  RelationGetRelationName(rt_entry_relation)),
3840  errdetail("Views with conditional DO INSTEAD rules are not automatically updatable."),
3841  errhint("To enable inserting into the view, provide an INSTEAD OF INSERT trigger or an unconditional ON INSERT DO INSTEAD rule.")));
3842  break;
3843  case CMD_UPDATE:
3844  ereport(ERROR,
3845  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3846  errmsg("cannot update view \"%s\"",
3847  RelationGetRelationName(rt_entry_relation)),
3848  errdetail("Views with conditional DO INSTEAD rules are not automatically updatable."),
3849  errhint("To enable updating the view, provide an INSTEAD OF UPDATE trigger or an unconditional ON UPDATE DO INSTEAD rule.")));
3850  break;
3851  case CMD_DELETE:
3852  ereport(ERROR,
3853  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3854  errmsg("cannot delete from view \"%s\"",
3855  RelationGetRelationName(rt_entry_relation)),
3856  errdetail("Views with conditional DO INSTEAD rules are not automatically updatable."),
3857  errhint("To enable deleting from the view, provide an INSTEAD OF DELETE trigger or an unconditional ON DELETE DO INSTEAD rule.")));
3858  break;
3859  default:
3860  elog(ERROR, "unrecognized CmdType: %d",
3861  (int) parsetree->commandType);
3862  break;
3863  }
3864  }
3865 
3866  /*
3867  * Attempt to rewrite the query to automatically update the view.
3868  * This throws an error if the view can't be automatically
3869  * updated.
3870  */
3871  parsetree = rewriteTargetView(parsetree, rt_entry_relation);
3872 
3873  /*
3874  * At this point product_queries contains any DO ALSO rule
3875  * actions. Add the rewritten query before or after those. This
3876  * must match the handling the original query would have gotten
3877  * below, if we allowed it to be included again.
3878  */
3879  if (parsetree->commandType == CMD_INSERT)
3880  product_queries = lcons(parsetree, product_queries);
3881  else
3882  product_queries = lappend(product_queries, parsetree);
3883 
3884  /*
3885  * Set the "instead" flag, as if there had been an unqualified
3886  * INSTEAD, to prevent the original query from being included a
3887  * second time below. The transformation will have rewritten any
3888  * RETURNING list, so we can also set "returning" to forestall
3889  * throwing an error below.
3890  */
3891  instead = true;
3892  returning = true;
3893  updatableview = true;
3894  }
3895 
3896  /*
3897  * If we got any product queries, recursively rewrite them --- but
3898  * first check for recursion!
3899  */
3900  if (product_queries != NIL)
3901  {
3902  ListCell *n;
3903  rewrite_event *rev;
3904 
3905  foreach(n, rewrite_events)
3906  {
3907  rev = (rewrite_event *) lfirst(n);
3908  if (rev->relation == RelationGetRelid(rt_entry_relation) &&
3909  rev->event == event)
3910  ereport(ERROR,
3911  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
3912  errmsg("infinite recursion detected in rules for relation \"%s\"",
3913  RelationGetRelationName(rt_entry_relation))));
3914  }
3915 
3916  rev = (rewrite_event *) palloc(sizeof(rewrite_event));
3917  rev->relation = RelationGetRelid(rt_entry_relation);
3918  rev->event = event;
3919  rewrite_events = lappend(rewrite_events, rev);
3920 
3921  foreach(n, product_queries)
3922  {
3923  Query *pt = (Query *) lfirst(n);
3924  List *newstuff;
3925 
3926  newstuff = RewriteQuery(pt, rewrite_events);
3927  rewritten = list_concat(rewritten, newstuff);
3928  }
3929 
3930  rewrite_events = list_delete_last(rewrite_events);
3931  }
3932 
3933  /*
3934  * If there is an INSTEAD, and the original query has a RETURNING, we
3935  * have to have found a RETURNING in the rule(s), else fail. (Because
3936  * DefineQueryRewrite only allows RETURNING in unconditional INSTEAD
3937  * rules, there's no need to worry whether the substituted RETURNING
3938  * will actually be executed --- it must be.)
3939  */
3940  if ((instead || qual_product != NULL) &&
3941  parsetree->returningList &&
3942  !returning)
3943  {
3944  switch (event)
3945  {
3946  case CMD_INSERT:
3947  ereport(ERROR,
3948  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3949  errmsg("cannot perform INSERT RETURNING on relation \"%s\"",
3950  RelationGetRelationName(rt_entry_relation)),
3951  errhint("You need an unconditional ON INSERT DO INSTEAD rule with a RETURNING clause.")));
3952  break;
3953  case CMD_UPDATE:
3954  ereport(ERROR,
3955  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3956  errmsg("cannot perform UPDATE RETURNING on relation \"%s\"",
3957  RelationGetRelationName(rt_entry_relation)),
3958  errhint("You need an unconditional ON UPDATE DO INSTEAD rule with a RETURNING clause.")));
3959  break;
3960  case CMD_DELETE:
3961  ereport(ERROR,
3962  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3963  errmsg("cannot perform DELETE RETURNING on relation \"%s\"",
3964  RelationGetRelationName(rt_entry_relation)),
3965  errhint("You need an unconditional ON DELETE DO INSTEAD rule with a RETURNING clause.")));
3966  break;
3967  default:
3968  elog(ERROR, "unrecognized commandType: %d",
3969  (int) event);
3970  break;
3971  }
3972  }
3973 
3974  /*
3975  * Updatable views are supported by ON CONFLICT, so don't prevent that
3976  * case from proceeding
3977  */
3978  if (parsetree->onConflict &&
3979  (product_queries != NIL || hasUpdate) &&
3980  !updatableview)
3981  ereport(ERROR,
3982  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3983  errmsg("INSERT with ON CONFLICT clause cannot be used with table that has INSERT or UPDATE rules")));
3984 
3985  table_close(rt_entry_relation, NoLock);
3986  }
3987 
3988  /*
3989  * For INSERTs, the original query is done first; for UPDATE/DELETE, it is
3990  * done last. This is needed because update and delete rule actions might
3991  * not do anything if they are invoked after the update or delete is
3992  * performed. The command counter increment between the query executions
3993  * makes the deleted (and maybe the updated) tuples disappear so the scans
3994  * for them in the rule actions cannot find them.
3995  *
3996  * If we found any unqualified INSTEAD, the original query is not done at
3997  * all, in any form. Otherwise, we add the modified form if qualified
3998  * INSTEADs were found, else the unmodified form.
3999  */
4000  if (!instead)
4001  {
4002  if (parsetree->commandType == CMD_INSERT)
4003  {
4004  if (qual_product != NULL)
4005  rewritten = lcons(qual_product, rewritten);
4006  else
4007  rewritten = lcons(parsetree, rewritten);
4008  }
4009  else
4010  {
4011  if (qual_product != NULL)
4012  rewritten = lappend(rewritten, qual_product);
4013  else
4014  rewritten = lappend(rewritten, parsetree);
4015  }
4016  }
4017 
4018  /*
4019  * If the original query has a CTE list, and we generated more than one
4020  * non-utility result query, we have to fail because we'll have copied the
4021  * CTE list into each result query. That would break the expectation of
4022  * single evaluation of CTEs. This could possibly be fixed by
4023  * restructuring so that a CTE list can be shared across multiple Query
4024  * and PlannableStatement nodes.
4025  */
4026  if (parsetree->cteList != NIL)
4027  {
4028  int qcount = 0;
4029 
4030  foreach(lc1, rewritten)
4031  {
4032  Query *q = (Query *) lfirst(lc1);
4033 
4034  if (q->commandType != CMD_UTILITY)
4035  qcount++;
4036  }
4037  if (qcount > 1)
4038  ereport(ERROR,
4039  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4040  errmsg("WITH cannot be used in a query that is rewritten by rules into multiple queries")));
4041  }
4042 
4043  return rewritten;
4044 }
#define NIL
Definition: pg_list.h:65
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
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:608
int resultRelation
Definition: parsenodes.h:130
Definition: nodes.h:539
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:1563
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:1579
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:995
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:1588
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::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  */
539  foreach(lc, parsetree->cteList)
540  {
541  CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
542  ListCell *lc2;
543 
544  foreach(lc2, sub_action->cteList)
545  {
546  CommonTableExpr *cte2 = (CommonTableExpr *) lfirst(lc2);
547 
548  if (strcmp(cte->ctename, cte2->ctename) == 0)
549  ereport(ERROR,
550  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
551  errmsg("WITH query name \"%s\" appears in both a rule action and the query being rewritten",
552  cte->ctename)));
553  }
554  }
555 
556  /* OK, it's safe to combine the CTE lists */
557  sub_action->cteList = list_concat(sub_action->cteList,
558  copyObject(parsetree->cteList));
559  }
560 
561  /*
562  * Event Qualification forces copying of parsetree and splitting into two
563  * queries one w/rule_qual, one w/NOT rule_qual. Also add user query qual
564  * onto rule action
565  */
566  AddQual(sub_action, rule_qual);
567 
568  AddQual(sub_action, parsetree->jointree->quals);
569 
570  /*
571  * Rewrite new.attribute with right hand side of target-list entry for
572  * appropriate field name in insert/update.
573  *
574  * KLUGE ALERT: since ReplaceVarsFromTargetList returns a mutated copy, we
575  * can't just apply it to sub_action; we have to remember to update the
576  * sublink inside rule_action, too.
577  */
578  if ((event == CMD_INSERT || event == CMD_UPDATE) &&
579  sub_action->commandType != CMD_UTILITY)
580  {
581  sub_action = (Query *)
582  ReplaceVarsFromTargetList((Node *) sub_action,
583  new_varno,
584  0,
585  rt_fetch(new_varno, sub_action->rtable),
586  parsetree->targetList,
587  (event == CMD_UPDATE) ?
590  current_varno,
591  NULL);
592  if (sub_action_ptr)
593  *sub_action_ptr = sub_action;
594  else
595  rule_action = sub_action;
596  }
597 
598  /*
599  * If rule_action has a RETURNING clause, then either throw it away if the
600  * triggering query has no RETURNING clause, or rewrite it to emit what
601  * the triggering query's RETURNING clause asks for. Throw an error if
602  * more than one rule has a RETURNING clause.
603  */
604  if (!parsetree->returningList)
605  rule_action->returningList = NIL;
606  else if (rule_action->returningList)
607  {
608  if (*returning_flag)
609  ereport(ERROR,
610  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
611  errmsg("cannot have RETURNING lists in multiple rules")));
612  *returning_flag = true;
613  rule_action->returningList = (List *)
615  parsetree->resultRelation,
616  0,
617  rt_fetch(parsetree->resultRelation,
618  parsetree->rtable),
619  rule_action->returningList,
621  0,
622  &rule_action->hasSubLinks);
623 
624  /*
625  * There could have been some SubLinks in parsetree's returningList,
626  * in which case we'd better mark the rule_action correctly.
627  */
628  if (parsetree->hasSubLinks && !rule_action->hasSubLinks)
629  rule_action->hasSubLinks =
630  checkExprHasSubLink((Node *) rule_action->returningList);
631  }
632 
633  return rule_action;
634 }
#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:539
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:1563
List * values_lists
Definition: parsenodes.h:1100
Node * quals
Definition: primnodes.h:1564
List * targetList
Definition: parsenodes.h:150
List * rtable
Definition: parsenodes.h:147
#define ERROR
Definition: elog.h:46
TableFunc * tablefunc
Definition: parsenodes.h:1095
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:1089
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:995
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 rangeTableEntry_used(Node *node, int rt_index, int sublevels_up)
Definition: rewriteManip.c:892
#define copyObject(obj)
Definition: nodes.h:655
Definition: pg_list.h:50
struct TableSampleClause * tablesample
Definition: parsenodes.h:1025
#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 707 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().

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

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

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

References IsA, lfirst, and RangeTblEntry::values_lists.

Referenced by rewriteValuesRTE().

1259 {
1260  ListCell *lc;
1261 
1262  foreach(lc, rte->values_lists)
1263  {
1264  List *sublist = (List *) lfirst(lc);
1265  ListCell *lc2;
1266 
1267  foreach(lc2, sublist)
1268  {
1269  Node *col = (Node *) lfirst(lc2);
1270 
1271  if (IsA(col, SetToDefault))
1272  return true;
1273  }
1274  }
1275  return false;
1276 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
Definition: nodes.h:539
List * values_lists
Definition: parsenodes.h:1100
#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 2475 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().

2476 {
2477  Var *var = (Var *) tle->expr;
2478 
2479  /*
2480  * For now, the only updatable columns we support are those that are Vars
2481  * referring to user columns of the underlying base relation.
2482  *
2483  * The view targetlist may contain resjunk columns (e.g., a view defined
2484  * like "SELECT * FROM t ORDER BY a+b" is auto-updatable) but such columns
2485  * are not auto-updatable, and in fact should never appear in the outer
2486  * query's targetlist.
2487  */
2488  if (tle->resjunk)
2489  return gettext_noop("Junk view columns are not updatable.");
2490 
2491  if (!IsA(var, Var) ||
2492  var->varno != rtr->rtindex ||
2493  var->varlevelsup != 0)
2494  return gettext_noop("View columns that are not columns of their base relation are not updatable.");
2495 
2496  if (var->varattno < 0)
2497  return gettext_noop("View columns that refer to system columns are not updatable.");
2498 
2499  if (var->varattno == 0)
2500  return gettext_noop("View columns that return whole-row references are not updatable.");
2501 
2502  return NULL; /* the view column is updatable */
2503 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
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:1461
Index varno
Definition: primnodes.h:189
Expr * expr
Definition: primnodes.h:1454

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

2675 {
2676  RangeTblRef *rtr;
2677  AttrNumber col;
2678  ListCell *cell;
2679 
2680  /*
2681  * The caller should have verified that this view is auto-updatable and so
2682  * there should be a single base relation.
2683  */
2684  Assert(list_length(viewquery->jointree->fromlist) == 1);
2685  rtr = linitial_node(RangeTblRef, viewquery->jointree->fromlist);
2686 
2687  /* Initialize the optional return values */
2688  if (updatable_cols != NULL)
2689  *updatable_cols = NULL;
2690  if (non_updatable_col != NULL)
2691  *non_updatable_col = NULL;
2692 
2693  /* Test each view column for updatability */
2695  foreach(cell, viewquery->targetList)
2696  {
2697  TargetEntry *tle = (TargetEntry *) lfirst(cell);
2698  const char *col_update_detail;
2699 
2700  col++;
2701  col_update_detail = view_col_is_auto_updatable(rtr, tle);
2702 
2703  if (col_update_detail == NULL)
2704  {
2705  /* The column is updatable */
2706  if (updatable_cols != NULL)
2707  *updatable_cols = bms_add_member(*updatable_cols, col);
2708  }
2709  else if (bms_is_member(col, required_cols))
2710  {
2711  /* The required column is not updatable */
2712  if (non_updatable_col != NULL)
2713  *non_updatable_col = tle->resname;
2714  return col_update_detail;
2715  }
2716  }
2717 
2718  return NULL; /* all the required view columns are updatable */
2719 }
FromExpr * jointree
Definition: parsenodes.h:148
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
List * fromlist
Definition: primnodes.h:1563
char * resname
Definition: primnodes.h:1456
#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 2437 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().

2438 {
2439  TriggerDesc *trigDesc = view->trigdesc;
2440 
2441  switch (event)
2442  {
2443  case CMD_INSERT:
2444  if (trigDesc && trigDesc->trig_insert_instead_row)
2445  return true;
2446  break;
2447  case CMD_UPDATE:
2448  if (trigDesc && trigDesc->trig_update_instead_row)
2449  return true;
2450  break;
2451  case CMD_DELETE:
2452  if (trigDesc && trigDesc->trig_delete_instead_row)
2453  return true;
2454  break;
2455  default:
2456  elog(ERROR, "unrecognized CmdType: %d", (int) event);
2457  break;
2458  }
2459  return false;
2460 }
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 2523 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().

2524 {
2525  RangeTblRef *rtr;
2526  RangeTblEntry *base_rte;
2527 
2528  /*----------
2529  * Check if the view is simply updatable. According to SQL-92 this means:
2530  * - No DISTINCT clause.
2531  * - Each TLE is a column reference, and each column appears at most once.
2532  * - FROM contains exactly one base relation.
2533  * - No GROUP BY or HAVING clauses.
2534  * - No set operations (UNION, INTERSECT or EXCEPT).
2535  * - No sub-queries in the WHERE clause that reference the target table.
2536  *
2537  * We ignore that last restriction since it would be complex to enforce
2538  * and there isn't any actual benefit to disallowing sub-queries. (The
2539  * semantic issues that the standard is presumably concerned about don't
2540  * arise in Postgres, since any such sub-query will not see any updates
2541  * executed by the outer query anyway, thanks to MVCC snapshotting.)
2542  *
2543  * We also relax the second restriction by supporting part of SQL:1999
2544  * feature T111, which allows for a mix of updatable and non-updatable
2545  * columns, provided that an INSERT or UPDATE doesn't attempt to assign to
2546  * a non-updatable column.
2547  *
2548  * In addition we impose these constraints, involving features that are
2549  * not part of SQL-92:
2550  * - No CTEs (WITH clauses).
2551  * - No OFFSET or LIMIT clauses (this matches a SQL:2008 restriction).
2552  * - No system columns (including whole-row references) in the tlist.
2553  * - No window functions in the tlist.
2554  * - No set-returning functions in the tlist.
2555  *
2556  * Note that we do these checks without recursively expanding the view.
2557  * If the base relation is a view, we'll recursively deal with it later.
2558  *----------
2559  */
2560  if (viewquery->distinctClause != NIL)
2561  return gettext_noop("Views containing DISTINCT are not automatically updatable.");
2562 
2563  if (viewquery->groupClause != NIL || viewquery->groupingSets)
2564  return gettext_noop("Views containing GROUP BY are not automatically updatable.");
2565 
2566  if (viewquery->havingQual != NULL)
2567  return gettext_noop("Views containing HAVING are not automatically updatable.");
2568 
2569  if (viewquery->setOperations != NULL)
2570  return gettext_noop("Views containing UNION, INTERSECT, or EXCEPT are not automatically updatable.");
2571 
2572  if (viewquery->cteList != NIL)
2573  return gettext_noop("Views containing WITH are not automatically updatable.");
2574 
2575  if (viewquery->limitOffset != NULL || viewquery->limitCount != NULL)
2576  return gettext_noop("Views containing LIMIT or OFFSET are not automatically updatable.");
2577 
2578  /*
2579  * We must not allow window functions or set returning functions in the
2580  * targetlist. Otherwise we might end up inserting them into the quals of
2581  * the main query. We must also check for aggregates in the targetlist in
2582  * case they appear without a GROUP BY.
2583  *
2584  * These restrictions ensure that each row of the view corresponds to a
2585  * unique row in the underlying base relation.
2586  */
2587  if (viewquery->hasAggs)
2588  return gettext_noop("Views that return aggregate functions are not automatically updatable.");
2589 
2590  if (viewquery->hasWindowFuncs)
2591  return gettext_noop("Views that return window functions are not automatically updatable.");
2592 
2593  if (viewquery->hasTargetSRFs)
2594  return gettext_noop("Views that return set-returning functions are not automatically updatable.");
2595 
2596  /*
2597  * The view query should select from a single base relation, which must be
2598  * a table or another view.
2599  */
2600  if (list_length(viewquery->jointree->fromlist) != 1)
2601  return gettext_noop("Views that do not se