X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;f=pg_hint_plan.c;h=29e3e6a985df3f7ec8b58af5e2de1279679e0e01;hb=5f0969f4977cf8b83db88c6f3c5502a8e89f65d2;hp=a625896c5e3ed9bebe60e214a76d1accf2a22d31;hpb=f1837d35ad44c22df9b27beafca5f5b959c0fd13;p=pghintplan%2Fpg_hint_plan.git diff --git a/pg_hint_plan.c b/pg_hint_plan.c index a625896..29e3e6a 100644 --- a/pg_hint_plan.c +++ b/pg_hint_plan.c @@ -3,7 +3,7 @@ * pg_hint_plan.c * hinting on how to execute a query for PostgreSQL * - * Copyright (c) 2012-2019, NIPPON TELEGRAPH AND TELEPHONE CORPORATION + * Copyright (c) 2012-2020, NIPPON TELEGRAPH AND TELEPHONE CORPORATION * *------------------------------------------------------------------------- */ @@ -38,6 +38,7 @@ #include "partitioning/partbounds.h" #include "tcop/utility.h" #include "utils/builtins.h" +#include "utils/float.h" #include "utils/lsyscache.h" #include "utils/memutils.h" #include "utils/rel.h" @@ -363,8 +364,8 @@ struct HintState 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 */ + double init_paratup_cost; /* parallel_tuple_cost */ + double init_parasetup_cost;/* parallel_setup_cost */ PlannerInfo *current_root; /* PlannerInfo for the followings */ Index parent_relid; /* inherit parent of table relid */ @@ -404,8 +405,9 @@ static void pg_hint_plan_ProcessUtility(PlannedStmt *pstmt, const char *queryString, ProcessUtilityContext context, ParamListInfo params, QueryEnvironment *queryEnv, - DestReceiver *dest, char *completionTag); -static PlannedStmt *pg_hint_plan_planner(Query *parse, int cursorOptions, + DestReceiver *dest, QueryCompletion *qc); +static PlannedStmt *pg_hint_plan_planner(Query *parse, const char *query_string, + int cursorOptions, ParamListInfo boundParams); static RelOptInfo *pg_hint_plan_join_search(PlannerInfo *root, int levels_needed, @@ -479,10 +481,11 @@ void pg_hint_plan_set_rel_pathlist(PlannerInfo * root, RelOptInfo *rel, static void create_plain_partial_paths(PlannerInfo *root, RelOptInfo *rel); static void make_rels_by_clause_joins(PlannerInfo *root, RelOptInfo *old_rel, + List *other_rels_list, ListCell *other_rels); static void make_rels_by_clauseless_joins(PlannerInfo *root, RelOptInfo *old_rel, - ListCell *other_rels); + List *other_rels); static bool has_join_restriction(PlannerInfo *root, RelOptInfo *rel); static void set_plain_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte); @@ -506,6 +509,8 @@ static void setup_scan_method_enforcement(ScanMethodHint *scanhint, HintState *state); static int set_config_int32_option(const char *name, int32 value, GucContext context); +static int set_config_double_option(const char *name, double value, + GucContext context); /* GUC variables */ static bool pg_hint_plan_enable_hint = true; @@ -1180,7 +1185,8 @@ RowsHintDesc(RowsHint *hint, StringInfo buf, bool nolf) quote_value(buf, hint->relnames[i]); } } - appendStringInfo(buf, " %s", hint->rows_str); + if (hint->rows_str != NULL) + appendStringInfo(buf, " %s", hint->rows_str); appendStringInfoString(buf, ")"); if (!nolf) appendStringInfoChar(buf, '\n'); @@ -1820,7 +1826,7 @@ get_query_string(ParseState *pstate, Query *query, Query **jumblequery) * case of DESCRIBE message handling or EXECUTE command. We may still see a * candidate top-level query in pstate in the case. */ - if (!p && pstate) + if (pstate && pstate->p_sourcetext) p = pstate->p_sourcetext; /* We don't see a query string, return NULL */ @@ -1887,13 +1893,24 @@ get_query_string(ParseState *pstate, Query *query, Query **jumblequery) PreparedStatement *entry; entry = FetchPreparedStatement(stmt->name, true); - p = entry->plansource->query_string; - target_query = (Query *) linitial (entry->plansource->query_list); + + if (entry->plansource->is_valid) + { + p = entry->plansource->query_string; + target_query = (Query *) linitial (entry->plansource->query_list); + } + else + { + /* igonre the hint for EXECUTE if invalidated */ + p = NULL; + target_query = NULL; + } } /* JumbleQuery accespts only a non-utility Query */ - if (!IsA(target_query, Query) || - target_query->utilityStmt != NULL) + if (target_query && + (!IsA(target_query, Query) || + target_query->utilityStmt != NULL)) target_query = NULL; if (jumblequery) @@ -2064,7 +2081,7 @@ create_hintstate(Query *parse, const char *hints) hstate->num_hints[HINT_TYPE_LEADING]); hstate->rows_hints = (RowsHint **) (hstate->set_hints + hstate->num_hints[HINT_TYPE_SET]); - hstate->parallel_hints = (ParallelHint **) (hstate->set_hints + + hstate->parallel_hints = (ParallelHint **) (hstate->rows_hints + hstate->num_hints[HINT_TYPE_ROWS]); return hstate; @@ -2358,6 +2375,8 @@ RowsHintParse(RowsHint *hint, HintState *hstate, Query *parse, List *name_list = NIL; char *rows_str; char *end_ptr; + ListCell *l; + int i = 0; if ((str = parse_parentheses(str, &name_list, hint_keyword)) == NULL) return NULL; @@ -2365,23 +2384,28 @@ RowsHintParse(RowsHint *hint, HintState *hstate, Query *parse, /* Last element must be rows specification */ hint->nrels = list_length(name_list) - 1; - if (hint->nrels > 0) + if (hint->nrels < 1) { - ListCell *l; - int i = 0; + hint_ereport(str, + ("%s hint needs at least one relation followed by one correction term.", + hint->base.keyword)); + hint->base.state = HINT_STATE_ERROR; - /* - * Transform relation names from list to array to sort them with qsort - * after. - */ - hint->relnames = palloc(sizeof(char *) * hint->nrels); - foreach (l, name_list) - { - if (hint->nrels <= i) - break; - hint->relnames[i] = lfirst(l); - i++; - } + return str; + } + + + /* + * Transform relation names from list to array to sort them with qsort + * after. + */ + hint->relnames = palloc(sizeof(char *) * hint->nrels); + foreach (l, name_list) + { + if (hint->nrels <= i) + break; + hint->relnames[i] = lfirst(l); + i++; } /* Retieve rows estimation */ @@ -2615,6 +2639,23 @@ set_config_int32_option(const char *name, int32 value, GucContext context) pg_hint_plan_parse_message_level); } +/* + * Sets GUC parameter of double type without throwing exceptions. Returns false + * if something wrong. + */ +static int +set_config_double_option(const char *name, double value, GucContext context) +{ + char *buf = float8out_internal(value); + int result; + + result = set_config_option_noerror(name, buf, context, + PGC_S_SESSION, GUC_ACTION_SAVE, true, + pg_hint_plan_parse_message_level); + pfree(buf); + return result; +} + /* setup scan method enforcement according to given options */ static void setup_guc_enforcement(SetHint **options, int noptions, GucContext context) @@ -2662,8 +2703,8 @@ setup_parallel_plan_enforcement(ParallelHint *hint, HintState *state) /* force means that enforce parallel as far as possible */ if (hint && hint->force_parallel && hint->nworkers > 0) { - set_config_int32_option("parallel_tuple_cost", 0, state->context); - set_config_int32_option("parallel_setup_cost", 0, state->context); + set_config_double_option("parallel_tuple_cost", 0.0, state->context); + set_config_double_option("parallel_setup_cost", 0.0, state->context); set_config_int32_option("min_parallel_table_scan_size", 0, state->context); set_config_int32_option("min_parallel_index_scan_size", 0, @@ -2671,9 +2712,9 @@ setup_parallel_plan_enforcement(ParallelHint *hint, HintState *state) } else { - set_config_int32_option("parallel_tuple_cost", + set_config_double_option("parallel_tuple_cost", state->init_paratup_cost, state->context); - set_config_int32_option("parallel_setup_cost", + set_config_double_option("parallel_setup_cost", state->init_parasetup_cost, state->context); set_config_int32_option("min_parallel_table_scan_size", state->init_min_para_tablescan_size, @@ -2857,9 +2898,7 @@ get_current_hint_string(ParseState *pstate, Query *query) */ query_len = strlen(query_str) + 1; normalized_query = - generate_normalized_query(&jstate, query_str, - query->stmt_location, - &query_len, + generate_normalized_query(&jstate, query_str, 0, &query_len, GetDatabaseEncoding()); /* @@ -2920,6 +2959,14 @@ get_current_hint_string(ParseState *pstate, Query *query) current_hint_str = get_hints_from_comment(query_str); MemoryContextSwitchTo(oldcontext); } + else + { + /* + * Failed to get query. We would be in fetching invalidated + * plancache. Try the next chance. + */ + current_hint_retrieved = false; + } if (debug_level > 1) { @@ -2967,14 +3014,14 @@ static void pg_hint_plan_ProcessUtility(PlannedStmt *pstmt, const char *queryString, ProcessUtilityContext context, ParamListInfo params, QueryEnvironment *queryEnv, - DestReceiver *dest, char *completionTag) + DestReceiver *dest, QueryCompletion *qc) { if (prev_ProcessUtility_hook) prev_ProcessUtility_hook(pstmt, queryString, context, params, queryEnv, - dest, completionTag); + dest, qc); else standard_ProcessUtility(pstmt, queryString, context, params, queryEnv, - dest, completionTag); + dest, qc); if (plpgsql_recurse_level == 0) current_hint_retrieved = false; @@ -2984,12 +3031,12 @@ pg_hint_plan_ProcessUtility(PlannedStmt *pstmt, const char *queryString, * Read and set up hint information */ static PlannedStmt * -pg_hint_plan_planner(Query *parse, int cursorOptions, ParamListInfo boundParams) +pg_hint_plan_planner(Query *parse, const char *query_string, int cursorOptions, ParamListInfo boundParams) { int save_nestlevel; PlannedStmt *result; HintState *hstate; - const char *prev_hint_str; + const char *prev_hint_str = NULL; /* * Use standard planner if pg_hint_plan is disabled or current nesting @@ -3014,7 +3061,8 @@ pg_hint_plan_planner(Query *parse, int cursorOptions, ParamListInfo boundParams) * Support for nested plpgsql functions. This is quite ugly but this is the * only point I could find where I can get the query string. */ - if (plpgsql_recurse_level > 0) + if (plpgsql_recurse_level > 0 && + error_context_stack && error_context_stack->arg) { MemoryContext oldcontext; @@ -3088,6 +3136,7 @@ pg_hint_plan_planner(Query *parse, int cursorOptions, ParamListInfo boundParams) */ recurse_level++; prev_hint_str = current_hint_str; + current_hint_str = NULL; /* * Use PG_TRY mechanism to recover GUC parameters and current_hint_state to @@ -3096,9 +3145,11 @@ pg_hint_plan_planner(Query *parse, int cursorOptions, ParamListInfo boundParams) PG_TRY(); { if (prev_planner) - result = (*prev_planner) (parse, cursorOptions, boundParams); + result = (*prev_planner) (parse, query_string, + cursorOptions, boundParams); else - result = standard_planner(parse, cursorOptions, boundParams); + result = standard_planner(parse, query_string, + cursorOptions, boundParams); current_hint_str = prev_hint_str; recurse_level--; @@ -3154,9 +3205,17 @@ standard_planner_proc: } current_hint_state = NULL; if (prev_planner) - return (*prev_planner) (parse, cursorOptions, boundParams); + result = (*prev_planner) (parse, query_string, + cursorOptions, boundParams); else - return standard_planner(parse, cursorOptions, boundParams); + result = standard_planner(parse, query_string, + cursorOptions, boundParams); + + /* The upper-level planner still needs the current hint state */ + if (HintStateStack != NIL) + current_hint_state = (HintState *) lfirst(list_head(HintStateStack)); + + return result; } /* @@ -3337,7 +3396,6 @@ restrict_indexes(PlannerInfo *root, ScanMethodHint *hint, RelOptInfo *rel, bool using_parent_hint) { ListCell *cell; - ListCell *prev; ListCell *next; StringInfoData buf; RangeTblEntry *rte = root->simple_rte_array[rel->relid]; @@ -3367,7 +3425,6 @@ restrict_indexes(PlannerInfo *root, ScanMethodHint *hint, RelOptInfo *rel, * Leaving only an specified index, we delete it from a IndexOptInfo list * other than it. */ - prev = NULL; if (debug_level > 0) initStringInfo(&buf); @@ -3378,8 +3435,7 @@ restrict_indexes(PlannerInfo *root, ScanMethodHint *hint, RelOptInfo *rel, ListCell *l; bool use_index = false; - next = lnext(cell); - + next = lnext(rel->indexlist, cell); foreach(l, hint->indexnames) { char *hintname = (char *) lfirst(l); @@ -3549,10 +3605,18 @@ restrict_indexes(PlannerInfo *root, ScanMethodHint *hint, RelOptInfo *rel, } if (!use_index) - rel->indexlist = list_delete_cell(rel->indexlist, cell, prev); - else - prev = cell; + { + rel->indexlist = list_delete_cell(rel->indexlist, cell); + /* + * The cells after the deleted cell have been moved towards the + * list head by 1 element. the next iteration should visit the + * cell at the same address if any. + */ + if (next) + next = cell; + } + pfree(indexname); } @@ -3732,32 +3796,50 @@ setup_hint_enforcement(PlannerInfo *root, RelOptInfo *rel, return 0; } - /* Forget about the parent of another subquery */ - if (root != current_hint_state->current_root) - current_hint_state->parent_relid = 0; - - /* Find the parent for this relation other than the registered parent */ - foreach (l, root->append_rel_list) + /* + * Forget about the parent of another subquery, but don't forget if the + * inhTargetkind of the root is not INHKIND_NONE, which signals the root + * contains only appendrel members. See inheritance_planner for details. + * + * (PG12.0) 428b260f87 added one more planning cycle for updates on + * partitioned tables and hints set up in the cycle are overriden by the + * second cycle. Since I didn't find no apparent distinction between the + * PlannerRoot of the cycle and that of ordinary CMD_SELECT, pg_hint_plan + * accepts both cycles and the later one wins. In the second cycle root + * doesn't have inheritance information at all so use the parent_relid set + * in the first cycle. + */ + if (root->inhTargetKind == INHKIND_NONE) { - AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l); + if (root != current_hint_state->current_root) + current_hint_state->parent_relid = 0; - if (appinfo->child_relid == rel->relid) + /* Find the parent for this relation other than the registered parent */ + foreach (l, root->append_rel_list) { - if (current_hint_state->parent_relid != appinfo->parent_relid) + AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l); + + if (appinfo->child_relid == rel->relid) { - new_parent_relid = appinfo->parent_relid; - current_hint_state->current_root = root; + if (current_hint_state->parent_relid != appinfo->parent_relid) + { + new_parent_relid = appinfo->parent_relid; + current_hint_state->current_root = root; + } + break; } - break; } - } - if (!l) - { - /* This relation doesn't have a parent. Cancel current_hint_state. */ - current_hint_state->parent_relid = 0; - current_hint_state->parent_scan_hint = NULL; - current_hint_state->parent_parallel_hint = NULL; + if (!l) + { + /* + * This relation doesn't have a parent. Cancel + * current_hint_state. + */ + current_hint_state->parent_relid = 0; + current_hint_state->parent_scan_hint = NULL; + current_hint_state->parent_parallel_hint = NULL; + } } if (new_parent_relid > 0) @@ -3794,7 +3876,7 @@ setup_hint_enforcement(PlannerInfo *root, RelOptInfo *rel, parentrel_oid = root->simple_rte_array[current_hint_state->parent_relid]->relid; - parent_rel = heap_open(parentrel_oid, NoLock); + parent_rel = table_open(parentrel_oid, NoLock); /* Search the parent relation for indexes match the hint spec */ foreach(l, RelationGetIndexList(parent_rel)) @@ -3818,7 +3900,7 @@ setup_hint_enforcement(PlannerInfo *root, RelOptInfo *rel, lappend(current_hint_state->parent_index_infos, parent_index_info); } - heap_close(parent_rel, NoLock); + table_close(parent_rel, NoLock); } } } @@ -3998,8 +4080,8 @@ OuterInnerJoinCreate(OuterInnerRels *outer_inner, LeadingHint *leading_hint, leading_hint->base.hint_str)); } - outer_rels = lfirst(outer_inner->outer_inner_pair->head); - inner_rels = lfirst(outer_inner->outer_inner_pair->tail); + outer_rels = linitial(outer_inner->outer_inner_pair); + inner_rels = llast(outer_inner->outer_inner_pair); outer_relids = OuterInnerJoinCreate(outer_rels, leading_hint, @@ -4306,14 +4388,13 @@ transform_join_hints(HintState *hstate, PlannerInfo *root, int nbaserel, { if (hstate->join_hint_level[i] != NIL) { - ListCell *prev = NULL; ListCell *next = NULL; for(l = list_head(hstate->join_hint_level[i]); l; l = next) { JoinMethodHint *hint = (JoinMethodHint *)lfirst(l); - next = lnext(l); + next = lnext(hstate->join_hint_level[i], l); if (hint->inner_nrels == 0 && !(bms_intersect(hint->joinrelids, joinrelids) == NULL || @@ -4321,11 +4402,16 @@ transform_join_hints(HintState *hstate, PlannerInfo *root, int nbaserel, hint->joinrelids))) { hstate->join_hint_level[i] = - list_delete_cell(hstate->join_hint_level[i], l, - prev); + list_delete_cell(hstate->join_hint_level[i], l); + /* + * The cells after the deleted cell have been moved + * towards the list head by 1 element. the next + * iteration should visit the cell at the same address + * if any. + */ + if (next) + next = l; } - else - prev = l; } } }