Does dbRollback() undo an ALTER TABLE executed inside a DBI transaction?
0 reputation · 21 Mar 2022, 22:25 UTC
0 reputation · 21 Mar 2022, 22:25 UTC
I am writing an R package that applies schema changes through DBI and want failures to leave the database untouched. My plan was to wrap everything in dbBegin() / dbCommit() and call dbRollback() on error, but I am unsure whether that actually protects statements like ALTER TABLE.
My understanding is that many backends issue an implicit commit around DDL, so dbRollback() would only revert DML executed after that point, while some systems (SQLite in its default mode, PostgreSQL) support transactional DDL. That would make rollback safety backend-dependent rather than something DBI guarantees.
Assume current CRAN DBI with RSQLite, RMariaDB, and RPostgres as the target backends, and that portability across all three matters.
Does DBI itself specify any behavior for rolling back DDL, or is it entirely delegated to the driver and DBMS? Is there a documented, portable pattern for making schema migrations failure-safe from R, or is per-backend branching the accepted approach? Which backends among these three actually roll back ALTER TABLE today?
34775 reputation · 21 Mar 2022, 23:43 UTC
Short answer: No, DBI does not guarantee it. dbRollback() will undo an ALTER TABLE with SQLite and PostgreSQL, but not with MariaDB/MySQL via RMariaDB. Rollback safety for DDL is backend-dependent, not a DBI guarantee.
DBI defines dbBegin, dbCommit and dbRollback as an API. It does not specify how a DBMS handles DDL inside a transaction. The SQL ROLLBACK issued by dbRollback() is subject to the underlying DBMS's transactional DDL rules and driver implementation.
Portability across RSQLite, RMariaDB and RPostgres requires per-backend handling:
Per-backend branching on dbGetInfo(con)$dbname or driver class is the accepted approach today.
Confirm behavior in your environment by checking the catalog after rollback:
# SQLite example
con <- dbConnect(RSQLite::SQLite(), "file.db")
dbBegin(con)
dbExecute(con, "ALTER TABLE test ADD COLUMN x INTEGER")
dbRollback(con)
# query sqlite_master to verify column not present
dbDisconnect(con)Repeat with information_schema for PostgreSQL and MariaDB. For SQLite, test with a file-backed database rather than :memory: for reliable results.
Assumption: current CRAN DBI, RSQLite, RPostgres and RMariaDB with stable transactional DDL semantics. Driver updates can change behavior, so verify with your versions.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.