]> granicus.if.org Git - postgresql/commitdiff
create_unique_plan() should not discard existing output columns of the
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 7 Aug 2003 19:20:24 +0000 (19:20 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 7 Aug 2003 19:20:24 +0000 (19:20 +0000)
subplan it starts with, as they may be needed at upper join levels.
See comments added to code for the non-obvious reason why.  Per bug report
from Robert Creager.

src/backend/optimizer/plan/createplan.c
src/backend/parser/parse_clause.c
src/include/parser/parse_clause.h
src/test/regress/expected/join.out
src/test/regress/sql/join.sql

index 7529b7c0c7f3bef38d8ae513d5c3f5a6e6eacc18..c77f7d405393fd6a22b701d9de573348e75bcc76 100644 (file)
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.151 2003/08/04 02:40:00 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.152 2003/08/07 19:20:22 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -504,52 +504,87 @@ create_unique_plan(Query *root, UniquePath * best_path)
 {
        Plan       *plan;
        Plan       *subplan;
-       List       *sub_targetlist;
+       List       *uniq_exprs;
+       int                     numGroupCols;
+       AttrNumber *groupColIdx;
+       int                     groupColPos;
+       List       *newtlist;
+       int                     nextresno;
+       bool            newitems;
        List       *my_tlist;
        List       *l;
 
        subplan = create_plan(root, best_path->subpath);
 
        /*
-        * If the subplan came from an IN subselect (currently always the
-        * case), we need to instantiate the correct output targetlist for the
-        * subselect, rather than using the flattened tlist.
+        * As constructed, the subplan has a "flat" tlist containing just the
+        * Vars needed here and at upper levels.  The values we are supposed
+        * to unique-ify may be expressions in these variables.  We have to
+        * add any such expressions to the subplan's tlist.  We then build
+        * control information showing which subplan output columns are to be
+        * examined by the grouping step.  (Since we do not remove any existing
+        * subplan outputs, not all the output columns may be used for grouping.)
+        *
+        * Note: the reason we don't remove any subplan outputs is that there
+        * are scenarios where a Var is needed at higher levels even though it
+        * is not one of the nominal outputs of an IN clause.  Consider
+        *              WHERE x IN (SELECT y FROM t1,t2 WHERE y = z)
+        * Implied equality deduction will generate an "x = z" clause, which may
+        * get used instead of "x = y" in the upper join step.  Therefore the
+        * sub-select had better deliver both y and z in its targetlist.  It is
+        * sufficient to unique-ify on y, however.
+        *
+        * To find the correct list of values to unique-ify, we look in the
+        * information saved for IN expressions.  If this code is ever used in
+        * other scenarios, some other way of finding what to unique-ify will
+        * be needed.
         */
-       sub_targetlist = NIL;
+       uniq_exprs = NIL;                       /* just to keep compiler quiet */
        foreach(l, root->in_info_list)
        {
                InClauseInfo *ininfo = (InClauseInfo *) lfirst(l);
 
                if (bms_equal(ininfo->righthand, best_path->path.parent->relids))
                {
-                       sub_targetlist = ininfo->sub_targetlist;
+                       uniq_exprs = ininfo->sub_targetlist;
                        break;
                }
        }
-
-       if (sub_targetlist)
+       if (l == NIL)                           /* fell out of loop? */
+               elog(ERROR, "could not find UniquePath in in_info_list");
+
+       /* set up to record positions of unique columns */
+       numGroupCols = length(uniq_exprs);
+       groupColIdx = (AttrNumber *) palloc(numGroupCols * sizeof(AttrNumber));
+       groupColPos = 0;
+       /* not sure if tlist might be shared with other nodes, so copy */
+       newtlist = copyObject(subplan->targetlist);
+       nextresno = length(newtlist) + 1;
+       newitems = false;
+
+       foreach(l, uniq_exprs)
        {
-               /*
-                * Transform list of plain Vars into targetlist
-                */
-               List       *newtlist = NIL;
-               int                     resno = 1;
+               Node       *uniqexpr = lfirst(l);
+               TargetEntry *tle;
 
-               foreach(l, sub_targetlist)
+               tle = tlistentry_member(uniqexpr, newtlist);
+               if (!tle)
                {
-                       Node       *tlexpr = lfirst(l);
-                       TargetEntry *tle;
-
-                       tle = makeTargetEntry(makeResdom(resno,
-                                                                                        exprType(tlexpr),
-                                                                                        exprTypmod(tlexpr),
+                       tle = makeTargetEntry(makeResdom(nextresno,
+                                                                                        exprType(uniqexpr),
+                                                                                        exprTypmod(uniqexpr),
                                                                                         NULL,
                                                                                         false),
-                                                                 (Expr *) tlexpr);
+                                                                 (Expr *) uniqexpr);
                        newtlist = lappend(newtlist, tle);
-                       resno++;
+                       nextresno++;
+                       newitems = true;
                }
+               groupColIdx[groupColPos++] = tle->resdom->resno;
+       }
 
+       if (newitems)
+       {
                /*
                 * If the top plan node can't do projections, we need to add a
                 * Result node to help it along.
@@ -563,21 +598,15 @@ create_unique_plan(Query *root, UniquePath * best_path)
                        subplan->targetlist = newtlist;
        }
 
+       /* Copy tlist again to make one we can put sorting labels on */
        my_tlist = copyObject(subplan->targetlist);
 
        if (best_path->use_hash)
        {
-               int                     numGroupCols = length(my_tlist);
                long            numGroups;
-               AttrNumber *groupColIdx;
-               int                     i;
 
                numGroups = (long) Min(best_path->rows, (double) LONG_MAX);
 
-               groupColIdx = (AttrNumber *) palloc(numGroupCols * sizeof(AttrNumber));
-               for (i = 0; i < numGroupCols; i++)
-                       groupColIdx[i] = i + 1;
-
                plan = (Plan *) make_agg(root,
                                                                 my_tlist,
                                                                 NIL,
@@ -590,9 +619,17 @@ create_unique_plan(Query *root, UniquePath * best_path)
        }
        else
        {
-               List       *sortList;
+               List       *sortList = NIL;
 
-               sortList = addAllTargetsToSortList(NULL, NIL, my_tlist, false);
+               for (groupColPos = 0; groupColPos < numGroupCols; groupColPos++)
+               {
+                       TargetEntry *tle;
+
+                       tle = nth(groupColIdx[groupColPos] - 1, my_tlist);
+                       Assert(tle->resdom->resno == groupColIdx[groupColPos]);
+                       sortList = addTargetToSortList(NULL, tle, sortList,
+                                                                                  my_tlist, NIL, false);
+               }
                plan = (Plan *) make_sort_from_sortclauses(root, my_tlist,
                                                                                                   subplan, sortList);
                plan = (Plan *) make_unique(my_tlist, plan, sortList);
index f56e06136e84af72f3a28e2c571e4ee331d0de17..ebc3ed23eecf5d8dcbe5223a9c7fa5b2cf0d1bbd 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.120 2003/08/04 02:40:01 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.121 2003/08/07 19:20:22 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -59,9 +59,6 @@ static Node *buildMergedJoinVar(ParseState *pstate, JoinType jointype,
                                   Var *l_colvar, Var *r_colvar);
 static TargetEntry *findTargetlistEntry(ParseState *pstate, Node *node,
                                        List *tlist, int clause);
-static List *addTargetToSortList(ParseState *pstate, TargetEntry *tle,
-                                       List *sortlist, List *targetlist,
-                                       List *opname, bool resolveUnknown);
 
 
 /*
@@ -1478,7 +1475,7 @@ addAllTargetsToSortList(ParseState *pstate, List *sortlist,
  *
  * Returns the updated ORDER BY list.
  */
-static List *
+List *
 addTargetToSortList(ParseState *pstate, TargetEntry *tle,
                                        List *sortlist, List *targetlist,
                                        List *opname, bool resolveUnknown)
index e806b4c86b8fd9dcc497e2cb464fde63758b6fa9..670b72cfbac0e0bb108d075cd7f758b13e349886 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parse_clause.h,v 1.35 2003/08/04 02:40:14 momjian Exp $
+ * $Id: parse_clause.h,v 1.36 2003/08/07 19:20:23 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -35,6 +35,9 @@ extern List *transformDistinctClause(ParseState *pstate, List *distinctlist,
 extern List *addAllTargetsToSortList(ParseState *pstate,
                                                List *sortlist, List *targetlist,
                                                bool resolveUnknown);
+extern List *addTargetToSortList(ParseState *pstate, TargetEntry *tle,
+                                       List *sortlist, List *targetlist,
+                                       List *opname, bool resolveUnknown);
 extern Index assignSortGroupRef(TargetEntry *tle, List *tlist);
 extern bool targetIsInSortList(TargetEntry *tle, List *sortList);
 
index 6ee15172acd0a38168bf519be0968b674a3d587a..2ce1d7b177f5da5cd736b0ae7df2f0ef58bd28fc 100644 (file)
@@ -2127,6 +2127,18 @@ on (x1 = xx1) where (xx2 is not null);
   4 | 44 |  4 |     |   4 |  44
 (3 rows)
 
+--
+-- regression test: check for bug with propagation of implied equality
+-- to outside an IN
+--
+select count(*) from tenk1 a where unique1 in
+  (select unique1 from tenk1 b join tenk1 c using (unique1)
+   where b.unique2 = 42);
+ count 
+-------
+     1
+(1 row)
+
 --
 -- Clean up
 --
index e4ccfa45828340d09fa8f73acd356291d40791c7..9a286345b1450f02eff0a79c5fcde27214c6ad4b 100644 (file)
@@ -330,6 +330,14 @@ on (x1 = xx1) where (y2 is not null);
 select * from (x left join y on (x1 = y1)) left join x xx(xx1,xx2)
 on (x1 = xx1) where (xx2 is not null);
 
+--
+-- regression test: check for bug with propagation of implied equality
+-- to outside an IN
+--
+select count(*) from tenk1 a where unique1 in
+  (select unique1 from tenk1 b join tenk1 c using (unique1)
+   where b.unique2 = 42);
+
 
 --
 -- Clean up