PostgreSQL Source Code  git master
rewriteHandler.c File Reference
#include "postgres.h"
#include "access/relation.h"
#include "access/sysattr.h"
#include "access/table.h"
#include "catalog/dependency.h"
#include "catalog/pg_type.h"
#include "commands/trigger.h"
#include "foreign/fdwapi.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/optimizer.h"
#include "parser/analyze.h"
#include "parser/parse_coerce.h"
#include "parser/parse_relation.h"
#include "parser/parsetree.h"
#include "rewrite/rewriteDefine.h"
#include "rewrite/rewriteHandler.h"
#include "rewrite/rewriteManip.h"
#include "rewrite/rowsecurity.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
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, int result_rti, 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 rewriteTargetListUD (Query *parsetree, RangeTblEntry *target_rte, Relation target_relation)
 
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:579
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:1879

◆ 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(), 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:2313
#define IsA(nodeptr, _type_)
Definition: nodes.h:579
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
List * joinaliasvars
Definition: parsenodes.h:1056
Index varlevelsup
Definition: primnodes.h:191
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:528
AttrNumber varattno
Definition: primnodes.h:186
Form_pg_class rd_rel
Definition: rel.h:110
Definition: primnodes.h:181
#define QTW_IGNORE_RC_SUBQUERIES
Definition: nodeFuncs.h:22
List * rtable
Definition: parsenodes.h:137
#define ERROR
Definition: elog.h:45
#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:321
Index varno
Definition: primnodes.h:184
#define RowShareLock
Definition: lockdefs.h:37
bool get_rte_attribute_is_dropped(RangeTblEntry *rte, AttrNumber attnum)
unsigned int Index
Definition: c.h:537
#define Assert(condition)
Definition: c.h:792
#define lfirst(lc)
Definition: pg_list.h:169
RTEKind rtekind
Definition: parsenodes.h:981
List * cteList
Definition: parsenodes.h:135
Query * subquery
Definition: parsenodes.h:1016
bool hasSubLinks
Definition: parsenodes.h:128
#define elog(elevel,...)
Definition: elog.h:228
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: pg_list.h:50
Node * strip_implicit_coercions(Node *node)
Definition: nodeFuncs.c:651

◆ adjust_view_column_set()

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

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

