#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;
}
1.7.1