PostgreSQL Source Code git master
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 char * view_query_is_auto_updatable (Query *viewquery, bool check_cols)
 
int relation_is_updatable (Oid reloid, List *outer_reloids, bool include_triggers, Bitmapset *include_cols)
 
void error_view_not_updatable (Relation view, CmdType command, List *mergeActionList, const char *detail)
 

Function Documentation

◆ AcquireRewriteLocks()

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

Definition at line 146 of file rewriteHandler.c.

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

References AccessShareLock, acquireLocksOnSubLinks(), AcquireRewriteLocks(), Assert, Query::cteList, CommonTableExpr::ctequery, elog, ERROR, 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, RangeTblEntry::relid, RowShareLock, rt_fetch, Query::rtable, RTE_JOIN, RTE_RELATION, RTE_SUBQUERY, RangeTblEntry::rtekind, strip_implicit_coercions(), RangeTblEntry::subquery, table_close(), table_open(), Var::varattno, Var::varlevelsup, and Var::varno.

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

◆ build_column_default()

Node * build_column_default ( Relation  rel,
int  attrno 
)

Definition at line 1224 of file rewriteHandler.c.

1225{
1226 TupleDesc rd_att = rel->rd_att;
1227 Form_pg_attribute att_tup = TupleDescAttr(rd_att, attrno - 1);
1228 Oid atttype = att_tup->atttypid;
1229 int32 atttypmod = att_tup->atttypmod;
1230 Node *expr = NULL;
1231 Oid exprtype;
1232
1233 if (att_tup->attidentity)
1234 {
1236
1237 nve->seqid = getIdentitySequence(rel, attrno, false);
1238 nve->typeId = att_tup->atttypid;
1239
1240 return (Node *) nve;
1241 }
1242
1243 /*
1244 * If relation has a default for this column, fetch that expression.
1245 */
1246 if (att_tup->atthasdef)
1247 {
1248 expr = TupleDescGetDefault(rd_att, attrno);
1249 if (expr == NULL)
1250 elog(ERROR, "default expression not found for attribute %d of relation \"%s\"",
1251 attrno, RelationGetRelationName(rel));
1252 }
1253
1254 /*
1255 * No per-column default, so look for a default for the type itself. But
1256 * not for generated columns.
1257 */
1258 if (expr == NULL && !att_tup->attgenerated)
1259 expr = get_typdefault(atttype);
1260
1261 if (expr == NULL)
1262 return NULL; /* No default anywhere */
1263
1264 /*
1265 * Make sure the value is coerced to the target column type; this will
1266 * generally be true already, but there seem to be some corner cases
1267 * involving domain defaults where it might not be true. This should match
1268 * the parser's processing of non-defaulted expressions --- see
1269 * transformAssignedExpr().
1270 */
1271 exprtype = exprType(expr);
1272
1273 expr = coerce_to_target_type(NULL, /* no UNKNOWN params here */
1274 expr, exprtype,
1275 atttype, atttypmod,
1278 -1);
1279 if (expr == NULL)
1280 ereport(ERROR,
1281 (errcode(ERRCODE_DATATYPE_MISMATCH),
1282 errmsg("column \"%s\" is of type %s"
1283 " but default expression is of type %s",
1284 NameStr(att_tup->attname),
1285 format_type_be(atttype),
1286 format_type_be(exprtype)),
1287 errhint("You will need to rewrite or cast the expression.")));
1288
1289 return expr;
1290}
#define NameStr(name)
Definition: c.h:703
int32_t int32
Definition: c.h:484
int errhint(const char *fmt,...)
Definition: elog.c:1317
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ereport(elevel,...)
Definition: elog.h:149
char * format_type_be(Oid type_oid)
Definition: format_type.c:343
Node * get_typdefault(Oid typid)
Definition: lsyscache.c:2475
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
#define makeNode(_type_)
Definition: nodes.h:155
Node * coerce_to_target_type(ParseState *pstate, Node *expr, Oid exprtype, Oid targettype, int32 targettypmod, CoercionContext ccontext, CoercionForm cformat, int location)
Definition: parse_coerce.c:78
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:200
Oid getIdentitySequence(Relation rel, AttrNumber attnum, bool missing_ok)
Definition: pg_depend.c:945
unsigned int Oid
Definition: postgres_ext.h:32
@ COERCE_IMPLICIT_CAST
Definition: primnodes.h:753
@ COERCION_ASSIGNMENT
Definition: primnodes.h:732
#define RelationGetRelationName(relation)
Definition: rel.h:540
TupleDesc rd_att
Definition: rel.h:112
Node * TupleDescGetDefault(TupleDesc tupdesc, AttrNumber attnum)
Definition: tupdesc.c:1048
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition: tupdesc.h:153

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

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

