Use the SetCookie opcode to implement user_version pragma

This commit is contained in:
meteorgan
2025-05-26 23:28:15 +08:00
parent ac97ac36a6
commit d9d3a5ecbb
4 changed files with 71 additions and 13 deletions

View File

@@ -10,10 +10,10 @@ use crate::fast_lock::SpinLock;
use crate::schema::Schema;
use crate::storage::sqlite3_ondisk::{DatabaseHeader, MIN_PAGE_CACHE_SIZE};
use crate::storage::wal::CheckpointMode;
use crate::util::normalize_ident;
use crate::util::{normalize_ident, parse_numeric_literal};
use crate::vdbe::builder::{ProgramBuilder, ProgramBuilderOpts, QueryMode};
use crate::vdbe::insn::{Cookie, Insn};
use crate::{bail_parse_error, Pager};
use crate::{bail_parse_error, Pager, Value};
use std::str::FromStr;
use strum::IntoEnumIterator;
@@ -142,27 +142,31 @@ fn update_pragma(
Ok(())
}
PragmaName::UserVersion => {
let version_value = match value {
let data = match value {
ast::Expr::Literal(ast::Literal::Numeric(numeric_value)) => {
numeric_value.parse::<i32>()?
parse_numeric_literal(&numeric_value)?
}
ast::Expr::Unary(ast::UnaryOperator::Negative, expr) => match *expr {
ast::Expr::Literal(ast::Literal::Numeric(numeric_value)) => {
-numeric_value.parse::<i32>()?
let data = "-".to_owned() + numeric_value.as_str();
parse_numeric_literal(&data)?
}
_ => bail_parse_error!("Not a valid value"),
},
_ => bail_parse_error!("Not a valid value"),
};
let version_value = match data {
Value::Integer(i) => i as i32,
Value::Float(f) => f as i32,
_ => unreachable!(),
};
let mut header_guard = header.lock();
// update in-memory
header_guard.user_version = version_value;
// update in disk
pager.write_database_header(&header_guard);
program.emit_insn(Insn::SetCookie {
db: 0,
cookie: Cookie::UserVersion,
value: version_value,
p5: 1,
});
Ok(())
}
PragmaName::SchemaVersion => {

View File

@@ -4520,6 +4520,37 @@ pub fn op_read_cookie(
Ok(InsnFunctionStepResult::Step)
}
pub fn op_set_cookie(
program: &Program,
state: &mut ProgramState,
insn: &Insn,
pager: &Rc<Pager>,
mv_store: Option<&Rc<MvStore>>,
) -> Result<InsnFunctionStepResult> {
let Insn::SetCookie {
db,
cookie,
value,
p5,
} = insn
else {
unreachable!("unexpected Insn {:?}", insn)
};
if *db > 0 {
todo!("temp databases not implemented yet");
}
match cookie {
Cookie::UserVersion => {
let mut header_guard = pager.db_header.lock();
header_guard.user_version = *value;
pager.write_database_header(&*header_guard);
}
cookie => todo!("{cookie:?} is not yet implement for SetCookie"),
}
state.pc += 1;
Ok(InsnFunctionStepResult::Step)
}
pub fn op_shift_right(
program: &Program,
state: &mut ProgramState,

View File

@@ -1373,6 +1373,20 @@ pub fn insn_to_str(
0,
"".to_string(),
),
Insn::SetCookie {
db,
cookie,
value,
p5,
} => (
"SetCookie",
*db as i32,
*cookie as i32,
*value,
Value::build_text(""),
*p5,
"".to_string(),
),
Insn::AutoCommit {
auto_commit,
rollback,

View File

@@ -844,6 +844,14 @@ pub enum Insn {
dest: usize,
cookie: Cookie,
},
/// Write the value in register P3 into cookie number P2 of database P1.
/// If P2 is the SCHEMA_VERSION cookie (cookie number 1) then the internal schema version is set to P3-P5
SetCookie {
db: usize,
cookie: Cookie,
value: i32,
p5: u16,
},
/// Open a new cursor P1 to a transient table.
OpenEphemeral {
cursor_id: usize,
@@ -1010,6 +1018,7 @@ impl Insn {
Insn::Noop => execute::op_noop,
Insn::PageCount { .. } => execute::op_page_count,
Insn::ReadCookie { .. } => execute::op_read_cookie,
Insn::SetCookie { .. } => execute::op_set_cookie,
Insn::OpenEphemeral { .. } | Insn::OpenAutoindex { .. } => execute::op_open_ephemeral,
Insn::Once { .. } => execute::op_once,
Insn::Found { .. } | Insn::NotFound { .. } => execute::op_found,