Repository: pingcap/tidb (Go)

Issue:
adddate function can write invalid date
## Bug Report

Please answer these questions before submitting your issue. Thanks!

### 1. Minimal reproduce step (Required)

```
drop table if exists t;
create table t(id int primary key, c int, d timestamp null default null);
begin;
insert into t values(1, 2, '2038-01-18 20:20:30');
update t set d = adddate(d, interval 1 day) where id < 10;
commit;
select * from t; -- ERROR 1292 (22007): Incorrect datetime value: '2038-01-19 20:20:30'
```

### 2. What did you expect to see? (Required)

```
MySQL [test]> update t set d = adddate(d, interval 1 day) where id < 10;
ERROR 1292 (22007): Incorrect datetime value: '2038-01-19 20:20:30' for column 'd' at row 1
```

### 3. What did you see instead (Required)

```
MySQL [test]> update t set d = adddate(d, interval 1 day) where id < 10;
Query OK, 1 row affected (0.003 sec)
Rows matched: 1  Changed: 1  Warnings: 0
```

### 4. What is your TiDB version? (Required)

This bug occurs both in 4.0 and master

```
Release Version: v4.0.0-beta.2-1419-g974c5fa78
Edition: Community
Git Commit Hash: 974c5fa78e69af35879da1494b771f498ebfb1b4
Git Branch: master
UTC Build Time: 2020-10-23 12:06:41
GoVersion: go1.13
Race Enabled: false
TiKV Min Version: v3.0.0-60965b006877ca7234adaced7890d7b029ed1306
Check Table Before Drop: false

Release Version: v4.0.8
Edition: Community
Git Commit Hash: 66ac9fc31f1733e5eb8d11891ec1b38f9c422817
Git Branch: heads/refs/tags/v4.0.8
UTC Build Time: 2020-10-30 08:21:16
GoVersion: go1.13
Race Enabled: false
TiKV Min Version: v3.0.0-60965b006877ca7234adaced7890d7b029ed1306
Check Table Before Drop: false
```



Discussion:
/label help-wanted difficulty-easy
These labels are not found `help-wanted difficulty-easy`.
I will fix it soon.
## 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
-->
I tested with the nightly version and got this.
```sql
CREATE TABLE t(c timestamp);
INSERT INTO t VALUES('2038-01-18 03:14:07');
UPDATE t SET c = adddate(c,INTERVAL 48 HOUR);
SELECT * FROM t; -- ERROR 1292 (22007): Incorrect datetime value: '2038-01-20 03:14:07'
```




Patch:
diff --git a/expression/builtin_time.go b/expression/builtin_time.go
index b661f71818ac9..d8fe5b39710d3 100644
--- a/expression/builtin_time.go
+++ b/expression/builtin_time.go
@@ -2757,11 +2757,9 @@ func (du *baseDateArithmitical) getDateFromDatetime(ctx sessionctx.Context, args
 		return types.ZeroTime, true, err
 	}
 
-	dateTp := mysql.TypeDate
-	if date.Type() == mysql.TypeDatetime || date.Type() == mysql.TypeTimestamp || types.IsClockUnit(unit) {
-		dateTp = mysql.TypeDatetime
+	if types.IsClockUnit(unit) {
+		date.SetType(mysql.TypeDatetime)
 	}
-	date.SetType(dateTp)
 	return date, false, nil
 }
 
@@ -3030,11 +3028,9 @@ func (du *baseDateArithmitical) vecGetDateFromDatetime(b *baseBuiltinFunc, input
 			continue
 		}
 
-		dateTp := mysql.TypeDate
-		if dates[i].Type() == mysql.TypeDatetime || dates[i].Type() == mysql.TypeTimestamp || isClockUnit {
-			dateTp = mysql.TypeDatetime
+		if isClockUnit {
+			dates[i].SetType(mysql.TypeDatetime)
 		}
-		dates[i].SetType(dateTp)
 	}
 	return nil
 }


Test patch:
diff --git a/expression/integration_test.go b/expression/integration_test.go
index 617aab9ff23ba..2a86d240b9da6 100644
--- a/expression/integration_test.go
+++ b/expression/integration_test.go
@@ -7722,6 +7722,15 @@ func (s *testIntegrationSerialSuite) TestClusteredIndexAndNewCollation(c *C) {
 	tk.MustQuery("select * from t").Check(testkit.Rows("&"))
 }
 
+func (s *testIntegrationSuite) TestIssue20860(c *C) {
+	tk := testkit.NewTestKit(c, s.store)
+	tk.MustExec("use test")
+	tk.MustExec("drop table if exists t;")
+	tk.MustExec("create table t(id int primary key, c int, d timestamp null default null)")
+	tk.MustExec("insert into t values(1, 2, '2038-01-18 20:20:30')")
+	c.Assert(tk.ExecToErr("update t set d = adddate(d, interval 1 day) where id < 10"), NotNil)
+}
+
 func (s *testIntegrationSerialSuite) TestIssue20608(c *C) {
 	collate.SetNewCollationEnabledForTest(true)
 	defer collate.SetNewCollationEnabledForTest(false)