Skip to main content

Crate sqlite_vdbe

Crate sqlite_vdbe 

Source
Expand description

§sqlite-vdbe

Low-level access to SQLite’s VDBE (Virtual Database Engine) bytecode.

This crate allows you to create and execute VDBE programs directly, without going through SQL parsing. This is useful for:

  • Building custom query engines on top of SQLite’s storage
  • Testing VDBE behavior
  • Learning how SQLite works internally
  • Implementing specialized database operations

§Example

use sqlite_vdbe::{Connection, Insn, StepResult};

fn main() -> sqlite_vdbe::Result<()> {
    // Open an in-memory database
    let mut conn = Connection::open_in_memory()?;

    // Create a program that computes 1 + 2
    let mut builder = conn.new_program()?;

    // Allocate registers
    let r1 = builder.alloc_register();  // Will hold 1
    let r2 = builder.alloc_register();  // Will hold 2
    let r3 = builder.alloc_register();  // Will hold result

    // Build the program using the ergonomic instruction API
    builder.add(Insn::Integer { value: 1, dest: r1 });
    builder.add(Insn::Integer { value: 2, dest: r2 });
    builder.add(Insn::Add { lhs: r1, rhs: r2, dest: r3 });
    builder.add(Insn::ResultRow { start: r3, count: 1 });
    builder.add(Insn::Halt);

    // Finish building and execute
    let mut program = builder.finish(1)?;

    match program.step()? {
        StepResult::Row => {
            let value = program.column_int(0);
            println!("Result: {}", value);  // Prints: Result: 3
        }
        StepResult::Done => {
            println!("No results");
        }
    }

    Ok(())
}

§VDBE Overview

The VDBE is a register-based virtual machine. Key concepts:

  • Registers: Memory cells that hold values (integers, floats, strings, blobs, NULL)
  • Instructions: Operations that manipulate registers and database state
  • Cursors: Handles for iterating over database tables/indexes
  • Program: A sequence of instructions that can be executed

§Register Conventions

  • Registers are 1-based (register 0 is reserved)
  • Use builder.alloc_register() to allocate registers
  • Result values are stored in the register specified by the dest field

§Common Instruction Patterns

use sqlite_vdbe::Insn;

// Load a constant integer
let load = Insn::Integer { value: 42, dest: 1 };

// Arithmetic: dest = lhs + rhs
let add = Insn::Add { lhs: 1, rhs: 2, dest: 3 };

// Output a row of results
let output = Insn::ResultRow { start: 1, count: 3 };

// Halt execution
let halt = Insn::Halt;

// Unconditional jump
let jump = Insn::Goto { target: 10 };

// Conditional jump
let branch = Insn::If { src: 1, target: 20, jump_if_null: false };

§Thread Safety

This crate is designed for single-threaded use. Connection, ProgramBuilder, and Program are all !Send and !Sync. SQLite connections should only be used from the thread that created them.

§Safety

This crate uses unsafe internally to call into SQLite’s C API. The safe Rust wrappers ensure proper memory management and prevent common errors.

Re-exports§

pub use connection::Connection;
pub use error::Error;
pub use error::Result;
pub use insn::Insn;
pub use insn::P4;
pub use insn::RawOpcode;
pub use program::Address;
pub use program::InsnRecord;
pub use program::Program;
pub use program::ProgramBuilder;
pub use program::StepResult;
pub use value::Value;
pub use ffi::SQLITE_BLOB;
pub use ffi::SQLITE_DONE;
pub use ffi::SQLITE_ERROR;
pub use ffi::SQLITE_FLOAT;
pub use ffi::SQLITE_INTEGER;
pub use ffi::SQLITE_NULL;
pub use ffi::SQLITE_OK;
pub use ffi::SQLITE_ROW;
pub use ffi::SQLITE_TEXT;

Modules§

connection
Database connection management
error
Error types for the VDBE API
ffi
FFI bindings to SQLite and VDBE internals
insn
VDBE Instructions with semantically named fields
program
VDBE program building and execution
value
Value types for VDBE registers and results