In the previous posts, we've explored the SQLite file format and built a simple SQL parser. It's time to put these pieces together and implement a query evaluator! In this post, we'll lay the groundwork for evaluating SQL queries and build a query evaluator that can handle basic SELECT statements. While our initial implementation won't support filtering, sorting, grouping, or joins yet, it will give us the foundation to add these features in future posts.
As usual, the complete source code for this post is available on GitHub.
Setting up our test database
Before we can evaluate queries, we need a database to query. We'll start by creating a simple database with a single table, table1 , with two columns, id and value :
sqlite3 queries_test.db sqlite> create table table1(id integer , value text); sqlite> insert into table1(id, value) values ...> (1, '11' ), ...> (2, '12' ), ...> (3, '13' ); sqlite> . exit
⚠️ You might be tempted to use an existing SQLite database to test your queries, but keep in mind that our implementation does not support overflow pages yet, so it might not be able to read the data from your database file.
Making the pager shareable
This section is specific to the Rust implementation. If you're following along with another language, you can safely skip it!
Currently, our pager can only be used through an exclusive mutable reference. This was fine for our initial use cases, but as we start building more complex features, maintaining this restriction will constrain our design. We'll make the pager shareable by wrapping its inner mutable fields in an Arc
// src/pager.rs - #[derive(Debug, Clone)] + #[derive(Debug)] pub struct Pager
... continue reading