pingcap / pingcap/tidb

UPDATE … AS OF TIMESTAMP silently ignores the timestamp and modifies current data

Open
#70,822 3 comments 0 reactions 0 assignees View on GitHub
affects-25.10 affects-26.3 affects-7.5 affects-8.1 affects-8.5 contribution severity/critical sig/transaction type/bug
Dominant language
Go
Stars
40.5k
Forks
6.2k
PR merge metrics
PR metrics pending

Description

## Bug Report

Please answer these questions before submitting your issue. Thanks!

### 1. Minimal reproduce step (Required)

```
CREATE TABLE ap1(id INT PRIMARY KEY, v INT);
INSERT INTO ap1 VALUES (1, 1), (2, 2);
SET @t = NOW(6);
INSERT INTO ap1 VALUES (3, 3);

UPDATE ap1 AS OF TIMESTAMP '@t' SET v = 99 WHERE id = 1;
-- TiDB: OK, rowcount=1 —— 静默执行!
SELECT * FROM ap1 WHERE id = 1; -- (1, 99) 当前数据被改!

UPDATE ap1 AS OF TIMESTAMP '@t' SET v = v * 100; -- 无 WHERE:全表更新!
SELECT * FROM ap1 ORDER BY id; -- (1,9900),(2,200),(3,300)

```
### 2. What did you expect to see? (Required)

DELETE / INSERT / REPLACE + AS OF are all correctly rejected with 1064, and UPDATE … AS OF … ORDER BY LIMIT is rejected too — plain and joined UPDATE are the only statements that bypass the guard. A user believing they operate on a historical snapshot modifies live data.

### 3. What did you see instead (Required)

```
mysql>
mysql> UPDATE ap1 AS OF TIMESTAMP '@t' SET v = 99 WHERE id = 1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0

mysql> -- TiDB: OK, rowcount=1 —— 静默执行!
mysql> SELECT * FROM ap1 WHERE id = 1; -- (1, 99) 当前数据被改!
+----+------+
| id | v |
+----+------+
| 1 | 99 |
+----+------+
1 row in set (0.00 sec)

mysql>
mysql> UPDATE ap1 AS OF TIMESTAMP '@t' SET v = v * 100; -- 无 WHERE:全表更新!
Query OK, 3 rows affected (0.00 sec)
Rows matched: 3 Changed: 3 Warnings: 0

mysql> SELECT * FROM ap1 ORDER BY id; -- (1,9900),(2,200),(3,300)
+----+------+
| id | v |
+----+------+
| 1 | 9900 |
| 2 | 200 |
| 3 | 300 |
+----+------+
3 rows in set (0.00 sec)
```
### 4. What is your TiDB version? (Required)

```
mysql> select tidb_version();
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| tidb_version() |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Release Version: v9.0.0-beta.2.pre-2174-g65ac2fad58-dirty
Edition: Community
Git Commit Hash: 65ac2fad582510b92d3c4b79999e48217c989737
Git Branch: master
UTC Build Time: 2026-08-30 15:18:00
GoVersion: go1.25.12
Race Enabled: false
Check Table Before Drop: false
Store: unistore
Kernel Type: Classic |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
```

Contributor guide

Open the contributing guide

Research direction

Start by reproducing the plain and joined UPDATE ... AS OF TIMESTAMP statements from the issue and compare their handling with DELETE, INSERT, and REPLACE AS OF statements, which are expected to return 1064. Trace the UPDATE path to identify where the AS OF guard is bypassed; done means both forms reject the statement and no current data is modified.

Written by the indexing model from the issue text.

Assessment

Tech stack
go, sql
Domain
databases
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.