Repository: pingcap/tidb (Go)

Issue:
expression: `sec_to_time` is not compatible with MySQL when the argument is a scientific notation number
## Bug Report

Please answer these questions before submitting your issue. Thanks!

### 1. What did you do?

<!-- If possible, provide a recipe for reproducing the error. -->
```
select sec_to_time(1e-5)
```
### 2. What did you expect to see?
```
mysql> select sec_to_time(1e-5);
+-------------------+
| sec_to_time(1e-5) |
+-------------------+
| 00:00:00.000010   |
+-------------------+
1 row in set (0.00 sec
```

### 3. What did you see instead?
```
mysql> select sec_to_time(1e-5);
ERROR 1292 (22007): Truncated incorrect time value: '00:00:1e-05'
```

### 4. What version of TiDB are you using? (`tidb-server -V` or run `select tidb_version();` on TiDB)
The latest master branch.


Discussion:

Patch:
diff --git a/expression/builtin_time.go b/expression/builtin_time.go
index cbb345ce2b16c..811b76a0b418c 100644
--- a/expression/builtin_time.go
+++ b/expression/builtin_time.go
@@ -5981,7 +5981,7 @@ func (b *builtinSecToTimeSig) evalDuration(row chunk.Row) (types.Duration, bool,
 	secondDemical = float64(second) + demical
 
 	var dur types.Duration
-	dur, err = types.ParseDuration(b.ctx.GetSessionVars().StmtCtx, fmt.Sprintf("%s%02d:%02d:%v", negative, hour, minute, secondDemical), int8(b.tp.Decimal))
+	dur, err = types.ParseDuration(b.ctx.GetSessionVars().StmtCtx, fmt.Sprintf("%s%02d:%02d:%s", negative, hour, minute, strconv.FormatFloat(secondDemical, 'f', -1, 64)), int8(b.tp.Decimal))
 	if err != nil {
 		return types.Duration{}, err != nil, err
 	}
diff --git a/expression/builtin_time_vec.go b/expression/builtin_time_vec.go
index 53e778a1cca08..9766e903e93d6 100644
--- a/expression/builtin_time_vec.go
+++ b/expression/builtin_time_vec.go
@@ -1869,7 +1869,7 @@ func (b *builtinSecToTimeSig) vecEvalDuration(input *chunk.Chunk, result *chunk.
 			second = seconds % 60
 		}
 		secondDemical := float64(second) + demical
-		duration, err := types.ParseDuration(b.ctx.GetSessionVars().StmtCtx, fmt.Sprintf("%s%02d:%02d:%v", negative, hour, minute, secondDemical), int8(b.tp.Decimal))
+		duration, err := types.ParseDuration(b.ctx.GetSessionVars().StmtCtx, fmt.Sprintf("%s%02d:%02d:%s", negative, hour, minute, strconv.FormatFloat(secondDemical, 'f', -1, 64)), int8(b.tp.Decimal))
 		if err != nil {
 			return err
 		}


Test patch:
diff --git a/expression/integration_test.go b/expression/integration_test.go
index b189b784128ff..9092254b22211 100755
--- a/expression/integration_test.go
+++ b/expression/integration_test.go
@@ -4967,6 +4967,14 @@ func (s *testIntegrationSuite) TestInvalidEndingStatement(c *C) {
 	assertParseErr(`drop table if exists t"`)
 }
 
+func (s *testIntegrationSuite) TestIssue15613(c *C) {
+	tk := testkit.NewTestKit(c, s.store)
+	tk.MustQuery("select sec_to_time(1e-4)").Check(testkit.Rows("00:00:00.000100"))
+	tk.MustQuery("select sec_to_time(1e-5)").Check(testkit.Rows("00:00:00.000010"))
+	tk.MustQuery("select sec_to_time(1e-6)").Check(testkit.Rows("00:00:00.000001"))
+	tk.MustQuery("select sec_to_time(1e-7)").Check(testkit.Rows("00:00:00.000000"))
+}
+
 func (s *testIntegrationSuite) TestIssue10675(c *C) {
 	tk := testkit.NewTestKit(c, s.store)
 	tk.MustExec("use test")