diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c index d3dfe9edf7e53510d90dc56041a46728510d3d43..af3b5fb0f5b995e7c16d9705e686f9a71d1fc5ae 100644 --- a/src/backend/commands/explain.c +++ b/src/backend/commands/explain.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994-5, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.135 2005/04/25 01:30:12 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.136 2005/06/03 23:05:28 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -100,6 +100,12 @@ ExplainQuery(ExplainStmt *stmt, DestReceiver *dest) } else { + /* + * Must acquire locks in case we didn't come fresh from the parser. + * XXX this also scribbles on query, another reason for copyObject + */ + AcquireRewriteLocks(query); + /* Rewrite through rule system */ rewritten = QueryRewrite(query); @@ -166,6 +172,8 @@ ExplainOneQuery(Query *query, ExplainStmt *stmt, TupOutputState *tstate) cursorOptions = dcstmt->options; /* Still need to rewrite cursor command */ Assert(query->commandType == CMD_SELECT); + /* get locks (we assume ExplainQuery already copied tree) */ + AcquireRewriteLocks(query); rewritten = QueryRewrite(query); if (list_length(rewritten) != 1) elog(ERROR, "unexpected rewrite result"); diff --git a/src/backend/commands/portalcmds.c b/src/backend/commands/portalcmds.c index affbe2b3e4998b579fc48f46a9718876b7cc107c..0ff536661360462dcf43b8955bed2b60b92197db 100644 --- a/src/backend/commands/portalcmds.c +++ b/src/backend/commands/portalcmds.c @@ -14,7 +14,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/portalcmds.c,v 1.41 2005/04/28 21:47:11 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/portalcmds.c,v 1.42 2005/06/03 23:05:28 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -76,6 +76,7 @@ PerformCursorOpen(DeclareCursorStmt *stmt, ParamListInfo params) * query, so we are not expecting rule rewriting to do anything * strange. */ + AcquireRewriteLocks(query); rewritten = QueryRewrite(query); if (list_length(rewritten) != 1 || !IsA(linitial(rewritten), Query)) elog(ERROR, "unexpected rewrite result"); diff --git a/src/backend/commands/prepare.c b/src/backend/commands/prepare.c index 16aae6869388b75caf6d1c272b5c789834e70ca2..be3416bd3e5bbdc32ba8569ba562a9f1869add19 100644 --- a/src/backend/commands/prepare.c +++ b/src/backend/commands/prepare.c @@ -10,7 +10,7 @@ * Copyright (c) 2002-2005, PostgreSQL Global Development Group * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.38 2005/05/29 04:23:03 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.39 2005/06/03 23:05:28 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -99,6 +99,7 @@ PrepareQuery(PrepareStmt *stmt) query = copyObject(stmt->query); /* Rewrite the query. The result could be 0, 1, or many queries. */ + AcquireRewriteLocks(query); query_list = QueryRewrite(query); /* Generate plans for queries. Snapshot is already set. */ diff --git a/src/backend/optimizer/util/var.c b/src/backend/optimizer/util/var.c index 3a6e7b216a9ec17c09f026172241870500eecc31..a95f7dcd76325889613937d3fa26d30939f729c5 100644 --- a/src/backend/optimizer/util/var.c +++ b/src/backend/optimizer/util/var.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/util/var.c,v 1.63 2004/12/31 22:00:23 pgsql Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/util/var.c,v 1.64 2005/06/03 23:05:28 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -524,9 +524,7 @@ flatten_join_alias_vars_mutator(Node *node, newvar = (Node *) lfirst(l); attnum++; /* Ignore dropped columns */ - if (get_rte_attribute_is_dropped(context->root->rtable, - var->varno, - attnum)) + if (IsA(newvar, Const)) continue; /* diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c index bb32ebdf1c1d20642194d93c13cd87ad9af0fc3e..25205d8894e9f9157d8b9400b2f218661c3988ae 100644 --- a/src/backend/parser/parse_relation.c +++ b/src/backend/parser/parse_relation.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.108 2005/05/29 17:10:23 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.109 2005/06/03 23:05:28 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1202,8 +1202,7 @@ addImplicitRTE(ParseState *pstate, RangeVar *relation) * results. If include_dropped is TRUE then empty strings and NULL constants * (not Vars!) are returned for dropped columns. * - * The target RTE is the rtindex'th entry of rtable. (The whole rangetable - * must be passed since we need it to determine dropped-ness for JOIN columns.) + * The target RTE is the rtindex'th entry of rtable. * sublevels_up is the varlevelsup value to use in the created Vars. * * The output lists go into *colnames and *colvars. @@ -1358,6 +1357,8 @@ expandRTE(List *rtable, int rtindex, int sublevels_up, varattno = 0; forboth(colname, rte->eref->colnames, aliasvar, rte->joinaliasvars) { + Node *avar = (Node *) lfirst(aliasvar); + varattno++; /* @@ -1365,26 +1366,19 @@ expandRTE(List *rtable, int rtindex, int sublevels_up, * deleted columns in the join; but we have to check * since this routine is also used by the rewriter, * and joins found in stored rules might have join - * columns for since-deleted columns. + * columns for since-deleted columns. This will be + * signaled by a NULL Const in the alias-vars list. */ - if (get_rte_attribute_is_dropped(rtable, rtindex, - varattno)) + if (IsA(avar, Const)) { if (include_dropped) { if (colnames) *colnames = lappend(*colnames, - makeString(pstrdup(""))); + makeString(pstrdup(""))); if (colvars) - { - /* - * can't use atttypid here, but it doesn't - * really matter what type the Const - * claims to be. - */ *colvars = lappend(*colvars, - makeNullConst(INT4OID)); - } + copyObject(avar)); } continue; } @@ -1399,7 +1393,6 @@ expandRTE(List *rtable, int rtindex, int sublevels_up, if (colvars) { - Node *avar = (Node *) lfirst(aliasvar); Var *varnode; varnode = makeVar(rtindex, varattno, @@ -1711,9 +1704,8 @@ get_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum, * Check whether attempted attribute ref is to a dropped column */ bool -get_rte_attribute_is_dropped(List *rtable, int rtindex, AttrNumber attnum) +get_rte_attribute_is_dropped(RangeTblEntry *rte, AttrNumber attnum) { - RangeTblEntry *rte = rt_fetch(rtindex, rtable); bool result; switch (rte->rtekind) @@ -1750,8 +1742,8 @@ get_rte_attribute_is_dropped(List *rtable, int rtindex, AttrNumber attnum) * constructed, but one in a stored rule might contain * columns that were dropped from the underlying tables, * if said columns are nowhere explicitly referenced in - * the rule. So we have to recursively look at the - * referenced column. + * the rule. This will be signaled to us by a NULL Const + * in the joinaliasvars list. */ Var *aliasvar; @@ -1760,18 +1752,7 @@ get_rte_attribute_is_dropped(List *rtable, int rtindex, AttrNumber attnum) elog(ERROR, "invalid varattno %d", attnum); aliasvar = (Var *) list_nth(rte->joinaliasvars, attnum - 1); - /* - * 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). - */ - if (!IsA(aliasvar, Var)) - result = false; - else - result = get_rte_attribute_is_dropped(rtable, - aliasvar->varno, - aliasvar->varattno); + result = IsA(aliasvar, Const); } break; case RTE_FUNCTION: diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c index 73c8dbab12740b7834141c48410ff3ab38a9296d..3c267ccdcd25b039b2b6242e892acecce0335d53 100644 --- a/src/backend/rewrite/rewriteHandler.c +++ b/src/backend/rewrite/rewriteHandler.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/rewrite/rewriteHandler.c,v 1.152 2005/05/29 18:34:57 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/rewrite/rewriteHandler.c,v 1.153 2005/06/03 23:05:28 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -40,6 +40,7 @@ typedef struct rewrite_event CmdType event; /* type of rule being fired */ } rewrite_event; +static bool acquireLocksOnSubLinks(Node *node, void *context); static Query *rewriteRuleAction(Query *parsetree, Query *rule_action, Node *rule_qual, @@ -57,6 +58,181 @@ static List *matchLocks(CmdType event, RuleLock *rulelocks, static Query *fireRIRrules(Query *parsetree, List *activeRIRs); +/* + * AcquireRewriteLocks - + * Acquire suitable locks on all the relations mentioned in the Query. + * These locks will ensure that the relation schemas don't change under us + * while we are rewriting and planning the query. + * + * A secondary purpose of this routine is to fix up JOIN RTE references to + * dropped columns (see details below). Because the RTEs are modified in + * place, it is generally appropriate for the caller of this routine to have + * first done a copyObject() to make a writable copy of the querytree in the + * current memory context. + * + * This processing can, and for efficiency's sake should, be skipped when the + * querytree has just been built by the parser: parse analysis already got + * all the same locks we'd get here, and the parser will have omitted dropped + * columns from JOINs to begin with. But we must do this whenever we are + * dealing with a querytree produced earlier than the current command. + * + * About JOINs and dropped columns: although the parser never includes an + * already-dropped column in a JOIN RTE's alias var list, it is possible for + * such a list in a stored rule to include references to dropped columns. + * (If the column is not explicitly referenced anywhere else in the query, + * the dependency mechanism won't consider it used by the rule and so won't + * prevent the column drop.) To support get_rte_attribute_is_dropped(), + * we replace join alias vars that reference dropped columns with NULL Const + * nodes. + * + * (In PostgreSQL 8.0, we did not do this processing but instead had + * get_rte_attribute_is_dropped() recurse to detect dropped columns in joins. + * That approach had horrible performance unfortunately; in particular + * construction of a nested join was O(N^2) in the nesting depth.) + */ +void +AcquireRewriteLocks(Query *parsetree) +{ + 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; + 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 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 (list_member_int(parsetree->rowMarks, rt_index)) + lockmode = RowShareLock; + else + lockmode = AccessShareLock; + + rel = heap_open(rte->relid, lockmode); + 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. + */ + newaliasvars = NIL; + 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 >= rt_index) + elog(ERROR, "unexpected varno %d in JOIN RTE %d", + aliasvar->varno, rt_index); + if (get_rte_attribute_is_dropped( + rt_fetch(aliasvar->varno, parsetree->rtable), + 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); + } + } + 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); + break; + + default: + /* ignore other types of RTEs */ + break; + } + } + + /* + * Recurse into sublink subqueries, too. But we already did the ones + * in the rtable. + */ + if (parsetree->hasSubLinks) + query_tree_walker(parsetree, acquireLocksOnSubLinks, NULL, + QTW_IGNORE_RT_SUBQUERIES); +} + +/* + * Walker to find sublink subqueries for AcquireRewriteLocks + */ +static bool +acquireLocksOnSubLinks(Node *node, void *context) +{ + if (node == NULL) + return false; + if (IsA(node, SubLink)) + { + SubLink *sub = (SubLink *) node; + + /* Do what we came for */ + AcquireRewriteLocks((Query *) sub->subselect); + /* Fall through to process lefthand args of SubLink */ + } + + /* + * Do NOT recurse into Query nodes, because AcquireRewriteLocks already + * processed subselects of subselects for us. + */ + return expression_tree_walker(node, acquireLocksOnSubLinks, context); +} + + /* * rewriteRuleAction - * Rewrite the rule action with appropriate qualifiers (taken from @@ -82,6 +258,12 @@ rewriteRuleAction(Query *parsetree, rule_action = (Query *) copyObject(rule_action); rule_qual = (Node *) copyObject(rule_qual); + /* + * Acquire necessary locks and fix any deleted JOIN RTE entries. + */ + AcquireRewriteLocks(rule_action); + (void) acquireLocksOnSubLinks(rule_qual, NULL); + current_varno = rt_index; rt_length = list_length(parsetree->rtable); new_varno = PRS2_NEW_VARNO + rt_length; @@ -693,6 +875,9 @@ matchLocks(CmdType event, } +/* + * ApplyRetrieveRule - expand an ON SELECT rule + */ static Query * ApplyRetrieveRule(Query *parsetree, RewriteRule *rule, @@ -713,11 +898,16 @@ ApplyRetrieveRule(Query *parsetree, elog(ERROR, "cannot handle per-attribute ON SELECT rule"); /* - * Make a modifiable copy of the view query, and recursively expand - * any view references inside it. + * Make a modifiable copy of the view query, and acquire needed locks + * on the relations it mentions. */ rule_action = copyObject(linitial(rule->actions)); + AcquireRewriteLocks(rule_action); + + /* + * Recursively expand any view references inside the view. + */ rule_action = fireRIRrules(rule_action, activeRIRs); /* @@ -868,7 +1058,6 @@ fireRIRrules(Query *parsetree, List *activeRIRs) List *locks; RuleLock *rules; RewriteRule *rule; - LOCKMODE lockmode; int i; ++rt_index; @@ -904,26 +1093,10 @@ fireRIRrules(Query *parsetree, List *activeRIRs) continue; /* - * This may well be the first access to the relation during the - * current statement (it will be, if this Query was extracted from - * a rule or somehow got here other than via the parser). - * Therefore, 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 - * RewriteQuery() already got the right lock on it, so we need no - * additional lock. Otherwise, check to see if the relation is - * accessed FOR UPDATE/SHARE or not. + * We can use NoLock here since either the parser or + * AcquireRewriteLocks should have locked the rel already. */ - if (rt_index == parsetree->resultRelation) - lockmode = NoLock; - else if (list_member_int(parsetree->rowMarks, rt_index)) - lockmode = RowShareLock; - else - lockmode = AccessShareLock; - - rel = heap_open(rte->relid, lockmode); + rel = heap_open(rte->relid, NoLock); /* * Collect the RIR rules that we must apply @@ -1015,9 +1188,17 @@ CopyAndAddInvertedQual(Query *parsetree, int rt_index, CmdType event) { - Query *new_tree = (Query *) copyObject(parsetree); + /* Don't scribble on the passed qual (it's in the relcache!) */ Node *new_qual = (Node *) copyObject(rule_qual); + /* + * In case there are subqueries in the qual, acquire necessary locks and + * fix any deleted JOIN RTE entries. (This is somewhat redundant with + * rewriteRuleAction, but not entirely ... consider restructuring so + * that we only need to process the qual this way once.) + */ + (void) acquireLocksOnSubLinks(new_qual, NULL); + /* Fix references to OLD */ ChangeVarNodes(new_qual, PRS2_OLD_VARNO, rt_index, 0); /* Fix references to NEW */ @@ -1030,9 +1211,9 @@ CopyAndAddInvertedQual(Query *parsetree, event, rt_index); /* And attach the fixed qual */ - AddInvertedQual(new_tree, new_qual); + AddInvertedQual(parsetree, new_qual); - return new_tree; + return parsetree; } @@ -1112,7 +1293,7 @@ fireRules(Query *parsetree, if (!*instead_flag) { if (*qual_product == NULL) - *qual_product = parsetree; + *qual_product = copyObject(parsetree); *qual_product = CopyAndAddInvertedQual(*qual_product, event_qual, rt_index, @@ -1177,15 +1358,10 @@ RewriteQuery(Query *parsetree, List *rewrite_events) Assert(rt_entry->rtekind == RTE_RELATION); /* - * This may well be the first access to the result relation during - * the current statement (it will be, if this Query was extracted - * from a rule or somehow got here other than via the parser). - * Therefore, grab the appropriate lock type for a result - * relation, and do not release it until end of transaction. This - * protects the rewriter and planner against schema changes - * mid-query. + * We can use NoLock here since either the parser or + * AcquireRewriteLocks should have locked the rel already. */ - rt_entry_relation = heap_open(rt_entry->relid, RowExclusiveLock); + rt_entry_relation = heap_open(rt_entry->relid, NoLock); /* * If it's an INSERT or UPDATE, rewrite the targetlist into @@ -1251,7 +1427,7 @@ RewriteQuery(Query *parsetree, List *rewrite_events) } } - heap_close(rt_entry_relation, NoLock); /* keep lock! */ + heap_close(rt_entry_relation, NoLock); } /* @@ -1295,8 +1471,8 @@ RewriteQuery(Query *parsetree, List *rewrite_events) * Rewrite one query via query rewrite system, possibly returning 0 * or many queries. * - * NOTE: The code in QueryRewrite was formerly in pg_parse_and_plan(), and was - * moved here so that it would be invoked during EXPLAIN. + * NOTE: the parsetree must either have come straight from the parser, + * or have been scanned by AcquireRewriteLocks to acquire suitable locks. */ List * QueryRewrite(Query *parsetree) diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 297eb75d8909812306771919b39254ca0d0eecc8..58b1ffbce9aa4890777df5beb724b16a0f54f38d 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.446 2005/06/02 21:03:24 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.447 2005/06/03 23:05:29 tgl Exp $ * * NOTES * this is the "main" module of the postgres backend and @@ -158,6 +158,7 @@ static int SocketBackend(StringInfo inBuf); static int ReadCommand(StringInfo inBuf); static bool log_after_parse(List *raw_parsetree_list, const char *query_string, char **prepare_string); +static List *pg_rewrite_queries(List *querytree_list); static void start_xact_command(void); static void finish_xact_command(void); static void SigHupHandler(SIGNAL_ARGS); @@ -642,8 +643,11 @@ pg_analyze_and_rewrite(Node *parsetree, Oid *paramTypes, int numParams) /* * Perform rewriting of a list of queries produced by parse analysis. + * + * Note: queries must just have come from the parser, because we do not do + * AcquireRewriteLocks() on them. */ -List * +static List * pg_rewrite_queries(List *querytree_list) { List *new_list = NIL; diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index be53f7373d9ce5274941e9a3cd6c53fe4d52a592..c6de4df714a2600f0fcbc78f554230bb4e5bdc39 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -3,7 +3,7 @@ * back to source text * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.198 2005/05/31 03:03:59 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.199 2005/06/03 23:05:29 tgl Exp $ * * This software is copyrighted by Jan Wieck - Hamburg. * @@ -67,6 +67,7 @@ #include "parser/parse_oper.h" #include "parser/parse_type.h" #include "parser/parsetree.h" +#include "rewrite/rewriteHandler.h" #include "rewrite/rewriteManip.h" #include "rewrite/rewriteSupport.h" #include "utils/array.h" @@ -1661,6 +1662,9 @@ make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc, */ query = getInsertSelectQuery(query, NULL); + /* Must acquire locks right away; see notes in get_query_def() */ + AcquireRewriteLocks(query); + context.buf = buf; context.namespaces = list_make1(&dpns); context.varprefix = (list_length(query->rtable) != 1); @@ -1795,6 +1799,14 @@ get_query_def(Query *query, StringInfo buf, List *parentnamespace, deparse_context context; deparse_namespace dpns; + /* + * Before we begin to examine the query, acquire locks on referenced + * relations, and fix up deleted columns in JOIN RTEs. This ensures + * consistent results. Note we assume it's OK to scribble on the + * passed querytree! + */ + AcquireRewriteLocks(query); + context.buf = buf; context.namespaces = lcons(&dpns, list_copy(parentnamespace)); context.varprefix = (parentnamespace != NIL || @@ -4245,6 +4257,7 @@ get_from_clause_alias(Alias *alias, int varno, Query *query, deparse_context *context) { StringInfo buf = context->buf; + RangeTblEntry *rte = rt_fetch(varno, query->rtable); ListCell *col; AttrNumber attnum; bool first = true; @@ -4256,7 +4269,7 @@ get_from_clause_alias(Alias *alias, int varno, foreach(col, alias->colnames) { attnum++; - if (get_rte_attribute_is_dropped(query->rtable, varno, attnum)) + if (get_rte_attribute_is_dropped(rte, attnum)) continue; if (first) { diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 97d5df935ac13cd4052a6d581e6faf870c63aadd..1208def12ce63674683d0bce0c19a62e92726e6b 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.278 2005/04/28 21:47:17 tgl Exp $ + * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.279 2005/06/03 23:05:29 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -465,7 +465,10 @@ typedef struct DefElem * those columns are known to be dropped at parse time. Again, however, * a stored rule might contain entries for columns dropped since the rule * was created. (This is only possible for columns not actually referenced - * in the rule.) + * in the rule.) When loading a stored rule, we replace the joinaliasvars + * items for any such columns with NULL Consts. (We can't simply delete + * them from the joinaliasvars list, because that would affect the attnums + * of Vars referencing the rest of the list.) * * inh is TRUE for relation references that should be expanded to include * inheritance children, if the rel has any. This *must* be FALSE for @@ -535,7 +538,10 @@ typedef struct RangeTblEntry * to the columns of the join result. An alias Var referencing column * K of the join result can be replaced by the K'th element of * joinaliasvars --- but to simplify the task of reverse-listing - * aliases correctly, we do not do that until planning time. + * aliases correctly, we do not do that until planning time. In a Query + * loaded from a stored rule, it is also possible for joinaliasvars + * items to be NULL Consts, denoting columns dropped since the rule was + * made. */ JoinType jointype; /* type of join */ List *joinaliasvars; /* list of alias-var expansions */ diff --git a/src/include/parser/parsetree.h b/src/include/parser/parsetree.h index c6911e9a2f8a1d505c908a4d9d538e1c8ebf4e79..c1997bb787ca4c5b9891156c11f2ffbf9b974b40 100644 --- a/src/include/parser/parsetree.h +++ b/src/include/parser/parsetree.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/parser/parsetree.h,v 1.29 2004/12/31 22:03:38 pgsql Exp $ + * $PostgreSQL: pgsql/src/include/parser/parsetree.h,v 1.30 2005/06/03 23:05:30 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -59,8 +59,8 @@ extern void get_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum, * Check whether an attribute of an RTE has been dropped (note that * get_rte_attribute_type will fail on such an attr) */ -extern bool get_rte_attribute_is_dropped(List *rtable, int rtindex, - AttrNumber attnum); +extern bool get_rte_attribute_is_dropped(RangeTblEntry *rte, + AttrNumber attnum); /* ---------------- diff --git a/src/include/rewrite/rewriteHandler.h b/src/include/rewrite/rewriteHandler.h index 566ab62c759525928fbb464bd5c911ed0aaef082..478dbdd0bab0366380659f7337a11fa6547073c3 100644 --- a/src/include/rewrite/rewriteHandler.h +++ b/src/include/rewrite/rewriteHandler.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/rewrite/rewriteHandler.h,v 1.24 2004/12/31 22:03:41 pgsql Exp $ + * $PostgreSQL: pgsql/src/include/rewrite/rewriteHandler.h,v 1.25 2005/06/03 23:05:30 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -17,6 +17,7 @@ #include "nodes/parsenodes.h" extern List *QueryRewrite(Query *parsetree); +extern void AcquireRewriteLocks(Query *parsetree); extern Node *build_column_default(Relation rel, int attrno); #endif /* REWRITEHANDLER_H */ diff --git a/src/include/tcop/tcopprot.h b/src/include/tcop/tcopprot.h index 23b338e7ae1ba7469e904387b7752b87e14fbaf2..d694146d59ae1e69105df913d0dd602f31adc89a 100644 --- a/src/include/tcop/tcopprot.h +++ b/src/include/tcop/tcopprot.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/tcop/tcopprot.h,v 1.74 2005/06/02 21:03:25 tgl Exp $ + * $PostgreSQL: pgsql/src/include/tcop/tcopprot.h,v 1.75 2005/06/03 23:05:30 tgl Exp $ * * OLD COMMENTS * This file was created so that other c files could get the two @@ -48,7 +48,6 @@ extern List *pg_parse_and_rewrite(const char *query_string, extern List *pg_parse_query(const char *query_string); extern List *pg_analyze_and_rewrite(Node *parsetree, Oid *paramTypes, int numParams); -extern List *pg_rewrite_queries(List *querytree_list); extern Plan *pg_plan_query(Query *querytree, ParamListInfo boundParams); extern List *pg_plan_queries(List *querytrees, ParamListInfo boundParams, bool needSnapshot);