mirror of
https://github.com/launchbadge/sqlx.git
synced 2025-12-31 13:50:55 +00:00
121 lines
3.5 KiB
Rust
121 lines
3.5 KiB
Rust
use core::slice;
|
|
|
|
use std::ffi::CStr;
|
|
use std::str::from_utf8_unchecked;
|
|
|
|
use libsqlite3_sys::{
|
|
sqlite3_column_blob, sqlite3_column_bytes, sqlite3_column_double, sqlite3_column_int,
|
|
sqlite3_column_int64, sqlite3_column_text, sqlite3_column_type, SQLITE_BLOB, SQLITE_FLOAT,
|
|
SQLITE_INTEGER, SQLITE_NULL, SQLITE_TEXT,
|
|
};
|
|
|
|
use crate::sqlite::statement::Statement;
|
|
use crate::sqlite::types::SqliteType;
|
|
use crate::sqlite::{Sqlite, SqliteTypeInfo};
|
|
use crate::value::RawValue;
|
|
|
|
pub struct SqliteValue<'c> {
|
|
pub(super) index: i32,
|
|
pub(super) statement: &'c Statement,
|
|
}
|
|
|
|
// https://www.sqlite.org/c3ref/column_blob.html
|
|
// https://www.sqlite.org/capi3ref.html#sqlite3_column_blob
|
|
|
|
// These routines return information about a single column of the current result row of a query.
|
|
|
|
impl<'c> SqliteValue<'c> {
|
|
/// Returns true if the value should be intrepreted as NULL.
|
|
pub(super) fn is_null(&self) -> bool {
|
|
self.r#type().is_none()
|
|
}
|
|
|
|
fn r#type(&self) -> Option<SqliteType> {
|
|
#[allow(unsafe_code)]
|
|
let type_code = unsafe { sqlite3_column_type(self.statement.handle(), self.index) };
|
|
|
|
// SQLITE_INTEGER, SQLITE_FLOAT, SQLITE_TEXT, SQLITE_BLOB, or SQLITE_NULL
|
|
match type_code {
|
|
SQLITE_INTEGER => Some(SqliteType::Integer),
|
|
SQLITE_FLOAT => Some(SqliteType::Float),
|
|
SQLITE_TEXT => Some(SqliteType::Text),
|
|
SQLITE_BLOB => Some(SqliteType::Blob),
|
|
SQLITE_NULL => None,
|
|
|
|
_ => unreachable!("received unexpected column type: {}", type_code),
|
|
}
|
|
}
|
|
|
|
/// Returns the 32-bit INTEGER result.
|
|
pub(super) fn int(&self) -> i32 {
|
|
#[allow(unsafe_code)]
|
|
unsafe {
|
|
sqlite3_column_int(self.statement.handle(), self.index)
|
|
}
|
|
}
|
|
|
|
/// Returns the 64-bit INTEGER result.
|
|
pub(super) fn int64(&self) -> i64 {
|
|
#[allow(unsafe_code)]
|
|
unsafe {
|
|
sqlite3_column_int64(self.statement.handle(), self.index)
|
|
}
|
|
}
|
|
|
|
/// Returns the 64-bit, REAL result.
|
|
pub(super) fn double(&self) -> f64 {
|
|
#[allow(unsafe_code)]
|
|
unsafe {
|
|
sqlite3_column_double(self.statement.handle(), self.index)
|
|
}
|
|
}
|
|
|
|
/// Returns the UTF-8 TEXT result.
|
|
pub(super) fn text(&self) -> Option<&'c str> {
|
|
#[allow(unsafe_code)]
|
|
unsafe {
|
|
let ptr = sqlite3_column_text(self.statement.handle(), self.index) as *const i8;
|
|
|
|
if ptr.is_null() {
|
|
None
|
|
} else {
|
|
Some(from_utf8_unchecked(CStr::from_ptr(ptr).to_bytes()))
|
|
}
|
|
}
|
|
}
|
|
|
|
fn bytes(&self) -> usize {
|
|
// Returns the size of the result in bytes.
|
|
#[allow(unsafe_code)]
|
|
let len = unsafe { sqlite3_column_bytes(self.statement.handle(), self.index) };
|
|
len as usize
|
|
}
|
|
|
|
/// Returns the BLOB result.
|
|
pub(super) fn blob(&self) -> &'c [u8] {
|
|
#[allow(unsafe_code)]
|
|
let ptr = unsafe { sqlite3_column_blob(self.statement.handle(), self.index) };
|
|
|
|
if ptr.is_null() {
|
|
// Empty BLOBs are received as null pointers
|
|
return &[];
|
|
}
|
|
|
|
#[allow(unsafe_code)]
|
|
unsafe {
|
|
slice::from_raw_parts(ptr as *const u8, self.bytes())
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'c> RawValue<'c> for SqliteValue<'c> {
|
|
type Database = Sqlite;
|
|
|
|
fn type_info(&self) -> Option<SqliteTypeInfo> {
|
|
Some(SqliteTypeInfo {
|
|
r#type: self.r#type()?,
|
|
affinity: None,
|
|
})
|
|
}
|
|
}
|