OSDN Git Service

Fix to remove plpgsql query string on non-local exit.
[pghintplan/pg_hint_plan.git] / core.c
diff --git a/core.c b/core.c
index 9b33a06..dd5acd6 100644 (file)
--- a/core.c
+++ b/core.c
@@ -6,6 +6,7 @@
  * src/backend/optimizer/path/allpaths.c
  *     set_append_rel_pathlist()
  *     generate_mergeappend_paths()
+ *     get_cheapest_parameterized_child_path()
  *     accumulate_append_subpath()
  *     standard_join_search()
  *
@@ -19,7 +20,7 @@
  *     mark_dummy_rel()
  *     restriction_is_constant_false()
  *
- * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *-------------------------------------------------------------------------
@@ -36,6 +37,7 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
        int                     parentRTindex = rti;
        List       *live_childrels = NIL;
        List       *subpaths = NIL;
+       bool            subpaths_valid = true;
        List       *all_child_pathkeys = NIL;
        List       *all_child_outers = NIL;
        ListCell   *l;
@@ -75,16 +77,22 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
                        continue;
 
                /*
-                * Child is live, so add its cheapest access path to the Append path
-                * we are constructing for the parent.
+                * Child is live, so add it to the live_childrels list for use below.
                 */
-               subpaths = accumulate_append_subpath(subpaths,
-                                                                                        childrel->cheapest_total_path);
-
-               /* Remember which childrels are live, for logic below */
                live_childrels = lappend(live_childrels, childrel);
 
                /*
+                * If child has an unparameterized cheapest-total path, add that to
+                * the unparameterized Append path we are constructing for the parent.
+                * If not, there's no workable unparameterized path.
+                */
+               if (childrel->cheapest_total_path->param_info == NULL)
+                       subpaths = accumulate_append_subpath(subpaths,
+                                                                                         childrel->cheapest_total_path);
+               else
+                       subpaths_valid = false;
+
+               /*
                 * Collect lists of all the available path orderings and
                 * parameterizations for all the children.      We use these as a
                 * heuristic to indicate which sort orderings and parameterizations we
@@ -150,17 +158,20 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
        }
 
        /*
-        * Next, build an unordered, unparameterized Append path for the rel.
-        * (Note: this is correct even if we have zero or one live subpath due to
-        * constraint exclusion.)
+        * If we found unparameterized paths for all children, build an unordered,
+        * unparameterized Append path for the rel.  (Note: this is correct even
+        * if we have zero or one live subpath due to constraint exclusion.)
         */
-       add_path(rel, (Path *) create_append_path(rel, subpaths, NULL));
+       if (subpaths_valid)
+               add_path(rel, (Path *) create_append_path(rel, subpaths, NULL));
 
        /*
-        * Build unparameterized MergeAppend paths based on the collected list of
-        * child pathkeys.
+        * Also build unparameterized MergeAppend paths based on the collected
+        * list of child pathkeys.
         */
-       generate_mergeappend_paths(root, rel, live_childrels, all_child_pathkeys);
+       if (subpaths_valid)
+               generate_mergeappend_paths(root, rel, live_childrels,
+                                                                  all_child_pathkeys);
 
        /*
         * Build Append paths for each parameterization seen among the child rels.
@@ -178,39 +189,29 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
        foreach(l, all_child_outers)
        {
                Relids          required_outer = (Relids) lfirst(l);
-               bool            ok = true;
                ListCell   *lcr;
 
                /* Select the child paths for an Append with this parameterization */
                subpaths = NIL;
