matrixorigin / matrixorigin/matrixone

[Compatibility]: DATE_ADD, DATE_SUB, and TIMESTAMPADD preserve TIMESTAMP type instead of DATETIME

Open
#28,563 1 comment 0 reactions 1 assignee Claimed by @jiangxinmeng1 View on GitHub
area/compatibility kind/bug needs-triage
Dominant language
Go
Stars
1.9k
Forks
311
Avg merge
1d 3h
Merged PRs (30d)
768

Description

## 现象

`DATE_ADD()`、`DATE_SUB()` 和 `TIMESTAMPADD()` 的输入是 `TIMESTAMP` 列时,MatrixOne 将结果继续解析为 `TIMESTAMP`;MySQL 8.0.46 将这类日期时间算术结果解析为 `DATETIME`。该差异会进入 view/CTAS 元数据,并改变物化结果在会话时区切换后的值。

下面使用 `TIMESTAMP(0)` 隔离类型问题;`DATE_ADD/DATE_SUB` 的小数秒精度问题已由 #28122 单独跟踪。

```sql
CREATE DATABASE interval_ts_repro;
USE interval_ts_repro;
SET time_zone = '+00:00';

CREATE TABLE src(id INT PRIMARY KEY, ts TIMESTAMP(0), dt DATETIME(0));
INSERT INTO src VALUES
(1, '2024-01-01 01:02:03', '2024-01-01 01:02:03');

CREATE VIEW v AS
SELECT
DATE_ADD(ts, INTERVAL 1 SECOND) AS da_ts,
DATE_SUB(ts, INTERVAL 1 DAY) AS ds_ts,
TIMESTAMPADD(SECOND, 1, ts) AS ta_ts,
DATE_ADD(dt, INTERVAL 1 SECOND) AS da_dt
FROM src;

SELECT column_name, data_type, datetime_precision
FROM information_schema.columns
WHERE table_schema = 'interval_ts_repro' AND table_name = 'v'
ORDER BY ordinal_position;
```

MatrixOne view 元数据:

```text
da_ts timestamp 0
ds_ts timestamp 0
ta_ts timestamp 0
da_dt datetime 0
```

MySQL 8.0.46:

```text
da_ts datetime 0
ds_ts datetime 0
ta_ts datetime 0
da_dt datetime 0
```

`DATE_ADD/DATE_SUB` 还可直接物化出不同语义:

```sql
CREATE TABLE copied AS
SELECT
DATE_ADD(ts, INTERVAL 1 SECOND) AS da_ts,
DATE_SUB(ts, INTERVAL 1 DAY) AS ds_ts,
DATE_ADD(dt, INTERVAL 1 SECOND) AS da_dt
FROM src;

SET time_zone = '+08:00';

SELECT CAST(da_ts AS CHAR), CAST(ds_ts AS CHAR), CAST(da_dt AS CHAR)
FROM copied;
```

MatrixOne 将两个 `TIMESTAMP` 派生列从创建时的 `01:02:04` / `01:02:03` 转换为 `09:02:04` / `09:02:03`;`DATETIME` 控制列不变。MySQL 的三个 CTAS 列均为 `DATETIME`,切换时区后都保持创建时的墙钟值。

`TIMESTAMPADD()` 的 CTAS 当前另受 #28562 阻塞,但 view 元数据已经能独立确认其返回类型差异。

## 影响

- view/CTAS schema inference 与 MySQL 不一致;
- MatrixOne 将日期时间算术的物化结果保存为绝对时间,跨会话时区读取时发生转换;
- MySQL 将结果保存为 `DATETIME` 墙钟值,不随读取会话时区改变。

## 代码定位

`pkg/sql/plan/function/list_builtIn.go` 中以下 overload 将 `TIMESTAMP` 输入的返回类型声明为 `T_timestamp`:

- `DATE_ADD` overload 4;
- `DATE_SUB` overload 4;
- `TIMESTAMPADD` overload 2/6。

对应执行路径也返回 `types.Timestamp`。相邻的 `DATETIME` 输入返回 `DATETIME`,符合 MySQL。

## 验证范围

- MatrixOne: latest `main` `ac660ae56ecd37bab3dd8c61193617a323377029`
- MySQL oracle: 8.0.46
- DATE_ADD / DATE_SUB / TIMESTAMPADD
- TIMESTAMP 与 DATETIME 控制
- view 和 CTAS 元数据、`+00:00` 创建后在 `+08:00` 读取
- 3 个全新数据库重复,结果一致

MySQL 文档明确说明 `DATE_ADD/DATE_SUB` 的首参数为 `DATETIME` 或 `TIMESTAMP` 时返回 `DATETIME`:
https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_date-add

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.