]> granicus.if.org Git - postgresql/commitdiff
Last week's patch for make_sort_from_pathkeys wasn't good enough: it has
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 8 Nov 2007 19:25:37 +0000 (19:25 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 8 Nov 2007 19:25:37 +0000 (19:25 +0000)
to be able to discard top-level RelabelType nodes on *both* sides of the
equivalence-class-to-target-list comparison, since make_pathkey_from_sortinfo
might either add or remove a RelabelType.  Also fix the latter to do the
removal case cleanly.  Per example from Peter.

src/backend/optimizer/path/pathkeys.c
src/backend/optimizer/plan/createplan.c
src/backend/optimizer/util/tlist.c
src/include/optimizer/tlist.h

index 2ad31203697cd0c9898ef567032e84f74319899f..f96d7bb5554a177f17e9f8e2982969007509380a 100644 (file)
@@ -11,7 +11,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/path/pathkeys.c,v 1.87 2007/11/02 18:54:15 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/path/pathkeys.c,v 1.88 2007/11/08 19:25:37 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -292,13 +292,14 @@ make_pathkey_from_sortinfo(PlannerInfo *root,
        if (exprType((Node *) expr) != opcintype &&
                !IsPolymorphicType(opcintype))
        {
-               /* Strip any existing RelabelType, and add a new one */
+               /* Strip any existing RelabelType, and add a new one if needed */
                while (expr && IsA(expr, RelabelType))
                        expr = (Expr *) ((RelabelType *) expr)->arg;
-               expr = (Expr *) makeRelabelType(expr,
-                                                                               opcintype,
-                                                                               -1,
-                                                                               COERCE_DONTCARE);
+               if (exprType((Node *) expr) != opcintype)
+                       expr = (Expr *) makeRelabelType(expr,
+                                                                                       opcintype,
+                                                                                       -1,
+                                                                                       COERCE_DONTCARE);
        }
 
        /* Now find or create a matching EquivalenceClass */
index fb9b437174fb3f362dd3a879561201436e2484f9..becb8255e87b22225a8a40ed2f7506900bfd8cb5 100644 (file)
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.232 2007/11/02 18:54:15 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.233 2007/11/08 19:25:37 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -2738,7 +2738,7 @@ make_sort_from_pathkeys(PlannerInfo *root, Plan *lefttree, List *pathkeys,
                /*
                 * We can sort by any non-constant expression listed in the pathkey's
                 * EquivalenceClass.  For now, we take the first one that corresponds
-                * to an available Var in the tlist. If there isn't any, use the first
+                * to an available item in the tlist. If there isn't any, use the first
                 * one that is an expression in the input's vars.  (The non-const
                 * restriction only matters if the EC is below_outer_join; but if it
                 * isn't, it won't contain consts anyway, else we'd have discarded
@@ -2766,24 +2766,21 @@ make_sort_from_pathkeys(PlannerInfo *root, Plan *lefttree, List *pathkeys,
 
                        /*
                         * We can also use it if the pathkey expression is a relabel
-                        * of the tlist entry.  This is needed for binary-compatible
-                        * cases (cf. make_pathkey_from_sortinfo).
+                        * of the tlist entry, or vice versa.  This is needed for
+                        * binary-compatible cases (cf. make_pathkey_from_sortinfo).
+                        * We prefer an exact match, though, so we do the basic
+                        * search first.
                         */
-                       if (IsA(em->em_expr, RelabelType))
+                       tle = tlist_member_ignore_relabel((Node *) em->em_expr, tlist);
+                       if (tle)
                        {
-                               Expr       *rtarg = ((RelabelType *) em->em_expr)->arg;
-
-                               tle = tlist_member((Node *) rtarg, tlist);
-                               if (tle)
-                               {
-                                       pk_datatype = em->em_datatype;
-                                       break;                  /* found expr already in tlist */
-                               }
+                               pk_datatype = em->em_datatype;
+                               break;                  /* found expr already in tlist */
                        }
                }
                if (!tle)
                {
-                       /* No matching Var; look for a computable expression */
+                       /* No matching tlist item; look for a computable expression */
                        Expr   *sortexpr = NULL;
 
                        foreach(j, pathkey->pk_eclass->ec_members)
@@ -2798,7 +2795,7 @@ make_sort_from_pathkeys(PlannerInfo *root, Plan *lefttree, List *pathkeys,
                                exprvars = pull_var_clause((Node *) sortexpr, false);
                                foreach(k, exprvars)
                                {
-                                       if (!tlist_member(lfirst(k), tlist))
+                                       if (!tlist_member_ignore_relabel(lfirst(k), tlist))
                                                break;
                                }
                                list_free(exprvars);
index 1e507235c53f120107dd52af7f86723ab23d89ab..e58fe7dc7f1af828bc6ff1e469b699b2fc52edc6 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/util/tlist.c,v 1.74 2007/01/05 22:19:33 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/util/tlist.c,v 1.75 2007/11/08 19:25:37 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -44,6 +44,34 @@ tlist_member(Node *node, List *targetlist)
        return NULL;
 }
 
+/*
+ * tlist_member_ignore_relabel
+ *       Same as above, except that we ignore top-level RelabelType nodes
+ *       while checking for a match.  This is needed for some scenarios
+ *       involving binary-compatible sort operations.
+ */
+TargetEntry *
+tlist_member_ignore_relabel(Node *node, List *targetlist)
+{
+       ListCell   *temp;
+
+       while (node && IsA(node, RelabelType))
+               node = (Node *) ((RelabelType *) node)->arg;
+
+       foreach(temp, targetlist)
+       {
+               TargetEntry *tlentry = (TargetEntry *) lfirst(temp);
+               Expr   *tlexpr = tlentry->expr;
+
+               while (tlexpr && IsA(tlexpr, RelabelType))
+                       tlexpr = ((RelabelType *) tlexpr)->arg;
+
+               if (equal(node, tlexpr))
+                       return tlentry;
+       }
+       return NULL;
+}
+
 /*
  * flatten_tlist
  *       Create a target list that only contains unique variables.
index 31156ebcbcc87e345cb720b43aaccd5ee4b19a10..bb127cbce2b62bedd9ed769a284be6af62091267 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/optimizer/tlist.h,v 1.45 2007/01/05 22:19:56 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/optimizer/tlist.h,v 1.46 2007/11/08 19:25:37 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -18,6 +18,7 @@
 
 
 extern TargetEntry *tlist_member(Node *node, List *targetlist);
+extern TargetEntry *tlist_member_ignore_relabel(Node *node, List *targetlist);
 
 extern List *flatten_tlist(List *tlist);
 extern List *add_to_flat_tlist(List *tlist, List *vars);