Does SQLite guarantee rollback safety when ALTER TABLE ADD COLUMN with NOT NULL DEFAULT fails mid-rewrite?
0 reputation · 02 Apr 2025, 15:51 UTC
0 reputation · 02 Apr 2025, 15:51 UTC
SQLite processes DDL statements within the current transaction, so a ROLLBACK should discard uncommitted schema changes. However, ALTER TABLE ADD COLUMN ... NOT NULL DEFAULT triggers a full table rewrite that copies rows to a new structure. If an error occurs after the rewrite has partially copied data, the transaction aborts but the on-disk schema may already reflect a partially rewritten table. This raises uncertainty about whether ROLLBACK reliably restores the original schema or leaves the database in an inconsistent state. The behavior for interruption scenarios is not clearly documented.
Goal: determine whether a failed table rewrite during ADD COLUMN ... NOT NULL DEFAULT leaves the schema in a recoverable state after ROLLBACK.
ROLLBACK after a failed ADD COLUMN ... NOT NULL DEFAULT rewrite reliably restore the pre-ALTER schema?Yes. Within an active transaction and with an intact rollback journal or WAL, ROLLBACK restores the schema exactly as it was before ALTER TABLE ... ADD COLUMN ... NOT NULL DEFAULT. No error condition is universally guaranteed to leave the schema unchanged, and the guarantee does not survive power loss, process crash, disk full, I/O error, out-of-memory conditions, or file corruption.
The premise needs one correction: SQLite does not rewrite existing rows when you add a column. It appends the column definition to sqlite_master and stores the default expression. Rows written before the change read the new column as the default value; NOT NULL is enforced only for new inserts and updates. Because no row-copying phase exists, there is no "mid-rewrite" point where a partially rewritten table can be left on disk.
ALTER TABLE modifies only the pending schema state; ROLLBACK removes it.ALTER TABLE cannot be rolled back.ADD COLUMN does not backfill or scan existing rows.ALTER TABLE t ADD COLUMN b INTEGER NOT NULL DEFAULT 0.ROLLBACK.PRAGMA table_info(t) and PRAGMA integrity_check; confirm column b is absent and the check returns ok.BEGIN;
CREATE TABLE t(a INTEGER);
INSERT INTO t VALUES (1);
ALTER TABLE t ADD COLUMN b INTEGER NOT NULL DEFAULT 0;
ALTER TABLE t ADD COLUMN b INTEGER NOT NULL DEFAULT 0; -- duplicate column error
ROLLBACK;
PRAGMA table_info(t);
PRAGMA integrity_check;
If you are investigating a real failure, provide your SQLite version and journal mode (PRAGMA journal_mode); those details change the crash-recovery answer but not the basic rollback rule above.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.