firtst release
修訂 | ceb5af4e8d1baaf04faeee21c602bddb1dc75e4c (tree) |
---|---|
時間 | 2020-02-14 15:43:50 |
作者 | Kyotaro Horiguchi <horikyota.ntt@gmai...> |
Commiter | Kyotaro Horiguchi |
Fix crash bug caused by plancache invalidation
https://github.com/ossc-db/pg_hint_plan/issues/41
After plancache is invalidated then revaliated, get_query_string
accesses query_list of invalid plansource then crash. Ignore invalid
plancache and get the correct hint string and Query node at the next
planning time during revalidation.
On the way fixing this, a bug related to planner reentrance is
fixed. That fix causes behavioral change for nested
planning. Previously outer-level hint (wrongly) overrides inner-level
query but currenlty outer-level hint no longer affects inner-level
query.
@@ -4464,6 +4464,11 @@ CREATE OR REPLACE FUNCTION recall_planner() RETURNS int AS $$ | ||
4464 | 4464 | ORDER BY t_1.c1 LIMIT 1; |
4465 | 4465 | $$ LANGUAGE SQL IMMUTABLE; |
4466 | 4466 | --No.13-4-1 |
4467 | +-- recall_planner() is reduced to constant while planning using the | |
4468 | +-- hint defined in the function. Then the outer query is planned based | |
4469 | +-- on the following hint. pg_hint_plan shows the log for the function | |
4470 | +-- but the resulting explain output doesn't contain the corresponding | |
4471 | +-- plan. | |
4467 | 4472 | /*+HashJoin(t_1 t_2)*/ |
4468 | 4473 | EXPLAIN (COSTS false) |
4469 | 4474 | SELECT recall_planner() FROM s1.t1 t_1 |
@@ -4471,7 +4476,7 @@ EXPLAIN (COSTS false) | ||
4471 | 4476 | ORDER BY t_1.c1; |
4472 | 4477 | LOG: pg_hint_plan: |
4473 | 4478 | used hint: |
4474 | -HashJoin(t_1 t_2) | |
4479 | +IndexScan(t_1) | |
4475 | 4480 | not used hint: |
4476 | 4481 | duplication hint: |
4477 | 4482 | error hint: |
@@ -4496,6 +4501,7 @@ error hint: | ||
4496 | 4501 | (7 rows) |
4497 | 4502 | |
4498 | 4503 | --No.13-4-2 |
4504 | +--See description for No.13-4-1 | |
4499 | 4505 | /*+HashJoin(st_1 st_2)*/ |
4500 | 4506 | EXPLAIN (COSTS false) |
4501 | 4507 | SELECT recall_planner() FROM s1.t1 st_1 |
@@ -4503,8 +4509,8 @@ EXPLAIN (COSTS false) | ||
4503 | 4509 | ORDER BY st_1.c1; |
4504 | 4510 | LOG: pg_hint_plan: |
4505 | 4511 | used hint: |
4512 | +IndexScan(t_1) | |
4506 | 4513 | not used hint: |
4507 | -HashJoin(st_1 st_2) | |
4508 | 4514 | duplication hint: |
4509 | 4515 | error hint: |
4510 | 4516 |
@@ -4528,6 +4534,7 @@ error hint: | ||
4528 | 4534 | (7 rows) |
4529 | 4535 | |
4530 | 4536 | --No.13-4-3 |
4537 | +--See description for No.13-4-1 | |
4531 | 4538 | /*+HashJoin(t_1 t_2)*/ |
4532 | 4539 | EXPLAIN (COSTS false) |
4533 | 4540 | SELECT recall_planner() FROM s1.t1 st_1 |
@@ -4535,7 +4542,7 @@ EXPLAIN (COSTS false) | ||
4535 | 4542 | ORDER BY st_1.c1; |
4536 | 4543 | LOG: pg_hint_plan: |
4537 | 4544 | used hint: |
4538 | -HashJoin(t_1 t_2) | |
4545 | +IndexScan(t_1) | |
4539 | 4546 | not used hint: |
4540 | 4547 | duplication hint: |
4541 | 4548 | error hint: |
@@ -4559,6 +4566,7 @@ error hint: | ||
4559 | 4566 | (6 rows) |
4560 | 4567 | |
4561 | 4568 | --No.13-4-4 |
4569 | +--See description for No.13-4-1 | |
4562 | 4570 | /*+HashJoin(st_1 st_2)*/ |
4563 | 4571 | EXPLAIN (COSTS false) |
4564 | 4572 | SELECT recall_planner() FROM s1.t1 t_1 |
@@ -4566,8 +4574,8 @@ EXPLAIN (COSTS false) | ||
4566 | 4574 | ORDER BY t_1.c1; |
4567 | 4575 | LOG: pg_hint_plan: |
4568 | 4576 | used hint: |
4577 | +IndexScan(t_1) | |
4569 | 4578 | not used hint: |
4570 | -HashJoin(st_1 st_2) | |
4571 | 4579 | duplication hint: |
4572 | 4580 | error hint: |
4573 | 4581 |
@@ -4590,19 +4598,18 @@ error hint: | ||
4590 | 4598 | (6 rows) |
4591 | 4599 | |
4592 | 4600 | --No.13-4-5 |
4601 | +-- See description for No.13-4-1. No joins in ths plan, so | |
4602 | +-- pg_hint_plan doesn't complain on the wrongly written error hint. | |
4593 | 4603 | /*+HashJoin(t_1 t_1)*/ |
4594 | 4604 | EXPLAIN (COSTS false) |
4595 | 4605 | SELECT recall_planner() FROM s1.t1 t_1 |
4596 | 4606 | ORDER BY t_1.c1; |
4597 | -INFO: pg_hint_plan: hint syntax error at or near "HashJoin(t_1 t_1)" | |
4598 | -DETAIL: Relation name "t_1" is duplicated. | |
4599 | -CONTEXT: SQL function "recall_planner" during startup | |
4600 | 4607 | LOG: pg_hint_plan: |
4601 | 4608 | used hint: |
4609 | +IndexScan(t_1) | |
4602 | 4610 | not used hint: |
4603 | 4611 | duplication hint: |
4604 | 4612 | error hint: |
4605 | -HashJoin(t_1 t_1) | |
4606 | 4613 | |
4607 | 4614 | CONTEXT: SQL function "recall_planner" during startup |
4608 | 4615 | LOG: pg_hint_plan: |
@@ -4627,6 +4634,14 @@ EXPLAIN (COSTS false) | ||
4627 | 4634 | SELECT recall_planner_one_t() FROM s1.t1 t_1 |
4628 | 4635 | JOIN s1.t2 t_2 ON (t_1.c1 = t_2.c1) |
4629 | 4636 | ORDER BY t_1.c1; |
4637 | +LOG: pg_hint_plan: | |
4638 | +used hint: | |
4639 | +IndexScan(t_1) | |
4640 | +not used hint: | |
4641 | +duplication hint: | |
4642 | +error hint: | |
4643 | + | |
4644 | +CONTEXT: SQL function "recall_planner_one_t" during startup | |
4630 | 4645 | QUERY PLAN |
4631 | 4646 | --------------------------------------------- |
4632 | 4647 | Merge Join |
@@ -4644,8 +4659,8 @@ EXPLAIN (COSTS false) | ||
4644 | 4659 | ORDER BY t_1.c1; |
4645 | 4660 | LOG: pg_hint_plan: |
4646 | 4661 | used hint: |
4662 | +IndexScan(t_1) | |
4647 | 4663 | not used hint: |
4648 | -HashJoin(t_1 t_1) | |
4649 | 4664 | duplication hint: |
4650 | 4665 | error hint: |
4651 | 4666 |
@@ -4672,20 +4687,18 @@ HashJoin(t_1 t_1) | ||
4672 | 4687 | DROP FUNCTION recall_planner_one_t(int); |
4673 | 4688 | ERROR: function recall_planner_one_t(integer) does not exist |
4674 | 4689 | --No.13-4-7 |
4690 | +-- See description for No.13-4-1. Complains on the wrongly written hint. | |
4675 | 4691 | /*+HashJoin(t_1 t_1)*/ |
4676 | 4692 | EXPLAIN (COSTS false) |
4677 | 4693 | SELECT recall_planner() FROM s1.t1 t_1 |
4678 | 4694 | JOIN s1.t2 t_2 ON (t_1.c1 = t_2.c1) |
4679 | 4695 | ORDER BY t_1.c1; |
4680 | -INFO: pg_hint_plan: hint syntax error at or near "HashJoin(t_1 t_1)" | |
4681 | -DETAIL: Relation name "t_1" is duplicated. | |
4682 | -CONTEXT: SQL function "recall_planner" during startup | |
4683 | 4696 | LOG: pg_hint_plan: |
4684 | 4697 | used hint: |
4698 | +IndexScan(t_1) | |
4685 | 4699 | not used hint: |
4686 | 4700 | duplication hint: |
4687 | 4701 | error hint: |
4688 | -HashJoin(t_1 t_1) | |
4689 | 4702 | |
4690 | 4703 | CONTEXT: SQL function "recall_planner" during startup |
4691 | 4704 | INFO: pg_hint_plan: hint syntax error at or near "HashJoin(t_1 t_1)" |
@@ -4715,15 +4728,11 @@ EXPLAIN (COSTS false) | ||
4715 | 4728 | ORDER BY t_1.c1; |
4716 | 4729 | INFO: pg_hint_plan: hint syntax error at or near "MergeJoin(t_1 t_2)HashJoin(t_1 t_2)" |
4717 | 4730 | DETAIL: Conflict join method hint. |
4718 | -INFO: pg_hint_plan: hint syntax error at or near "MergeJoin(t_1 t_2)HashJoin(t_1 t_2)" | |
4719 | -DETAIL: Conflict join method hint. | |
4720 | -CONTEXT: SQL function "recall_planner" during startup | |
4721 | 4731 | LOG: pg_hint_plan: |
4722 | 4732 | used hint: |
4723 | -HashJoin(t_1 t_2) | |
4733 | +IndexScan(t_1) | |
4724 | 4734 | not used hint: |
4725 | 4735 | duplication hint: |
4726 | -MergeJoin(t_1 t_2) | |
4727 | 4736 | error hint: |
4728 | 4737 | |
4729 | 4738 | CONTEXT: SQL function "recall_planner" during startup |
@@ -4746,3 +4755,93 @@ error hint: | ||
4746 | 4755 | -> Seq Scan on t2 t_2 |
4747 | 4756 | (7 rows) |
4748 | 4757 | |
4758 | +--No.14-1-1 plancache invalidation | |
4759 | +CREATE TABLE s1.tpc AS SELECT a FROM generate_series(0, 999) a; | |
4760 | +CREATE INDEX ON s1.tpc(a); | |
4761 | +PREPARE p1 AS SELECT * FROM s1.tpc WHERE a < 999; | |
4762 | +/*+ IndexScan(tpc) */PREPARE p2 AS SELECT * FROM s1.tpc WHERE a < 999; | |
4763 | +/*+ SeqScan(tpc) */PREPARE p3(int) AS SELECT * FROM s1.tpc WHERE a = $1; | |
4764 | +EXPLAIN EXECUTE p1; | |
4765 | + QUERY PLAN | |
4766 | +------------------------------------------------------ | |
4767 | + Seq Scan on tpc (cost=0.00..17.50 rows=333 width=4) | |
4768 | + Filter: (a < 999) | |
4769 | +(2 rows) | |
4770 | + | |
4771 | +EXPLAIN EXECUTE p2; | |
4772 | +LOG: pg_hint_plan: | |
4773 | +used hint: | |
4774 | +IndexScan(tpc) | |
4775 | +not used hint: | |
4776 | +duplication hint: | |
4777 | +error hint: | |
4778 | + | |
4779 | + QUERY PLAN | |
4780 | +------------------------------------------------------------------------ | |
4781 | + Index Scan using tpc_a_idx on tpc (cost=0.28..34.10 rows=333 width=4) | |
4782 | + Index Cond: (a < 999) | |
4783 | +(2 rows) | |
4784 | + | |
4785 | +EXPLAIN EXECUTE p3(500); | |
4786 | +LOG: pg_hint_plan: | |
4787 | +used hint: | |
4788 | +SeqScan(tpc) | |
4789 | +not used hint: | |
4790 | +duplication hint: | |
4791 | +error hint: | |
4792 | + | |
4793 | + QUERY PLAN | |
4794 | +---------------------------------------------------- | |
4795 | + Seq Scan on tpc (cost=0.00..17.50 rows=5 width=4) | |
4796 | + Filter: (a = 500) | |
4797 | +(2 rows) | |
4798 | + | |
4799 | +-- The DROP invalidates the plan caches | |
4800 | +DROP TABLE s1.tpc; | |
4801 | +EXPLAIN EXECUTE p1; | |
4802 | +ERROR: relation "s1.tpc" does not exist | |
4803 | +EXPLAIN EXECUTE p2; | |
4804 | +ERROR: relation "s1.tpc" does not exist | |
4805 | +EXPLAIN EXECUTE p3(500); | |
4806 | +ERROR: relation "s1.tpc" does not exist | |
4807 | +CREATE TABLE s1.tpc AS SELECT a FROM generate_series(0, 999) a; | |
4808 | +CREATE INDEX ON s1.tpc(a); | |
4809 | +EXPLAIN EXECUTE p1; | |
4810 | + QUERY PLAN | |
4811 | +------------------------------------------------------ | |
4812 | + Seq Scan on tpc (cost=0.00..17.50 rows=333 width=4) | |
4813 | + Filter: (a < 999) | |
4814 | +(2 rows) | |
4815 | + | |
4816 | +EXPLAIN EXECUTE p2; | |
4817 | +LOG: pg_hint_plan: | |
4818 | +used hint: | |
4819 | +IndexScan(tpc) | |
4820 | +not used hint: | |
4821 | +duplication hint: | |
4822 | +error hint: | |
4823 | + | |
4824 | + QUERY PLAN | |
4825 | +------------------------------------------------------------------------ | |
4826 | + Index Scan using tpc_a_idx on tpc (cost=0.28..34.10 rows=333 width=4) | |
4827 | + Index Cond: (a < 999) | |
4828 | +(2 rows) | |
4829 | + | |
4830 | +EXPLAIN EXECUTE p3(500); | |
4831 | +LOG: pg_hint_plan: | |
4832 | +used hint: | |
4833 | +SeqScan(tpc) | |
4834 | +not used hint: | |
4835 | +duplication hint: | |
4836 | +error hint: | |
4837 | + | |
4838 | + QUERY PLAN | |
4839 | +---------------------------------------------------- | |
4840 | + Seq Scan on tpc (cost=0.00..17.50 rows=5 width=4) | |
4841 | + Filter: (a = 500) | |
4842 | +(2 rows) | |
4843 | + | |
4844 | +DEALLOCATE p1; | |
4845 | +DEALLOCATE p2; | |
4846 | +DEALLOCATE p3; | |
4847 | +DROP TABLE s1.tpc; |
@@ -451,6 +451,7 @@ static int pg_hint_plan_debug_message_level = LOG; | ||
451 | 451 | static bool pg_hint_plan_enable_hint_table = false; |
452 | 452 | |
453 | 453 | static int plpgsql_recurse_level = 0; /* PLpgSQL recursion level */ |
454 | +static int recurse_level = 0; /* recursion level incl. direct SPI calls */ | |
454 | 455 | static int hint_inhibit_level = 0; /* Inhibit hinting if this is above 0 */ |
455 | 456 | /* (This could not be above 1) */ |
456 | 457 |
@@ -1679,7 +1680,7 @@ get_query_string(ParseState *pstate, Query *query, Query **jumblequery) | ||
1679 | 1680 | * case of DESCRIBE message handling or EXECUTE command. We may still see a |
1680 | 1681 | * candidate top-level query in pstate in the case. |
1681 | 1682 | */ |
1682 | - if (!p && pstate) | |
1683 | + if (pstate && pstate->p_sourcetext) | |
1683 | 1684 | p = pstate->p_sourcetext; |
1684 | 1685 | |
1685 | 1686 | /* We don't see a query string, return NULL */ |
@@ -1756,13 +1757,24 @@ get_query_string(ParseState *pstate, Query *query, Query **jumblequery) | ||
1756 | 1757 | PreparedStatement *entry; |
1757 | 1758 | |
1758 | 1759 | entry = FetchPreparedStatement(stmt->name, true); |
1759 | - p = entry->plansource->query_string; | |
1760 | - target_query = (Query *) linitial (entry->plansource->query_list); | |
1760 | + | |
1761 | + if (entry->plansource->is_valid) | |
1762 | + { | |
1763 | + p = entry->plansource->query_string; | |
1764 | + target_query = (Query *) linitial (entry->plansource->query_list); | |
1765 | + } | |
1766 | + else | |
1767 | + { | |
1768 | + /* igonre the hint for EXECUTE if invalidated */ | |
1769 | + p = NULL; | |
1770 | + target_query = NULL; | |
1771 | + } | |
1761 | 1772 | } |
1762 | 1773 | |
1763 | 1774 | /* JumbleQuery accespts only a non-utility Query */ |
1764 | - if (!IsA(target_query, Query) || | |
1765 | - target_query->utilityStmt != NULL) | |
1775 | + if (target_query && | |
1776 | + (!IsA(target_query, Query) || | |
1777 | + target_query->utilityStmt != NULL)) | |
1766 | 1778 | target_query = NULL; |
1767 | 1779 | |
1768 | 1780 | if (jumblequery) |
@@ -2601,6 +2613,14 @@ get_current_hint_string(ParseState *pstate, Query *query) | ||
2601 | 2613 | current_hint_str = get_hints_from_comment(query_str); |
2602 | 2614 | MemoryContextSwitchTo(oldcontext); |
2603 | 2615 | } |
2616 | + else | |
2617 | + { | |
2618 | + /* | |
2619 | + * Failed to get query. We would be in fetching invalidated | |
2620 | + * plancache. Try the next chance. | |
2621 | + */ | |
2622 | + current_hint_retrieved = false; | |
2623 | + } | |
2604 | 2624 | |
2605 | 2625 | if (debug_level > 1) |
2606 | 2626 | { |
@@ -2669,6 +2689,7 @@ pg_hint_plan_planner(Query *parse, int cursorOptions, ParamListInfo boundParams) | ||
2669 | 2689 | int save_nestlevel; |
2670 | 2690 | PlannedStmt *result; |
2671 | 2691 | HintState *hstate; |
2692 | + const char *prev_hint_str = NULL; | |
2672 | 2693 | |
2673 | 2694 | /* |
2674 | 2695 | * Use standard planner if pg_hint_plan is disabled or current nesting |
@@ -2761,8 +2782,17 @@ pg_hint_plan_planner(Query *parse, int cursorOptions, ParamListInfo boundParams) | ||
2761 | 2782 | } |
2762 | 2783 | |
2763 | 2784 | /* |
2764 | - * Use PG_TRY mechanism to recover GUC parameters and current_hint to the | |
2765 | - * state when this planner started when error occurred in planner. | |
2785 | + * The planner call below may replace current_hint_str. Store and restore | |
2786 | + * it so that the subsequent planning in the upper level doesn't get | |
2787 | + * confused. | |
2788 | + */ | |
2789 | + recurse_level++; | |
2790 | + prev_hint_str = current_hint_str; | |
2791 | + current_hint_str = NULL; | |
2792 | + | |
2793 | + /* | |
2794 | + * Use PG_TRY mechanism to recover GUC parameters and current_hint_state to | |
2795 | + * the state when this planner started when error occurred in planner. | |
2766 | 2796 | */ |
2767 | 2797 | PG_TRY(); |
2768 | 2798 | { |
@@ -2770,6 +2800,9 @@ pg_hint_plan_planner(Query *parse, int cursorOptions, ParamListInfo boundParams) | ||
2770 | 2800 | result = (*prev_planner) (parse, cursorOptions, boundParams); |
2771 | 2801 | else |
2772 | 2802 | result = standard_planner(parse, cursorOptions, boundParams); |
2803 | + | |
2804 | + current_hint_str = prev_hint_str; | |
2805 | + recurse_level--; | |
2773 | 2806 | } |
2774 | 2807 | PG_CATCH(); |
2775 | 2808 | { |
@@ -2777,6 +2810,8 @@ pg_hint_plan_planner(Query *parse, int cursorOptions, ParamListInfo boundParams) | ||
2777 | 2810 | * Rollback changes of GUC parameters, and pop current hint context |
2778 | 2811 | * from hint stack to rewind the state. |
2779 | 2812 | */ |
2813 | + current_hint_str = prev_hint_str; | |
2814 | + recurse_level--; | |
2780 | 2815 | AtEOXact_GUC(true, save_nestlevel); |
2781 | 2816 | pop_hint(); |
2782 | 2817 | PG_RE_THROW(); |
@@ -1150,6 +1150,11 @@ CREATE OR REPLACE FUNCTION recall_planner() RETURNS int AS $$ | ||
1150 | 1150 | $$ LANGUAGE SQL IMMUTABLE; |
1151 | 1151 | |
1152 | 1152 | --No.13-4-1 |
1153 | +-- recall_planner() is reduced to constant while planning using the | |
1154 | +-- hint defined in the function. Then the outer query is planned based | |
1155 | +-- on the following hint. pg_hint_plan shows the log for the function | |
1156 | +-- but the resulting explain output doesn't contain the corresponding | |
1157 | +-- plan. | |
1153 | 1158 | /*+HashJoin(t_1 t_2)*/ |
1154 | 1159 | EXPLAIN (COSTS false) |
1155 | 1160 | SELECT recall_planner() FROM s1.t1 t_1 |
@@ -1157,6 +1162,7 @@ EXPLAIN (COSTS false) | ||
1157 | 1162 | ORDER BY t_1.c1; |
1158 | 1163 | |
1159 | 1164 | --No.13-4-2 |
1165 | +--See description for No.13-4-1 | |
1160 | 1166 | /*+HashJoin(st_1 st_2)*/ |
1161 | 1167 | EXPLAIN (COSTS false) |
1162 | 1168 | SELECT recall_planner() FROM s1.t1 st_1 |
@@ -1164,6 +1170,7 @@ EXPLAIN (COSTS false) | ||
1164 | 1170 | ORDER BY st_1.c1; |
1165 | 1171 | |
1166 | 1172 | --No.13-4-3 |
1173 | +--See description for No.13-4-1 | |
1167 | 1174 | /*+HashJoin(t_1 t_2)*/ |
1168 | 1175 | EXPLAIN (COSTS false) |
1169 | 1176 | SELECT recall_planner() FROM s1.t1 st_1 |
@@ -1171,6 +1178,7 @@ EXPLAIN (COSTS false) | ||
1171 | 1178 | ORDER BY st_1.c1; |
1172 | 1179 | |
1173 | 1180 | --No.13-4-4 |
1181 | +--See description for No.13-4-1 | |
1174 | 1182 | /*+HashJoin(st_1 st_2)*/ |
1175 | 1183 | EXPLAIN (COSTS false) |
1176 | 1184 | SELECT recall_planner() FROM s1.t1 t_1 |
@@ -1178,6 +1186,8 @@ EXPLAIN (COSTS false) | ||
1178 | 1186 | ORDER BY t_1.c1; |
1179 | 1187 | |
1180 | 1188 | --No.13-4-5 |
1189 | +-- See description for No.13-4-1. No joins in ths plan, so | |
1190 | +-- pg_hint_plan doesn't complain on the wrongly written error hint. | |
1181 | 1191 | /*+HashJoin(t_1 t_1)*/ |
1182 | 1192 | EXPLAIN (COSTS false) |
1183 | 1193 | SELECT recall_planner() FROM s1.t1 t_1 |
@@ -1203,6 +1213,7 @@ EXPLAIN (COSTS false) | ||
1203 | 1213 | DROP FUNCTION recall_planner_one_t(int); |
1204 | 1214 | |
1205 | 1215 | --No.13-4-7 |
1216 | +-- See description for No.13-4-1. Complains on the wrongly written hint. | |
1206 | 1217 | /*+HashJoin(t_1 t_1)*/ |
1207 | 1218 | EXPLAIN (COSTS false) |
1208 | 1219 | SELECT recall_planner() FROM s1.t1 t_1 |
@@ -1215,3 +1226,27 @@ EXPLAIN (COSTS false) | ||
1215 | 1226 | SELECT recall_planner() FROM s1.t1 t_1 |
1216 | 1227 | JOIN s1.t2 t_2 ON (t_1.c1 = t_2.c1) |
1217 | 1228 | ORDER BY t_1.c1; |
1229 | + | |
1230 | +--No.14-1-1 plancache invalidation | |
1231 | +CREATE TABLE s1.tpc AS SELECT a FROM generate_series(0, 999) a; | |
1232 | +CREATE INDEX ON s1.tpc(a); | |
1233 | +PREPARE p1 AS SELECT * FROM s1.tpc WHERE a < 999; | |
1234 | +/*+ IndexScan(tpc) */PREPARE p2 AS SELECT * FROM s1.tpc WHERE a < 999; | |
1235 | +/*+ SeqScan(tpc) */PREPARE p3(int) AS SELECT * FROM s1.tpc WHERE a = $1; | |
1236 | +EXPLAIN EXECUTE p1; | |
1237 | +EXPLAIN EXECUTE p2; | |
1238 | +EXPLAIN EXECUTE p3(500); | |
1239 | +-- The DROP invalidates the plan caches | |
1240 | +DROP TABLE s1.tpc; | |
1241 | +EXPLAIN EXECUTE p1; | |
1242 | +EXPLAIN EXECUTE p2; | |
1243 | +EXPLAIN EXECUTE p3(500); | |
1244 | +CREATE TABLE s1.tpc AS SELECT a FROM generate_series(0, 999) a; | |
1245 | +CREATE INDEX ON s1.tpc(a); | |
1246 | +EXPLAIN EXECUTE p1; | |
1247 | +EXPLAIN EXECUTE p2; | |
1248 | +EXPLAIN EXECUTE p3(500); | |
1249 | +DEALLOCATE p1; | |
1250 | +DEALLOCATE p2; | |
1251 | +DEALLOCATE p3; | |
1252 | +DROP TABLE s1.tpc; |