OSDN Git Service

Support DECLARE CURSOR syntax and added regression for table hinting.
[pghintplan/pg_hint_plan.git] / pg_hint_plan.c
index b97a10d..3469500 100644 (file)
@@ -17,6 +17,7 @@
 #include "miscadmin.h"
 #include "nodes/nodeFuncs.h"
 #include "nodes/params.h"
+#include "nodes/relation.h"
 #include "optimizer/clauses.h"
 #include "optimizer/cost.h"
 #include "optimizer/geqo.h"
@@ -28,6 +29,7 @@
 #include "optimizer/prep.h"
 #include "optimizer/restrictinfo.h"
 #include "parser/analyze.h"
+#include "parser/parsetree.h"
 #include "parser/scansup.h"
 #include "tcop/utility.h"
 #include "utils/builtins.h"
@@ -344,7 +346,10 @@ struct HintState
        /* Initial values of parameters  */
        int                             init_scan_mask;         /* enable_* mask */
        int                             init_nworkers;          /* max_parallel_workers_per_gather */
-       int                             init_min_para_size;     /* min_parallel_relation_size*/
+       /* min_parallel_table_scan_size*/
+       int                             init_min_para_tablescan_size;
+       /* min_parallel_index_scan_size*/
+       int                             init_min_para_indexscan_size;
        int                             init_paratup_cost;      /* parallel_tuple_cost */
        int                             init_parasetup_cost;/* parallel_setup_cost */
 
@@ -454,8 +459,8 @@ void pg_hint_plan_set_rel_pathlist(PlannerInfo * root, RelOptInfo *rel,
                                                                   Index rti, RangeTblEntry *rte);
 static void create_plain_partial_paths(PlannerInfo *root,
                                                                                                        RelOptInfo *rel);
-static int compute_parallel_worker(RelOptInfo *rel, BlockNumber pages);
-
+static void add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel,
+                                                                       List *live_childrels);
 static void make_rels_by_clause_joins(PlannerInfo *root, RelOptInfo *old_rel,
                                                                          ListCell *other_rels);
 static void make_rels_by_clauseless_joins(PlannerInfo *root,
@@ -467,8 +472,9 @@ static void set_plain_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
 static void set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
                                                                        Index rti, RangeTblEntry *rte);
 static void generate_mergeappend_paths(PlannerInfo *root, RelOptInfo *rel,
-                                                  List *live_childrels,
-                                                  List *all_child_pathkeys);
+                                                                          List *live_childrels,
+                                                                          List *all_child_pathkeys,
+                                                                          List *partitioned_rels);
 static Path *get_cheapest_parameterized_child_path(PlannerInfo *root,
                                                                          RelOptInfo *rel,
                                                                          Relids required_outer);
@@ -962,7 +968,8 @@ HintStateCreate(void)
        hstate->scan_hints = NULL;
        hstate->init_scan_mask = 0;
        hstate->init_nworkers = 0;
-       hstate->init_min_para_size = 0;
+       hstate->init_min_para_tablescan_size = 0;
+       hstate->init_min_para_indexscan_size = 0;
        hstate->init_paratup_cost = 0;
        hstate->init_parasetup_cost = 0;
        hstate->parent_relid = 0;
@@ -1787,8 +1794,9 @@ get_hints_from_table(const char *client_query, const char *client_application)
 /*
  * Get client-supplied query string. Addtion to that the jumbled query is
  * supplied if the caller requested. From the restriction of JumbleQuery, some
- * kind of query needs special amendments. Reutrns NULL if the current hint
- * string is still valid.
+ * kind of query needs special amendments. Reutrns NULL if this query doesn't
+ * change the current hint. This function returns NULL also when something
+ * wrong has happend and let the caller continue using the current hints.
  */
 static const char *
 get_query_string(ParseState *pstate, Query *query, Query **jumblequery)
@@ -1798,70 +1806,74 @@ get_query_string(ParseState *pstate, Query *query, Query **jumblequery)
        if (jumblequery != NULL)
                *jumblequery = query;
 
