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

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

◆ build_column_default()

Node * build_column_default ( Relation  rel,
int  attrno 
)

Definition at line 1231 of file rewriteHandler.c.

1232{
1233 TupleDesc rd_att = rel->rd_att;
1234 Form_pg_attribute att_tup = TupleDescAttr(rd_att, attrno - 1);
1235 Oid atttype = att_tup->atttypid;
1236 int32 atttypmod = att_tup->atttypmod;
1237 Node *expr = NULL;
1238 Oid exprtype;
1239
1240 if (att_tup->attidentity)
1241 {
1243
1244 nve->seqid = getIdentitySequence(rel, attrno, false);
1245 nve->typeId = att_tup->atttypid;
1246
1247 return (Node *) nve;
1248 }
1249
1250 /*
1251 * If relation has a default for this column, fetch that expression.
1252 */
1253 if (att_tup->atthasdef)
1254 {
1255 expr = TupleDescGetDefault(rd_att, attrno);
1256 if (expr == NULL)
1257 elog(ERROR, "default expression not found for attribute %d of relation \"%s\"",
1258 attrno, RelationGetRelationName(rel));
1259 }
1260
1261 /*
1262 * No per-column default, so look for a default for the type itself. But
1263 * not for generated columns.
1264 */
1265 if (expr == NULL && !att_tup->attgenerated)
1266 expr = get_typdefault(atttype);
1267
1268 if (expr == NULL)
1269 return NULL; /* No default anywhere */
1270
1271 /*
1272 * Make sure the value is coerced to the target column type; this will
1273 * generally be true already, but there seem to be some corner cases
1274 * involving domain defaults where it might not be true. This should match
1275 * the parser's processing of non-defaulted expressions --- see
1276 * transformAssignedExpr().
1277 */
1278 exprtype = exprType(expr);
1279
1280 expr = coerce_to_target_type(NULL, /* no UNKNOWN params here */
1281 expr, exprtype,
1282 atttype, atttypmod,
1285 -1);
1286 if (expr == NULL)
1287 ereport(ERROR,
1288 (errcode(ERRCODE_DATATYPE_MISMATCH),
1289 errmsg("column \"%s\" is of type %s"
1290 " but default expression is of type %s",
1291 NameStr(att_tup->attname),
1292 format_type_be(atttype),
1293 format_type_be(exprtype)),
1294 errhint("You will need to rewrite or cast the expression.")));
1295
1296 return expr;
1297}
#define NameStr(name)
Definition: c.h:754
int32_t int32
Definition: c.h:537
int errhint(const char *fmt,...)
Definition: elog.c:1330
int errcode(int sqlerrcode)
Definition: elog.c:863
int errmsg(const char *fmt,...)
Definition: elog.c:1080
#define ereport(elevel,...)
Definition: elog.h:150
char * format_type_be(Oid type_oid)
Definition: format_type.c:343
Node * get_typdefault(Oid typid)
Definition: lsyscache.c:2615
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
#define makeNode(_type_)
Definition: nodes.h:161
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:79
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:202
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:768
@ COERCION_ASSIGNMENT
Definition: primnodes.h:747
#define RelationGetRelationName(relation)
Definition: rel.h:549
TupleDesc rd_att
Definition: rel.h:112
Node * TupleDescGetDefault(TupleDesc tupdesc, AttrNumber attnum)
Definition: tupdesc.c:1092
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition: tupdesc.h:160

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(), build_generation_expression(), ExecInitGenerated(), rewriteTargetListIU(), rewriteValuesRTE(), and slot_fill_defaults().

◆ build_generation_expression()

Node * build_generation_expression ( Relation  rel,
int  attrno 
)

Definition at line 4521 of file rewriteHandler.c.

4522{
4523 TupleDesc rd_att = RelationGetDescr(rel);
4524 Form_pg_attribute att_tup = TupleDescAttr(rd_att, attrno - 1);
4525 Node *defexpr;
4526 Oid attcollid;
4527
4528 Assert(rd_att->constr && rd_att->constr->has_generated_virtual);
4529 Assert(att_tup->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL);
4530
4531 defexpr = build_column_default(rel, attrno);
4532 if (defexpr == NULL)
4533 elog(ERROR, "no generation expression found for column number %d of table \"%s\"",
4534 attrno, RelationGetRelationName(rel));
4535
4536 /*
4537 * If the column definition has a collation and it is different from the
4538 * collation of the generation expression, put a COLLATE clause around the
4539 * expression.
4540 */
4541 attcollid = att_tup->attcollation;
4542 if (attcollid && attcollid != exprCollation(defexpr))
4543 {
4545
4546 ce->arg = (Expr *) defexpr;
4547 ce->collOid = attcollid;
4548 ce->location = -1;
4549
4550 defexpr = (Node *) ce;
4551 }
4552
4553 return defexpr;
4554}
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:821
#define RelationGetDescr(relation)
Definition: rel.h:541
Node * build_column_default(Relation rel, int attrno)
Expr * arg
Definition: primnodes.h:1312
ParseLoc location
Definition: primnodes.h:1314
bool has_generated_virtual
Definition: tupdesc.h:47
TupleConstr * constr
Definition: tupdesc.h:141

