Repository: pingcap/tidb (Go)

Issue:
Should not use Point Get if the Unique index is invisible
## Bug Report

Please answer these questions before submitting your issue. Thanks!

### 1. Minimal reproduce step (Required)

<!-- a step by step guide for reproducing the bug. -->
```sql
mysql> CREATE TABLE t1 (c1 INT, UNIQUE(c1));
Query OK, 0 rows affected (0.01 sec)

mysql> ALTER TABLE t1 ALTER INDEX c1 INVISIBLE;
Query OK, 0 rows affected (0.01 sec)

mysql> desc select * from t1 where c1 = 10;
+-------------+---------+------+------------------------+---------------+
| id          | estRows | task | access object          | operator info |
+-------------+---------+------+------------------------+---------------+
| Point_Get_1 | 1.00    | root | table:t1, index:c1(c1) |               |
+-------------+---------+------+------------------------+---------------+
1 row in set (0.00 sec)
```

### 2. What did you expect to see? (Required)

The query plan should not be `Point_Get` relied on `index:c1` because it is marked as invisible.

### 3. What did you see instead (Required)

The query plan is `Point_Get`

### 4. What is your TiDB version? (Required)

<!-- Paste the output of SELECT tidb_version() -->

```
mysql> select tidb_version();
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| tidb_version()                                                                                                                                                                                                                                                                                                                        |
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Release Version: v4.0.0-beta.2-1464-g369c12f77-dirty
Edition: Community
Git Commit Hash: 369c12f779f8e990f38af6a158be1d702aef4922
Git Branch: issue20759
UTC Build Time: 2020-11-02 07:44:07
GoVersion: go1.15.1
Race Enabled: false
TiKV Min Version: v3.0.0-60965b006877ca7234adaced7890d7b029ed1306
Check Table Before Drop: false |
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.01 sec)
```


Discussion:
cc @bb7133 
/assign @xiongjiwei
Seems BatchPointGet got same problem.
> Seems BatchPointGet got same problem.

Yes, I guess the reason is PointGet and BatchPointGet are in 'the fast path' in the planner(rather than the 'general plans'), which is missed before.
https://github.com/pingcap/tidb/blob/master/planner/core/point_get_plan.go#L802
seems missing check `idxInfo.Invisible`
> https://github.com/pingcap/tidb/blob/master/planner/core/point_get_plan.go#L802
> seems missing check `idxInfo.Invisible`

Yeah it should be easy to fix...
https://github.com/pingcap/tidb/blob/master/planner/core/point_get_plan.go#L543
Also here too.
@blacktear23 hi, would you like to fix this bug? 
@xiongjiwei OK
/assign @blacktear23 
## Please edit this comment or add a new comment to complete the following information

### Not a bug

1. Remove the 'type/bug' label
2. Add notes to indicate why it is not a bug

### Duplicate bug

1. Add the 'type/duplicate' label
2. Add the link to the original bug

### Bug

Note: Make Sure that 'component', and 'severity' labels are added
Example for how to fill out the template: https://github.com/pingcap/tidb/issues/20100

#### 1. Root Cause Analysis (RCA) (optional) 
<!-- Write down the reason why this bug occurs -->

#### 2. Symptom (optional)

<!-- What will the user see when this bug occurs. The error message may be in the terminal, log or monitoring -->

#### 3. All Trigger Conditions (optional)

<!-- All the user scenarios that may trigger this bug -->

#### 4. Workaround (optional)

#### 5. Affected versions

<!--
In the format of [start_version:end_version], multiple version ranges are
accepted. If the bug only affects the unreleased version, please input:
"unreleased". For example:

Notes:
  1. Do not use any white spaces in '[]'.
  2. The range in '[]' is a closed interval
  3. The version format is `v$Major.$Minor.$Patch`, the $Majoy and $Minor
     number in a version range should be the same. [v3.0.1:v3.1.2] is
     invalid because the $Minor number of the version range is different.

Example 1: [v3.0.1:v3.0.5], [v4.0.1:v4.0.5]
Example 2: unreleased
-->

#### 6. Fixed versions

<!--
The first released version that contains this fix in each minor version. If the bug's affected version has been released, the fixed version should be a detailed version number; If the bug doesn't affect any released version, the fixed version can be "master";  

Example 1: v3.0.13, v4.0.5
Example 2: master
-->



Patch:
diff --git a/planner/core/point_get_plan.go b/planner/core/point_get_plan.go
index fd3a8afa25d16..77efe8f5d5a67 100644
--- a/planner/core/point_get_plan.go
+++ b/planner/core/point_get_plan.go
@@ -540,7 +540,7 @@ func newBatchPointGetPlan(
 	var matchIdxInfo *model.IndexInfo
 	permutations := make([]int, len(whereColNames))
 	for _, idxInfo := range tbl.Indices {
-		if !idxInfo.Unique || idxInfo.State != model.StatePublic {
+		if !idxInfo.Unique || idxInfo.State != model.StatePublic || idxInfo.Invisible {
 			continue
 		}
 		if len(idxInfo.Columns) != len(whereColNames) || idxInfo.HasPrefixIndex() {
@@ -799,10 +799,7 @@ func tryPointGetPlan(ctx sessionctx.Context, selStmt *ast.SelectStmt) *PointGetP
 	}
 
 	for _, idxInfo := range tbl.Indices {
-		if !idxInfo.Unique {
-			continue
-		}
-		if idxInfo.State != model.StatePublic {
+		if !idxInfo.Unique || idxInfo.State != model.StatePublic || idxInfo.Invisible {
 			continue
 		}
 		if isTableDual {


Test patch:
diff --git a/planner/core/point_get_plan_test.go b/planner/core/point_get_plan_test.go
index c74a1140fc4a2..91c2ff0c5cc5a 100644
--- a/planner/core/point_get_plan_test.go
+++ b/planner/core/point_get_plan_test.go
@@ -536,3 +536,29 @@ func (s *testPointGetSuite) TestIssue20692(c *C) {
 	tk3.MustExec("commit;")
 	tk3.MustQuery("select * from t;").Check(testkit.Rows("10 20 30 40"))
 }
+
+func (s *testPointGetSuite) TestPointGetWithInvisibleIndex(c *C) {
+	tk := testkit.NewTestKit(c, s.store)
+	tk.MustExec("use test")
+	tk.MustExec("drop table if exists t")
+	tk.MustExec("create table t (c1 int, unique(c1))")
+	tk.MustExec("alter table t alter index c1 invisible")
+	tk.MustQuery("explain select * from t where c1 = 10").Check(testkit.Rows(
+		"TableReader_7 1.00 root  data:Selection_6",
+		"└─Selection_6 1.00 cop[tikv]  eq(test.t.c1, 10)",
+		"  └─TableFullScan_5 10000.00 cop[tikv] table:t keep order:false, stats:pseudo",
+	))
+}
+
+func (s *testPointGetSuite) TestBatchPointGetWithInvisibleIndex(c *C) {
+	tk := testkit.NewTestKit(c, s.store)
+	tk.MustExec("use test")
+	tk.MustExec("drop table if exists t")
+	tk.MustExec("create table t (c1 int, unique(c1))")
+	tk.MustExec("alter table t alter index c1 invisible")
+	tk.MustQuery("explain select * from t where c1 in (10, 20)").Check(testkit.Rows(
+		"TableReader_7 2.00 root  data:Selection_6",
+		"└─Selection_6 2.00 cop[tikv]  in(test.t.c1, 10, 20)",
+		"  └─TableFullScan_5 10000.00 cop[tikv] table:t keep order:false, stats:pseudo",
+	))
+}