1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
pub use crate::wire_format::{
BindKey, BindList, BindPair, BindValue, SqliteError, SqliteRow, SqliteValue,
};
pub mod sqlite_guest_bindings {
#[link(wasm_import_module = "lunatic::sqlite")]
extern "C" {
/// opens a new connection and stores a reference to the resource
///
/// returns the connection_id which can be used for later calls and
/// can be safely transported between guest and host
pub fn open(path: *const u8, path_len: usize, connection_id: *mut u32) -> u64;
///
/// Creates a new prepared statement and returns the id of the prepared statement
/// to the guest so that values can be bound to the statement at a later point
pub fn query_prepare(connection_id: u64, query_str: *const u8, query_str_len: u32) -> u64;
/// Executes the passed query and returns the SQLite response code
pub fn execute(connection_id: u64, exec_str: *const u8, exec_str_len: u32) -> u32;
/// Binds one or more values to the statement identified by `statement_id`.
/// The function expects to receive a `BindList` encoded via `bincode` as demonstrated by this example:
///
/// ```
///
/// let query = "INSERT INTO cars (manufacturer, model) VALUES(:manufacturer, :model_name);"
/// let statement_id = unsafe {sqlite_guest_bindings::query_prepare(connection_id, query.as_ptr(), query.len() as u32)};
///
/// let key = BindKey::String("model_name".into());
/// let value = BindValue::Int(996);
/// let bind_list = BindList(vec![
/// BindPair(key, value)
/// ]);
/// let encoded = bincode::serialize(&bind_list).unwrap();
/// let result = unsafe {
/// sqlite_guest_bindings::bind_value(
/// statement_id,
/// encoded.as_ptr() as u32,
/// encoded.len() as u32,
/// )
/// };
/// ```
///
/// Anything other than a `BindList` will be rejected and a Trap will be returned
pub fn bind_value(statement_id: u64, bind_data_ptr: u32, bind_data_len: u32);
/// returns count of changes/rows that the last call to SQLite triggered
pub fn sqlite3_changes(connection_id: u64) -> u32;
/// resets the bound statement so that it can be used/bound again
pub fn statement_reset(statement_id: u64);
/// furthers the internal SQLite cursor and returns either
/// SQLITE_DONE or SQLITE_ROW to indicate whether there's more
/// data to be pulled from the previous query
pub fn sqlite3_step(connection_id: u64) -> u32;
/// Drops the connection identified by `connection_id` in the host and
/// closes the connection to SQLite
pub fn sqlite3_finalize(connection_id: u64);
/// returns the count of columns for the executed statement
pub fn column_count(statement_id: u64) -> u32;
/// NOTE: the following functions will require a registered `alloc` function
/// because it relies on calling into the guest and allocating a chunk of memory
/// in the guest so that results of queries can be written directly into the
/// guest memory and not temporarily stored in the host as is the case with
/// `query_prepare_and_consume` and `query_result_get`.
///
/// The functions have a return value of `u64` which contains the pointer
/// to the allocated guest memory (most likely a `Vec<u8>`) to which the
/// results of the call have been written.
/// The value of `u64` is split into two `u32` parts respectively:
/// - the length of data written
/// - the pointer to the data
///
/// and can be retrieved via a function such as this:
///
/// ```
/// fn unroll_vec(ptr: u64) -> Vec<u8> {
/// unsafe {
/// // the leftmost half contains the length
/// let length = (ptr >> 32) as usize;
/// // the rightmost half contains the pointer
/// let ptr = 0x00000000FFFFFFFF & ptr;
/// Vec::from_raw_parts(ptr as *mut u8, length, length)
/// }
/// }
/// ```
///
///
/// looks up the value of the last error, encodes an `SqliteError` via bincode
/// and writes it into a guest allocated Vec<u8>
/// Returns a composite length + pointer to the data (see explanation above)
pub fn last_error(connection_id: u64, opaque_ptr: *mut u32) -> u32;
/// reads the column under index `col_idx` encodes a `SqliteValue` via bincode
/// and writes it into a guest allocated Vec<u8>
/// Returns a composite length + pointer to the data (see explanation above)
pub fn read_column(statement_id: u64, col_idx: u32, opaque_ptr: *mut u32) -> u32;
/// reads the next row, encodes a `SqliteRow` via bincode
/// and writes it into a guest allocated Vec<u8>
pub fn read_row(statement_id: u64, opaque_ptr: *mut u32) -> u32;
/// looks up the name of the column under index `col_idx`, encodes a `String` via bincode
/// and writes it into a guest allocated Vec<u8>
pub fn column_name(statement_id: u64, col_idx: u32, opaque_ptr: *mut u32) -> u32;
/// looks up the value of the last error, encodes a `Vec<String>` via bincode
/// and writes it into a guest allocated Vec<u8>
pub fn column_names(statement_id: u64, opaque_ptr: *mut u32) -> u32;
}
}