Skip to content

Commit c3faf05

Browse files
committed
Merge #713: Add datatype for is_spent sqlite column
54d7684 Sqlite migrations should either succeed or fail (Vladimir Fomene) 369e17b Add datatype for is_spent sqlite column (Vladimir Fomene) Pull request description: ### Description During table creation, Sqlite does not throw an error when a column datatype is not defined. In addition, the datatype provided during table creation does not put a constraint on the type of data that can be put in that column. So you can easily put a string value in an integer column. Despite this, I think it is important for us to add the datatype for clarity. ### Notes to the reviewers You can read more about how Sqlite dynamic typing [here](https://www.sqlite.org/faq.html). I have amended our `migrate` code with a new commit. The idea is to run migrations in a transaction so that they either succeed or fail. This prevents us from having the database in an inconsistent state at any point in time. ### Checklists #### All Submissions: * [x] I've signed all my commits * [x] I followed the [contribution guidelines](https://github.com/bitcoindevkit/bdk/blob/master/CONTRIBUTING.md) * [x] I ran `cargo fmt` and `cargo clippy` before committing #### Bugfixes: * [ ] This pull request breaks the existing API * [ ] I've added tests to reproduce the issue which are now passing * [ ] I'm linking the issue being fixed by this PR ACKs for top commit: rajarshimaitra: tACK 54d7684 afilini: ACK 54d7684 Tree-SHA512: bb6c0467f799ca917f8d45c6495b766352b3177fc81952fcdd678208abf092fdeae966686528a5dcb3f342d7171783274df6312a08cbef3580063e059f5f7254
2 parents aad5461 + 54d7684 commit c3faf05

File tree

1 file changed

+36
-18
lines changed

1 file changed

+36
-18
lines changed

src/database/sqlite.rs

Lines changed: 36 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,11 @@ static MIGRATIONS: &[&str] = &[
5252
"DELETE FROM transactions;",
5353
"DELETE FROM utxos;",
5454
"DROP INDEX idx_txid_vout;",
55+
"CREATE UNIQUE INDEX idx_utxos_txid_vout ON utxos(txid, vout);",
56+
"ALTER TABLE utxos RENAME TO utxos_old;",
57+
"CREATE TABLE utxos (value INTEGER, keychain TEXT, vout INTEGER, txid BLOB, script BLOB, is_spent BOOLEAN DEFAULT 0);",
58+
"INSERT INTO utxos SELECT value, keychain, vout, txid, script, is_spent FROM utxos_old;",
59+
"DROP TABLE utxos_old;",
5560
"CREATE UNIQUE INDEX idx_utxos_txid_vout ON utxos(txid, vout);"
5661
];
5762

@@ -916,8 +921,8 @@ impl BatchDatabase for SqliteDatabase {
916921
}
917922

918923
pub fn get_connection<T: AsRef<Path>>(path: &T) -> Result<Connection, Error> {
919-
let connection = Connection::open(path)?;
920-
migrate(&connection)?;
924+
let mut connection = Connection::open(path)?;
925+
migrate(&mut connection)?;
921926
Ok(connection)
922927
}
923928

@@ -952,28 +957,41 @@ pub fn set_schema_version(conn: &Connection, version: i32) -> rusqlite::Result<u
952957
)
953958
}
954959

955-
pub fn migrate(conn: &Connection) -> rusqlite::Result<()> {
960+
pub fn migrate(conn: &mut Connection) -> Result<(), Error> {
956961
let version = get_schema_version(conn)?;
957962
let stmts = &MIGRATIONS[(version as usize)..];
958-
let mut i: i32 = version;
959963

960-
if version == MIGRATIONS.len() as i32 {
964+
// begin transaction, all migration statements and new schema version commit or rollback
965+
let tx = conn.transaction()?;
966+
967+
// execute every statement and return `Some` new schema version
968+
// if execution fails, return `Error::Rusqlite`
969+
// if no statements executed returns `None`
970+
let new_version = stmts
971+
.iter()
972+
.enumerate()
973+
.map(|version_stmt| {
974+
log::info!(
975+
"executing db migration {}: `{}`",
976+
version + version_stmt.0 as i32 + 1,
977+
version_stmt.1
978+
);
979+
tx.execute(version_stmt.1, [])
980+
// map result value to next migration version
981+
.map(|_| version_stmt.0 as i32 + version + 1)
982+
})
983+
.last()
984+
.transpose()?;
985+
986+
// if `Some` new statement version, set new schema version
987+
if let Some(version) = new_version {
988+
set_schema_version(&tx, version)?;
989+
} else {
961990
log::info!("db up to date, no migration needed");
962-
return Ok(());
963991
}
964992

965-
for stmt in stmts {
966-
let res = conn.execute(stmt, []);
967-
if res.is_err() {
968-
println!("migration failed on:\n{}\n{:?}", stmt, res);
969-
break;
970-
}
971-
972-
i += 1;
973-
}
974-
975-
set_schema_version(conn, i)?;
976-
993+
// commit transaction
994+
tx.commit()?;
977995
Ok(())
978996
}
979997

0 commit comments

Comments
 (0)