+               subpaths_valid = true;
                foreach(lcr, live_childrels)
                {
                        RelOptInfo *childrel = (RelOptInfo *) lfirst(lcr);
-                       Path       *cheapest_total;
+                       Path       *subpath;
 
-                       cheapest_total =
-                               get_cheapest_path_for_pathkeys(childrel->pathlist,
-                                                                                          NIL,
-                                                                                          required_outer,
-                                                                                          TOTAL_COST);
-                       Assert(cheapest_total != NULL);
-
-                       /* Children must have exactly the desired parameterization */
-                       if (!bms_equal(PATH_REQ_OUTER(cheapest_total), required_outer))
+                       subpath = get_cheapest_parameterized_child_path(root,
+                                                                                                                       childrel,
+                                                                                                                       required_outer);
+                       if (subpath == NULL)
                        {
-                               cheapest_total = reparameterize_path(root, cheapest_total,
-                                                                                                        required_outer, 1.0);
-                               if (cheapest_total == NULL)
-                               {
-                                       ok = false;
-                                       break;
-                               }
+                               /* failed to make a suitable path for this child */
+                               subpaths_valid = false;
+                               break;
                        }
-
-                       subpaths = accumulate_append_subpath(subpaths, cheapest_total);
+                       subpaths = accumulate_append_subpath(subpaths, subpath);
                }
 
-               if (ok)
+               if (subpaths_valid)
                        add_path(rel, (Path *)
                                         create_append_path(rel, subpaths, required_outer));
        }
@@ -318,6 +319,79 @@ generate_mergeappend_paths(PlannerInfo *root, RelOptInfo *rel,
 }
 
 /*
+ * get_cheapest_parameterized_child_path
+ *             Get cheapest path for this relation that has exactly the requested
+ *             parameterization.
+ *
+ * Returns NULL if unable to create such a path.
+ */
+static Path *
+get_cheapest_parameterized_child_path(PlannerInfo *root, RelOptInfo *rel,
+                                                                         Relids required_outer)
+{
+       Path       *cheapest;
+       ListCell   *lc;
+
+       /*
+        * Look up the cheapest existing path with no more than the needed
+        * parameterization.  If it has exactly the needed parameterization, we're
+        * done.
+        */
+       cheapest = get_cheapest_path_for_pathkeys(rel->pathlist,
+                                                                                         NIL,
+                                                                                         required_outer,
+                                                                                         TOTAL_COST);
+       Assert(cheapest != NULL);
+       if (bms_equal(PATH_REQ_OUTER(cheapest), required_outer))
+               return cheapest;
+
+       /*
+        * Otherwise, we can "reparameterize" an existing path to match the given
+        * parameterization, which effectively means pushing down additional
+        * joinquals to be checked within the path's scan.  However, some existing
+        * paths might check the available joinquals already while others don't;
+        * therefore, it's not clear which existing path will be cheapest after
+        * reparameterization.  We have to go through them all and find out.
+        */
+       cheapest = NULL;
+       foreach(lc, rel->pathlist)
+       {
+               Path       *path = (Path *) lfirst(lc);
+
+               /* Can't use it if it needs more than requested parameterization */
+               if (!bms_is_subset(PATH_REQ_OUTER(path), required_outer))
+                       continue;
+
+               /*
+                * Reparameterization can only increase the path's cost, so if it's
+                * already more expensive than the current cheapest, forget it.
+                */
+               if (cheapest != NULL &&
+                       compare_path_costs(cheapest, path, TOTAL_COST) <= 0)
+                       continue;
+
+               /* Reparameterize if needed, then recheck cost */
+               if (!bms_equal(PATH_REQ_OUTER(path), required_outer))
+               {
+                       path = reparameterize_path(root, path, required_outer, 1.0);
+                       if (path == NULL)
+                               continue;               /* failed to reparameterize this one */
+                       Assert(bms_equal(PATH_REQ_OUTER(path), required_outer));
+
+                       if (cheapest != NULL &&
+                               compare_path_costs(cheapest, path, TOTAL_COST) <= 0)
+                               continue;
+               }
+
+               /* We have a new best path */
+               cheapest = path;
+       }
+
+       /* Return the best path, or NULL if we found no suitable candidate */
+       return cheapest;
+}
+
+/*
  * accumulate_append_subpath
  *             Add a subpath to the list being built for an Append or MergeAppend
  *