OSDN Git Service

Reflected changes as of release 10.0.
[pghintplan/pg_hint_plan.git] / core.c
diff --git a/core.c b/core.c
index 94d8031..b36cdd8 100644 (file)
--- a/core.c
+++ b/core.c
@@ -3,15 +3,38 @@
  * core.c
  *       Routines copied from PostgreSQL core distribution.
  *
+
+ * The main purpose of this files is having access to static functions in core.
+ * Another purpose is tweaking functions behavior by replacing part of them by
+ * macro definitions. See at the end of pg_hint_plan.c for details. Anyway,
+ * this file *must* contain required functions without making any change.
+ *
+ * This file contains the following functions from corresponding files.
+ *
  * src/backend/optimizer/path/allpaths.c
+ *
+ *     static functions:
+ *        set_plain_rel_pathlist()
  *     set_append_rel_pathlist()
+ *     add_paths_to_append_rel()
  *     generate_mergeappend_paths()
  *     get_cheapest_parameterized_child_path()
  *     accumulate_append_subpath()
- *     standard_join_search()
+ *
+ *  public functions:
+ *     standard_join_search(): This funcion is not static. The reason for
+ *        including this function is make_rels_by_clause_joins. In order to
+ *        avoid generating apparently unwanted join combination, we decided to
+ *        change the behavior of make_join_rel, which is called under this
+ *        function.
  *
  * src/backend/optimizer/path/joinrels.c
- *     join_search_one_level()
+ *
+ *     public functions:
+ *     join_search_one_level(): We have to modify this to call my definition of
+ *                 make_rels_by_clause_joins.
+ *
+ *     static functions:
  *     make_rels_by_clause_joins()
  *     make_rels_by_clauseless_joins()
  *     join_is_legal()
  *     mark_dummy_rel()
  *     restriction_is_constant_false()
  *
- * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
+ *
+ * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *-------------------------------------------------------------------------
  */
 