3044 {
3045  Bitmapset *result = NULL;
3046  int col;
3047 
3048  col = -1;
3049  while ((col = bms_next_member(cols, col)) >= 0)
3050  {
3051  /* bit numbers are offset by FirstLowInvalidHeapAttributeNumber */
3053 
3054  if (attno == InvalidAttrNumber)
3055  {
3056  /*
3057  * There's a whole-row reference to the view. For permissions
3058  * purposes, treat it as a reference to each column available from
3059  * the view. (We should *not* convert this to a whole-row
3060  * reference to the base relation, since the view may not touch
3061  * all columns of the base relation.)
3062  */
3063  ListCell *lc;
3064 
3065  foreach(lc, targetlist)
3066  {
3067  TargetEntry *tle = lfirst_node(TargetEntry, lc);
3068  Var *var;
3069 
3070  if (tle->resjunk)
3071  continue;
3072  var = castNode(Var, tle->expr);
3073  result = bms_add_member(result,
3074  var->varattno - FirstLowInvalidHeapAttributeNumber);
3075  }
3076  }
3077  else
3078  {
3079  /*
3080  * Views do not have system columns, so we do not expect to see
3081  * any other system attnos here. If we do find one, the error
3082  * case will apply.
3083  */
3084  TargetEntry *tle = get_tle_by_resno(targetlist, attno);
3085 
3086  if (tle != NULL && !tle->resjunk && IsA(tle->expr, Var))
3087  {
3088  Var *var = (Var *) tle->expr;
3089 
3090  result = bms_add_member(result,
3091  var->varattno - FirstLowInvalidHeapAttributeNumber);
3092  }
3093  else
3094  elog(ERROR, "attribute number %d not found in view targetlist",
3095  attno);
3096  }
3097  }
3098 
3099  return result;
3100 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:579
#define castNode(_type_, nodeptr)
Definition: nodes.h:597
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1043
AttrNumber varattno
Definition: primnodes.h:186
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
Definition: primnodes.h:181
bool resjunk
Definition: primnodes.h:1438
#define ERROR
Definition: elog.h:45
#define lfirst_node(type, lc)
Definition: pg_list.h:172
Expr * expr
Definition: primnodes.h:1431
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:736
#define InvalidAttrNumber
Definition: attnum.h:23
#define elog(elevel,...)
Definition: elog.h:228
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:579
FromExpr * jointree
Definition: parsenodes.h:138
List * fromlist
Definition: primnodes.h:1534
#define foreach_delete_current(lst, cell)
Definition: pg_list.h:357
#define lfirst(lc)
Definition: pg_list.h:169
#define copyObject(obj)
Definition: nodes.h:644
Definition: pg_list.h:50

◆ ApplyRetrieveRule()

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

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

1806 {
1807  Query *rule_action;
1808  RangeTblEntry *rte,
1809  *subrte;
1810  RowMarkClause *rc;
1811 
1812  if (list_length(rule->actions) != 1)
1813  elog(ERROR, "expected just one rule action");
1814  if (rule->qual != NULL)
1815  elog(ERROR, "cannot handle qualified ON SELECT rule");
1816 
1817  if (rt_index == parsetree->resultRelation)
1818  {
1819  /*
1820  * We have a view as the result relation of the query, and it wasn't
1821  * rewritten by any rule. This case is supported if there is an
1822  * INSTEAD OF trigger that will trap attempts to insert/update/delete
1823  * view rows. The executor will check that; for the moment just plow
1824  * ahead. We have two cases:
1825  *
1826  * For INSERT, we needn't do anything. The unmodified RTE will serve
1827  * fine as the result relation.
1828  *
1829  * For UPDATE/DELETE, we need to expand the view so as to have source
1830  * data for the operation. But we also need an unmodified RTE to
1831  * serve as the target. So, copy the RTE and add the copy to the
1832  * rangetable. Note that the copy does not get added to the jointree.
1833  * Also note that there's a hack in fireRIRrules to avoid calling this
1834  * function again when it arrives at the copied RTE.
1835  */
1836  if (parsetree->commandType == CMD_INSERT)
1837  return parsetree;
1838  else if (parsetree->commandType == CMD_UPDATE ||
1839  parsetree->commandType == CMD_DELETE)
1840  {
1841  RangeTblEntry *newrte;
1842  Var *var;
1843  TargetEntry *tle;
1844 
1845  rte = rt_fetch(rt_index, parsetree->rtable);
1846  newrte = copyObject(rte);
1847  parsetree->rtable = lappend(parsetree->rtable, newrte);
1848  parsetree->resultRelation = list_length(parsetree->rtable);
1849 
1850  /*
1851  * There's no need to do permissions checks twice, so wipe out the
1852  * permissions info for the original RTE (we prefer to keep the
1853  * bits set on the result RTE).
1854  */
1855  rte->requiredPerms = 0;
1856  rte->checkAsUser = InvalidOid;
1857  rte->selectedCols = NULL;
1858  rte->insertedCols = NULL;
1859  rte->updatedCols = NULL;
1860  rte->extraUpdatedCols = NULL;
1861 
1862  /*
1863  * For the most part, Vars referencing the view should remain as
1864  * they are, meaning that they implicitly represent OLD values.
1865  * But in the RETURNING list if any, we want such Vars to
1866  * represent NEW values, so change them to reference the new RTE.
1867  *
1868  * Since ChangeVarNodes scribbles on the tree in-place, copy the
1869  * RETURNING list first for safety.
1870  */
1871  parsetree->returningList = copyObject(parsetree->returningList);
1872  ChangeVarNodes((Node *) parsetree->returningList, rt_index,
1873  parsetree->resultRelation, 0);
1874 
1875  /*
1876  * To allow the executor to compute the original view row to pass
1877  * to the INSTEAD OF trigger, we add a resjunk whole-row Var
1878  * referencing the original RTE. This will later get expanded
1879  * into a RowExpr computing all the OLD values of the view row.
1880  */
1881  var = makeWholeRowVar(rte, rt_index, 0, false);
1882  tle = makeTargetEntry((Expr *) var,
1883  list_length(parsetree->targetList) + 1,
1884  pstrdup("wholerow"),
1885  true);
1886 
1887  parsetree->targetList = lappend(parsetree->targetList, tle);
1888 
1889  /* Now, continue with expanding the original view RTE */
1890  }
1891  else
1892  elog(ERROR, "unrecognized commandType: %d",
1893  (int) parsetree->commandType);
1894  }
1895 
1896  /*
1897  * Check if there's a FOR [KEY] UPDATE/SHARE clause applying to this view.
1898  *
1899  * Note: we needn't explicitly consider any such clauses appearing in
1900  * ancestor query levels; their effects have already been pushed down to
1901  * here by markQueryForLocking, and will be reflected in "rc".
1902  */
1903  rc = get_parse_rowmark(parsetree, rt_index);
1904 
1905  /*
1906  * Make a modifiable copy of the view query, and acquire needed locks on
1907  * the relations it mentions. Force at least RowShareLock for all such
1908  * rels if there's a FOR [KEY] UPDATE/SHARE clause affecting this view.
1909  */
1910  rule_action = copyObject(linitial(rule->actions));
1911 
1912  AcquireRewriteLocks(rule_action, true, (rc != NULL));
1913 
1914  /*
1915  * If FOR [KEY] UPDATE/SHARE of view, mark all the contained tables as
1916  * implicit FOR [KEY] UPDATE/SHARE, the same as the parser would have done
1917  * if the view's subquery had been written out explicitly.
1918  */
1919  if (rc != NULL)
1920  markQueryForLocking(rule_action, (Node *) rule_action->jointree,
1921  rc->strength, rc->waitPolicy, true);
1922 
1923  /*
1924  * Recursively expand any view references inside the view.
1925  *
1926  * Note: this must happen after markQueryForLocking. That way, any UPDATE
1927  * permission bits needed for sub-views are initially applied to their
1928  * RTE_RELATION RTEs by markQueryForLocking, and then transferred to their
1929  * OLD rangetable entries by the action below (in a recursive call of this
1930  * routine).
1931  */
1932  rule_action = fireRIRrules(rule_action, activeRIRs);
1933 
1934  /*
1935  * Now, plug the view query in as a subselect, converting the relation's
1936  * original RTE to a subquery RTE.
1937  */
1938  rte = rt_fetch(rt_index, parsetree->rtable);
1939 
1940  rte->rtekind = RTE_SUBQUERY;
1941  rte->subquery = rule_action;
1942  rte->security_barrier = RelationIsSecurityView(relation);
1943  /* Clear fields that should not be set in a subquery RTE */
1944  rte->relid = InvalidOid;
1945  rte->relkind = 0;
1946  rte->rellockmode = 0;
1947  rte->tablesample = NULL;
1948  rte->inh = false; /* must not be set for a subquery */
1949 
1950  /*
1951  * We move the view's permission check data down to its rangetable. The
1952  * checks will actually be done against the OLD entry therein.
1953  */
1954  subrte = rt_fetch(PRS2_OLD_VARNO, rule_action->rtable);
1955  Assert(subrte->relid == relation->rd_id);
1956  subrte->requiredPerms = rte->requiredPerms;
1957  subrte->checkAsUser = rte->checkAsUser;
1958  subrte->selectedCols = rte->selectedCols;
1959  subrte->insertedCols = rte->insertedCols;
1960  subrte->updatedCols = rte->updatedCols;
1961  subrte->extraUpdatedCols = rte->extraUpdatedCols;
1962 
1963  rte->requiredPerms = 0; /* no permission check on subquery itself */
1964  rte->checkAsUser = InvalidOid;
1965  rte->selectedCols = NULL;
1966  rte->insertedCols = NULL;
1967  rte->updatedCols = NULL;
1968  rte->extraUpdatedCols = NULL;
1969 
1970  return parsetree;
1971 }
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:138
char * pstrdup(const char *in)
Definition: mcxt.c:1187
int resultRelation
Definition: parsenodes.h:122
Definition: nodes.h:528
Var * makeWholeRowVar(RangeTblEntry *rte, Index varno, Index varlevelsup, bool allowScalar)
Definition: makefuncs.c:133
AclMode requiredPerms
Definition: parsenodes.h:1124
Definition: primnodes.h:181
LockClauseStrength strength
Definition: parsenodes.h:1388
List * targetList
Definition: parsenodes.h:140
Bitmapset * extraUpdatedCols
Definition: parsenodes.h:1129
Bitmapset * selectedCols
Definition: parsenodes.h:1126
#define linitial(l)
Definition: pg_list.h:174
List * rtable
Definition: parsenodes.h:137
#define ERROR
Definition: elog.h:45
void AcquireRewriteLocks(Query *parsetree, bool forExecute, bool forUpdatePushedDown)
List * actions
Definition: prs2lock.h:29
List * returningList
Definition: parsenodes.h:146
#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:112
List * lappend(List *list, void *datum)
Definition: list.c:321
#define PRS2_OLD_VARNO
Definition: primnodes.h:178
bool security_barrier
Definition: parsenodes.h:1017
#define InvalidOid
Definition: postgres_ext.h:36
Bitmapset * updatedCols
Definition: parsenodes.h:1128
CmdType commandType
Definition: parsenodes.h:112
#define Assert(condition)
Definition: c.h:792
static int list_length(const List *l)
Definition: pg_list.h:149
LockWaitPolicy waitPolicy
Definition: parsenodes.h:1389
RTEKind rtekind
Definition: parsenodes.h:981
Query * subquery
Definition: parsenodes.h:1016
#define elog(elevel,...)
Definition: elog.h:228
Bitmapset * insertedCols
Definition: parsenodes.h:1127
#define RelationIsSecurityView(relation)
Definition: rel.h:388
void ChangeVarNodes(Node *node, int rt_index, int new_index, int sublevels_up)
Definition: rewriteManip.c:610
#define copyObject(obj)
Definition: nodes.h:644
static Query * fireRIRrules(Query *parsetree, List *activeRIRs)
struct TableSampleClause * tablesample
Definition: parsenodes.h:1011

◆ build_column_default()

Node* build_column_default ( Relation  rel,
int  attrno 
)

Definition at line 1217 of file rewriteHandler.c.

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

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

1218 {
1219  TupleDesc rd_att = rel->rd_att;
1220  Form_pg_attribute att_tup = TupleDescAttr(rd_att, attrno - 1);
1221  Oid atttype = att_tup->atttypid;
1222  int32 atttypmod = att_tup->atttypmod;
1223  Node *expr = NULL;
1224  Oid exprtype;
1225 
1226  if (att_tup->attidentity)
1227  {
1229 
1230  nve->seqid = getIdentitySequence(RelationGetRelid(rel), attrno, false);
1231  nve->typeId = att_tup->atttypid;
1232 
1233  return (Node *) nve;
1234  }
1235 
1236  /*
1237  * Scan to see if relation has a default for this column.
1238  */
1239  if (att_tup->atthasdef && rd_att->constr &&
1240  rd_att->constr->num_defval > 0)
1241  {
1242  AttrDefault *defval = rd_att->constr->defval;
1243  int ndef = rd_att->constr->num_defval;
1244 
1245  while (--ndef >= 0)
1246  {
1247  if (attrno == defval[ndef].adnum)
1248  {
1249  /*
1250  * Found it, convert string representation to node tree.
1251  */
1252  expr = stringToNode(defval[ndef].adbin);
1253  break;
1254  }
1255  }
1256  }
1257 
1258  /*
1259  * No per-column default, so look for a default for the type itself. But
1260  * not for generated columns.
1261  */
1262  if (expr == NULL && !att_tup->attgenerated)
1263  expr = get_typdefault(atttype);
1264 
1265  if (expr == NULL)
1266  return NULL; /* No default anywhere */
1267 
1268  /*
1269  * Make sure the value is coerced to the target column type; this will
1270  * generally be true already, but there seem to be some corner cases
1271  * involving domain defaults where it might not be true. This should match
1272  * the parser's processing of non-defaulted expressions --- see
1273  * transformAssignedExpr().
1274  */
1275  exprtype = exprType(expr);
1276 
1277  expr = coerce_to_target_type(NULL, /* no UNKNOWN params here */
1278  expr, exprtype,
1279  atttype, atttypmod,
1282  -1);
1283  if (expr == NULL)
1284  ereport(ERROR,
1285  (errcode(ERRCODE_DATATYPE_MISMATCH),
1286  errmsg("column \"%s\" is of type %s"
1287  " but default expression is of type %s",
1288  NameStr(att_tup->attname),
1289  format_type_be(atttype),
1290  format_type_be(exprtype)),
1291  errhint("You will need to rewrite or cast the expression.")));
1292 
1293  return expr;
1294 }
int errhint(const char *fmt,...)
Definition: elog.c:1162
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
Definition: nodes.h:528
int errcode(int sqlerrcode)
Definition: elog.c:704
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:954
signed int int32
Definition: c.h:417
AttrDefault * defval
Definition: tupdesc.h:39
#define ERROR
Definition: elog.h:45
Node * coerce_to_target_type(ParseState *pstate, Node *expr, Oid exprtype, Oid targettype, int32 targettypmod, CoercionContext ccontext, CoercionForm cformat, int location)
Definition: parse_coerce.c:78
TupleConstr * constr
Definition: tupdesc.h:85
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:193
TupleDesc rd_att
Definition: rel.h:111
#define ereport(elevel,...)
Definition: elog.h:155
#define makeNode(_type_)
Definition: nodes.h:576
Node * get_typdefault(Oid typid)
Definition: lsyscache.c:2368
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:41
uint16 num_defval
Definition: tupdesc.h:42
int errmsg(const char *fmt,...)
Definition: elog.c:915
#define NameStr(name)
Definition: c.h:669
#define RelationGetRelid(relation)
Definition: rel.h:457

◆ CopyAndAddInvertedQual()

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

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

2355 {
2356  /* Don't scribble on the passed qual (it's in the relcache!) */
2357  Node *new_qual = copyObject(rule_qual);
2359 
2360  context.for_execute = true;
2361 
2362  /*
2363  * In case there are subqueries in the qual, acquire necessary locks and
2364  * fix any deleted JOIN RTE entries. (This is somewhat redundant with
2365  * rewriteRuleAction, but not entirely ... consider restructuring so that
2366  * we only need to process the qual this way once.)
2367  */
2368  (void) acquireLocksOnSubLinks(new_qual, &context);
2369 
2370  /* Fix references to OLD */
2371  ChangeVarNodes(new_qual, PRS2_OLD_VARNO, rt_index, 0);
2372  /* Fix references to NEW */
2373  if (event == CMD_INSERT || event == CMD_UPDATE)
2374  new_qual = ReplaceVarsFromTargetList(new_qual,
2376  0,
2377  rt_fetch(rt_index,
2378  parsetree->rtable),
2379  parsetree->targetList,
2380  (event == CMD_UPDATE) ?
2383  rt_index,
2384  &parsetree->hasSubLinks);
2385  /* And attach the fixed qual */
2386  AddInvertedQual(parsetree, new_qual);
2387 
2388  return parsetree;
2389 }
static bool acquireLocksOnSubLinks(Node *node, acquireLocksOnSubLinks_context *context)
void AddInvertedQual(Query *parsetree, Node *qual)
Definition: nodes.h:528
List * targetList
Definition: parsenodes.h:140
List * rtable
Definition: parsenodes.h:137
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
#define PRS2_OLD_VARNO
Definition: primnodes.h:178
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:128
void ChangeVarNodes(Node *node, int rt_index, int new_index, int sublevels_up)
Definition: rewriteManip.c:610
#define copyObject(obj)
Definition: nodes.h:644
#define PRS2_NEW_VARNO
Definition: primnodes.h:179

◆ fill_extraUpdatedCols()

void fill_extraUpdatedCols ( RangeTblEntry target_rte,
Relation  target_relation 
)

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

1699 {
1700  TupleDesc tupdesc = RelationGetDescr(target_relation);
1701  TupleConstr *constr = tupdesc->constr;
1702 
1703  target_rte->extraUpdatedCols = NULL;
1704 
1705  if (constr && constr->has_generated_stored)
1706  {
1707  for (int i = 0; i < constr->num_defval; i++)
1708  {
1709  AttrDefault *defval = &constr->defval[i];
1710  Node *expr;
1711  Bitmapset *attrs_used = NULL;
1712 
1713  /* skip if not generated column */
1714  if (!TupleDescAttr(tupdesc, defval->adnum - 1)->attgenerated)
1715  continue;
1716 
1717  /* identify columns this generated column depends on */
1718  expr = stringToNode(defval->adbin);
1719  pull_varattnos(expr, 1, &attrs_used);
1720 
1721  if (bms_overlap(target_rte->updatedCols, attrs_used))
1722  target_rte->extraUpdatedCols =
1723  bms_add_member(target_rte->extraUpdatedCols,
1725  }
1726  }
1727 }
#define RelationGetDescr(relation)
Definition: rel.h:483
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
Definition: nodes.h:528
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:219
AttrDefault * defval
Definition: tupdesc.h:39
bool has_generated_stored
Definition: tupdesc.h:45
Bitmapset * extraUpdatedCols
Definition: parsenodes.h:1129
TupleConstr * constr
Definition: tupdesc.h:85
Bitmapset * updatedCols
Definition: parsenodes.h:1128
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 1325 of file rewriteHandler.c.

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

Referenced by rewriteTargetListIU().

1326 {
1327  Bitmapset *default_only_cols = NULL;
1328  ListCell *lc;
1329 
1330  foreach(lc, rte->values_lists)
1331  {
1332  List *sublist = (List *) lfirst(lc);
1333  ListCell *lc2;
1334  int i;
1335 
1336  if (default_only_cols == NULL)
1337  {
1338  /* Populate the initial result bitmap from the first row */
1339  i = 0;
1340  foreach(lc2, sublist)
1341  {
1342  Node *col = (Node *) lfirst(lc2);
1343 
1344  i++;
1345  if (IsA(col, SetToDefault))
1346  default_only_cols = bms_add_member(default_only_cols, i);
1347  }
1348  }
1349  else
1350  {
1351  /* Update the result bitmap from this next row */
1352  i = 0;
1353  foreach(lc2, sublist)
1354  {
1355  Node *col = (Node *) lfirst(lc2);
1356 
1357  i++;
1358  if (!IsA(col, SetToDefault))
1359  default_only_cols = bms_del_member(default_only_cols, i);
1360  }
1361  }
1362 
1363  /*
1364  * If no column in the rows read so far contains only DEFAULT items,
1365  * we are done.
1366  */
1367  if (bms_is_empty(default_only_cols))
1368  break;
1369  }
1370 
1371  return default_only_cols;
1372 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:579
Definition: nodes.h:528
List * values_lists
Definition: parsenodes.h:1079
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 2045 of file rewriteHandler.c.

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

Referenced by fireRIRrules().

2046 {
2047  if (node == NULL)
2048  return false;
2049  if (IsA(node, SubLink))
2050  {
2051  SubLink *sub = (SubLink *) node;
2052 
2053  /* Do what we came for */
2054  sub->subselect = (Node *) fireRIRrules((Query *) sub->subselect,
2055  activeRIRs);
2056  /* Fall through to process lefthand args of SubLink */
2057  }
2058 
2059  /*
2060  * Do NOT recurse into Query nodes, because fireRIRrules already processed
2061  * subselects of subselects for us.
2062  */
2064  (void *) activeRIRs);
2065 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:579
Definition: nodes.h:528
static bool fireRIRonSubLink(Node *node, List *activeRIRs)
bool expression_tree_walker(Node *node, bool(*walker)(), void *context)
Definition: nodeFuncs.c:1879
static Query * fireRIRrules(Query *parsetree, List *activeRIRs)

◆ fireRIRrules()

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

Definition at line 2076 of file rewriteHandler.c.

References acquireLocksOnSubLinks(), ApplyRetrieveRule(), CMD_SELECT, Query::cteList, CommonTableExpr::ctequery, 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, 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, rt_fetch, Query::rtable, RTE_RELATION, RTE_SUBQUERY, RangeTblEntry::rtekind, RuleLock::rules, rules, RangeTblEntry::securityQuals, RangeTblEntry::subquery, table_close(), table_open(), and Query::withCheckOptions.

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

2077 {
2078  int origResultRelation = parsetree->resultRelation;
2079  int rt_index;
2080  ListCell *lc;
2081 
2082  /*
2083  * don't try to convert this into a foreach loop, because rtable list can
2084  * get changed each time through...
2085  */
2086  rt_index = 0;
2087  while (rt_index < list_length(parsetree->rtable))
2088  {
2089  RangeTblEntry *rte;
2090  Relation rel;
2091  List *locks;
2092  RuleLock *rules;
2093  RewriteRule *rule;
2094  int i;
2095 
2096  ++rt_index;
2097 
2098  rte = rt_fetch(rt_index, parsetree->rtable);
2099 
2100  /*
2101  * A subquery RTE can't have associated rules, so there's nothing to
2102  * do to this level of the query, but we must recurse into the
2103  * subquery to expand any rule references in it.
2104  */
2105  if (rte->rtekind == RTE_SUBQUERY)
2106  {
2107  rte->subquery = fireRIRrules(rte->subquery, activeRIRs);
2108  continue;
2109  }
2110 
2111  /*
2112  * Joins and other non-relation RTEs can be ignored completely.
2113  */
2114  if (rte->rtekind != RTE_RELATION)
2115  continue;
2116 
2117  /*
2118  * Always ignore RIR rules for materialized views referenced in
2119  * queries. (This does not prevent refreshing MVs, since they aren't
2120  * referenced in their own query definitions.)
2121  *
2122  * Note: in the future we might want to allow MVs to be conditionally
2123  * expanded as if they were regular views, if they are not scannable.
2124  * In that case this test would need to be postponed till after we've
2125  * opened the rel, so that we could check its state.
2126  */
2127  if (rte->relkind == RELKIND_MATVIEW)
2128  continue;
2129 
2130  /*
2131  * In INSERT ... ON CONFLICT, ignore the EXCLUDED pseudo-relation;
2132  * even if it points to a view, we needn't expand it, and should not
2133  * because we want the RTE to remain of RTE_RELATION type. Otherwise,
2134  * it would get changed to RTE_SUBQUERY type, which is an
2135  * untested/unsupported situation.
2136  */
2137  if (parsetree->onConflict &&
2138  rt_index == parsetree->onConflict->exclRelIndex)
2139  continue;
2140 
2141  /*
2142  * If the table is not referenced in the query, then we ignore it.
2143  * This prevents infinite expansion loop due to new rtable entries
2144  * inserted by expansion of a rule. A table is referenced if it is
2145  * part of the join set (a source table), or is referenced by any Var
2146  * nodes, or is the result table.
2147  */
2148  if (rt_index != parsetree->resultRelation &&
2149  !rangeTableEntry_used((Node *) parsetree, rt_index, 0))
2150  continue;
2151 
2152  /*
2153  * Also, if this is a new result relation introduced by
2154  * ApplyRetrieveRule, we don't want to do anything more with it.
2155  */
2156  if (rt_index == parsetree->resultRelation &&
2157  rt_index != origResultRelation)
2158  continue;
2159 
2160  /*
2161  * We can use NoLock here since either the parser or
2162  * AcquireRewriteLocks should have locked the rel already.
2163  */
2164  rel = table_open(rte->relid, NoLock);
2165 
2166  /*
2167  * Collect the RIR rules that we must apply
2168  */
2169  rules = rel->rd_rules;
2170  if (rules != NULL)
2171  {
2172  locks = NIL;
2173  for (i = 0; i < rules->numLocks; i++)
2174  {
2175  rule = rules->rules[i];
2176  if (rule->event != CMD_SELECT)
2177  continue;
2178 
2179  locks = lappend(locks, rule);
2180  }
2181 
2182  /*
2183  * If we found any, apply them --- but first check for recursion!
2184  */
2185  if (locks != NIL)
2186  {
2187  ListCell *l;
2188 
2189  if (list_member_oid(activeRIRs, RelationGetRelid(rel)))
2190  ereport(ERROR,
2191  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2192  errmsg("infinite recursion detected in rules for relation \"%s\"",
2193  RelationGetRelationName(rel))));
2194  activeRIRs = lappend_oid(activeRIRs, RelationGetRelid(rel));
2195 
2196  foreach(l, locks)
2197  {
2198  rule = lfirst(l);
2199 
2200  parsetree = ApplyRetrieveRule(parsetree,
2201  rule,
2202  rt_index,
2203  rel,
2204  activeRIRs);
2205  }
2206 
2207  activeRIRs = list_delete_last(activeRIRs);
2208  }
2209  }
2210 
2211  table_close(rel, NoLock);
2212  }
2213 
2214  /* Recurse into subqueries in WITH */
2215  foreach(lc, parsetree->cteList)
2216  {
2217  CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
2218 
2219  cte->ctequery = (Node *)
2220  fireRIRrules((Query *) cte->ctequery, activeRIRs);
2221  }
2222 
2223  /*
2224  * Recurse into sublink subqueries, too. But we already did the ones in
2225  * the rtable and cteList.
2226  */
2227  if (parsetree->hasSubLinks)
2228  query_tree_walker(parsetree, fireRIRonSubLink, (void *) activeRIRs,
2230 
2231  /*
2232  * Apply any row level security policies. We do this last because it
2233  * requires special recursion detection if the new quals have sublink
2234  * subqueries, and if we did it in the loop above query_tree_walker would
2235  * then recurse into those quals a second time.
2236  */
2237  rt_index = 0;
2238  foreach(lc, parsetree->rtable)
2239  {
2240  RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
2241  Relation rel;
2242  List *securityQuals;
2243  List *withCheckOptions;
2244  bool hasRowSecurity;
2245  bool hasSubLinks;
2246 
2247  ++rt_index;
2248 
2249  /* Only normal relations can have RLS policies */
2250  if (rte->rtekind != RTE_RELATION ||
2251  (rte->relkind != RELKIND_RELATION &&
2252  rte->relkind != RELKIND_PARTITIONED_TABLE))
2253  continue;
2254 
2255  rel = table_open(rte->relid, NoLock);
2256 
2257  /*
2258  * Fetch any new security quals that must be applied to this RTE.
2259  */
2260  get_row_security_policies(parsetree, rte, rt_index,
2261  &securityQuals, &withCheckOptions,
2262  &hasRowSecurity, &hasSubLinks);
2263 
2264  if (securityQuals != NIL || withCheckOptions != NIL)
2265  {
2266  if (hasSubLinks)
2267  {
2269 
2270  /*
2271  * Recursively process the new quals, checking for infinite
2272  * recursion.
2273  */
2274  if (list_member_oid(activeRIRs, RelationGetRelid(rel)))
2275  ereport(ERROR,
2276  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2277  errmsg("infinite recursion detected in policy for relation \"%s\"",
2278  RelationGetRelationName(rel))));
2279 
2280  activeRIRs = lappend_oid(activeRIRs, RelationGetRelid(rel));
2281 
2282  /*
2283  * get_row_security_policies just passed back securityQuals
2284  * and/or withCheckOptions, and there were SubLinks, make sure
2285  * we lock any relations which are referenced.
2286  *
2287  * These locks would normally be acquired by the parser, but
2288  * securityQuals and withCheckOptions are added post-parsing.
2289  */
2290  context.for_execute = true;
2291  (void) acquireLocksOnSubLinks((Node *) securityQuals, &context);
2292  (void) acquireLocksOnSubLinks((Node *) withCheckOptions,
2293  &context);
2294 
2295  /*
2296  * Now that we have the locks on anything added by
2297  * get_row_security_policies, fire any RIR rules for them.
2298  */
2299  expression_tree_walker((Node *) securityQuals,
2300  fireRIRonSubLink, (void *) activeRIRs);
2301 
2302  expression_tree_walker((Node *) withCheckOptions,
2303  fireRIRonSubLink, (void *) activeRIRs);
2304 
2305  activeRIRs = list_delete_last(activeRIRs);
2306  }
2307 
2308  /*
2309  * Add the new security barrier quals to the start of the RTE's
2310  * list so that they get applied before any existing barrier quals
2311  * (which would have come from a security-barrier view, and should
2312  * get lower priority than RLS conditions on the table itself).
2313  */
2314  rte->securityQuals = list_concat(securityQuals,
2315  rte->securityQuals);
2316 
2317  parsetree->withCheckOptions = list_concat(withCheckOptions,
2318  parsetree->withCheckOptions);
2319  }
2320 
2321  /*
2322  * Make sure the query is marked correctly if row level security
2323  * applies, or if the new quals had sublinks.
2324  */
2325  if (hasRowSecurity)
2326  parsetree->hasRowSecurity = true;
2327  if (hasSubLinks)
2328  parsetree->hasSubLinks = true;
2329 
2330  table_close(rel, NoLock);
2331  }
2332 
2333  return parsetree;
2334 }
#define NIL
Definition: pg_list.h:65
bool query_tree_walker(Query *query, bool(*walker)(), void *context, int flags)
Definition: nodeFuncs.c:2313
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
int numLocks
Definition: prs2lock.h:42
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:144
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:1130
int resultRelation
Definition: parsenodes.h:122
Definition: nodes.h:528
List * list_concat(List *list1, const List *list2)
Definition: list.c:515
int errcode(int sqlerrcode)
Definition: elog.c:704
List * lappend_oid(List *list, Oid datum)
Definition: list.c:357
Definition: localtime.c:72
#define QTW_IGNORE_RC_SUBQUERIES
Definition: nodeFuncs.h:22
List * rtable
Definition: parsenodes.h:137
#define ERROR
Definition: elog.h:45
static bool fireRIRonSubLink(Node *node, List *activeRIRs)
#define NoLock
Definition: lockdefs.h:34
CmdType event
Definition: prs2lock.h:27
List * list_delete_last(List *list)
Definition: list.c:877
static struct rule * rules
Definition: zic.c:281
#define RelationGetRelationName(relation)
Definition: rel.h:491
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:321
#define ereport(elevel,...)
Definition: elog.h:155
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:674
#define lfirst(lc)
Definition: pg_list.h:169
RuleLock * rd_rules
Definition: rel.h:114
bool expression_tree_walker(Node *node, bool(*walker)(), void *context)
Definition: nodeFuncs.c:1879
static int list_length(const List *l)
Definition: pg_list.h:149
RTEKind rtekind
Definition: parsenodes.h:981
Query * subquery
Definition: parsenodes.h:1016
int errmsg(const char *fmt,...)
Definition: elog.c:915
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:457

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

2428 {
2429  List *results = NIL;
2430  ListCell *l;
2431 
2432  foreach(l, locks)
2433  {
2434  RewriteRule *rule_lock = (RewriteRule *) lfirst(l);
2435  Node *event_qual = rule_lock->qual;
2436  List *actions = rule_lock->actions;
2437  QuerySource qsrc;
2438  ListCell *r;
2439 
2440  /* Determine correct QuerySource value for actions */
2441  if (rule_lock->isInstead)
2442  {
2443  if (event_qual != NULL)
2444  qsrc = QSRC_QUAL_INSTEAD_RULE;
2445  else
2446  {
2447  qsrc = QSRC_INSTEAD_RULE;
2448  *instead_flag = true; /* report unqualified INSTEAD */
2449  }
2450  }
2451  else
2452  qsrc = QSRC_NON_INSTEAD_RULE;
2453 
2454  if (qsrc == QSRC_QUAL_INSTEAD_RULE)
2455  {
2456  /*
2457  * If there are INSTEAD rules with qualifications, the original
2458  * query is still performed. But all the negated rule
2459  * qualifications of the INSTEAD rules are added so it does its
2460  * actions only in cases where the rule quals of all INSTEAD rules
2461  * are false. Think of it as the default action in a case. We save
2462  * this in *qual_product so RewriteQuery() can add it to the query
2463  * list after we mangled it up enough.
2464  *
2465  * If we have already found an unqualified INSTEAD rule, then
2466  * *qual_product won't be used, so don't bother building it.
2467  */
2468  if (!*instead_flag)
2469  {
2470  if (*qual_product == NULL)
2471  *qual_product = copyObject(parsetree);
2472  *qual_product = CopyAndAddInvertedQual(*qual_product,
2473  event_qual,
2474  rt_index,
2475  event);
2476  }
2477  }
2478 
2479  /* Now process the rule's actions and add them to the result list */
2480  foreach(r, actions)
2481  {
2482  Query *rule_action = lfirst(r);
2483 
2484  if (rule_action->commandType == CMD_NOTHING)
2485  continue;
2486 
2487  rule_action = rewriteRuleAction(parsetree, rule_action,
2488  event_qual, rt_index, event,
2489  returning_flag);
2490 
2491  rule_action->querySource = qsrc;
2492  rule_action->canSetTag = false; /* might change later */
2493 
2494  results = lappend(results, rule_action);
2495  }
2496  }
2497 
2498  return results;
2499 }
#define NIL
Definition: pg_list.h:65
Node * qual
Definition: prs2lock.h:28
QuerySource
Definition: parsenodes.h:40
Definition: nodes.h:528
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:321
CmdType commandType
Definition: parsenodes.h:112
QuerySource querySource
Definition: parsenodes.h:114
#define lfirst(lc)
Definition: pg_list.h:169
bool canSetTag
Definition: parsenodes.h:118
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:644
Definition: pg_list.h:50

◆ get_assignment_input()

static Node * get_assignment_input ( Node node)
static

Definition at line 1188 of file rewriteHandler.c.

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

Referenced by process_matched_tle().

1189 {
1190  if (node == NULL)
1191  return NULL;
1192  if (IsA(node, FieldStore))
1193  {
1194  FieldStore *fstore = (FieldStore *) node;
1195 
1196  return (Node *) fstore->arg;
1197  }
1198  else if (IsA(node, SubscriptingRef))
1199  {
1200  SubscriptingRef *sbsref = (SubscriptingRef *) node;
1201 
1202  if (sbsref->refassgnexpr == NULL)
1203  return NULL;
1204 
1205  return (Node *) sbsref->refexpr;
1206  }
1207 
1208  return NULL;
1209 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:579
Expr * arg
Definition: primnodes.h:815
Definition: nodes.h:528
Expr * refassgnexpr
Definition: primnodes.h:446
Expr * refexpr
Definition: primnodes.h:444

◆ get_view_query()

Query* get_view_query ( Relation  view)

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

2513 {
2514  int i;
2515 
2516  Assert(view->rd_rel->relkind == RELKIND_VIEW);
2517 
2518  for (i = 0; i < view->rd_rules->numLocks; i++)
2519  {
2520  RewriteRule *rule = view->rd_rules->rules[i];
2521 
2522  if (rule->event == CMD_SELECT)
2523  {
2524  /* A _RETURN rule should have only one action */
2525  if (list_length(rule->actions) != 1)
2526  elog(ERROR, "invalid _RETURN rule action specification");
2527 
2528  return (Query *) linitial(rule->actions);
2529  }
2530  }
2531 
2532  elog(ERROR, "failed to find _RETURN rule for view");
2533  return NULL; /* keep compiler quiet */
2534 }
int numLocks
Definition: prs2lock.h:42
Form_pg_class rd_rel
Definition: rel.h:110
Definition: localtime.c:72
#define linitial(l)
Definition: pg_list.h:174
#define ERROR
Definition: elog.h:45
CmdType event
Definition: prs2lock.h:27
RewriteRule ** rules
Definition: prs2lock.h:43
List * actions
Definition: prs2lock.h:29
#define Assert(condition)
Definition: c.h:792
RuleLock * rd_rules
Definition: rel.h:114
static int list_length(const List *l)
Definition: pg_list.h:149
#define elog(elevel,...)
Definition: elog.h:228
int i

◆ markQueryForLocking()

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

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

1988 {
1989  if (jtnode == NULL)
1990  return;
1991  if (IsA(jtnode, RangeTblRef))
1992  {
1993  int rti = ((RangeTblRef *) jtnode)->rtindex;
1994  RangeTblEntry *rte = rt_fetch(rti, qry->rtable);
1995 
1996  if (rte->rtekind == RTE_RELATION)
1997  {
1998  applyLockingClause(qry, rti, strength, waitPolicy, pushedDown);
2000  }
2001  else if (rte->rtekind == RTE_SUBQUERY)
2002  {
2003  applyLockingClause(qry, rti, strength, waitPolicy, pushedDown);
2004  /* FOR UPDATE/SHARE of subquery is propagated to subquery's rels */
2006  strength, waitPolicy, true);
2007  }
2008  /* other RTE types are unaffected by FOR UPDATE */
2009  }
2010  else if (IsA(jtnode, FromExpr))
2011  {
2012  FromExpr *f = (FromExpr *) jtnode;
2013  ListCell *l;
2014 
2015  foreach(l, f->fromlist)
2016  markQueryForLocking(qry, lfirst(l), strength, waitPolicy, pushedDown);
2017  }
2018  else if (IsA(jtnode, JoinExpr))
2019  {
2020  JoinExpr *j = (JoinExpr *) jtnode;
2021 
2022  markQueryForLocking(qry, j->larg, strength, waitPolicy, pushedDown);
2023  markQueryForLocking(qry, j->rarg, strength, waitPolicy, pushedDown);
2024  }
2025  else
2026  elog(ERROR, "unrecognized node type: %d",
2027  (int) nodeTag(jtnode));
2028 }
static void markQueryForLocking(Query *qry, Node *jtnode, LockClauseStrength strength, LockWaitPolicy waitPolicy, bool pushedDown)
#define IsA(nodeptr, _type_)
Definition: nodes.h:579
FromExpr * jointree
Definition: parsenodes.h:138
Definition: nodes.h:528
AclMode requiredPerms
Definition: parsenodes.h:1124
List * fromlist
Definition: primnodes.h:1534
Node * larg
Definition: primnodes.h:1514
List * rtable
Definition: parsenodes.h:137
#define ERROR
Definition: elog.h:45
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
Node * rarg
Definition: primnodes.h:1515
#define lfirst(lc)
Definition: pg_list.h:169
#define ACL_SELECT_FOR_UPDATE
Definition: parsenodes.h:90
#define nodeTag(nodeptr)
Definition: nodes.h:533
RTEKind rtekind
Definition: parsenodes.h:981
Query * subquery
Definition: parsenodes.h:1016
#define elog(elevel,...)
Definition: elog.h:228
void applyLockingClause(Query *qry, Index rtindex, LockClauseStrength strength, LockWaitPolicy waitPolicy, bool pushedDown)
Definition: analyze.c:3136

◆ matchLocks()

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

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

1740 {
1741  List *matching_locks = NIL;
1742  int nlocks;
1743  int i;
1744 
1745  if (rulelocks == NULL)
1746  return NIL;
1747 
1748  if (parsetree->commandType != CMD_SELECT)
1749  {
1750  if (parsetree->resultRelation != varno)
1751  return NIL;
1752  }
1753 
1754  nlocks = rulelocks->numLocks;
1755 
1756  for (i = 0; i < nlocks; i++)
1757  {
1758  RewriteRule *oneLock = rulelocks->rules[i];
1759 
1760  if (oneLock->event == CMD_UPDATE)
1761  *hasUpdate = true;
1762 
1763  /*
1764  * Suppress ON INSERT/UPDATE/DELETE rules that are disabled or
1765  * configured to not fire during the current sessions replication
1766  * role. ON SELECT rules will always be applied in order to keep views
1767  * working even in LOCAL or REPLICA role.
1768  */
1769  if (oneLock->event != CMD_SELECT)
1770  {
1772  {
1773  if (oneLock->enabled == RULE_FIRES_ON_ORIGIN ||
1774  oneLock->enabled == RULE_DISABLED)
1775  continue;
1776  }
1777  else /* ORIGIN or LOCAL ROLE */
1778  {
1779  if (oneLock->enabled == RULE_FIRES_ON_REPLICA ||
1780  oneLock->enabled == RULE_DISABLED)
1781  continue;
1782  }
1783  }
1784 
1785  if (oneLock->event == event)
1786  {
1787  if (parsetree->commandType != CMD_SELECT ||
1788  rangeTableEntry_used((Node *) parsetree, varno, 0))
1789  matching_locks = lappend(matching_locks, oneLock);
1790  }
1791  }
1792 
1793  return matching_locks;
1794 }
#define NIL
Definition: pg_list.h:65
int numLocks
Definition: prs2lock.h:42
int resultRelation
Definition: parsenodes.h:122
Definition: nodes.h:528
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:321
#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:112
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 1035 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().

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

◆ QueryRewrite()

List* QueryRewrite ( Query parsetree)

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

4156 {
4157  uint64 input_query_id = parsetree->queryId;
4158  List *querylist;
4159  List *results;
4160  ListCell *l;
4161  CmdType origCmdType;
4162  bool foundOriginalQuery;
4163  Query *lastInstead;
4164 
4165  /*
4166  * This function is only applied to top-level original queries
4167  */
4168  Assert(parsetree->querySource == QSRC_ORIGINAL);
4169  Assert(parsetree->canSetTag);
4170 
4171  /*
4172  * Step 1
4173  *
4174  * Apply all non-SELECT rules possibly getting 0 or many queries
4175  */
4176  querylist = RewriteQuery(parsetree, NIL);
4177 
4178  /*
4179  * Step 2
4180  *
4181  * Apply all the RIR rules on each query
4182  *
4183  * This is also a handy place to mark each query with the original queryId
4184  */
4185  results = NIL;
4186  foreach(l, querylist)
4187  {
4188  Query *query = (Query *) lfirst(l);
4189 
4190  query = fireRIRrules(query, NIL);
4191 
4192  query->queryId = input_query_id;
4193 
4194  results = lappend(results, query);
4195  }
4196 
4197  /*
4198  * Step 3
4199  *
4200  * Determine which, if any, of the resulting queries is supposed to set
4201  * the command-result tag; and update the canSetTag fields accordingly.
4202  *
4203  * If the original query is still in the list, it sets the command tag.
4204  * Otherwise, the last INSTEAD query of the same kind as the original is
4205  * allowed to set the tag. (Note these rules can leave us with no query
4206  * setting the tag. The tcop code has to cope with this by setting up a
4207  * default tag based on the original un-rewritten query.)
4208  *
4209  * The Asserts verify that at most one query in the result list is marked
4210  * canSetTag. If we aren't checking asserts, we can fall out of the loop
4211  * as soon as we find the original query.
4212  */
4213  origCmdType = parsetree->commandType;
4214  foundOriginalQuery = false;
4215  lastInstead = NULL;
4216 
4217  foreach(l, results)
4218  {
4219  Query *query = (Query *) lfirst(l);
4220 
4221  if (query->querySource == QSRC_ORIGINAL)
4222  {
4223  Assert(query->canSetTag);
4224  Assert(!foundOriginalQuery);
4225  foundOriginalQuery = true;
4226 #ifndef USE_ASSERT_CHECKING
4227  break;
4228 #endif
4229  }
4230  else
4231  {
4232  Assert(!query->canSetTag);
4233  if (query->commandType == origCmdType &&
4234  (query->querySource == QSRC_INSTEAD_RULE ||
4236  lastInstead = query;
4237  }
4238  }
4239 
4240  if (!foundOriginalQuery && lastInstead != NULL)
4241  lastInstead->canSetTag = true;
4242 
4243  return results;
4244 }
#define NIL
Definition: pg_list.h:65
static List * RewriteQuery(Query *parsetree, List *rewrite_events)
List * lappend(List *list, void *datum)
Definition: list.c:321
uint64 queryId
Definition: parsenodes.h:116
CmdType commandType
Definition: parsenodes.h:112
QuerySource querySource
Definition: parsenodes.h:114
#define Assert(condition)
Definition: c.h:792
#define lfirst(lc)
Definition: pg_list.h:169
bool canSetTag
Definition: parsenodes.h:118
static Query * fireRIRrules(Query *parsetree, List *activeRIRs)
Definition: pg_list.h:50
CmdType
Definition: nodes.h:671

◆ relation_is_updatable()

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

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

2866 {
2867  int events = 0;
2868  Relation rel;
2869  RuleLock *rulelocks;
2870 
2871 #define ALL_EVENTS ((1 << CMD_INSERT) | (1 << CMD_UPDATE) | (1 << CMD_DELETE))
2872 
2873  /* Since this function recurses, it could be driven to stack overflow */
2875 
2876  rel = try_relation_open(reloid, AccessShareLock);
2877 
2878  /*
2879  * If the relation doesn't exist, return zero rather than throwing an
2880  * error. This is helpful since scanning an information_schema view under
2881  * MVCC rules can result in referencing rels that have actually been
2882  * deleted already.
2883  */
2884  if (rel == NULL)
2885  return 0;
2886 
2887  /* If we detect a recursive view, report that it is not updatable */
2888  if (list_member_oid(outer_reloids, RelationGetRelid(rel)))
2889  {
2891  return 0;
2892  }
2893 
2894  /* If the relation is a table, it is always updatable */
2895  if (rel->rd_rel->relkind == RELKIND_RELATION ||
2896  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
2897  {
2899  return ALL_EVENTS;
2900  }
2901 
2902  /* Look for unconditional DO INSTEAD rules, and note supported events */
2903  rulelocks = rel->rd_rules;
2904  if (rulelocks != NULL)
2905  {
2906  int i;
2907 
2908  for (i = 0; i < rulelocks->numLocks; i++)
2909  {
2910  if (rulelocks->rules[i]->isInstead &&
2911  rulelocks->rules[i]->qual == NULL)
2912  {
2913  events |= ((1 << rulelocks->rules[i]->event) & ALL_EVENTS);
2914  }
2915  }
2916 
2917  /* If we have rules for all events, we're done */
2918  if (events == ALL_EVENTS)
2919  {
2921  return events;
2922  }
2923  }
2924 
2925  /* Similarly look for INSTEAD OF triggers, if they are to be included */
2926  if (include_triggers)
2927  {
2928  TriggerDesc *trigDesc = rel->trigdesc;
2929 
2930  if (trigDesc)
2931  {
2932  if (trigDesc->trig_insert_instead_row)
2933  events |= (1 << CMD_INSERT);
2934  if (trigDesc->trig_update_instead_row)
2935  events |= (1 << CMD_UPDATE);
2936  if (trigDesc->trig_delete_instead_row)
2937  events |= (1 << CMD_DELETE);
2938 
2939  /* If we have triggers for all events, we're done */
2940  if (events == ALL_EVENTS)
2941  {
2943  return events;
2944  }
2945  }
2946  }
2947 
2948  /* If this is a foreign table, check which update events it supports */
2949  if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
2950  {
2951  FdwRoutine *fdwroutine = GetFdwRoutineForRelation(rel, false);
2952 
2953  if (fdwroutine->IsForeignRelUpdatable != NULL)
2954  events |= fdwroutine->IsForeignRelUpdatable(rel);
2955  else
2956  {
2957  /* Assume presence of executor functions is sufficient */
2958  if (fdwroutine->ExecForeignInsert != NULL)
2959  events |= (1 << CMD_INSERT);
2960  if (fdwroutine->ExecForeignUpdate != NULL)
2961  events |= (1 << CMD_UPDATE);
2962  if (fdwroutine->ExecForeignDelete != NULL)
2963  events |= (1 << CMD_DELETE);
2964  }
2965 
2967  return events;
2968  }
2969 
2970  /* Check if this is an automatically updatable view */
2971  if (rel->rd_rel->relkind == RELKIND_VIEW)
2972  {
2973  Query *viewquery = get_view_query(rel);
2974 
2975  if (view_query_is_auto_updatable(viewquery, false) == NULL)
2976  {
2977  Bitmapset *updatable_cols;
2978  int auto_events;
2979  RangeTblRef *rtr;
2980  RangeTblEntry *base_rte;
2981  Oid baseoid;
2982 
2983  /*
2984  * Determine which of the view's columns are updatable. If there
2985  * are none within the set of columns we are looking at, then the
2986  * view doesn't support INSERT/UPDATE, but it may still support
2987  * DELETE.
2988  */
2989  view_cols_are_auto_updatable(viewquery, NULL,
2990  &updatable_cols, NULL);
2991 
2992  if (include_cols != NULL)
2993  updatable_cols = bms_int_members(updatable_cols, include_cols);
2994 
2995  if (bms_is_empty(updatable_cols))
2996  auto_events = (1 << CMD_DELETE); /* May support DELETE */
2997  else
2998  auto_events = ALL_EVENTS; /* May support all events */
2999 
3000  /*
3001  * The base relation must also support these update commands.
3002  * Tables are always updatable, but for any other kind of base
3003  * relation we must do a recursive check limited to the columns
3004  * referenced by the locally updatable columns in this view.
3005  */
3006  rtr = (RangeTblRef *) linitial(viewquery->jointree->fromlist);
3007  base_rte = rt_fetch(rtr->rtindex, viewquery->rtable);
3008  Assert(base_rte->rtekind == RTE_RELATION);
3009 
3010  if (base_rte->relkind != RELKIND_RELATION &&
3011  base_rte->relkind != RELKIND_PARTITIONED_TABLE)
3012  {
3013  baseoid = base_rte->relid;
3014  outer_reloids = lappend_oid(outer_reloids,
3015  RelationGetRelid(rel));
3016  include_cols = adjust_view_column_set(updatable_cols,
3017  viewquery->targetList);
3018  auto_events &= relation_is_updatable(baseoid,
3019  outer_reloids,
3020  include_triggers,
3021  include_cols);
3022  outer_reloids = list_delete_last(outer_reloids);
3023  }
3024  events |= auto_events;
3025  }
3026  }
3027 
3028  /* If we reach here, the relation may support some update commands */
3030  return events;
3031 }
ExecForeignDelete_function ExecForeignDelete
Definition: fdwapi.h:213
Node * qual
Definition: prs2lock.h:28
int numLocks
Definition: prs2lock.h:42
FromExpr * jointree
Definition: parsenodes.h:138
ExecForeignInsert_function ExecForeignInsert
Definition: fdwapi.h:211
static const char * view_cols_are_auto_updatable(Query *viewquery, Bitmapset *required_cols, Bitmapset **updatable_cols, char **non_updatable_col)
#define AccessShareLock
Definition: lockdefs.h:36
List * fromlist
Definition: primnodes.h:1534
Form_pg_class rd_rel
Definition: rel.h:110
unsigned int Oid
Definition: postgres_ext.h:31
List * lappend_oid(List *list, Oid datum)
Definition: list.c:357
bool isInstead
Definition: prs2lock.h:31
Relation try_relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:89
List * targetList
Definition: parsenodes.h:140
bool trig_insert_instead_row
Definition: reltrigger.h:58
#define linitial(l)
Definition: pg_list.h:174
List * rtable
Definition: parsenodes.h:137
#define ALL_EVENTS
TriggerDesc * trigdesc
Definition: rel.h:116
void check_stack_depth(void)
Definition: postgres.c:3377
CmdType event
Definition: prs2lock.h:27
List * list_delete_last(List *list)
Definition: list.c:877
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:212
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:674
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
#define Assert(condition)
Definition: c.h:792
RuleLock * rd_rules
Definition: rel.h:114
RTEKind rtekind
Definition: parsenodes.h:981
FdwRoutine * GetFdwRoutineForRelation(Relation relation, bool makecopy)
Definition: foreign.c:427
Query * get_view_query(Relation view)
int i
IsForeignRelUpdatable_function IsForeignRelUpdatable
Definition: fdwapi.h:217
Bitmapset * bms_int_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:902
const char * view_query_is_auto_updatable(Query *viewquery, bool check_cols)
#define RelationGetRelid(relation)
Definition: rel.h:457

◆ RewriteQuery()

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

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

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

◆ 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:138
bool checkExprHasSubLink(Node *node)
Definition: rewriteManip.c:277
int resultRelation
Definition: parsenodes.h:122
Definition: nodes.h:528
List * list_concat(List *list1, const List *list2)
Definition: list.c:515
int errcode(int sqlerrcode)
Definition: elog.c:704
static List * adjustJoinTreeList(Query *parsetree, bool removert, int rt_index)
List * fromlist
Definition: primnodes.h:1534
List * values_lists
Definition: parsenodes.h:1079
Node * quals
Definition: primnodes.h:1535
List * targetList
Definition: parsenodes.h:140
List * rtable
Definition: parsenodes.h:137
#define ERROR
Definition: elog.h:45
TableFunc * tablefunc
Definition: parsenodes.h:1074
void AcquireRewriteLocks(Query *parsetree, bool forExecute, bool forUpdatePushedDown)
List * returningList
Definition: parsenodes.h:146
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
#define PRS2_OLD_VARNO
Definition: primnodes.h:178
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:155
CmdType commandType
Definition: parsenodes.h:112
#define Assert(condition)
Definition: c.h:792
#define lfirst(lc)
Definition: pg_list.h:169
List * functions
Definition: parsenodes.h:1068
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:981
List * cteList
Definition: parsenodes.h:135
Node * setOperations
Definition: parsenodes.h:166
int errmsg(const char *fmt,...)
Definition: elog.c:915
bool hasSubLinks
Definition: parsenodes.h:128
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:644
Definition: pg_list.h:50
struct TableSampleClause * tablesample
Definition: parsenodes.h:1011
#define PRS2_NEW_VARNO
Definition: primnodes.h:179
bool hasRowSecurity
Definition: parsenodes.h:133

◆ rewriteTargetListIU()

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

Definition at line 727 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(), makeVar(), NameStr, NIL, OVERRIDING_SYSTEM_VALUE, OVERRIDING_USER_VALUE, palloc0(), pfree(), process_matched_tle(), pstrdup(), RelationData::rd_att, RelationData::rd_rel, RelationGetNumberOfAttributes, TargetEntry::resjunk, TargetEntry::resno, TupleDescAttr, Var::varattno, Var::varno, and view_has_instead_trigger().

Referenced by RewriteQuery().

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

◆ rewriteTargetListUD()

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

Definition at line 1624 of file rewriteHandler.c.

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

Referenced by preprocess_targetlist().

1626 {
1627  Var *var = NULL;
1628  const char *attrname;
1629  TargetEntry *tle;
1630 
1631  if (target_relation->rd_rel->relkind == RELKIND_RELATION ||
1632  target_relation->rd_rel->relkind == RELKIND_MATVIEW ||
1633  target_relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1634  {
1635  /*
1636  * Emit CTID so that executor can find the row to update or delete.
1637  */
1638  var = makeVar(parsetree->resultRelation,
1640  TIDOID,
1641  -1,
1642  InvalidOid,
1643  0);
1644 
1645  attrname = "ctid";
1646  }
1647  else if (target_relation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
1648  {
1649  /*
1650  * Let the foreign table's FDW add whatever junk TLEs it wants.
1651  */
1652  FdwRoutine *fdwroutine;
1653 
1654  fdwroutine = GetFdwRoutineForRelation(target_relation, false);
1655 
1656  if (fdwroutine->AddForeignUpdateTargets != NULL)
1657  fdwroutine->AddForeignUpdateTargets(parsetree, target_rte,
1658  target_relation);
1659 
1660  /*
1661  * If we have a row-level trigger corresponding to the operation, emit
1662  * a whole-row Var so that executor will have the "old" row to pass to
1663  * the trigger. Alas, this misses system columns.
1664  */
1665  if (target_relation->trigdesc &&
1666  ((parsetree->commandType == CMD_UPDATE &&
1667  (target_relation->trigdesc->trig_update_after_row ||
1668  target_relation->trigdesc->trig_update_before_row)) ||
1669  (parsetree->commandType == CMD_DELETE &&
1670  (target_relation->trigdesc->trig_delete_after_row ||
1671  target_relation->trigdesc->trig_delete_before_row))))
1672  {
1673  var = makeWholeRowVar(target_rte,
1674  parsetree->resultRelation,
1675  0,
1676  false);
1677 
1678  attrname = "wholerow";
1679  }
1680  }
1681 
1682  if (var != NULL)
1683  {
1684  tle = makeTargetEntry((Expr *) var,
1685  list_length(parsetree->targetList) + 1,
1686  pstrdup(attrname),
1687  true);
1688 
1689  parsetree->targetList = lappend(parsetree->targetList, tle);
1690  }
1691 }
char * pstrdup(const char *in)
Definition: mcxt.c:1187
int resultRelation
Definition: parsenodes.h:122
Var * makeWholeRowVar(RangeTblEntry *rte, Index varno, Index varlevelsup, bool allowScalar)
Definition: makefuncs.c:133
Form_pg_class rd_rel
Definition: rel.h:110
Definition: primnodes.h:181
AddForeignUpdateTargets_function AddForeignUpdateTargets
Definition: fdwapi.h:208
List * targetList
Definition: parsenodes.h:140
TriggerDesc * trigdesc
Definition: rel.h:116
bool trig_delete_after_row
Definition: reltrigger.h:67
bool trig_update_before_row
Definition: reltrigger.h:61
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:238
Var * makeVar(Index varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:66
bool trig_update_after_row
Definition: reltrigger.h:62
List * lappend(List *list, void *datum)
Definition: list.c:321
#define InvalidOid
Definition: postgres_ext.h:36
CmdType commandType
Definition: parsenodes.h:112
static int list_length(const List *l)
Definition: pg_list.h:149
FdwRoutine * GetFdwRoutineForRelation(Relation relation, bool makecopy)
Definition: foreign.c:427
#define SelfItemPointerAttributeNumber
Definition: sysattr.h:21
bool trig_delete_before_row
Definition: reltrigger.h:66

◆ rewriteTargetView()

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

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

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

◆ rewriteValuesRTE()

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

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

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

References IsA, lfirst, and RangeTblEntry::values_lists.

Referenced by rewriteValuesRTE().

1300 {
1301  ListCell *lc;
1302 
1303  foreach(lc, rte->values_lists)
1304  {
1305  List *sublist = (List *) lfirst(lc);
1306  ListCell *lc2;
1307 
1308  foreach(lc2, sublist)
1309  {
1310  Node *col = (Node *) lfirst(lc2);
1311 
1312  if (IsA(col, SetToDefault))
1313  return true;
1314  }
1315  }
1316  return false;
1317 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:579
Definition: nodes.h:528
List * values_lists
Definition: parsenodes.h:1079
#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 2583 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().

2584 {
2585  Var *var = (Var *) tle->expr;
2586 
2587  /*
2588  * For now, the only updatable columns we support are those that are Vars
2589  * referring to user columns of the underlying base relation.
2590  *
2591  * The view targetlist may contain resjunk columns (e.g., a view defined
2592  * like "SELECT * FROM t ORDER BY a+b" is auto-updatable) but such columns
2593  * are not auto-updatable, and in fact should never appear in the outer
2594  * query's targetlist.
2595  */
2596  if (tle->resjunk)
2597  return gettext_noop("Junk view columns are not updatable.");
2598 
2599  if (!IsA(var, Var) ||
2600  var->varno != rtr->rtindex ||
2601  var->varlevelsup != 0)
2602  return gettext_noop("View columns that are not columns of their base relation are not updatable.");
2603 
2604  if (var->varattno < 0)
2605  return gettext_noop("View columns that refer to system columns are not updatable.");
2606 
2607  if (var->varattno == 0)
2608  return gettext_noop("View columns that return whole-row references are not updatable.");
2609 
2610  return NULL; /* the view column is updatable */
2611 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:579
Index varlevelsup
Definition: primnodes.h:191
#define gettext_noop(x)
Definition: c.h:1185
AttrNumber varattno
Definition: primnodes.h:186
Definition: primnodes.h:181
bool resjunk
Definition: primnodes.h:1438
Index varno
Definition: primnodes.h:184
Expr * expr
Definition: primnodes.h:1431

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

2783 {
2784  RangeTblRef *rtr;
2785  AttrNumber col;
2786  ListCell *cell;
2787 
2788  /*
2789  * The caller should have verified that this view is auto-updatable and so
2790  * there should be a single base relation.
2791  */
2792  Assert(list_length(viewquery->jointree->fromlist) == 1);
2793  rtr = linitial_node(RangeTblRef, viewquery->jointree->fromlist);
2794 
2795  /* Initialize the optional return values */
2796  if (updatable_cols != NULL)
2797  *updatable_cols = NULL;
2798  if (non_updatable_col != NULL)
2799  *non_updatable_col = NULL;
2800 
2801  /* Test each view column for updatability */
2803  foreach(cell, viewquery->targetList)
2804  {
2805  TargetEntry *tle = (TargetEntry *) lfirst(cell);
2806  const char *col_update_detail;
2807 
2808  col++;
2809  col_update_detail = view_col_is_auto_updatable(rtr, tle);
2810 
2811  if (col_update_detail == NULL)
2812  {
2813  /* The column is updatable */
2814  if (updatable_cols != NULL)
2815  *updatable_cols = bms_add_member(*updatable_cols, col);
2816  }
2817  else if (bms_is_member(col, required_cols))
2818  {
2819  /* The required column is not updatable */
2820  if (non_updatable_col != NULL)
2821  *non_updatable_col = tle->resname;
2822  return col_update_detail;
2823  }
2824  }
2825 
2826  return NULL; /* all the required view columns are updatable */
2827 }
FromExpr * jointree
Definition: parsenodes.h:138
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
List * fromlist
Definition: primnodes.h:1534
char * resname
Definition: primnodes.h:1433
#define linitial_node(type, l)
Definition: pg_list.h:177
List * targetList
Definition: parsenodes.h:140
#define Assert(condition)
Definition: c.h:792
#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 2545 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(), rewriteTargetListIU(), and rewriteValuesRTE().

2546 {
2547  TriggerDesc *trigDesc = view->trigdesc;
2548 
2549  switch (event)
2550  {
2551  case CMD_INSERT:
2552  if (trigDesc && trigDesc->trig_insert_instead_row)
2553  return true;
2554  break;
2555  case CMD_UPDATE:
2556  if (trigDesc && trigDesc->trig_update_instead_row)
2557  return true;
2558  break;
2559  case CMD_DELETE:
2560  if (trigDesc && trigDesc->trig_delete_instead_row)
2561  return true;
2562  break;
2563  default:
2564  elog(ERROR, "unrecognized CmdType: %d", (int) event);
2565  break;
2566  }
2567  return false;
2568 }
bool trig_insert_instead_row
Definition: reltrigger.h:58