diff --git a/COMPAT.md b/COMPAT.md index 962271493..de149ff0c 100644 --- a/COMPAT.md +++ b/COMPAT.md @@ -170,7 +170,7 @@ Limbo aims to be fully compatible with SQLite, with opt-in features not supporte | PRAGMA temp_store_directory | Not Needed | deprecated in SQLite | | PRAGMA threads | No | | | PRAGMA trusted_schema | No | | -| PRAGMA user_version | Partial | Only read implemented | +| PRAGMA user_version | Yes | | | PRAGMA vdbe_addoptrace | No | | | PRAGMA vdbe_debug | No | | | PRAGMA vdbe_listing | No | | diff --git a/core/storage/sqlite3_ondisk.rs b/core/storage/sqlite3_ondisk.rs index 19648c9e9..06a9569ab 100644 --- a/core/storage/sqlite3_ondisk.rs +++ b/core/storage/sqlite3_ondisk.rs @@ -141,7 +141,7 @@ pub struct DatabaseHeader { text_encoding: u32, /// The "user version" as read and set by the user_version pragma. - pub user_version: u32, + pub user_version: i32, /// True (non-zero) for incremental-vacuum mode. False (zero) otherwise. incremental_vacuum_enabled: u32, @@ -321,7 +321,7 @@ fn finish_read_database_header( } header.vacuum_mode_largest_root_page = u32::from_be_bytes([buf[52], buf[53], buf[54], buf[55]]); header.text_encoding = u32::from_be_bytes([buf[56], buf[57], buf[58], buf[59]]); - header.user_version = u32::from_be_bytes([buf[60], buf[61], buf[62], buf[63]]); + header.user_version = i32::from_be_bytes([buf[60], buf[61], buf[62], buf[63]]); header.incremental_vacuum_enabled = u32::from_be_bytes([buf[64], buf[65], buf[66], buf[67]]); header.application_id = u32::from_be_bytes([buf[68], buf[69], buf[70], buf[71]]); header.reserved_for_expansion.copy_from_slice(&buf[72..92]); diff --git a/core/translate/pragma.rs b/core/translate/pragma.rs index 0c7889e94..5c66445f9 100644 --- a/core/translate/pragma.rs +++ b/core/translate/pragma.rs @@ -142,8 +142,28 @@ fn update_pragma( Ok(()) } PragmaName::UserVersion => { - // TODO: Implement updating user_version - todo!("updating user_version not yet implemented") + let version_value = match value { + ast::Expr::Literal(ast::Literal::Numeric(numeric_value)) => { + numeric_value.parse::()? + } + ast::Expr::Unary(ast::UnaryOperator::Negative, expr) => match *expr { + ast::Expr::Literal(ast::Literal::Numeric(numeric_value)) => { + -numeric_value.parse::()? + } + _ => bail_parse_error!("Not a valid value"), + }, + _ => bail_parse_error!("Not a valid value"), + }; + + let mut header_guard = header.lock(); + + // update in-memory + header_guard.user_version = version_value; + + // update in disk + pager.write_database_header(&header_guard); + + Ok(()) } PragmaName::SchemaVersion => { // TODO: Implement updating schema_version @@ -286,14 +306,15 @@ fn update_cache_size(value: i64, header: Arc>, pager: R cache_size_unformatted = MIN_PAGE_CACHE_SIZE as i64; } + let mut header_guard = header.lock(); + // update in-memory header - header.lock().default_page_cache_size = cache_size_unformatted + header_guard.default_page_cache_size = cache_size_unformatted .try_into() .unwrap_or_else(|_| panic!("invalid value, too big for a i32 {}", value)); // update in disk - let header_copy = header.lock().clone(); - pager.write_database_header(&header_copy); + pager.write_database_header(&header_guard); // update cache size pager diff --git a/testing/pragma.test b/testing/pragma.test index 4d56e06ab..fd98b19b9 100755 --- a/testing/pragma.test +++ b/testing/pragma.test @@ -49,4 +49,9 @@ do_execsql_test_on_specific_db "testing/testing_user_version_10.db" pragma-user- do_execsql_test_on_specific_db ":memory:" pragma-user-version-default { PRAGMA user_version -} {0} \ No newline at end of file +} {0} + +do_execsql_test_on_specific_db ":memory:" pragma-user-version-update { + PRAGMA user_version = 42; + PRAGMA user_version; +} {42}