]> granicus.if.org Git - postgresql/commitdiff
Replace the parser's namespace tree (which formerly had the same
authorTom Lane <tgl@sss.pgh.pa.us>
Sun, 5 Jun 2005 00:38:11 +0000 (00:38 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sun, 5 Jun 2005 00:38:11 +0000 (00:38 +0000)
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
src/backend/commands/tablecmds.c
src/backend/parser/analyze.c
src/backend/parser/parse_clause.c
src/backend/parser/parse_relation.c
src/backend/parser/parse_target.c
src/backend/utils/adt/ruleutils.c
src/include/nodes/parsenodes.h
src/include/parser/parse_node.h
src/include/parser/parse_relation.h

index 530cca8be86a20bd3d68a3047331529f3c0b35ed..8c6f6bec2557154f66da32d8829ad62c32a93b11 100644 (file)
@@ -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.
index 4335792ee712dc82658ec48a160e1eb17a2a2437..c7669dfc58fe6afe43dc771bd14d2ba176222ca7 100644 (file)
@@ -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);
 
index ee6bfe6ae92ebe512e7d94aa7ecd67425974ea99..1c8fe6cf773012e6f202455fff154afbeeded896 100644 (file)
@@ -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,
index 8d282d13e4f5198b259e87fa7ed556b60bcb0bf5..593f8f1f4b6352aa1ad80cae0b999ad856be33e5 100644 (file)
@@ -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;
        }
index 39d18ffbf8a38b177b7a7fa7b4dfe9b028775603..5786ac44d0709fb6c54559e3537be849d9e3b67f 100644 (file)
@@ -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 $
  *
  *-------------------------------------------------------------------------
  */
 /* 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;
index 27e818dcbe2ddfa31af8c6f3a91cf1abf1c63191..dd2c0b4e31c5c5217b97c1c8942653637c783d47 100644 (file)
@@ -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;
 }
 
index c6de4df714a2600f0fcbc78f554230bb4e5bdc39..bc3e774d640ce8767c6c212da6d2026543d32d15 100644 (file)
@@ -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)
index 1208def12ce63674683d0bce0c19a62e92726e6b..9a525eb1de0c86029aa2c44f799a7564b86a7bf0 100644 (file)
@@ -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;
index bfcf00fd47d7ea922f6e983cbbe7ed5486d74069..291282e09202cee5d97f3496af680ec217337cbe 100644 (file)
@@ -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 $
  *
  *-------------------------------------------------------------------------
  */
  * 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 */
index b74098e10c774705e0a829d78ab89d7d09e0faef..e6d989cf87e4f415850dc2c113979c08a8eedd8f 100644 (file)
@@ -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,