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,