References CollateExpr::arg, Assert(), build_column_default(), CollateExpr::collOid, TupleDescData::constr, elog, ERROR, exprCollation(), TupleConstr::has_generated_virtual, CollateExpr::location, makeNode, RelationGetDescr, RelationGetRelationName, and TupleDescAttr().

Referenced by ExecRelGenVirtualNotNull(), expand_generated_columns_internal(), and expand_virtual_generated_columns().

◆ error_view_not_updatable()

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

Definition at line 3122 of file rewriteHandler.c.

3126{
3127 TriggerDesc *trigDesc = view->trigdesc;
3128
3129 switch (command)
3130 {
3131 case CMD_INSERT:
3132 ereport(ERROR,
3133 errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3134 errmsg("cannot insert into view \"%s\"",
3136 detail ? errdetail_internal("%s", _(detail)) : 0,
3137 errhint("To enable inserting into the view, provide an INSTEAD OF INSERT trigger or an unconditional ON INSERT DO INSTEAD rule."));
3138 break;
3139 case CMD_UPDATE:
3140 ereport(ERROR,
3141 errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3142 errmsg("cannot update view \"%s\"",
3144 detail ? errdetail_internal("%s", _(detail)) : 0,
3145 errhint("To enable updating the view, provide an INSTEAD OF UPDATE trigger or an unconditional ON UPDATE DO INSTEAD rule."));
3146 break;
3147 case CMD_DELETE:
3148 ereport(ERROR,
3149 errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3150 errmsg("cannot delete from view \"%s\"",
3152 detail ? errdetail_internal("%s", _(detail)) : 0,
3153 errhint("To enable deleting from the view, provide an INSTEAD OF DELETE trigger or an unconditional ON DELETE DO INSTEAD rule."));
3154 break;
3155 case CMD_MERGE:
3156
3157 /*
3158 * Note that the error hints here differ from above, since MERGE
3159 * doesn't support rules.
3160 */
3161 foreach_node(MergeAction, action, mergeActionList)
3162 {
3163 switch (action->commandType)
3164 {
3165 case CMD_INSERT:
3166 if (!trigDesc || !trigDesc->trig_insert_instead_row)
3167 ereport(ERROR,
3168 errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3169 errmsg("cannot insert into view \"%s\"",
3171 detail ? errdetail_internal("%s", _(detail)) : 0,
3172 errhint("To enable inserting into the view using MERGE, provide an INSTEAD OF INSERT trigger."));
3173 break;
3174 case CMD_UPDATE:
3175 if (!trigDesc || !trigDesc->trig_update_instead_row)
3176 ereport(ERROR,
3177 errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3178 errmsg("cannot update view \"%s\"",
3180 detail ? errdetail_internal("%s", _(detail)) : 0,
3181 errhint("To enable updating the view using MERGE, provide an INSTEAD OF UPDATE trigger."));
3182 break;
3183 case CMD_DELETE:
3184 if (!trigDesc || !trigDesc->trig_delete_instead_row)
3185 ereport(ERROR,
3186 errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3187 errmsg("cannot delete from view \"%s\"",
3189 detail ? errdetail_internal("%s", _(detail)) : 0,
3190 errhint("To enable deleting from the view using MERGE, provide an INSTEAD OF DELETE trigger."));
3191 break;
3192 case CMD_NOTHING:
3193 break;
3194 default:
3195 elog(ERROR, "unrecognized commandType: %d", action->commandType);
3196 break;
3197 }
3198 }
3199 break;
3200 default:
3201 elog(ERROR, "unrecognized CmdType: %d", (int) command);
3202 break;
3203 }
3204}
int errdetail_internal(const char *fmt,...)
Definition: elog.c:1243
#define _(x)
Definition: elog.c:91
@ 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: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().

◆ expand_generated_columns_in_expr()

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

Definition at line 4495 of file rewriteHandler.c.

4496{
4497 TupleDesc tupdesc = RelationGetDescr(rel);
4498
4499 if (tupdesc->constr && tupdesc->constr->has_generated_virtual)
4500 {
4501 RangeTblEntry *rte;
4502
4503 rte = makeNode(RangeTblEntry);
4504 /* eref needs to be set, but the actual name doesn't matter */
4505 rte->eref = makeAlias(RelationGetRelationName(rel), NIL);
4506 rte->rtekind = RTE_RELATION;
4507 rte->relid = RelationGetRelid(rel);
4508
4509 node = expand_generated_columns_internal(node, rel, rt_index, rte, 0);
4510 }
4511
4512 return node;
4513}
Alias * makeAlias(const char *aliasname, List *colnames)
Definition: makefuncs.c:438
#define RelationGetRelid(relation)
Definition: rel.h:515
static Node * expand_generated_columns_internal(Node *node, Relation rel, int rt_index, RangeTblEntry *rte, int result_relation)

References TupleDescData::constr, expand_generated_columns_internal(), TupleConstr::has_generated_virtual, makeAlias(), makeNode, NIL, RelationGetDescr, RelationGetRelationName, RelationGetRelid, RTE_RELATION, and RangeTblEntry::rtekind.

Referenced by ATPrepAlterColumnType(), ATRewriteTable(), ExecRelCheck(), get_relation_constraints(), pgoutput_row_filter_init(), QueueCheckConstraintValidation(), TransformPubWhereClauses(), and TriggerEnabled().

◆ get_view_query()

Query * get_view_query ( Relation  view)

Definition at line 2485 of file rewriteHandler.c.

2486{
2487 int i;
2488
2489 Assert(view->rd_rel->relkind == RELKIND_VIEW);
2490
2491 for (i = 0; i < view->rd_rules->numLocks; i++)
2492 {
2493 RewriteRule *rule = view->rd_rules->rules[i];
2494
2495 if (rule->event == CMD_SELECT)
2496 {
2497 /* A _RETURN rule should have only one action */
2498 if (list_length(rule->actions) != 1)
2499 elog(ERROR, "invalid _RETURN rule action specification");
2500
2501 return (Query *) linitial(rule->actions);
2502 }
2503 }
2504
2505 elog(ERROR, "failed to find _RETURN rule for view");
2506 return NULL; /* keep compiler quiet */
2507}
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
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 4567 of file rewriteHandler.c.

4568{
4569 int64 input_query_id = parsetree->queryId;
4570 List *querylist;
4571 List *results;
4572 ListCell *l;
4573 CmdType origCmdType;
4574 bool foundOriginalQuery;
4575 Query *lastInstead;
4576
4577 /*
4578 * This function is only applied to top-level original queries
4579 */
4580 Assert(parsetree->querySource == QSRC_ORIGINAL);
4581 Assert(parsetree->canSetTag);
4582
4583 /*
4584 * Step 1
4585 *
4586 * Apply all non-SELECT rules possibly getting 0 or many queries
4587 */
4588 querylist = RewriteQuery(parsetree, NIL, 0, 0);
4589
4590 /*
4591 * Step 2
4592 *
4593 * Apply all the RIR rules on each query
4594 *
4595 * This is also a handy place to mark each query with the original queryId
4596 */
4597 results = NIL;
4598 foreach(l, querylist)
4599 {
4600 Query *query = (Query *) lfirst(l);
4601
4602 query = fireRIRrules(query, NIL);
4603
4604 query->queryId = input_query_id;
4605
4606 results = lappend(results, query);
4607 }
4608
4609 /*
4610 * Step 3
4611 *
4612 * Determine which, if any, of the resulting queries is supposed to set
4613 * the command-result tag; and update the canSetTag fields accordingly.
4614 *
4615 * If the original query is still in the list, it sets the command tag.
4616 * Otherwise, the last INSTEAD query of the same kind as the original is
4617 * allowed to set the tag. (Note these rules can leave us with no query
4618 * setting the tag. The tcop code has to cope with this by setting up a
4619 * default tag based on the original un-rewritten query.)
4620 *
4621 * The Asserts verify that at most one query in the result list is marked
4622 * canSetTag. If we aren't checking asserts, we can fall out of the loop
4623 * as soon as we find the original query.
4624 */
4625 origCmdType = parsetree->commandType;
4626 foundOriginalQuery = false;
4627 lastInstead = NULL;
4628
4629 foreach(l, results)
4630 {
4631 Query *query = (Query *) lfirst(l);
4632
4633 if (query->querySource == QSRC_ORIGINAL)
4634 {
4635 Assert(query->canSetTag);
4636 Assert(!foundOriginalQuery);
4637 foundOriginalQuery = true;
4638#ifndef USE_ASSERT_CHECKING
4639 break;
4640#endif
4641 }
4642 else
4643 {
4644 Assert(!query->canSetTag);
4645 if (query->commandType == origCmdType &&
4646 (query->querySource == QSRC_INSTEAD_RULE ||
4647 query->querySource == QSRC_QUAL_INSTEAD_RULE))
4648 lastInstead = query;
4649 }
4650 }
4651
4652 if (!foundOriginalQuery && lastInstead != NULL)
4653 lastInstead->canSetTag = true;
4654
4655 return results;
4656}
int64_t int64
Definition: c.h:538
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, 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 2867 of file rewriteHandler.c.

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

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

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

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

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