1use ffi;
2use libc::{c_double, c_int};
3use std::collections::HashMap;
4use std::marker::PhantomData;
5use std::rc::Rc;
6
7use cursor::{Cursor, CursorWithOwnership, Row};
8use error::Result;
9use value::{Type, Value};
10
11macro_rules! transient(
13 () => (::std::mem::transmute(!0 as *const ::libc::c_void));
14);
15
16#[derive(Debug, Clone)]
18pub struct Statement {
19 raw: *mut ffi::sqlite3_stmt,
20 column_names: Vec<String>,
21 column_mapping: Rc<HashMap<String, usize>>,
22 phantom: PhantomData<ffi::sqlite3_stmt>,
23}
24
25unsafe impl<'l> Sync for Statement {}
26unsafe impl<'l> Send for Statement {}
27
28pub trait Bindable {
30 fn bind(self, _: &mut Statement) -> Result<()>;
32}
33
34pub trait BindableWithIndex {
36 fn bind<T: ParameterIndex>(self, _: &mut Statement, _: T) -> Result<()>;
40}
41
42pub trait ColumnIndex: Copy + std::fmt::Debug {
44 fn index(self, statement: &Statement) -> Result<usize>;
48}
49
50pub trait ParameterIndex: Copy + std::fmt::Debug {
52 fn index(self, statement: &Statement) -> Result<usize>;
56}
57
58pub trait ReadableWithIndex: Sized {
60 fn read<T: ColumnIndex>(_: &Statement, _: T) -> Result<Self>;
64}
65
66#[derive(Clone, Copy, Debug, PartialEq, Eq)]
68pub enum State {
69 Row,
71 Done,
73}
74
75impl Statement {
76 #[inline]
131 pub fn bind<T: Bindable>(&mut self, value: T) -> Result<()> {
132 value.bind(self)?;
133 Ok(())
134 }
135
136 pub fn bind_iter<T, U>(&mut self, value: T) -> Result<()>
153 where
154 T: IntoIterator<Item = U>,
155 U: Bindable,
156 {
157 for value in value {
158 self.bind(value)?;
159 }
160 Ok(())
161 }
162
163 #[inline]
165 pub fn column_count(&self) -> usize {
166 self.column_names.len()
167 }
168
169 #[doc(hidden)]
170 #[inline]
171 pub fn column_mapping(&self) -> Rc<HashMap<String, usize>> {
172 self.column_mapping.clone()
173 }
174
175 #[inline]
179 pub fn column_name<T: ColumnIndex>(&self, index: T) -> Result<&str> {
180 Ok(&self.column_names[index.index(self)?])
181 }
182
183 #[inline]
185 pub fn column_names(&self) -> &[String] {
186 &self.column_names
187 }
188
189 pub fn column_type<T: ColumnIndex>(&self, index: T) -> Result<Type> {
194 Ok(
195 match unsafe { ffi::sqlite3_column_type(self.raw, index.index(self)? as c_int) } {
196 ffi::SQLITE_BLOB => Type::Binary,
197 ffi::SQLITE_FLOAT => Type::Float,
198 ffi::SQLITE_INTEGER => Type::Integer,
199 ffi::SQLITE_TEXT => Type::String,
200 ffi::SQLITE_NULL => Type::Null,
201 _ => unreachable!(),
202 },
203 )
204 }
205
206 #[inline]
208 pub fn iter(&mut self) -> Cursor {
209 self.into()
210 }
211
212 pub fn next(&mut self) -> Result<State> {
217 Ok(match unsafe { ffi::sqlite3_step(self.raw) } {
218 ffi::SQLITE_ROW => State::Row,
219 ffi::SQLITE_DONE => State::Done,
220 code => {
221 return Err(::Error {
222 code: Some(code as isize),
223 message: None,
224 })
225 }
226 })
227 }
228
229 #[inline]
243 pub fn parameter_index(&self, parameter: &str) -> Result<Option<usize>> {
244 let index = unsafe {
245 ffi::sqlite3_bind_parameter_index(self.raw, str_to_cstr!(parameter).as_ptr())
246 };
247 match index {
248 0 => Ok(None),
249 _ => Ok(Some(index as usize)),
250 }
251 }
252
253 #[inline]
257 pub fn read<T, U>(&self, index: U) -> Result<T>
258 where
259 T: ReadableWithIndex,
260 U: ColumnIndex,
261 {
262 ReadableWithIndex::read(self, index)
263 }
264
265 #[inline]
267 pub fn reset(&mut self) -> Result<()> {
268 unsafe { ok!(ffi::sqlite3_reset(self.raw)) };
269 Ok(())
270 }
271
272 #[doc(hidden)]
273 #[inline]
274 pub fn as_raw(&self) -> *mut ffi::sqlite3_stmt {
275 self.raw
276 }
277}
278
279impl Drop for Statement {
280 #[inline]
281 fn drop(&mut self) {
282 unsafe { ffi::sqlite3_finalize(self.raw) };
283 }
284}
285
286impl<'m> From<&'m mut Statement> for Cursor<'m> {
287 #[inline]
288 fn from(statement: &'m mut Statement) -> Self {
289 ::cursor::new(statement)
290 }
291}
292
293impl IntoIterator for Statement {
294 type Item = Result<Row>;
295 type IntoIter = CursorWithOwnership;
296
297 #[inline]
298 fn into_iter(self) -> Self::IntoIter {
299 ::cursor::new_with_ownership(self)
300 }
301}
302
303impl<T, U> Bindable for (T, U)
304where
305 T: ParameterIndex,
306 U: BindableWithIndex,
307{
308 #[inline]
309 fn bind(self, statement: &mut Statement) -> Result<()> {
310 self.1.bind(statement, self.0)
311 }
312}
313
314impl<T> Bindable for &[T]
315where
316 T: BindableWithIndex + Clone,
317{
318 fn bind(self, statement: &mut Statement) -> Result<()> {
319 for (index, value) in self.iter().enumerate() {
320 value.clone().bind(statement, index + 1)?;
321 }
322 Ok(())
323 }
324}
325
326impl<T, U> Bindable for &[(T, U)]
327where
328 T: ParameterIndex,
329 U: BindableWithIndex + Clone,
330{
331 fn bind(self, statement: &mut Statement) -> Result<()> {
332 for (index, value) in self.iter() {
333 value.clone().bind(statement, *index)?;
334 }
335 Ok(())
336 }
337}
338
339impl BindableWithIndex for &[u8] {
340 #[inline]
341 fn bind<T: ParameterIndex>(self, statement: &mut Statement, index: T) -> Result<()> {
342 unsafe {
343 ok!(ffi::sqlite3_bind_blob(
344 statement.raw,
345 index.index(statement)? as c_int,
346 self.as_ptr() as *const _,
347 self.len() as c_int,
348 transient!(),
349 ));
350 }
351 Ok(())
352 }
353}
354
355impl BindableWithIndex for f64 {
356 #[inline]
357 fn bind<T: ParameterIndex>(self, statement: &mut Statement, index: T) -> Result<()> {
358 unsafe {
359 ok!(ffi::sqlite3_bind_double(
360 statement.raw,
361 index.index(statement)? as c_int,
362 self as c_double
363 ));
364 }
365 Ok(())
366 }
367}
368
369impl BindableWithIndex for i64 {
370 #[inline]
371 fn bind<T: ParameterIndex>(self, statement: &mut Statement, index: T) -> Result<()> {
372 unsafe {
373 ok!(ffi::sqlite3_bind_int64(
374 statement.raw,
375 index.index(statement)? as c_int,
376 self as ffi::sqlite3_int64
377 ));
378 }
379 Ok(())
380 }
381}
382
383impl BindableWithIndex for &str {
384 #[inline]
385 fn bind<T: ParameterIndex>(self, statement: &mut Statement, index: T) -> Result<()> {
386 unsafe {
387 let value = ffi::sqlite3_bind_text(
388 statement.raw,
389 index.index(statement)? as c_int,
390 self.as_ptr() as *const _,
391 self.len() as c_int,
392 transient!(),
393 );
394 ok!(value);
395 }
396 Ok(())
397 }
398}
399
400impl BindableWithIndex for () {
401 #[inline]
402 fn bind<T: ParameterIndex>(self, statement: &mut Statement, index: T) -> Result<()> {
403 unsafe {
404 ok!(ffi::sqlite3_bind_null(
405 statement.raw,
406 index.index(statement)? as c_int
407 ));
408 }
409 Ok(())
410 }
411}
412
413impl BindableWithIndex for Value {
414 #[inline]
415 fn bind<T: ParameterIndex>(self, statement: &mut Statement, index: T) -> Result<()> {
416 (index, &self).bind(statement)
417 }
418}
419
420impl BindableWithIndex for &Value {
421 fn bind<T: ParameterIndex>(self, statement: &mut Statement, index: T) -> Result<()> {
422 match self {
423 &Value::Binary(ref value) => (value as &[u8]).bind(statement, index),
424 &Value::Float(value) => value.bind(statement, index),
425 &Value::Integer(value) => value.bind(statement, index),
426 &Value::String(ref value) => (value as &str).bind(statement, index),
427 &Value::Null => ().bind(statement, index),
428 }
429 }
430}
431
432impl<T> BindableWithIndex for Option<T>
433where
434 T: BindableWithIndex,
435{
436 #[inline]
437 fn bind<U: ParameterIndex>(self, statement: &mut Statement, index: U) -> Result<()> {
438 match self {
439 Some(value) => value.bind(statement, index),
440 None => ().bind(statement, index),
441 }
442 }
443}
444
445impl<T> BindableWithIndex for &Option<T>
446where
447 T: BindableWithIndex + Clone,
448{
449 #[inline]
450 fn bind<U: ParameterIndex>(self, statement: &mut Statement, index: U) -> Result<()> {
451 match self {
452 Some(value) => value.clone().bind(statement, index),
453 None => ().bind(statement, index),
454 }
455 }
456}
457
458impl ColumnIndex for &str {
459 #[inline]
460 fn index(self, statement: &Statement) -> Result<usize> {
461 if statement.column_mapping.contains_key(self) {
462 Ok(statement.column_mapping[self])
463 } else {
464 raise!("the index is out of range ({})", self);
465 }
466 }
467}
468
469impl ColumnIndex for usize {
470 #[inline]
471 fn index(self, statement: &Statement) -> Result<usize> {
472 if self < statement.column_count() {
473 Ok(self)
474 } else {
475 raise!("the index is out of range ({})", self);
476 }
477 }
478}
479
480impl ParameterIndex for &str {
481 #[inline]
482 fn index(self, statement: &Statement) -> Result<usize> {
483 match statement.parameter_index(self)? {
484 Some(index) => return Ok(index),
485 _ => raise!("the index is out of range ({})", self),
486 }
487 }
488}
489
490impl ParameterIndex for usize {
491 #[inline]
492 fn index(self, _: &Statement) -> Result<usize> {
493 if self > 0 {
494 Ok(self)
495 } else {
496 raise!("the index is out of range ({})", self);
497 }
498 }
499}
500
501impl ReadableWithIndex for Value {
502 fn read<T: ColumnIndex>(statement: &Statement, index: T) -> Result<Self> {
503 Ok(match statement.column_type(index)? {
504 Type::Binary => Value::Binary(ReadableWithIndex::read(statement, index)?),
505 Type::Float => Value::Float(ReadableWithIndex::read(statement, index)?),
506 Type::Integer => Value::Integer(ReadableWithIndex::read(statement, index)?),
507 Type::String => Value::String(ReadableWithIndex::read(statement, index)?),
508 Type::Null => Value::Null,
509 })
510 }
511}
512
513impl ReadableWithIndex for f64 {
514 #[inline]
515 fn read<T: ColumnIndex>(statement: &Statement, index: T) -> Result<Self> {
516 Ok(unsafe {
517 ffi::sqlite3_column_double(statement.raw, index.index(statement)? as c_int) as f64
518 })
519 }
520}
521
522impl ReadableWithIndex for i64 {
523 #[inline]
524 fn read<T: ColumnIndex>(statement: &Statement, index: T) -> Result<Self> {
525 Ok(unsafe {
526 ffi::sqlite3_column_int64(statement.raw, index.index(statement)? as c_int) as i64
527 })
528 }
529}
530
531impl ReadableWithIndex for String {
532 #[inline]
533 fn read<T: ColumnIndex>(statement: &Statement, index: T) -> Result<Self> {
534 unsafe {
535 let pointer = ffi::sqlite3_column_text(statement.raw, index.index(statement)? as c_int);
536 if pointer.is_null() {
537 raise!("cannot read a text column");
538 }
539 Ok(c_str_to_string!(pointer))
540 }
541 }
542}
543
544impl ReadableWithIndex for Vec<u8> {
545 #[inline]
546 fn read<T: ColumnIndex>(statement: &Statement, index: T) -> Result<Self> {
547 use std::ptr::copy_nonoverlapping as copy;
548 unsafe {
549 let pointer = ffi::sqlite3_column_blob(statement.raw, index.index(statement)? as c_int);
550 if pointer.is_null() {
551 return Ok(vec![]);
552 }
553 let count =
554 ffi::sqlite3_column_bytes(statement.raw, index.index(statement)? as c_int) as usize;
555 let mut buffer = Vec::with_capacity(count);
556 buffer.set_len(count);
557 copy(pointer as *const u8, buffer.as_mut_ptr(), count);
558 Ok(buffer)
559 }
560 }
561}
562
563impl<T: ReadableWithIndex> ReadableWithIndex for Option<T> {
564 #[inline]
565 fn read<U: ColumnIndex>(statement: &Statement, index: U) -> Result<Self> {
566 if statement.column_type(index)? == Type::Null {
567 Ok(None)
568 } else {
569 T::read(statement, index).map(Some)
570 }
571 }
572}
573
574#[inline]
575pub fn new<'l, T>(raw_connection: *mut ffi::sqlite3, statement: T) -> Result<Statement>
576where
577 T: AsRef<str>,
578{
579 let mut raw_statement = 0 as *mut _;
580 unsafe {
581 ok!(
582 raw_connection,
583 ffi::sqlite3_prepare_v2(
584 raw_connection,
585 str_to_cstr!(statement.as_ref()).as_ptr(),
586 -1,
587 &mut raw_statement,
588 0 as *mut _,
589 )
590 );
591 }
592 let column_count = unsafe { ffi::sqlite3_column_count(raw_statement) as usize };
593 let column_names = (0..column_count)
594 .map(|index| unsafe {
595 let raw = ffi::sqlite3_column_name(raw_statement, index as c_int);
596 debug_assert!(!raw.is_null());
597 c_str_to_str!(raw).unwrap().to_string()
598 })
599 .collect::<Vec<_>>();
600 let column_mapping = column_names
601 .iter()
602 .enumerate()
603 .map(|(index, name)| (name.to_string(), index))
604 .collect();
605 Ok(Statement {
606 raw: raw_statement,
607 column_names: column_names,
608 column_mapping: Rc::new(column_mapping),
609 phantom: PhantomData,
610 })
611}