+
+/*
+ * set_plain_rel_pathlist
+ *       Build access paths for a plain relation (no subquery, no inheritance)
+ */
+static void
+set_plain_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
+{
+       Relids          required_outer;
+
+       /*
+        * We don't support pushing join clauses into the quals of a seqscan, but
+        * it could still have required parameterization due to LATERAL refs in
+        * its tlist.
+        */
+       required_outer = rel->lateral_relids;
+
+       /* Consider sequential scan */
+       add_path(rel, create_seqscan_path(root, rel, required_outer, 0));
+
+       /* If appropriate, consider parallel sequential scan */
+       if (rel->consider_parallel && required_outer == NULL)
+               create_plain_partial_paths(root, rel);
+
+       /* Consider index scans */
+       create_index_paths(root, rel);
+
+       /* Consider TID scans */
+       create_tidscan_paths(root, rel);
+}
+
+
 /*
  * set_append_rel_pathlist
  *       Build access paths for an "append relation"
@@ -36,17 +92,11 @@ 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;
 
        /*
         * Generate access paths for each member relation, and remember the
-        * cheapest path for each one.  Also, identify all pathkeys (orderings)
-        * and parameterizations (required_outer sets) available for the member
-        * relations.
+        * non-dummy children.
         */
        foreach(l, root->append_rel_list)
        {
@@ -54,7 +104,6 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
                int                     childRTindex;
                RangeTblEntry *childRTE;
                RelOptInfo *childrel;
-               ListCell   *lcp;
 
                /* append_rel_list contains all append rels; ignore others */
                if (appinfo->parent_relid != parentRTindex)
@@ -66,6 +115,15 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
                childrel = root->simple_rel_array[childRTindex];
 
                /*
+                * If set_append_rel_size() decided the parent appendrel was
+                * parallel-unsafe at some point after visiting this child rel, we
+                * need to propagate the unsafety marking down to the child, so that
+                * we don't generate useless partial paths for it.
+                */
+               if (!rel->consider_parallel)
+                       childrel->consider_parallel = false;
+
+               /*
                 * Compute the child's access paths.
                 */
                set_rel_pathlist(root, childrel, childRTindex, childRTE);
@@ -80,6 +138,88 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
                 * Child is live, so add it to the live_childrels list for use below.
                 */
                live_childrels = lappend(live_childrels, childrel);
+       }
+
+       /* Add paths to the "append" relation. */
+       add_paths_to_append_rel(root, rel, live_childrels);
+}
+
+/*
+ * add_paths_to_append_rel
+ *             Generate paths for given "append" relation given the set of non-dummy
+ *             child rels.
+ *
+ * The function collects all parameterizations and orderings supported by the
+ * non-dummy children. For every such parameterization or ordering, it creates
+ * an append path collecting one path from each non-dummy child with given
+ * parameterization or ordering. Similarly it collects partial paths from
+ * non-dummy children to create partial append paths.
+ */
+static void
+add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel,
+                                               List *live_childrels)
+{
+       List       *subpaths = NIL;
+       bool            subpaths_valid = true;
+       List       *partial_subpaths = NIL;
+       bool            partial_subpaths_valid = true;
+       List       *all_child_pathkeys = NIL;
+       List       *all_child_outers = NIL;
+       ListCell   *l;
+       List       *partitioned_rels = NIL;
+       RangeTblEntry *rte;
+       bool            build_partitioned_rels = false;
+
+       /*
+        * A plain relation will already have a PartitionedChildRelInfo if it is
+        * partitioned.  For a subquery RTE, no PartitionedChildRelInfo exists; we
+        * collect all partitioned_rels associated with any child.  (This assumes
+        * that we don't need to look through multiple levels of subquery RTEs; if
+        * we ever do, we could create a PartitionedChildRelInfo with the
+        * accumulated list of partitioned_rels which would then be found when
+        * populated our parent rel with paths.  For the present, that appears to
+        * be unnecessary.)
+        */
+       rte = planner_rt_fetch(rel->relid, root);
+       switch (rte->rtekind)
+       {
+               case RTE_RELATION:
+                       if (rte->relkind == RELKIND_PARTITIONED_TABLE)
+                       {
+                               partitioned_rels =
+                                       get_partitioned_child_rels(root, rel->relid);
+                               Assert(list_length(partitioned_rels) >= 1);
+                       }
+                       break;
+               case RTE_SUBQUERY:
+                       build_partitioned_rels = true;
+                       break;
+               default:
+                       elog(ERROR, "unexpcted rtekind: %d", (int) rte->rtekind);
+       }
+
+       /*
+        * For every non-dummy child, remember the cheapest path.  Also, identify
+        * all pathkeys (orderings) and parameterizations (required_outer sets)
+        * available for the non-dummy member relations.
+        */
+       foreach(l, live_childrels)
+       {
+               RelOptInfo *childrel = lfirst(l);
+               ListCell   *lcp;
+
+               /*
+                * If we need to build partitioned_rels, accumulate the partitioned
+                * rels for this child.
+                */
+               if (build_partitioned_rels)
+               {
+                       List       *cprels;
+
+                       cprels = get_partitioned_child_rels(root, childrel->relid);
+                       partitioned_rels = list_concat(partitioned_rels,
+                                                                                  list_copy(cprels));
+               }
 
                /*
                 * If child has an unparameterized cheapest-total path, add that to
@@ -88,10 +228,17 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
                 */
                if (childrel->cheapest_total_path->param_info == NULL)
                        subpaths = accumulate_append_subpath(subpaths,
-                                                                                         childrel->cheapest_total_path);
+                                                                                                childrel->cheapest_total_path);
                else
                        subpaths_valid = false;
 
+               /* Same idea, but for a partial plan. */
+               if (childrel->partial_pathlist != NIL)
+                       partial_subpaths = accumulate_append_subpath(partial_subpaths,
+                                                                                                                linitial(childrel->partial_pathlist));
+               else
+                       partial_subpaths_valid = false;
+
                /*
                 * Collect lists of all the available path orderings and
                 * parameterizations for all the children.  We use these as a
@@ -163,7 +310,37 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
         * if we have zero or one live subpath due to constraint exclusion.)
         */
        if (subpaths_valid)
-               add_path(rel, (Path *) create_append_path(rel, subpaths, NULL));
+               add_path(rel, (Path *) create_append_path(rel, subpaths, NULL, 0,
+                                                                                                 partitioned_rels));
+
+       /*
+        * Consider an append of partial unordered, unparameterized partial paths.
+        */
+       if (partial_subpaths_valid)
+       {
+               AppendPath *appendpath;
+               ListCell   *lc;
+               int                     parallel_workers = 0;
+
+               /*
+                * Decide on the number of workers to request for this append path.
+                * For now, we just use the maximum value from among the members.  It
+                * might be useful to use a higher number if the Append node were
+                * smart enough to spread out the workers, but it currently isn't.
+                */
+               foreach(lc, partial_subpaths)
+               {
+                       Path       *path = lfirst(lc);
+
+                       parallel_workers = Max(parallel_workers, path->parallel_workers);
+               }
+               Assert(parallel_workers > 0);
+
+               /* Generate a partial append path. */
+               appendpath = create_append_path(rel, partial_subpaths, NULL,
+                                                                               parallel_workers, partitioned_rels);
+               add_partial_path(rel, (Path *) appendpath);
+       }
 
        /*
         * Also build unparameterized MergeAppend paths based on the collected
@@ -171,7 +348,8 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
         */
        if (subpaths_valid)
                generate_mergeappend_paths(root, rel, live_childrels,
-                                                                  all_child_pathkeys);
+                                                                  all_child_pathkeys,
+                                                                  partitioned_rels);
 
        /*
         * Build Append paths for each parameterization seen among the child rels.
@@ -213,10 +391,12 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
 
                if (subpaths_valid)
                        add_path(rel, (Path *)
-                                        create_append_path(rel, subpaths, required_outer));
+                                        create_append_path(rel, subpaths, required_outer, 0,
+                                                                               partitioned_rels));
        }
 }
 
+
 /*
  * generate_mergeappend_paths
  *             Generate MergeAppend paths for an append relation
@@ -243,7 +423,8 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
 static void
 generate_mergeappend_paths(PlannerInfo *root, RelOptInfo *rel,
                                                   List *live_childrels,
-                                                  List *all_child_pathkeys)
+                                                  List *all_child_pathkeys,
+                                                  List *partitioned_rels)
 {
        ListCell   *lcp;
 
@@ -267,12 +448,14 @@ generate_mergeappend_paths(PlannerInfo *root, RelOptInfo *rel,
                                get_cheapest_path_for_pathkeys(childrel->pathlist,
                                                                                           pathkeys,
                                                                                           NULL,
-                                                                                          STARTUP_COST);
+                                                                                          STARTUP_COST,
+                                                                                          false);
                        cheapest_total =
                                get_cheapest_path_for_pathkeys(childrel->pathlist,
                                                                                           pathkeys,
                                                                                           NULL,
-                                                                                          TOTAL_COST);
+                                                                                          TOTAL_COST,
+                                                                                          false);
 
                        /*
                         * If we can't find any paths with the right order just use the
@@ -305,16 +488,19 @@ generate_mergeappend_paths(PlannerInfo *root, RelOptInfo *rel,
                                                                                                                rel,
                                                                                                                startup_subpaths,
                                                                                                                pathkeys,
-                                                                                                               NULL));
+                                                                                                               NULL,
+                                                                                                               partitioned_rels));
                if (startup_neq_total)
                        add_path(rel, (Path *) create_merge_append_path(root,
                                                                                                                        rel,
                                                                                                                        total_subpaths,
                                                                                                                        pathkeys,
-                                                                                                                       NULL));
+                                                                                                                       NULL,
+                                                                                                                       partitioned_rels));
        }
 }
 
+
 /*
  * get_cheapest_parameterized_child_path
  *             Get cheapest path for this relation that has exactly the requested
@@ -337,7 +523,8 @@ get_cheapest_parameterized_child_path(PlannerInfo *root, RelOptInfo *rel,
        cheapest = get_cheapest_path_for_pathkeys(rel->pathlist,
                                                                                          NIL,
                                                                                          required_outer,
-                                                                                         TOTAL_COST);
+                                                                                         TOTAL_COST,
+                                                                                         false);
        Assert(cheapest != NULL);
        if (bms_equal(PATH_REQ_OUTER(cheapest), required_outer))
                return cheapest;
@@ -388,6 +575,7 @@ get_cheapest_parameterized_child_path(PlannerInfo *root, RelOptInfo *rel,
        return cheapest;
 }
 
+
 /*
  * accumulate_append_subpath
  *             Add a subpath to the list being built for an Append or MergeAppend
@@ -423,6 +611,7 @@ accumulate_append_subpath(List *subpaths, Path *path)
                return lappend(subpaths, path);
 }
 
+
 /*
  * standard_join_search
  *       Find possible joinpaths for a query by successively finding ways
@@ -491,12 +680,19 @@ standard_join_search(PlannerInfo *root, int levels_needed, List *initial_rels)
                join_search_one_level(root, lev);
 
                /*
-                * Do cleanup work on each just-processed rel.
+                * Run generate_gather_paths() for each just-processed joinrel.  We
+                * could not do this earlier because both regular and partial paths
+                * can get added to a particular joinrel at multiple times within
+                * join_search_one_level.  After that, we're done creating paths for
+                * the joinrel, so run set_cheapest().
                 */
                foreach(lc, root->join_rel_level[lev])
                {
                        rel = (RelOptInfo *) lfirst(lc);
 
+                       /* Create GatherPaths for any useful partial paths for rel */
+                       generate_gather_paths(root, rel);
+
                        /* Find and save the cheapest paths for this rel */
                        set_cheapest(rel);
 
@@ -521,6 +717,26 @@ standard_join_search(PlannerInfo *root, int levels_needed, List *initial_rels)
 }
 
 /*
+ * create_plain_partial_paths
+ *       Build partial access paths for parallel scan of a plain relation
+ */
+static void
+create_plain_partial_paths(PlannerInfo *root, RelOptInfo *rel)
+{
+       int                     parallel_workers;
+
+       parallel_workers = compute_parallel_worker(rel, rel->pages, -1);
+
+       /* If any limit was set to zero, the user doesn't want a parallel scan. */
+       if (parallel_workers <= 0)
+               return;
+
+       /* Add an unordered partial path based on a parallel sequential scan. */
+       add_partial_path(rel, create_seqscan_path(root, rel, NULL, parallel_workers));
+}
+
+
+/*
  * join_search_one_level
  *       Consider ways to produce join relations containing exactly 'level'
  *       jointree items.  (This is one step of the dynamic-programming method
@@ -576,7 +792,7 @@ join_search_one_level(PlannerInfo *root, int level)
 
                        if (level == 2)         /* consider remaining initial rels */
                                other_rels = lnext(r);
