diff --git a/expected/pg_hint_plan.out b/expected/pg_hint_plan.out index 58c6dada..b282bb97 100644 --- a/expected/pg_hint_plan.out +++ b/expected/pg_hint_plan.out @@ -5479,15 +5479,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)*/ @@ -5527,15 +5527,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 @@ -6654,8 +6654,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: @@ -6832,8 +6832,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: @@ -7195,15 +7195,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)*/ @@ -7211,15 +7211,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].*)*/ @@ -7227,15 +7227,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].*)*/ @@ -7275,15 +7275,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)*/ @@ -7291,15 +7291,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].*)*/ @@ -7307,15 +7307,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].*)*/ @@ -7359,15 +7359,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)*/ @@ -7375,15 +7375,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].*)*/ @@ -7391,15 +7391,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 @@ -7522,8 +7522,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: @@ -7563,8 +7563,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: @@ -7686,8 +7686,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: @@ -7727,8 +7727,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: @@ -7868,8 +7868,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: @@ -7909,8 +7909,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 0f36d22a..8c5fd359 100644 --- a/expected/ut-S.out +++ b/expected/ut-S.out @@ -4534,8 +4534,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: @@ -4543,8 +4543,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 @@ -4552,8 +4552,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: @@ -4561,8 +4561,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 @@ -4570,8 +4570,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: @@ -4579,8 +4579,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; @@ -5282,11 +5282,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 @@ -5306,12 +5306,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) ---- @@ -6009,15 +6009,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 @@ -6069,8 +6069,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: @@ -6109,15 +6109,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 @@ -6160,15 +6160,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 a31bb480..d9ae882c 100644 --- a/pg_hint_plan.c +++ b/pg_hint_plan.c @@ -3433,15 +3433,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 @@ -3454,18 +3464,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); @@ -3646,11 +3658,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; @@ -3677,6 +3720,8 @@ restrict_indexes(PlannerInfo *root, ScanMethodHint *hint, RelOptInfo *rel, pfree(buf.data); pfree(rel_buf.data); } + + return restrict_result; } /* @@ -3897,8 +3942,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) { @@ -3944,14 +3987,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) {