-       Assert(plpgsql_recurse_level == 0);
-
        if (query->commandType == CMD_UTILITY)
        {
-               Query *target_query = query;
+               Query *target_query = (Query *)query->utilityStmt;
 
-               /* Use the target query if EXPLAIN */
-               if (IsA(query->utilityStmt, ExplainStmt))
+               /*
+                * Some CMD_UTILITY statements have a subquery that we can hint on.
+                * Since EXPLAIN can be placed before other kind of utility statements
+                * and EXECUTE can be contained other kind of utility statements, these
+                * conditions are not mutually exclusive and should be considered in
+                * this order.
+                */
+               if (IsA(target_query, ExplainStmt))
                {
-                       ExplainStmt *stmt = (ExplainStmt *)(query->utilityStmt);
+                       ExplainStmt *stmt = (ExplainStmt *)target_query;
+                       
                        Assert(IsA(stmt->query, Query));
                        target_query = (Query *)stmt->query;
 
+                       /* strip out the top-level query for further processing */
                        if (target_query->commandType == CMD_UTILITY &&
                                target_query->utilityStmt != NULL)
                                target_query = (Query *)target_query->utilityStmt;
+               }
 
-                       if (jumblequery)
-                               *jumblequery = target_query;
+               if (IsA(target_query, DeclareCursorStmt))
+               {
+                       DeclareCursorStmt *stmt = (DeclareCursorStmt *)target_query;
+                       Query *query = (Query *)stmt->query;
+
+                       /* the target must be CMD_SELECT in this case */
+                       Assert(IsA(query, Query) && query->commandType == CMD_SELECT);
+                       target_query = query;
                }
 
                if (IsA(target_query, CreateTableAsStmt))
                {
-                       /*
-                        * Use the the body query for CREATE AS. The Query for jumble also
-                        * replaced with the corresponding one.
-                        */
                        CreateTableAsStmt  *stmt = (CreateTableAsStmt *) target_query;
-                       PreparedStatement  *entry;
-                       Query                      *ent_query;
 
                        Assert(IsA(stmt->query, Query));
                        target_query = (Query *) stmt->query;
 
+                       /* strip out the top-level query for further processing */
                        if (target_query->commandType == CMD_UTILITY &&
-                               IsA(target_query->utilityStmt, ExecuteStmt))
-                       {
-                               ExecuteStmt *estmt = (ExecuteStmt *) target_query->utilityStmt;
-                               entry = FetchPreparedStatement(estmt->name, true);
-                               p = entry->plansource->query_string;
-                               ent_query = (Query *) linitial (entry->plansource->query_list);
-                               Assert(IsA(ent_query, Query));
-                               if (jumblequery)
-                                       *jumblequery = ent_query;
-                       }
+                               target_query->utilityStmt != NULL)
+                               target_query = (Query *)target_query->utilityStmt;
                }
-               else
+
                if (IsA(target_query, ExecuteStmt))
                {
                        /*
-                        * Use the prepared query for EXECUTE. The Query for jumble also
-                        * replaced with the corresponding one.
+                        * Use the prepared query for EXECUTE. The Query for jumble
+                        * also replaced with the corresponding one.
                         */
                        ExecuteStmt *stmt = (ExecuteStmt *)target_query;
                        PreparedStatement  *entry;
-                       Query                      *ent_query;
 
                        entry = FetchPreparedStatement(stmt->name, true);
                        p = entry->plansource->query_string;
-                       ent_query = (Query *) linitial (entry->plansource->query_list);
-                       Assert(IsA(ent_query, Query));
-                       if (jumblequery)
-                               *jumblequery = ent_query;
+                       target_query = (Query *) linitial (entry->plansource->query_list);
                }
+                       
+               /* JumbleQuery accespts only a non-utility Query */
+               if (!IsA(target_query, Query) ||
+                       target_query->utilityStmt != NULL)
+                       target_query = NULL;
+
+               if (jumblequery)
+                       *jumblequery = target_query;
        }
        /* Return NULL if the pstate is not identical to the top-level query */
        else if (strcmp(pstate->p_sourcetext, p) != 0)
@@ -2625,7 +2637,9 @@ setup_parallel_plan_enforcement(ParallelHint *hint, HintState *state)
        {
                set_config_int32_option("parallel_tuple_cost", 0, state->context);
                set_config_int32_option("parallel_setup_cost", 0, state->context);
-               set_config_int32_option("min_parallel_relation_size", 0,
+               set_config_int32_option("min_parallel_table_scan_size", 0,
+                                                               state->context);
+               set_config_int32_option("min_parallel_index_scan_size", 0,
                                                                state->context);
        }
        else
@@ -2634,8 +2648,12 @@ setup_parallel_plan_enforcement(ParallelHint *hint, HintState *state)
                                                                state->init_paratup_cost, state->context);
                set_config_int32_option("parallel_setup_cost",
                                                                state->init_parasetup_cost, state->context);
