diff options
author | Tom Lane | 2005-06-03 23:05:30 +0000 |
---|---|---|
committer | Tom Lane | 2005-06-03 23:05:30 +0000 |
commit | 54ecd00ef4e0c9ffc445b83b874753511414f85f (patch) | |
tree | 50678ee68d966655eb8cdd28d228203f82c33add | |
parent | 8c761b674503bef91201c17a96411eb70cfe10f9 (diff) |
Revise handling of dropped columns in JOIN alias lists to avoid a
performance problem pointed out by phil@vodafone: to wit, we were
spending O(N^2) time to check dropped-ness in an N-deep join tree,
even in the case where the tree was freshly constructed and couldn't
possibly mention any dropped columns. Instead of recursing in
get_rte_attribute_is_dropped(), change the data structure definition:
the joinaliasvars list of a JOIN RTE must have a NULL Const instead
of a Var at any position that references a now-dropped column. This
costs nothing during normal parse-rewrite-plan path, and instead we
have a linear-time update to make when loading a stored rule that
might contain now-dropped columns. While at it, move the responsibility
for acquring locks on relations referenced by rules into this separate
function (which I therefore chose to call AcquireRewriteLocks).
This saves effort --- namely, duplicated lock grabs in parser and rewriter
--- in the normal path at a cost of one extra non-locked heap_open()
in the stored-rule path; seems a good tradeoff. A fringe benefit is
that it is now *much* clearer that we acquire lock on relations referenced
in rules before we make any rewriter decisions based on their properties.
(I don't know of any bug of that ilk, but it wasn't exactly clear before.)
-rw-r--r-- | src/backend/commands/explain.c | 8 | ||||
-rw-r--r-- | src/backend/commands/portalcmds.c | 1 | ||||
-rw-r--r-- | src/backend/commands/prepare.c | 1 | ||||
-rw-r--r-- | src/backend/optimizer/util/var.c | 4 | ||||
-rw-r--r-- | src/backend/parser/parse_relation.c | 43 | ||||
-rw-r--r-- | src/backend/rewrite/rewriteHandler.c | 250 | ||||
-rw-r--r-- | src/backend/tcop/postgres.c | 6 | ||||
-rw-r--r-- | src/backend/utils/adt/ruleutils.c | 15 | ||||
-rw-r--r-- | src/include/nodes/parsenodes.h | 10 | ||||
-rw-r--r-- | src/include/parser/parsetree.h | 4 | ||||
-rw-r--r-- | src/include/rewrite/rewriteHandler.h | 1 | ||||
-rw-r--r-- | src/include/tcop/tcopprot.h | 1 |
12 files changed, 266 insertions, 78 deletions
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c index 685aa2cebe..30c4cca731 100644 --- a/src/backend/commands/explain.c +++ b/src/backend/commands/explain.c @@ -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 bfeaeea17e..f3ad0d1c58 100644 --- a/src/backend/commands/portalcmds.c +++ b/src/backend/commands/portalcmds.c @@ -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 9801417570..079e7423b0 100644 --- a/src/backend/commands/prepare.c +++ b/src/backend/commands/prepare.c @@ -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 d6c75c6299..97814c744c 100644 --- a/src/backend/optimizer/util/var.c +++ b/src/backend/optimizer/util/var.c @@ -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 799b13fccb..8f3ca765d8 100644 --- a/src/backend/parser/parse_relation.c +++ b/src/backend/parser/parse_relation.c @@ -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 f3362aeb27..3fe76d2750 100644 --- a/src/backend/rewrite/rewriteHandler.c +++ b/src/backend/rewrite/rewriteHandler.c @@ -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, @@ -58,6 +59,181 @@ 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 * the triggering query). @@ -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 d3625b79bf..b20de077cd 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -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 8fad5a0e75..3de011c37b 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -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 ad3eed096d..a69d1b3ad5 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -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 2b35f8d100..fec3e35a82 100644 --- a/src/include/parser/parsetree.h +++ b/src/include/parser/parsetree.h @@ -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 9f609993b8..3dfefa38a6 100644 --- a/src/include/rewrite/rewriteHandler.h +++ b/src/include/rewrite/rewriteHandler.h @@ -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 7248cc7177..331c006bb3 100644 --- a/src/include/tcop/tcopprot.h +++ b/src/include/tcop/tcopprot.h @@ -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); |