`ALTER SEQUENCE ... RESTART WITH n` returns wrong value — rounds to arithmetic progression instead of returning `n` exactly
- Dominant language
- Go
- Stars
- 40.5k
- Forks
- 6.2k
- PR merge metrics
- PR metrics pending
Description
## Summary
`ALTER SEQUENCE seq RESTART WITH n` is specified by the SQL standard (ISO/IEC 9075-2:2003, §11 "Alter sequence generator statement") to make the very next `NEXTVAL` return **exactly `n`**. TiDB instead returns the **smallest value in the sequence's arithmetic progression `{START + k×INCREMENT}` that is ≥ n**, rounding up when `n` is not itself a member of that progression. This causes incorrect behavior in ORM frameworks (e.g. Hibernate ORM) that rely on standard `RESTART WITH` semantics for sequence resynchronization.
## Minimal Reproduction
```sql
-- Sequence with START=1 INCREMENT=20; valid values are {1, 21, 41, ..., 201, 221, ...}
CREATE SEQUENCE s START WITH 1 INCREMENT BY 20;
SELECT NEXTVAL(s); -- 1
SELECT NEXTVAL(s); -- 21
-- 220 is NOT in {1, 21, ..., 201, 221, ...}
ALTER SEQUENCE s RESTART WITH 220;
SELECT NEXTVAL(s); -- Expected: 220 Actual: 221
-- 221 IS in the progression — no rounding here
ALTER SEQUENCE s RESTART WITH 221;
SELECT NEXTVAL(s); -- Expected: 221 Actual: 221 ✓
-- NOCACHE does NOT fix the behavior
DROP SEQUENCE s;
CREATE SEQUENCE s START WITH 1 INCREMENT BY 20 NOCACHE;
ALTER SEQUENCE s RESTART WITH 220;
SELECT NEXTVAL(s); -- Expected: 220 Actual: 221 (still wrong)
DROP SEQUENCE s;
```
## Expected vs Actual
| Statement | Expected (SQL standard) | Actual (TiDB) |
|---|---|---|
| `RESTART WITH 220` on `{1,21,…,201,221,…}` | **220** | **221** |
| `RESTART WITH 219` on `{1,21,…,201,221,…}` | 219 | 221 |
| `RESTART WITH 200` on `{20,40,…,200,220,…}` | 200 | 200 ✓ (happens to be in progression) |
| `RESTART WITH 201` on `{20,40,…,200,220,…}` | 201 | 220 |
TiDB returns the correct value **only** when `n` is already a member of `{START + k×INCREMENT}`.
## SQL Standard Reference
**ISO/IEC 9075-2:2003 (SQL:2003), section 11 — "Alter sequence generator statement"** specifies that `RESTART WITH n` sets the sequence's current value so that the next execution of `NEXT VALUE FOR` returns exactly `n`. No rounding to the arithmetic progression is permitted.
All major SQL-standard-compliant databases confirm this:
- **PostgreSQL**: *"RESTART WITH restart — The specified value will be returned by the next call of `nextval`."* (https://www.postgresql.org/docs/current/sql-altersequence.html)
- **MariaDB**: *"Equivalent to calling `SETVAL()` with `is_used=0` — the specified value will be returned by the next call of `nextval`."* (https://mariadb.com/docs/server/reference/sql-structure/sequences/alter-sequence)
- **SQL Server**: *"`RESTART WITH` — the next value returned by the sequence object"* (https://learn.microsoft.com/en-us/sql/t-sql/statements/alter-sequence-transact-sql)
## SETVAL Has the Same Problem
`SETVAL(seq, n)` exhibits the same rounding behavior. Additionally, when `n` is less than the sequence's current value, `SETVAL` silently returns `NULL` and has no effect — making it impossible to reset a sequence backwards via `SETVAL`.
```sql
CREATE SEQUENCE s START WITH 1 INCREMENT BY 20;
SELECT NEXTVAL(s); -- 1
SELECT NEXTVAL(s); -- 21
SELECT SETVAL(s, 200); -- returns 200
SELECT NEXTVAL(s); -- 201 (rounds to next valid ≥ 200+1)
-- Try to go backwards — silently ignored
SELECT SETVAL(s, 10); -- NULL (no-op, can't go backwards)
SELECT NEXTVAL(s); -- 221 (continues unaffected)
```
## Impact on Hibernate ORM
Hibernate ORM's `SchemaManager.resynchronizeGenerators()` (SequenceStructure.java) issues `ALTER SEQUENCE seq RESTART WITH n` to realign a sequence after rows are bulk-inserted with explicit IDs. With `PooledOptimizer` (allocation size = 20), after inserting rows with max ID = 200, Hibernate computes `startWith = 220` and issues:
```sql
ALTER SEQUENCE TheSequence RESTART WITH 220;
```
On PostgreSQL/MariaDB: next `NEXTVAL` = 220 → `PooledOptimizer` allocates IDs [201, 220] → first generated ID = **201** ✓
On TiDB: next `NEXTVAL` = **221** → `PooledOptimizer` allocates IDs [202, 221] → first generated ID = **202** ✗
This causes `SchemaManagerResyncSequencesTest` to fail. A workaround was implemented in Hibernate (TiDBSequenceSupport) that changes sequence creation to `START WITH incrementSize` and adjusts the restart value to `RESTART WITH (startWith − increment + 1)` to compensate for TiDB's rounding. This workaround would not be needed if TiDB followed the standard.
- Test: https://github.com/hibernate/hibernate-orm/blob/main/hibernate-core/src/test/java/org/hibernate/orm/test/schemamanager/SchemaManagerResyncSequencesTest.java
- Workaround: https://github.com/hibernate/hibernate-orm/blob/main/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/TiDBSequenceSupport.java
## TiDB Version
Reproduced on TiDB v8.5.6 (April 2026)
Contributor guide
Assessment
This issue has not been assessed yet.