-                       else    /* consider all initial rels */
+                       else                            /* consider all initial rels */
                                other_rels = list_head(joinrels[1]);
 
                        make_rels_by_clause_joins(root,
@@ -722,6 +938,7 @@ join_search_one_level(PlannerInfo *root, int level)
        }
 }
 
+
 /*
  * make_rels_by_clause_joins
  *       Build joins between the given relation 'old_rel' and other relations
@@ -762,6 +979,7 @@ make_rels_by_clause_joins(PlannerInfo *root,
        }
 }
 
+
 /*
  * make_rels_by_clauseless_joins
  *       Given a relation 'old_rel' and a list of other relations
@@ -794,6 +1012,7 @@ make_rels_by_clauseless_joins(PlannerInfo *root,
        }
 }
 
+
 /*
  * join_is_legal
  *        Determine whether a proposed join is legal given the query's
@@ -1097,7 +1316,7 @@ join_is_legal(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2,
                                                !bms_is_subset(sjinfo->min_righthand, join_plus_rhs))
                                        {
                                                join_plus_rhs = bms_add_members(join_plus_rhs,
-                                                                                                         sjinfo->min_righthand);
+                                                                                                               sjinfo->min_righthand);
                                                more = true;
                                        }
                                        /* full joins constrain both sides symmetrically */
