Repository: pingcap/tidb (Go)

Issue:
Query result may be wrong when use `like` to do index range scan on PAD SPACE column
## Bug Report

Please answer these questions before submitting your issue. Thanks!

### 1. Minimal reproduce step (Required)

```sql
create table t(a varchar(20) collate utf8mb4_bin, index ia(a));
insert into t value('测试'),('测试  ');
select *,length(a) from t where a like '测试 %';
select *,length(a) from t where a like '测试';
```

### 2. What did you expect to see? (Required)

From mysql:
```
> select *,length(a) from t where a like '测试 %';
+----------+-----------+
| a        | length(a) |
+----------+-----------+
| 测试     |         8 |
+----------+-----------+

> select *,length(a) from t where a like '测试';
+--------+-----------+
| a      | length(a) |
+--------+-----------+
| 测试   |         6 |
+--------+-----------+
```

### 3. What did you see instead (Required)

```
> select *,length(a) from t use index () where a like '测试 %';
+----------+-----------+
| a        | length(a) |
+----------+-----------+
| 测试     |         8 |
+----------+-----------+

> select *,length(a) from t use index (ia) where a like '测试 %';
+----------+-----------+
| a        | length(a) |
+----------+-----------+
| 测试     |         6 |
| 测试     |         8 |
+----------+-----------+

> select *,length(a) from t use index () where a like '测试';
+--------+-----------+
| a      | length(a) |
+--------+-----------+
| 测试   |         6 |
+--------+-----------+

> select *,length(a) from t use index (ia) where a like '测试';
+----------+-----------+
| a        | length(a) |
+----------+-----------+
| 测试     |         6 |
| 测试     |         8 |
+----------+-----------+
```

### 4. What is your TiDB version? (Required)

From v6.0.0 to latest master





Fix (patch):
diff --git a/pkg/util/ranger/checker.go b/pkg/util/ranger/checker.go
index b279678459460..2c7812b6cdb3f 100644
--- a/pkg/util/ranger/checker.go
+++ b/pkg/util/ranger/checker.go
@@ -17,6 +17,7 @@ package ranger
 import (
 	"github.com/pingcap/tidb/pkg/expression"
 	"github.com/pingcap/tidb/pkg/parser/ast"
+	"github.com/pingcap/tidb/pkg/parser/charset"
 	"github.com/pingcap/tidb/pkg/parser/mysql"
 	"github.com/pingcap/tidb/pkg/sessionctx"
 	"github.com/pingcap/tidb/pkg/types"
@@ -168,11 +169,22 @@ func (c *conditionChecker) checkLikeFunc(scalar *expression.ScalarFunction) (isA
 	if err != nil {
 		return false, true
 	}
+	likeFuncReserve := !c.isFullLengthColumn()
+
+	// Different from `=`, trailing spaces are always significant, and can't be ignored in `like`.
+	// In tidb's implementation, for PAD SPACE collations, the trailing spaces are removed in the index key. So we are
+	// unable to distinguish 'xxx' from 'xxx   ' by a single index range scan, and we may read more data than needed by
+	// the `like` function. Therefore, a Selection is needed to filter the data.
+	// Since all collations, except for binary, implemented in tidb are PAD SPACE collations for now, we use a simple
+	// collation != binary check here.
+	if collation != charset.CollationBin {
+		likeFuncReserve = true
+	}
+
 	if len(patternStr) == 0 {
-		return true, !c.isFullLengthColumn()
+		return true, likeFuncReserve
 	}
 	escape := byte(scalar.GetArgs()[2].(*expression.Constant).Value.GetInt64())
-	likeFuncReserve := !c.isFullLengthColumn()
 	for i := 0; i < len(patternStr); i++ {
 		if patternStr[i] == escape {
 			i++