From c428ff06b2d9b5d808115f9e66fe2b31da875164 Mon Sep 17 00:00:00 2001 From: Pekka Enberg Date: Sun, 24 Aug 2025 20:10:31 +0300 Subject: [PATCH] sqlite3: Implement sqlite3_bind_parameter_index() --- core/lib.rs | 4 ++++ sqlite3/include/sqlite3.h | 2 ++ sqlite3/src/lib.rs | 22 +++++++++++++++++++++ sqlite3/tests/compat/mod.rs | 39 +++++++++++++++++++++++++++++++++++++ 4 files changed, 67 insertions(+) diff --git a/core/lib.rs b/core/lib.rs index 843c40bc3..e8e629887 100644 --- a/core/lib.rs +++ b/core/lib.rs @@ -2166,6 +2166,10 @@ impl Statement { self.program.parameters.count() } + pub fn parameter_index(&self, name: &str) -> Option> { + self.program.parameters.index(name) + } + pub fn bind_at(&mut self, index: NonZero, value: Value) { self.state.bind_at(index, value); } diff --git a/sqlite3/include/sqlite3.h b/sqlite3/include/sqlite3.h index 21695d4f1..68a8944e5 100644 --- a/sqlite3/include/sqlite3.h +++ b/sqlite3/include/sqlite3.h @@ -153,6 +153,8 @@ int sqlite3_bind_parameter_count(sqlite3_stmt *_stmt); const char *sqlite3_bind_parameter_name(sqlite3_stmt *_stmt, int _idx); +int sqlite3_bind_parameter_index(sqlite3_stmt *_stmt, const char *_name); + int sqlite3_bind_null(sqlite3_stmt *_stmt, int _idx); int sqlite3_bind_int64(sqlite3_stmt *_stmt, int _idx, int64_t _val); diff --git a/sqlite3/src/lib.rs b/sqlite3/src/lib.rs index 89facaec3..b7bd6529a 100644 --- a/sqlite3/src/lib.rs +++ b/sqlite3/src/lib.rs @@ -538,6 +538,28 @@ pub unsafe extern "C" fn sqlite3_bind_parameter_name( } } +#[no_mangle] +pub unsafe extern "C" fn sqlite3_bind_parameter_index( + stmt: *mut sqlite3_stmt, + name: *const ffi::c_char, +) -> ffi::c_int { + if stmt.is_null() || name.is_null() { + return 0; + } + + let stmt = &*stmt; + let name_str = match CStr::from_ptr(name).to_str() { + Ok(s) => s, + Err(_) => return 0, + }; + + if let Some(index) = stmt.stmt.parameter_index(name_str) { + index.get() as ffi::c_int + } else { + 0 + } +} + #[no_mangle] pub unsafe extern "C" fn sqlite3_bind_null(stmt: *mut sqlite3_stmt, idx: ffi::c_int) -> ffi::c_int { if stmt.is_null() { diff --git a/sqlite3/tests/compat/mod.rs b/sqlite3/tests/compat/mod.rs index c1a92f7a8..a40ae7538 100644 --- a/sqlite3/tests/compat/mod.rs +++ b/sqlite3/tests/compat/mod.rs @@ -50,6 +50,7 @@ extern "C" { fn sqlite3_bind_int(stmt: *mut sqlite3_stmt, idx: i32, val: i64) -> i32; fn sqlite3_bind_parameter_count(stmt: *mut sqlite3_stmt) -> i32; fn sqlite3_bind_parameter_name(stmt: *mut sqlite3_stmt, idx: i32) -> *const libc::c_char; + fn sqlite3_bind_parameter_index(stmt: *mut sqlite3_stmt, name: *const libc::c_char) -> i32; fn sqlite3_clear_bindings(stmt: *mut sqlite3_stmt) -> i32; fn sqlite3_column_name(stmt: *mut sqlite3_stmt, idx: i32) -> *const libc::c_char; fn sqlite3_last_insert_rowid(db: *mut sqlite3) -> i32; @@ -1240,4 +1241,42 @@ mod tests { assert_eq!(sqlite3_close(db), SQLITE_OK); } } + + #[test] + fn test_sqlite3_bind_parameter_index() { + const SQLITE_OK: i32 = 0; + + unsafe { + let mut db: *mut sqlite3 = ptr::null_mut(); + let mut stmt: *mut sqlite3_stmt = ptr::null_mut(); + + assert_eq!(sqlite3_open(c":memory:".as_ptr(), &mut db), SQLITE_OK); + + assert_eq!( + sqlite3_prepare_v2( + db, + c"SELECT * FROM sqlite_master WHERE name = :table_name AND type = :object_type" + .as_ptr(), + -1, + &mut stmt, + ptr::null_mut() + ), + SQLITE_OK + ); + + let index1 = sqlite3_bind_parameter_index(stmt, c":table_name".as_ptr()); + assert_eq!(index1, 1); + + let index2 = sqlite3_bind_parameter_index(stmt, c":object_type".as_ptr()); + assert_eq!(index2, 2); + + let index3 = sqlite3_bind_parameter_index(stmt, c":nonexistent".as_ptr()); + assert_eq!(index3, 0); + + let index4 = sqlite3_bind_parameter_index(stmt, ptr::null()); + assert_eq!(index4, 0); + + assert_eq!(sqlite3_finalize(stmt), SQLITE_OK); + } + } }