From d80834bfe54b17ad61c4dea83bb94deb0f840d58 Mon Sep 17 00:00:00 2001 From: gwenn Date: Sat, 7 Dec 2024 13:06:17 +0100 Subject: [PATCH] Check limit See https://sqlite.org/forum/forumpost/0ea7672a43 --- src/limits.rs | 85 +++++++++++++++++++++++++++++++++------------------ 1 file changed, 56 insertions(+), 29 deletions(-) diff --git a/src/limits.rs b/src/limits.rs index 2587b5c..5107f57 100644 --- a/src/limits.rs +++ b/src/limits.rs @@ -1,6 +1,6 @@ //! Run-Time Limits -use crate::{ffi, Connection}; +use crate::{ffi, Connection, Error, Result}; use std::os::raw::c_int; /// Run-Time limit categories, for use with [`Connection::limit`] and @@ -44,24 +44,47 @@ pub enum Limit { /// The maximum number of auxiliary worker threads that a single prepared /// statement may start. SQLITE_LIMIT_WORKER_THREADS = ffi::SQLITE_LIMIT_WORKER_THREADS, + /// Only used for testing + #[cfg(test)] + INVALID = -1, } impl Connection { /// Returns the current value of a [`Limit`]. #[inline] #[cfg_attr(docsrs, doc(cfg(feature = "limits")))] - pub fn limit(&self, limit: Limit) -> i32 { + pub fn limit(&self, limit: Limit) -> Result { let c = self.db.borrow(); - unsafe { ffi::sqlite3_limit(c.db(), limit as c_int, -1) } + let rc = unsafe { ffi::sqlite3_limit(c.db(), limit as c_int, -1) }; + if rc < 0 { + return Err(Error::SqliteFailure( + ffi::Error::new(ffi::SQLITE_RANGE), + Some(format!("{limit:?} is invalid")), + )); + } + Ok(rc) } /// Changes the [`Limit`] to `new_val`, returning the prior /// value of the limit. #[inline] #[cfg_attr(docsrs, doc(cfg(feature = "limits")))] - pub fn set_limit(&self, limit: Limit, new_val: i32) -> i32 { + pub fn set_limit(&self, limit: Limit, new_val: i32) -> Result { + if new_val < 0 { + return Err(Error::SqliteFailure( + ffi::Error::new(ffi::SQLITE_RANGE), + Some(format!("{new_val} is invalid")), + )); + } let c = self.db.borrow_mut(); - unsafe { ffi::sqlite3_limit(c.db(), limit as c_int, new_val) } + let rc = unsafe { ffi::sqlite3_limit(c.db(), limit as c_int, new_val) }; + if rc < 0 { + return Err(Error::SqliteFailure( + ffi::Error::new(ffi::SQLITE_RANGE), + Some(format!("{limit:?} is invalid")), + )); + } + Ok(rc) } } @@ -106,12 +129,10 @@ mod test { Limit::SQLITE_LIMIT_VARIABLE_NUMBER as i32, ffi::SQLITE_LIMIT_VARIABLE_NUMBER, ); - #[cfg(feature = "bundled")] assert_eq!( Limit::SQLITE_LIMIT_TRIGGER_DEPTH as i32, ffi::SQLITE_LIMIT_TRIGGER_DEPTH, ); - #[cfg(feature = "bundled")] assert_eq!( Limit::SQLITE_LIMIT_WORKER_THREADS as i32, ffi::SQLITE_LIMIT_WORKER_THREADS, @@ -121,38 +142,44 @@ mod test { #[test] fn test_limit() -> Result<()> { let db = Connection::open_in_memory()?; - db.set_limit(Limit::SQLITE_LIMIT_LENGTH, 1024); - assert_eq!(1024, db.limit(Limit::SQLITE_LIMIT_LENGTH)); + db.set_limit(Limit::SQLITE_LIMIT_LENGTH, 1024)?; + assert_eq!(1024, db.limit(Limit::SQLITE_LIMIT_LENGTH)?); - db.set_limit(Limit::SQLITE_LIMIT_SQL_LENGTH, 1024); - assert_eq!(1024, db.limit(Limit::SQLITE_LIMIT_SQL_LENGTH)); + db.set_limit(Limit::SQLITE_LIMIT_SQL_LENGTH, 1024)?; + assert_eq!(1024, db.limit(Limit::SQLITE_LIMIT_SQL_LENGTH)?); - db.set_limit(Limit::SQLITE_LIMIT_COLUMN, 64); - assert_eq!(64, db.limit(Limit::SQLITE_LIMIT_COLUMN)); + db.set_limit(Limit::SQLITE_LIMIT_COLUMN, 64)?; + assert_eq!(64, db.limit(Limit::SQLITE_LIMIT_COLUMN)?); - db.set_limit(Limit::SQLITE_LIMIT_EXPR_DEPTH, 256); - assert_eq!(256, db.limit(Limit::SQLITE_LIMIT_EXPR_DEPTH)); + db.set_limit(Limit::SQLITE_LIMIT_EXPR_DEPTH, 256)?; + assert_eq!(256, db.limit(Limit::SQLITE_LIMIT_EXPR_DEPTH)?); - db.set_limit(Limit::SQLITE_LIMIT_COMPOUND_SELECT, 32); - assert_eq!(32, db.limit(Limit::SQLITE_LIMIT_COMPOUND_SELECT)); + db.set_limit(Limit::SQLITE_LIMIT_COMPOUND_SELECT, 32)?; + assert_eq!(32, db.limit(Limit::SQLITE_LIMIT_COMPOUND_SELECT)?); - db.set_limit(Limit::SQLITE_LIMIT_FUNCTION_ARG, 32); - assert_eq!(32, db.limit(Limit::SQLITE_LIMIT_FUNCTION_ARG)); + db.set_limit(Limit::SQLITE_LIMIT_FUNCTION_ARG, 32)?; + assert_eq!(32, db.limit(Limit::SQLITE_LIMIT_FUNCTION_ARG)?); - db.set_limit(Limit::SQLITE_LIMIT_ATTACHED, 2); - assert_eq!(2, db.limit(Limit::SQLITE_LIMIT_ATTACHED)); + db.set_limit(Limit::SQLITE_LIMIT_ATTACHED, 2)?; + assert_eq!(2, db.limit(Limit::SQLITE_LIMIT_ATTACHED)?); - db.set_limit(Limit::SQLITE_LIMIT_LIKE_PATTERN_LENGTH, 128); - assert_eq!(128, db.limit(Limit::SQLITE_LIMIT_LIKE_PATTERN_LENGTH)); + db.set_limit(Limit::SQLITE_LIMIT_LIKE_PATTERN_LENGTH, 128)?; + assert_eq!(128, db.limit(Limit::SQLITE_LIMIT_LIKE_PATTERN_LENGTH)?); - db.set_limit(Limit::SQLITE_LIMIT_VARIABLE_NUMBER, 99); - assert_eq!(99, db.limit(Limit::SQLITE_LIMIT_VARIABLE_NUMBER)); + db.set_limit(Limit::SQLITE_LIMIT_VARIABLE_NUMBER, 99)?; + assert_eq!(99, db.limit(Limit::SQLITE_LIMIT_VARIABLE_NUMBER)?); - db.set_limit(Limit::SQLITE_LIMIT_TRIGGER_DEPTH, 32); - assert_eq!(32, db.limit(Limit::SQLITE_LIMIT_TRIGGER_DEPTH)); + db.set_limit(Limit::SQLITE_LIMIT_TRIGGER_DEPTH, 32)?; + assert_eq!(32, db.limit(Limit::SQLITE_LIMIT_TRIGGER_DEPTH)?); - db.set_limit(Limit::SQLITE_LIMIT_WORKER_THREADS, 2); - assert_eq!(2, db.limit(Limit::SQLITE_LIMIT_WORKER_THREADS)); + db.set_limit(Limit::SQLITE_LIMIT_WORKER_THREADS, 2)?; + assert_eq!(2, db.limit(Limit::SQLITE_LIMIT_WORKER_THREADS)?); + + assert!(db + .set_limit(Limit::SQLITE_LIMIT_WORKER_THREADS, -1) + .is_err()); + assert!(db.set_limit(Limit::INVALID, 0).is_err()); + assert!(db.limit(Limit::INVALID).is_err()); Ok(()) } }