mirror of
https://github.com/aljazceru/turso.git
synced 2026-01-01 07:24:19 +01:00
Initial pass on SQLite C ABI
This adds initial SQLite C ABI compatibility to Limbo to make sure we drive the Rust API in the right way that allows us to implement SQLite semantics.
This commit is contained in:
130
sqlite3/src/lib.rs
Normal file
130
sqlite3/src/lib.rs
Normal file
@@ -0,0 +1,130 @@
|
||||
#![allow(non_camel_case_types)]
|
||||
|
||||
use std::rc::Rc;
|
||||
use std::ffi;
|
||||
|
||||
pub const SQLITE_OK: ffi::c_int = 0;
|
||||
pub const SQLITE_ERROR: ffi::c_int = 1;
|
||||
pub const SQLITE_BUSY: ffi::c_int = 5;
|
||||
pub const SQLITE_NOTFOUND: ffi::c_int = 14;
|
||||
pub const SQLITE_MISUSE: ffi::c_int = 21;
|
||||
pub const SQLITE_ROW: ffi::c_int = 100;
|
||||
pub const SQLITE_DONE: ffi::c_int = 101;
|
||||
|
||||
pub struct sqlite3 {
|
||||
pub(crate) db: limbo_core::Database,
|
||||
pub(crate) conn: limbo_core::Connection,
|
||||
}
|
||||
|
||||
impl sqlite3 {
|
||||
pub fn new(db: limbo_core::Database, conn: limbo_core::Connection) -> Self {
|
||||
Self { db, conn }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct sqlite3_stmt {
|
||||
pub(crate) stmt: limbo_core::Statement,
|
||||
}
|
||||
|
||||
impl sqlite3_stmt {
|
||||
pub fn new(stmt: limbo_core::Statement) -> Self {
|
||||
Self { stmt }
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sqlite3_open(
|
||||
filename: *const ffi::c_char,
|
||||
db_out: *mut *mut sqlite3,
|
||||
) -> ffi::c_int {
|
||||
if filename.is_null() {
|
||||
return SQLITE_MISUSE;
|
||||
}
|
||||
if db_out.is_null() {
|
||||
return SQLITE_MISUSE;
|
||||
}
|
||||
let filename = ffi::CStr::from_ptr(filename);
|
||||
let filename = match filename.to_str() {
|
||||
Ok(s) => s,
|
||||
Err(_) => return SQLITE_MISUSE,
|
||||
};
|
||||
let io = match limbo_core::PlatformIO::new() {
|
||||
Ok(io) => Rc::new(io),
|
||||
Err(_) => return SQLITE_MISUSE,
|
||||
};
|
||||
match limbo_core::Database::open_file(io, filename) {
|
||||
Ok(db) => {
|
||||
let conn = db.connect();
|
||||
*db_out = Box::leak(Box::new(sqlite3::new(db, conn)));
|
||||
SQLITE_OK
|
||||
}
|
||||
Err(e) => {
|
||||
SQLITE_NOTFOUND
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sqlite3_close(db: *mut sqlite3) -> ffi::c_int {
|
||||
if db.is_null() {
|
||||
return SQLITE_OK;
|
||||
}
|
||||
let _ = Box::from_raw(db);
|
||||
SQLITE_OK
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sqlite3_prepare_v2(
|
||||
db: *mut sqlite3,
|
||||
sql: *const ffi::c_char,
|
||||
len: ffi::c_int,
|
||||
out_stmt: *mut *mut sqlite3_stmt,
|
||||
tail: *mut *const ffi::c_char,
|
||||
) -> ffi::c_int {
|
||||
if db.is_null() || sql.is_null() || out_stmt.is_null() {
|
||||
return SQLITE_MISUSE;
|
||||
}
|
||||
let db: &mut sqlite3 = &mut *db;
|
||||
let sql = ffi::CStr::from_ptr(sql);
|
||||
let sql = match sql.to_str() {
|
||||
Ok(s) => s,
|
||||
Err(_) => return SQLITE_MISUSE,
|
||||
};
|
||||
let stmt = match db.conn.prepare(sql) {
|
||||
Ok(stmt) => stmt,
|
||||
Err(_) => return SQLITE_ERROR,
|
||||
};
|
||||
*out_stmt = Box::leak(Box::new(sqlite3_stmt::new(stmt)));
|
||||
SQLITE_OK
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sqlite3_finalize(stmt: *mut sqlite3_stmt) -> ffi::c_int {
|
||||
if stmt.is_null() {
|
||||
return SQLITE_MISUSE;
|
||||
}
|
||||
let _ = Box::from_raw(stmt);
|
||||
SQLITE_OK
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sqlite3_step(db: *mut sqlite3_stmt) -> std::ffi::c_int {
|
||||
let stmt = &mut *db;
|
||||
if let Ok(result) = stmt.stmt.step() {
|
||||
match result {
|
||||
limbo_core::RowResult::IO => SQLITE_BUSY,
|
||||
limbo_core::RowResult::Done => SQLITE_DONE,
|
||||
limbo_core::RowResult::Row(_) => SQLITE_ROW,
|
||||
}
|
||||
} else {
|
||||
SQLITE_ERROR
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sqlite3_column_text(
|
||||
db: *mut sqlite3_stmt,
|
||||
idx: std::ffi::c_int,
|
||||
) -> *const std::ffi::c_uchar {
|
||||
todo!();
|
||||
}
|
||||
Reference in New Issue
Block a user