1use std::borrow::Cow;
2use std::marker::PhantomData;
3use std::ptr::NonNull;
4use std::slice::from_raw_parts;
5use std::str::from_utf8;
6use std::sync::Arc;
7
8use libsqlite3_sys::{
9 sqlite3_value, sqlite3_value_blob, sqlite3_value_bytes, sqlite3_value_double,
10 sqlite3_value_dup, sqlite3_value_free, sqlite3_value_int64, sqlite3_value_type, SQLITE_NULL,
11};
12
13pub(crate) use sqlx_core::value::{Value, ValueRef};
14
15use crate::error::BoxDynError;
16use crate::type_info::DataType;
17use crate::{Sqlite, SqliteTypeInfo};
18
19enum SqliteValueData<'r> {
20 Value(&'r SqliteValue),
21 BorrowedHandle(ValueHandle<'r>),
22}
23
24pub struct SqliteValueRef<'r>(SqliteValueData<'r>);
25
26impl<'r> SqliteValueRef<'r> {
27 pub(crate) fn value(value: &'r SqliteValue) -> Self {
28 Self(SqliteValueData::Value(value))
29 }
30
31 #[allow(unused)]
34 pub(crate) unsafe fn borrowed(value: *mut sqlite3_value, type_info: SqliteTypeInfo) -> Self {
35 debug_assert!(!value.is_null());
36 let handle = ValueHandle::new_borrowed(NonNull::new_unchecked(value), type_info);
37 Self(SqliteValueData::BorrowedHandle(handle))
38 }
39
40 pub(super) fn int64(&self) -> i64 {
45 match &self.0 {
46 SqliteValueData::Value(v) => v.0.int64(),
47 SqliteValueData::BorrowedHandle(v) => v.int64(),
48 }
49 }
50
51 pub(super) fn double(&self) -> f64 {
52 match &self.0 {
53 SqliteValueData::Value(v) => v.0.double(),
54 SqliteValueData::BorrowedHandle(v) => v.double(),
55 }
56 }
57
58 pub(super) fn blob(&self) -> &'r [u8] {
59 match &self.0 {
60 SqliteValueData::Value(v) => v.0.blob(),
61 SqliteValueData::BorrowedHandle(v) => v.blob(),
62 }
63 }
64
65 pub(super) fn text(&self) -> Result<&'r str, BoxDynError> {
66 match &self.0 {
67 SqliteValueData::Value(v) => v.0.text(),
68 SqliteValueData::BorrowedHandle(v) => v.text(),
69 }
70 }
71}
72
73impl<'r> ValueRef<'r> for SqliteValueRef<'r> {
74 type Database = Sqlite;
75
76 fn to_owned(&self) -> SqliteValue {
77 match &self.0 {
78 SqliteValueData::Value(v) => (*v).clone(),
79 SqliteValueData::BorrowedHandle(v) => unsafe {
80 SqliteValue::new(v.value.as_ptr(), v.type_info.clone())
81 },
82 }
83 }
84
85 fn type_info(&self) -> Cow<'_, SqliteTypeInfo> {
86 match &self.0 {
87 SqliteValueData::Value(v) => v.type_info(),
88 SqliteValueData::BorrowedHandle(v) => v.type_info(),
89 }
90 }
91
92 fn is_null(&self) -> bool {
93 match &self.0 {
94 SqliteValueData::Value(v) => v.is_null(),
95 SqliteValueData::BorrowedHandle(v) => v.is_null(),
96 }
97 }
98}
99
100#[derive(Clone)]
101pub struct SqliteValue(Arc<ValueHandle<'static>>);
102
103pub(crate) struct ValueHandle<'a> {
104 value: NonNull<sqlite3_value>,
105 type_info: SqliteTypeInfo,
106 free_on_drop: bool,
107 _sqlite_value_lifetime: PhantomData<&'a ()>,
108}
109
110unsafe impl<'a> Send for ValueHandle<'a> {}
112unsafe impl<'a> Sync for ValueHandle<'a> {}
113
114impl ValueHandle<'static> {
115 fn new_owned(value: NonNull<sqlite3_value>, type_info: SqliteTypeInfo) -> Self {
116 Self {
117 value,
118 type_info,
119 free_on_drop: true,
120 _sqlite_value_lifetime: PhantomData,
121 }
122 }
123}
124
125impl<'a> ValueHandle<'a> {
126 fn new_borrowed(value: NonNull<sqlite3_value>, type_info: SqliteTypeInfo) -> Self {
127 Self {
128 value,
129 type_info,
130 free_on_drop: false,
131 _sqlite_value_lifetime: PhantomData,
132 }
133 }
134
135 fn type_info_opt(&self) -> Option<SqliteTypeInfo> {
136 let dt = DataType::from_code(unsafe { sqlite3_value_type(self.value.as_ptr()) });
137
138 if let DataType::Null = dt {
139 None
140 } else {
141 Some(SqliteTypeInfo(dt))
142 }
143 }
144
145 fn int64(&self) -> i64 {
146 unsafe { sqlite3_value_int64(self.value.as_ptr()) }
147 }
148
149 fn double(&self) -> f64 {
150 unsafe { sqlite3_value_double(self.value.as_ptr()) }
151 }
152
153 fn blob<'b>(&self) -> &'b [u8] {
154 let len = unsafe { sqlite3_value_bytes(self.value.as_ptr()) };
155
156 let len = usize::try_from(len).unwrap_or_else(|_| {
159 panic!("sqlite3_value_bytes() returned value out of range for usize: {len}")
160 });
161
162 if len == 0 {
163 return &[];
165 }
166
167 let ptr = unsafe { sqlite3_value_blob(self.value.as_ptr()) } as *const u8;
168 debug_assert!(!ptr.is_null());
169
170 unsafe { from_raw_parts(ptr, len) }
171 }
172
173 fn text<'b>(&self) -> Result<&'b str, BoxDynError> {
174 Ok(from_utf8(self.blob())?)
175 }
176
177 fn type_info(&self) -> Cow<'_, SqliteTypeInfo> {
178 self.type_info_opt()
179 .map(Cow::Owned)
180 .unwrap_or(Cow::Borrowed(&self.type_info))
181 }
182
183 fn is_null(&self) -> bool {
184 unsafe { sqlite3_value_type(self.value.as_ptr()) == SQLITE_NULL }
185 }
186}
187
188impl<'a> Drop for ValueHandle<'a> {
189 fn drop(&mut self) {
190 if self.free_on_drop {
191 unsafe {
192 sqlite3_value_free(self.value.as_ptr());
193 }
194 }
195 }
196}
197
198impl SqliteValue {
199 pub(crate) unsafe fn new(value: *mut sqlite3_value, type_info: SqliteTypeInfo) -> Self {
201 debug_assert!(!value.is_null());
202 let handle =
203 ValueHandle::new_owned(NonNull::new_unchecked(sqlite3_value_dup(value)), type_info);
204 Self(Arc::new(handle))
205 }
206}
207
208impl Value for SqliteValue {
209 type Database = Sqlite;
210
211 fn as_ref(&self) -> SqliteValueRef<'_> {
212 SqliteValueRef::value(self)
213 }
214
215 fn type_info(&self) -> Cow<'_, SqliteTypeInfo> {
216 self.0.type_info()
217 }
218
219 fn is_null(&self) -> bool {
220 self.0.is_null()
221 }
222}
223
224