diff --git a/Cargo.lock b/Cargo.lock index 26cd80646..2c0eb8db1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1616,6 +1616,7 @@ dependencies = [ "limbo_macros", "limbo_percentile", "limbo_regexp", + "limbo_series", "limbo_time", "limbo_uuid", "log", @@ -1707,6 +1708,7 @@ version = "0.0.14" dependencies = [ "limbo_ext", "log", + "mimalloc", ] [[package]] diff --git a/core/Cargo.toml b/core/Cargo.toml index 386bf01c7..687f4ff19 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -27,6 +27,7 @@ percentile = ["limbo_percentile/static"] regexp = ["limbo_regexp/static"] time = ["limbo_time/static"] crypto = ["limbo_crypto/static"] +series = ["limbo_series/static"] [target.'cfg(target_os = "linux")'.dependencies] io-uring = { version = "0.6.1", optional = true } @@ -67,6 +68,7 @@ limbo_regexp = { path = "../extensions/regexp", optional = true, features = ["st limbo_percentile = { path = "../extensions/percentile", optional = true, features = ["static"] } limbo_time = { path = "../extensions/time", optional = true, features = ["static"] } limbo_crypto = { path = "../extensions/crypto", optional = true, features = ["static"] } +limbo_series = { path = "../extensions/series", optional = true, features = ["static"] } miette = "7.4.0" strum = "0.26" parking_lot = "0.12.3" diff --git a/core/ext/mod.rs b/core/ext/mod.rs index 6d034e313..c4b6006e3 100644 --- a/core/ext/mod.rs +++ b/core/ext/mod.rs @@ -131,6 +131,7 @@ impl Database { return ResultCode::Error; }; let vtab_module = self.vtab_modules.get(name).unwrap().clone(); + let vtab = VirtualTable { name: name.to_string(), implementation: vtab_module, @@ -172,6 +173,10 @@ impl Database { if unsafe { !limbo_crypto::register_extension_static(&ext_api).is_ok() } { return Err("Failed to register crypto extension".to_string()); } + #[cfg(feature = "series")] + if unsafe { !limbo_series::register_extension_static(&ext_api).is_ok() } { + return Err("Failed to register series extension".to_string()); + } Ok(()) } } diff --git a/core/util.rs b/core/util.rs index 5251b36cf..654951700 100644 --- a/core/util.rs +++ b/core/util.rs @@ -1,7 +1,6 @@ +use sqlite3_parser::ast::{self, CreateTableBody, Expr, FunctionTail, Literal}; use std::{rc::Rc, sync::Arc}; -use sqlite3_parser::ast::{CreateTableBody, Expr, FunctionTail, Literal}; - use crate::{ schema::{self, Column, Schema, Type}, Result, Statement, StepResult, IO, @@ -308,7 +307,7 @@ pub fn exprs_are_equivalent(expr1: &Expr, expr2: &Expr) -> bool { } } -pub fn columns_from_create_table_body(body: CreateTableBody) -> Result, ()> { +pub fn columns_from_create_table_body(body: ast::CreateTableBody) -> Result, ()> { let CreateTableBody::ColumnsAndConstraints { columns, .. } = body else { return Err(()); }; diff --git a/core/vdbe/mod.rs b/core/vdbe/mod.rs index c25dc572b..5003b72c6 100644 --- a/core/vdbe/mod.rs +++ b/core/vdbe/mod.rs @@ -280,6 +280,7 @@ fn get_cursor_as_virtual_mut<'long, 'short>( .as_virtual_mut(); cursor } + struct Bitfield([u64; N]); impl Bitfield { diff --git a/extensions/core/src/lib.rs b/extensions/core/src/lib.rs index fec363c44..0e550fca1 100644 --- a/extensions/core/src/lib.rs +++ b/extensions/core/src/lib.rs @@ -99,8 +99,8 @@ pub type VtabFnEof = unsafe extern "C" fn(cursor: *mut c_void) -> bool; pub trait VTabModule: 'static { type VCursor: VTabCursor; + const NAME: &'static str; - fn name() -> &'static str; fn connect(api: &ExtensionApi) -> ResultCode; fn open() -> Self::VCursor; fn filter(cursor: &mut Self::VCursor, arg_count: i32, args: &[Value]) -> ResultCode; diff --git a/extensions/series/Cargo.toml b/extensions/series/Cargo.toml index 73a634ac7..cca322294 100644 --- a/extensions/series/Cargo.toml +++ b/extensions/series/Cargo.toml @@ -6,10 +6,16 @@ edition.workspace = true license.workspace = true repository.workspace = true +[features] +static = ["limbo_ext/static"] + [lib] crate-type = ["cdylib", "lib"] [dependencies] -limbo_ext = { path = "../core"} +limbo_ext = { path = "../core", features = ["static"] } log = "0.4.20" + +[target.'cfg(not(target_family = "wasm"))'.dependencies] +mimalloc = { version = "*", default-features = false } diff --git a/extensions/series/src/lib.rs b/extensions/series/src/lib.rs index f438c6fce..63b6c6227 100644 --- a/extensions/series/src/lib.rs +++ b/extensions/series/src/lib.rs @@ -1,21 +1,27 @@ use limbo_ext::{ register_extension, ExtensionApi, ResultCode, VTabCursor, VTabModule, VTabModuleDerive, Value, - ValueType, }; register_extension! { vtabs: { GenerateSeriesVTab } } +macro_rules! try_option { + ($expr:expr, $err:expr) => { + match $expr { + Some(val) => val, + None => return $err, + } + }; +} + /// A virtual table that generates a sequence of integers #[derive(Debug, VTabModuleDerive)] struct GenerateSeriesVTab; impl VTabModule for GenerateSeriesVTab { type VCursor = GenerateSeriesCursor; - fn name() -> &'static str { - "generate_series" - } + const NAME: &'static str = "generate_series"; fn connect(api: &ExtensionApi) -> ResultCode { // Create table schema @@ -25,8 +31,7 @@ impl VTabModule for GenerateSeriesVTab { stop INTEGER HIDDEN, step INTEGER HIDDEN )"; - let name = Self::name(); - api.declare_virtual_table(name, sql) + api.declare_virtual_table(Self::NAME, sql) } fn open() -> Self::VCursor { @@ -43,35 +48,19 @@ impl VTabModule for GenerateSeriesVTab { if arg_count == 0 || arg_count > 3 { return ResultCode::InvalidArgs; } - let start = { - if args[0].value_type() == ValueType::Integer { - args[0].to_integer().unwrap() - } else { - return ResultCode::InvalidArgs; - } - }; - let stop = if args.len() == 1 { - i64::MAX - } else { - if args[1].value_type() == ValueType::Integer { - args[1].to_integer().unwrap() - } else { - return ResultCode::InvalidArgs; - } - }; - let step = if args.len() <= 2 { - 1 - } else { - if args[2].value_type() == ValueType::Integer { - args[2].to_integer().unwrap() - } else { - return ResultCode::InvalidArgs; - } - }; + let start = try_option!(args[0].to_integer(), ResultCode::InvalidArgs); + let stop = try_option!( + args.get(1).map(|v| v.to_integer().unwrap_or(i64::MAX)), + ResultCode::InvalidArgs + ); + let step = try_option!( + args.get(2).map(|v| v.to_integer().unwrap_or(1)), + ResultCode::InvalidArgs + ); cursor.start = start; cursor.current = start; - cursor.stop = stop; cursor.step = step; + cursor.stop = stop; ResultCode::OK } diff --git a/macros/src/lib.rs b/macros/src/lib.rs index 6b0df9679..8dee8dc66 100644 --- a/macros/src/lib.rs +++ b/macros/src/lib.rs @@ -343,6 +343,9 @@ pub fn derive_vtab_module(input: TokenStream) -> TokenStream { unsafe extern "C" fn #connect_fn_name( db: *const ::std::ffi::c_void, ) -> ::limbo_ext::ResultCode { + if db.is_null() { + return ::limbo_ext::ResultCode::Error; + } let api = unsafe { &*(db as *const ExtensionApi) }; <#struct_name as ::limbo_ext::VTabModule>::connect(api) } @@ -360,6 +363,9 @@ pub fn derive_vtab_module(input: TokenStream) -> TokenStream { argc: i32, argv: *const ::limbo_ext::Value, ) -> ::limbo_ext::ResultCode { + if cursor.is_null() { + return ::limbo_ext::ResultCode::Error; + } let cursor = unsafe { &mut *(cursor as *mut <#struct_name as ::limbo_ext::VTabModule>::VCursor) }; let args = std::slice::from_raw_parts(argv, argc as usize); <#struct_name as ::limbo_ext::VTabModule>::filter(cursor, argc, args) @@ -370,6 +376,9 @@ pub fn derive_vtab_module(input: TokenStream) -> TokenStream { cursor: *mut ::std::ffi::c_void, idx: u32, ) -> ::limbo_ext::Value { + if cursor.is_null() { + return ::limbo_ext::Value::error(ResultCode::Error); + } let cursor = unsafe { &mut *(cursor as *mut <#struct_name as ::limbo_ext::VTabModule>::VCursor) }; <#struct_name as ::limbo_ext::VTabModule>::column(cursor, idx) } @@ -378,6 +387,9 @@ pub fn derive_vtab_module(input: TokenStream) -> TokenStream { unsafe extern "C" fn #next_fn_name( cursor: *mut ::std::ffi::c_void, ) -> ::limbo_ext::ResultCode { + if cursor.is_null() { + return ::limbo_ext::ResultCode::Error; + } let cursor = unsafe { &mut *(cursor as *mut <#struct_name as ::limbo_ext::VTabModule>::VCursor) }; <#struct_name as ::limbo_ext::VTabModule>::next(cursor) } @@ -386,6 +398,9 @@ pub fn derive_vtab_module(input: TokenStream) -> TokenStream { unsafe extern "C" fn #eof_fn_name( cursor: *mut ::std::ffi::c_void, ) -> bool { + if cursor.is_null() { + return true; + } let cursor = unsafe { &mut *(cursor as *mut <#struct_name as ::limbo_ext::VTabModule>::VCursor) }; <#struct_name as ::limbo_ext::VTabModule>::eof(cursor) } @@ -399,7 +414,7 @@ pub fn derive_vtab_module(input: TokenStream) -> TokenStream { } let api = &*api; - let name = <#struct_name as ::limbo_ext::VTabModule>::name(); + let name = <#struct_name as ::limbo_ext::VTabModule>::NAME; // name needs to be a c str FFI compatible, NOT CString let name_c = std::ffi::CString::new(name).unwrap(); @@ -493,9 +508,9 @@ pub fn register_extension(input: TokenStream) -> TokenStream { let result = unsafe{ #vtab_ident::#register_fn(api)}; if result == ::limbo_ext::ResultCode::OK { let result = <#vtab_ident as ::limbo_ext::VTabModule>::connect(api); - return result; - } else { - return result; + if !result.is_ok() { + return result; + } } } } @@ -535,5 +550,6 @@ pub fn register_extension(input: TokenStream) -> TokenStream { ::limbo_ext::ResultCode::OK } }; + TokenStream::from(expanded) }