firtst release
修訂 | 647bad47746afec7b58d3a498bce6f36bd9ae984 (tree) |
---|---|
時間 | 2019-02-26 17:49:50 |
作者 | 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.
@@ -521,6 +521,7 @@ static int pg_hint_plan_debug_message_level = LOG; | ||
521 | 521 | static bool pg_hint_plan_enable_hint_table = false; |
522 | 522 | |
523 | 523 | static int plpgsql_recurse_level = 0; /* PLpgSQL recursion level */ |
524 | +static int recurse_level = 0; /* recursion level incl. direct SPI calls */ | |
524 | 525 | static int hint_inhibit_level = 0; /* Inhibit hinting if this is above 0 */ |
525 | 526 | /* (This could not be above 1) */ |
526 | 527 | static int max_hint_nworkers = -1; /* Maximum nworkers of Workers hints */ |
@@ -2993,6 +2994,7 @@ pg_hint_plan_planner(Query *parse, int cursorOptions, ParamListInfo boundParams) | ||
2993 | 2994 | int save_nestlevel; |
2994 | 2995 | PlannedStmt *result; |
2995 | 2996 | HintState *hstate; |
2997 | + const char *prev_hint_str; | |
2996 | 2998 | |
2997 | 2999 | /* |
2998 | 3000 | * Use standard planner if pg_hint_plan is disabled or current nesting |
@@ -3021,9 +3023,6 @@ pg_hint_plan_planner(Query *parse, int cursorOptions, ParamListInfo boundParams) | ||
3021 | 3023 | { |
3022 | 3024 | MemoryContext oldcontext; |
3023 | 3025 | |
3024 | - if (current_hint_str) | |
3025 | - pfree((void *)current_hint_str); | |
3026 | - | |
3027 | 3026 | oldcontext = MemoryContextSwitchTo(TopMemoryContext); |
3028 | 3027 | current_hint_str = |
3029 | 3028 | get_hints_from_comment((char *)error_context_stack->arg); |
@@ -3093,10 +3092,21 @@ pg_hint_plan_planner(Query *parse, int cursorOptions, ParamListInfo boundParams) | ||
3093 | 3092 | */ |
3094 | 3093 | PG_TRY(); |
3095 | 3094 | { |
3095 | + /* | |
3096 | + * The planner call below may replace current_hint_str. Store and | |
3097 | + * restore it so that the subsequent planning in the upper level | |
3098 | + * doesn't get confused. | |
3099 | + */ | |
3100 | + recurse_level++; | |
3101 | + prev_hint_str = current_hint_str; | |
3102 | + | |
3096 | 3103 | if (prev_planner) |
3097 | 3104 | result = (*prev_planner) (parse, cursorOptions, boundParams); |
3098 | 3105 | else |
3099 | 3106 | result = standard_planner(parse, cursorOptions, boundParams); |
3107 | + | |
3108 | + current_hint_str = prev_hint_str; | |
3109 | + recurse_level--; | |
3100 | 3110 | } |
3101 | 3111 | PG_CATCH(); |
3102 | 3112 | { |
@@ -3104,6 +3114,8 @@ pg_hint_plan_planner(Query *parse, int cursorOptions, ParamListInfo boundParams) | ||
3104 | 3114 | * Rollback changes of GUC parameters, and pop current hint context |
3105 | 3115 | * from hint stack to rewind the state. |
3106 | 3116 | */ |
3117 | + current_hint_str = prev_hint_str; | |
3118 | + recurse_level--; | |
3107 | 3119 | AtEOXact_GUC(true, save_nestlevel); |
3108 | 3120 | pop_hint(); |
3109 | 3121 | PG_RE_THROW(); |
@@ -3114,7 +3126,7 @@ pg_hint_plan_planner(Query *parse, int cursorOptions, ParamListInfo boundParams) | ||
3114 | 3126 | /* |
3115 | 3127 | * current_hint_str is useless after planning of the top-level query. |
3116 | 3128 | */ |
3117 | - if (plpgsql_recurse_level < 1 && current_hint_str) | |
3129 | + if (recurse_level < 1 && current_hint_str) | |
3118 | 3130 | { |
3119 | 3131 | pfree((void *)current_hint_str); |
3120 | 3132 | current_hint_str = NULL; |