@@ -1122,6 +1341,7 @@ join_is_legal(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2,
        return true;
 }
 
+
 /*
  * has_join_restriction
  *             Detect whether the specified relation has join-order restrictions,
@@ -1172,6 +1392,7 @@ has_join_restriction(PlannerInfo *root, RelOptInfo *rel)
        return false;
 }
 
+
 /*
  * is_dummy_rel --- has relation been proven empty?
  */
@@ -1181,6 +1402,7 @@ is_dummy_rel(RelOptInfo *rel)
        return IS_DUMMY_REL(rel);
 }
 
+
 /*
  * Mark a relation as proven empty.
  *
@@ -1213,9 +1435,10 @@ mark_dummy_rel(RelOptInfo *rel)
 
        /* Evict any previously chosen paths */
        rel->pathlist = NIL;
+       rel->partial_pathlist = NIL;
 
        /* Set up the dummy path */
-       add_path(rel, (Path *) create_append_path(rel, NIL, NULL));
+       add_path(rel, (Path *) create_append_path(rel, NIL, NULL, 0, NIL));
 
        /* Set or update cheapest_total_path and related fields */
        set_cheapest(rel);
@@ -1223,6 +1446,7 @@ mark_dummy_rel(RelOptInfo *rel)
        MemoryContextSwitchTo(oldcontext);
 }
 
+
 /*
  * restriction_is_constant_false --- is a restrictlist just FALSE?
  *
@@ -1247,9 +1471,8 @@ restriction_is_constant_false(List *restrictlist, bool only_pushed_down)
         */
        foreach(lc, restrictlist)
        {
-               RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
+               RestrictInfo *rinfo = lfirst_node(RestrictInfo, lc);
 
-               Assert(IsA(rinfo, RestrictInfo));
                if (only_pushed_down && !rinfo->is_pushed_down)
                        continue;