DEV Community

Cover image for How the VM Actually Executes a Program in SQLite
Athreya aka Maneshwar
Athreya aka Maneshwar

Posted on

How the VM Actually Executes a Program in SQLite

Hello, I'm Maneshwar. I'm working on git-lrc: a Git hook for Checking AI generated code.

So far, we’ve looked at bytecode instructions, insert logic, and join logic. But we haven’t yet stepped into the interpreter itself.

Today we answer a very direct question:

How does SQLite’s VM execute a bytecode program?

Where Execution Begins

Every bytecode program starts at instruction 0.

The VM continues executing instructions until one of three things happens:

  1. It encounters an explicit Halt instruction.
  2. The program counter (pc) moves past the last instruction this is treated as an implicit Halt.
  3. An execution error occurs.

When execution stops, SQLite performs cleanup, all open cursors are closed, memory allocated to the VM is released and if an error occurred, any pending transaction is rolled back.

That last point is critical. The VM is not just executing instructions, it is also enforcing atomicity. If something fails mid-execution, the system restores consistency before returning control.

The Interpreter Loop

At the core of SQLite’s execution engine is a function named:

sqlite3VdbeExec
Enter fullscreen mode Exit fullscreen mode

This function takes a pointer to a Vdbe object (the prepared statement). Internally, the interpreter is remarkably simple:

  • A for loop
  • A large switch statement image

Each iteration:

  1. Fetch instruction from aOp[pc]
  2. Decode opcode
  3. Execute corresponding case block
  4. Increment or modify pc

Most instructions simply do:

pc++
Enter fullscreen mode Exit fullscreen mode

But jump instructions overwrite pc with a new value.

Execution continues until either:

  • A Halt is processed
  • Or pc >= nOp (past last instruction)

That condition marks normal termination.

Here is the structural overview:

Figure 7.2: Structure of the VM interpreter

What’s striking is how unremarkable the structure is. No deep recursion. No complex scheduling. Just a deterministic interpreter loop.

The complexity lies not in the loop — but in the semantics of each opcode case.

The Vdbe Object — The Complete VM State

When you call sqlite3_prepare, the pointer you receive (sqlite3_stmt*) is actually a pointer to a Vdbe object.

That object holds everything needed to execute the program.

Some important components:

  • aOp → array of bytecode instructions
  • pc → program counter
  • aMem → register array
  • nMem → number of registers
  • Cursor structures
  • Runtime bookkeeping state

All memory used during execution lives inside aMem.

The VM does not dynamically allocate registers per instruction, the compiler decides how many are needed ahead of time, and execution reuses them.

The internal structure looks roughly like this:

figure 7.3: Th e Vdbe structure.

When you think of the VM, think of the Vdbe object as the entire virtual computer: memory, program, registers, cursors, state — all encapsulated.

Cursors in the VM

Earlier, we discussed B-tree cursors in the tree module. The VM has its own abstraction on top of that: VdbeCursor.

A VdbeCursor:

  • Points to a specific table or index B-tree
  • Can seek to a specific key
  • Can iterate forward or backward
  • Can read the current record
  • Can insert or delete entries

Each cursor operates independently even if multiple cursors point to the same table or index.

This independence is important during joins, subqueries, and correlated lookups.

Every open cursor inside the VM is represented by a VdbeCursor structure.

Here is its internal layout:

Figur e 7.4: Th e VdbeCursor structu re.

Instructions such as:

  • OP_OpenRead
  • OP_OpenWrite
  • OP_Column
  • OP_Next

all operate on these cursor structures.

When the VM halts, all cursors are automatically closed. There is no manual cleanup required at the SQL level the interpreter ensures consistent teardown.

What Happens During Execution

Let’s tie everything together with a conceptual timeline:

  1. sqlite3_prepare builds a Vdbe object.
  2. sqlite3_step calls sqlite3VdbeExec.
  3. The interpreter loop starts at pc = 0.
  4. Instructions are fetched and executed.
  5. If ResultRow executes, sqlite3_step returns SQLITE_ROW.
  6. Execution resumes on the next call to sqlite3_step.
  7. Eventually, Halt executes or pc >= nOp.
  8. VM cleans up and returns final status.

It’s a cooperative execution model. The VM yields results incrementally but retains full execution state between calls.

git-lrc

AI agents write code fast. They also silently remove logic, change behavior, and introduce bugs -- without telling you. You often find out in production.
git-lrc fixes this. It hooks into git commit and reviews every diff before it lands. 60-second setup. Completely free.

Any feedback or contributors are welcome! It’s online, source-available, and ready for anyone to use.
⭐ Star it on GitHub:

GitHub logo HexmosTech / git-lrc

Free, Unlimited AI Code Reviews That Run on Commit

git-lrc logo

git-lrc

Free, Unlimited AI Code Reviews That Run on Commit


git-lrc - Free, unlimited AI code reviews that run on commit | Product Hunt

AI agents write code fast. They also silently remove logic, change behavior, and introduce bugs -- without telling you. You often find out in production.

git-lrc fixes this. It hooks into git commit and reviews every diff before it lands. 60-second setup. Completely free.

See It In Action

See git-lrc catch serious security issues such as leaked credentials, expensive cloud operations, and sensitive material in log statements

git-lrc-intro-60s.mp4

Why

  • 🤖 AI agents silently break things. Code removed. Logic changed. Edge cases gone. You won't notice until production.
  • 🔍 Catch it before it ships. AI-powered inline comments show you exactly what changed and what looks wrong.
  • 🔁 Build a habit, ship better code. Regular review → fewer bugs → more robust code → better results in your team.
  • 🔗 Why git? Git is universal. Every editor, every IDE, every AI…




Top comments (0)