-               set_config_int32_option("min_parallel_relation_size",
-                                                               state->init_min_para_size, state->context);
+               set_config_int32_option("min_parallel_table_scan_size",
+                                                               state->init_min_para_tablescan_size,
+                                                               state->context);
+               set_config_int32_option("min_parallel_index_scan_size",
+                                                               state->init_min_para_indexscan_size,
+                                                               state->context);
        }
 }
 
@@ -2852,7 +2870,7 @@ pg_hint_plan_post_parse_analyze(ParseState *pstate, Query *query)
                        }
                }
 
-               /* retrun if we have hint here*/
+               /* retrun if we have hint here */
                if (current_hint_str)
                        return;
        }
@@ -2965,7 +2983,10 @@ pg_hint_plan_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
        
        current_hint_state->init_scan_mask = get_current_scan_mask();
        current_hint_state->init_join_mask = get_current_join_mask();
-       current_hint_state->init_min_para_size = min_parallel_relation_size;
+       current_hint_state->init_min_para_tablescan_size =
+               min_parallel_table_scan_size;
+       current_hint_state->init_min_para_indexscan_size =
+               min_parallel_index_scan_size;
        current_hint_state->init_paratup_cost = parallel_tuple_cost;
        current_hint_state->init_parasetup_cost = parallel_setup_cost;
 
@@ -4419,50 +4440,24 @@ pg_hint_plan_set_rel_pathlist(PlannerInfo * root, RelOptInfo *rel,
                return;
 
        /* Here, we regenerate paths with the current hint restriction */
-
-       if (found_hints & HINT_BM_SCAN_METHOD)
+       if (found_hints & HINT_BM_SCAN_METHOD || found_hints & HINT_BM_PARALLEL)
        {
-               /*
-                * With scan hints, we regenerate paths for this relation from the
-                * first under the restricion.
-                */
+               /* Just discard all the paths considered so far */
                list_free_deep(rel->pathlist);
                rel->pathlist = NIL;
 
-               set_plain_rel_pathlist(root, rel, rte);
-       }
-
-       if (found_hints & HINT_BM_PARALLEL)
-       {
-               Assert (phint);
-
-               /* the partial_pathlist may be for different parameters, discard it */
-               if (rel->partial_pathlist)
+               /* Remove all the partial paths if Parallel hint is specfied */
+               if ((found_hints & HINT_BM_PARALLEL) && rel->partial_pathlist)
                {
                        list_free_deep(rel->partial_pathlist);
                        rel->partial_pathlist = NIL;
                }
 
-               /* also remove gather path */
-               if (rel->pathlist)
-               {
-                       ListCell *cell, *prev = NULL, *next;
-
-                       for (cell = list_head(rel->pathlist) ; cell; cell = next)
-                       {
-                               Path *path = (Path *) lfirst(cell);
-
-                               next = lnext(cell);
-                               if (IsA(path, GatherPath))
-                                       rel->pathlist = list_delete_cell(rel->pathlist,
-                                                                                                        cell, prev);
-                               else
-                                       prev = cell;
-                       }
-               }
+               /* Regenerate paths with the current enforcement */
+               set_plain_rel_pathlist(root, rel, rte);
 
-               /* then generate new paths if needed */
-               if (phint->nworkers > 0)
+               /* Additional work to enforce parallel query execution */
+               if (phint && phint->nworkers > 0)
                {
                        /* Lower the priorities of non-parallel paths */
                        foreach (l, rel->pathlist)
@@ -4476,15 +4471,6 @@ pg_hint_plan_set_rel_pathlist(PlannerInfo * root, RelOptInfo *rel,
                                }
                        }
 
-                       /*
-                        * generate partial paths with enforcement, this is affected by
-                        * scan method enforcement. Specifically, the cost of this partial
-                        * seqscan path will be disabled_cost if seqscan is inhibited by
-                        * hint or GUC parameters.
-                        */
-                       Assert (rel->partial_pathlist == NIL);
-                       create_plain_partial_paths(root, rel);
-
                        /* enforce number of workers if requested */
                        if (phint->force_parallel)
                        {