rusqlite/
raw_statement.rs1use super::ffi;
2use super::unlock_notify;
3#[cfg(not(any(
4 feature = "loadable_extension",
5 feature = "loadable_extension_embedded"
6)))]
7use super::StatementStatus;
8#[cfg(feature = "modern_sqlite")]
9use crate::util::SqliteMallocString;
10use std::ffi::CStr;
11use std::os::raw::c_int;
12use std::ptr;
13use std::sync::Arc;
14
15#[derive(Debug)]
17pub struct RawStatement {
18 ptr: *mut ffi::sqlite3_stmt,
19 tail: usize,
20 cache: crate::util::ParamIndexCache,
22 statement_cache_key: Option<Arc<str>>,
33}
34
35impl RawStatement {
36 #[inline]
37 pub unsafe fn new(stmt: *mut ffi::sqlite3_stmt, tail: usize) -> RawStatement {
38 RawStatement {
39 ptr: stmt,
40 tail,
41 cache: Default::default(),
42 statement_cache_key: None,
43 }
44 }
45
46 #[inline]
47 pub fn is_null(&self) -> bool {
48 self.ptr.is_null()
49 }
50
51 #[inline]
52 pub(crate) fn set_statement_cache_key(&mut self, p: impl Into<Arc<str>>) {
53 self.statement_cache_key = Some(p.into());
54 }
55
56 #[inline]
57 pub(crate) fn statement_cache_key(&self) -> Option<Arc<str>> {
58 self.statement_cache_key.clone()
59 }
60
61 #[inline]
62 pub unsafe fn ptr(&self) -> *mut ffi::sqlite3_stmt {
63 self.ptr
64 }
65
66 #[inline]
67 pub fn column_count(&self) -> usize {
68 unsafe { ffi::sqlite3_column_count(self.ptr) as usize }
70 }
71
72 #[inline]
73 pub fn column_type(&self, idx: usize) -> c_int {
74 unsafe { ffi::sqlite3_column_type(self.ptr, idx as c_int) }
75 }
76
77 #[inline]
78 #[cfg(feature = "column_decltype")]
79 pub fn column_decltype(&self, idx: usize) -> Option<&CStr> {
80 unsafe {
81 let decltype = ffi::sqlite3_column_decltype(self.ptr, idx as c_int);
82 if decltype.is_null() {
83 None
84 } else {
85 Some(CStr::from_ptr(decltype))
86 }
87 }
88 }
89
90 #[inline]
91 pub fn column_name(&self, idx: usize) -> Option<&CStr> {
92 let idx = idx as c_int;
93 if idx < 0 || idx >= self.column_count() as c_int {
94 return None;
95 }
96 unsafe {
97 let ptr = ffi::sqlite3_column_name(self.ptr, idx);
98 assert!(
101 !ptr.is_null(),
102 "Null pointer from sqlite3_column_name: Out of memory?"
103 );
104 Some(CStr::from_ptr(ptr))
105 }
106 }
107
108 #[cfg_attr(not(feature = "unlock_notify"), inline)]
109 pub fn step(&self) -> c_int {
110 if cfg!(feature = "unlock_notify") {
111 let db = unsafe { ffi::sqlite3_db_handle(self.ptr) };
112 let mut rc;
113 loop {
114 rc = unsafe { ffi::sqlite3_step(self.ptr) };
115 if unsafe { !unlock_notify::is_locked(db, rc) } {
116 break;
117 }
118 rc = unsafe { unlock_notify::wait_for_unlock_notify(db) };
119 if rc != ffi::SQLITE_OK {
120 break;
121 }
122 self.reset();
123 }
124 rc
125 } else {
126 unsafe { ffi::sqlite3_step(self.ptr) }
127 }
128 }
129
130 #[inline]
131 pub fn reset(&self) -> c_int {
132 unsafe { ffi::sqlite3_reset(self.ptr) }
133 }
134
135 #[inline]
136 pub fn bind_parameter_count(&self) -> usize {
137 unsafe { ffi::sqlite3_bind_parameter_count(self.ptr) as usize }
138 }
139
140 #[inline]
141 pub fn bind_parameter_index(&self, name: &str) -> Option<usize> {
142 self.cache.get_or_insert_with(name, |param_cstr| {
143 let r = unsafe { ffi::sqlite3_bind_parameter_index(self.ptr, param_cstr.as_ptr()) };
144 match r {
145 0 => None,
146 i => Some(i as usize),
147 }
148 })
149 }
150
151 #[inline]
152 pub fn clear_bindings(&self) -> c_int {
153 unsafe { ffi::sqlite3_clear_bindings(self.ptr) }
154 }
155
156 #[inline]
157 pub fn sql(&self) -> Option<&CStr> {
158 if self.ptr.is_null() {
159 None
160 } else {
161 Some(unsafe { CStr::from_ptr(ffi::sqlite3_sql(self.ptr)) })
162 }
163 }
164
165 #[inline]
166 pub fn finalize(mut self) -> c_int {
167 self.finalize_()
168 }
169
170 #[inline]
171 fn finalize_(&mut self) -> c_int {
172 let r = unsafe { ffi::sqlite3_finalize(self.ptr) };
173 self.ptr = ptr::null_mut();
174 r
175 }
176
177 #[inline]
178 #[cfg(all(feature = "extra_check", feature = "modern_sqlite"))] pub fn readonly(&self) -> bool {
180 unsafe { ffi::sqlite3_stmt_readonly(self.ptr) != 0 }
181 }
182
183 #[inline]
184 #[cfg(feature = "modern_sqlite")] pub(crate) fn expanded_sql(&self) -> Option<SqliteMallocString> {
186 unsafe { SqliteMallocString::from_raw(ffi::sqlite3_expanded_sql(self.ptr)) }
187 }
188
189 #[cfg(not(any(
190 feature = "loadable_extension",
191 feature = "loadable_extension_embedded"
192 )))]
193 #[inline]
194 pub fn get_status(&self, status: StatementStatus, reset: bool) -> i32 {
195 assert!(!self.ptr.is_null());
196 unsafe { ffi::sqlite3_stmt_status(self.ptr, status as i32, reset as i32) }
197 }
198
199 #[inline]
200 #[cfg(feature = "extra_check")]
201 pub fn has_tail(&self) -> bool {
202 self.tail != 0
203 }
204
205 #[inline]
206 pub fn tail(&self) -> usize {
207 self.tail
208 }
209}
210
211impl Drop for RawStatement {
212 fn drop(&mut self) {
213 self.finalize_();
214 }
215}