]> granicus.if.org Git - postgresql/commitdiff
get_names_for_var didn't do recursion for unnamed JOIN vars quite right;
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 13 Jan 2005 17:19:10 +0000 (17:19 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 13 Jan 2005 17:19:10 +0000 (17:19 +0000)
got it wrong when the JOIN was in an outer query level.  Per example from
Laurie Burrow.  Also fix same issue in markTargetListOrigin.  I think the
latter is only a latent bug since we currently don't apply markTargetListOrigin
except at the outer level ... but should do it right anyway.

src/backend/parser/parse_target.c
src/backend/utils/adt/ruleutils.c

index b931b3bb0ced99ebf1a1044650bf351b2acb36fa..ebba3e868f1142a2092ec56f930883b30991bf03 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/parser/parse_target.c,v 1.128 2004/12/31 22:00:27 pgsql Exp $
+ *       $PostgreSQL: pgsql/src/backend/parser/parse_target.c,v 1.129 2005/01/13 17:19:09 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -29,7 +29,8 @@
 #include "utils/typcache.h"
 
 
-static void markTargetListOrigin(ParseState *pstate, Resdom *res, Var *var);
+static void markTargetListOrigin(ParseState *pstate, Resdom *res,
+                                                                Var *var, int levelsup);
 static Node *transformAssignmentIndirection(ParseState *pstate,
                                                           Node *basenode,
                                                           const char *targetName,
@@ -174,7 +175,7 @@ markTargetListOrigins(ParseState *pstate, List *targetlist)
        {
                TargetEntry *tle = (TargetEntry *) lfirst(l);
 
-               markTargetListOrigin(pstate, tle->resdom, (Var *) tle->expr);
+               markTargetListOrigin(pstate, tle->resdom, (Var *) tle->expr, 0);
        }
 }
 
@@ -182,18 +183,22 @@ markTargetListOrigins(ParseState *pstate, List *targetlist)
  * markTargetListOrigin()
  *             If 'var' is a Var of a plain relation, mark 'res' with its origin
  *
+ * levelsup is an extra offset to interpret the Var's varlevelsup correctly.
+ *
  * This is split out so it can recurse for join references.  Note that we
  * do not drill down into views, but report the view as the column owner.
  */
 static void
-markTargetListOrigin(ParseState *pstate, Resdom *res, Var *var)
+markTargetListOrigin(ParseState *pstate, Resdom *res, Var *var, int levelsup)
 {
+       int                     netlevelsup;
        RangeTblEntry *rte;
        AttrNumber      attnum;
 
        if (var == NULL || !IsA(var, Var))
                return;
-       rte = GetRTEByRangeTablePosn(pstate, var->varno, var->varlevelsup);
+       netlevelsup = var->varlevelsup + levelsup;
+       rte = GetRTEByRangeTablePosn(pstate, var->varno, netlevelsup);
        attnum = var->varattno;
 
        switch (rte->rtekind)
@@ -223,7 +228,7 @@ markTargetListOrigin(ParseState *pstate, Resdom *res, Var *var)
 
                                Assert(attnum > 0 && attnum <= list_length(rte->joinaliasvars));
                                aliasvar = (Var *) list_nth(rte->joinaliasvars, attnum - 1);
-                               markTargetListOrigin(pstate, res, aliasvar);
+                               markTargetListOrigin(pstate, res, aliasvar, netlevelsup);
                        }
                        break;
                case RTE_SPECIAL:
index 4cd5cd6972a7abb8a9902bf1fa0b38e8a58dd843..f3458a5abef18e156219ae19ccd361d33206e0c0 100644 (file)
@@ -3,7 +3,7 @@
  *                             back to source text
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.187 2004/12/13 00:33:06 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.188 2005/01/13 17:19:10 tgl Exp $
  *
  *       This software is copyrighted by Jan Wieck - Hamburg.
  *
@@ -182,7 +182,7 @@ static void get_setop_query(Node *setOp, Query *query,
 static Node *get_rule_sortgroupclause(SortClause *srt, List *tlist,
                                                 bool force_colno,
                                                 deparse_context *context);
-static void get_names_for_var(Var *var, deparse_context *context,
+static void get_names_for_var(Var *var, int levelsup, deparse_context *context,
                                  char **schemaname, char **refname, char **attname);
 static RangeTblEntry *find_rte_by_refname(const char *refname,
                                        deparse_context *context);
@@ -1998,7 +1998,7 @@ get_basic_select_query(Query *query, deparse_context *context,
                                char       *refname;
                                char       *attname;
 
-                               get_names_for_var(var, context,
+                               get_names_for_var(var, 0, context,
                                                                  &schemaname, &refname, &attname);
                                tell_as = (attname == NULL ||
                                                   strcmp(attname, colname) != 0);
@@ -2392,6 +2392,10 @@ get_utility_query_def(Query *query, deparse_context *context)
 /*
  * Get the schemaname, refname and attname for a (possibly nonlocal) Var.
  *
+ * In some cases (currently only when recursing into an unnamed join)
+ * the Var's varlevelsup has to be interpreted with respect to a context
+ * above the current one; levelsup indicates the offset.
+ *
  * schemaname is usually returned as NULL.     It will be non-null only if
  * use of the unqualified refname would find the wrong RTE.
  *
@@ -2404,17 +2408,20 @@ get_utility_query_def(Query *query, deparse_context *context)
  * distinguish this case.)
  */
 static void
-get_names_for_var(Var *var, deparse_context *context,
+get_names_for_var(Var *var, int levelsup, deparse_context *context,
                                  char **schemaname, char **refname, char **attname)
 {
+       int                     netlevelsup;
        deparse_namespace *dpns;
        RangeTblEntry *rte;
 
        /* Find appropriate nesting depth */
-       if (var->varlevelsup >= list_length(context->namespaces))
-               elog(ERROR, "bogus varlevelsup: %d", var->varlevelsup);
+       netlevelsup = var->varlevelsup + levelsup;
+       if (netlevelsup >= list_length(context->namespaces))
+               elog(ERROR, "bogus varlevelsup: %d offset %d",
+                        var->varlevelsup, levelsup);
        dpns = (deparse_namespace *) list_nth(context->namespaces,
-                                                                                 var->varlevelsup);
+                                                                                 netlevelsup);
 
        /* Find the relevant RTE */
        if (var->varno >= 1 && var->varno <= list_length(dpns->rtable))
@@ -2467,7 +2474,7 @@ get_names_for_var(Var *var, deparse_context *context,
                                                                                        var->varattno-1);
                                if (IsA(aliasvar, Var))
                                {
-                                       get_names_for_var(aliasvar, context,
+                                       get_names_for_var(aliasvar, netlevelsup, context,
                                                                          schemaname, refname, attname);
                                        return;
                                }
@@ -2867,7 +2874,7 @@ get_rule_expr(Node *node, deparse_context *context,
                                char       *refname;
                                char       *attname;
 
-                               get_names_for_var(var, context,
+                               get_names_for_var(var, 0, context,
                                                                  &schemaname, &refname, &attname);
                                if (refname && (context->varprefix || attname == NULL))
                                {