firtst release
Revision | 9d0d4e2bb4559097e7bb0d84d71274822ee2fa2c (tree) |
---|---|
Time | 2020-02-17 21:07:20 |
Author | Kyotaro Horiguchi <horikyota.ntt@gmai...> |
Commiter | Kyotaro Horiguchi |
Restore current hint state when returned from non-hinted query planning.
If no hint is given for the current level query, pg_hint_plan_planner
calls the next level of planner after erasing the
current_hint_state. But it forgot to restore the state before the
planning of the rest part of the current-level query. It is
(a-kind-of) broken by the commit d422966 but overlooked as an
inevitable side-effect of the fix. Get back the behavior by restoring
current_hint_state after returned from the lower level planner with
unhinted query.
Issue: https://github.com/ossc-db/pg_hint_plan/issues/30
Reported-by: higuchi-daisuke
@@ -4338,6 +4338,9 @@ BEGIN | ||
4338 | 4338 | RETURN new_cnt; |
4339 | 4339 | END; |
4340 | 4340 | $$ LANGUAGE plpgsql IMMUTABLE; |
4341 | +-- The function called at the bottom desn't use a hint, the immediate | |
4342 | +-- caller level should restore its own hint. So, the first LOG from | |
4343 | +-- pg_hint_plan should use the IndexScan(t_1) hint | |
4341 | 4344 | EXPLAIN (COSTS false) SELECT nested_planner(5) FROM s1.t1 t_1 ORDER BY t_1.c1; |
4342 | 4345 | NOTICE: nested_planner(5) |
4343 | 4346 | NOTICE: nested_planner(4) |
@@ -4345,7 +4348,12 @@ NOTICE: nested_planner(3) | ||
4345 | 4348 | NOTICE: nested_planner(2) |
4346 | 4349 | NOTICE: nested_planner(1) |
4347 | 4350 | LOG: pg_hint_plan: |
4348 | -no hint | |
4351 | +used hint: | |
4352 | +IndexScan(t_1) | |
4353 | +not used hint: | |
4354 | +duplication hint: | |
4355 | +error hint: | |
4356 | + | |
4349 | 4357 | LOG: pg_hint_plan: |
4350 | 4358 | used hint: |
4351 | 4359 | IndexScan(t_1) |
@@ -4372,7 +4380,9 @@ error hint: | ||
4372 | 4380 | Index Only Scan using t1_i1 on t1 t_1 |
4373 | 4381 | (1 row) |
4374 | 4382 | |
4375 | -/*+SeqScan(t_2)*/ | |
4383 | +-- The top level uses SeqScan(t_1), but the function should use only | |
4384 | +-- the hint in the function. | |
4385 | +/*+SeqScan(t_1) SeqScan(t_2)*/ | |
4376 | 4386 | EXPLAIN (COSTS false) SELECT nested_planner(5) FROM s1.t1 t_1 ORDER BY t_1.c1; |
4377 | 4387 | NOTICE: nested_planner(5) |
4378 | 4388 | NOTICE: nested_planner(4) |
@@ -4409,15 +4419,18 @@ error hint: | ||
4409 | 4419 | |
4410 | 4420 | LOG: pg_hint_plan: |
4411 | 4421 | used hint: |
4422 | +SeqScan(t_1) | |
4412 | 4423 | not used hint: |
4413 | 4424 | SeqScan(t_2) |
4414 | 4425 | duplication hint: |
4415 | 4426 | error hint: |
4416 | 4427 | |
4417 | - QUERY PLAN | |
4418 | ---------------------------------------- | |
4419 | - Index Only Scan using t1_i1 on t1 t_1 | |
4420 | -(1 row) | |
4428 | + QUERY PLAN | |
4429 | +-------------------------- | |
4430 | + Sort | |
4431 | + Sort Key: c1 | |
4432 | + -> Seq Scan on t1 t_1 | |
4433 | +(3 rows) | |
4421 | 4434 | |
4422 | 4435 | ---- |
4423 | 4436 | ---- No. A-13-4 output of debugging log on hint status |
@@ -3761,9 +3761,8 @@ error hint: | ||
3761 | 3761 | c4 | text | | | |
3762 | 3762 | Indexes: |
3763 | 3763 | "ti1_pkey" PRIMARY KEY, btree (c1) |
3764 | - "ti1_c2_key" UNIQUE CONSTRAINT, btree (c2) | |
3765 | - "ti1_uniq" UNIQUE, btree (c1) | |
3766 | 3764 | "ti1_btree" btree (c1) |
3765 | + "ti1_c2_key" UNIQUE CONSTRAINT, btree (c2) | |
3767 | 3766 | "ti1_expr" btree ((c1 < 100)) |
3768 | 3767 | "ti1_gin" gin (c1) |
3769 | 3768 | "ti1_gist" gist (c1) |
@@ -3775,6 +3774,7 @@ Indexes: | ||
3775 | 3774 | "ti1_multi" btree (c1, c2, c3, c4) |
3776 | 3775 | "ti1_pred" btree (lower(c4)) |
3777 | 3776 | "ti1_ts" gin (to_tsvector('english'::regconfig, c4)) |
3777 | + "ti1_uniq" UNIQUE, btree (c1) | |
3778 | 3778 | |
3779 | 3779 | EXPLAIN (COSTS false) SELECT * FROM s1.ti1 WHERE c1 < 100 AND c2 = 1 AND lower(c4) = '1' AND to_tsvector('english', c4) @@ 'a & b' AND ctid = '(1,1)'; |
3780 | 3780 | QUERY PLAN |
@@ -3201,9 +3201,15 @@ standard_planner_proc: | ||
3201 | 3201 | } |
3202 | 3202 | current_hint_state = NULL; |
3203 | 3203 | if (prev_planner) |
3204 | - return (*prev_planner) (parse, cursorOptions, boundParams); | |
3204 | + result = (*prev_planner) (parse, cursorOptions, boundParams); | |
3205 | 3205 | else |
3206 | - return standard_planner(parse, cursorOptions, boundParams); | |
3206 | + result = standard_planner(parse, cursorOptions, boundParams); | |
3207 | + | |
3208 | + /* The upper-level planner still needs the current hint state */ | |
3209 | + if (HintStateStack != NIL) | |
3210 | + current_hint_state = (HintState *) lfirst(list_head(HintStateStack)); | |
3211 | + | |
3212 | + return result; | |
3207 | 3213 | } |
3208 | 3214 | |
3209 | 3215 | /* |
@@ -1137,8 +1137,14 @@ BEGIN | ||
1137 | 1137 | END; |
1138 | 1138 | $$ LANGUAGE plpgsql IMMUTABLE; |
1139 | 1139 | |
1140 | +-- The function called at the bottom desn't use a hint, the immediate | |
1141 | +-- caller level should restore its own hint. So, the first LOG from | |
1142 | +-- pg_hint_plan should use the IndexScan(t_1) hint | |
1140 | 1143 | EXPLAIN (COSTS false) SELECT nested_planner(5) FROM s1.t1 t_1 ORDER BY t_1.c1; |
1141 | -/*+SeqScan(t_2)*/ | |
1144 | + | |
1145 | +-- The top level uses SeqScan(t_1), but the function should use only | |
1146 | +-- the hint in the function. | |
1147 | +/*+SeqScan(t_1) SeqScan(t_2)*/ | |
1142 | 1148 | EXPLAIN (COSTS false) SELECT nested_planner(5) FROM s1.t1 t_1 ORDER BY t_1.c1; |
1143 | 1149 | |
1144 | 1150 | ---- |