PostgreSQL Source Code git master
Loading...
Searching...
No Matches
rewriteHandler.h File Reference
#include "nodes/parsenodes.h"
#include "utils/relcache.h"
Include dependency graph for rewriteHandler.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

ListQueryRewrite (Query *parsetree)
 
void AcquireRewriteLocks (Query *parsetree, bool forExecute, bool forUpdatePushedDown)
 
Nodebuild_column_default (Relation rel, int attrno)
 
Queryget_view_query (Relation view)
 
bool view_has_instead_trigger (Relation view, CmdType event, List *mergeActionList)
 
const charview_query_is_auto_updatable (Query *viewquery, bool check_cols)
 
int relation_is_updatable (Oid reloid, List *outer_reloids, bool include_triggers, Bitmapset *include_cols)
 
void error_view_not_updatable (Relation view, CmdType command, List *mergeActionList, const char *detail)
 
Nodeexpand_generated_columns_in_expr (Node *node, Relation rel, int rt_index)
 
Nodebuild_generation_expression (Relation rel, int attrno)
 

Function Documentation

◆ AcquireRewriteLocks()

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

Definition at line 148 of file rewriteHandler.c.

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

References AccessShareLock, acquireLocksOnSubLinks(), AcquireRewriteLocks(), Assert, Query::cteList, CommonTableExpr::ctequery, elog, ERROR, fb(), acquireLocksOnSubLinks_context::for_execute, get_parse_rowmark(), get_rte_attribute_is_dropped(), IsA, lappend(), lfirst, NIL, NoLock, QTW_IGNORE_RC_SUBQUERIES, query_tree_walker, RelationData::rd_rel, relation_close(), relation_open(), RowShareLock, rt_fetch, Query::rtable, RTE_GRAPH_TABLE, RTE_JOIN, RTE_RELATION, RTE_SUBQUERY, and strip_implicit_coercions().

Referenced by acquireLocksOnSubLinks(), AcquireRewriteLocks(), ApplyRetrieveRule(), fmgr_sql_validator(), get_query_def(), inline_sql_function_in_from(), make_ruledef(), prepare_next_query(), print_function_sqlbody(), refresh_matview_datafill(), RevalidateCachedQuery(), rewriteGraphTable(), and rewriteRuleAction().

◆ build_column_default()

Node * build_column_default ( Relation  rel,
int  attrno 
)
extern

Definition at line 1279 of file rewriteHandler.c.

