1use super::{ffi, iterator::*, sqlite3_match_version, types::*, value::*, Connection};
6pub use params::*;
7use std::{
8 convert::{AsMut, AsRef},
9 ffi::{CStr, CString},
10 mem::MaybeUninit,
11 num::NonZeroI32,
12 ops::{Index, IndexMut},
13 slice, str,
14};
15
16mod params;
17mod test;
18
19#[derive(Debug, Copy, Clone, Eq, PartialEq)]
20enum QueryState {
21 Ready,
22 Active,
23 Finished,
24}
25
26pub struct Statement {
78 base: *mut ffi::sqlite3_stmt,
79 state: QueryState,
80 columns: Box<[Column]>,
84}
85
86impl Connection {
87 pub fn prepare_first<'a>(&self, sql: &'a str) -> Result<(Option<Statement>, &'a str)> {
91 const FLAGS: u32 = 0;
92 let guard = self.lock();
93 let mut ret = MaybeUninit::uninit();
94 let mut rest = MaybeUninit::uninit();
95 Error::from_sqlite_desc(
96 unsafe {
97 sqlite3_match_version! {
98 3_020_000 => ffi::sqlite3_prepare_v3(
99 self.as_mut_ptr(),
100 sql.as_ptr() as _,
101 sql.len() as _,
102 FLAGS,
103 ret.as_mut_ptr(),
104 rest.as_mut_ptr(),
105 ),
106 _ => ffi::sqlite3_prepare_v2(
107 self.as_mut_ptr(),
108 sql.as_ptr() as _,
109 sql.len() as _,
110 ret.as_mut_ptr(),
111 rest.as_mut_ptr(),
112 ),
113 }
114 },
115 guard,
116 )?;
117
118 let stmt = unsafe { ret.assume_init() };
119 let stmt = if stmt.is_null() {
120 None
121 } else {
122 let len = unsafe { ffi::sqlite3_column_count(stmt) as usize };
123 let columns = (0..len).map(|i| Column::new(stmt, i)).collect();
124 Some(Statement {
125 base: stmt,
126 state: QueryState::Ready,
127 columns,
128 })
129 };
130
131 let rest = unsafe { rest.assume_init() };
132 let offset = rest as usize - sql.as_ptr() as usize;
133 let rest = unsafe { sql.get_unchecked(offset..) };
134 Ok((stmt, rest))
135 }
136
137 pub fn prepare(&self, sql: &str) -> Result<Statement> {
140 self.prepare_first(sql)?.0.ok_or(SQLITE_MISUSE)
141 }
142
143 pub fn query<P>(&self, sql: &str, params: P) -> Result<Statement>
146 where
147 P: Params,
148 {
149 let mut stmt = self.prepare(sql)?;
150 stmt.query(params)?;
151 Ok(stmt)
152 }
153
154 pub fn query_row<P, R, F>(&self, sql: &str, params: P, f: F) -> Result<R>
157 where
158 P: Params,
159 F: FnOnce(&mut QueryResult) -> Result<R>,
160 {
161 self.prepare(sql)?.query_row(params, f)
162 }
163
164 pub fn execute<P: Params>(&self, sql: &str, params: P) -> Result<i64> {
166 self.prepare(sql)?.execute(params)
167 }
168
169 pub fn insert<P: Params>(&self, sql: &str, params: P) -> Result<i64> {
171 self.prepare(sql)?.insert(params)
172 }
173}
174
175impl Statement {
176 pub unsafe fn as_ptr(&self) -> *mut ffi::sqlite3_stmt {
183 self.base
184 }
185
186 pub fn query<P: Params>(&mut self, params: P) -> Result<&mut Self> {
192 if self.state != QueryState::Ready {
193 self.reset()?;
194 }
195 params.bind_params(self)?;
196 Ok(self)
197 }
198
199 pub fn query_row<P, R, F>(&mut self, params: P, f: F) -> Result<R>
207 where
208 P: Params,
209 F: FnOnce(&mut QueryResult) -> Result<R>,
210 {
211 let res = self.query(params)?.next().map(|o| o.map(|row| f(row)));
212 let reset_res = self.reset();
215 match res {
216 Ok(None) => Err(SQLITE_EMPTY),
217 Ok(Some(r)) => {
218 reset_res?;
219 r
220 }
221 Err(e) => Err(e),
222 }
223 }
224
225 pub fn execute<P: Params>(&mut self, params: P) -> Result<i64> {
234 let db = unsafe { self.db() }.lock();
235
236 let res = self.query(params)?.next().map(|r| r.is_some());
237 let reset_res = self.reset();
240 match res {
241 Ok(false) => {
242 reset_res?;
243 Ok(unsafe {
244 sqlite3_match_version! {
245 3_037_000 => ffi::sqlite3_changes64(db.as_mut_ptr()),
246 _ => ffi::sqlite3_changes(db.as_mut_ptr()) as _,
247 }
248 })
249 }
250 Ok(true) => Err(SQLITE_MISUSE), Err(e) => Err(e),
252 }
253 }
254
255 pub fn insert<P: Params>(&mut self, params: P) -> Result<i64> {
261 let db = unsafe { self.db() }.lock();
262 let res = self.query(params)?.next().map(|r| r.is_some());
263 let reset_res = self.reset();
266 match res {
267 Ok(false) => {
268 reset_res?;
269 Ok(unsafe { ffi::sqlite3_last_insert_rowid(db.as_mut_ptr()) })
270 }
271 Ok(true) => Err(SQLITE_MISUSE), Err(e) => Err(e),
273 }
274 }
275
276 pub fn sql(&self) -> Result<&str> {
278 unsafe {
279 let ret = ffi::sqlite3_sql(self.base);
280 Ok(CStr::from_ptr(ret).to_str()?)
281 }
282 }
283
284 pub fn parameter_count(&self) -> i32 {
287 unsafe { ffi::sqlite3_bind_parameter_count(self.base) }
288 }
289
290 pub fn parameter_name(&self, position: i32) -> Option<&str> {
293 unsafe {
294 let ptr = ffi::sqlite3_bind_parameter_name(self.base, position);
295 match ptr.is_null() {
296 true => None,
297 false => Some(str::from_utf8_unchecked(CStr::from_ptr(ptr).to_bytes())),
300 }
301 }
302 }
303
304 pub fn parameter_position(&self, name: impl Into<Vec<u8>>) -> Option<NonZeroI32> {
306 CString::new(name).ok().and_then(|name| {
307 NonZeroI32::new(unsafe { ffi::sqlite3_bind_parameter_index(self.base, name.as_ptr()) })
308 })
309 }
310
311 pub fn column_count(&self) -> usize {
313 unsafe { ffi::sqlite3_column_count(self.base) as _ }
314 }
315
316 pub fn current_result(&self) -> Option<&QueryResult> {
320 match self.state {
321 QueryState::Active => Some(QueryResult::from_statement(self)),
322 _ => None,
323 }
324 }
325
326 pub fn current_result_mut(&mut self) -> Option<&mut QueryResult> {
328 match self.state {
329 QueryState::Active => Some(QueryResult::from_statement_mut(self)),
330 _ => None,
331 }
332 }
333
334 pub unsafe fn db<'a>(&self) -> &'a Connection {
342 Connection::from_ptr(ffi::sqlite3_db_handle(self.base))
343 }
344
345 fn reset(&mut self) -> Result<()> {
346 unsafe {
347 ffi::sqlite3_reset(self.base);
348 Error::from_sqlite(ffi::sqlite3_clear_bindings(self.base))?;
349 }
350 self.state = QueryState::Ready;
351 Ok(())
352 }
353}
354
355impl FallibleIteratorMut for Statement {
356 type Item = QueryResult;
357 type Error = Error;
358
359 fn next(&mut self) -> Result<Option<&mut Self::Item>> {
360 match self.state {
361 QueryState::Ready | QueryState::Active => unsafe {
362 let guard = self.db().lock();
363 let rc = ffi::sqlite3_step(self.base);
364 Error::from_sqlite_desc(rc, guard)?;
365 match rc {
366 ffi::SQLITE_DONE => {
367 self.state = QueryState::Finished;
368 Ok(None)
369 }
370 ffi::SQLITE_ROW => {
371 self.state = QueryState::Active;
372 Ok(Some(QueryResult::from_statement_mut(self)))
373 }
374 _ => unreachable!(),
375 }
376 },
377 QueryState::Finished => Ok(None),
378 }
379 }
380}
381
382impl std::fmt::Debug for Statement {
383 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
384 f.debug_struct("Statement")
385 .field("state", &self.state)
386 .finish_non_exhaustive()
387 }
388}
389
390impl Drop for Statement {
391 fn drop(&mut self) {
392 unsafe { ffi::sqlite3_finalize(self.base) };
393 }
394}
395
396#[repr(transparent)]
398pub struct QueryResult {
399 stmt: Statement,
400}
401
402impl QueryResult {
403 fn from_statement(stmt: &Statement) -> &Self {
404 unsafe { &*(stmt as *const Statement as *const Self) }
405 }
406
407 fn from_statement_mut(stmt: &mut Statement) -> &mut Self {
408 unsafe { &mut *(stmt as *mut Statement as *mut Self) }
409 }
410
411 pub fn len(&self) -> usize {
413 self.stmt.column_count()
414 }
415}
416
417impl Index<usize> for QueryResult {
418 type Output = Column;
419
420 fn index(&self, index: usize) -> &Self::Output {
421 &self.stmt.columns[index]
422 }
423}
424
425impl IndexMut<usize> for QueryResult {
426 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
427 &mut self.stmt.columns[index]
428 }
429}
430
431impl std::fmt::Debug for QueryResult {
432 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
433 let mut dt = f.debug_tuple("QueryResult");
434 for i in 0..self.len() {
435 dt.field(&self[i]);
436 }
437 dt.finish()
438 }
439}
440
441pub struct Column {
446 stmt: *mut ffi::sqlite3_stmt,
447 position: usize,
448}
449
450impl Column {
451 fn new(stmt: *mut ffi::sqlite3_stmt, position: usize) -> Self {
452 Self { stmt, position }
453 }
454
455 pub fn name(&self) -> Result<&str> {
459 unsafe {
460 let ret = ffi::sqlite3_column_name(self.stmt, self.position as _);
461 if ret.is_null() {
462 Err(SQLITE_NOMEM)
463 } else {
464 Ok(CStr::from_ptr(ret).to_str()?)
465 }
466 }
467 }
468
469 pub fn database_name(&self) -> Result<Option<&str>> {
472 unsafe {
473 let ret = ffi::sqlite3_column_database_name(self.stmt, self.position as _);
474 if ret.is_null() {
475 Ok(None)
476 } else {
477 Ok(Some(CStr::from_ptr(ret).to_str()?))
478 }
479 }
480 }
481
482 pub fn table_name(&self) -> Result<Option<&str>> {
485 unsafe {
486 let ret = ffi::sqlite3_column_table_name(self.stmt, self.position as _);
487 if ret.is_null() {
488 Ok(None)
489 } else {
490 Ok(Some(CStr::from_ptr(ret).to_str()?))
491 }
492 }
493 }
494
495 pub fn origin_name(&self) -> Result<Option<&str>> {
498 unsafe {
499 let ret = ffi::sqlite3_column_origin_name(self.stmt, self.position as _);
500 if ret.is_null() {
501 Ok(None)
502 } else {
503 Ok(Some(CStr::from_ptr(ret).to_str()?))
504 }
505 }
506 }
507
508 pub fn decltype(&self) -> Result<Option<&str>> {
512 unsafe {
513 let ret = ffi::sqlite3_column_decltype(self.stmt, self.position as _);
514 if ret.is_null() {
515 Ok(None)
516 } else {
517 Ok(Some(CStr::from_ptr(ret).to_str()?))
518 }
519 }
520 }
521}
522
523impl AsRef<ValueRef> for Column {
524 fn as_ref(&self) -> &ValueRef {
525 unsafe { ValueRef::from_ptr(ffi::sqlite3_column_value(self.stmt, self.position as _)) }
526 }
527}
528
529impl AsMut<ValueRef> for Column {
530 fn as_mut(&mut self) -> &mut ValueRef {
531 unsafe { ValueRef::from_ptr(ffi::sqlite3_column_value(self.stmt, self.position as _)) }
532 }
533}
534
535impl FromValue for Column {
536 fn value_type(&self) -> ValueType {
537 unsafe { ValueType::from_sqlite(ffi::sqlite3_column_type(self.stmt, self.position as _)) }
538 }
539
540 fn get_i32(&self) -> i32 {
541 unsafe { ffi::sqlite3_column_int(self.stmt, self.position as _) }
542 }
543
544 fn get_i64(&self) -> i64 {
545 unsafe { ffi::sqlite3_column_int64(self.stmt, self.position as _) }
546 }
547
548 fn get_f64(&self) -> f64 {
549 unsafe { ffi::sqlite3_column_double(self.stmt, self.position as _) }
550 }
551
552 unsafe fn get_blob_unchecked(&self) -> &[u8] {
553 let len = ffi::sqlite3_column_bytes(self.stmt, self.position as _);
554 if len == 0 {
555 return &[];
556 }
557 let data = ffi::sqlite3_column_blob(self.stmt, self.position as _);
558 slice::from_raw_parts(data as _, len as _)
559 }
560
561 fn get_blob(&mut self) -> Result<&[u8]> {
562 unsafe {
563 let len = ffi::sqlite3_column_bytes(self.stmt, self.position as _);
564 if len == 0 {
565 return Ok(&[]);
566 }
567 let data = ffi::sqlite3_column_blob(self.stmt, self.position as _);
568 if data.is_null() {
569 return Err(SQLITE_NOMEM);
570 } else {
571 Ok(slice::from_raw_parts(data as _, len as _))
572 }
573 }
574 }
575}
576
577impl std::fmt::Debug for Column {
578 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
579 match self.value_type() {
580 ValueType::Integer => f.debug_tuple("Integer").field(&self.get_i64()).finish(),
581 ValueType::Float => f.debug_tuple("Float").field(&self.get_f64()).finish(),
582 ValueType::Text => f
583 .debug_tuple("Text")
584 .field(unsafe { &self.get_str_unchecked() })
585 .finish(),
586 ValueType::Blob => f
587 .debug_tuple("Blob")
588 .field(unsafe { &self.get_blob_unchecked() })
589 .finish(),
590 ValueType::Null => f.debug_tuple("Null").finish(),
591 }
592 }
593}