Merge 'Syntactic improvements' from Jorge López Tello

This is a purely syntactic PR. It doesn't change behavior, just rewrites
some loops and removes unneeded parts, like lifetime annotations and
references. Mainly because the Clippy and IDE warnings get annoying.
Don't worry about the number of commits, I just separated based on type
of change.

Closes #732
This commit is contained in:
Pekka Enberg
2025-01-19 12:17:28 +02:00
38 changed files with 387 additions and 416 deletions

View File

@@ -101,17 +101,16 @@ impl Cursor {
// For DDL and DML statements, // For DDL and DML statements,
// we need to execute the statement immediately // we need to execute the statement immediately
if stmt_is_ddl || stmt_is_dml { if stmt_is_ddl || stmt_is_dml {
loop { while stmt
match stmt.borrow_mut().step().map_err(|e| { .borrow_mut()
PyErr::new::<OperationalError, _>(format!("Step error: {:?}", e)) .step()
})? { .map_err(|e| PyErr::new::<OperationalError, _>(format!("Step error: {:?}", e)))?
limbo_core::StepResult::IO => { .eq(&limbo_core::StepResult::IO)
self.conn.io.run_once().map_err(|e| { {
PyErr::new::<OperationalError, _>(format!("IO error: {:?}", e)) self.conn
})?; .io
} .run_once()
_ => break, .map_err(|e| PyErr::new::<OperationalError, _>(format!("IO error: {:?}", e)))?;
}
} }
} }
@@ -268,20 +267,26 @@ impl Connection {
#[allow(clippy::arc_with_non_send_sync)] #[allow(clippy::arc_with_non_send_sync)]
#[pyfunction] #[pyfunction]
pub fn connect(path: &str) -> Result<Connection> { pub fn connect(path: &str) -> Result<Connection> {
#[inline(always)]
fn open_or(
io: Arc<dyn limbo_core::IO>,
path: &str,
) -> std::result::Result<Arc<limbo_core::Database>, PyErr> {
limbo_core::Database::open_file(io, path).map_err(|e| {
PyErr::new::<DatabaseError, _>(format!("Failed to open database: {:?}", e))
})
}
match path { match path {
":memory:" => { ":memory:" => {
let io: Arc<dyn limbo_core::IO> = Arc::new(limbo_core::MemoryIO::new()?); let io: Arc<dyn limbo_core::IO> = Arc::new(limbo_core::MemoryIO::new()?);
let db = limbo_core::Database::open_file(io.clone(), path).map_err(|e| { let db = open_or(io.clone(), path)?;
PyErr::new::<DatabaseError, _>(format!("Failed to open database: {:?}", e))
})?;
let conn: Rc<limbo_core::Connection> = db.connect(); let conn: Rc<limbo_core::Connection> = db.connect();
Ok(Connection { conn, io }) Ok(Connection { conn, io })
} }
path => { path => {
let io: Arc<dyn limbo_core::IO> = Arc::new(limbo_core::PlatformIO::new()?); let io: Arc<dyn limbo_core::IO> = Arc::new(limbo_core::PlatformIO::new()?);
let db = limbo_core::Database::open_file(io.clone(), path).map_err(|e| { let db = open_or(io.clone(), path)?;
PyErr::new::<DatabaseError, _>(format!("Failed to open database: {:?}", e))
})?;
let conn: Rc<limbo_core::Connection> = db.connect(); let conn: Rc<limbo_core::Connection> = db.connect();
Ok(Connection { conn, io }) Ok(Connection { conn, io })
} }

View File

@@ -11,7 +11,7 @@ use std::sync::Arc;
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error)]
pub enum Error { pub enum Error {
#[error("SQL conversion failure: `{0}`")] #[error("SQL conversion failure: `{0}`")]
ToSqlConversionFailure(crate::BoxError), ToSqlConversionFailure(BoxError),
} }
impl From<limbo_core::LimboError> for Error { impl From<limbo_core::LimboError> for Error {

View File

@@ -153,7 +153,7 @@ impl From<u32> for Value {
} }
impl TryFrom<u64> for Value { impl TryFrom<u64> for Value {
type Error = crate::Error; type Error = Error;
fn try_from(value: u64) -> Result<Value> { fn try_from(value: u64) -> Result<Value> {
if value > i64::MAX as u64 { if value > i64::MAX as u64 {

View File

@@ -135,7 +135,7 @@ pub enum Command {
impl Command { impl Command {
fn min_args(&self) -> usize { fn min_args(&self) -> usize {
(match self { 1 + match self {
Self::Quit Self::Quit
| Self::Schema | Self::Schema
| Self::Help | Self::Help
@@ -150,7 +150,7 @@ impl Command {
| Self::NullValue | Self::NullValue
| Self::LoadExtension => 1, | Self::LoadExtension => 1,
Self::Import => 2, Self::Import => 2,
} + 1) // argv0 } // argv0
} }
fn usage(&self) -> &str { fn usage(&self) -> &str {
@@ -337,7 +337,7 @@ impl Limbo {
.map_err(|e| e.to_string()) .map_err(|e| e.to_string())
} }
fn display_in_memory(&mut self) -> std::io::Result<()> { fn display_in_memory(&mut self) -> io::Result<()> {
if self.opts.db_file == ":memory:" { if self.opts.db_file == ":memory:" {
self.writeln("Connected to a transient in-memory database.")?; self.writeln("Connected to a transient in-memory database.")?;
self.writeln("Use \".open FILENAME\" to reopen on a persistent database")?; self.writeln("Use \".open FILENAME\" to reopen on a persistent database")?;
@@ -345,7 +345,7 @@ impl Limbo {
Ok(()) Ok(())
} }
fn show_info(&mut self) -> std::io::Result<()> { fn show_info(&mut self) -> io::Result<()> {
let opts = format!("{}", self.opts); let opts = format!("{}", self.opts);
self.writeln(opts) self.writeln(opts)
} }

View File

@@ -214,7 +214,7 @@ pub enum ScalarFunc {
} }
impl Display for ScalarFunc { impl Display for ScalarFunc {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let str = match self { let str = match self {
Self::Cast => "cast".to_string(), Self::Cast => "cast".to_string(),
Self::Changes => "changes".to_string(), Self::Changes => "changes".to_string(),
@@ -343,7 +343,7 @@ impl MathFunc {
} }
impl Display for MathFunc { impl Display for MathFunc {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let str = match self { let str = match self {
Self::Acos => "acos".to_string(), Self::Acos => "acos".to_string(),
Self::Acosh => "acosh".to_string(), Self::Acosh => "acosh".to_string(),

View File

@@ -4,7 +4,6 @@ use pest_derive::Parser;
use serde::de; use serde::de;
use serde::forward_to_deserialize_any; use serde::forward_to_deserialize_any;
use std::collections::VecDeque; use std::collections::VecDeque;
use std::f64;
use crate::json::error::{self, Error, Result}; use crate::json::error::{self, Error, Result};

View File

@@ -36,7 +36,7 @@ pub fn get_json(json_value: &OwnedValue) -> crate::Result<OwnedValue> {
} }
let json_val = get_json_value(json_value)?; let json_val = get_json_value(json_value)?;
let json = crate::json::to_string(&json_val).unwrap(); let json = to_string(&json_val).unwrap();
Ok(OwnedValue::Text(LimboText::json(Rc::new(json)))) Ok(OwnedValue::Text(LimboText::json(Rc::new(json))))
} }
@@ -52,7 +52,7 @@ pub fn get_json(json_value: &OwnedValue) -> crate::Result<OwnedValue> {
OwnedValue::Null => Ok(OwnedValue::Null), OwnedValue::Null => Ok(OwnedValue::Null),
_ => { _ => {
let json_val = get_json_value(json_value)?; let json_val = get_json_value(json_value)?;
let json = crate::json::to_string(&json_val).unwrap(); let json = to_string(&json_val).unwrap();
Ok(OwnedValue::Text(LimboText::json(Rc::new(json)))) Ok(OwnedValue::Text(LimboText::json(Rc::new(json))))
} }
@@ -61,7 +61,7 @@ pub fn get_json(json_value: &OwnedValue) -> crate::Result<OwnedValue> {
fn get_json_value(json_value: &OwnedValue) -> crate::Result<Val> { fn get_json_value(json_value: &OwnedValue) -> crate::Result<Val> {
match json_value { match json_value {
OwnedValue::Text(ref t) => match crate::json::from_str::<Val>(&t.value) { OwnedValue::Text(ref t) => match from_str::<Val>(&t.value) {
Ok(json) => Ok(json), Ok(json) => Ok(json),
Err(_) => { Err(_) => {
crate::bail_parse_error!("malformed JSON") crate::bail_parse_error!("malformed JSON")
@@ -92,17 +92,17 @@ pub fn json_array(values: &[OwnedValue]) -> crate::Result<OwnedValue> {
if t.subtype == TextSubtype::Json { if t.subtype == TextSubtype::Json {
s.push_str(&t.value); s.push_str(&t.value);
} else { } else {
match crate::json::to_string(&*t.value) { match to_string(&*t.value) {
Ok(json) => s.push_str(&json), Ok(json) => s.push_str(&json),
Err(_) => crate::bail_parse_error!("malformed JSON"), Err(_) => crate::bail_parse_error!("malformed JSON"),
} }
} }
} }
OwnedValue::Integer(i) => match crate::json::to_string(&i) { OwnedValue::Integer(i) => match to_string(&i) {
Ok(json) => s.push_str(&json), Ok(json) => s.push_str(&json),
Err(_) => crate::bail_parse_error!("malformed JSON"), Err(_) => crate::bail_parse_error!("malformed JSON"),
}, },
OwnedValue::Float(f) => match crate::json::to_string(&f) { OwnedValue::Float(f) => match to_string(&f) {
Ok(json) => s.push_str(&json), Ok(json) => s.push_str(&json),
Err(_) => crate::bail_parse_error!("malformed JSON"), Err(_) => crate::bail_parse_error!("malformed JSON"),
}, },
@@ -152,7 +152,7 @@ pub fn json_arrow_extract(value: &OwnedValue, path: &OwnedValue) -> crate::Resul
let extracted = json_extract_single(&json, path, false)?; let extracted = json_extract_single(&json, path, false)?;
if let Some(val) = extracted { if let Some(val) = extracted {
let json = crate::json::to_string(val).unwrap(); let json = to_string(val).unwrap();
Ok(OwnedValue::Text(LimboText::json(Rc::new(json)))) Ok(OwnedValue::Text(LimboText::json(Rc::new(json))))
} else { } else {
@@ -190,7 +190,7 @@ pub fn json_extract(value: &OwnedValue, paths: &[OwnedValue]) -> crate::Result<O
let json = get_json_value(value)?; let json = get_json_value(value)?;
let extracted = json_extract_single(&json, &paths[0], true)?.unwrap_or_else(|| &Val::Null); let extracted = json_extract_single(&json, &paths[0], true)?.unwrap_or_else(|| &Val::Null);
return convert_json_to_db_type(&extracted, false); return convert_json_to_db_type(extracted, false);
} }
let json = get_json_value(value)?; let json = get_json_value(value)?;
@@ -209,7 +209,7 @@ pub fn json_extract(value: &OwnedValue, paths: &[OwnedValue]) -> crate::Result<O
return Ok(OwnedValue::Null); return Ok(OwnedValue::Null);
} }
result.push_str(&crate::json::to_string(&extracted).unwrap()); result.push_str(&to_string(&extracted).unwrap());
result.push(','); result.push(',');
} }
} }
@@ -228,6 +228,7 @@ pub fn json_extract(value: &OwnedValue, paths: &[OwnedValue]) -> crate::Result<O
/// > an INTEGER one for a JSON true value, /// > an INTEGER one for a JSON true value,
/// > the dequoted text for a JSON string value, /// > the dequoted text for a JSON string value,
/// > and a text representation for JSON object and array values. /// > and a text representation for JSON object and array values.
///
/// https://sqlite.org/json1.html#the_json_extract_function /// https://sqlite.org/json1.html#the_json_extract_function
/// ///
/// *all_as_db* - if true, objects and arrays will be returned as pure TEXT without the JSON subtype /// *all_as_db* - if true, objects and arrays will be returned as pure TEXT without the JSON subtype
@@ -245,7 +246,7 @@ fn convert_json_to_db_type(extracted: &Val, all_as_db: bool) -> crate::Result<Ow
} }
Val::String(s) => Ok(OwnedValue::Text(LimboText::new(Rc::new(s.clone())))), Val::String(s) => Ok(OwnedValue::Text(LimboText::new(Rc::new(s.clone())))),
_ => { _ => {
let json = crate::json::to_string(&extracted).unwrap(); let json = to_string(&extracted).unwrap();
if all_as_db { if all_as_db {
Ok(OwnedValue::Text(LimboText::new(Rc::new(json)))) Ok(OwnedValue::Text(LimboText::new(Rc::new(json))))
} else { } else {
@@ -369,12 +370,12 @@ fn json_extract_single<'a>(
} }
} }
Ok(Some(&current_element)) Ok(Some(current_element))
} }
pub fn json_error_position(json: &OwnedValue) -> crate::Result<OwnedValue> { pub fn json_error_position(json: &OwnedValue) -> crate::Result<OwnedValue> {
match json { match json {
OwnedValue::Text(t) => match crate::json::from_str::<Val>(&t.value) { OwnedValue::Text(t) => match from_str::<Val>(&t.value) {
Ok(_) => Ok(OwnedValue::Integer(0)), Ok(_) => Ok(OwnedValue::Integer(0)),
Err(JsonError::Message { location, .. }) => { Err(JsonError::Message { location, .. }) => {
if let Some(loc) = location { if let Some(loc) = location {

View File

@@ -45,7 +45,7 @@ use util::parse_schema_rows;
pub use error::LimboError; pub use error::LimboError;
use translate::select::prepare_select_plan; use translate::select::prepare_select_plan;
pub type Result<T, E = error::LimboError> = std::result::Result<T, E>; pub type Result<T, E = LimboError> = std::result::Result<T, E>;
use crate::translate::optimizer::optimize_plan; use crate::translate::optimizer::optimize_plan;
pub use io::OpenFlags; pub use io::OpenFlags;
@@ -86,7 +86,7 @@ impl Database {
pub fn open_file(io: Arc<dyn IO>, path: &str) -> Result<Arc<Database>> { pub fn open_file(io: Arc<dyn IO>, path: &str) -> Result<Arc<Database>> {
use storage::wal::WalFileShared; use storage::wal::WalFileShared;
let file = io.open_file(path, io::OpenFlags::Create, true)?; let file = io.open_file(path, OpenFlags::Create, true)?;
maybe_init_database_file(&file, &io)?; maybe_init_database_file(&file, &io)?;
let page_io = Rc::new(FileStorage::new(file)); let page_io = Rc::new(FileStorage::new(file));
let wal_path = format!("{}-wal", path); let wal_path = format!("{}-wal", path);
@@ -194,7 +194,7 @@ impl Database {
} }
pub fn maybe_init_database_file(file: &Rc<dyn File>, io: &Arc<dyn IO>) -> Result<()> { pub fn maybe_init_database_file(file: &Rc<dyn File>, io: &Arc<dyn IO>) -> Result<()> {
if file.size().unwrap() == 0 { if file.size()? == 0 {
// init db // init db
let db_header = DatabaseHeader::default(); let db_header = DatabaseHeader::default();
let page1 = allocate_page( let page1 = allocate_page(
@@ -223,8 +223,7 @@ pub fn maybe_init_database_file(file: &Rc<dyn File>, io: &Arc<dyn IO>) -> Result
let completion = Completion::Write(WriteCompletion::new(Box::new(move |_| { let completion = Completion::Write(WriteCompletion::new(Box::new(move |_| {
*flag_complete.borrow_mut() = true; *flag_complete.borrow_mut() = true;
}))); })));
file.pwrite(0, contents.buffer.clone(), Rc::new(completion)) file.pwrite(0, contents.buffer.clone(), Rc::new(completion))?;
.unwrap();
} }
let mut limit = 100; let mut limit = 100;
loop { loop {
@@ -475,6 +474,7 @@ impl Statement {
} }
} }
#[derive(PartialEq)]
pub enum StepResult<'a> { pub enum StepResult<'a> {
Row(Row<'a>), Row(Row<'a>),
IO, IO,
@@ -483,12 +483,13 @@ pub enum StepResult<'a> {
Busy, Busy,
} }
#[derive(PartialEq)]
pub struct Row<'a> { pub struct Row<'a> {
pub values: Vec<Value<'a>>, pub values: Vec<Value<'a>>,
} }
impl<'a> Row<'a> { impl<'a> Row<'a> {
pub fn get<T: crate::types::FromValue<'a> + 'a>(&self, idx: usize) -> Result<T> { pub fn get<T: types::FromValue<'a> + 'a>(&self, idx: usize) -> Result<T> {
let value = &self.values[idx]; let value = &self.values[idx];
T::from_value(value) T::from_value(value)
} }
@@ -509,9 +510,9 @@ impl Rows {
} }
pub(crate) struct SymbolTable { pub(crate) struct SymbolTable {
pub functions: HashMap<String, Rc<crate::function::ExternalFunc>>, pub functions: HashMap<String, Rc<function::ExternalFunc>>,
#[cfg(not(target_family = "wasm"))] #[cfg(not(target_family = "wasm"))]
extensions: Vec<(libloading::Library, *const ExtensionApi)>, extensions: Vec<(Library, *const ExtensionApi)>,
} }
impl std::fmt::Debug for SymbolTable { impl std::fmt::Debug for SymbolTable {
@@ -563,7 +564,7 @@ impl SymbolTable {
&self, &self,
name: &str, name: &str,
_arg_count: usize, _arg_count: usize,
) -> Option<Rc<crate::function::ExternalFunc>> { ) -> Option<Rc<function::ExternalFunc>> {
self.functions.get(name).cloned() self.functions.get(name).cloned()
} }
} }
@@ -589,7 +590,7 @@ impl Iterator for QueryRunner<'_> {
match self.parser.next() { match self.parser.next() {
Ok(Some(cmd)) => Some(self.conn.run_cmd(cmd)), Ok(Some(cmd)) => Some(self.conn.run_cmd(cmd)),
Ok(None) => None, Ok(None) => None,
Err(err) => Some(Result::Err(LimboError::from(err))), Err(err) => Some(Err(LimboError::from(err))),
} }
} }
} }

View File

@@ -29,6 +29,12 @@ pub struct Parameters {
pub list: Vec<Parameter>, pub list: Vec<Parameter>,
} }
impl Default for Parameters {
fn default() -> Self {
Self::new()
}
}
impl Parameters { impl Parameters {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
@@ -76,7 +82,7 @@ impl Parameters {
log::trace!("anonymous parameter at {index}"); log::trace!("anonymous parameter at {index}");
index index
} }
name if name.starts_with(&['$', ':', '@', '#']) => { name if name.starts_with(['$', ':', '@', '#']) => {
match self match self
.list .list
.iter() .iter()
@@ -97,7 +103,7 @@ impl Parameters {
} }
} }
index => { index => {
// SAFETY: Garanteed from parser that the index is bigger that 0. // SAFETY: Guaranteed from parser that the index is bigger than 0.
let index: NonZero<usize> = index.parse().unwrap(); let index: NonZero<usize> = index.parse().unwrap();
if index > self.index { if index > self.index {
self.index = index.checked_add(1).unwrap(); self.index = index.checked_add(1).unwrap();

View File

@@ -167,7 +167,7 @@ impl BTreeCursor {
/// Check if the table is empty. /// Check if the table is empty.
/// This is done by checking if the root page has no cells. /// This is done by checking if the root page has no cells.
fn is_empty_table(&mut self) -> Result<CursorResult<bool>> { fn is_empty_table(&self) -> Result<CursorResult<bool>> {
let page = self.pager.read_page(self.root_page)?; let page = self.pager.read_page(self.root_page)?;
return_if_locked!(page); return_if_locked!(page);
@@ -473,7 +473,7 @@ impl BTreeCursor {
&record.values[..record.values.len() - 1] >= &index_key.values &record.values[..record.values.len() - 1] >= &index_key.values
} }
SeekOp::EQ => { SeekOp::EQ => {
&record.values[..record.values.len() - 1] == &index_key.values record.values[..record.values.len() - 1] == index_key.values
} }
}; };
self.stack.advance(); self.stack.advance();
@@ -542,7 +542,7 @@ impl BTreeCursor {
match contents.rightmost_pointer() { match contents.rightmost_pointer() {
Some(right_most_pointer) => { Some(right_most_pointer) => {
self.stack.set_cell_index(contents.cell_count() as i32 + 1); self.stack.set_cell_index(contents.cell_count() as i32 + 1);
let mem_page = self.pager.read_page(right_most_pointer as usize).unwrap(); let mem_page = self.pager.read_page(right_most_pointer as usize)?;
self.stack.push(mem_page); self.stack.push(mem_page);
continue; continue;
} }
@@ -643,7 +643,7 @@ impl BTreeCursor {
}; };
if target_leaf_page_is_in_the_left_subtree { if target_leaf_page_is_in_the_left_subtree {
// we don't advance in case of index tree internal nodes because we will visit this node going up // we don't advance in case of index tree internal nodes because we will visit this node going up
let mem_page = self.pager.read_page(*left_child_page as usize).unwrap(); let mem_page = self.pager.read_page(*left_child_page as usize)?;
self.stack.push(mem_page); self.stack.push(mem_page);
found_cell = true; found_cell = true;
break; break;
@@ -663,7 +663,7 @@ impl BTreeCursor {
match contents.rightmost_pointer() { match contents.rightmost_pointer() {
Some(right_most_pointer) => { Some(right_most_pointer) => {
self.stack.advance(); self.stack.advance();
let mem_page = self.pager.read_page(right_most_pointer as usize).unwrap(); let mem_page = self.pager.read_page(right_most_pointer as usize)?;
self.stack.push(mem_page); self.stack.push(mem_page);
continue; continue;
} }
@@ -716,7 +716,7 @@ impl BTreeCursor {
// insert // insert
let overflow = { let overflow = {
let contents = page.get().contents.as_mut().unwrap(); let contents = page.get().contents.as_mut().unwrap();
log::debug!( debug!(
"insert_into_page(overflow, cell_count={})", "insert_into_page(overflow, cell_count={})",
contents.cell_count() contents.cell_count()
); );
@@ -1027,15 +1027,13 @@ impl BTreeCursor {
// Right page pointer is u32 in right most pointer, and in cell is u32 too, so we can use a *u32 to hold where we want to change this value // Right page pointer is u32 in right most pointer, and in cell is u32 too, so we can use a *u32 to hold where we want to change this value
let mut right_pointer = PAGE_HEADER_OFFSET_RIGHTMOST_PTR; let mut right_pointer = PAGE_HEADER_OFFSET_RIGHTMOST_PTR;
for cell_idx in 0..parent_contents.cell_count() { for cell_idx in 0..parent_contents.cell_count() {
let cell = parent_contents let cell = parent_contents.cell_get(
.cell_get( cell_idx,
cell_idx, self.pager.clone(),
self.pager.clone(), self.payload_overflow_threshold_max(page_type.clone()),
self.payload_overflow_threshold_max(page_type.clone()), self.payload_overflow_threshold_min(page_type.clone()),
self.payload_overflow_threshold_min(page_type.clone()), self.usable_space(),
self.usable_space(), )?;
)
.unwrap();
let found = match cell { let found = match cell {
BTreeCell::TableInteriorCell(interior) => { BTreeCell::TableInteriorCell(interior) => {
interior._left_child_page as usize == current_idx interior._left_child_page as usize == current_idx
@@ -1128,16 +1126,14 @@ impl BTreeCursor {
for page in new_pages.iter_mut().take(new_pages_len - 1) { for page in new_pages.iter_mut().take(new_pages_len - 1) {
let contents = page.get().contents.as_mut().unwrap(); let contents = page.get().contents.as_mut().unwrap();
assert!(contents.cell_count() == 1); assert_eq!(contents.cell_count(), 1);
let last_cell = contents let last_cell = contents.cell_get(
.cell_get( contents.cell_count() - 1,
contents.cell_count() - 1, self.pager.clone(),
self.pager.clone(), self.payload_overflow_threshold_max(contents.page_type()),
self.payload_overflow_threshold_max(contents.page_type()), self.payload_overflow_threshold_min(contents.page_type()),
self.payload_overflow_threshold_min(contents.page_type()), self.usable_space(),
self.usable_space(), )?;
)
.unwrap();
let last_cell_pointer = match last_cell { let last_cell_pointer = match last_cell {
BTreeCell::TableInteriorCell(interior) => interior._left_child_page, BTreeCell::TableInteriorCell(interior) => interior._left_child_page,
_ => unreachable!(), _ => unreachable!(),
@@ -1170,8 +1166,7 @@ impl BTreeCursor {
self.payload_overflow_threshold_max(contents.page_type()), self.payload_overflow_threshold_max(contents.page_type()),
self.payload_overflow_threshold_min(contents.page_type()), self.payload_overflow_threshold_min(contents.page_type()),
self.usable_space(), self.usable_space(),
) )?;
.unwrap();
if is_leaf { if is_leaf {
// create a new divider cell and push // create a new divider cell and push
@@ -1353,7 +1348,7 @@ impl BTreeCursor {
/// Defragment a page. This means packing all the cells to the end of the page. /// Defragment a page. This means packing all the cells to the end of the page.
fn defragment_page(&self, page: &PageContent, db_header: Ref<DatabaseHeader>) { fn defragment_page(&self, page: &PageContent, db_header: Ref<DatabaseHeader>) {
log::debug!("defragment_page"); debug!("defragment_page");
let cloned_page = page.clone(); let cloned_page = page.clone();
// TODO(pere): usable space should include offset probably // TODO(pere): usable space should include offset probably
let usable_space = (db_header.page_size - db_header.reserved_space as u16) as u64; let usable_space = (db_header.page_size - db_header.reserved_space as u16) as u64;
@@ -1505,8 +1500,8 @@ impl BTreeCursor {
} }
// Next should always be 0 (NULL) at this point since we have reached the end of the freeblocks linked list // Next should always be 0 (NULL) at this point since we have reached the end of the freeblocks linked list
assert!( assert_eq!(
next == 0, next, 0,
"corrupted page: freeblocks list not in ascending order" "corrupted page: freeblocks list not in ascending order"
); );
@@ -1555,7 +1550,7 @@ impl BTreeCursor {
} }
let payload_overflow_threshold_max = self.payload_overflow_threshold_max(page_type.clone()); let payload_overflow_threshold_max = self.payload_overflow_threshold_max(page_type.clone());
log::debug!( debug!(
"fill_cell_payload(record_size={}, payload_overflow_threshold_max={})", "fill_cell_payload(record_size={}, payload_overflow_threshold_max={})",
record_buf.len(), record_buf.len(),
payload_overflow_threshold_max payload_overflow_threshold_max
@@ -1565,7 +1560,7 @@ impl BTreeCursor {
cell_payload.extend_from_slice(record_buf.as_slice()); cell_payload.extend_from_slice(record_buf.as_slice());
return; return;
} }
log::debug!("fill_cell_payload(overflow)"); debug!("fill_cell_payload(overflow)");
let payload_overflow_threshold_min = self.payload_overflow_threshold_min(page_type); let payload_overflow_threshold_min = self.payload_overflow_threshold_min(page_type);
// see e.g. https://github.com/sqlite/sqlite/blob/9591d3fe93936533c8c3b0dc4d025ac999539e11/src/dbstat.c#L371 // see e.g. https://github.com/sqlite/sqlite/blob/9591d3fe93936533c8c3b0dc4d025ac999539e11/src/dbstat.c#L371

View File

@@ -48,7 +48,7 @@ impl DatabaseStorage for FileStorage {
let buffer_size = buffer.borrow().len(); let buffer_size = buffer.borrow().len();
assert!(buffer_size >= 512); assert!(buffer_size >= 512);
assert!(buffer_size <= 65536); assert!(buffer_size <= 65536);
assert!((buffer_size & (buffer_size - 1)) == 0); assert_eq!(buffer_size & (buffer_size - 1), 0);
let pos = (page_idx - 1) * buffer_size; let pos = (page_idx - 1) * buffer_size;
self.file.pwrite(pos, buffer, c)?; self.file.pwrite(pos, buffer, c)?;
Ok(()) Ok(())

View File

@@ -216,7 +216,7 @@ impl Pager {
} }
/// Reads a page from the database. /// Reads a page from the database.
pub fn read_page(&self, page_idx: usize) -> crate::Result<PageRef> { pub fn read_page(&self, page_idx: usize) -> Result<PageRef> {
trace!("read_page(page_idx = {})", page_idx); trace!("read_page(page_idx = {})", page_idx);
let mut page_cache = self.page_cache.write().unwrap(); let mut page_cache = self.page_cache.write().unwrap();
let page_key = PageCacheKey::new(page_idx, Some(self.wal.borrow().get_max_frame())); let page_key = PageCacheKey::new(page_idx, Some(self.wal.borrow().get_max_frame()));
@@ -295,7 +295,7 @@ impl Pager {
} }
pub fn add_dirty(&self, page_id: usize) { pub fn add_dirty(&self, page_id: usize) {
// TODO: cehck duplicates? // TODO: check duplicates?
let mut dirty_pages = RefCell::borrow_mut(&self.dirty_pages); let mut dirty_pages = RefCell::borrow_mut(&self.dirty_pages);
dirty_pages.insert(page_id); dirty_pages.insert(page_id);
} }
@@ -312,7 +312,7 @@ impl Pager {
PageCacheKey::new(*page_id, Some(self.wal.borrow().get_max_frame())); PageCacheKey::new(*page_id, Some(self.wal.borrow().get_max_frame()));
let page = cache.get(&page_key).expect("we somehow added a page to dirty list but we didn't mark it as dirty, causing cache to drop it."); let page = cache.get(&page_key).expect("we somehow added a page to dirty list but we didn't mark it as dirty, causing cache to drop it.");
let page_type = page.get().contents.as_ref().unwrap().maybe_page_type(); let page_type = page.get().contents.as_ref().unwrap().maybe_page_type();
log::trace!("cacheflush(page={}, page_type={:?}", page_id, page_type); trace!("cacheflush(page={}, page_type={:?}", page_id, page_type);
self.wal.borrow_mut().append_frame( self.wal.borrow_mut().append_frame(
page.clone(), page.clone(),
db_size, db_size,
@@ -374,7 +374,7 @@ impl Pager {
pub fn checkpoint(&self) -> Result<CheckpointStatus> { pub fn checkpoint(&self) -> Result<CheckpointStatus> {
loop { loop {
let state = self.checkpoint_state.borrow().clone(); let state = self.checkpoint_state.borrow().clone();
log::trace!("pager_checkpoint(state={:?})", state); trace!("pager_checkpoint(state={:?})", state);
match state { match state {
CheckpointState::Checkpoint => { CheckpointState::Checkpoint => {
let in_flight = self.checkpoint_inflight.clone(); let in_flight = self.checkpoint_inflight.clone();
@@ -404,12 +404,12 @@ impl Pager {
} }
CheckpointState::CheckpointDone => { CheckpointState::CheckpointDone => {
let in_flight = self.checkpoint_inflight.clone(); let in_flight = self.checkpoint_inflight.clone();
if *in_flight.borrow() > 0 { return if *in_flight.borrow() > 0 {
return Ok(CheckpointStatus::IO); Ok(CheckpointStatus::IO)
} else { } else {
self.checkpoint_state.replace(CheckpointState::Checkpoint); self.checkpoint_state.replace(CheckpointState::Checkpoint);
return Ok(CheckpointStatus::Done); Ok(CheckpointStatus::Done)
} };
} }
} }
} }
@@ -437,7 +437,7 @@ impl Pager {
} }
/* /*
Get's a new page that increasing the size of the page or uses a free page. Gets a new page that increasing the size of the page or uses a free page.
Currently free list pages are not yet supported. Currently free list pages are not yet supported.
*/ */
#[allow(clippy::readonly_write_lock)] #[allow(clippy::readonly_write_lock)]

View File

@@ -263,7 +263,7 @@ fn finish_read_database_header(
) -> Result<()> { ) -> Result<()> {
let buf = buf.borrow(); let buf = buf.borrow();
let buf = buf.as_slice(); let buf = buf.as_slice();
let mut header = std::cell::RefCell::borrow_mut(&header); let mut header = RefCell::borrow_mut(&header);
header.magic.copy_from_slice(&buf[0..16]); header.magic.copy_from_slice(&buf[0..16]);
header.page_size = u16::from_be_bytes([buf[16], buf[17]]); header.page_size = u16::from_be_bytes([buf[16], buf[17]]);
header.write_version = buf[18]; header.write_version = buf[18];
@@ -705,12 +705,12 @@ pub fn begin_write_btree_page(
page: &PageRef, page: &PageRef,
write_counter: Rc<RefCell<usize>>, write_counter: Rc<RefCell<usize>>,
) -> Result<()> { ) -> Result<()> {
log::trace!("begin_write_btree_page(page={})", page.get().id); trace!("begin_write_btree_page(page={})", page.get().id);
let page_source = &pager.page_io; let page_source = &pager.page_io;
let page_finish = page.clone(); let page_finish = page.clone();
let page_id = page.get().id; let page_id = page.get().id;
log::trace!("begin_write_btree_page(page_id={})", page_id); trace!("begin_write_btree_page(page_id={})", page_id);
let buffer = { let buffer = {
let page = page.get(); let page = page.get();
let contents = page.contents.as_ref().unwrap(); let contents = page.contents.as_ref().unwrap();
@@ -721,7 +721,7 @@ pub fn begin_write_btree_page(
let write_complete = { let write_complete = {
let buf_copy = buffer.clone(); let buf_copy = buffer.clone();
Box::new(move |bytes_written: i32| { Box::new(move |bytes_written: i32| {
log::trace!("finish_write_btree_page"); trace!("finish_write_btree_page");
let buf_copy = buf_copy.clone(); let buf_copy = buf_copy.clone();
let buf_len = buf_copy.borrow().len(); let buf_len = buf_copy.borrow().len();
*write_counter.borrow_mut() -= 1; *write_counter.borrow_mut() -= 1;
@@ -926,7 +926,7 @@ pub enum SerialType {
} }
impl TryFrom<u64> for SerialType { impl TryFrom<u64> for SerialType {
type Error = crate::error::LimboError; type Error = LimboError;
fn try_from(value: u64) -> Result<Self> { fn try_from(value: u64) -> Result<Self> {
match value { match value {
@@ -1165,7 +1165,7 @@ pub fn begin_read_wal_frame(
buffer_pool: Rc<BufferPool>, buffer_pool: Rc<BufferPool>,
page: PageRef, page: PageRef,
) -> Result<()> { ) -> Result<()> {
log::trace!( trace!(
"begin_read_wal_frame(offset={}, page={})", "begin_read_wal_frame(offset={}, page={})",
offset, offset,
page.get().id page.get().id
@@ -1340,7 +1340,7 @@ pub fn checksum_wal(
input: (u32, u32), input: (u32, u32),
native_endian: bool, // Sqlite interprets big endian as "native" native_endian: bool, // Sqlite interprets big endian as "native"
) -> (u32, u32) { ) -> (u32, u32) {
assert!(buf.len() % 8 == 0, "buffer must be a multiple of 8"); assert_eq!(buf.len() % 8, 0, "buffer must be a multiple of 8");
let mut s0: u32 = input.0; let mut s0: u32 = input.0;
let mut s1: u32 = input.1; let mut s1: u32 = input.1;
let mut i = 0; let mut i = 0;
@@ -1366,7 +1366,7 @@ pub fn checksum_wal(
impl WalHeader { impl WalHeader {
pub fn as_bytes(&self) -> &[u8] { pub fn as_bytes(&self) -> &[u8] {
unsafe { std::mem::transmute::<&WalHeader, &[u8; std::mem::size_of::<WalHeader>()]>(self) } unsafe { std::mem::transmute::<&WalHeader, &[u8; size_of::<WalHeader>()]>(self) }
} }
} }

View File

@@ -66,7 +66,7 @@ impl LimboRwLock {
} }
} }
/// Locks exlusively. Returns true if it was successful, false if it couldn't lock it /// Locks exclusively. Returns true if it was successful, false if it couldn't lock it
pub fn write(&mut self) -> bool { pub fn write(&mut self) -> bool {
let lock = self.lock.load(Ordering::SeqCst); let lock = self.lock.load(Ordering::SeqCst);
match lock { match lock {
@@ -197,7 +197,7 @@ struct OngoingCheckpoint {
#[allow(dead_code)] #[allow(dead_code)]
pub struct WalFile { pub struct WalFile {
io: Arc<dyn crate::io::IO>, io: Arc<dyn IO>,
buffer_pool: Rc<BufferPool>, buffer_pool: Rc<BufferPool>,
sync_state: RefCell<SyncState>, sync_state: RefCell<SyncState>,
@@ -222,7 +222,7 @@ pub struct WalFile {
/// that needs to be communicated between threads so this struct does the job. /// that needs to be communicated between threads so this struct does the job.
#[allow(dead_code)] #[allow(dead_code)]
pub struct WalFileShared { pub struct WalFileShared {
wal_header: Arc<RwLock<sqlite3_ondisk::WalHeader>>, wal_header: Arc<RwLock<WalHeader>>,
min_frame: u64, min_frame: u64,
max_frame: u64, max_frame: u64,
nbackfills: u64, nbackfills: u64,
@@ -237,7 +237,7 @@ pub struct WalFileShared {
pages_in_frames: Vec<u64>, pages_in_frames: Vec<u64>,
last_checksum: (u32, u32), // Check of last frame in WAL, this is a cumulative checksum over all frames in the WAL last_checksum: (u32, u32), // Check of last frame in WAL, this is a cumulative checksum over all frames in the WAL
file: Rc<dyn File>, file: Rc<dyn File>,
/// read_locks is a list of read locks that can coexist with the max_frame nubmer stored in /// read_locks is a list of read locks that can coexist with the max_frame number stored in
/// value. There is a limited amount because and unbounded amount of connections could be /// value. There is a limited amount because and unbounded amount of connections could be
/// fatal. Therefore, for now we copy how SQLite behaves with limited amounts of read max /// fatal. Therefore, for now we copy how SQLite behaves with limited amounts of read max
/// frames that is equal to 5 /// frames that is equal to 5
@@ -293,7 +293,7 @@ impl Wal for WalFile {
self.max_frame_read_lock_index = max_read_mark_index as usize; self.max_frame_read_lock_index = max_read_mark_index as usize;
self.max_frame = max_read_mark as u64; self.max_frame = max_read_mark as u64;
self.min_frame = shared.nbackfills + 1; self.min_frame = shared.nbackfills + 1;
log::trace!( trace!(
"begin_read_tx(min_frame={}, max_frame={}, lock={})", "begin_read_tx(min_frame={}, max_frame={}, lock={})",
self.min_frame, self.min_frame,
self.max_frame, self.max_frame,
@@ -424,7 +424,7 @@ impl Wal for WalFile {
); );
'checkpoint_loop: loop { 'checkpoint_loop: loop {
let state = self.ongoing_checkpoint.state; let state = self.ongoing_checkpoint.state;
log::debug!("checkpoint(state={:?})", state); debug!("checkpoint(state={:?})", state);
match state { match state {
CheckpointState::Start => { CheckpointState::Start => {
// TODO(pere): check what frames are safe to checkpoint between many readers! // TODO(pere): check what frames are safe to checkpoint between many readers!
@@ -447,7 +447,7 @@ impl Wal for WalFile {
self.ongoing_checkpoint.max_frame = max_safe_frame; self.ongoing_checkpoint.max_frame = max_safe_frame;
self.ongoing_checkpoint.current_page = 0; self.ongoing_checkpoint.current_page = 0;
self.ongoing_checkpoint.state = CheckpointState::ReadFrame; self.ongoing_checkpoint.state = CheckpointState::ReadFrame;
log::trace!( trace!(
"checkpoint_start(min_frame={}, max_frame={})", "checkpoint_start(min_frame={}, max_frame={})",
self.ongoing_checkpoint.max_frame, self.ongoing_checkpoint.max_frame,
self.ongoing_checkpoint.min_frame self.ongoing_checkpoint.min_frame
@@ -475,11 +475,9 @@ impl Wal for WalFile {
if *frame >= self.ongoing_checkpoint.min_frame if *frame >= self.ongoing_checkpoint.min_frame
&& *frame <= self.ongoing_checkpoint.max_frame && *frame <= self.ongoing_checkpoint.max_frame
{ {
log::debug!( debug!(
"checkpoint page(state={:?}, page={}, frame={})", "checkpoint page(state={:?}, page={}, frame={})",
state, state, page, *frame
page,
*frame
); );
self.ongoing_checkpoint.page.get().id = page as usize; self.ongoing_checkpoint.page.get().id = page as usize;
@@ -553,13 +551,13 @@ impl Wal for WalFile {
match state { match state {
SyncState::NotSyncing => { SyncState::NotSyncing => {
let shared = self.shared.write().unwrap(); let shared = self.shared.write().unwrap();
log::debug!("wal_sync"); debug!("wal_sync");
{ {
let syncing = self.syncing.clone(); let syncing = self.syncing.clone();
*syncing.borrow_mut() = true; *syncing.borrow_mut() = true;
let completion = Completion::Sync(SyncCompletion { let completion = Completion::Sync(SyncCompletion {
complete: Box::new(move |_| { complete: Box::new(move |_| {
log::debug!("wal_sync finish"); debug!("wal_sync finish");
*syncing.borrow_mut() = false; *syncing.borrow_mut() = false;
}), }),
}); });
@@ -671,7 +669,7 @@ impl WalFileShared {
}; };
let native = cfg!(target_endian = "big"); // if target_endian is let native = cfg!(target_endian = "big"); // if target_endian is
// already big then we don't care but if isn't, header hasn't yet been // already big then we don't care but if isn't, header hasn't yet been
// encoded to big endian, therefore we wan't to swap bytes to compute this // encoded to big endian, therefore we want to swap bytes to compute this
// checksum. // checksum.
let checksums = (0, 0); let checksums = (0, 0);
let checksums = checksum_wal( let checksums = checksum_wal(

View File

@@ -290,9 +290,9 @@ fn emit_program_for_delete(
Ok(()) Ok(())
} }
fn emit_delete_insns<'a>( fn emit_delete_insns(
program: &mut ProgramBuilder, program: &mut ProgramBuilder,
t_ctx: &mut TranslateCtx<'a>, t_ctx: &mut TranslateCtx,
source: &SourceOperator, source: &SourceOperator,
limit: &Option<usize>, limit: &Option<usize>,
) -> Result<()> { ) -> Result<()> {

View File

@@ -1602,7 +1602,7 @@ pub fn translate_expr(
} else { } else {
// must be a float // must be a float
program.emit_insn(Insn::Real { program.emit_insn(Insn::Real {
value: val.parse().unwrap(), value: val.parse()?,
dest: target_register, dest: target_register,
}); });
} }
@@ -1830,7 +1830,7 @@ fn wrap_eval_jump_expr_zero_or_null(
} }
pub fn maybe_apply_affinity(col_type: Type, target_register: usize, program: &mut ProgramBuilder) { pub fn maybe_apply_affinity(col_type: Type, target_register: usize, program: &mut ProgramBuilder) {
if col_type == crate::schema::Type::Real { if col_type == Type::Real {
program.emit_insn(Insn::RealAffinity { program.emit_insn(Insn::RealAffinity {
register: target_register, register: target_register,
}) })

View File

@@ -74,7 +74,7 @@ pub fn translate_insert(
// Check if rowid was provided (through INTEGER PRIMARY KEY as a rowid alias) // Check if rowid was provided (through INTEGER PRIMARY KEY as a rowid alias)
let rowid_alias_index = table.columns.iter().position(|c| c.is_rowid_alias); let rowid_alias_index = table.columns.iter().position(|c| c.is_rowid_alias);
let has_user_provided_rowid = { let has_user_provided_rowid = {
assert!(column_mappings.len() == table.columns.len()); assert_eq!(column_mappings.len(), table.columns.len());
if let Some(index) = rowid_alias_index { if let Some(index) = rowid_alias_index {
column_mappings[index].value_index.is_some() column_mappings[index].value_index.is_some()
} else { } else {

View File

@@ -780,7 +780,7 @@ pub fn close_loop(
target_pc: lj_meta.label_match_flag_set_true, target_pc: lj_meta.label_match_flag_set_true,
}); });
assert!(program.offset() == jump_offset); assert_eq!(program.offset(), jump_offset);
} }
close_loop(program, t_ctx, left)?; close_loop(program, t_ctx, left)?;

View File

@@ -291,12 +291,12 @@ fn check_automatic_pk_index_required(
for result in primary_key_column_results { for result in primary_key_column_results {
if let Err(e) = result { if let Err(e) = result {
crate::bail_parse_error!("{}", e); bail_parse_error!("{}", e);
} }
let column_name = result.unwrap(); let column_name = result?;
let column_def = columns.get(&ast::Name(column_name.clone())); let column_def = columns.get(&ast::Name(column_name.clone()));
if column_def.is_none() { if column_def.is_none() {
crate::bail_parse_error!("No such column: {}", column_name); bail_parse_error!("No such column: {}", column_name);
} }
if matches!( if matches!(
@@ -326,10 +326,7 @@ fn check_automatic_pk_index_required(
ast::ColumnConstraint::PrimaryKey { .. } ast::ColumnConstraint::PrimaryKey { .. }
) { ) {
if primary_key_definition.is_some() { if primary_key_definition.is_some() {
crate::bail_parse_error!( bail_parse_error!("table {} has more than one primary key", tbl_name);
"table {} has more than one primary key",
tbl_name
);
} }
let typename = col_def.col_type.as_ref().map(|t| t.name.as_str()); let typename = col_def.col_type.as_ref().map(|t| t.name.as_str());
primary_key_definition = primary_key_definition =
@@ -340,7 +337,7 @@ fn check_automatic_pk_index_required(
// Check if table has rowid // Check if table has rowid
if options.contains(ast::TableOptions::WITHOUT_ROWID) { if options.contains(ast::TableOptions::WITHOUT_ROWID) {
crate::bail_parse_error!("WITHOUT ROWID tables are not supported yet"); bail_parse_error!("WITHOUT ROWID tables are not supported yet");
} }
// Check if we need an automatic index // Check if we need an automatic index
@@ -364,7 +361,7 @@ fn check_automatic_pk_index_required(
} }
} }
ast::CreateTableBody::AsSelect(_) => { ast::CreateTableBody::AsSelect(_) => {
crate::bail_parse_error!("CREATE TABLE AS SELECT not supported yet") bail_parse_error!("CREATE TABLE AS SELECT not supported yet")
} }
} }
} }
@@ -578,11 +575,11 @@ fn update_pragma(
PragmaName::CacheSize => { PragmaName::CacheSize => {
let cache_size = match value { let cache_size = match value {
ast::Expr::Literal(ast::Literal::Numeric(numeric_value)) => { ast::Expr::Literal(ast::Literal::Numeric(numeric_value)) => {
numeric_value.parse::<i64>().unwrap() numeric_value.parse::<i64>()?
} }
ast::Expr::Unary(ast::UnaryOperator::Negative, expr) => match *expr { ast::Expr::Unary(ast::UnaryOperator::Negative, expr) => match *expr {
ast::Expr::Literal(ast::Literal::Numeric(numeric_value)) => { ast::Expr::Literal(ast::Literal::Numeric(numeric_value)) => {
-numeric_value.parse::<i64>().unwrap() -numeric_value.parse::<i64>()?
} }
_ => bail_parse_error!("Not a valid value"), _ => bail_parse_error!("Not a valid value"),
}, },

View File

@@ -97,7 +97,7 @@ pub struct DeletePlan {
} }
impl Display for Plan { impl Display for Plan {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self { match self {
Select(select_plan) => write!(f, "{}", select_plan.source), Select(select_plan) => write!(f, "{}", select_plan.source),
Delete(delete_plan) => write!(f, "{}", delete_plan.source), Delete(delete_plan) => write!(f, "{}", delete_plan.source),

View File

@@ -12,7 +12,7 @@ use crate::{
}; };
use sqlite3_parser::ast::{self, Expr, FromClause, JoinType, Limit}; use sqlite3_parser::ast::{self, Expr, FromClause, JoinType, Limit};
pub const ROWID: &'static str = "rowid"; pub const ROWID: &str = "rowid";
pub struct OperatorIdCounter { pub struct OperatorIdCounter {
id: usize, id: usize,
@@ -29,7 +29,7 @@ impl OperatorIdCounter {
} }
} }
pub fn resolve_aggregates(expr: &ast::Expr, aggs: &mut Vec<Aggregate>) -> bool { pub fn resolve_aggregates(expr: &Expr, aggs: &mut Vec<Aggregate>) -> bool {
if aggs if aggs
.iter() .iter()
.any(|a| exprs_are_equivalent(&a.original_expr, expr)) .any(|a| exprs_are_equivalent(&a.original_expr, expr))
@@ -37,7 +37,7 @@ pub fn resolve_aggregates(expr: &ast::Expr, aggs: &mut Vec<Aggregate>) -> bool {
return true; return true;
} }
match expr { match expr {
ast::Expr::FunctionCall { name, args, .. } => { Expr::FunctionCall { name, args, .. } => {
let args_count = if let Some(args) = &args { let args_count = if let Some(args) = &args {
args.len() args.len()
} else { } else {
@@ -63,7 +63,7 @@ pub fn resolve_aggregates(expr: &ast::Expr, aggs: &mut Vec<Aggregate>) -> bool {
} }
} }
} }
ast::Expr::FunctionCallStar { name, .. } => { Expr::FunctionCallStar { name, .. } => {
if let Ok(Func::Agg(f)) = if let Ok(Func::Agg(f)) =
Func::resolve_function(normalize_ident(name.0.as_str()).as_str(), 0) Func::resolve_function(normalize_ident(name.0.as_str()).as_str(), 0)
{ {
@@ -77,13 +77,13 @@ pub fn resolve_aggregates(expr: &ast::Expr, aggs: &mut Vec<Aggregate>) -> bool {
false false
} }
} }
ast::Expr::Binary(lhs, _, rhs) => { Expr::Binary(lhs, _, rhs) => {
let mut contains_aggregates = false; let mut contains_aggregates = false;
contains_aggregates |= resolve_aggregates(lhs, aggs); contains_aggregates |= resolve_aggregates(lhs, aggs);
contains_aggregates |= resolve_aggregates(rhs, aggs); contains_aggregates |= resolve_aggregates(rhs, aggs);
contains_aggregates contains_aggregates
} }
ast::Expr::Unary(_, expr) => { Expr::Unary(_, expr) => {
let mut contains_aggregates = false; let mut contains_aggregates = false;
contains_aggregates |= resolve_aggregates(expr, aggs); contains_aggregates |= resolve_aggregates(expr, aggs);
contains_aggregates contains_aggregates
@@ -93,12 +93,9 @@ pub fn resolve_aggregates(expr: &ast::Expr, aggs: &mut Vec<Aggregate>) -> bool {
} }
} }
pub fn bind_column_references( pub fn bind_column_references(expr: &mut Expr, referenced_tables: &[TableReference]) -> Result<()> {
expr: &mut ast::Expr,
referenced_tables: &[TableReference],
) -> Result<()> {
match expr { match expr {
ast::Expr::Id(id) => { Expr::Id(id) => {
// true and false are special constants that are effectively aliases for 1 and 0 // true and false are special constants that are effectively aliases for 1 and 0
// and not identifiers of columns // and not identifiers of columns
if id.0.eq_ignore_ascii_case("true") || id.0.eq_ignore_ascii_case("false") { if id.0.eq_ignore_ascii_case("true") || id.0.eq_ignore_ascii_case("false") {
@@ -106,7 +103,7 @@ pub fn bind_column_references(
} }
let normalized_id = normalize_ident(id.0.as_str()); let normalized_id = normalize_ident(id.0.as_str());
if referenced_tables.len() > 0 { if !referenced_tables.is_empty() {
if let Some(row_id_expr) = if let Some(row_id_expr) =
parse_row_id(&normalized_id, 0, || referenced_tables.len() != 1)? parse_row_id(&normalized_id, 0, || referenced_tables.len() != 1)?
{ {
@@ -133,7 +130,7 @@ pub fn bind_column_references(
crate::bail_parse_error!("Column {} not found", id.0); crate::bail_parse_error!("Column {} not found", id.0);
} }
let (tbl_idx, col_idx, is_rowid_alias) = match_result.unwrap(); let (tbl_idx, col_idx, is_rowid_alias) = match_result.unwrap();
*expr = ast::Expr::Column { *expr = Expr::Column {
database: None, // TODO: support different databases database: None, // TODO: support different databases
table: tbl_idx, table: tbl_idx,
column: col_idx, column: col_idx,
@@ -141,7 +138,7 @@ pub fn bind_column_references(
}; };
Ok(()) Ok(())
} }
ast::Expr::Qualified(tbl, id) => { Expr::Qualified(tbl, id) => {
let normalized_table_name = normalize_ident(tbl.0.as_str()); let normalized_table_name = normalize_ident(tbl.0.as_str());
let matching_tbl_idx = referenced_tables.iter().position(|t| { let matching_tbl_idx = referenced_tables.iter().position(|t| {
t.table_identifier t.table_identifier
@@ -169,7 +166,7 @@ pub fn bind_column_references(
.columns() .columns()
.get(col_idx.unwrap()) .get(col_idx.unwrap())
.unwrap(); .unwrap();
*expr = ast::Expr::Column { *expr = Expr::Column {
database: None, // TODO: support different databases database: None, // TODO: support different databases
table: tbl_idx, table: tbl_idx,
column: col_idx.unwrap(), column: col_idx.unwrap(),
@@ -177,7 +174,7 @@ pub fn bind_column_references(
}; };
Ok(()) Ok(())
} }
ast::Expr::Between { Expr::Between {
lhs, lhs,
not: _, not: _,
start, start,
@@ -188,12 +185,12 @@ pub fn bind_column_references(
bind_column_references(end, referenced_tables)?; bind_column_references(end, referenced_tables)?;
Ok(()) Ok(())
} }
ast::Expr::Binary(expr, _operator, expr1) => { Expr::Binary(expr, _operator, expr1) => {
bind_column_references(expr, referenced_tables)?; bind_column_references(expr, referenced_tables)?;
bind_column_references(expr1, referenced_tables)?; bind_column_references(expr1, referenced_tables)?;
Ok(()) Ok(())
} }
ast::Expr::Case { Expr::Case {
base, base,
when_then_pairs, when_then_pairs,
else_expr, else_expr,
@@ -210,9 +207,9 @@ pub fn bind_column_references(
} }
Ok(()) Ok(())
} }
ast::Expr::Cast { expr, type_name: _ } => bind_column_references(expr, referenced_tables), Expr::Cast { expr, type_name: _ } => bind_column_references(expr, referenced_tables),
ast::Expr::Collate(expr, _string) => bind_column_references(expr, referenced_tables), Expr::Collate(expr, _string) => bind_column_references(expr, referenced_tables),
ast::Expr::FunctionCall { Expr::FunctionCall {
name: _, name: _,
distinctness: _, distinctness: _,
args, args,
@@ -227,11 +224,11 @@ pub fn bind_column_references(
Ok(()) Ok(())
} }
// Already bound earlier // Already bound earlier
ast::Expr::Column { .. } | ast::Expr::RowId { .. } => Ok(()), Expr::Column { .. } | Expr::RowId { .. } => Ok(()),
ast::Expr::DoublyQualified(_, _, _) => todo!(), Expr::DoublyQualified(_, _, _) => todo!(),
ast::Expr::Exists(_) => todo!(), Expr::Exists(_) => todo!(),
ast::Expr::FunctionCallStar { .. } => Ok(()), Expr::FunctionCallStar { .. } => Ok(()),
ast::Expr::InList { lhs, not: _, rhs } => { Expr::InList { lhs, not: _, rhs } => {
bind_column_references(lhs, referenced_tables)?; bind_column_references(lhs, referenced_tables)?;
if let Some(rhs) = rhs { if let Some(rhs) = rhs {
for arg in rhs { for arg in rhs {
@@ -240,36 +237,36 @@ pub fn bind_column_references(
} }
Ok(()) Ok(())
} }
ast::Expr::InSelect { .. } => todo!(), Expr::InSelect { .. } => todo!(),
ast::Expr::InTable { .. } => todo!(), Expr::InTable { .. } => todo!(),
ast::Expr::IsNull(expr) => { Expr::IsNull(expr) => {
bind_column_references(expr, referenced_tables)?; bind_column_references(expr, referenced_tables)?;
Ok(()) Ok(())
} }
ast::Expr::Like { lhs, rhs, .. } => { Expr::Like { lhs, rhs, .. } => {
bind_column_references(lhs, referenced_tables)?; bind_column_references(lhs, referenced_tables)?;
bind_column_references(rhs, referenced_tables)?; bind_column_references(rhs, referenced_tables)?;
Ok(()) Ok(())
} }
ast::Expr::Literal(_) => Ok(()), Expr::Literal(_) => Ok(()),
ast::Expr::Name(_) => todo!(), Expr::Name(_) => todo!(),
ast::Expr::NotNull(expr) => { Expr::NotNull(expr) => {
bind_column_references(expr, referenced_tables)?; bind_column_references(expr, referenced_tables)?;
Ok(()) Ok(())
} }
ast::Expr::Parenthesized(expr) => { Expr::Parenthesized(expr) => {
for e in expr.iter_mut() { for e in expr.iter_mut() {
bind_column_references(e, referenced_tables)?; bind_column_references(e, referenced_tables)?;
} }
Ok(()) Ok(())
} }
ast::Expr::Raise(_, _) => todo!(), Expr::Raise(_, _) => todo!(),
ast::Expr::Subquery(_) => todo!(), Expr::Subquery(_) => todo!(),
ast::Expr::Unary(_, expr) => { Expr::Unary(_, expr) => {
bind_column_references(expr, referenced_tables)?; bind_column_references(expr, referenced_tables)?;
Ok(()) Ok(())
} }
ast::Expr::Variable(_) => Ok(()), Expr::Variable(_) => Ok(()),
} }
} }
@@ -413,7 +410,7 @@ struct JoinParseResult {
source_operator: SourceOperator, source_operator: SourceOperator,
is_outer_join: bool, is_outer_join: bool,
using: Option<ast::DistinctNames>, using: Option<ast::DistinctNames>,
predicates: Option<Vec<ast::Expr>>, predicates: Option<Vec<Expr>>,
} }
fn parse_join( fn parse_join(
@@ -457,22 +454,20 @@ fn parse_join(
assert!(!left_tables.is_empty()); assert!(!left_tables.is_empty());
let right_table = &tables[table_index]; let right_table = &tables[table_index];
let right_cols = &right_table.columns(); let right_cols = &right_table.columns();
let mut distinct_names = None; let mut distinct_names: Option<ast::DistinctNames> = None;
// TODO: O(n^2) maybe not great for large tables or big multiway joins // TODO: O(n^2) maybe not great for large tables or big multiway joins
for right_col in right_cols.iter() { for right_col in right_cols.iter() {
let mut found_match = false; let mut found_match = false;
for left_table in left_tables.iter() { for left_table in left_tables.iter() {
for left_col in left_table.columns().iter() { for left_col in left_table.columns().iter() {
if left_col.name == right_col.name { if left_col.name == right_col.name {
if distinct_names.is_none() { if let Some(distinct_names) = distinct_names.as_mut() {
distinct_names =
Some(ast::DistinctNames::new(ast::Name(left_col.name.clone())));
} else {
distinct_names distinct_names
.as_mut()
.unwrap()
.insert(ast::Name(left_col.name.clone())) .insert(ast::Name(left_col.name.clone()))
.unwrap(); .unwrap();
} else {
distinct_names =
Some(ast::DistinctNames::new(ast::Name(left_col.name.clone())));
} }
found_match = true; found_match = true;
break; break;
@@ -483,10 +478,11 @@ fn parse_join(
} }
} }
} }
if distinct_names.is_none() { if let Some(distinct_names) = distinct_names {
Some(ast::JoinConstraint::Using(distinct_names))
} else {
crate::bail_parse_error!("No columns found to NATURAL join on"); crate::bail_parse_error!("No columns found to NATURAL join on");
} }
Some(ast::JoinConstraint::Using(distinct_names.unwrap()))
} else { } else {
constraint constraint
}; };
@@ -540,15 +536,15 @@ fn parse_join(
} }
let (left_table_idx, left_col_idx, left_col) = left_col.unwrap(); let (left_table_idx, left_col_idx, left_col) = left_col.unwrap();
let (right_col_idx, right_col) = right_col.unwrap(); let (right_col_idx, right_col) = right_col.unwrap();
using_predicates.push(ast::Expr::Binary( using_predicates.push(Expr::Binary(
Box::new(ast::Expr::Column { Box::new(Expr::Column {
database: None, database: None,
table: left_table_idx, table: left_table_idx,
column: left_col_idx, column: left_col_idx,
is_rowid_alias: left_col.is_rowid_alias, is_rowid_alias: left_col.is_rowid_alias,
}), }),
ast::Operator::Equals, ast::Operator::Equals,
Box::new(ast::Expr::Column { Box::new(Expr::Column {
database: None, database: None,
table: right_table.table_index, table: right_table.table_index,
column: right_col_idx, column: right_col_idx,
@@ -586,12 +582,9 @@ pub fn parse_limit(limit: Limit) -> Option<usize> {
} }
} }
pub fn break_predicate_at_and_boundaries( pub fn break_predicate_at_and_boundaries(predicate: Expr, out_predicates: &mut Vec<Expr>) {
predicate: ast::Expr,
out_predicates: &mut Vec<ast::Expr>,
) {
match predicate { match predicate {
ast::Expr::Binary(left, ast::Operator::And, right) => { Expr::Binary(left, ast::Operator::And, right) => {
break_predicate_at_and_boundaries(*left, out_predicates); break_predicate_at_and_boundaries(*left, out_predicates);
break_predicate_at_and_boundaries(*right, out_predicates); break_predicate_at_and_boundaries(*right, out_predicates);
} }
@@ -601,7 +594,7 @@ pub fn break_predicate_at_and_boundaries(
} }
} }
fn parse_row_id<F>(column_name: &str, table_id: usize, fn_check: F) -> Result<Option<ast::Expr>> fn parse_row_id<F>(column_name: &str, table_id: usize, fn_check: F) -> Result<Option<Expr>>
where where
F: FnOnce() -> bool, F: FnOnce() -> bool,
{ {
@@ -610,7 +603,7 @@ where
crate::bail_parse_error!("ROWID is ambiguous"); crate::bail_parse_error!("ROWID is ambiguous");
} }
return Ok(Some(ast::Expr::RowId { return Ok(Some(Expr::RowId {
database: None, // TODO: support different databases database: None, // TODO: support different databases
table: table_id, table: table_id,
})); }));

View File

@@ -69,10 +69,10 @@ pub fn prepare_select_plan(
let mut aggregate_expressions = Vec::new(); let mut aggregate_expressions = Vec::new();
for (result_column_idx, column) in columns.iter_mut().enumerate() { for (result_column_idx, column) in columns.iter_mut().enumerate() {
match column { match column {
ast::ResultColumn::Star => { ResultColumn::Star => {
plan.source.select_star(&mut plan.result_columns); plan.source.select_star(&mut plan.result_columns);
} }
ast::ResultColumn::TableStar(name) => { ResultColumn::TableStar(name) => {
let name_normalized = normalize_ident(name.0.as_str()); let name_normalized = normalize_ident(name.0.as_str());
let referenced_table = plan let referenced_table = plan
.referenced_tables .referenced_tables
@@ -96,7 +96,7 @@ pub fn prepare_select_plan(
}); });
} }
} }
ast::ResultColumn::Expr(ref mut expr, maybe_alias) => { ResultColumn::Expr(ref mut expr, maybe_alias) => {
bind_column_references(expr, &plan.referenced_tables)?; bind_column_references(expr, &plan.referenced_tables)?;
match expr { match expr {
ast::Expr::FunctionCall { ast::Expr::FunctionCall {

View File

@@ -12,9 +12,9 @@ use super::{
/// Emit the subqueries contained in the FROM clause. /// Emit the subqueries contained in the FROM clause.
/// This is done first so the results can be read in the main query loop. /// This is done first so the results can be read in the main query loop.
pub fn emit_subqueries<'a>( pub fn emit_subqueries(
program: &mut ProgramBuilder, program: &mut ProgramBuilder,
t_ctx: &mut TranslateCtx<'a>, t_ctx: &mut TranslateCtx,
referenced_tables: &mut [TableReference], referenced_tables: &mut [TableReference],
source: &mut SourceOperator, source: &mut SourceOperator,
) -> Result<()> { ) -> Result<()> {

View File

@@ -146,13 +146,13 @@ impl OwnedValue {
let Some(text) = v.to_text() else { let Some(text) = v.to_text() else {
return OwnedValue::Null; return OwnedValue::Null;
}; };
OwnedValue::build_text(std::rc::Rc::new(text)) OwnedValue::build_text(Rc::new(text))
} }
ExtValueType::Blob => { ExtValueType::Blob => {
let Some(blob) = v.to_blob() else { let Some(blob) = v.to_blob() else {
return OwnedValue::Null; return OwnedValue::Null;
}; };
OwnedValue::Blob(std::rc::Rc::new(blob)) OwnedValue::Blob(Rc::new(blob))
} }
ExtValueType::Error => { ExtValueType::Error => {
let Some(err) = v.to_error() else { let Some(err) = v.to_error() else {
@@ -241,7 +241,7 @@ impl PartialOrd<OwnedValue> for OwnedValue {
} }
} }
impl std::cmp::PartialOrd<AggContext> for AggContext { impl PartialOrd<AggContext> for AggContext {
fn partial_cmp(&self, other: &AggContext) -> Option<std::cmp::Ordering> { fn partial_cmp(&self, other: &AggContext) -> Option<std::cmp::Ordering> {
match (self, other) { match (self, other) {
(Self::Avg(a, _), Self::Avg(b, _)) => a.partial_cmp(b), (Self::Avg(a, _), Self::Avg(b, _)) => a.partial_cmp(b),
@@ -255,9 +255,9 @@ impl std::cmp::PartialOrd<AggContext> for AggContext {
} }
} }
impl std::cmp::Eq for OwnedValue {} impl Eq for OwnedValue {}
impl std::cmp::Ord for OwnedValue { impl Ord for OwnedValue {
fn cmp(&self, other: &Self) -> std::cmp::Ordering { fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.partial_cmp(other).unwrap() self.partial_cmp(other).unwrap()
} }
@@ -660,7 +660,7 @@ mod tests {
let header_length = record.values.len() + 1; let header_length = record.values.len() + 1;
let header = &buf[0..header_length]; let header = &buf[0..header_length];
// First byte should be header size // First byte should be header size
assert!(header[0] == header_length as u8); // Header should be larger than number of values assert_eq!(header[0], header_length as u8); // Header should be larger than number of values
// Check that correct serial types were chosen // Check that correct serial types were chosen
assert_eq!(header[1] as u64, u64::from(SerialType::I8)); assert_eq!(header[1] as u64, u64::from(SerialType::I8));

View File

@@ -328,7 +328,7 @@ pub mod tests {
Add, Add,
Box::new(Expr::Literal(Literal::Numeric("826".to_string()))), Box::new(Expr::Literal(Literal::Numeric("826".to_string()))),
); );
assert!(super::exprs_are_equivalent(&expr1, &expr2)); assert!(exprs_are_equivalent(&expr1, &expr2));
} }
#[test] #[test]
@@ -343,7 +343,7 @@ pub mod tests {
Add, Add,
Box::new(Expr::Literal(Literal::Numeric("123".to_string()))), Box::new(Expr::Literal(Literal::Numeric("123".to_string()))),
); );
assert!(super::exprs_are_equivalent(&expr1, &expr2)); assert!(exprs_are_equivalent(&expr1, &expr2));
} }
#[test] #[test]
@@ -358,7 +358,7 @@ pub mod tests {
Subtract, Subtract,
Box::new(Expr::Literal(Literal::Numeric("364".to_string()))), Box::new(Expr::Literal(Literal::Numeric("364".to_string()))),
); );
assert!(!super::exprs_are_equivalent(&expr3, &expr4)); assert!(!exprs_are_equivalent(&expr3, &expr4));
} }
#[test] #[test]
@@ -373,7 +373,7 @@ pub mod tests {
Subtract, Subtract,
Box::new(Expr::Literal(Literal::Numeric("22.0".to_string()))), Box::new(Expr::Literal(Literal::Numeric("22.0".to_string()))),
); );
assert!(super::exprs_are_equivalent(&expr3, &expr4)); assert!(exprs_are_equivalent(&expr3, &expr4));
} }
#[test] #[test]
@@ -392,7 +392,7 @@ pub mod tests {
order_by: None, order_by: None,
filter_over: None, filter_over: None,
}; };
assert!(super::exprs_are_equivalent(&func1, &func2)); assert!(exprs_are_equivalent(&func1, &func2));
let func3 = Expr::FunctionCall { let func3 = Expr::FunctionCall {
name: Id("SUM".to_string()), name: Id("SUM".to_string()),
@@ -401,7 +401,7 @@ pub mod tests {
order_by: None, order_by: None,
filter_over: None, filter_over: None,
}; };
assert!(!super::exprs_are_equivalent(&func1, &func3)); assert!(!exprs_are_equivalent(&func1, &func3));
} }
#[test] #[test]
@@ -420,7 +420,7 @@ pub mod tests {
order_by: None, order_by: None,
filter_over: None, filter_over: None,
}; };
assert!(!super::exprs_are_equivalent(&sum, &sum_distinct)); assert!(!exprs_are_equivalent(&sum, &sum_distinct));
} }
#[test] #[test]
@@ -435,7 +435,7 @@ pub mod tests {
Multiply, Multiply,
Box::new(Expr::Literal(Literal::Numeric("42".to_string()))), Box::new(Expr::Literal(Literal::Numeric("42".to_string()))),
); );
assert!(super::exprs_are_equivalent(&expr1, &expr2)); assert!(exprs_are_equivalent(&expr1, &expr2));
} }
#[test] #[test]
@@ -450,7 +450,7 @@ pub mod tests {
Add, Add,
Box::new(Expr::Literal(Literal::Numeric("683".to_string()))), Box::new(Expr::Literal(Literal::Numeric("683".to_string()))),
); );
assert!(super::exprs_are_equivalent(&expr1, &expr2)); assert!(exprs_are_equivalent(&expr1, &expr2));
} }
#[test] #[test]
fn test_expressions_parenthesized_equivalent() { fn test_expressions_parenthesized_equivalent() {
@@ -464,7 +464,7 @@ pub mod tests {
Add, Add,
Box::new(Expr::Literal(Literal::Numeric("7".to_string()))), Box::new(Expr::Literal(Literal::Numeric("7".to_string()))),
); );
assert!(super::exprs_are_equivalent(&expr7, &expr8)); assert!(exprs_are_equivalent(&expr7, &expr8));
} }
#[test] #[test]
@@ -483,7 +483,7 @@ pub mod tests {
rhs: Box::new(Expr::Literal(Literal::String("%john%".to_string()))), rhs: Box::new(Expr::Literal(Literal::String("%john%".to_string()))),
escape: Some(Box::new(Expr::Literal(Literal::String("\\".to_string())))), escape: Some(Box::new(Expr::Literal(Literal::String("\\".to_string())))),
}; };
assert!(super::exprs_are_equivalent(&expr1, &expr2)); assert!(exprs_are_equivalent(&expr1, &expr2));
} }
#[test] #[test]
@@ -502,7 +502,7 @@ pub mod tests {
rhs: Box::new(Expr::Literal(Literal::String("%john%".to_string()))), rhs: Box::new(Expr::Literal(Literal::String("%john%".to_string()))),
escape: Some(Box::new(Expr::Literal(Literal::String("#".to_string())))), escape: Some(Box::new(Expr::Literal(Literal::String("#".to_string())))),
}; };
assert!(!super::exprs_are_equivalent(&expr1, &expr2)); assert!(!exprs_are_equivalent(&expr1, &expr2));
} }
#[test] #[test]
fn test_expressions_equivalent_between() { fn test_expressions_equivalent_between() {
@@ -518,7 +518,7 @@ pub mod tests {
start: Box::new(Expr::Literal(Literal::Numeric("18".to_string()))), start: Box::new(Expr::Literal(Literal::Numeric("18".to_string()))),
end: Box::new(Expr::Literal(Literal::Numeric("65".to_string()))), end: Box::new(Expr::Literal(Literal::Numeric("65".to_string()))),
}; };
assert!(super::exprs_are_equivalent(&expr1, &expr2)); assert!(exprs_are_equivalent(&expr1, &expr2));
// differing BETWEEN bounds // differing BETWEEN bounds
let expr3 = Expr::Between { let expr3 = Expr::Between {
@@ -527,7 +527,7 @@ pub mod tests {
start: Box::new(Expr::Literal(Literal::Numeric("20".to_string()))), start: Box::new(Expr::Literal(Literal::Numeric("20".to_string()))),
end: Box::new(Expr::Literal(Literal::Numeric("65".to_string()))), end: Box::new(Expr::Literal(Literal::Numeric("65".to_string()))),
}; };
assert!(!super::exprs_are_equivalent(&expr1, &expr3)); assert!(!exprs_are_equivalent(&expr1, &expr3));
} }
#[test] #[test]
fn test_cast_exprs_equivalent() { fn test_cast_exprs_equivalent() {
@@ -546,16 +546,16 @@ pub mod tests {
size: None, size: None,
}), }),
}; };
assert!(super::exprs_are_equivalent(&cast1, &cast2)); assert!(exprs_are_equivalent(&cast1, &cast2));
} }
#[test] #[test]
fn test_ident_equivalency() { fn test_ident_equivalency() {
assert!(super::check_ident_equivalency("\"foo\"", "foo")); assert!(check_ident_equivalency("\"foo\"", "foo"));
assert!(super::check_ident_equivalency("[foo]", "foo")); assert!(check_ident_equivalency("[foo]", "foo"));
assert!(super::check_ident_equivalency("`FOO`", "foo")); assert!(check_ident_equivalency("`FOO`", "foo"));
assert!(super::check_ident_equivalency("\"foo\"", "`FOO`")); assert!(check_ident_equivalency("\"foo\"", "`FOO`"));
assert!(!super::check_ident_equivalency("\"foo\"", "[bar]")); assert!(!check_ident_equivalency("\"foo\"", "[bar]"));
assert!(!super::check_ident_equivalency("foo", "\"bar\"")); assert!(!check_ident_equivalency("foo", "\"bar\""));
} }
} }

View File

@@ -83,7 +83,7 @@ impl ProgramBuilder {
let cursor = self.next_free_cursor_id; let cursor = self.next_free_cursor_id;
self.next_free_cursor_id += 1; self.next_free_cursor_id += 1;
self.cursor_ref.push((table_identifier, cursor_type)); self.cursor_ref.push((table_identifier, cursor_type));
assert!(self.cursor_ref.len() == self.next_free_cursor_id); assert_eq!(self.cursor_ref.len(), self.next_free_cursor_id);
cursor cursor
} }

View File

@@ -579,14 +579,14 @@ fn parse_modifier(modifier: &str) -> Result<Modifier> {
if parts[0].len() == digits_in_date { if parts[0].len() == digits_in_date {
let date = parse_modifier_date(parts[0])?; let date = parse_modifier_date(parts[0])?;
Ok(Modifier::DateOffset { Ok(Modifier::DateOffset {
years: sign * date.year() as i32, years: sign * date.year(),
months: sign * date.month() as i32, months: sign * date.month() as i32,
days: sign * date.day() as i32, days: sign * date.day() as i32,
}) })
} else { } else {
// time values are either 12, 8 or 5 digits // time values are either 12, 8 or 5 digits
let time = parse_modifier_time(parts[0])?; let time = parse_modifier_time(parts[0])?;
let time_delta = (sign * (time.num_seconds_from_midnight() as i32)) as i32; let time_delta = sign * (time.num_seconds_from_midnight() as i32);
Ok(Modifier::TimeOffset(TimeDelta::seconds(time_delta.into()))) Ok(Modifier::TimeOffset(TimeDelta::seconds(time_delta.into())))
} }
} }
@@ -596,7 +596,7 @@ fn parse_modifier(modifier: &str) -> Result<Modifier> {
// Convert time to total seconds (with sign) // Convert time to total seconds (with sign)
let time_delta = sign * (time.num_seconds_from_midnight() as i32); let time_delta = sign * (time.num_seconds_from_midnight() as i32);
Ok(Modifier::DateTimeOffset { Ok(Modifier::DateTimeOffset {
years: sign * (date.year() as i32), years: sign * (date.year()),
months: sign * (date.month() as i32), months: sign * (date.month() as i32),
days: sign * date.day() as i32, days: sign * date.day() as i32,
seconds: time_delta, seconds: time_delta,
@@ -1401,7 +1401,7 @@ mod tests {
fn format(dt: NaiveDateTime) -> String { fn format(dt: NaiveDateTime) -> String {
dt.format("%Y-%m-%d %H:%M:%S").to_string() dt.format("%Y-%m-%d %H:%M:%S").to_string()
} }
fn weekday_sunday_based(dt: &chrono::NaiveDateTime) -> u32 { fn weekday_sunday_based(dt: &NaiveDateTime) -> u32 {
dt.weekday().num_days_from_sunday() dt.weekday().num_days_from_sunday()
} }
@@ -1438,8 +1438,7 @@ mod tests {
&[text("2023-06-15 12:30:45"), text("subsec")], &[text("2023-06-15 12:30:45"), text("subsec")],
DateTimeOutput::Time, DateTimeOutput::Time,
); );
let result = let result = NaiveTime::parse_from_str(&result.to_string(), "%H:%M:%S%.3f").unwrap();
chrono::NaiveTime::parse_from_str(&result.to_string(), "%H:%M:%S%.3f").unwrap();
assert_eq!(time.time(), result); assert_eq!(time.time(), result);
} }
@@ -1537,8 +1536,7 @@ mod tests {
DateTimeOutput::DateTime, DateTimeOutput::DateTime,
); );
let result = let result =
chrono::NaiveDateTime::parse_from_str(&result.to_string(), "%Y-%m-%d %H:%M:%S%.3f") NaiveDateTime::parse_from_str(&result.to_string(), "%Y-%m-%d %H:%M:%S%.3f").unwrap();
.unwrap();
assert_eq!(expected, result); assert_eq!(expected, result);
} }

View File

@@ -10,7 +10,7 @@ pub fn construct_like_escape_arg(escape_value: &OwnedValue) -> Result<char, Limb
let mut escape_chars = text.value.chars(); let mut escape_chars = text.value.chars();
match (escape_chars.next(), escape_chars.next()) { match (escape_chars.next(), escape_chars.next()) {
(Some(escape), None) => Ok(escape), (Some(escape), None) => Ok(escape),
_ => Result::Err(LimboError::Constraint( _ => Err(LimboError::Constraint(
"ESCAPE expression must be a single character".to_string(), "ESCAPE expression must be a single character".to_string(),
)), )),
} }
@@ -143,7 +143,7 @@ fn construct_glob_regex(pattern: &str) -> Result<Regex, LimboError> {
} }
}; };
while let Some(next_ch) = chars.next() { for next_ch in chars.by_ref() {
match next_ch { match next_ch {
']' => { ']' => {
bracket_closed = true; bracket_closed = true;
@@ -175,7 +175,7 @@ fn construct_glob_regex(pattern: &str) -> Result<Regex, LimboError> {
if bracket_closed { if bracket_closed {
Ok(Regex::new(&regex_pattern).unwrap()) Ok(Regex::new(&regex_pattern).unwrap())
} else { } else {
Result::Err(LimboError::Constraint( Err(LimboError::Constraint(
"blob pattern is not closed".to_string(), "blob pattern is not closed".to_string(),
)) ))
} }

View File

@@ -889,26 +889,26 @@ impl Program {
} }
} }
log::trace!("Halt auto_commit {}", self.auto_commit); log::trace!("Halt auto_commit {}", self.auto_commit);
if self.auto_commit { return if self.auto_commit {
return match pager.end_tx() { match pager.end_tx() {
Ok(crate::storage::wal::CheckpointStatus::IO) => Ok(StepResult::IO), Ok(crate::storage::wal::CheckpointStatus::IO) => Ok(StepResult::IO),
Ok(crate::storage::wal::CheckpointStatus::Done) => Ok(StepResult::Done), Ok(crate::storage::wal::CheckpointStatus::Done) => Ok(StepResult::Done),
Err(e) => Err(e), Err(e) => Err(e),
}; }
} else { } else {
return Ok(StepResult::Done); Ok(StepResult::Done)
} };
} }
Insn::Transaction { write } => { Insn::Transaction { write } => {
let connection = self.connection.upgrade().unwrap(); let connection = self.connection.upgrade().unwrap();
let current_state = connection.transaction_state.borrow().clone(); let current_state = connection.transaction_state.borrow().clone();
let (new_transaction_state, updated) = match (&current_state, write) { let (new_transaction_state, updated) = match (&current_state, write) {
(crate::TransactionState::Write, true) => (TransactionState::Write, false), (TransactionState::Write, true) => (TransactionState::Write, false),
(crate::TransactionState::Write, false) => (TransactionState::Write, false), (TransactionState::Write, false) => (TransactionState::Write, false),
(crate::TransactionState::Read, true) => (TransactionState::Write, true), (TransactionState::Read, true) => (TransactionState::Write, true),
(crate::TransactionState::Read, false) => (TransactionState::Read, false), (TransactionState::Read, false) => (TransactionState::Read, false),
(crate::TransactionState::None, true) => (TransactionState::Write, true), (TransactionState::None, true) => (TransactionState::Write, true),
(crate::TransactionState::None, false) => (TransactionState::Read, true), (TransactionState::None, false) => (TransactionState::Read, true),
}; };
if updated && matches!(current_state, TransactionState::None) { if updated && matches!(current_state, TransactionState::None) {
@@ -1481,7 +1481,7 @@ impl Program {
_ => unreachable!(), _ => unreachable!(),
}) })
.collect(); .collect();
let cursor = sorter::Sorter::new(order); let cursor = Sorter::new(order);
sorter_cursors.insert(*cursor_id, cursor); sorter_cursors.insert(*cursor_id, cursor);
state.pc += 1; state.pc += 1;
} }
@@ -1630,7 +1630,7 @@ impl Program {
}, },
crate::function::Func::Scalar(scalar_func) => match scalar_func { crate::function::Func::Scalar(scalar_func) => match scalar_func {
ScalarFunc::Cast => { ScalarFunc::Cast => {
assert!(arg_count == 2); assert_eq!(arg_count, 2);
assert!(*start_reg + 1 < state.registers.len()); assert!(*start_reg + 1 < state.registers.len());
let reg_value_argument = state.registers[*start_reg].clone(); let reg_value_argument = state.registers[*start_reg].clone();
let OwnedValue::Text(reg_value_type) = let OwnedValue::Text(reg_value_type) =
@@ -1715,7 +1715,7 @@ impl Program {
&state.registers[*start_reg + 2], &state.registers[*start_reg + 2],
) { ) {
Ok(x) => x, Ok(x) => x,
Err(e) => return Result::Err(e), Err(e) => return Err(e),
}; };
OwnedValue::Integer(exec_like_with_escape( OwnedValue::Integer(exec_like_with_escape(
@@ -1920,7 +1920,7 @@ impl Program {
state.registers[*dest] = OwnedValue::build_text(Rc::new(version)); state.registers[*dest] = OwnedValue::build_text(Rc::new(version));
} }
ScalarFunc::Replace => { ScalarFunc::Replace => {
assert!(arg_count == 3); assert_eq!(arg_count, 3);
let source = &state.registers[*start_reg]; let source = &state.registers[*start_reg];
let pattern = &state.registers[*start_reg + 1]; let pattern = &state.registers[*start_reg + 1];
let replacement = &state.registers[*start_reg + 2]; let replacement = &state.registers[*start_reg + 2];
@@ -2326,7 +2326,7 @@ fn trace_insn(program: &Program, addr: InsnReference, insn: &Insn) {
addr, addr,
insn, insn,
String::new(), String::new(),
program.comments.get(&(addr as u32)).copied() program.comments.get(&{ addr }).copied()
) )
); );
} }
@@ -2337,7 +2337,7 @@ fn print_insn(program: &Program, addr: InsnReference, insn: &Insn, indent: Strin
addr, addr,
insn, insn,
indent, indent,
program.comments.get(&(addr as u32)).copied(), program.comments.get(&{ addr }).copied(),
); );
println!("{}", s); println!("{}", s);
} }
@@ -3195,10 +3195,7 @@ fn checked_cast_text_to_numeric(text: &str) -> std::result::Result<OwnedValue, (
// try casting to numeric if not possible return integer 0 // try casting to numeric if not possible return integer 0
fn cast_text_to_numeric(text: &str) -> OwnedValue { fn cast_text_to_numeric(text: &str) -> OwnedValue {
match checked_cast_text_to_numeric(text) { checked_cast_text_to_numeric(text).unwrap_or(OwnedValue::Integer(0))
Ok(value) => value,
Err(_) => OwnedValue::Integer(0),
}
} }
// Check if float can be losslessly converted to 51-bit integer // Check if float can be losslessly converted to 51-bit integer

View File

@@ -35,7 +35,7 @@ pub trait ArbitraryFrom<T> {
pub(crate) fn frequency< pub(crate) fn frequency<
'a, 'a,
T, T,
R: rand::Rng, R: Rng,
N: Sum + PartialOrd + Copy + Default + SampleUniform + SubAssign, N: Sum + PartialOrd + Copy + Default + SampleUniform + SubAssign,
>( >(
choices: Vec<(N, Box<dyn Fn(&mut R) -> T + 'a>)>, choices: Vec<(N, Box<dyn Fn(&mut R) -> T + 'a>)>,
@@ -55,23 +55,20 @@ pub(crate) fn frequency<
} }
/// one_of is a helper function for composing different generators with equal probability of occurence. /// one_of is a helper function for composing different generators with equal probability of occurence.
pub(crate) fn one_of<'a, T, R: rand::Rng>( pub(crate) fn one_of<'a, T, R: Rng>(choices: Vec<Box<dyn Fn(&mut R) -> T + 'a>>, rng: &mut R) -> T {
choices: Vec<Box<dyn Fn(&mut R) -> T + 'a>>,
rng: &mut R,
) -> T {
let index = rng.gen_range(0..choices.len()); let index = rng.gen_range(0..choices.len());
choices[index](rng) choices[index](rng)
} }
/// pick is a helper function for uniformly picking a random element from a slice /// pick is a helper function for uniformly picking a random element from a slice
pub(crate) fn pick<'a, T, R: rand::Rng>(choices: &'a [T], rng: &mut R) -> &'a T { pub(crate) fn pick<'a, T, R: Rng>(choices: &'a [T], rng: &mut R) -> &'a T {
let index = rng.gen_range(0..choices.len()); let index = rng.gen_range(0..choices.len());
&choices[index] &choices[index]
} }
/// pick_index is typically used for picking an index from a slice to later refer to the element /// pick_index is typically used for picking an index from a slice to later refer to the element
/// at that index. /// at that index.
pub(crate) fn pick_index<R: rand::Rng>(choices: usize, rng: &mut R) -> usize { pub(crate) fn pick_index<R: Rng>(choices: usize, rng: &mut R) -> usize {
rng.gen_range(0..choices) rng.gen_range(0..choices)
} }

View File

@@ -330,7 +330,7 @@ impl Interaction {
); );
return Err(err.unwrap()); return Err(err.unwrap());
} }
let rows = rows.unwrap(); let rows = rows?;
assert!(rows.is_some()); assert!(rows.is_some());
let mut rows = rows.unwrap(); let mut rows = rows.unwrap();
let mut out = Vec::new(); let mut out = Vec::new();

View File

@@ -44,7 +44,7 @@ impl Arbitrary for ColumnType {
} }
impl ArbitraryFrom<&Table> for Vec<Value> { impl ArbitraryFrom<&Table> for Vec<Value> {
fn arbitrary_from<R: rand::Rng>(rng: &mut R, table: &Table) -> Self { fn arbitrary_from<R: Rng>(rng: &mut R, table: &Table) -> Self {
let mut row = Vec::new(); let mut row = Vec::new();
for column in table.columns.iter() { for column in table.columns.iter() {
let value = Value::arbitrary_from(rng, &column.column_type); let value = Value::arbitrary_from(rng, &column.column_type);

View File

@@ -64,10 +64,7 @@ fn main() -> Result<(), String> {
let cli_opts = SimulatorCLI::parse(); let cli_opts = SimulatorCLI::parse();
cli_opts.validate()?; cli_opts.validate()?;
let seed = match cli_opts.seed { let seed = cli_opts.seed.unwrap_or_else(|| thread_rng().next_u64());
Some(seed) => seed,
None => rand::thread_rng().next_u64(),
};
let output_dir = match &cli_opts.output_dir { let output_dir = match &cli_opts.output_dir {
Some(dir) => Path::new(dir).to_path_buf(), Some(dir) => Path::new(dir).to_path_buf(),

View File

@@ -3,7 +3,7 @@ use std::sync::{Arc, Mutex};
use limbo_core::{LimboError, Result}; use limbo_core::{LimboError, Result};
use crate::generation::{ use crate::generation::{
self, pick_index, pick_index,
plan::{Interaction, InteractionPlan, InteractionPlanState, ResultSet}, plan::{Interaction, InteractionPlan, InteractionPlanState, ResultSet},
}; };
@@ -45,7 +45,7 @@ impl ExecutionHistory {
pub(crate) struct ExecutionResult { pub(crate) struct ExecutionResult {
pub(crate) history: ExecutionHistory, pub(crate) history: ExecutionHistory,
pub(crate) error: Option<limbo_core::LimboError>, pub(crate) error: Option<LimboError>,
} }
impl ExecutionResult { impl ExecutionResult {
@@ -87,7 +87,7 @@ pub(crate) fn execute_plans(
if now.elapsed().as_secs() >= env.opts.max_time_simulation as u64 { if now.elapsed().as_secs() >= env.opts.max_time_simulation as u64 {
return ExecutionResult::new( return ExecutionResult::new(
history, history,
Some(limbo_core::LimboError::InternalError( Some(LimboError::InternalError(
"maximum time for simulation reached".into(), "maximum time for simulation reached".into(),
)), )),
); );
@@ -170,7 +170,7 @@ fn execute_interaction(
) -> Result<ExecutionContinuation> { ) -> Result<ExecutionContinuation> {
log::info!("executing: {}", interaction); log::info!("executing: {}", interaction);
match interaction { match interaction {
generation::plan::Interaction::Query(_) => { Interaction::Query(_) => {
let conn = match &mut env.connections[connection_index] { let conn = match &mut env.connections[connection_index] {
SimConnection::Connected(conn) => conn, SimConnection::Connected(conn) => conn,
SimConnection::Disconnected => unreachable!(), SimConnection::Disconnected => unreachable!(),
@@ -181,11 +181,11 @@ fn execute_interaction(
log::debug!("{:?}", results); log::debug!("{:?}", results);
stack.push(results); stack.push(results);
} }
generation::plan::Interaction::Assertion(_) => { Interaction::Assertion(_) => {
interaction.execute_assertion(stack, env)?; interaction.execute_assertion(stack, env)?;
stack.clear(); stack.clear();
} }
generation::plan::Interaction::Assumption(_) => { Interaction::Assumption(_) => {
let assumption_result = interaction.execute_assumption(stack, env); let assumption_result = interaction.execute_assumption(stack, env);
stack.clear(); stack.clear();

View File

@@ -55,7 +55,7 @@ impl SimulatorFile {
} }
} }
impl limbo_core::File for SimulatorFile { impl File for SimulatorFile {
fn lock_file(&self, exclusive: bool) -> Result<()> { fn lock_file(&self, exclusive: bool) -> Result<()> {
if *self.fault.borrow() { if *self.fault.borrow() {
return Err(limbo_core::LimboError::InternalError( return Err(limbo_core::LimboError::InternalError(
@@ -88,7 +88,7 @@ impl limbo_core::File for SimulatorFile {
fn pwrite( fn pwrite(
&self, &self,
pos: usize, pos: usize,
buffer: Rc<std::cell::RefCell<limbo_core::Buffer>>, buffer: Rc<RefCell<limbo_core::Buffer>>,
c: Rc<limbo_core::Completion>, c: Rc<limbo_core::Completion>,
) -> Result<()> { ) -> Result<()> {
*self.nr_pwrite_calls.borrow_mut() += 1; *self.nr_pwrite_calls.borrow_mut() += 1;

View File

@@ -78,7 +78,7 @@ impl IO for SimulatorIO {
"Injected fault".into(), "Injected fault".into(),
)); ));
} }
self.inner.run_once().unwrap(); self.inner.run_once()?;
Ok(()) Ok(())
} }

View File

@@ -46,7 +46,7 @@ pub struct sqlite3 {
pub(crate) err_mask: ffi::c_int, pub(crate) err_mask: ffi::c_int,
pub(crate) malloc_failed: bool, pub(crate) malloc_failed: bool,
pub(crate) e_open_state: u8, pub(crate) e_open_state: u8,
pub(crate) p_err: *mut std::ffi::c_void, pub(crate) p_err: *mut ffi::c_void,
} }
impl sqlite3 { impl sqlite3 {
@@ -107,7 +107,7 @@ pub unsafe extern "C" fn sqlite3_open(
if db_out.is_null() { if db_out.is_null() {
return SQLITE_MISUSE; return SQLITE_MISUSE;
} }
let filename = ffi::CStr::from_ptr(filename); let filename = CStr::from_ptr(filename);
let filename = match filename.to_str() { let filename = match filename.to_str() {
Ok(s) => s, Ok(s) => s,
Err(_) => return SQLITE_MISUSE, Err(_) => return SQLITE_MISUSE,
@@ -164,14 +164,9 @@ pub unsafe extern "C" fn sqlite3_trace_v2(
_db: *mut sqlite3, _db: *mut sqlite3,
_mask: ffi::c_uint, _mask: ffi::c_uint,
_callback: Option< _callback: Option<
unsafe extern "C" fn( unsafe extern "C" fn(ffi::c_uint, *mut ffi::c_void, *mut ffi::c_void, *mut ffi::c_void),
ffi::c_uint,
*mut std::ffi::c_void,
*mut std::ffi::c_void,
*mut std::ffi::c_void,
),
>, >,
_context: *mut std::ffi::c_void, _context: *mut ffi::c_void,
) -> ffi::c_int { ) -> ffi::c_int {
stub!(); stub!();
} }
@@ -181,7 +176,7 @@ pub unsafe extern "C" fn sqlite3_progress_handler(
_db: *mut sqlite3, _db: *mut sqlite3,
_n: ffi::c_int, _n: ffi::c_int,
_callback: Option<unsafe extern "C" fn() -> ffi::c_int>, _callback: Option<unsafe extern "C" fn() -> ffi::c_int>,
_context: *mut std::ffi::c_void, _context: *mut ffi::c_void,
) -> ffi::c_int { ) -> ffi::c_int {
stub!(); stub!();
} }
@@ -195,15 +190,13 @@ pub unsafe extern "C" fn sqlite3_busy_timeout(_db: *mut sqlite3, _ms: ffi::c_int
pub unsafe extern "C" fn sqlite3_set_authorizer( pub unsafe extern "C" fn sqlite3_set_authorizer(
_db: *mut sqlite3, _db: *mut sqlite3,
_callback: Option<unsafe extern "C" fn() -> ffi::c_int>, _callback: Option<unsafe extern "C" fn() -> ffi::c_int>,
_context: *mut std::ffi::c_void, _context: *mut ffi::c_void,
) -> ffi::c_int { ) -> ffi::c_int {
stub!(); stub!();
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn sqlite3_context_db_handle( pub unsafe extern "C" fn sqlite3_context_db_handle(_context: *mut ffi::c_void) -> *mut ffi::c_void {
_context: *mut std::ffi::c_void,
) -> *mut std::ffi::c_void {
stub!(); stub!();
} }
@@ -219,7 +212,7 @@ pub unsafe extern "C" fn sqlite3_prepare_v2(
return SQLITE_MISUSE; return SQLITE_MISUSE;
} }
let db: &mut sqlite3 = &mut *db; let db: &mut sqlite3 = &mut *db;
let sql = ffi::CStr::from_ptr(sql); let sql = CStr::from_ptr(sql);
let sql = match sql.to_str() { let sql = match sql.to_str() {
Ok(s) => s, Ok(s) => s,
Err(_) => return SQLITE_MISUSE, Err(_) => return SQLITE_MISUSE,
@@ -242,7 +235,7 @@ pub unsafe extern "C" fn sqlite3_finalize(stmt: *mut sqlite3_stmt) -> ffi::c_int
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn sqlite3_step(stmt: *mut sqlite3_stmt) -> std::ffi::c_int { pub unsafe extern "C" fn sqlite3_step(stmt: *mut sqlite3_stmt) -> ffi::c_int {
let stmt = &mut *stmt; let stmt = &mut *stmt;
if let Ok(result) = stmt.stmt.step() { if let Ok(result) = stmt.stmt.step() {
match result { match result {
@@ -262,10 +255,10 @@ pub unsafe extern "C" fn sqlite3_step(stmt: *mut sqlite3_stmt) -> std::ffi::c_in
type exec_callback = Option< type exec_callback = Option<
unsafe extern "C" fn( unsafe extern "C" fn(
context: *mut std::ffi::c_void, context: *mut ffi::c_void,
n_column: std::ffi::c_int, n_column: ffi::c_int,
argv: *mut *mut std::ffi::c_char, argv: *mut *mut ffi::c_char,
colv: *mut *mut std::ffi::c_char, colv: *mut *mut ffi::c_char,
) -> ffi::c_int, ) -> ffi::c_int,
>; >;
@@ -274,14 +267,14 @@ pub unsafe extern "C" fn sqlite3_exec(
db: *mut sqlite3, db: *mut sqlite3,
sql: *const ffi::c_char, sql: *const ffi::c_char,
_callback: exec_callback, _callback: exec_callback,
_context: *mut std::ffi::c_void, _context: *mut ffi::c_void,
_err: *mut *mut std::ffi::c_char, _err: *mut *mut ffi::c_char,
) -> ffi::c_int { ) -> ffi::c_int {
if db.is_null() || sql.is_null() { if db.is_null() || sql.is_null() {
return SQLITE_MISUSE; return SQLITE_MISUSE;
} }
let db: &mut sqlite3 = &mut *db; let db: &mut sqlite3 = &mut *db;
let sql = ffi::CStr::from_ptr(sql); let sql = CStr::from_ptr(sql);
let sql = match sql.to_str() { let sql = match sql.to_str() {
Ok(s) => s, Ok(s) => s,
Err(_) => return SQLITE_MISUSE, Err(_) => return SQLITE_MISUSE,
@@ -317,8 +310,8 @@ pub unsafe extern "C" fn sqlite3_stmt_busy(_stmt: *mut sqlite3_stmt) -> ffi::c_i
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn sqlite3_serialize( pub unsafe extern "C" fn sqlite3_serialize(
_db: *mut sqlite3, _db: *mut sqlite3,
_schema: *const std::ffi::c_char, _schema: *const ffi::c_char,
_out: *mut *mut std::ffi::c_void, _out: *mut *mut ffi::c_void,
_out_bytes: *mut ffi::c_int, _out_bytes: *mut ffi::c_int,
_flags: ffi::c_uint, _flags: ffi::c_uint,
) -> ffi::c_int { ) -> ffi::c_int {
@@ -328,8 +321,8 @@ pub unsafe extern "C" fn sqlite3_serialize(
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn sqlite3_deserialize( pub unsafe extern "C" fn sqlite3_deserialize(
_db: *mut sqlite3, _db: *mut sqlite3,
_schema: *const std::ffi::c_char, _schema: *const ffi::c_char,
_in_: *const std::ffi::c_void, _in_: *const ffi::c_void,
_in_bytes: ffi::c_int, _in_bytes: ffi::c_int,
_flags: ffi::c_uint, _flags: ffi::c_uint,
) -> ffi::c_int { ) -> ffi::c_int {
@@ -381,12 +374,12 @@ pub unsafe extern "C" fn sqlite3_limit(
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn sqlite3_malloc64(_n: ffi::c_int) -> *mut std::ffi::c_void { pub unsafe extern "C" fn sqlite3_malloc64(_n: ffi::c_int) -> *mut ffi::c_void {
stub!(); stub!();
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn sqlite3_free(_ptr: *mut std::ffi::c_void) { pub unsafe extern "C" fn sqlite3_free(_ptr: *mut ffi::c_void) {
stub!(); stub!();
} }
@@ -404,52 +397,50 @@ pub unsafe extern "C" fn sqlite3_errcode(_db: *mut sqlite3) -> ffi::c_int {
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn sqlite3_errstr(_err: ffi::c_int) -> *const std::ffi::c_char { pub unsafe extern "C" fn sqlite3_errstr(_err: ffi::c_int) -> *const ffi::c_char {
sqlite3_errstr_impl(_err) sqlite3_errstr_impl(_err)
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn sqlite3_user_data( pub unsafe extern "C" fn sqlite3_user_data(_context: *mut ffi::c_void) -> *mut ffi::c_void {
_context: *mut std::ffi::c_void,
) -> *mut std::ffi::c_void {
stub!(); stub!();
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn sqlite3_backup_init( pub unsafe extern "C" fn sqlite3_backup_init(
_dest_db: *mut sqlite3, _dest_db: *mut sqlite3,
_dest_name: *const std::ffi::c_char, _dest_name: *const ffi::c_char,
_source_db: *mut sqlite3, _source_db: *mut sqlite3,
_source_name: *const std::ffi::c_char, _source_name: *const ffi::c_char,
) -> *mut std::ffi::c_void { ) -> *mut ffi::c_void {
stub!(); stub!();
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn sqlite3_backup_step( pub unsafe extern "C" fn sqlite3_backup_step(
_backup: *mut std::ffi::c_void, _backup: *mut ffi::c_void,
_n_pages: ffi::c_int, _n_pages: ffi::c_int,
) -> ffi::c_int { ) -> ffi::c_int {
stub!(); stub!();
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn sqlite3_backup_remaining(_backup: *mut std::ffi::c_void) -> ffi::c_int { pub unsafe extern "C" fn sqlite3_backup_remaining(_backup: *mut ffi::c_void) -> ffi::c_int {
stub!(); stub!();
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn sqlite3_backup_pagecount(_backup: *mut std::ffi::c_void) -> ffi::c_int { pub unsafe extern "C" fn sqlite3_backup_pagecount(_backup: *mut ffi::c_void) -> ffi::c_int {
stub!(); stub!();
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn sqlite3_backup_finish(_backup: *mut std::ffi::c_void) -> ffi::c_int { pub unsafe extern "C" fn sqlite3_backup_finish(_backup: *mut ffi::c_void) -> ffi::c_int {
stub!(); stub!();
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn sqlite3_expanded_sql(_stmt: *mut sqlite3_stmt) -> *mut std::ffi::c_char { pub unsafe extern "C" fn sqlite3_expanded_sql(_stmt: *mut sqlite3_stmt) -> *mut ffi::c_char {
stub!(); stub!();
} }
@@ -473,7 +464,7 @@ pub unsafe extern "C" fn sqlite3_bind_parameter_count(_stmt: *mut sqlite3_stmt)
pub unsafe extern "C" fn sqlite3_bind_parameter_name( pub unsafe extern "C" fn sqlite3_bind_parameter_name(
_stmt: *mut sqlite3_stmt, _stmt: *mut sqlite3_stmt,
_idx: ffi::c_int, _idx: ffi::c_int,
) -> *const std::ffi::c_char { ) -> *const ffi::c_char {
stub!(); stub!();
} }
@@ -507,9 +498,9 @@ pub unsafe extern "C" fn sqlite3_bind_double(
pub unsafe extern "C" fn sqlite3_bind_text( pub unsafe extern "C" fn sqlite3_bind_text(
_stmt: *mut sqlite3_stmt, _stmt: *mut sqlite3_stmt,
_idx: ffi::c_int, _idx: ffi::c_int,
_text: *const std::ffi::c_char, _text: *const ffi::c_char,
_len: ffi::c_int, _len: ffi::c_int,
_destroy: *mut std::ffi::c_void, _destroy: *mut ffi::c_void,
) -> ffi::c_int { ) -> ffi::c_int {
stub!(); stub!();
} }
@@ -518,9 +509,9 @@ pub unsafe extern "C" fn sqlite3_bind_text(
pub unsafe extern "C" fn sqlite3_bind_blob( pub unsafe extern "C" fn sqlite3_bind_blob(
_stmt: *mut sqlite3_stmt, _stmt: *mut sqlite3_stmt,
_idx: ffi::c_int, _idx: ffi::c_int,
_blob: *const std::ffi::c_void, _blob: *const ffi::c_void,
_len: ffi::c_int, _len: ffi::c_int,
_destroy: *mut std::ffi::c_void, _destroy: *mut ffi::c_void,
) -> ffi::c_int { ) -> ffi::c_int {
stub!(); stub!();
} }
@@ -542,7 +533,7 @@ pub unsafe extern "C" fn sqlite3_column_count(_stmt: *mut sqlite3_stmt) -> ffi::
pub unsafe extern "C" fn sqlite3_column_decltype( pub unsafe extern "C" fn sqlite3_column_decltype(
_stmt: *mut sqlite3_stmt, _stmt: *mut sqlite3_stmt,
_idx: ffi::c_int, _idx: ffi::c_int,
) -> *const std::ffi::c_char { ) -> *const ffi::c_char {
stub!(); stub!();
} }
@@ -550,7 +541,7 @@ pub unsafe extern "C" fn sqlite3_column_decltype(
pub unsafe extern "C" fn sqlite3_column_name( pub unsafe extern "C" fn sqlite3_column_name(
_stmt: *mut sqlite3_stmt, _stmt: *mut sqlite3_stmt,
_idx: ffi::c_int, _idx: ffi::c_int,
) -> *const std::ffi::c_char { ) -> *const ffi::c_char {
stub!(); stub!();
} }
@@ -568,7 +559,7 @@ pub unsafe extern "C" fn sqlite3_column_double(_stmt: *mut sqlite3_stmt, _idx: f
pub unsafe extern "C" fn sqlite3_column_blob( pub unsafe extern "C" fn sqlite3_column_blob(
_stmt: *mut sqlite3_stmt, _stmt: *mut sqlite3_stmt,
_idx: ffi::c_int, _idx: ffi::c_int,
) -> *const std::ffi::c_void { ) -> *const ffi::c_void {
stub!(); stub!();
} }
@@ -581,7 +572,7 @@ pub unsafe extern "C" fn sqlite3_column_bytes(
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn sqlite3_value_type(value: *mut std::ffi::c_void) -> ffi::c_int { pub unsafe extern "C" fn sqlite3_value_type(value: *mut ffi::c_void) -> ffi::c_int {
let value = value as *mut limbo_core::Value; let value = value as *mut limbo_core::Value;
let value = &*value; let value = &*value;
match value { match value {
@@ -594,7 +585,7 @@ pub unsafe extern "C" fn sqlite3_value_type(value: *mut std::ffi::c_void) -> ffi
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn sqlite3_value_int64(value: *mut std::ffi::c_void) -> i64 { pub unsafe extern "C" fn sqlite3_value_int64(value: *mut ffi::c_void) -> i64 {
let value = value as *mut limbo_core::Value; let value = value as *mut limbo_core::Value;
let value = &*value; let value = &*value;
match value { match value {
@@ -604,7 +595,7 @@ pub unsafe extern "C" fn sqlite3_value_int64(value: *mut std::ffi::c_void) -> i6
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn sqlite3_value_double(value: *mut std::ffi::c_void) -> f64 { pub unsafe extern "C" fn sqlite3_value_double(value: *mut ffi::c_void) -> f64 {
let value = value as *mut limbo_core::Value; let value = value as *mut limbo_core::Value;
let value = &*value; let value = &*value;
match value { match value {
@@ -614,9 +605,7 @@ pub unsafe extern "C" fn sqlite3_value_double(value: *mut std::ffi::c_void) -> f
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn sqlite3_value_text( pub unsafe extern "C" fn sqlite3_value_text(value: *mut ffi::c_void) -> *const ffi::c_uchar {
value: *mut std::ffi::c_void,
) -> *const std::ffi::c_uchar {
let value = value as *mut limbo_core::Value; let value = value as *mut limbo_core::Value;
let value = &*value; let value = &*value;
match value { match value {
@@ -626,19 +615,17 @@ pub unsafe extern "C" fn sqlite3_value_text(
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn sqlite3_value_blob( pub unsafe extern "C" fn sqlite3_value_blob(value: *mut ffi::c_void) -> *const ffi::c_void {
value: *mut std::ffi::c_void,
) -> *const std::ffi::c_void {
let value = value as *mut limbo_core::Value; let value = value as *mut limbo_core::Value;
let value = &*value; let value = &*value;
match value { match value {
limbo_core::Value::Blob(blob) => blob.as_ptr() as *const std::ffi::c_void, limbo_core::Value::Blob(blob) => blob.as_ptr() as *const ffi::c_void,
_ => std::ptr::null(), _ => std::ptr::null(),
} }
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn sqlite3_value_bytes(value: *mut std::ffi::c_void) -> ffi::c_int { pub unsafe extern "C" fn sqlite3_value_bytes(value: *mut ffi::c_void) -> ffi::c_int {
let value = value as *mut limbo_core::Value; let value = value as *mut limbo_core::Value;
let value = &*value; let value = &*value;
match value { match value {
@@ -650,8 +637,8 @@ pub unsafe extern "C" fn sqlite3_value_bytes(value: *mut std::ffi::c_void) -> ff
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn sqlite3_column_text( pub unsafe extern "C" fn sqlite3_column_text(
stmt: *mut sqlite3_stmt, stmt: *mut sqlite3_stmt,
idx: std::ffi::c_int, idx: ffi::c_int,
) -> *const std::ffi::c_uchar { ) -> *const ffi::c_uchar {
let stmt = &mut *stmt; let stmt = &mut *stmt;
let row = stmt.row.borrow(); let row = stmt.row.borrow();
let row = match row.as_ref() { let row = match row.as_ref() {
@@ -665,11 +652,11 @@ pub unsafe extern "C" fn sqlite3_column_text(
} }
pub struct TabResult { pub struct TabResult {
az_result: Vec<*mut std::ffi::c_char>, az_result: Vec<*mut ffi::c_char>,
n_row: usize, n_row: usize,
n_column: usize, n_column: usize,
z_err_msg: Option<CString>, z_err_msg: Option<CString>,
rc: std::ffi::c_int, rc: ffi::c_int,
} }
impl TabResult { impl TabResult {
@@ -697,11 +684,11 @@ impl TabResult {
#[no_mangle] #[no_mangle]
unsafe extern "C" fn sqlite_get_table_cb( unsafe extern "C" fn sqlite_get_table_cb(
context: *mut std::ffi::c_void, context: *mut ffi::c_void,
n_column: std::ffi::c_int, n_column: ffi::c_int,
argv: *mut *mut std::ffi::c_char, argv: *mut *mut ffi::c_char,
colv: *mut *mut std::ffi::c_char, colv: *mut *mut ffi::c_char,
) -> std::ffi::c_int { ) -> ffi::c_int {
let res = &mut *(context as *mut TabResult); let res = &mut *(context as *mut TabResult);
if res.n_row == 0 { if res.n_row == 0 {
@@ -729,7 +716,7 @@ unsafe extern "C" fn sqlite_get_table_cb(
let value_cstring = if !value.is_null() { let value_cstring = if !value.is_null() {
let len = libc::strlen(value); let len = libc::strlen(value);
let mut buf = Vec::with_capacity(len + 1); let mut buf = Vec::with_capacity(len + 1);
libc::strncpy(buf.as_mut_ptr() as *mut std::ffi::c_char, value, len); libc::strncpy(buf.as_mut_ptr() as *mut ffi::c_char, value, len);
buf.set_len(len + 1); buf.set_len(len + 1);
CString::from_vec_with_nul(buf).unwrap() CString::from_vec_with_nul(buf).unwrap()
} else { } else {
@@ -745,12 +732,12 @@ unsafe extern "C" fn sqlite_get_table_cb(
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn sqlite3_get_table( pub unsafe extern "C" fn sqlite3_get_table(
db: *mut sqlite3, db: *mut sqlite3,
sql: *const std::ffi::c_char, sql: *const ffi::c_char,
paz_result: *mut *mut *mut std::ffi::c_char, paz_result: *mut *mut *mut ffi::c_char,
pn_row: *mut std::ffi::c_int, pn_row: *mut ffi::c_int,
pn_column: *mut std::ffi::c_int, pn_column: *mut ffi::c_int,
pz_err_msg: *mut *mut std::ffi::c_char, pz_err_msg: *mut *mut ffi::c_char,
) -> std::ffi::c_int { ) -> ffi::c_int {
if db.is_null() || sql.is_null() || paz_result.is_null() { if db.is_null() || sql.is_null() || paz_result.is_null() {
return SQLITE_ERROR; return SQLITE_ERROR;
} }
@@ -781,8 +768,8 @@ pub unsafe extern "C" fn sqlite3_get_table(
} }
*paz_result = res.az_result.as_mut_ptr(); *paz_result = res.az_result.as_mut_ptr();
*pn_row = res.n_row as std::ffi::c_int; *pn_row = res.n_row as ffi::c_int;
*pn_column = res.n_column as std::ffi::c_int; *pn_column = res.n_column as ffi::c_int;
std::mem::forget(res); std::mem::forget(res);
@@ -790,60 +777,60 @@ pub unsafe extern "C" fn sqlite3_get_table(
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn sqlite3_free_table(paz_result: *mut *mut *mut std::ffi::c_char) { pub unsafe extern "C" fn sqlite3_free_table(paz_result: *mut *mut *mut ffi::c_char) {
let res = &mut *(paz_result as *mut TabResult); let res = &mut *(paz_result as *mut TabResult);
res.free(); res.free();
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn sqlite3_result_null(_context: *mut std::ffi::c_void) { pub unsafe extern "C" fn sqlite3_result_null(_context: *mut ffi::c_void) {
stub!(); stub!();
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn sqlite3_result_int64(_context: *mut std::ffi::c_void, _val: i64) { pub unsafe extern "C" fn sqlite3_result_int64(_context: *mut ffi::c_void, _val: i64) {
stub!(); stub!();
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn sqlite3_result_double(_context: *mut std::ffi::c_void, _val: f64) { pub unsafe extern "C" fn sqlite3_result_double(_context: *mut ffi::c_void, _val: f64) {
stub!(); stub!();
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn sqlite3_result_text( pub unsafe extern "C" fn sqlite3_result_text(
_context: *mut std::ffi::c_void, _context: *mut ffi::c_void,
_text: *const std::ffi::c_char, _text: *const ffi::c_char,
_len: ffi::c_int, _len: ffi::c_int,
_destroy: *mut std::ffi::c_void, _destroy: *mut ffi::c_void,
) { ) {
stub!(); stub!();
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn sqlite3_result_blob( pub unsafe extern "C" fn sqlite3_result_blob(
_context: *mut std::ffi::c_void, _context: *mut ffi::c_void,
_blob: *const std::ffi::c_void, _blob: *const ffi::c_void,
_len: ffi::c_int, _len: ffi::c_int,
_destroy: *mut std::ffi::c_void, _destroy: *mut ffi::c_void,
) { ) {
stub!(); stub!();
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn sqlite3_result_error_nomem(_context: *mut std::ffi::c_void) { pub unsafe extern "C" fn sqlite3_result_error_nomem(_context: *mut ffi::c_void) {
stub!(); stub!();
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn sqlite3_result_error_toobig(_context: *mut std::ffi::c_void) { pub unsafe extern "C" fn sqlite3_result_error_toobig(_context: *mut ffi::c_void) {
stub!(); stub!();
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn sqlite3_result_error( pub unsafe extern "C" fn sqlite3_result_error(
_context: *mut std::ffi::c_void, _context: *mut ffi::c_void,
_err: *const std::ffi::c_char, _err: *const ffi::c_char,
_len: ffi::c_int, _len: ffi::c_int,
) { ) {
stub!(); stub!();
@@ -851,29 +838,29 @@ pub unsafe extern "C" fn sqlite3_result_error(
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn sqlite3_aggregate_context( pub unsafe extern "C" fn sqlite3_aggregate_context(
_context: *mut std::ffi::c_void, _context: *mut ffi::c_void,
_n: ffi::c_int, _n: ffi::c_int,
) -> *mut std::ffi::c_void { ) -> *mut ffi::c_void {
stub!(); stub!();
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn sqlite3_blob_open( pub unsafe extern "C" fn sqlite3_blob_open(
_db: *mut sqlite3, _db: *mut sqlite3,
_db_name: *const std::ffi::c_char, _db_name: *const ffi::c_char,
_table_name: *const std::ffi::c_char, _table_name: *const ffi::c_char,
_column_name: *const std::ffi::c_char, _column_name: *const ffi::c_char,
_rowid: i64, _rowid: i64,
_flags: ffi::c_int, _flags: ffi::c_int,
_blob_out: *mut *mut std::ffi::c_void, _blob_out: *mut *mut ffi::c_void,
) -> ffi::c_int { ) -> ffi::c_int {
stub!(); stub!();
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn sqlite3_blob_read( pub unsafe extern "C" fn sqlite3_blob_read(
_blob: *mut std::ffi::c_void, _blob: *mut ffi::c_void,
_data: *mut std::ffi::c_void, _data: *mut ffi::c_void,
_n: ffi::c_int, _n: ffi::c_int,
_offset: ffi::c_int, _offset: ffi::c_int,
) -> ffi::c_int { ) -> ffi::c_int {
@@ -882,8 +869,8 @@ pub unsafe extern "C" fn sqlite3_blob_read(
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn sqlite3_blob_write( pub unsafe extern "C" fn sqlite3_blob_write(
_blob: *mut std::ffi::c_void, _blob: *mut ffi::c_void,
_data: *const std::ffi::c_void, _data: *const ffi::c_void,
_n: ffi::c_int, _n: ffi::c_int,
_offset: ffi::c_int, _offset: ffi::c_int,
) -> ffi::c_int { ) -> ffi::c_int {
@@ -891,19 +878,19 @@ pub unsafe extern "C" fn sqlite3_blob_write(
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn sqlite3_blob_bytes(_blob: *mut std::ffi::c_void) -> ffi::c_int { pub unsafe extern "C" fn sqlite3_blob_bytes(_blob: *mut ffi::c_void) -> ffi::c_int {
stub!(); stub!();
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn sqlite3_blob_close(_blob: *mut std::ffi::c_void) -> ffi::c_int { pub unsafe extern "C" fn sqlite3_blob_close(_blob: *mut ffi::c_void) -> ffi::c_int {
stub!(); stub!();
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn sqlite3_stricmp( pub unsafe extern "C" fn sqlite3_stricmp(
_a: *const std::ffi::c_char, _a: *const ffi::c_char,
_b: *const std::ffi::c_char, _b: *const ffi::c_char,
) -> ffi::c_int { ) -> ffi::c_int {
stub!(); stub!();
} }
@@ -911,9 +898,9 @@ pub unsafe extern "C" fn sqlite3_stricmp(
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn sqlite3_create_collation_v2( pub unsafe extern "C" fn sqlite3_create_collation_v2(
_db: *mut sqlite3, _db: *mut sqlite3,
_name: *const std::ffi::c_char, _name: *const ffi::c_char,
_enc: ffi::c_int, _enc: ffi::c_int,
_context: *mut std::ffi::c_void, _context: *mut ffi::c_void,
_cmp: Option<unsafe extern "C" fn() -> ffi::c_int>, _cmp: Option<unsafe extern "C" fn() -> ffi::c_int>,
_destroy: Option<unsafe extern "C" fn()>, _destroy: Option<unsafe extern "C" fn()>,
) -> ffi::c_int { ) -> ffi::c_int {
@@ -923,10 +910,10 @@ pub unsafe extern "C" fn sqlite3_create_collation_v2(
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn sqlite3_create_function_v2( pub unsafe extern "C" fn sqlite3_create_function_v2(
_db: *mut sqlite3, _db: *mut sqlite3,
_name: *const std::ffi::c_char, _name: *const ffi::c_char,
_n_args: ffi::c_int, _n_args: ffi::c_int,
_enc: ffi::c_int, _enc: ffi::c_int,
_context: *mut std::ffi::c_void, _context: *mut ffi::c_void,
_func: Option<unsafe extern "C" fn()>, _func: Option<unsafe extern "C" fn()>,
_step: Option<unsafe extern "C" fn()>, _step: Option<unsafe extern "C" fn()>,
_final_: Option<unsafe extern "C" fn()>, _final_: Option<unsafe extern "C" fn()>,
@@ -938,10 +925,10 @@ pub unsafe extern "C" fn sqlite3_create_function_v2(
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn sqlite3_create_window_function( pub unsafe extern "C" fn sqlite3_create_window_function(
_db: *mut sqlite3, _db: *mut sqlite3,
_name: *const std::ffi::c_char, _name: *const ffi::c_char,
_n_args: ffi::c_int, _n_args: ffi::c_int,
_enc: ffi::c_int, _enc: ffi::c_int,
_context: *mut std::ffi::c_void, _context: *mut ffi::c_void,
_x_step: Option<unsafe extern "C" fn()>, _x_step: Option<unsafe extern "C" fn()>,
_x_final: Option<unsafe extern "C" fn()>, _x_final: Option<unsafe extern "C" fn()>,
_x_value: Option<unsafe extern "C" fn()>, _x_value: Option<unsafe extern "C" fn()>,
@@ -952,7 +939,7 @@ pub unsafe extern "C" fn sqlite3_create_window_function(
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn sqlite3_errmsg(_db: *mut sqlite3) -> *const std::ffi::c_char { pub unsafe extern "C" fn sqlite3_errmsg(_db: *mut sqlite3) -> *const ffi::c_char {
if _db.is_null() { if _db.is_null() {
return sqlite3_errstr(SQLITE_NOMEM); return sqlite3_errstr(SQLITE_NOMEM);
} }
@@ -965,7 +952,7 @@ pub unsafe extern "C" fn sqlite3_errmsg(_db: *mut sqlite3) -> *const std::ffi::c
let err_msg = if (*_db).err_code != SQLITE_OK { let err_msg = if (*_db).err_code != SQLITE_OK {
if !(*_db).p_err.is_null() { if !(*_db).p_err.is_null() {
(*_db).p_err as *const std::ffi::c_char (*_db).p_err as *const ffi::c_char
} else { } else {
std::ptr::null() std::ptr::null()
} }
@@ -994,7 +981,7 @@ pub unsafe extern "C" fn sqlite3_extended_errcode(_db: *mut sqlite3) -> ffi::c_i
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn sqlite3_complete(_sql: *const std::ffi::c_char) -> ffi::c_int { pub unsafe extern "C" fn sqlite3_complete(_sql: *const ffi::c_char) -> ffi::c_int {
stub!(); stub!();
} }
@@ -1004,7 +991,7 @@ pub unsafe extern "C" fn sqlite3_threadsafe() -> ffi::c_int {
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn sqlite3_libversion() -> *const std::ffi::c_char { pub unsafe extern "C" fn sqlite3_libversion() -> *const ffi::c_char {
c"3.42.0".as_ptr() c"3.42.0".as_ptr()
} }
@@ -1013,7 +1000,7 @@ pub unsafe extern "C" fn sqlite3_libversion_number() -> ffi::c_int {
3042000 3042000
} }
fn sqlite3_errstr_impl(rc: i32) -> *const std::ffi::c_char { fn sqlite3_errstr_impl(rc: i32) -> *const ffi::c_char {
const ERROR_MESSAGES: [&str; 29] = [ const ERROR_MESSAGES: [&str; 29] = [
"not an error", // SQLITE_OK "not an error", // SQLITE_OK
"SQL logic error", // SQLITE_ERROR "SQL logic error", // SQLITE_ERROR
@@ -1055,18 +1042,18 @@ fn sqlite3_errstr_impl(rc: i32) -> *const std::ffi::c_char {
const NO_MORE_ROWS_AVAILABLE: &str = "no more rows available"; const NO_MORE_ROWS_AVAILABLE: &str = "no more rows available";
match rc { match rc {
SQLITE_ABORT_ROLLBACK => ABORT_ROLLBACK.as_ptr() as *const std::ffi::c_char, SQLITE_ABORT_ROLLBACK => ABORT_ROLLBACK.as_ptr() as *const ffi::c_char,
SQLITE_ROW => ANOTHER_ROW_AVAILABLE.as_ptr() as *const std::ffi::c_char, SQLITE_ROW => ANOTHER_ROW_AVAILABLE.as_ptr() as *const ffi::c_char,
SQLITE_DONE => NO_MORE_ROWS_AVAILABLE.as_ptr() as *const std::ffi::c_char, SQLITE_DONE => NO_MORE_ROWS_AVAILABLE.as_ptr() as *const ffi::c_char,
_ => { _ => {
let rc = rc & 0xff; let rc = rc & 0xff;
if rc >= 0 if rc >= 0
&& rc < ERROR_MESSAGES.len() as i32 && rc < ERROR_MESSAGES.len() as i32
&& !ERROR_MESSAGES[rc as usize].is_empty() && !ERROR_MESSAGES[rc as usize].is_empty()
{ {
ERROR_MESSAGES[rc as usize].as_ptr() as *const std::ffi::c_char ERROR_MESSAGES[rc as usize].as_ptr() as *const ffi::c_char
} else { } else {
UNKNOWN_ERROR.as_ptr() as *const std::ffi::c_char UNKNOWN_ERROR.as_ptr() as *const ffi::c_char
} }
} }
} }
@@ -1075,7 +1062,7 @@ fn sqlite3_errstr_impl(rc: i32) -> *const std::ffi::c_char {
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn sqlite3_wal_checkpoint( pub unsafe extern "C" fn sqlite3_wal_checkpoint(
_db: *mut sqlite3, _db: *mut sqlite3,
_db_name: *const std::ffi::c_char, _db_name: *const ffi::c_char,
) -> ffi::c_int { ) -> ffi::c_int {
sqlite3_wal_checkpoint_v2( sqlite3_wal_checkpoint_v2(
_db, _db,
@@ -1089,7 +1076,7 @@ pub unsafe extern "C" fn sqlite3_wal_checkpoint(
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn sqlite3_wal_checkpoint_v2( pub unsafe extern "C" fn sqlite3_wal_checkpoint_v2(
db: *mut sqlite3, db: *mut sqlite3,
_db_name: *const std::ffi::c_char, _db_name: *const ffi::c_char,
_mode: ffi::c_int, _mode: ffi::c_int,
_log_size: *mut ffi::c_int, _log_size: *mut ffi::c_int,
_checkpoint_count: *mut ffi::c_int, _checkpoint_count: *mut ffi::c_int,

View File

@@ -332,7 +332,7 @@ mod tests {
for i in 0..iterations { for i in 0..iterations {
let insert_query = format!("INSERT INTO test VALUES ({})", i); let insert_query = format!("INSERT INTO test VALUES ({})", i);
do_flush(&conn, &tmp_db)?; do_flush(&conn, &tmp_db)?;
conn.checkpoint().unwrap(); conn.checkpoint()?;
match conn.query(insert_query) { match conn.query(insert_query) {
Ok(Some(ref mut rows)) => loop { Ok(Some(ref mut rows)) => loop {
match rows.next_row()? { match rows.next_row()? {
@@ -351,7 +351,7 @@ mod tests {
} }
do_flush(&conn, &tmp_db)?; do_flush(&conn, &tmp_db)?;
conn.clear_page_cache().unwrap(); conn.clear_page_cache()?;
let list_query = "SELECT * FROM test LIMIT 1"; let list_query = "SELECT * FROM test LIMIT 1";
let mut current_index = 0; let mut current_index = 0;
match conn.query(list_query) { match conn.query(list_query) {
@@ -391,7 +391,7 @@ mod tests {
// threshold is 1000 by default // threshold is 1000 by default
fn insert(i: usize, conn: &Rc<Connection>, tmp_db: &TempDatabase) -> anyhow::Result<()> { fn insert(i: usize, conn: &Rc<Connection>, tmp_db: &TempDatabase) -> anyhow::Result<()> {
log::debug!("inserting {}", i); debug!("inserting {}", i);
let insert_query = format!("INSERT INTO test VALUES ({})", i); let insert_query = format!("INSERT INTO test VALUES ({})", i);
match conn.query(insert_query) { match conn.query(insert_query) {
Ok(Some(ref mut rows)) => loop { Ok(Some(ref mut rows)) => loop {
@@ -408,16 +408,16 @@ mod tests {
eprintln!("{}", err); eprintln!("{}", err);
} }
}; };
log::debug!("inserted {}", i); debug!("inserted {}", i);
tmp_db.io.run_once()?; tmp_db.io.run_once()?;
Ok(()) Ok(())
} }
fn count(conn: &Rc<Connection>, tmp_db: &TempDatabase) -> anyhow::Result<usize> { fn count(conn: &Rc<Connection>, tmp_db: &TempDatabase) -> anyhow::Result<usize> {
log::debug!("counting"); debug!("counting");
let list_query = "SELECT count(x) FROM test"; let list_query = "SELECT count(x) FROM test";
loop { loop {
if let Some(ref mut rows) = conn.query(list_query).unwrap() { if let Some(ref mut rows) = conn.query(list_query)? {
loop { loop {
match rows.next_row()? { match rows.next_row()? {
StepResult::Row(row) => { StepResult::Row(row) => {
@@ -426,7 +426,7 @@ mod tests {
Value::Integer(i) => *i as i32, Value::Integer(i) => *i as i32,
_ => unreachable!(), _ => unreachable!(),
}; };
log::debug!("counted {}", count); debug!("counted {}", count);
return Ok(count as usize); return Ok(count as usize);
} }
StepResult::IO => { StepResult::IO => {
@@ -443,14 +443,14 @@ mod tests {
{ {
let conn = tmp_db.connect_limbo(); let conn = tmp_db.connect_limbo();
insert(1, &conn, &tmp_db).unwrap(); insert(1, &conn, &tmp_db)?;
assert_eq!(count(&conn, &tmp_db).unwrap(), 1); assert_eq!(count(&conn, &tmp_db)?, 1);
conn.close()?; conn.close()?;
} }
{ {
let conn = tmp_db.connect_limbo(); let conn = tmp_db.connect_limbo();
assert_eq!( assert_eq!(
count(&conn, &tmp_db).unwrap(), count(&conn, &tmp_db)?,
1, 1,
"failed to read from wal from another connection" "failed to read from wal from another connection"
); );
@@ -619,7 +619,7 @@ mod tests {
let mut stmt = conn.prepare("select ?")?; let mut stmt = conn.prepare("select ?")?;
stmt.bind_at(1.try_into().unwrap(), Value::Integer(1)); stmt.bind_at(1.try_into()?, Value::Integer(1));
loop { loop {
match stmt.step()? { match stmt.step()? {
@@ -633,7 +633,7 @@ mod tests {
stmt.reset(); stmt.reset();
stmt.bind_at(1.try_into().unwrap(), Value::Integer(2)); stmt.bind_at(1.try_into()?, Value::Integer(2));
loop { loop {
match stmt.step()? { match stmt.step()? {
@@ -656,14 +656,14 @@ mod tests {
let mut stmt = conn.prepare("select ?, ?1, :named, ?3, ?4")?; let mut stmt = conn.prepare("select ?, ?1, :named, ?3, ?4")?;
stmt.bind_at(1.try_into().unwrap(), Value::Text(&"hello".to_string())); stmt.bind_at(1.try_into()?, Value::Text(&"hello".to_string()));
let i = stmt.parameters().index(":named").unwrap(); let i = stmt.parameters().index(":named").unwrap();
stmt.bind_at(i, Value::Integer(42)); stmt.bind_at(i, Value::Integer(42));
stmt.bind_at(3.try_into().unwrap(), Value::Blob(&vec![0x1, 0x2, 0x3])); stmt.bind_at(3.try_into()?, Value::Blob(&vec![0x1, 0x2, 0x3]));
stmt.bind_at(4.try_into().unwrap(), Value::Float(0.5)); stmt.bind_at(4.try_into()?, Value::Float(0.5));
assert_eq!(stmt.parameters().count(), 4); assert_eq!(stmt.parameters().count(), 4);