From 6506b3147d7ccc328553ab96e37b5613888a2d07 Mon Sep 17 00:00:00 2001 From: Glauber Costa Date: Sat, 19 Jul 2025 20:28:08 -0500 Subject: [PATCH] implement pragma application_id Just for completeness, because it is easy. --- COMPAT.md | 2 +- core/pragma.rs | 4 +++ core/storage/header_accessor.rs | 2 +- core/translate/pragma.rs | 26 +++++++++++++++++ core/vdbe/execute.rs | 4 +++ core/vdbe/insn.rs | 2 ++ testing/pragma.test | 29 +++++++++++++++++++ vendored/sqlite3-parser/src/parser/ast/mod.rs | 2 ++ 8 files changed, 69 insertions(+), 2 deletions(-) diff --git a/COMPAT.md b/COMPAT.md index f3b3fbcd0..8ce5220da 100644 --- a/COMPAT.md +++ b/COMPAT.md @@ -104,7 +104,7 @@ Turso aims to be fully compatible with SQLite, with opt-in features not supporte | Statement | Status | Comment | |----------------------------------|------------|----------------------------------------------| | PRAGMA analysis_limit | No | | -| PRAGMA application_id | No | | +| PRAGMA application_id | Yes | | | PRAGMA auto_vacuum | No | | | PRAGMA automatic_index | No | | | PRAGMA busy_timeout | No | | diff --git a/core/pragma.rs b/core/pragma.rs index 2b112ed88..7c45eefcb 100644 --- a/core/pragma.rs +++ b/core/pragma.rs @@ -35,6 +35,10 @@ pub fn pragma_for(pragma: &PragmaName) -> Pragma { use PragmaName::*; match pragma { + ApplicationId => Pragma::new( + PragmaFlags::NoColumns1 | PragmaFlags::Result0, + &["application_id"], + ), CacheSize => Pragma::new( PragmaFlags::NeedSchema | PragmaFlags::Result0 diff --git a/core/storage/header_accessor.rs b/core/storage/header_accessor.rs index b29b047d6..b9ac8902b 100644 --- a/core/storage/header_accessor.rs +++ b/core/storage/header_accessor.rs @@ -190,7 +190,7 @@ impl_header_field_accessor!( u32, HEADER_OFFSET_INCREMENTAL_VACUUM_ENABLED ); -impl_header_field_accessor!(application_id, u32, HEADER_OFFSET_APPLICATION_ID); +impl_header_field_accessor!(application_id, i32, HEADER_OFFSET_APPLICATION_ID); //impl_header_field_accessor!(reserved_for_expansion, [u8; 20], HEADER_OFFSET_RESERVED_FOR_EXPANSION); impl_header_field_accessor!(version_valid_for, u32, HEADER_OFFSET_VERSION_VALID_FOR); impl_header_field_accessor!(version_number, u32, HEADER_OFFSET_VERSION_NUMBER); diff --git a/core/translate/pragma.rs b/core/translate/pragma.rs index 9b3cd40ff..667c27be7 100644 --- a/core/translate/pragma.rs +++ b/core/translate/pragma.rs @@ -82,6 +82,22 @@ fn update_pragma( mut program: ProgramBuilder, ) -> crate::Result<(ProgramBuilder, TransactionMode)> { match pragma { + PragmaName::ApplicationId => { + let data = parse_signed_number(&value)?; + let app_id_value = match data { + Value::Integer(i) => i as i32, + Value::Float(f) => f as i32, + _ => unreachable!(), + }; + + program.emit_insn(Insn::SetCookie { + db: 0, + cookie: Cookie::ApplicationId, + value: app_id_value, + p5: 1, + }); + Ok((program, TransactionMode::Write)) + } PragmaName::CacheSize => { let cache_size = match parse_signed_number(&value)? { Value::Integer(size) => size, @@ -245,6 +261,16 @@ fn query_pragma( ) -> crate::Result<(ProgramBuilder, TransactionMode)> { let register = program.alloc_register(); match pragma { + PragmaName::ApplicationId => { + program.emit_insn(Insn::ReadCookie { + db: 0, + dest: register, + cookie: Cookie::ApplicationId, + }); + program.add_pragma_result_column(pragma.to_string()); + program.emit_result_row(register, 1); + Ok((program, TransactionMode::Read)) + } PragmaName::CacheSize => { program.emit_int(connection.get_cache_size() as i64, register); program.emit_result_row(register, 1); diff --git a/core/vdbe/execute.rs b/core/vdbe/execute.rs index 1ced21636..4414be2f5 100644 --- a/core/vdbe/execute.rs +++ b/core/vdbe/execute.rs @@ -5843,6 +5843,7 @@ pub fn op_read_cookie( todo!("temp databases not implemented yet"); } let cookie_value = match cookie { + Cookie::ApplicationId => header_accessor::get_application_id(pager)?.into(), Cookie::UserVersion => header_accessor::get_user_version(pager)?.into(), Cookie::SchemaVersion => header_accessor::get_schema_cookie(pager)?.into(), Cookie::LargestRootPageNumber => { @@ -5875,6 +5876,9 @@ pub fn op_set_cookie( todo!("temp databases not implemented yet"); } match cookie { + Cookie::ApplicationId => { + header_accessor::set_application_id(pager, *value)?; + } Cookie::UserVersion => { header_accessor::set_user_version(pager, *value)?; } diff --git a/core/vdbe/insn.rs b/core/vdbe/insn.rs index 90a3fcec1..239f00fd7 100644 --- a/core/vdbe/insn.rs +++ b/core/vdbe/insn.rs @@ -1136,4 +1136,6 @@ pub enum Cookie { UserVersion = 6, /// The auto-vacuum mode setting. IncrementalVacuum = 7, + /// The application ID as set by the application_id pragma. + ApplicationId = 8, } diff --git a/testing/pragma.test b/testing/pragma.test index 548fcfe8b..f9527806e 100755 --- a/testing/pragma.test +++ b/testing/pragma.test @@ -137,6 +137,35 @@ do_execsql_test_on_specific_db ":memory:" pragma-user-version-float-value { PRAGMA user_version; } {10} +do_execsql_test_on_specific_db ":memory:" pragma-application-id-default { + PRAGMA application_id +} {0} + +do_execsql_test_on_specific_db ":memory:" pragma-application-id-update { + PRAGMA application_id = 12345; + PRAGMA application_id; +} {12345} + +do_execsql_test_on_specific_db ":memory:" pragma-application-id-float-value { + PRAGMA application_id = 10.9; + PRAGMA application_id; +} {10} + +do_execsql_test_on_specific_db ":memory:" pragma-application-id-large-value { + PRAGMA application_id = 2147483647; + PRAGMA application_id; +} {2147483647} + +do_execsql_test_on_specific_db ":memory:" pragma-application-id-negative-value { + PRAGMA application_id = -23; + PRAGMA application_id; +} {-23} + +do_execsql_test_on_specific_db ":memory:" pragma-application-id-zero { + PRAGMA application_id = 0; + PRAGMA application_id; +} {0} + do_execsql_test pragma-legacy-file-format { PRAGMA legacy_file_format } {} diff --git a/vendored/sqlite3-parser/src/parser/ast/mod.rs b/vendored/sqlite3-parser/src/parser/ast/mod.rs index 9c661e5bc..096149c72 100644 --- a/vendored/sqlite3-parser/src/parser/ast/mod.rs +++ b/vendored/sqlite3-parser/src/parser/ast/mod.rs @@ -1743,6 +1743,8 @@ pub type PragmaValue = Expr; // TODO #[strum(serialize_all = "snake_case")] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum PragmaName { + /// Returns the application ID of the database file. + ApplicationId, /// set the autovacuum mode AutoVacuum, /// `cache_size` pragma