From a4996a895399a4b0363c7dace71fc6ce8acbc196 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Sun, 5 Jun 2005 00:38:11 +0000 Subject: [PATCH] Replace the parser's namespace tree (which formerly had the same representation as the jointree) with two lists of RTEs, one showing the RTEs accessible by qualified names, and the other showing the RTEs accessible by unqualified names. I think this is conceptually simpler than what we did before, and it's sure a whole lot easier to search. This seems to eliminate the parse-time bottleneck for deeply nested JOIN structures that was exhibited by phil@vodafone. --- src/backend/catalog/heap.c | 4 +- src/backend/commands/tablecmds.c | 4 +- src/backend/parser/analyze.c | 82 +++---- src/backend/parser/parse_clause.c | 297 ++++++++++++++---------- src/backend/parser/parse_relation.c | 348 ++++++---------------------- src/backend/parser/parse_target.c | 50 ++-- src/backend/utils/adt/ruleutils.c | 10 +- src/include/nodes/parsenodes.h | 12 +- src/include/parser/parse_node.h | 24 +- src/include/parser/parse_relation.h | 9 +- 10 files changed, 341 insertions(+), 499 deletions(-) diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index 530cca8be8..8c6f6bec25 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.284 2005/04/14 20:03:23 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.285 2005/06/05 00:38:07 tgl Exp $ * * * INTERFACE ROUTINES @@ -1486,7 +1486,7 @@ AddRelationRawConstraints(Relation rel, NULL, false, true); - addRTEtoQuery(pstate, rte, true, true); + addRTEtoQuery(pstate, rte, true, true, true); /* * Process column default expressions. diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 4335792ee7..c7669dfc58 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.159 2005/05/30 07:20:58 neilc Exp $ + * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.160 2005/06/05 00:38:08 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -4720,7 +4720,7 @@ ATPrepAlterColumnType(List **wqueue, NULL, false, true); - addRTEtoQuery(pstate, rte, false, true); + addRTEtoQuery(pstate, rte, false, true, true); transform = transformExpr(pstate, cmd->transform); diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c index ee6bfe6ae9..1c8fe6cf77 100644 --- a/src/backend/parser/analyze.c +++ b/src/backend/parser/analyze.c @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.321 2005/04/28 21:47:14 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.322 2005/06/05 00:38:09 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -512,7 +512,8 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt, Query *qry = makeNode(Query); Query *selectQuery = NULL; List *sub_rtable; - List *sub_namespace; + List *sub_relnamespace; + List *sub_varnamespace; List *icolumns; List *attrnos; ListCell *icols; @@ -528,20 +529,23 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt, * SELECT. This can only happen if we are inside a CREATE RULE, and * in that case we want the rule's OLD and NEW rtable entries to * appear as part of the SELECT's rtable, not as outer references for - * it. (Kluge!) The SELECT's joinlist is not affected however. We + * it. (Kluge!) The SELECT's joinlist is not affected however. We * must do this before adding the target table to the INSERT's rtable. */ if (stmt->selectStmt) { sub_rtable = pstate->p_rtable; pstate->p_rtable = NIL; - sub_namespace = pstate->p_namespace; - pstate->p_namespace = NIL; + sub_relnamespace = pstate->p_relnamespace; + pstate->p_relnamespace = NIL; + sub_varnamespace = pstate->p_varnamespace; + pstate->p_varnamespace = NIL; } else { sub_rtable = NIL; /* not used, but keep compiler quiet */ - sub_namespace = NIL; + sub_relnamespace = NIL; + sub_varnamespace = NIL; } /* @@ -578,7 +582,8 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt, * through 6.5 had bugs of just that nature...) */ sub_pstate->p_rtable = sub_rtable; - sub_pstate->p_namespace = sub_namespace; + sub_pstate->p_relnamespace = sub_relnamespace; + sub_pstate->p_varnamespace = sub_varnamespace; /* * Note: we are not expecting that extras_before and extras_after @@ -605,7 +610,7 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt, rte = addRangeTableEntryForSubquery(pstate, selectQuery, makeAlias("*SELECT*", NIL), - true); + false); rtr = makeNode(RangeTblRef); /* assume new rte is at end */ rtr->rtindex = list_length(pstate->p_rtable); @@ -1481,8 +1486,8 @@ transformIndexStmt(ParseState *pstate, IndexStmt *stmt) */ rte = addRangeTableEntry(pstate, stmt->relation, NULL, false, true); - /* no to join list, yes to namespace */ - addRTEtoQuery(pstate, rte, false, true); + /* no to join list, yes to namespaces */ + addRTEtoQuery(pstate, rte, false, true, true); stmt->whereClause = transformWhereClause(pstate, stmt->whereClause, "WHERE"); @@ -1500,8 +1505,8 @@ transformIndexStmt(ParseState *pstate, IndexStmt *stmt) { rte = addRangeTableEntry(pstate, stmt->relation, NULL, false, true); - /* no to join list, yes to namespace */ - addRTEtoQuery(pstate, rte, false, true); + /* no to join list, yes to namespaces */ + addRTEtoQuery(pstate, rte, false, true, true); } ielem->expr = transformExpr(pstate, ielem->expr); @@ -1559,10 +1564,10 @@ transformRuleStmt(ParseState *pstate, RuleStmt *stmt, Assert(pstate->p_rtable == NIL); oldrte = addRangeTableEntryForRelation(pstate, rel, makeAlias("*OLD*", NIL), - false, true); + false, false); newrte = addRangeTableEntryForRelation(pstate, rel, makeAlias("*NEW*", NIL), - false, true); + false, false); /* Must override addRangeTableEntry's default access-check flags */ oldrte->requiredPerms = 0; newrte->requiredPerms = 0; @@ -1572,24 +1577,22 @@ transformRuleStmt(ParseState *pstate, RuleStmt *stmt, * the one(s) that are relevant for the current kind of rule. In an * UPDATE rule, quals must refer to OLD.field or NEW.field to be * unambiguous, but there's no need to be so picky for INSERT & - * DELETE. (Note we marked the RTEs "inFromCl = true" above to allow - * unqualified references to their fields.) We do not add them to the - * joinlist. + * DELETE. We do not add them to the joinlist. */ switch (stmt->event) { case CMD_SELECT: - addRTEtoQuery(pstate, oldrte, false, true); + addRTEtoQuery(pstate, oldrte, false, true, true); break; case CMD_UPDATE: - addRTEtoQuery(pstate, oldrte, false, true); - addRTEtoQuery(pstate, newrte, false, true); + addRTEtoQuery(pstate, oldrte, false, true, true); + addRTEtoQuery(pstate, newrte, false, true, true); break; case CMD_INSERT: - addRTEtoQuery(pstate, newrte, false, true); + addRTEtoQuery(pstate, newrte, false, true, true); break; case CMD_DELETE: - addRTEtoQuery(pstate, oldrte, false, true); + addRTEtoQuery(pstate, oldrte, false, true, true); break; default: elog(ERROR, "unrecognized event type: %d", @@ -1651,10 +1654,9 @@ transformRuleStmt(ParseState *pstate, RuleStmt *stmt, /* * Set up OLD/NEW in the rtable for this statement. The - * entries are marked not inFromCl because we don't want them - * to be referred to by unqualified field names nor "*" in the - * rule actions. We must add them to the namespace, however, - * or they won't be accessible at all. We decide later + * entries are added only to relnamespace, not varnamespace, + * because we don't want them to be referred to by unqualified + * field names nor "*" in the rule actions. We decide later * whether to put them in the joinlist. */ oldrte = addRangeTableEntryForRelation(sub_pstate, rel, @@ -1665,8 +1667,8 @@ transformRuleStmt(ParseState *pstate, RuleStmt *stmt, false, false); oldrte->requiredPerms = 0; newrte->requiredPerms = 0; - addRTEtoQuery(sub_pstate, oldrte, false, true); - addRTEtoQuery(sub_pstate, newrte, false, true); + addRTEtoQuery(sub_pstate, oldrte, false, true, false); + addRTEtoQuery(sub_pstate, newrte, false, true, false); /* Transform the rule action statement */ top_subqry = transformStmt(sub_pstate, action, @@ -1776,7 +1778,7 @@ transformRuleStmt(ParseState *pstate, RuleStmt *stmt, /* hack so we can use addRTEtoQuery() */ sub_pstate->p_rtable = sub_qry->rtable; sub_pstate->p_joinlist = sub_qry->jointree->fromlist; - addRTEtoQuery(sub_pstate, oldrte, true, false); + addRTEtoQuery(sub_pstate, oldrte, true, false, false); sub_qry->jointree->fromlist = sub_pstate->p_joinlist; } @@ -1906,10 +1908,10 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt) *dtlist; List *targetvars, *targetnames, - *sv_namespace, + *sv_relnamespace, + *sv_varnamespace, *sv_rtable; RangeTblEntry *jrte; - RangeTblRef *jrtr; int tllen; qry->commandType = CMD_SELECT; @@ -2027,7 +2029,7 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt) /* * As a first step towards supporting sort clauses that are - * expressions using the output columns, generate a namespace entry + * expressions using the output columns, generate a varnamespace entry * that makes the output columns visible. A Join RTE node is handy * for this, since we can easily control the Vars generated upon * matches. @@ -2041,15 +2043,16 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt) JOIN_INNER, targetvars, NULL, - true); - jrtr = makeNode(RangeTblRef); - jrtr->rtindex = 1; /* only entry in dummy rtable */ + false); sv_rtable = pstate->p_rtable; pstate->p_rtable = list_make1(jrte); - sv_namespace = pstate->p_namespace; - pstate->p_namespace = list_make1(jrtr); + sv_relnamespace = pstate->p_relnamespace; + pstate->p_relnamespace = NIL; /* no qualified names allowed */ + + sv_varnamespace = pstate->p_varnamespace; + pstate->p_varnamespace = list_make1(jrte); /* * For now, we don't support resjunk sort clauses on the output of a @@ -2064,8 +2067,9 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt) &qry->targetList, false /* no unknowns expected */ ); - pstate->p_namespace = sv_namespace; pstate->p_rtable = sv_rtable; + pstate->p_relnamespace = sv_relnamespace; + pstate->p_varnamespace = sv_varnamespace; if (tllen != list_length(qry->targetList)) ereport(ERROR, @@ -2164,7 +2168,7 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt) * happen because the namespace will be empty, but it could happen * if we are inside a rule. */ - if (pstate->p_namespace) + if (pstate->p_relnamespace || pstate->p_varnamespace) { if (contain_vars_of_level((Node *) selectQuery, 1)) ereport(ERROR, diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c index 8d282d13e4..593f8f1f4b 100644 --- a/src/backend/parser/parse_clause.c +++ b/src/backend/parser/parse_clause.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.141 2005/06/04 19:19:42 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.142 2005/06/05 00:38:09 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -47,14 +47,19 @@ static void extractRemainingColumns(List *common_colnames, static Node *transformJoinUsingClause(ParseState *pstate, List *leftVars, List *rightVars); static Node *transformJoinOnClause(ParseState *pstate, JoinExpr *j, - List *containedRels); -static RangeTblRef *transformTableEntry(ParseState *pstate, RangeVar *r); -static RangeTblRef *transformRangeSubselect(ParseState *pstate, + RangeTblEntry *l_rte, + RangeTblEntry *r_rte, + List *relnamespace, + Relids containedRels); +static RangeTblEntry *transformTableEntry(ParseState *pstate, RangeVar *r); +static RangeTblEntry *transformRangeSubselect(ParseState *pstate, RangeSubselect *r); -static RangeTblRef *transformRangeFunction(ParseState *pstate, +static RangeTblEntry *transformRangeFunction(ParseState *pstate, RangeFunction *r); static Node *transformFromClauseItem(ParseState *pstate, Node *n, - List **containedRels); + RangeTblEntry **top_rte, int *top_rti, + List **relnamespace, + Relids *containedRels); static Node *buildMergedJoinVar(ParseState *pstate, JoinType jointype, Var *l_colvar, Var *r_colvar); static TargetEntry *findTargetlistEntry(ParseState *pstate, Node *node, @@ -64,12 +69,12 @@ static TargetEntry *findTargetlistEntry(ParseState *pstate, Node *node, /* * transformFromClause - * Process the FROM clause and add items to the query's range table, - * joinlist, and namespace. + * joinlist, and namespaces. * - * Note: we assume that pstate's p_rtable, p_joinlist, and p_namespace lists - * were initialized to NIL when the pstate was created. We will add onto - * any entries already present --- this is needed for rule processing, as - * well as for UPDATE and DELETE. + * Note: we assume that pstate's p_rtable, p_joinlist, p_relnamespace, and + * p_varnamespace lists were initialized to NIL when the pstate was created. + * We will add onto any entries already present --- this is needed for rule + * processing, as well as for UPDATE and DELETE. * * The range table may grow still further when we transform the expressions * in the query's quals and target list. (This is possible because in @@ -85,17 +90,27 @@ transformFromClause(ParseState *pstate, List *frmList) * The grammar will have produced a list of RangeVars, * RangeSubselects, RangeFunctions, and/or JoinExprs. Transform each * one (possibly adding entries to the rtable), check for duplicate - * refnames, and then add it to the joinlist and namespace. + * refnames, and then add it to the joinlist and namespaces. */ foreach(fl, frmList) { Node *n = lfirst(fl); - List *containedRels; - - n = transformFromClauseItem(pstate, n, &containedRels); - checkNameSpaceConflicts(pstate, (Node *) pstate->p_namespace, n); + RangeTblEntry *rte; + int rtindex; + List *relnamespace; + Relids containedRels; + + n = transformFromClauseItem(pstate, n, + &rte, + &rtindex, + &relnamespace, + &containedRels); + checkNameSpaceConflicts(pstate, pstate->p_relnamespace, relnamespace); pstate->p_joinlist = lappend(pstate->p_joinlist, n); - pstate->p_namespace = lappend(pstate->p_namespace, n); + pstate->p_relnamespace = list_concat(pstate->p_relnamespace, + relnamespace); + pstate->p_varnamespace = lappend(pstate->p_varnamespace, rte); + bms_free(containedRels); } } @@ -165,10 +180,10 @@ setTargetTable(ParseState *pstate, RangeVar *relation, rte->requiredPerms = requiredPerms; /* - * If UPDATE/DELETE, add table to joinlist and namespace. + * If UPDATE/DELETE, add table to joinlist and namespaces. */ if (alsoSource) - addRTEtoQuery(pstate, rte, true, true); + addRTEtoQuery(pstate, rte, true, true, true); return rtindex; } @@ -322,10 +337,14 @@ transformJoinUsingClause(ParseState *pstate, List *leftVars, List *rightVars) */ static Node * transformJoinOnClause(ParseState *pstate, JoinExpr *j, - List *containedRels) + RangeTblEntry *l_rte, + RangeTblEntry *r_rte, + List *relnamespace, + Relids containedRels) { Node *result; - List *save_namespace; + List *save_relnamespace; + List *save_varnamespace; Relids clause_varnos; int varno; @@ -339,12 +358,16 @@ transformJoinOnClause(ParseState *pstate, JoinExpr *j, * can't legally alter the namespace by causing implicit relation refs * to be added. */ - save_namespace = pstate->p_namespace; - pstate->p_namespace = list_make2(j->larg, j->rarg); + save_relnamespace = pstate->p_relnamespace; + save_varnamespace = pstate->p_varnamespace; + + pstate->p_relnamespace = relnamespace; + pstate->p_varnamespace = list_make2(l_rte, r_rte); result = transformWhereClause(pstate, j->quals, "JOIN/ON"); - pstate->p_namespace = save_namespace; + pstate->p_relnamespace = save_relnamespace; + pstate->p_varnamespace = save_varnamespace; /* * Second, we need to check that the ON condition doesn't refer to any @@ -355,15 +378,13 @@ transformJoinOnClause(ParseState *pstate, JoinExpr *j, * here.) */ clause_varnos = pull_varnos(result); - while ((varno = bms_first_member(clause_varnos)) >= 0) + clause_varnos = bms_del_members(clause_varnos, containedRels); + if ((varno = bms_first_member(clause_varnos)) >= 0) { - if (!list_member_int(containedRels, varno)) - { - ereport(ERROR, - (errcode(ERRCODE_INVALID_COLUMN_REFERENCE), - errmsg("JOIN/ON clause refers to \"%s\", which is not part of JOIN", - rt_fetch(varno, pstate->p_rtable)->eref->aliasname))); - } + ereport(ERROR, + (errcode(ERRCODE_INVALID_COLUMN_REFERENCE), + errmsg("JOIN/ON clause refers to \"%s\", which is not part of JOIN", + rt_fetch(varno, pstate->p_rtable)->eref->aliasname))); } bms_free(clause_varnos); @@ -373,11 +394,10 @@ transformJoinOnClause(ParseState *pstate, JoinExpr *j, /* * transformTableEntry --- transform a RangeVar (simple relation reference) */ -static RangeTblRef * +static RangeTblEntry * transformTableEntry(ParseState *pstate, RangeVar *r) { RangeTblEntry *rte; - RangeTblRef *rtr; /* * mark this entry to indicate it comes from the FROM clause. In SQL, @@ -389,29 +409,19 @@ transformTableEntry(ParseState *pstate, RangeVar *r) rte = addRangeTableEntry(pstate, r, r->alias, interpretInhOption(r->inhOpt), true); - /* - * We create a RangeTblRef, but we do not add it to the joinlist or - * namespace; our caller must do that if appropriate. - */ - rtr = makeNode(RangeTblRef); - /* assume new rte is at end */ - rtr->rtindex = list_length(pstate->p_rtable); - Assert(rte == rt_fetch(rtr->rtindex, pstate->p_rtable)); - - return rtr; + return rte; } /* * transformRangeSubselect --- transform a sub-SELECT appearing in FROM */ -static RangeTblRef * +static RangeTblEntry * transformRangeSubselect(ParseState *pstate, RangeSubselect *r) { List *parsetrees; Query *query; RangeTblEntry *rte; - RangeTblRef *rtr; /* * We require user to supply an alias for a subselect, per SQL92. To @@ -461,7 +471,7 @@ transformRangeSubselect(ParseState *pstate, RangeSubselect *r) * visible in the current query. Also note that outer references are * OK. */ - if (pstate->p_namespace) + if (pstate->p_relnamespace || pstate->p_varnamespace) { if (contain_vars_of_level((Node *) query, 1)) ereport(ERROR, @@ -474,29 +484,19 @@ transformRangeSubselect(ParseState *pstate, RangeSubselect *r) */ rte = addRangeTableEntryForSubquery(pstate, query, r->alias, true); - /* - * We create a RangeTblRef, but we do not add it to the joinlist or - * namespace; our caller must do that if appropriate. - */ - rtr = makeNode(RangeTblRef); - /* assume new rte is at end */ - rtr->rtindex = list_length(pstate->p_rtable); - Assert(rte == rt_fetch(rtr->rtindex, pstate->p_rtable)); - - return rtr; + return rte; } /* * transformRangeFunction --- transform a function call appearing in FROM */ -static RangeTblRef * +static RangeTblEntry * transformRangeFunction(ParseState *pstate, RangeFunction *r) { Node *funcexpr; char *funcname; RangeTblEntry *rte; - RangeTblRef *rtr; /* * Get function name for possible use as alias. We use the same @@ -520,7 +520,7 @@ transformRangeFunction(ParseState *pstate, RangeFunction *r) * XXX this will need further work to support SQL99's LATERAL() feature, * wherein such references would indeed be legal. */ - if (pstate->p_namespace) + if (pstate->p_relnamespace || pstate->p_varnamespace) { if (contain_vars_of_level(funcexpr, 0)) ereport(ERROR, @@ -558,16 +558,7 @@ transformRangeFunction(ParseState *pstate, RangeFunction *r) rte = addRangeTableEntryForFunction(pstate, funcname, funcexpr, r, true); - /* - * We create a RangeTblRef, but we do not add it to the joinlist or - * namespace; our caller must do that if appropriate. - */ - rtr = makeNode(RangeTblRef); - /* assume new rte is at end */ - rtr->rtindex = list_length(pstate->p_rtable); - Assert(rte == rt_fetch(rtr->rtindex, pstate->p_rtable)); - - return rtr; + return rte; } @@ -575,109 +566,151 @@ transformRangeFunction(ParseState *pstate, RangeFunction *r) * transformFromClauseItem - * Transform a FROM-clause item, adding any required entries to the * range table list being built in the ParseState, and return the - * transformed item ready to include in the joinlist and namespace. + * transformed item ready to include in the joinlist and namespaces. * This routine can recurse to handle SQL92 JOIN expressions. * - * Aside from the primary return value (the transformed joinlist item) - * this routine also returns an integer list of the rangetable indexes - * of all the base and join relations represented in the joinlist item. - * This list is needed for checking JOIN/ON conditions in higher levels. + * The function return value is the node to add to the jointree (a + * RangeTblRef or JoinExpr). Additional output parameters are: + * + * *top_rte: receives the RTE corresponding to the jointree item. + * (We could extract this from the function return node, but it saves cycles + * to pass it back separately.) + * + * *top_rti: receives the rangetable index of top_rte. (Ditto.) + * + * *relnamespace: receives a List of the RTEs exposed as relation names + * by this item. + * + * *containedRels: receives a bitmap set of the rangetable indexes + * of all the base and join relations represented in this jointree item. + * This is needed for checking JOIN/ON conditions in higher levels. + * + * We do not need to pass back an explicit varnamespace value, because + * in all cases the varnamespace contribution is exactly top_rte. */ static Node * -transformFromClauseItem(ParseState *pstate, Node *n, List **containedRels) +transformFromClauseItem(ParseState *pstate, Node *n, + RangeTblEntry **top_rte, int *top_rti, + List **relnamespace, + Relids *containedRels) { if (IsA(n, RangeVar)) { /* Plain relation reference */ RangeTblRef *rtr; + RangeTblEntry *rte; + int rtindex; - rtr = transformTableEntry(pstate, (RangeVar *) n); - *containedRels = list_make1_int(rtr->rtindex); + rte = transformTableEntry(pstate, (RangeVar *) n); + /* assume new rte is at end */ + rtindex = list_length(pstate->p_rtable); + Assert(rte == rt_fetch(rtindex, pstate->p_rtable)); + *top_rte = rte; + *top_rti = rtindex; + *relnamespace = list_make1(rte); + *containedRels = bms_make_singleton(rtindex); + rtr = makeNode(RangeTblRef); + rtr->rtindex = rtindex; return (Node *) rtr; } else if (IsA(n, RangeSubselect)) { /* sub-SELECT is like a plain relation */ RangeTblRef *rtr; + RangeTblEntry *rte; + int rtindex; - rtr = transformRangeSubselect(pstate, (RangeSubselect *) n); - *containedRels = list_make1_int(rtr->rtindex); + rte = transformRangeSubselect(pstate, (RangeSubselect *) n); + /* assume new rte is at end */ + rtindex = list_length(pstate->p_rtable); + Assert(rte == rt_fetch(rtindex, pstate->p_rtable)); + *top_rte = rte; + *top_rti = rtindex; + *relnamespace = list_make1(rte); + *containedRels = bms_make_singleton(rtindex); + rtr = makeNode(RangeTblRef); + rtr->rtindex = rtindex; return (Node *) rtr; } else if (IsA(n, RangeFunction)) { /* function is like a plain relation */ RangeTblRef *rtr; + RangeTblEntry *rte; + int rtindex; - rtr = transformRangeFunction(pstate, (RangeFunction *) n); - *containedRels = list_make1_int(rtr->rtindex); + rte = transformRangeFunction(pstate, (RangeFunction *) n); + /* assume new rte is at end */ + rtindex = list_length(pstate->p_rtable); + Assert(rte == rt_fetch(rtindex, pstate->p_rtable)); + *top_rte = rte; + *top_rti = rtindex; + *relnamespace = list_make1(rte); + *containedRels = bms_make_singleton(rtindex); + rtr = makeNode(RangeTblRef); + rtr->rtindex = rtindex; return (Node *) rtr; } else if (IsA(n, JoinExpr)) { /* A newfangled join expression */ JoinExpr *j = (JoinExpr *) n; - List *my_containedRels, - *l_containedRels, - *r_containedRels, + RangeTblEntry *l_rte; + RangeTblEntry *r_rte; + int l_rtindex; + int r_rtindex; + Relids l_containedRels, + r_containedRels, + my_containedRels; + List *l_relnamespace, + *r_relnamespace, + *my_relnamespace, *l_colnames, *r_colnames, *res_colnames, *l_colvars, *r_colvars, *res_colvars; - Index leftrti, - rightrti; RangeTblEntry *rte; /* * Recursively process the left and right subtrees */ - j->larg = transformFromClauseItem(pstate, j->larg, &l_containedRels); - j->rarg = transformFromClauseItem(pstate, j->rarg, &r_containedRels); - - /* - * Generate combined list of relation indexes for possible use by - * transformJoinOnClause below. - */ - my_containedRels = list_concat(l_containedRels, r_containedRels); + j->larg = transformFromClauseItem(pstate, j->larg, + &l_rte, + &l_rtindex, + &l_relnamespace, + &l_containedRels); + j->rarg = transformFromClauseItem(pstate, j->rarg, + &r_rte, + &r_rtindex, + &r_relnamespace, + &r_containedRels); /* * Check for conflicting refnames in left and right subtrees. Must * do this because higher levels will assume I hand back a self- * consistent namespace subtree. */ - checkNameSpaceConflicts(pstate, j->larg, j->rarg); + checkNameSpaceConflicts(pstate, l_relnamespace, r_relnamespace); + + /* + * Generate combined relation membership info for possible use by + * transformJoinOnClause below. + */ + my_relnamespace = list_concat(l_relnamespace, r_relnamespace); + my_containedRels = bms_join(l_containedRels, r_containedRels); + + pfree(r_relnamespace); /* free unneeded list header */ /* * Extract column name and var lists from both subtrees * * Note: expandRTE returns new lists, safe for me to modify */ - if (IsA(j->larg, RangeTblRef)) - leftrti = ((RangeTblRef *) j->larg)->rtindex; - else if (IsA(j->larg, JoinExpr)) - leftrti = ((JoinExpr *) j->larg)->rtindex; - else - { - elog(ERROR, "unrecognized node type: %d", (int) nodeTag(j->larg)); - leftrti = 0; /* keep compiler quiet */ - } - rte = rt_fetch(leftrti, pstate->p_rtable); - expandRTE(rte, leftrti, 0, false, + expandRTE(l_rte, l_rtindex, 0, false, &l_colnames, &l_colvars); - - if (IsA(j->rarg, RangeTblRef)) - rightrti = ((RangeTblRef *) j->rarg)->rtindex; - else if (IsA(j->rarg, JoinExpr)) - rightrti = ((JoinExpr *) j->rarg)->rtindex; - else - { - elog(ERROR, "unrecognized node type: %d", (int) nodeTag(j->rarg)); - rightrti = 0; /* keep compiler quiet */ - } - rte = rt_fetch(rightrti, pstate->p_rtable); - expandRTE(rte, rightrti, 0, false, + expandRTE(r_rte, r_rtindex, 0, false, &r_colnames, &r_colvars); /* @@ -829,7 +862,10 @@ transformFromClauseItem(ParseState *pstate, Node *n, List **containedRels) else if (j->quals) { /* User-written ON-condition; transform it */ - j->quals = transformJoinOnClause(pstate, j, my_containedRels); + j->quals = transformJoinOnClause(pstate, j, + l_rte, r_rte, + my_relnamespace, + my_containedRels); } else { @@ -877,10 +913,27 @@ transformFromClauseItem(ParseState *pstate, Node *n, List **containedRels) j->rtindex = list_length(pstate->p_rtable); Assert(rte == rt_fetch(j->rtindex, pstate->p_rtable)); + *top_rte = rte; + *top_rti = j->rtindex; + + /* + * Prepare returned namespace list. If the JOIN has an alias + * then it hides the contained RTEs as far as the relnamespace + * goes; otherwise, put the contained RTEs and *not* the JOIN + * into relnamespace. + */ + if (j->alias) + { + *relnamespace = list_make1(rte); + list_free(my_relnamespace); + } + else + *relnamespace = my_relnamespace; + /* - * Include join RTE in returned containedRels list + * Include join RTE in returned containedRels set */ - *containedRels = lcons_int(j->rtindex, my_containedRels); + *containedRels = bms_add_member(my_containedRels, j->rtindex); return (Node *) j; } diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c index 39d18ffbf8..5786ac44d0 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.110 2005/06/04 19:19:42 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.111 2005/06/05 00:38:09 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -34,12 +34,9 @@ /* GUC parameter */ bool add_missing_from; -static Node *scanNameSpaceForRefname(ParseState *pstate, Node *nsnode, - const char *refname); -static Node *scanNameSpaceForRelid(ParseState *pstate, Node *nsnode, - Oid relid); -static void scanNameSpaceForConflict(ParseState *pstate, Node *nsnode, - RangeTblEntry *rte1, const char *aliasname1); +static RangeTblEntry *scanNameSpaceForRefname(ParseState *pstate, + const char *refname); +static RangeTblEntry *scanNameSpaceForRelid(ParseState *pstate, Oid relid); static bool isLockedRel(ParseState *pstate, char *refname); static void expandRelation(Oid relid, Alias *eref, int rtindex, int sublevels_up, @@ -97,188 +94,92 @@ refnameRangeTblEntry(ParseState *pstate, while (pstate != NULL) { - Node *nsnode; + RangeTblEntry *result; if (OidIsValid(relId)) - nsnode = scanNameSpaceForRelid(pstate, - (Node *) pstate->p_namespace, - relId); + result = scanNameSpaceForRelid(pstate, relId); else - nsnode = scanNameSpaceForRefname(pstate, - (Node *) pstate->p_namespace, - refname); + result = scanNameSpaceForRefname(pstate, refname); - if (nsnode) - { - /* should get an RTE or JoinExpr */ - if (IsA(nsnode, RangeTblEntry)) - return (RangeTblEntry *) nsnode; - Assert(IsA(nsnode, JoinExpr)); - return rt_fetch(((JoinExpr *) nsnode)->rtindex, pstate->p_rtable); - } + if (result) + return result; - pstate = pstate->parentParseState; if (sublevels_up) (*sublevels_up)++; else break; + + pstate = pstate->parentParseState; } return NULL; } /* - * Recursively search a namespace for an RTE or joinexpr matching the - * given unqualified refname. Return the node if a unique match, or NULL + * Search the query's table namespace for an RTE matching the + * given unqualified refname. Return the RTE if a unique match, or NULL * if no match. Raise error if multiple matches. - * - * The top level of p_namespace is a list, and we recurse into any joins - * that are not subqueries. */ -static Node * -scanNameSpaceForRefname(ParseState *pstate, Node *nsnode, - const char *refname) +static RangeTblEntry * +scanNameSpaceForRefname(ParseState *pstate, const char *refname) { - Node *result = NULL; - Node *newresult; + RangeTblEntry *result = NULL; + ListCell *l; - if (nsnode == NULL) - return NULL; - if (IsA(nsnode, RangeTblRef)) + foreach(l, pstate->p_relnamespace) { - int varno = ((RangeTblRef *) nsnode)->rtindex; - RangeTblEntry *rte = rt_fetch(varno, pstate->p_rtable); + RangeTblEntry *rte = (RangeTblEntry *) lfirst(l); if (strcmp(rte->eref->aliasname, refname) == 0) - result = (Node *) rte; - } - else if (IsA(nsnode, JoinExpr)) - { - JoinExpr *j = (JoinExpr *) nsnode; - - if (j->alias) { - if (strcmp(j->alias->aliasname, refname) == 0) - return (Node *) j; /* matched a join alias */ - - /* - * Tables within an aliased join are invisible from outside - * the join, according to the scope rules of SQL92 (the join - * is considered a subquery). So, stop here. - */ - return NULL; - } - result = scanNameSpaceForRefname(pstate, j->larg, refname); - newresult = scanNameSpaceForRefname(pstate, j->rarg, refname); - if (!result) - result = newresult; - else if (newresult) - ereport(ERROR, - (errcode(ERRCODE_AMBIGUOUS_ALIAS), - errmsg("table reference \"%s\" is ambiguous", - refname))); - } - else if (IsA(nsnode, List)) - { - ListCell *l; - - foreach(l, (List *) nsnode) - { - newresult = scanNameSpaceForRefname(pstate, lfirst(l), refname); - if (!result) - result = newresult; - else if (newresult) + if (result) ereport(ERROR, (errcode(ERRCODE_AMBIGUOUS_ALIAS), errmsg("table reference \"%s\" is ambiguous", refname))); + result = rte; } } - else - elog(ERROR, "unrecognized node type: %d", (int) nodeTag(nsnode)); return result; } /* - * Recursively search a namespace for a relation RTE matching the - * given relation OID. Return the node if a unique match, or NULL + * Search the query's table namespace for a relation RTE matching the + * given relation OID. Return the RTE if a unique match, or NULL * if no match. Raise error if multiple matches (which shouldn't * happen if the namespace was checked correctly when it was created). * - * The top level of p_namespace is a list, and we recurse into any joins - * that are not subqueries. - * * See the comments for refnameRangeTblEntry to understand why this * acts the way it does. */ -static Node * -scanNameSpaceForRelid(ParseState *pstate, Node *nsnode, Oid relid) +static RangeTblEntry * +scanNameSpaceForRelid(ParseState *pstate, Oid relid) { - Node *result = NULL; - Node *newresult; + RangeTblEntry *result = NULL; + ListCell *l; - if (nsnode == NULL) - return NULL; - if (IsA(nsnode, RangeTblRef)) + foreach(l, pstate->p_relnamespace) { - int varno = ((RangeTblRef *) nsnode)->rtindex; - RangeTblEntry *rte = rt_fetch(varno, pstate->p_rtable); + RangeTblEntry *rte = (RangeTblEntry *) lfirst(l); /* yes, the test for alias==NULL should be there... */ if (rte->rtekind == RTE_RELATION && rte->relid == relid && rte->alias == NULL) - result = (Node *) rte; - } - else if (IsA(nsnode, JoinExpr)) - { - JoinExpr *j = (JoinExpr *) nsnode; - - if (j->alias) { - /* - * Tables within an aliased join are invisible from outside - * the join, according to the scope rules of SQL92 (the join - * is considered a subquery). So, stop here. - */ - return NULL; - } - result = scanNameSpaceForRelid(pstate, j->larg, relid); - newresult = scanNameSpaceForRelid(pstate, j->rarg, relid); - if (!result) - result = newresult; - else if (newresult) - ereport(ERROR, - (errcode(ERRCODE_AMBIGUOUS_ALIAS), - errmsg("table reference %u is ambiguous", - relid))); - } - else if (IsA(nsnode, List)) - { - ListCell *l; - - foreach(l, (List *) nsnode) - { - newresult = scanNameSpaceForRelid(pstate, lfirst(l), relid); - if (!result) - result = newresult; - else if (newresult) + if (result) ereport(ERROR, (errcode(ERRCODE_AMBIGUOUS_ALIAS), errmsg("table reference %u is ambiguous", relid))); + result = rte; } } - else - elog(ERROR, "unrecognized node type: %d", (int) nodeTag(nsnode)); return result; } /* - * Recursively check for name conflicts between two namespaces or - * namespace subtrees. Raise an error if any is found. - * - * Works by recursively scanning namespace1 for RTEs and join nodes, - * and for each one recursively scanning namespace2 for a match. + * Check for relation-name conflicts between two relnamespace lists. + * Raise an error if any is found. * * Note: we assume that each given argument does not contain conflicts * itself; we just want to know if the two can be merged together. @@ -288,108 +189,33 @@ scanNameSpaceForRelid(ParseState *pstate, Node *nsnode, Oid relid) * are for different relation OIDs (implying they are in different schemas). */ void -checkNameSpaceConflicts(ParseState *pstate, Node *namespace1, - Node *namespace2) +checkNameSpaceConflicts(ParseState *pstate, List *namespace1, + List *namespace2) { - if (namespace1 == NULL) - return; - if (IsA(namespace1, RangeTblRef)) - { - int varno = ((RangeTblRef *) namespace1)->rtindex; - RangeTblEntry *rte = rt_fetch(varno, pstate->p_rtable); - - if (rte->rtekind == RTE_RELATION && rte->alias == NULL) - scanNameSpaceForConflict(pstate, namespace2, - rte, rte->eref->aliasname); - else - scanNameSpaceForConflict(pstate, namespace2, - NULL, rte->eref->aliasname); - } - else if (IsA(namespace1, JoinExpr)) - { - JoinExpr *j = (JoinExpr *) namespace1; - - if (j->alias) - { - scanNameSpaceForConflict(pstate, namespace2, - NULL, j->alias->aliasname); - - /* - * Tables within an aliased join are invisible from outside - * the join, according to the scope rules of SQL92 (the join - * is considered a subquery). So, stop here. - */ - return; - } - checkNameSpaceConflicts(pstate, j->larg, namespace2); - checkNameSpaceConflicts(pstate, j->rarg, namespace2); - } - else if (IsA(namespace1, List)) - { - ListCell *l; - - foreach(l, (List *) namespace1) - checkNameSpaceConflicts(pstate, lfirst(l), namespace2); - } - else - elog(ERROR, "unrecognized node type: %d", (int) nodeTag(namespace1)); -} + ListCell *l1; -/* - * Subroutine for checkNameSpaceConflicts: scan namespace2 - */ -static void -scanNameSpaceForConflict(ParseState *pstate, Node *nsnode, - RangeTblEntry *rte1, const char *aliasname1) -{ - if (nsnode == NULL) - return; - if (IsA(nsnode, RangeTblRef)) + foreach(l1, namespace1) { - int varno = ((RangeTblRef *) nsnode)->rtindex; - RangeTblEntry *rte = rt_fetch(varno, pstate->p_rtable); - - if (strcmp(rte->eref->aliasname, aliasname1) != 0) - return; /* definitely no conflict */ - if (rte->rtekind == RTE_RELATION && rte->alias == NULL && - rte1 != NULL && rte->relid != rte1->relid) - return; /* no conflict per SQL92 rule */ - ereport(ERROR, - (errcode(ERRCODE_DUPLICATE_ALIAS), - errmsg("table name \"%s\" specified more than once", - aliasname1))); - } - else if (IsA(nsnode, JoinExpr)) - { - JoinExpr *j = (JoinExpr *) nsnode; + RangeTblEntry *rte1 = (RangeTblEntry *) lfirst(l1); + const char *aliasname1 = rte1->eref->aliasname; + ListCell *l2; - if (j->alias) + foreach(l2, namespace2) { - if (strcmp(j->alias->aliasname, aliasname1) == 0) - ereport(ERROR, - (errcode(ERRCODE_DUPLICATE_ALIAS), + RangeTblEntry *rte2 = (RangeTblEntry *) lfirst(l2); + + if (strcmp(rte2->eref->aliasname, aliasname1) != 0) + continue; /* definitely no conflict */ + if (rte1->rtekind == RTE_RELATION && rte1->alias == NULL && + rte2->rtekind == RTE_RELATION && rte2->alias == NULL && + rte1->relid != rte2->relid) + continue; /* no conflict per SQL92 rule */ + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_ALIAS), errmsg("table name \"%s\" specified more than once", aliasname1))); - - /* - * Tables within an aliased join are invisible from outside - * the join, according to the scope rules of SQL92 (the join - * is considered a subquery). So, stop here. - */ - return; } - scanNameSpaceForConflict(pstate, j->larg, rte1, aliasname1); - scanNameSpaceForConflict(pstate, j->rarg, rte1, aliasname1); } - else if (IsA(nsnode, List)) - { - ListCell *l; - - foreach(l, (List *) nsnode) - scanNameSpaceForConflict(pstate, lfirst(l), rte1, aliasname1); - } - else - elog(ERROR, "unrecognized node type: %d", (int) nodeTag(nsnode)); } /* @@ -541,48 +367,18 @@ colNameToVar(ParseState *pstate, char *colname, bool localonly) { Node *result = NULL; ParseState *orig_pstate = pstate; - int levels_up = 0; while (pstate != NULL) { - ListCell *ns; - - /* - * We need to look only at top-level namespace items, and even for - * those, ignore RTEs that are marked as not inFromCl and not the - * query's target relation. - */ - foreach(ns, pstate->p_namespace) - { - Node *nsnode = (Node *) lfirst(ns); - Node *newresult = NULL; - - if (IsA(nsnode, RangeTblRef)) - { - int varno = ((RangeTblRef *) nsnode)->rtindex; - RangeTblEntry *rte = rt_fetch(varno, pstate->p_rtable); - - if (!rte->inFromCl && - rte != pstate->p_target_rangetblentry) - continue; - - /* use orig_pstate here to get the right sublevels_up */ - newresult = scanRTEForColumn(orig_pstate, rte, colname); - } - else if (IsA(nsnode, JoinExpr)) - { - int varno = ((JoinExpr *) nsnode)->rtindex; - RangeTblEntry *rte = rt_fetch(varno, pstate->p_rtable); + ListCell *l; - /* joins are always inFromCl, so no need to check */ - Assert(rte->inFromCl); + foreach(l, pstate->p_varnamespace) + { + RangeTblEntry *rte = (RangeTblEntry *) lfirst(l); + Node *newresult; - /* use orig_pstate here to get the right sublevels_up */ - newresult = scanRTEForColumn(orig_pstate, rte, colname); - } - else - elog(ERROR, "unrecognized node type: %d", - (int) nodeTag(nsnode)); + /* use orig_pstate here to get the right sublevels_up */ + newresult = scanRTEForColumn(orig_pstate, rte, colname); if (newresult) { @@ -599,7 +395,6 @@ colNameToVar(ParseState *pstate, char *colname, bool localonly) break; /* found, or don't want to look at parent */ pstate = pstate->parentParseState; - levels_up++; } return result; @@ -1136,22 +931,26 @@ isLockedRel(ParseState *pstate, char *refname) /* * Add the given RTE as a top-level entry in the pstate's join list - * and/or name space list. (We assume caller has checked for any - * namespace conflict.) + * and/or name space lists. (We assume caller has checked for any + * namespace conflicts.) */ void addRTEtoQuery(ParseState *pstate, RangeTblEntry *rte, - bool addToJoinList, bool addToNameSpace) + bool addToJoinList, + bool addToRelNameSpace, bool addToVarNameSpace) { - int rtindex = RTERangeTablePosn(pstate, rte, NULL); - RangeTblRef *rtr = makeNode(RangeTblRef); - - rtr->rtindex = rtindex; - if (addToJoinList) + { + int rtindex = RTERangeTablePosn(pstate, rte, NULL); + RangeTblRef *rtr = makeNode(RangeTblRef); + + rtr->rtindex = rtindex; pstate->p_joinlist = lappend(pstate->p_joinlist, rtr); - if (addToNameSpace) - pstate->p_namespace = lappend(pstate->p_namespace, rtr); + } + if (addToRelNameSpace) + pstate->p_relnamespace = lappend(pstate->p_relnamespace, rte); + if (addToVarNameSpace) + pstate->p_varnamespace = lappend(pstate->p_varnamespace, rte); } /* @@ -1166,7 +965,8 @@ addImplicitRTE(ParseState *pstate, RangeVar *relation) RangeTblEntry *rte; rte = addRangeTableEntry(pstate, relation, NULL, false, false); - addRTEtoQuery(pstate, rte, true, true); + /* Add to joinlist and relnamespace, but not varnamespace */ + addRTEtoQuery(pstate, rte, true, true, false); warnAutoRange(pstate, relation); return rte; diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c index 27e818dcbe..dd2c0b4e31 100644 --- a/src/backend/parser/parse_target.c +++ b/src/backend/parser/parse_target.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/parse_target.c,v 1.135 2005/06/04 19:19:42 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_target.c,v 1.136 2005/06/05 00:38:10 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -750,52 +750,32 @@ ExpandColumnRefStar(ParseState *pstate, ColumnRef *cref) * ExpandAllTables() * Turns '*' (in the target list) into a list of targetlist entries. * - * tlist entries are generated for each relation appearing at the top level - * of the query's namespace, except for RTEs marked not inFromCl. (These - * may include NEW/OLD pseudo-entries, implicit RTEs, etc.) + * tlist entries are generated for each relation appearing in the query's + * varnamespace. We do not consider relnamespace because that would include + * input tables of aliasless JOINs, NEW/OLD pseudo-entries, implicit RTEs, + * etc. */ static List * ExpandAllTables(ParseState *pstate) { List *target = NIL; - bool found_table = false; - ListCell *ns; - - foreach(ns, pstate->p_namespace) - { - Node *n = (Node *) lfirst(ns); - int rtindex; - RangeTblEntry *rte; + ListCell *l; - if (IsA(n, RangeTblRef)) - rtindex = ((RangeTblRef *) n)->rtindex; - else if (IsA(n, JoinExpr)) - rtindex = ((JoinExpr *) n)->rtindex; - else - { - elog(ERROR, "unrecognized node type: %d", (int) nodeTag(n)); - rtindex = 0; /* keep compiler quiet */ - } + /* Check for SELECT *; */ + if (!pstate->p_varnamespace) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("SELECT * with no tables specified is not valid"))); - /* - * Ignore added-on relations that were not listed in the FROM - * clause. - */ - rte = rt_fetch(rtindex, pstate->p_rtable); - if (!rte->inFromCl) - continue; + foreach(l, pstate->p_varnamespace) + { + RangeTblEntry *rte = (RangeTblEntry *) lfirst(l); + int rtindex = RTERangeTablePosn(pstate, rte, NULL); - found_table = true; target = list_concat(target, expandRelAttrs(pstate, rte, rtindex, 0)); } - /* Check for SELECT *; */ - if (!found_table) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("SELECT * with no tables specified is not valid"))); - return target; } diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index c6de4df714..bc3e774d64 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.199 2005/06/03 23:05:29 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.200 2005/06/05 00:38:10 tgl Exp $ * * This software is copyrighted by Jan Wieck - Hamburg. * @@ -4009,8 +4009,8 @@ get_from_clause(Query *query, const char *prefix, deparse_context *context) * We use the query's jointree as a guide to what to print. However, * we must ignore auto-added RTEs that are marked not inFromCl. (These * can only appear at the top level of the jointree, so it's - * sufficient to check here.) Also ignore the rule pseudo-RTEs for NEW - * and OLD. + * sufficient to check here.) This check also ensures we ignore + * the rule pseudo-RTEs for NEW and OLD. */ foreach(l, query->jointree->fromlist) { @@ -4023,10 +4023,6 @@ get_from_clause(Query *query, const char *prefix, deparse_context *context) if (!rte->inFromCl) continue; - if (strcmp(rte->eref->aliasname, "*NEW*") == 0) - continue; - if (strcmp(rte->eref->aliasname, "*OLD*") == 0) - continue; } if (first) diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 1208def12c..9a525eb1de 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.279 2005/06/03 23:05:29 tgl Exp $ + * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.280 2005/06/05 00:38:10 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -479,10 +479,10 @@ typedef struct DefElem * FROM clause, but POSTQUEL allows you to refer to tables not listed, * in which case a range table entry will be generated. We still support * this POSTQUEL feature, although there is some doubt whether it's - * convenient or merely confusing. The flag is needed since an - * implicitly-added RTE shouldn't change the namespace for unqualified - * column names processed later, and it also shouldn't affect the - * expansion of '*'. + * convenient or merely confusing. The flag is not actually needed + * anymore during parsing, since the parser uses a separate "namespace" + * data structure to control visibility, but it is needed by ruleutils.c + * to determine whether RTEs should be included in decompiled queries. * * requiredPerms and checkAsUser specify run-time access permissions * checks to be performed at query startup. The user must have *all* @@ -552,7 +552,7 @@ typedef struct RangeTblEntry Alias *alias; /* user-written alias clause, if any */ Alias *eref; /* expanded reference names */ bool inh; /* inheritance requested? */ - bool inFromCl; /* present in FROM clause */ + bool inFromCl; /* present in FROM clause? */ AclMode requiredPerms; /* bitmask of required access permissions */ AclId checkAsUser; /* if not zero, check access as this user */ } RangeTblEntry; diff --git a/src/include/parser/parse_node.h b/src/include/parser/parse_node.h index bfcf00fd47..291282e092 100644 --- a/src/include/parser/parse_node.h +++ b/src/include/parser/parse_node.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/parser/parse_node.h,v 1.43 2005/04/28 21:47:18 tgl Exp $ + * $PostgreSQL: pgsql/src/include/parser/parse_node.h,v 1.44 2005/06/05 00:38:11 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -27,12 +27,19 @@ * p_joinlist: list of join items (RangeTblRef and JoinExpr nodes) that * will become the fromlist of the query's top-level FromExpr node. * - * p_namespace: list of join items that represents the current namespace - * for table and column lookup. This may be just a subset of the rtable + - * joinlist, and/or may contain entries that are not yet added to the main - * joinlist. Note that an RTE that is present in p_namespace, but does not - * have its inFromCl flag set, is accessible only with an explicit qualifier; - * lookups of unqualified column names should ignore it. + * p_relnamespace: list of RTEs that represents the current namespace for + * table lookup, ie, those RTEs that are accessible by qualified names. + * This may be just a subset of the rtable + joinlist, and/or may contain + * entries that are not yet added to the main joinlist. + * + * p_varnamespace: list of RTEs that represents the current namespace for + * column lookup, ie, those RTEs that are accessible by unqualified names. + * This is different from p_relnamespace because a JOIN without an alias does + * not hide the contained tables (so they must still be in p_relnamespace) + * but it does hide their columns (unqualified references to the columns must + * refer to the JOIN, not the member tables). Also, we put POSTQUEL-style + * implicit RTEs into p_relnamespace but not p_varnamespace, so that they + * do not affect the set of columns available for unqualified references. * * p_paramtypes: an array of p_numparams type OIDs for $n parameter symbols * (zeroth entry in array corresponds to $1). If p_variableparams is true, the @@ -49,7 +56,8 @@ typedef struct ParseState List *p_rtable; /* range table so far */ List *p_joinlist; /* join items so far (will become FromExpr * node's fromlist) */ - List *p_namespace; /* current lookup namespace (join items) */ + List *p_relnamespace; /* current namespace for relations */ + List *p_varnamespace; /* current namespace for columns */ Oid *p_paramtypes; /* OIDs of types for $n parameter symbols */ int p_numparams; /* allocated size of p_paramtypes[] */ int p_next_resno; /* next targetlist resno to assign */ diff --git a/src/include/parser/parse_relation.h b/src/include/parser/parse_relation.h index b74098e10c..e6d989cf87 100644 --- a/src/include/parser/parse_relation.h +++ b/src/include/parser/parse_relation.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/parser/parse_relation.h,v 1.50 2005/06/04 19:19:42 tgl Exp $ + * $PostgreSQL: pgsql/src/include/parser/parse_relation.h,v 1.51 2005/06/05 00:38:11 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -22,8 +22,8 @@ extern RangeTblEntry *refnameRangeTblEntry(ParseState *pstate, const char *schemaname, const char *refname, int *sublevels_up); -extern void checkNameSpaceConflicts(ParseState *pstate, Node *namespace1, - Node *namespace2); +extern void checkNameSpaceConflicts(ParseState *pstate, List *namespace1, + List *namespace2); extern int RTERangeTablePosn(ParseState *pstate, RangeTblEntry *rte, int *sublevels_up); @@ -64,7 +64,8 @@ extern RangeTblEntry *addRangeTableEntryForJoin(ParseState *pstate, Alias *alias, bool inFromCl); extern void addRTEtoQuery(ParseState *pstate, RangeTblEntry *rte, - bool addToJoinList, bool addToNameSpace); + bool addToJoinList, + bool addToRelNameSpace, bool addToVarNameSpace); extern RangeTblEntry *addImplicitRTE(ParseState *pstate, RangeVar *relation); extern void expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up, bool include_dropped, -- 2.40.0