implement the JournalMode vdbe instruction

We do this already, but not through any opcode.
Move it to an opcode for compatibility reasons.
This commit is contained in:
Glauber Costa
2025-08-06 14:27:48 -05:00
parent f36974f086
commit 071330a739
5 changed files with 87 additions and 14 deletions

View File

@@ -479,7 +479,7 @@ Modifiers:
| IntegrityCk | Yes | |
| IsNull | Yes | |
| IsUnique | No | |
| JournalMode | No | |
| JournalMode | Yes | |
| Jump | Yes | |
| Last | Yes | |
| Le | Yes | |

View File

@@ -120,14 +120,23 @@ fn update_pragma(
let year = chrono::Local::now().year();
bail_parse_error!("It's {year}. UTF-8 won.");
}
PragmaName::JournalMode => query_pragma(
PragmaName::JournalMode,
schema,
None,
pager,
connection,
program,
),
PragmaName::JournalMode => {
// For JournalMode, when setting a value, we use the opcode
let mode_str = match value {
Expr::Name(name) => name.as_str().to_string(),
_ => parse_string(&value)?,
};
let result_reg = program.alloc_register();
program.emit_insn(Insn::JournalMode {
db: 0,
dest: result_reg,
new_mode: Some(mode_str),
});
program.emit_result_row(result_reg, 1);
program.add_pragma_result_column("journal_mode".into());
Ok((program, TransactionMode::None))
}
PragmaName::LegacyFileFormat => Ok((program, TransactionMode::None)),
PragmaName::WalCheckpoint => query_pragma(
PragmaName::WalCheckpoint,
@@ -349,7 +358,12 @@ fn query_pragma(
Ok((program, TransactionMode::None))
}
PragmaName::JournalMode => {
program.emit_string8("wal".into(), register);
// Use the JournalMode opcode to get the current journal mode
program.emit_insn(Insn::JournalMode {
db: 0,
dest: register,
new_mode: None,
});
program.emit_result_row(register, 1);
program.add_pragma_result_column(pragma.to_string());
Ok((program, TransactionMode::None))

View File

@@ -8322,12 +8322,12 @@ pub fn op_max_pgcnt(
pager: &Rc<Pager>,
mv_store: Option<&Arc<MvStore>>,
) -> Result<InsnFunctionStepResult> {
let Insn::MaxPgcnt { db, dest, new_max } = insn else {
unreachable!("unexpected Insn {:?}", insn)
};
load_insn!(MaxPgcnt { db, dest, new_max }, insn);
if *db > 0 {
todo!("temp/attached databases not implemented yet");
return Err(LimboError::InternalError(
"temp/attached databases not implemented yet".to_string(),
));
}
let result_value = if *new_max == 0 {
@@ -8346,6 +8346,46 @@ pub fn op_max_pgcnt(
Ok(InsnFunctionStepResult::Step)
}
pub fn op_journal_mode(
program: &Program,
state: &mut ProgramState,
insn: &Insn,
pager: &Rc<Pager>,
mv_store: Option<&Arc<MvStore>>,
) -> Result<InsnFunctionStepResult> {
let Insn::JournalMode { db, dest, new_mode } = insn else {
unreachable!("unexpected Insn {:?}", insn)
};
if *db > 0 {
todo!("temp/attached databases not implemented yet");
}
// Currently, Turso only supports WAL mode
// If a new mode is specified, we validate it but always return "wal"
if let Some(mode) = new_mode {
let mode_lower = mode.to_lowercase();
// Valid journal modes in SQLite are: delete, truncate, persist, memory, wal, off
// We accept any valid mode but always use WAL
match mode_lower.as_str() {
"delete" | "truncate" | "persist" | "memory" | "wal" | "off" => {
// Mode is valid, but we stay in WAL mode
}
_ => {
// Invalid journal mode
return Err(LimboError::ParseError(format!(
"Unknown journal mode: {mode}"
)));
}
}
}
// Always return "wal" as the current journal mode
state.registers[*dest] = Register::Value(Value::build_text("wal"));
state.pc += 1;
Ok(InsnFunctionStepResult::Step)
}
#[cfg(test)]
mod tests {
use super::*;

View File

@@ -1654,6 +1654,16 @@ pub fn insn_to_str(
0,
format!("r[{dest}]=max_page_count(db[{db}],{new_max})"),
),
Insn::JournalMode { db, dest, new_mode } => (
"JournalMode",
*db as i32,
*dest as i32,
0,
Value::build_text(new_mode.as_ref().unwrap_or(&String::new())),
0,
format!("r[{dest}]=journal_mode(db[{db}]{})",
new_mode.as_ref().map_or(String::new(), |m| format!(",'{m}'"))),
),
Insn::CollSeq { reg, collation } => (
"CollSeq",
reg.unwrap_or(0) as i32,

View File

@@ -1043,6 +1043,14 @@ pub enum Insn {
dest: usize, // P2: output register
new_max: usize, // P3: new maximum page count (0 = just return current)
},
/// Get or set the journal mode for database P1.
/// If P3 is not null, it contains the new journal mode string.
/// Store the resulting journal mode in register P2.
JournalMode {
db: usize, // P1: database index
dest: usize, // P2: output register for result
new_mode: Option<String>, // P3: new journal mode (if setting)
},
}
impl Insn {
@@ -1175,6 +1183,7 @@ impl Insn {
Insn::RenameTable { .. } => execute::op_rename_table,
Insn::DropColumn { .. } => execute::op_drop_column,
Insn::MaxPgcnt { .. } => execute::op_max_pgcnt,
Insn::JournalMode { .. } => execute::op_journal_mode,
}
}
}