1280{
1281 TupleDesc rd_att = rel->rd_att;
1283 Oid atttype = att_tup->atttypid;
1284 int32 atttypmod = att_tup->atttypmod;
1285 Node *expr = NULL;
1286 Oid exprtype;
1287
1288 if (att_tup->attidentity)
1289 {
1291
1292 nve->seqid = getIdentitySequence(rel, attrno, false);
1293 nve->typeId = att_tup->atttypid;
1294
1295 return (Node *) nve;
1296 }
1297
1298 /*
1299 * If relation has a default for this column, fetch that expression.
1300 */
1301 if (att_tup->atthasdef)
1302 {
1303 expr = TupleDescGetDefault(rd_att, attrno);
1304 if (expr == NULL)
1305 elog(ERROR, "default expression not found for attribute %d of relation \"%s\"",
1307 }
1308
1309 /*
1310 * No per-column default, so look for a default for the type itself. But
1311 * not for generated columns.
1312 */
1313 if (expr == NULL && !att_tup->attgenerated)
1314 expr = get_typdefault(atttype);
1315
1316 if (expr == NULL)
1317 return NULL; /* No default anywhere */
1318
1319 /*
1320 * Make sure the value is coerced to the target column type; this will
1321 * generally be true already, but there seem to be some corner cases
1322 * involving domain defaults where it might not be true. This should match
1323 * the parser's processing of non-defaulted expressions --- see
1324 * transformAssignedExpr().
1325 */
1326 exprtype = exprType(expr);
1327
1328 expr = coerce_to_target_type(NULL, /* no UNKNOWN params here */
1329 expr, exprtype,
1330 atttype, atttypmod,
1333 -1);
1334 if (expr == NULL)
1335 ereport(ERROR,
1337 errmsg("column \"%s\" is of type %s"
1338 " but default expression is of type %s",
1339 NameStr(att_tup->attname),
1340 format_type_be(atttype),
1341 format_type_be(exprtype)),
1342 errhint("You will need to rewrite or cast the expression.")));
1343
1344 return expr;
1345}
#define NameStr(name)
Definition c.h:835
int32_t int32
Definition c.h:620
int errcode(int sqlerrcode)
Definition elog.c:875
int errhint(const char *fmt,...) pg_attribute_printf(1
#define ereport(elevel,...)
Definition elog.h:152
char * format_type_be(Oid type_oid)
Node * get_typdefault(Oid typid)
Definition lsyscache.c:2643
Oid exprType(const Node *expr)
Definition nodeFuncs.c:42
#define makeNode(_type_)
Definition nodes.h:161
static char * errmsg
Node * coerce_to_target_type(ParseState *pstate, Node *expr, Oid exprtype, Oid targettype, int32 targettypmod, CoercionContext ccontext, CoercionForm cformat, int location)
FormData_pg_attribute * Form_pg_attribute
Oid getIdentitySequence(Relation rel, AttrNumber attnum, bool missing_ok)
Definition pg_depend.c:1018
unsigned int Oid
@ COERCE_IMPLICIT_CAST
Definition primnodes.h:769
@ COERCION_ASSIGNMENT
Definition primnodes.h:748
#define RelationGetRelationName(relation)
Definition rel.h:550
TupleDesc rd_att
Definition rel.h:112
Node * TupleDescGetDefault(TupleDesc tupdesc, AttrNumber attnum)
Definition tupdesc.c:1152
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition tupdesc.h:178

References COERCE_IMPLICIT_CAST, coerce_to_target_type(), COERCION_ASSIGNMENT, elog, ereport, errcode(), errhint(), errmsg, ERROR, exprType(), fb(), format_type_be(), get_typdefault(), getIdentitySequence(), makeNode, NameStr, RelationData::rd_att, RelationGetRelationName, TupleDescAttr(), and TupleDescGetDefault().

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

◆ build_generation_expression()

Node * build_generation_expression ( Relation  rel,
int  attrno 
)
extern

Definition at line 4685 of file rewriteHandler.c.

4686{
4687 TupleDesc rd_att = RelationGetDescr(rel);
4689 Node *defexpr;
4690 Oid attcollid;
4691
4692 Assert(rd_att->constr &&
4693 (rd_att->constr->has_generated_virtual ||
4694 rd_att->constr->has_generated_stored));
4695 Assert(att_tup->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL ||
4696 att_tup->attgenerated == ATTRIBUTE_GENERATED_STORED);
4697
4698 defexpr = build_column_default(rel, attrno);
4699 if (defexpr == NULL)
4700 elog(ERROR, "no generation expression found for column number %d of table \"%s\"",
4702
4703 /*
4704 * If the column definition has a collation and it is different from the
4705 * collation of the generation expression, put a COLLATE clause around the
4706 * expression.
4707 */
4708 attcollid = att_tup->attcollation;
4709 if (attcollid && attcollid != exprCollation(defexpr))
4710 {
4712
4713 ce->arg = (Expr *) defexpr;
4714 ce->collOid = attcollid;
4715 ce->location = -1;
4716
4717 defexpr = (Node *) ce;
4718 }
4719
4720 return defexpr;
4721}
Oid exprCollation(const Node *expr)
Definition nodeFuncs.c:826
#define RelationGetDescr(relation)
Definition rel.h:542
Node * build_column_default(Relation rel, int attrno)
bool has_generated_virtual
Definition tupdesc.h:47
bool has_generated_stored
Definition tupdesc.h:46
TupleConstr * constr
Definition tupdesc.h:159

References Assert, build_column_default(), TupleDescData::constr, elog, ERROR, exprCollation(), fb(), TupleConstr::has_generated_stored, TupleConstr::has_generated_virtual, makeNode, RelationGetDescr, RelationGetRelationName, and TupleDescAttr().

Referenced by createTableConstraints(), ExecRelGenVirtualNotNull(), expand_virtual_generated_columns(), and get_generated_columns().

◆ error_view_not_updatable()

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

Definition at line 3212 of file rewriteHandler.c.

3216{
3217 TriggerDesc *trigDesc = view->trigdesc;
3218
3219 switch (command)
3220 {
3221 case CMD_INSERT:
3222 ereport(ERROR,
3224 errmsg("cannot insert into view \"%s\"",
3226 detail ? errdetail_internal("%s", _(detail)) : 0,
3227 errhint("To enable inserting into the view, provide an INSTEAD OF INSERT trigger or an unconditional ON INSERT DO INSTEAD rule."));
3228 break;
3229 case CMD_UPDATE:
3230 ereport(ERROR,
3232 errmsg("cannot update view \"%s\"",
3234 detail ? errdetail_internal("%s", _(detail)) : 0,
3235 errhint("To enable updating the view, provide an INSTEAD OF UPDATE trigger or an unconditional ON UPDATE DO INSTEAD rule."));
3236 break;
3237 case CMD_DELETE:
3238 ereport(ERROR,
3240 errmsg("cannot delete from view \"%s\"",
3242 detail ? errdetail_internal("%s", _(detail)) : 0,
3243 errhint("To enable deleting from the view, provide an INSTEAD OF DELETE trigger or an unconditional ON DELETE DO INSTEAD rule."));
3244 break;
3245 case CMD_MERGE:
3246
3247 /*
3248 * Note that the error hints here differ from above, since MERGE
3249 * doesn't support rules.
3250 */
3251 foreach_node(MergeAction, action, mergeActionList)
3252 {
3253 switch (action->commandType)
3254 {
3255 case CMD_INSERT:
3256 if (!trigDesc || !trigDesc->trig_insert_instead_row)
3257 ereport(ERROR,
3259 errmsg("cannot insert into view \"%s\"",
3261 detail ? errdetail_internal("%s", _(detail)) : 0,
3262 errhint("To enable inserting into the view using MERGE, provide an INSTEAD OF INSERT trigger."));
3263 break;
3264 case CMD_UPDATE:
3265 if (!trigDesc || !trigDesc->trig_update_instead_row)
3266 ereport(ERROR,
3268 errmsg("cannot update view \"%s\"",
3270 detail ? errdetail_internal("%s", _(detail)) : 0,
3271 errhint("To enable updating the view using MERGE, provide an INSTEAD OF UPDATE trigger."));
3272 break;
3273 case CMD_DELETE:
3274 if (!trigDesc || !trigDesc->trig_delete_instead_row)
3275 ereport(ERROR,
3277 errmsg("cannot delete from view \"%s\"",
3279 detail ? errdetail_internal("%s", _(detail)) : 0,
3280 errhint("To enable deleting from the view using MERGE, provide an INSTEAD OF DELETE trigger."));
3281 break;
3282 case CMD_NOTHING:
3283 break;
3284 default:
3285 elog(ERROR, "unrecognized commandType: %d", action->commandType);
3286 break;
3287 }
3288 }
3289 break;
3290 default:
3291 elog(ERROR, "unrecognized CmdType: %d", (int) command);
3292 break;
3293 }
3294}
#define _(x)
Definition elog.c:96
int int errdetail_internal(const char *fmt,...) pg_attribute_printf(1
@ CMD_MERGE
Definition nodes.h:279
@ CMD_INSERT
Definition nodes.h:277
@ CMD_DELETE
Definition nodes.h:278
@ CMD_UPDATE
Definition nodes.h:276
@ CMD_NOTHING
Definition nodes.h:282
#define foreach_node(type, var, lst)
Definition pg_list.h:528
TriggerDesc * trigdesc
Definition rel.h:117

References _, CMD_DELETE, CMD_INSERT, CMD_MERGE, CMD_NOTHING, CMD_UPDATE, elog, ereport, errcode(), errdetail_internal(), errhint(), errmsg, ERROR, fb(), foreach_node, RelationGetRelationName, and RelationData::trigdesc.

Referenced by CheckValidResultRel(), RewriteQuery(), and rewriteTargetView().

◆ expand_generated_columns_in_expr()

Node * expand_generated_columns_in_expr ( Node node,
Relation  rel,
int  rt_index 
)
extern

Definition at line 4646 of file rewriteHandler.c.

4647{
4648 TupleDesc tupdesc = RelationGetDescr(rel);
4649
4650 if (tupdesc->constr && tupdesc->constr->has_generated_virtual)
4651 {
4653 List *vcols;
4654
4656 /* eref needs to be set, but the actual name doesn't matter */
4658 rte->rtekind = RTE_RELATION;
4659 rte->relid = RelationGetRelid(rel);
4660
4661 vcols = get_generated_columns(rel, rt_index, false);
4662
4663 if (vcols)
4664 {
4665 /*
4666 * Passing NULL for outer_hasSubLinks is safe because generation
4667 * expressions cannot contain SubLinks, so the replacement cannot
4668 * introduce any.
4669 */
4670 node = ReplaceVarsFromTargetList(node, rt_index, 0, rte, vcols, 0,
4671 REPLACEVARS_CHANGE_VARNO, rt_index,
4672 NULL);
4673 }
4674 }
4675
4676 return node;
4677}
Alias * makeAlias(const char *aliasname, List *colnames)
Definition makefuncs.c:438
#define RelationGetRelid(relation)
Definition rel.h:516
static List * get_generated_columns(Relation rel, int rt_index, bool include_stored)
Node * ReplaceVarsFromTargetList(Node *node, int target_varno, int sublevels_up, RangeTblEntry *target_rte, List *targetlist, int result_relation, ReplaceVarsNoMatchOption nomatch_option, int nomatch_varno, bool *outer_hasSubLinks)
@ REPLACEVARS_CHANGE_VARNO

References TupleDescData::constr, fb(), get_generated_columns(), TupleConstr::has_generated_virtual, makeAlias(), makeNode, NIL, RelationGetDescr, RelationGetRelationName, RelationGetRelid, REPLACEVARS_CHANGE_VARNO, ReplaceVarsFromTargetList(), and RTE_RELATION.

Referenced by ATExecAlterCheckConstrEnforceability(), ATPrepAlterColumnType(), ATRewriteTable(), createTableConstraints(), ExecRelCheck(), fetch_statentries_for_relation(), get_relation_constraints(), get_relation_statistics(), pgoutput_row_filter_init(), QueueCheckConstraintValidation(), TransformPubWhereClauses(), and TriggerEnabled().

◆ get_view_query()

Query * get_view_query ( Relation  view)
extern

Definition at line 2575 of file rewriteHandler.c.

2576{
2577 int i;
2578
2579 Assert(view->rd_rel->relkind == RELKIND_VIEW);
2580
2581 for (i = 0; i < view->rd_rules->numLocks; i++)
2582 {
2583 RewriteRule *rule = view->rd_rules->rules[i];
2584
2585 if (rule->event == CMD_SELECT)
2586 {
2587 /* A _RETURN rule should have only one action */
2588 if (list_length(rule->actions) != 1)
2589 elog(ERROR, "invalid _RETURN rule action specification");
2590
2591 return (Query *) linitial(rule->actions);
2592 }
2593 }
2594
2595 elog(ERROR, "failed to find _RETURN rule for view");
2596 return NULL; /* keep compiler quiet */
2597}
int i
Definition isn.c:77
@ CMD_SELECT
Definition nodes.h:275
static int list_length(const List *l)
Definition pg_list.h:152
#define linitial(l)
Definition pg_list.h:178
RuleLock * rd_rules
Definition rel.h:115
RewriteRule ** rules
Definition prs2lock.h:43
int numLocks
Definition prs2lock.h:42

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

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

◆ QueryRewrite()

List * QueryRewrite ( Query parsetree)
extern

Definition at line 4734 of file rewriteHandler.c.

4735{
4736 int64 input_query_id = parsetree->queryId;
4737 List *querylist;
4738 List *results;
4739 ListCell *l;
4741 bool foundOriginalQuery;
4743
4744 /*
4745 * This function is only applied to top-level original queries
4746 */
4747 Assert(parsetree->querySource == QSRC_ORIGINAL);
4748 Assert(parsetree->canSetTag);
4749
4750 /*
4751 * Step 1
4752 *
4753 * Apply all non-SELECT rules possibly getting 0 or many queries
4754 */
4755 querylist = RewriteQuery(parsetree, NIL, 0, 0);
4756
4757 /*
4758 * Step 2
4759 *
4760 * Apply all the RIR rules on each query
4761 *
4762 * This is also a handy place to mark each query with the original queryId
4763 */
4764 results = NIL;
4765 foreach(l, querylist)
4766 {
4767 Query *query = (Query *) lfirst(l);
4768
4769 query = fireRIRrules(query, NIL);
4770
4771 query->queryId = input_query_id;
4772
4773 results = lappend(results, query);
4774 }
4775
4776 /*
4777 * Step 3
4778 *
4779 * Determine which, if any, of the resulting queries is supposed to set
4780 * the command-result tag; and update the canSetTag fields accordingly.
4781 *
4782 * If the original query is still in the list, it sets the command tag.
4783 * Otherwise, the last INSTEAD query of the same kind as the original is
4784 * allowed to set the tag. (Note these rules can leave us with no query
4785 * setting the tag. The tcop code has to cope with this by setting up a
4786 * default tag based on the original un-rewritten query.)
4787 *
4788 * The Asserts verify that at most one query in the result list is marked
4789 * canSetTag. If we aren't checking asserts, we can fall out of the loop
4790 * as soon as we find the original query.
4791 */
4792 origCmdType = parsetree->commandType;
4793 foundOriginalQuery = false;
4794 lastInstead = NULL;
4795
4796 foreach(l, results)
4797 {
4798 Query *query = (Query *) lfirst(l);
4799
4800 if (query->querySource == QSRC_ORIGINAL)
4801 {
4802 Assert(query->canSetTag);
4804 foundOriginalQuery = true;
4805#ifndef USE_ASSERT_CHECKING
4806 break;
4807#endif
4808 }
4809 else
4810 {
4811 Assert(!query->canSetTag);
4812 if (query->commandType == origCmdType &&
4813 (query->querySource == QSRC_INSTEAD_RULE ||
4814 query->querySource == QSRC_QUAL_INSTEAD_RULE))
4815 lastInstead = query;
4816 }
4817 }
4818
4820 lastInstead->canSetTag = true;
4821
4822 return results;
4823}
int64_t int64
Definition c.h:621
CmdType
Definition nodes.h:273
@ QSRC_QUAL_INSTEAD_RULE
Definition parsenodes.h:39
@ QSRC_ORIGINAL
Definition parsenodes.h:36
@ QSRC_INSTEAD_RULE
Definition parsenodes.h:38
static List * RewriteQuery(Query *parsetree, List *rewrite_events, int orig_rt_length, int num_ctes_processed)
static Query * fireRIRrules(Query *parsetree, List *activeRIRs)
CmdType commandType
Definition parsenodes.h:121

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

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

◆ relation_is_updatable()

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

Definition at line 2957 of file rewriteHandler.c.

2961{
2962 int events = 0;
2963 Relation rel;
2965
2966#define ALL_EVENTS ((1 << CMD_INSERT) | (1 << CMD_UPDATE) | (1 << CMD_DELETE))
2967
2968 /* Since this function recurses, it could be driven to stack overflow */
2970
2971 rel = try_relation_open(reloid, AccessShareLock);
2972
2973 /*
2974 * If the relation doesn't exist, return zero rather than throwing an
2975 * error. This is helpful since scanning an information_schema view under
2976 * MVCC rules can result in referencing rels that have actually been
2977 * deleted already.
2978 */
2979 if (rel == NULL)
2980 return 0;
2981
2982 /* If we detect a recursive view, report that it is not updatable */
2984 {
2986 return 0;
2987 }
2988
2989 /* If the relation is a table, it is always updatable */
2990 if (rel->rd_rel->relkind == RELKIND_RELATION ||
2991 rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
2992 {
2994 return ALL_EVENTS;
2995 }
2996
2997 /* Look for unconditional DO INSTEAD rules, and note supported events */
2998 rulelocks = rel->rd_rules;
2999 if (rulelocks != NULL)
3000 {
3001 int i;
3002
3003 for (i = 0; i < rulelocks->numLocks; i++)
3004 {
3005 if (rulelocks->rules[i]->isInstead &&
3006 rulelocks->rules[i]->qual == NULL)
3007 {
3008 events |= ((1 << rulelocks->rules[i]->event) & ALL_EVENTS);
3009 }
3010 }
3011
3012 /* If we have rules for all events, we're done */
3013 if (events == ALL_EVENTS)
3014 {
3016 return events;
3017 }
3018 }
3019
3020 /* Similarly look for INSTEAD OF triggers, if they are to be included */
3021 if (include_triggers)
3022 {
3024
3025 if (trigDesc)
3026 {
3027 if (trigDesc->trig_insert_instead_row)
3028 events |= (1 << CMD_INSERT);
3029 if (trigDesc->trig_update_instead_row)
3030 events |= (1 << CMD_UPDATE);
3031 if (trigDesc->trig_delete_instead_row)
3032 events |= (1 << CMD_DELETE);
3033
3034 /* If we have triggers for all events, we're done */
3035 if (events == ALL_EVENTS)
3036 {
3038 return events;
3039 }
3040 }
3041 }
3042
3043 /* If this is a foreign table, check which update events it supports */
3044 if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
3045 {
3046 FdwRoutine *fdwroutine = GetFdwRoutineForRelation(rel, false);
3047
3048 if (fdwroutine->IsForeignRelUpdatable != NULL)
3049 events |= fdwroutine->IsForeignRelUpdatable(rel);
3050 else
3051 {
3052 /* Assume presence of executor functions is sufficient */
3053 if (fdwroutine->ExecForeignInsert != NULL)
3054 events |= (1 << CMD_INSERT);
3055 if (fdwroutine->ExecForeignUpdate != NULL)
3056 events |= (1 << CMD_UPDATE);
3057 if (fdwroutine->ExecForeignDelete != NULL)
3058 events |= (1 << CMD_DELETE);
3059 }
3060
3062 return events;
3063 }
3064
3065 /* Check if this is an automatically updatable view */
3066 if (rel->rd_rel->relkind == RELKIND_VIEW)
3067 {
3069
3071 {
3073 int auto_events;
3076 Oid baseoid;
3077
3078 /*
3079 * Determine which of the view's columns are updatable. If there
3080 * are none within the set of columns we are looking at, then the
3081 * view doesn't support INSERT/UPDATE, but it may still support
3082 * DELETE.
3083 */
3086
3087 if (include_cols != NULL)
3089
3091 auto_events = (1 << CMD_DELETE); /* May support DELETE */
3092 else
3093 auto_events = ALL_EVENTS; /* May support all events */
3094
3095 /*
3096 * The base relation must also support these update commands.
3097 * Tables are always updatable, but for any other kind of base
3098 * relation we must do a recursive check limited to the columns
3099 * referenced by the locally updatable columns in this view.
3100 */
3101 rtr = (RangeTblRef *) linitial(viewquery->jointree->fromlist);
3102 base_rte = rt_fetch(rtr->rtindex, viewquery->rtable);
3103 Assert(base_rte->rtekind == RTE_RELATION);
3104
3105 if (base_rte->relkind != RELKIND_RELATION &&
3107 {
3108 baseoid = base_rte->relid;
3110 RelationGetRelid(rel));
3112 viewquery->targetList);
3116 include_cols);
3118 }
3119 events |= auto_events;
3120 }
3121 }
3122
3123 /* If we reach here, the relation may support some update commands */
3125 return events;
3126}
Bitmapset * bms_int_members(Bitmapset *a, const Bitmapset *b)
Definition bitmapset.c:1093
#define bms_is_empty(a)
Definition bitmapset.h:118
FdwRoutine * GetFdwRoutineForRelation(Relation relation, bool makecopy)
Definition foreign.c:474
List * lappend_oid(List *list, Oid datum)
Definition list.c:375
List * list_delete_last(List *list)
Definition list.c:957
bool list_member_oid(const List *list, Oid datum)
Definition list.c:722
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)
Query * get_view_query(Relation view)
static Bitmapset * adjust_view_column_set(Bitmapset *cols, List *targetlist)
const char * view_query_is_auto_updatable(Query *viewquery, bool check_cols)
#define ALL_EVENTS
Relation try_relation_open(Oid relationId, LOCKMODE lockmode)
Definition relation.c:89
void check_stack_depth(void)
Definition stack_depth.c:95
ExecForeignInsert_function ExecForeignInsert
Definition fdwapi.h:236
ExecForeignUpdate_function ExecForeignUpdate
Definition fdwapi.h:239
ExecForeignDelete_function ExecForeignDelete
Definition fdwapi.h:240
IsForeignRelUpdatable_function IsForeignRelUpdatable
Definition fdwapi.h:244

References AccessShareLock, adjust_view_column_set(), ALL_EVENTS, Assert, bms_int_members(), bms_is_empty, check_stack_depth(), CMD_DELETE, CMD_INSERT, CMD_UPDATE, FdwRoutine::ExecForeignDelete, FdwRoutine::ExecForeignInsert, FdwRoutine::ExecForeignUpdate, fb(), get_view_query(), GetFdwRoutineForRelation(), i, FdwRoutine::IsForeignRelUpdatable, lappend_oid(), linitial, list_delete_last(), list_member_oid(), RelationData::rd_rel, RelationData::rd_rules, relation_close(), relation_is_updatable(), RelationGetRelid, rt_fetch, RTE_RELATION, 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().

◆ view_has_instead_trigger()

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

Definition at line 2614 of file rewriteHandler.c.

2615{
2616 TriggerDesc *trigDesc = view->trigdesc;
2617
2618 switch (event)
2619 {
2620 case CMD_INSERT:
2621 if (trigDesc && trigDesc->trig_insert_instead_row)
2622 return true;
2623 break;
2624 case CMD_UPDATE:
2625 if (trigDesc && trigDesc->trig_update_instead_row)
2626 return true;
2627 break;
2628 case CMD_DELETE:
2629 if (trigDesc && trigDesc->trig_delete_instead_row)
2630 return true;
2631 break;
2632 case CMD_MERGE:
2633 foreach_node(MergeAction, action, mergeActionList)
2634 {
2635 switch (action->commandType)
2636 {
2637 case CMD_INSERT:
2638 if (!trigDesc || !trigDesc->trig_insert_instead_row)
2639 return false;
2640 break;
2641 case CMD_UPDATE:
2642 if (!trigDesc || !trigDesc->trig_update_instead_row)
2643 return false;
2644 break;
2645 case CMD_DELETE:
2646 if (!trigDesc || !trigDesc->trig_delete_instead_row)
2647 return false;
2648 break;
2649 case CMD_NOTHING:
2650 /* No trigger required */
2651 break;
2652 default:
2653 elog(ERROR, "unrecognized commandType: %d", action->commandType);
2654 break;
2655 }
2656 }
2657 return true; /* no actions without an INSTEAD OF trigger */
2658 default:
2659 elog(ERROR, "unrecognized CmdType: %d", (int) event);
2660 break;
2661 }
2662 return false;
2663}

References CMD_DELETE, CMD_INSERT, CMD_MERGE, CMD_NOTHING, CMD_UPDATE, elog, ERROR, fb(), foreach_node, and RelationData::trigdesc.

Referenced by CheckValidResultRel(), RewriteQuery(), rewriteTargetView(), and rewriteValuesRTE().

◆ view_query_is_auto_updatable()

const char * view_query_is_auto_updatable ( Query viewquery,
bool  check_cols 
)
extern

Definition at line 2726 of file rewriteHandler.c.

2727{
2730
2731 /*----------
2732 * Check if the view is simply updatable. According to SQL-92 this means:
2733 * - No DISTINCT clause.
2734 * - Each TLE is a column reference, and each column appears at most once.
2735 * - FROM contains exactly one base relation.
2736 * - No GROUP BY or HAVING clauses.
2737 * - No set operations (UNION, INTERSECT or EXCEPT).
2738 * - No sub-queries in the WHERE clause that reference the target table.
2739 *
2740 * We ignore that last restriction since it would be complex to enforce
2741 * and there isn't any actual benefit to disallowing sub-queries. (The
2742 * semantic issues that the standard is presumably concerned about don't
2743 * arise in Postgres, since any such sub-query will not see any updates
2744 * executed by the outer query anyway, thanks to MVCC snapshotting.)
2745 *
2746 * We also relax the second restriction by supporting part of SQL:1999
2747 * feature T111, which allows for a mix of updatable and non-updatable
2748 * columns, provided that an INSERT or UPDATE doesn't attempt to assign to
2749 * a non-updatable column.
2750 *
2751 * In addition we impose these constraints, involving features that are
2752 * not part of SQL-92:
2753 * - No CTEs (WITH clauses).
2754 * - No OFFSET or LIMIT clauses (this matches a SQL:2008 restriction).
2755 * - No system columns (including whole-row references) in the tlist.
2756 * - No window functions in the tlist.
2757 * - No set-returning functions in the tlist.
2758 *
2759 * Note that we do these checks without recursively expanding the view.
2760 * If the base relation is a view, we'll recursively deal with it later.
2761 *----------
2762 */
2763 if (viewquery->distinctClause != NIL)
2764 return gettext_noop("Views containing DISTINCT are not automatically updatable.");
2765
2766 if (viewquery->groupClause != NIL || viewquery->groupingSets)
2767 return gettext_noop("Views containing GROUP BY are not automatically updatable.");
2768
2769 if (viewquery->havingQual != NULL)
2770 return gettext_noop("Views containing HAVING are not automatically updatable.");
2771
2772 if (viewquery->setOperations != NULL)
2773 return gettext_noop("Views containing UNION, INTERSECT, or EXCEPT are not automatically updatable.");
2774
2775 if (viewquery->cteList != NIL)
2776 return gettext_noop("Views containing WITH are not automatically updatable.");
2777
2778 if (viewquery->limitOffset != NULL || viewquery->limitCount != NULL)
2779 return gettext_noop("Views containing LIMIT or OFFSET are not automatically updatable.");
2780
2781 /*
2782 * We must not allow window functions or set returning functions in the
2783 * targetlist. Otherwise we might end up inserting them into the quals of
2784 * the main query. We must also check for aggregates in the targetlist in
2785 * case they appear without a GROUP BY.
2786 *
2787 * These restrictions ensure that each row of the view corresponds to a
2788 * unique row in the underlying base relation.
2789 */
2790 if (viewquery->hasAggs)
2791 return gettext_noop("Views that return aggregate functions are not automatically updatable.");
2792
2793 if (viewquery->hasWindowFuncs)
2794 return gettext_noop("Views that return window functions are not automatically updatable.");
2795
2796 if (viewquery->hasTargetSRFs)
2797 return gettext_noop("Views that return set-returning functions are not automatically updatable.");
2798
2799 /*
2800 * The view query should select from a single base relation, which must be
2801 * a table or another view.
2802 */
2803 if (list_length(viewquery->jointree->fromlist) != 1)
2804 return gettext_noop("Views that do not select from a single table or view are not automatically updatable.");
2805
2806 rtr = (RangeTblRef *) linitial(viewquery->jointree->fromlist);
2807 if (!IsA(rtr, RangeTblRef))
2808 return gettext_noop("Views that do not select from a single table or view are not automatically updatable.");
2809
2810 base_rte = rt_fetch(rtr->rtindex, viewquery->rtable);
2811 if (base_rte->rtekind != RTE_RELATION ||
2812 (base_rte->relkind != RELKIND_RELATION &&
2813 base_rte->relkind != RELKIND_FOREIGN_TABLE &&
2814 base_rte->relkind != RELKIND_VIEW &&
2816 return gettext_noop("Views that do not select from a single table or view are not automatically updatable.");
2817
2818 if (base_rte->tablesample)
2819 return gettext_noop("Views containing TABLESAMPLE are not automatically updatable.");
2820
2821 /*
2822 * Check that the view has at least one updatable column. This is required
2823 * for INSERT/UPDATE but not for DELETE.
2824 */
2825 if (check_cols)
2826 {
2827 ListCell *cell;
2828 bool found;
2829
2830 found = false;
2831 foreach(cell, viewquery->targetList)
2832 {
2833 TargetEntry *tle = (TargetEntry *) lfirst(cell);
2834
2836 {
2837 found = true;
2838 break;
2839 }
2840 }
2841
2842 if (!found)
2843 return gettext_noop("Views that have no updatable columns are not automatically updatable.");
2844 }
2845
2846 return NULL; /* the view is updatable */
2847}
#define gettext_noop(x)
Definition c.h:1285
static const char * view_col_is_auto_updatable(RangeTblRef *rtr, TargetEntry *tle)

References fb(), gettext_noop, IsA, lfirst, linitial, list_length(), NIL, rt_fetch, RTE_RELATION, and view_col_is_auto_updatable().

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