#include "utils/relcache.h"
#include "nodes/parsenodes.h"
Go to the source code of this file.
Functions | |
List * | QueryRewrite (Query *parsetree) |
void | AcquireRewriteLocks (Query *parsetree, bool forUpdatePushedDown) |
Node * | build_column_default (Relation rel, int attrno) |
bool | relation_is_updatable (Oid reloid, int req_events) |
Definition at line 103 of file rewriteHandler.c.
References acquireLocksOnSubLinks(), AcquireRewriteLocks(), Assert, Query::cteList, CommonTableExpr::ctequery, elog, ERROR, get_parse_rowmark(), get_rte_attribute_is_dropped(), Query::hasSubLinks, heap_close, heap_open(), INT4OID, InvalidOid, IsA, RangeTblEntry::joinaliasvars, lappend(), lfirst, makeNullConst(), NoLock, NULL, QTW_IGNORE_RC_SUBQUERIES, query_tree_walker(), RelationData::rd_rel, RangeTblEntry::relid, RangeTblEntry::relkind, Query::resultRelation, RowShareLock, rt_fetch, Query::rtable, RTE_JOIN, RTE_RELATION, RTE_SUBQUERY, RangeTblEntry::rtekind, RangeTblEntry::subquery, Var::varattno, Var::varlevelsup, and Var::varno.
Referenced by acquireLocksOnSubLinks(), AcquireRewriteLocks(), ApplyRetrieveRule(), get_query_def(), make_ruledef(), and rewriteRuleAction().
{ ListCell *l; int rt_index; /* * First, process RTEs of the current query level. */ rt_index = 0; foreach(l, parsetree->rtable) { RangeTblEntry *rte = (RangeTblEntry *) lfirst(l); Relation rel; LOCKMODE lockmode; List *newaliasvars; Index curinputvarno; RangeTblEntry *curinputrte; ListCell *ll; ++rt_index; switch (rte->rtekind) { case RTE_RELATION: /* * Grab the appropriate lock type for the relation, and do not * release it until end of transaction. This protects the * rewriter and planner against schema changes mid-query. * * If the relation is the query's result relation, then we * need RowExclusiveLock. Otherwise, check to see if the * relation is accessed FOR [KEY] UPDATE/SHARE or not. We can't * just grab AccessShareLock because then the executor would * be trying to upgrade the lock, leading to possible * deadlocks. */ if (rt_index == parsetree->resultRelation) lockmode = RowExclusiveLock; else if (forUpdatePushedDown || get_parse_rowmark(parsetree, rt_index) != NULL) lockmode = RowShareLock; else lockmode = AccessShareLock; rel = heap_open(rte->relid, lockmode); /* * While we have the relation open, update the RTE's relkind, * just in case it changed since this rule was made. */ rte->relkind = rel->rd_rel->relkind; heap_close(rel, NoLock); break; case RTE_JOIN: /* * Scan the join's alias var list to see if any columns have * been dropped, and if so replace those Vars with NULL * Consts. * * Since a join has only two inputs, we can expect to see * multiple references to the same input RTE; optimize away * multiple fetches. */ newaliasvars = NIL; curinputvarno = 0; curinputrte = NULL; foreach(ll, rte->joinaliasvars) { Var *aliasvar = (Var *) lfirst(ll); /* * If the list item isn't a simple Var, then it must * represent a merged column, ie a USING column, and so it * couldn't possibly be dropped, since it's referenced in * the join clause. (Conceivably it could also be a NULL * constant already? But that's OK too.) */ if (IsA(aliasvar, Var)) { /* * The elements of an alias list have to refer to * earlier RTEs of the same rtable, because that's the * order the planner builds things in. So we already * processed the referenced RTE, and so it's safe to * use get_rte_attribute_is_dropped on it. (This might * not hold after rewriting or planning, but it's OK * to assume here.) */ Assert(aliasvar->varlevelsup == 0); if (aliasvar->varno != curinputvarno) { curinputvarno = aliasvar->varno; if (curinputvarno >= rt_index) elog(ERROR, "unexpected varno %d in JOIN RTE %d", curinputvarno, rt_index); curinputrte = rt_fetch(curinputvarno, parsetree->rtable); } if (get_rte_attribute_is_dropped(curinputrte, aliasvar->varattno)) { /* * can't use vartype here, since that might be a * now-dropped type OID, but it doesn't really * matter what type the Const claims to be. */ aliasvar = (Var *) makeNullConst(INT4OID, -1, InvalidOid); } } newaliasvars = lappend(newaliasvars, aliasvar); } rte->joinaliasvars = newaliasvars; break; case RTE_SUBQUERY: /* * The subquery RTE itself is all right, but we have to * recurse to process the represented subquery. */ AcquireRewriteLocks(rte->subquery, (forUpdatePushedDown || get_parse_rowmark(parsetree, rt_index) != NULL)); break; default: /* ignore other types of RTEs */ break; } } /* Recurse into subqueries in WITH */ foreach(l, parsetree->cteList) { CommonTableExpr *cte = (CommonTableExpr *) lfirst(l); AcquireRewriteLocks((Query *) cte->ctequery, false); } /* * Recurse into sublink subqueries, too. But we already did the ones in * the rtable and cteList. */ if (parsetree->hasSubLinks) query_tree_walker(parsetree, acquireLocksOnSubLinks, NULL, QTW_IGNORE_RC_SUBQUERIES); }
Definition at line 974 of file rewriteHandler.c.
References tupleDesc::attrs, COERCE_IMPLICIT_CAST, coerce_to_target_type(), COERCION_ASSIGNMENT, tupleDesc::constr, tupleConstr::defval, ereport, errcode(), errhint(), errmsg(), ERROR, exprType(), format_type_be(), get_typdefault(), NameStr, NULL, tupleConstr::num_defval, RelationData::rd_att, and stringToNode().
Referenced by ATExecAddColumn(), ATExecAlterColumnType(), BeginCopyFrom(), rewriteTargetListIU(), and rewriteValuesRTE().
{ TupleDesc rd_att = rel->rd_att; Form_pg_attribute att_tup = rd_att->attrs[attrno - 1]; Oid atttype = att_tup->atttypid; int32 atttypmod = att_tup->atttypmod; Node *expr = NULL; Oid exprtype; /* * Scan to see if relation has a default for this column. */ if (rd_att->constr && rd_att->constr->num_defval > 0) { AttrDefault *defval = rd_att->constr->defval; int ndef = rd_att->constr->num_defval; while (--ndef >= 0) { if (attrno == defval[ndef].adnum) { /* * Found it, convert string representation to node tree. */ expr = stringToNode(defval[ndef].adbin); break; } } } if (expr == NULL) { /* * No per-column default, so look for a default for the type itself. */ expr = get_typdefault(atttype); } if (expr == NULL) return NULL; /* No default anywhere */ /* * Make sure the value is coerced to the target column type; this will * generally be true already, but there seem to be some corner cases * involving domain defaults where it might not be true. This should match * the parser's processing of non-defaulted expressions --- see * transformAssignedExpr(). */ exprtype = exprType(expr); expr = coerce_to_target_type(NULL, /* no UNKNOWN params here */ expr, exprtype, atttype, atttypmod, COERCION_ASSIGNMENT, COERCE_IMPLICIT_CAST, -1); if (expr == NULL) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("column \"%s\" is of type %s" " but default expression is of type %s", NameStr(att_tup->attname), format_type_be(atttype), format_type_be(exprtype)), errhint("You will need to rewrite or cast the expression."))); return expr; }
Definition at line 2854 of file rewriteHandler.c.
References Assert, Query::canSetTag, Query::commandType, fireRIRrules(), lappend(), lfirst, NIL, NULL, QSRC_INSTEAD_RULE, QSRC_ORIGINAL, QSRC_QUAL_INSTEAD_RULE, Query::queryId, Query::querySource, and RewriteQuery().
Referenced by ExecCreateTableAs(), ExplainOneUtility(), ExplainQuery(), pg_rewrite_query(), PrepareQuery(), and refresh_matview_datafill().
{ uint32 input_query_id = parsetree->queryId; List *querylist; List *results; ListCell *l; CmdType origCmdType; bool foundOriginalQuery; Query *lastInstead; /* * This function is only applied to top-level original queries */ Assert(parsetree->querySource == QSRC_ORIGINAL); Assert(parsetree->canSetTag); /* * Step 1 * * Apply all non-SELECT rules possibly getting 0 or many queries */ querylist = RewriteQuery(parsetree, NIL); /* * Step 2 * * Apply all the RIR rules on each query * * This is also a handy place to mark each query with the original queryId */ results = NIL; foreach(l, querylist) { Query *query = (Query *) lfirst(l); query = fireRIRrules(query, NIL, false); query->queryId = input_query_id; results = lappend(results, query); } /* * Step 3 * * Determine which, if any, of the resulting queries is supposed to set * the command-result tag; and update the canSetTag fields accordingly. * * If the original query is still in the list, it sets the command tag. * Otherwise, the last INSTEAD query of the same kind as the original is * allowed to set the tag. (Note these rules can leave us with no query * setting the tag. The tcop code has to cope with this by setting up a * default tag based on the original un-rewritten query.) * * The Asserts verify that at most one query in the result list is marked * canSetTag. If we aren't checking asserts, we can fall out of the loop * as soon as we find the original query. */ origCmdType = parsetree->commandType; foundOriginalQuery = false; lastInstead = NULL; foreach(l, results) { Query *query = (Query *) lfirst(l); if (query->querySource == QSRC_ORIGINAL) { Assert(query->canSetTag); Assert(!foundOriginalQuery); foundOriginalQuery = true; #ifndef USE_ASSERT_CHECKING break; #endif } else { Assert(!query->canSetTag); if (query->commandType == origCmdType && (query->querySource == QSRC_INSTEAD_RULE || query->querySource == QSRC_QUAL_INSTEAD_RULE)) lastInstead = query; } } if (!foundOriginalQuery && lastInstead != NULL) lastInstead->canSetTag = true; return results; }
Definition at line 2083 of file rewriteHandler.c.
References AccessShareLock, RewriteRule::event, FromExpr::fromlist, get_view_query(), i, RewriteRule::isInstead, Query::jointree, linitial, NULL, RuleLock::numLocks, RewriteRule::qual, RelationData::rd_rel, RelationData::rd_rules, relation_close(), relation_is_updatable(), RangeTblEntry::relid, RangeTblEntry::relkind, RELKIND_RELATION, RELKIND_VIEW, rt_fetch, Query::rtable, RangeTblRef::rtindex, RuleLock::rules, try_relation_open(), and view_is_auto_updatable().
Referenced by pg_view_is_insertable(), pg_view_is_updatable(), and relation_is_updatable().
{ Relation rel; RuleLock *rulelocks; rel = try_relation_open(reloid, AccessShareLock); /* * If the relation doesn't exist, say "false" rather than throwing an * error. This is helpful since scanning an information_schema view * under MVCC rules can result in referencing rels that were just * deleted according to a SnapshotNow probe. */ if (rel == NULL) return false; /* Look for unconditional DO INSTEAD rules, and note supported events */ rulelocks = rel->rd_rules; if (rulelocks != NULL) { int events = 0; int i; for (i = 0; i < rulelocks->numLocks; i++) { if (rulelocks->rules[i]->isInstead && rulelocks->rules[i]->qual == NULL) { events |= 1 << rulelocks->rules[i]->event; } } /* If we have all rules needed, say "yes" */ if ((events & req_events) == req_events) { relation_close(rel, AccessShareLock); return true; } } /* Check if this is an automatically updatable view */ if (rel->rd_rel->relkind == RELKIND_VIEW && view_is_auto_updatable(rel) == NULL) { Query *viewquery; RangeTblRef *rtr; RangeTblEntry *base_rte; Oid baseoid; /* The base relation must also be updatable */ viewquery = get_view_query(rel); rtr = (RangeTblRef *) linitial(viewquery->jointree->fromlist); base_rte = rt_fetch(rtr->rtindex, viewquery->rtable); if (base_rte->relkind == RELKIND_RELATION) { /* Tables are always updatable */ relation_close(rel, AccessShareLock); return true; } else { /* Do a recursive check for any other kind of base relation */ baseoid = base_rte->relid; relation_close(rel, AccessShareLock); return relation_is_updatable(baseoid, req_events); } } /* If we reach here, the relation is not updatable */ relation_close(rel, AccessShareLock); return false; }