◆ error_view_not_updatable()

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

Definition at line 3115 of file rewriteHandler.c.

3119{
3120 TriggerDesc *trigDesc = view->trigdesc;
3121
3122 switch (command)
3123 {
3124 case CMD_INSERT:
3125 ereport(ERROR,
3126 errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3127 errmsg("cannot insert into view \"%s\"",
3129 detail ? errdetail_internal("%s", _(detail)) : 0,
3130 errhint("To enable inserting into the view, provide an INSTEAD OF INSERT trigger or an unconditional ON INSERT DO INSTEAD rule."));
3131 break;
3132 case CMD_UPDATE:
3133 ereport(ERROR,
3134 errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3135 errmsg("cannot update view \"%s\"",
3137 detail ? errdetail_internal("%s", _(detail)) : 0,
3138 errhint("To enable updating the view, provide an INSTEAD OF UPDATE trigger or an unconditional ON UPDATE DO INSTEAD rule."));
3139 break;
3140 case CMD_DELETE:
3141 ereport(ERROR,
3142 errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3143 errmsg("cannot delete from view \"%s\"",
3145 detail ? errdetail_internal("%s", _(detail)) : 0,
3146 errhint("To enable deleting from the view, provide an INSTEAD OF DELETE trigger or an unconditional ON DELETE DO INSTEAD rule."));
3147 break;
3148 case CMD_MERGE:
3149
3150 /*
3151 * Note that the error hints here differ from above, since MERGE
3152 * doesn't support rules.
3153 */
3154 foreach_node(MergeAction, action, mergeActionList)
3155 {
3156 switch (action->commandType)
3157 {
3158 case CMD_INSERT:
3159 if (!trigDesc || !trigDesc->trig_insert_instead_row)
3160 ereport(ERROR,
3161 errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3162 errmsg("cannot insert into view \"%s\"",
3164 detail ? errdetail_internal("%s", _(detail)) : 0,
3165 errhint("To enable inserting into the view using MERGE, provide an INSTEAD OF INSERT trigger."));
3166 break;
3167 case CMD_UPDATE:
3168 if (!trigDesc || !trigDesc->trig_update_instead_row)
3169 ereport(ERROR,
3170 errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3171 errmsg("cannot update view \"%s\"",
3173 detail ? errdetail_internal("%s", _(detail)) : 0,
3174 errhint("To enable updating the view using MERGE, provide an INSTEAD OF UPDATE trigger."));
3175 break;
3176 case CMD_DELETE:
3177 if (!trigDesc || !trigDesc->trig_delete_instead_row)
3178 ereport(ERROR,
3179 errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3180 errmsg("cannot delete from view \"%s\"",
3182 detail ? errdetail_internal("%s", _(detail)) : 0,
3183 errhint("To enable deleting from the view using MERGE, provide an INSTEAD OF DELETE trigger."));
3184 break;
3185 case CMD_NOTHING:
3186 break;
3187 default:
3188 elog(ERROR, "unrecognized commandType: %d", action->commandType);
3189 break;
3190 }
3191 }
3192 break;
3193 default:
3194 elog(ERROR, "unrecognized CmdType: %d", (int) command);
3195 break;
3196 }
3197}
int errdetail_internal(const char *fmt,...)
Definition: elog.c:1230
#define _(x)
Definition: elog.c:90
@ CMD_MERGE
Definition: nodes.h:269
@ CMD_INSERT
Definition: nodes.h:267
@ CMD_DELETE
Definition: nodes.h:268
@ CMD_UPDATE
Definition: nodes.h:266
@ CMD_NOTHING
Definition: nodes.h:272
#define foreach_node(type, var, lst)
Definition: pg_list.h:496
TriggerDesc * trigdesc
Definition: rel.h:117
bool trig_update_instead_row
Definition: reltrigger.h:63
bool trig_delete_instead_row
Definition: reltrigger.h:68
bool trig_insert_instead_row
Definition: reltrigger.h:58

References _, generate_unaccent_rules::action, CMD_DELETE, CMD_INSERT, CMD_MERGE, CMD_NOTHING, CMD_UPDATE, elog, ereport, errcode(), errdetail_internal(), errhint(), errmsg(), ERROR, foreach_node, RelationGetRelationName, TriggerDesc::trig_delete_instead_row, TriggerDesc::trig_insert_instead_row, TriggerDesc::trig_update_instead_row, and RelationData::trigdesc.

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

◆ get_view_query()

Query * get_view_query ( Relation  view)

Definition at line 2478 of file rewriteHandler.c.

2479{
2480 int i;
2481
2482 Assert(view->rd_rel->relkind == RELKIND_VIEW);
2483
2484 for (i = 0; i < view->rd_rules->numLocks; i++)
2485 {
2486 RewriteRule *rule = view->rd_rules->rules[i];
2487
2488 if (rule->event == CMD_SELECT)
2489 {
2490 /* A _RETURN rule should have only one action */
2491 if (list_length(rule->actions) != 1)
2492 elog(ERROR, "invalid _RETURN rule action specification");
2493
2494 return (Query *) linitial(rule->actions);
2495 }
2496 }
2497
2498 elog(ERROR, "failed to find _RETURN rule for view");
2499 return NULL; /* keep compiler quiet */
2500}
int i
Definition: isn.c:72
@ CMD_SELECT
Definition: nodes.h:265
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
Definition: localtime.c:73

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

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

◆ QueryRewrite()

List * QueryRewrite ( Query parsetree)

Definition at line 4419 of file rewriteHandler.c.

4420{
4421 uint64 input_query_id = parsetree->queryId;
4422 List *querylist;
4423 List *results;
4424 ListCell *l;
4425 CmdType origCmdType;
4426 bool foundOriginalQuery;
4427 Query *lastInstead;
4428
4429 /*
4430 * This function is only applied to top-level original queries
4431 */
4432 Assert(parsetree->querySource == QSRC_ORIGINAL);
4433 Assert(parsetree->canSetTag);
4434
4435 /*
4436 * Step 1
4437 *
4438 * Apply all non-SELECT rules possibly getting 0 or many queries
4439 */
4440 querylist = RewriteQuery(parsetree, NIL, 0);
4441
4442 /*
4443 * Step 2
4444 *
4445 * Apply all the RIR rules on each query
4446 *
4447 * This is also a handy place to mark each query with the original queryId
4448 */
4449 results = NIL;
4450 foreach(l, querylist)
4451 {
4452 Query *query = (Query *) lfirst(l);
4453
4454 query = fireRIRrules(query, NIL);
4455
4456 query->queryId = input_query_id;
4457
4458 results = lappend(results, query);
4459 }
4460
4461 /*
4462 * Step 3
4463 *
4464 * Determine which, if any, of the resulting queries is supposed to set
4465 * the command-result tag; and update the canSetTag fields accordingly.
4466 *
4467 * If the original query is still in the list, it sets the command tag.
4468 * Otherwise, the last INSTEAD query of the same kind as the original is
4469 * allowed to set the tag. (Note these rules can leave us with no query
4470 * setting the tag. The tcop code has to cope with this by setting up a
4471 * default tag based on the original un-rewritten query.)
4472 *
4473 * The Asserts verify that at most one query in the result list is marked
4474 * canSetTag. If we aren't checking asserts, we can fall out of the loop
4475 * as soon as we find the original query.
4476 */
4477 origCmdType = parsetree->commandType;
4478 foundOriginalQuery = false;
4479 lastInstead = NULL;
4480
4481 foreach(l, results)
4482 {
4483 Query *query = (Query *) lfirst(l);
4484
4485 if (query->querySource == QSRC_ORIGINAL)
4486 {
4487 Assert(query->canSetTag);
4488 Assert(!foundOriginalQuery);
4489 foundOriginalQuery = true;
4490#ifndef USE_ASSERT_CHECKING
4491 break;
4492#endif
4493 }
4494 else
4495 {
4496 Assert(!query->canSetTag);
4497 if (query->commandType == origCmdType &&
4498 (query->querySource == QSRC_INSTEAD_RULE ||
4499 query->querySource == QSRC_QUAL_INSTEAD_RULE))
4500 lastInstead = query;
4501 }
4502 }
4503
4504 if (!foundOriginalQuery && lastInstead != NULL)
4505 lastInstead->canSetTag = true;
4506
4507 return results;
4508}
uint64_t uint64
Definition: c.h:489
CmdType
Definition: nodes.h:263
@ 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)
static Query * fireRIRrules(Query *parsetree, List *activeRIRs)
CmdType commandType
Definition: parsenodes.h:121

References Assert, Query::commandType, 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 
)

Definition at line 2860 of file rewriteHandler.c.

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

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

◆ view_has_instead_trigger()

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

Definition at line 2517 of file rewriteHandler.c.

2518{
2519 TriggerDesc *trigDesc = view->trigdesc;
2520
2521 switch (event)
2522 {
2523 case CMD_INSERT:
2524 if (trigDesc && trigDesc->trig_insert_instead_row)
2525 return true;
2526 break;
2527 case CMD_UPDATE:
2528 if (trigDesc && trigDesc->trig_update_instead_row)
2529 return true;
2530 break;
2531 case CMD_DELETE:
2532 if (trigDesc && trigDesc->trig_delete_instead_row)
2533 return true;
2534 break;
2535 case CMD_MERGE:
2536 foreach_node(MergeAction, action, mergeActionList)
2537 {
2538 switch (action->commandType)
2539 {
2540 case CMD_INSERT:
2541 if (!trigDesc || !trigDesc->trig_insert_instead_row)
2542 return false;
2543 break;
2544 case CMD_UPDATE:
2545 if (!trigDesc || !trigDesc->trig_update_instead_row)
2546 return false;
2547 break;
2548 case CMD_DELETE:
2549 if (!trigDesc || !trigDesc->trig_delete_instead_row)
2550 return false;
2551 break;
2552 case CMD_NOTHING:
2553 /* No trigger required */
2554 break;
2555 default:
2556 elog(ERROR, "unrecognized commandType: %d", action->commandType);
2557 break;
2558 }
2559 }
2560 return true; /* no actions without an INSTEAD OF trigger */
2561 default:
2562 elog(ERROR, "unrecognized CmdType: %d", (int) event);
2563 break;
2564 }
2565 return false;
2566}

References generate_unaccent_rules::action, CMD_DELETE, CMD_INSERT, CMD_MERGE, CMD_NOTHING, CMD_UPDATE, elog, ERROR, foreach_node, TriggerDesc::trig_delete_instead_row, TriggerDesc::trig_insert_instead_row, TriggerDesc::trig_update_instead_row, 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 
)

Definition at line 2629 of file rewriteHandler.c.

2630{
2631 RangeTblRef *rtr;
2632 RangeTblEntry *base_rte;
2633
2634 /*----------
2635 * Check if the view is simply updatable. According to SQL-92 this means:
2636 * - No DISTINCT clause.
2637 * - Each TLE is a column reference, and each column appears at most once.
2638 * - FROM contains exactly one base relation.
2639 * - No GROUP BY or HAVING clauses.
2640 * - No set operations (UNION, INTERSECT or EXCEPT).
2641 * - No sub-queries in the WHERE clause that reference the target table.
2642 *
2643 * We ignore that last restriction since it would be complex to enforce
2644 * and there isn't any actual benefit to disallowing sub-queries. (The
2645 * semantic issues that the standard is presumably concerned about don't
2646 * arise in Postgres, since any such sub-query will not see any updates
2647 * executed by the outer query anyway, thanks to MVCC snapshotting.)
2648 *
2649 * We also relax the second restriction by supporting part of SQL:1999
2650 * feature T111, which allows for a mix of updatable and non-updatable
2651 * columns, provided that an INSERT or UPDATE doesn't attempt to assign to
2652 * a non-updatable column.
2653 *
2654 * In addition we impose these constraints, involving features that are
2655 * not part of SQL-92:
2656 * - No CTEs (WITH clauses).
2657 * - No OFFSET or LIMIT clauses (this matches a SQL:2008 restriction).
2658 * - No system columns (including whole-row references) in the tlist.
2659 * - No window functions in the tlist.
2660 * - No set-returning functions in the tlist.
2661 *
2662 * Note that we do these checks without recursively expanding the view.
2663 * If the base relation is a view, we'll recursively deal with it later.
2664 *----------
2665 */
2666 if (viewquery->distinctClause != NIL)
2667 return gettext_noop("Views containing DISTINCT are not automatically updatable.");
2668
2669 if (viewquery->groupClause != NIL || viewquery->groupingSets)
2670 return gettext_noop("Views containing GROUP BY are not automatically updatable.");
2671
2672 if (viewquery->havingQual != NULL)
2673 return gettext_noop("Views containing HAVING are not automatically updatable.");
2674
2675 if (viewquery->setOperations != NULL)
2676 return gettext_noop("Views containing UNION, INTERSECT, or EXCEPT are not automatically updatable.");
2677
2678 if (viewquery->cteList != NIL)
2679 return gettext_noop("Views containing WITH are not automatically updatable.");
2680
2681 if (viewquery->limitOffset != NULL || viewquery->limitCount != NULL)
2682 return gettext_noop("Views containing LIMIT or OFFSET are not automatically updatable.");
2683
2684 /*
2685 * We must not allow window functions or set returning functions in the
2686 * targetlist. Otherwise we might end up inserting them into the quals of
2687 * the main query. We must also check for aggregates in the targetlist in
2688 * case they appear without a GROUP BY.
2689 *
2690 * These restrictions ensure that each row of the view corresponds to a
2691 * unique row in the underlying base relation.
2692 */
2693 if (viewquery->hasAggs)
2694 return gettext_noop("Views that return aggregate functions are not automatically updatable.");
2695
2696 if (viewquery->hasWindowFuncs)
2697 return gettext_noop("Views that return window functions are not automatically updatable.");
2698
2699 if (viewquery->hasTargetSRFs)
2700 return gettext_noop("Views that return set-returning functions are not automatically updatable.");
2701
2702 /*
2703 * The view query should select from a single base relation, which must be
2704 * a table or another view.
2705 */
2706 if (list_length(viewquery->jointree->fromlist) != 1)
2707 return gettext_noop("Views that do not select from a single table or view are not automatically updatable.");
2708
2709 rtr = (RangeTblRef *) linitial(viewquery->jointree->fromlist);
2710 if (!IsA(rtr, RangeTblRef))
2711 return gettext_noop("Views that do not select from a single table or view are not automatically updatable.");
2712
2713 base_rte = rt_fetch(rtr->rtindex, viewquery->rtable);
2714 if (base_rte->rtekind != RTE_RELATION ||
2715 (base_rte->relkind != RELKIND_RELATION &&
2716 base_rte->relkind != RELKIND_FOREIGN_TABLE &&
2717 base_rte->relkind != RELKIND_VIEW &&
2718 base_rte->relkind != RELKIND_PARTITIONED_TABLE))
2719 return gettext_noop("Views that do not select from a single table or view are not automatically updatable.");
2720
2721 if (base_rte->tablesample)
2722 return gettext_noop("Views containing TABLESAMPLE are not automatically updatable.");
2723
2724 /*
2725 * Check that the view has at least one updatable column. This is required
2726 * for INSERT/UPDATE but not for DELETE.
2727 */
2728 if (check_cols)
2729 {
2730 ListCell *cell;
2731 bool found;
2732
2733 found = false;
2734 foreach(cell, viewquery->targetList)
2735 {
2736 TargetEntry *tle = (TargetEntry *) lfirst(cell);
2737
2738 if (view_col_is_auto_updatable(rtr, tle) == NULL)
2739 {
2740 found = true;
2741 break;
2742 }
2743 }
2744
2745 if (!found)
2746 return gettext_noop("Views that have no updatable columns are not automatically updatable.");
2747 }
2748
2749 return NULL; /* the view is updatable */
2750}
#define gettext_noop(x)
Definition: c.h:1153
static const char * view_col_is_auto_updatable(RangeTblRef *rtr, TargetEntry *tle)
Node * limitCount
Definition: parsenodes.h:225
Node * setOperations
Definition: parsenodes.h:230
List * groupClause
Definition: parsenodes.h:211
Node * havingQual
Definition: parsenodes.h:216
Node * limitOffset
Definition: parsenodes.h:224
List * groupingSets
Definition: parsenodes.h:214
List * distinctClause
Definition: parsenodes.h:220
struct TableSampleClause * tablesample
Definition: parsenodes.h:1107

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

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