Repository: pingcap/tidb (Go)

Issue:
Cast int string to JSON results in wrong type
## Bug Report

Please answer these questions before submitting your issue. Thanks!

### 1. Minimal reproduce step (Required)

```sql
select CAST("9223372036854775808" as json);
select json_type(CAST("9223372036854775808" as json));
```

### 2. What did you expect to see? (Required)

```sql
mysql [localhost:8022] {msandbox} (test) > select CAST("9223372036854775808" as json);
+-------------------------------------+
| CAST("9223372036854775808" as json) |
+-------------------------------------+
| 9223372036854775808                 |
+-------------------------------------+
1 row in set (0.00 sec)

mysql [localhost:8022] {msandbox} (test) > select json_type(CAST("9223372036854775808" as json));
+------------------------------------------------+
| json_type(CAST("9223372036854775808" as json)) |
+------------------------------------------------+
| UNSIGNED INTEGER                               |
+------------------------------------------------+
1 row in set (0.00 sec)
```

### 3. What did you see instead (Required)

```sql
mysql> select CAST("9223372036854775808" as json);
+-------------------------------------+
| CAST("9223372036854775808" as json) |
+-------------------------------------+
| 9223372036854776000                 |
+-------------------------------------+
1 row in set (0.00 sec)

mysql> select json_type(CAST("9223372036854775808" as json));
+------------------------------------------------+
| json_type(CAST("9223372036854775808" as json)) |
+------------------------------------------------+
| DOUBLE                                         |
+------------------------------------------------+
1 row in set (0.00 sec)
```

### 4. What is your TiDB version? (Required)

```sql
mysql> SELECT tidb_version()\G
*************************** 1. row ***************************
tidb_version(): Release Version: v4.0.0-beta.2-1770-g51fbf415c
Edition: Community
Git Commit Hash: 51fbf415c904ad77b2a4c29fbfb3ff513ed60f8c
Git Branch: master
UTC Build Time: 2020-12-09 14:19:36
GoVersion: go1.13
Race Enabled: false
TiKV Min Version: v3.0.0-60965b006877ca7234adaced7890d7b029ed1306
Check Table Before Drop: false
1 row in set (0.00 sec)
```


Discussion:
## 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/types/json/binary.go b/types/json/binary.go
index eb31dd9eb2dab..061d656e5cc13 100644
--- a/types/json/binary.go
+++ b/types/json/binary.go
@@ -540,29 +540,29 @@ func appendUint32(buf []byte, v uint32) []byte {
 }
 
 func appendBinaryNumber(buf []byte, x json.Number) (TypeCode, []byte, error) {
-	var typeCode TypeCode
+	// The type interpretation process is as follows:
+	// - Attempt float64 if it contains Ee.
+	// - Next attempt int64
+	// - Then uint64 (valid in MySQL JSON, not in JSON decode library)
+	// - Then float64
+	// - Return an error
 	if strings.ContainsAny(string(x), "Ee.") {
-		typeCode = TypeCodeFloat64
 		f64, err := x.Float64()
 		if err != nil {
-			return typeCode, nil, errors.Trace(err)
-		}
-		buf = appendBinaryFloat64(buf, f64)
-	} else {
-		typeCode = TypeCodeInt64
-		i64, err := x.Int64()
-		if err != nil {
-			typeCode = TypeCodeFloat64
-			f64, err := x.Float64()
-			if err != nil {
-				return typeCode, nil, errors.Trace(err)
-			}
-			buf = appendBinaryFloat64(buf, f64)
-		} else {
-			buf = appendBinaryUint64(buf, uint64(i64))
+			return TypeCodeFloat64, nil, errors.Trace(err)
 		}
+		return TypeCodeFloat64, appendBinaryFloat64(buf, f64), nil
+	} else if val, err := x.Int64(); err == nil {
+		return TypeCodeInt64, appendBinaryUint64(buf, uint64(val)), nil
+	} else if val, err := strconv.ParseUint(string(x), 10, 64); err == nil {
+		return TypeCodeUint64, appendBinaryUint64(buf, val), nil
 	}
-	return typeCode, buf, nil
+	val, err := x.Float64()
+	if err == nil {
+		return TypeCodeFloat64, appendBinaryFloat64(buf, val), nil
+	}
+	var typeCode TypeCode
+	return typeCode, nil, errors.Trace(err)
 }
 
 func appendBinaryString(buf []byte, v string) []byte {


Test patch:
diff --git a/expression/integration_test.go b/expression/integration_test.go
index 15eb49a08d23e..4a3cf222d0ca6 100644
--- a/expression/integration_test.go
+++ b/expression/integration_test.go
@@ -7931,6 +7931,16 @@ func (s *testIntegrationSuite) TestIssue17868(c *C) {
 	tk.MustQuery("select col2 != 1 from t7").Check(testkit.Rows("1"))
 }
 
+func (s *testIntegrationSuite) TestIssue21619(c *C) {
+	tk := testkit.NewTestKit(c, s.store)
+	tk.MustQuery(`select CAST("9223372036854775808" as json)`).Check(testkit.Rows("9223372036854775808"))
+	tk.MustQuery(`select json_type(CAST("9223372036854775808" as json))`).Check(testkit.Rows("UNSIGNED INTEGER"))
+	tk.MustQuery(`select CAST(9223372036854775808 as json)`).Check(testkit.Rows("9223372036854775808"))
+	tk.MustQuery(`select json_type(CAST(9223372036854775808 as json))`).Check(testkit.Rows("UNSIGNED INTEGER"))
+	tk.MustQuery(`select CAST(-9223372036854775808 as json)`).Check(testkit.Rows("-9223372036854775808"))
+	tk.MustQuery(`select json_type(CAST(-9223372036854775808 as json))`).Check(testkit.Rows("INTEGER"))
+}
+
 func (s *testIntegrationSuite) TestIssue10467(c *C) {
 	tk := testkit.NewTestKit(c, s.store)
 	tk.MustExec("use test")