firtst release
修訂 | 9599067426fd440c898ad01252e70c90b6948585 (tree) |
---|---|
時間 | 2019-02-26 18:30:07 |
作者 | Kyotaro Horiguchi <horiguchi.kyotaro@lab....> |
Commiter | Kyotaro Horiguchi |
Correctly handle planner nesting
pg_hint_plan assumed that plpgsql is the only source of nested planner
calls. Actually nested call can be made in any shapes. Most of the
cases doesn't harm but in a special case where pg_dbms_stats makes a
SPI call during query planning, that affects subsequent planner
work. Hints lose effect when pg_dbms_stats searches "locked
statistics" tables while planning the target query.
@@ -512,6 +512,7 @@ static int pg_hint_plan_debug_message_level = LOG; | ||
512 | 512 | static bool pg_hint_plan_enable_hint_table = false; |
513 | 513 | |
514 | 514 | static int plpgsql_recurse_level = 0; /* PLpgSQL recursion level */ |
515 | +static int recurse_level = 0; /* recursion level incl. direct SPI calls */ | |
515 | 516 | static int hint_inhibit_level = 0; /* Inhibit hinting if this is above 0 */ |
516 | 517 | /* (This could not be above 1) */ |
517 | 518 | static int max_hint_nworkers = -1; /* Maximum nworkers of Workers hints */ |
@@ -2984,6 +2985,7 @@ pg_hint_plan_planner(Query *parse, int cursorOptions, ParamListInfo boundParams) | ||
2984 | 2985 | int save_nestlevel; |
2985 | 2986 | PlannedStmt *result; |
2986 | 2987 | HintState *hstate; |
2988 | + const char *prev_hint_str; | |
2987 | 2989 | |
2988 | 2990 | /* |
2989 | 2991 | * Use standard planner if pg_hint_plan is disabled or current nesting |
@@ -3012,9 +3014,6 @@ pg_hint_plan_planner(Query *parse, int cursorOptions, ParamListInfo boundParams) | ||
3012 | 3014 | { |
3013 | 3015 | MemoryContext oldcontext; |
3014 | 3016 | |
3015 | - if (current_hint_str) | |
3016 | - pfree((void *)current_hint_str); | |
3017 | - | |
3018 | 3017 | oldcontext = MemoryContextSwitchTo(TopMemoryContext); |
3019 | 3018 | current_hint_str = |
3020 | 3019 | get_hints_from_comment((char *)error_context_stack->arg); |
@@ -3084,10 +3083,21 @@ pg_hint_plan_planner(Query *parse, int cursorOptions, ParamListInfo boundParams) | ||
3084 | 3083 | */ |
3085 | 3084 | PG_TRY(); |
3086 | 3085 | { |
3086 | + /* | |
3087 | + * The planner call below may replace current_hint_str. Store and | |
3088 | + * restore it so that the subsequent planning in the upper level | |
3089 | + * doesn't get confused. | |
3090 | + */ | |
3091 | + recurse_level++; | |
3092 | + prev_hint_str = current_hint_str; | |
3093 | + | |
3087 | 3094 | if (prev_planner) |
3088 | 3095 | result = (*prev_planner) (parse, cursorOptions, boundParams); |
3089 | 3096 | else |
3090 | 3097 | result = standard_planner(parse, cursorOptions, boundParams); |
3098 | + | |
3099 | + current_hint_str = prev_hint_str; | |
3100 | + recurse_level--; | |
3091 | 3101 | } |
3092 | 3102 | PG_CATCH(); |
3093 | 3103 | { |
@@ -3095,6 +3105,8 @@ pg_hint_plan_planner(Query *parse, int cursorOptions, ParamListInfo boundParams) | ||
3095 | 3105 | * Rollback changes of GUC parameters, and pop current hint context |
3096 | 3106 | * from hint stack to rewind the state. |
3097 | 3107 | */ |
3108 | + current_hint_str = prev_hint_str; | |
3109 | + recurse_level--; | |
3098 | 3110 | AtEOXact_GUC(true, save_nestlevel); |
3099 | 3111 | pop_hint(); |
3100 | 3112 | PG_RE_THROW(); |
@@ -3105,7 +3117,7 @@ pg_hint_plan_planner(Query *parse, int cursorOptions, ParamListInfo boundParams) | ||
3105 | 3117 | /* |
3106 | 3118 | * current_hint_str is useless after planning of the top-level query. |
3107 | 3119 | */ |
3108 | - if (plpgsql_recurse_level < 1 && current_hint_str) | |
3120 | + if (recurse_level < 1 && current_hint_str) | |
3109 | 3121 | { |
3110 | 3122 | pfree((void *)current_hint_str); |
3111 | 3123 | current_hint_str = NULL; |