diff --git a/expected/pg_hint_plan.out b/expected/pg_hint_plan.out index b6c789b7..8ef19f85 100644 --- a/expected/pg_hint_plan.out +++ b/expected/pg_hint_plan.out @@ -5570,15 +5570,15 @@ EXPLAIN (COSTS false) SELECT * FROM t5 WHERE t5.id = 1; LOG: available indexes for IndexScan(t5): LOG: pg_hint_plan: used hint: -IndexScan(t5 no_exist) not used hint: +IndexScan(t5 no_exist) duplication hint: error hint: - QUERY PLAN --------------------- - Seq Scan on t5 - Filter: (id = 1) + QUERY PLAN +---------------------------------------------------------------------------------------- + Index Scan using t5_idaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa on t5 + Index Cond: (id = 1) (2 rows) /*+IndexScan(t5 t5_id1 t5_id2)*/ @@ -5618,15 +5618,15 @@ EXPLAIN (COSTS false) SELECT * FROM t5 WHERE t5.id = 1; LOG: available indexes for IndexScan(t5): LOG: pg_hint_plan: used hint: -IndexScan(t5 no_exist5 no_exist2) not used hint: +IndexScan(t5 no_exist5 no_exist2) duplication hint: error hint: - QUERY PLAN --------------------- - Seq Scan on t5 - Filter: (id = 1) + QUERY PLAN +---------------------------------------------------------------------------------------- + Index Scan using t5_idaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa on t5 + Index Cond: (id = 1) (2 rows) -- outer inner @@ -6745,8 +6745,8 @@ LOG: available indexes for IndexScan(p2_c3_c1): LOG: available indexes for IndexScan(p2_c3_c2): LOG: pg_hint_plan: used hint: -IndexScan(p2 p2_val) not used hint: +IndexScan(p2 p2_val) duplication hint: error hint: @@ -6923,8 +6923,8 @@ LOG: available indexes for IndexScan(p2_c1_c1): LOG: available indexes for IndexScan(p2_c1_c2): LOG: pg_hint_plan: used hint: -IndexScan(p2 no_exist) not used hint: +IndexScan(p2 no_exist) duplication hint: error hint: @@ -7286,15 +7286,15 @@ EXPLAIN (COSTS false) SELECT id FROM t5 WHERE id = 1; LOG: available indexes for IndexScanRegexp(t5): LOG: pg_hint_plan: used hint: -IndexScanRegexp(t5 t5[^_].*) not used hint: +IndexScanRegexp(t5 t5[^_].*) duplication hint: error hint: - QUERY PLAN --------------------- - Seq Scan on t5 - Filter: (id = 1) + QUERY PLAN +--------------------------------------------------------------------------------------------- + Index Only Scan using t5_idaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa on t5 + Index Cond: (id = 1) (2 rows) /*+ IndexScanRegexp(t5 ^.*t5_idaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab)*/ @@ -7302,15 +7302,15 @@ EXPLAIN (COSTS false) SELECT id FROM t5 WHERE id = 1; LOG: available indexes for IndexScanRegexp(t5): LOG: pg_hint_plan: used hint: -IndexScanRegexp(t5 ^.*t5_idaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab) not used hint: +IndexScanRegexp(t5 ^.*t5_idaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab) duplication hint: error hint: - QUERY PLAN --------------------- - Seq Scan on t5 - Filter: (id = 1) + QUERY PLAN +--------------------------------------------------------------------------------------------- + Index Only Scan using t5_idaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa on t5 + Index Cond: (id = 1) (2 rows) /*+ IndexScan(t5 t5_id[0-9].*)*/ @@ -7318,15 +7318,15 @@ EXPLAIN (COSTS false) SELECT id FROM t5 WHERE id = 1; LOG: available indexes for IndexScan(t5): LOG: pg_hint_plan: used hint: -IndexScan(t5 t5_id[0-9].*) not used hint: +IndexScan(t5 t5_id[0-9].*) duplication hint: error hint: - QUERY PLAN --------------------- - Seq Scan on t5 - Filter: (id = 1) + QUERY PLAN +--------------------------------------------------------------------------------------------- + Index Only Scan using t5_idaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa on t5 + Index Cond: (id = 1) (2 rows) /*+ IndexOnlyScanRegexp(t5 t5_[^i].*)*/ @@ -7366,15 +7366,15 @@ EXPLAIN (COSTS false) SELECT id FROM t5 WHERE id = 1; LOG: available indexes for IndexOnlyScanRegexp(t5): LOG: pg_hint_plan: used hint: -IndexOnlyScanRegexp(t5 t5[^_].*) not used hint: +IndexOnlyScanRegexp(t5 t5[^_].*) duplication hint: error hint: - QUERY PLAN --------------------- - Seq Scan on t5 - Filter: (id = 1) + QUERY PLAN +--------------------------------------------------------------------------------------------- + Index Only Scan using t5_idaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa on t5 + Index Cond: (id = 1) (2 rows) /*+ IndexOnlyScanRegexp(t5 ^.*t5_idaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab)*/ @@ -7382,15 +7382,15 @@ EXPLAIN (COSTS false) SELECT id FROM t5 WHERE id = 1; LOG: available indexes for IndexOnlyScanRegexp(t5): LOG: pg_hint_plan: used hint: -IndexOnlyScanRegexp(t5 ^.*t5_idaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab) not used hint: +IndexOnlyScanRegexp(t5 ^.*t5_idaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab) duplication hint: error hint: - QUERY PLAN --------------------- - Seq Scan on t5 - Filter: (id = 1) + QUERY PLAN +--------------------------------------------------------------------------------------------- + Index Only Scan using t5_idaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa on t5 + Index Cond: (id = 1) (2 rows) /*+ IndexOnlyScan(t5 t5_id[0-9].*)*/ @@ -7398,15 +7398,15 @@ EXPLAIN (COSTS false) SELECT id FROM t5 WHERE id = 1; LOG: available indexes for IndexOnlyScan(t5): LOG: pg_hint_plan: used hint: -IndexOnlyScan(t5 t5_id[0-9].*) not used hint: +IndexOnlyScan(t5 t5_id[0-9].*) duplication hint: error hint: - QUERY PLAN --------------------- - Seq Scan on t5 - Filter: (id = 1) + QUERY PLAN +--------------------------------------------------------------------------------------------- + Index Only Scan using t5_idaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa on t5 + Index Cond: (id = 1) (2 rows) /*+ BitmapScanRegexp(t5 t5_[^i].*)*/ @@ -7450,15 +7450,15 @@ EXPLAIN (COSTS false) SELECT id FROM t5 WHERE id = 1; LOG: available indexes for BitmapScanRegexp(t5): LOG: pg_hint_plan: used hint: -BitmapScanRegexp(t5 t5[^_].*) not used hint: +BitmapScanRegexp(t5 t5[^_].*) duplication hint: error hint: - QUERY PLAN --------------------- - Seq Scan on t5 - Filter: (id = 1) + QUERY PLAN +--------------------------------------------------------------------------------------------- + Index Only Scan using t5_idaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa on t5 + Index Cond: (id = 1) (2 rows) /*+ BitmapScanRegexp(t5 ^.*t5_idaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab)*/ @@ -7466,15 +7466,15 @@ EXPLAIN (COSTS false) SELECT id FROM t5 WHERE id = 1; LOG: available indexes for BitmapScanRegexp(t5): LOG: pg_hint_plan: used hint: -BitmapScanRegexp(t5 ^.*t5_idaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab) not used hint: +BitmapScanRegexp(t5 ^.*t5_idaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab) duplication hint: error hint: - QUERY PLAN --------------------- - Seq Scan on t5 - Filter: (id = 1) + QUERY PLAN +--------------------------------------------------------------------------------------------- + Index Only Scan using t5_idaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa on t5 + Index Cond: (id = 1) (2 rows) /*+ BitmapScan(t5 t5_id[0-9].*)*/ @@ -7482,15 +7482,15 @@ EXPLAIN (COSTS false) SELECT id FROM t5 WHERE id = 1; LOG: available indexes for BitmapScan(t5): LOG: pg_hint_plan: used hint: -BitmapScan(t5 t5_id[0-9].*) not used hint: +BitmapScan(t5 t5_id[0-9].*) duplication hint: error hint: - QUERY PLAN --------------------- - Seq Scan on t5 - Filter: (id = 1) + QUERY PLAN +--------------------------------------------------------------------------------------------- + Index Only Scan using t5_idaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa on t5 + Index Cond: (id = 1) (2 rows) -- Inheritance @@ -7613,8 +7613,8 @@ LOG: available indexes for IndexScanRegexp(p1_c3_c1): LOG: available indexes for IndexScanRegexp(p1_c3_c2): LOG: pg_hint_plan: used hint: -IndexScanRegexp(p1 p1[^_].*) not used hint: +IndexScanRegexp(p1 p1[^_].*) duplication hint: error hint: @@ -7654,8 +7654,8 @@ LOG: available indexes for IndexScan(p1_c3_c1): LOG: available indexes for IndexScan(p1_c3_c2): LOG: pg_hint_plan: used hint: -IndexScan(p1 p1_.*val2.*) not used hint: +IndexScan(p1 p1_.*val2.*) duplication hint: error hint: @@ -7777,8 +7777,8 @@ LOG: available indexes for IndexOnlyScanRegexp(p1_c3_c1): LOG: available indexes for IndexOnlyScanRegexp(p1_c3_c2): LOG: pg_hint_plan: used hint: -IndexOnlyScanRegexp(p1 p1[^_].*) not used hint: +IndexOnlyScanRegexp(p1 p1[^_].*) duplication hint: error hint: @@ -7818,8 +7818,8 @@ LOG: available indexes for IndexOnlyScan(p1_c3_c1): LOG: available indexes for IndexOnlyScan(p1_c3_c2): LOG: pg_hint_plan: used hint: -IndexOnlyScan(p1 p1_.*val2.*) not used hint: +IndexOnlyScan(p1 p1_.*val2.*) duplication hint: error hint: @@ -7959,8 +7959,8 @@ LOG: available indexes for BitmapScanRegexp(p1_c3_c1): LOG: available indexes for BitmapScanRegexp(p1_c3_c2): LOG: pg_hint_plan: used hint: -BitmapScanRegexp(p1 p1[^_].*) not used hint: +BitmapScanRegexp(p1 p1[^_].*) duplication hint: error hint: @@ -8000,8 +8000,8 @@ LOG: available indexes for BitmapScan(p1_c3_c1): LOG: available indexes for BitmapScan(p1_c3_c2): LOG: pg_hint_plan: used hint: -BitmapScan(p1 p1_.*val2.*) not used hint: +BitmapScan(p1 p1_.*val2.*) duplication hint: error hint: diff --git a/expected/ut-S.out b/expected/ut-S.out index 82cb4408..047d1ce6 100644 --- a/expected/ut-S.out +++ b/expected/ut-S.out @@ -4474,8 +4474,8 @@ error hint: LOG: available indexes for IndexScan(ti1): LOG: pg_hint_plan: used hint: -IndexScan(ti1 not_exist) not used hint: +IndexScan(ti1 not_exist) duplication hint: error hint: @@ -4483,8 +4483,8 @@ error hint: \! sql/maskout.sh results/ut-S.tmpout QUERY PLAN ---------------- - Seq Scan on ti1 (cost={inf}..{inf} rows=1 width=xxx) - Filter: (c1 = 100) + Index Scan using ti1_hash on ti1 (cost=xxx..xxx rows=1 width=xxx) + Index Cond: (c1 = 100) -- No. S-3-5-5 \o results/ut-S.tmpout @@ -4492,8 +4492,8 @@ error hint: LOG: available indexes for BitmapScan(ti1): LOG: pg_hint_plan: used hint: -BitmapScan(ti1 not_exist) not used hint: +BitmapScan(ti1 not_exist) duplication hint: error hint: @@ -4501,8 +4501,8 @@ error hint: \! sql/maskout.sh results/ut-S.tmpout QUERY PLAN ---------------- - Seq Scan on ti1 (cost={inf}..{inf} rows=1 width=xxx) - Filter: (c1 = 100) + Index Scan using ti1_hash on ti1 (cost=xxx..xxx rows=1 width=xxx) + Index Cond: (c1 = 100) -- No. S-3-5-6 \o results/ut-S.tmpout @@ -4510,8 +4510,8 @@ error hint: LOG: available indexes for IndexOnlyScan(ti1): LOG: pg_hint_plan: used hint: -IndexOnlyScan(ti1 not_exist) not used hint: +IndexOnlyScan(ti1 not_exist) duplication hint: error hint: @@ -4519,8 +4519,8 @@ error hint: \! sql/maskout.sh results/ut-S.tmpout QUERY PLAN ---------------- - Seq Scan on ti1 (cost={inf}..{inf} rows=1 width=xxx) - Filter: (c1 = 100) + Index Scan using ti1_hash on ti1 (cost=xxx..xxx rows=1 width=xxx) + Index Cond: (c1 = 100) -- No. S-3-5-7 EXPLAIN (COSTS false) SELECT * FROM s1.t1 WHERE t1.c1 = 1; @@ -5223,11 +5223,11 @@ error hint: Append (cost=xxx..xxx rows=4 width=xxx) -> Index Scan using p1_i2 on p1 p1_1 (cost=xxx..xxx rows=1 width=xxx) Index Cond: (c2 = 1) - -> Seq Scan on p1c1 p1_2 (cost={inf}..{inf} rows=1 width=xxx) + -> Seq Scan on p1c1 p1_2 (cost=xxx..xxx rows=1 width=xxx) Filter: (c2 = 1) - -> Seq Scan on p1c2 p1_3 (cost={inf}..{inf} rows=1 width=xxx) + -> Seq Scan on p1c2 p1_3 (cost=xxx..xxx rows=1 width=xxx) Filter: (c2 = 1) - -> Seq Scan on p1c3 p1_4 (cost={inf}..{inf} rows=1 width=xxx) + -> Seq Scan on p1c3 p1_4 (cost=xxx..xxx rows=1 width=xxx) Filter: (c2 = 1) -- No. S-3-10-5 @@ -5247,12 +5247,12 @@ error hint: \! sql/maskout.sh results/ut-S.tmpout QUERY PLAN ---------------- - Append (cost={inf}..{inf} rows=3 width=xxx) - -> Seq Scan on p2 p2_1 (cost={inf}..{inf} rows=1 width=xxx) + Append (cost=xxx..xxx rows=3 width=xxx) + -> Seq Scan on p2 p2_1 (cost=xxx..xxx rows=1 width=xxx) Filter: (c1 = 1) -> Index Scan using p2c1_pkey on p2c1 p2_2 (cost=xxx..xxx rows=1 width=xxx) Index Cond: (c1 = 1) - -> Seq Scan on p2c1c1 p2_3 (cost={inf}..{inf} rows=1 width=xxx) + -> Seq Scan on p2c1c1 p2_3 (cost=xxx..xxx rows=1 width=xxx) Filter: (c1 = 1) ---- @@ -5950,15 +5950,15 @@ EXPLAIN (COSTS false) SELECT * FROM s1.ti1 WHERE c2 = 1; LOG: available indexes for IndexScanRegexp(ti1): LOG: pg_hint_plan: used hint: -IndexScanRegexp(ti1 no.*_exist) not used hint: +IndexScanRegexp(ti1 no.*_exist) duplication hint: error hint: - QUERY PLAN --------------------- - Seq Scan on ti1 - Filter: (c2 = 1) + QUERY PLAN +-------------------------------- + Index Scan using ti1_i4 on ti1 + Index Cond: (c2 = 1) (2 rows) -- No. S-3-14-4 @@ -6010,8 +6010,8 @@ LOG: available indexes for IndexScanRegexp(p1): LOG: available indexes for IndexScanRegexp(p1c1): LOG: pg_hint_plan: used hint: -IndexScanRegexp(p1 no.*_exist) not used hint: +IndexScanRegexp(p1 no.*_exist) duplication hint: error hint: @@ -6050,15 +6050,15 @@ EXPLAIN (COSTS false) SELECT * FROM s1.ti1 WHERE c2 = 1; LOG: available indexes for IndexScan(ti1): LOG: pg_hint_plan: used hint: -IndexScan(ti1 not_exist) not used hint: +IndexScan(ti1 not_exist) duplication hint: error hint: - QUERY PLAN --------------------- - Seq Scan on ti1 - Filter: (c2 = 1) + QUERY PLAN +-------------------------------- + Index Scan using ti1_i4 on ti1 + Index Cond: (c2 = 1) (2 rows) -- No. S-3-15-3 @@ -6101,15 +6101,15 @@ EXPLAIN (COSTS false) SELECT * FROM s1.ti1 WHERE c2 = 1; LOG: available indexes for IndexScan(ti1): LOG: pg_hint_plan: used hint: -IndexScan(ti1 not_exist1 not_exist2) not used hint: +IndexScan(ti1 not_exist1 not_exist2) duplication hint: error hint: - QUERY PLAN --------------------- - Seq Scan on ti1 - Filter: (c2 = 1) + QUERY PLAN +-------------------------------- + Index Scan using ti1_i4 on ti1 + Index Cond: (c2 = 1) (2 rows) DELETE FROM pg_db_role_setting WHERE setrole = (SELECT oid FROM pg_roles WHERE rolname = current_user); diff --git a/pg_hint_plan.c b/pg_hint_plan.c index a421aa41..2d4421fa 100644 --- a/pg_hint_plan.c +++ b/pg_hint_plan.c @@ -3425,15 +3425,25 @@ regexpeq(const char *s1, const char *s2) } -/* Remove indexes instructed not to use by hint. */ -static void +/* + * Filter out indexes instructed in the hint as not to be used. + * + * This routine is used in relationship with the scan method enforcement, and + * it returns true to allow the follow-up scan method to be enforced, and false + * to prevent the scan enforcement. Currently, this code will not enforce + * the scan enforcement if *all* the indexes available to a relation have been + * discarded. + */ +static bool restrict_indexes(PlannerInfo *root, ScanMethodHint *hint, RelOptInfo *rel, - bool using_parent_hint) + bool using_parent_hint) { ListCell *cell; StringInfoData buf; RangeTblEntry *rte = root->simple_rte_array[rel->relid]; Oid relationObjectId = rte->relid; + List *unused_indexes = NIL; + bool restrict_result; /* * We delete all the IndexOptInfo list and prevent you from being usable by @@ -3446,18 +3456,20 @@ restrict_indexes(PlannerInfo *root, ScanMethodHint *hint, RelOptInfo *rel, rel->indexlist = NIL; hint->base.state = HINT_STATE_USED; - return; + return true; } /* * When a list of indexes is not specified, we just use all indexes. */ if (hint->indexnames == NIL) - return; + return true; /* * Leaving only an specified index, we delete it from a IndexOptInfo list - * other than it. + * other than it. However, if none of the specified indexes are available, + * then we keep all the indexes and skip enforcing the scan method. i.e., + * we skip the scan hint altogether for the relation. */ if (debug_level > 0) initStringInfo(&buf); @@ -3651,11 +3663,42 @@ restrict_indexes(PlannerInfo *root, ScanMethodHint *hint, RelOptInfo *rel, } if (!use_index) - rel->indexlist = foreach_delete_current(rel->indexlist, cell); + unused_indexes = lappend_oid(unused_indexes, info->indexoid); pfree(indexname); } + /* + * Update the list of indexes available to the IndexOptInfo based on what + * has been discarded previously. + * + * If the hint has no matching indexes, skip applying the hinted scan + * method. For example if an IndexScan hint does not have any matching + * indexes, we should not enforce an enable_indexscan. + */ + if (list_length(unused_indexes) < list_length(rel->indexlist)) + { + foreach (cell, unused_indexes) + { + Oid final_oid = lfirst_oid(cell); + ListCell *l; + + foreach (l, rel->indexlist) + { + IndexOptInfo *info = (IndexOptInfo *) lfirst(l); + + if (info->indexoid == final_oid) + rel->indexlist = foreach_delete_current(rel->indexlist, l); + } + } + + restrict_result = true; + } + else + restrict_result = false; + + list_free(unused_indexes); + if (debug_level > 0) { StringInfoData rel_buf; @@ -3682,6 +3725,8 @@ restrict_indexes(PlannerInfo *root, ScanMethodHint *hint, RelOptInfo *rel, pfree(buf.data); pfree(rel_buf.data); } + + return restrict_result; } /* @@ -3870,8 +3915,6 @@ setup_hint_enforcement(PlannerInfo *root, RelOptInfo *rel, { ScanMethodHint * pshint = current_hint_state->parent_scan_hint; - pshint->base.state = HINT_STATE_USED; - /* Apply index mask in the same manner to the parent. */ if (pshint->indexnames) { @@ -3917,14 +3960,22 @@ setup_hint_enforcement(PlannerInfo *root, RelOptInfo *rel, { bool using_parent_hint = (shint == current_hint_state->parent_scan_hint); + bool restrict_result; ret |= HINT_BM_SCAN_METHOD; - /* Setup scan enforcement environment */ - setup_scan_method_enforcement(shint, current_hint_state); + /* restrict unwanted indexes */ + restrict_result = restrict_indexes(root, shint, rel, using_parent_hint); - /* restrict unwanted inexes */ - restrict_indexes(root, shint, rel, using_parent_hint); + /* + * Setup scan enforcement environment + * + * This has to be called after restrict_indexes(), that may decide to + * skip the scan method enforcement depending on the index restrictions + * applied. + */ + if (restrict_result) + setup_scan_method_enforcement(shint, current_hint_state); if (debug_level > 1) {