diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index 530cca8be86a20bd3d68a3047331529f3c0b35ed..8c6f6bec2557154f66da32d8829ad62c32a93b11 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 4335792ee712dc82658ec48a160e1eb17a2a2437..c7669dfc58fe6afe43dc771bd14d2ba176222ca7 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 ee6bfe6ae92ebe512e7d94aa7ecd67425974ea99..1c8fe6cf773012e6f202455fff154afbeeded896 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 8d282d13e4f5198b259e87fa7ed556b60bcb0bf5..593f8f1f4b6352aa1ad80cae0b999ad856be33e5 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 39d18ffbf8a38b177b7a7fa7b4dfe9b028775603..5786ac44d0709fb6c54559e3537be849d9e3b67f 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 27e818dcbe2ddfa31af8c6f3a91cf1abf1c63191..dd2c0b4e31c5c5217b97c1c8942653637c783d47 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 c6de4df714a2600f0fcbc78f554230bb4e5bdc39..bc3e774d640ce8767c6c212da6d2026543d32d15 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 1208def12ce63674683d0bce0c19a62e92726e6b..9a525eb1de0c86029aa2c44f799a7564b86a7bf0 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 bfcf00fd47d7ea922f6e983cbbe7ed5486d74069..291282e09202cee5d97f3496af680ec217337cbe 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 b74098e10c774705e0a829d78ab89d7d09e0faef..e6d989cf87e4f415850dc2c113979c08a8eedd8f 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,