Skip to main content

Crate rudb

Crate rudb 

Source
Expand description

The embedding API: connections, prepared statements, configuration and results.

Rank 13 in the layer rule. See xtask/layers.toml and spec/18-package-layout.md.

This is the crate somebody who wants a database depends on. Everything below it is an implementation detail that happens to be published, and everything above it is a different way of reaching this same API: rudb-c-api is this over the C ABI and rudb-cli is this behind a prompt.

use rudb::{Database, Field, LogicalType, Value};

let db = Database::new();
db.create_table("t", vec![Field::new("x", LogicalType::Integer)])?;
db.append("t", &[vec![Value::Integer(1)], vec![Value::Integer(7)]])?;

let result = db.query("SELECT x FROM t WHERE x > 5")?;
assert_eq!(result.len(), 1);
assert_eq!(result.value_at(0, 0), Value::Integer(7));

§What a query is today

Parse, bind, optimize, execute. The optimizer is one pass, which is column pruning, so a scan reads the columns something above it asks for and the plan is otherwise the shape the binder built it. The rest of spec/09-optimizer.md’s sequence is M1 work. There are no transactions, and rudb-txn is in the dependency list for the same reason: the seam is where it will be and nothing goes through it yet.

Database::create_table and Database::append are how rows get in without SQL, and they are a real part of the API rather than a test helper, since an embedded analytical database gets most of its data from a program rather than from a string of SQL. The DDL statements bind to the same catalog calls these make.

§Prepared statements

Database::prepare and Connection::prepare parse a statement once and hand back a Prepared that runs with values for its parameters, written ?, ?1, $1 or $name. The statement is bound again for each set of values rather than planned once and filled in, because an analytical plan depends on what the values are: a scan that keeps one row in a million and a scan that keeps half the table want different plans, and the binder is cheap next to either.

§Threading

A Database is a handle. Cloning one, or calling Database::connect, gives another handle on the same database, and every method takes &self, so the program embedding this is the one that decides how many threads there are. The catalog is behind a reader writer lock: any number of queries read at once and a statement that writes has the database to itself while it runs.

That lock is the whole of the concurrency story until rudb-txn has one. A statement that writes is serialized against every reader rather than isolated from them, which is correct and is coarse, and the thing that makes it finer is a transaction rather than a different lock.

Structs§

Chunk
A batch of columns of equal length.
Connection
A connection to a database.
Database
An in process database.
Error
An error, carrying a code, a message and optionally where in the query it happened.
Field
A named field of a STRUCT or a UNION, and a named column of a table.
Prepared
A prepared statement.
QueryResult
The rows a query produced, with the names and types of its columns.
Statement
One statement out of a script, and where it started.

Enums§

LogicalType
What SQL thinks a value is.
Value
A single SQL value.

Functions§

is_complete
Whether a script ends on a statement boundary.
statements
Every statement in a script, in order.

Type Aliases§

Result
The result type used everywhere in the workspace.