rusqlite/
raw_statement.rs1use super::ffi;
2use super::StatementStatus;
3use crate::util::ParamIndexCache;
4use crate::util::SqliteMallocString;
5use std::ffi::{c_int, CStr};
6use std::ptr;
7use std::sync::Arc;
8
9#[derive(Debug)]
11pub struct RawStatement {
12 ptr: *mut ffi::sqlite3_stmt,
13 cache: ParamIndexCache,
15 statement_cache_key: Option<Arc<str>>,
26}
27
28impl RawStatement {
29 #[inline]
30 pub unsafe fn new(stmt: *mut ffi::sqlite3_stmt) -> Self {
31 Self {
32 ptr: stmt,
33 cache: ParamIndexCache::default(),
34 statement_cache_key: None,
35 }
36 }
37
38 #[inline]
39 pub fn is_null(&self) -> bool {
40 self.ptr.is_null()
41 }
42
43 #[inline]
44 pub(crate) fn set_statement_cache_key(&mut self, p: impl Into<Arc<str>>) {
45 self.statement_cache_key = Some(p.into());
46 }
47
48 #[inline]
49 pub(crate) fn statement_cache_key(&self) -> Option<Arc<str>> {
50 self.statement_cache_key.clone()
51 }
52
53 #[inline]
54 pub unsafe fn ptr(&self) -> *mut ffi::sqlite3_stmt {
55 self.ptr
56 }
57
58 #[inline]
59 pub fn column_count(&self) -> usize {
60 unsafe { ffi::sqlite3_column_count(self.ptr) as usize }
62 }
63
64 #[inline]
65 pub fn column_type(&self, idx: usize) -> c_int {
66 unsafe { ffi::sqlite3_column_type(self.ptr, idx as c_int) }
67 }
68
69 #[inline]
70 #[cfg(feature = "column_metadata")]
71 pub fn column_database_name(&self, idx: usize) -> Option<&CStr> {
72 unsafe {
73 let db_name = ffi::sqlite3_column_database_name(self.ptr, idx as c_int);
74 if db_name.is_null() {
75 None
76 } else {
77 Some(CStr::from_ptr(db_name))
78 }
79 }
80 }
81
82 #[inline]
83 #[cfg(feature = "column_metadata")]
84 pub fn column_table_name(&self, idx: usize) -> Option<&CStr> {
85 unsafe {
86 let tbl_name = ffi::sqlite3_column_table_name(self.ptr, idx as c_int);
87 if tbl_name.is_null() {
88 None
89 } else {
90 Some(CStr::from_ptr(tbl_name))
91 }
92 }
93 }
94
95 #[inline]
96 #[cfg(feature = "column_metadata")]
97 pub fn column_origin_name(&self, idx: usize) -> Option<&CStr> {
98 unsafe {
99 let origin_name = ffi::sqlite3_column_origin_name(self.ptr, idx as c_int);
100 if origin_name.is_null() {
101 None
102 } else {
103 Some(CStr::from_ptr(origin_name))
104 }
105 }
106 }
107
108 #[inline]
109 #[cfg(feature = "column_decltype")]
110 pub fn column_decltype(&self, idx: usize) -> Option<&CStr> {
111 unsafe {
112 let decltype = ffi::sqlite3_column_decltype(self.ptr, idx as c_int);
113 if decltype.is_null() {
114 None
115 } else {
116 Some(CStr::from_ptr(decltype))
117 }
118 }
119 }
120
121 #[inline]
122 pub fn column_name(&self, idx: usize) -> Option<&CStr> {
123 let idx = idx as c_int;
124 if idx < 0 || idx >= self.column_count() as c_int {
125 return None;
126 }
127 unsafe {
128 let ptr = ffi::sqlite3_column_name(self.ptr, idx);
129 assert!(
132 !ptr.is_null(),
133 "Null pointer from sqlite3_column_name: Out of memory?"
134 );
135 Some(CStr::from_ptr(ptr))
136 }
137 }
138
139 #[inline]
140 #[cfg(not(feature = "unlock_notify"))]
141 pub fn step(&self) -> c_int {
142 unsafe { ffi::sqlite3_step(self.ptr) }
143 }
144
145 #[cfg(feature = "unlock_notify")]
146 pub fn step(&self) -> c_int {
147 use crate::unlock_notify;
148 let mut db = ptr::null_mut::<ffi::sqlite3>();
149 loop {
150 unsafe {
151 let mut rc = ffi::sqlite3_step(self.ptr);
152 if (rc & 0xff) != ffi::SQLITE_LOCKED {
157 break rc;
158 }
159 if db.is_null() {
160 db = ffi::sqlite3_db_handle(self.ptr);
161 }
162 if !unlock_notify::is_locked(db, rc) {
163 break rc;
164 }
165 rc = unlock_notify::wait_for_unlock_notify(db);
166 if rc != ffi::SQLITE_OK {
167 break rc;
168 }
169 self.reset();
170 }
171 }
172 }
173
174 #[inline]
175 pub fn reset(&self) -> c_int {
176 unsafe { ffi::sqlite3_reset(self.ptr) }
177 }
178
179 #[inline]
180 pub fn bind_parameter_count(&self) -> usize {
181 unsafe { ffi::sqlite3_bind_parameter_count(self.ptr) as usize }
182 }
183
184 #[inline]
185 pub fn bind_parameter_index(&self, name: &str) -> Option<usize> {
186 self.cache.get_or_insert_with(name, |param_cstr| {
187 let r = unsafe { ffi::sqlite3_bind_parameter_index(self.ptr, param_cstr.as_ptr()) };
188 match r {
189 0 => None,
190 i => Some(i as usize),
191 }
192 })
193 }
194
195 #[inline]
196 pub fn bind_parameter_name(&self, index: i32) -> Option<&CStr> {
197 unsafe {
198 let name = ffi::sqlite3_bind_parameter_name(self.ptr, index);
199 if name.is_null() {
200 None
201 } else {
202 Some(CStr::from_ptr(name))
203 }
204 }
205 }
206
207 #[inline]
208 pub fn clear_bindings(&mut self) {
209 unsafe {
210 ffi::sqlite3_clear_bindings(self.ptr);
211 } }
213
214 #[inline]
215 pub fn sql(&self) -> Option<&CStr> {
216 if self.ptr.is_null() {
217 None
218 } else {
219 Some(unsafe { CStr::from_ptr(ffi::sqlite3_sql(self.ptr)) })
220 }
221 }
222
223 #[inline]
224 pub fn finalize(mut self) -> c_int {
225 self.finalize_()
226 }
227
228 #[inline]
229 fn finalize_(&mut self) -> c_int {
230 let r = unsafe { ffi::sqlite3_finalize(self.ptr) };
231 self.ptr = ptr::null_mut();
232 r
233 }
234
235 #[inline]
237 pub fn readonly(&self) -> bool {
238 unsafe { ffi::sqlite3_stmt_readonly(self.ptr) != 0 }
239 }
240
241 #[inline]
242 pub(crate) fn expanded_sql(&self) -> Option<SqliteMallocString> {
243 unsafe { expanded_sql(self.ptr) }
244 }
245
246 #[inline]
247 pub fn get_status(&self, status: StatementStatus, reset: bool) -> i32 {
248 unsafe { stmt_status(self.ptr, status, reset) }
249 }
250
251 #[inline]
252 #[cfg(feature = "modern_sqlite")] pub fn is_explain(&self) -> i32 {
254 unsafe { ffi::sqlite3_stmt_isexplain(self.ptr) }
255 }
256
257 }
259
260#[inline]
261pub(crate) unsafe fn expanded_sql(ptr: *mut ffi::sqlite3_stmt) -> Option<SqliteMallocString> {
262 SqliteMallocString::from_raw(ffi::sqlite3_expanded_sql(ptr))
263}
264#[inline]
265pub(crate) unsafe fn stmt_status(
266 ptr: *mut ffi::sqlite3_stmt,
267 status: StatementStatus,
268 reset: bool,
269) -> i32 {
270 assert!(!ptr.is_null());
271 ffi::sqlite3_stmt_status(ptr, status as i32, reset as i32)
272}
273
274impl Drop for RawStatement {
275 fn drop(&mut self) {
276 self.finalize_();
277 }
278}