diesel/sqlite/connection/
functions.rs1#[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
2extern crate libsqlite3_sys as ffi;
3
4#[cfg(all(target_family = "wasm", target_os = "unknown"))]
5use sqlite_wasm_rs as ffi;
6
7use super::raw::RawConnection;
8use super::{Sqlite, SqliteAggregateFunction, SqliteBindValue};
9use crate::backend::Backend;
10use crate::deserialize::{FromSqlRow, StaticallySizedRow};
11use crate::result::{DatabaseErrorKind, Error, QueryResult};
12use crate::row::{Field, PartialRow, Row, RowIndex, RowSealed};
13use crate::serialize::{IsNull, Output, ToSql};
14use crate::sql_types::HasSqlType;
15use crate::sqlite::connection::bind_collector::InternalSqliteBindValue;
16use crate::sqlite::connection::sqlite_value::OwnedSqliteValue;
17use crate::sqlite::SqliteValue;
18
19pub(super) fn register<ArgsSqlType, RetSqlType, Args, Ret, F>(
20 conn: &RawConnection,
21 fn_name: &str,
22 deterministic: bool,
23 mut f: F,
24) -> QueryResult<()>
25where
26 F: FnMut(&RawConnection, Args) -> Ret + std::panic::UnwindSafe + Send + 'static,
27 Args: FromSqlRow<ArgsSqlType, Sqlite> + StaticallySizedRow<ArgsSqlType, Sqlite>,
28 Ret: ToSql<RetSqlType, Sqlite>,
29 Sqlite: HasSqlType<RetSqlType>,
30{
31 let fields_needed = Args::FIELD_COUNT;
32 if fields_needed > 127 {
33 return Err(Error::DatabaseError(
34 DatabaseErrorKind::UnableToSendCommand,
35 Box::new("SQLite functions cannot take more than 127 parameters".to_string()),
36 ));
37 }
38
39 conn.register_sql_function(fn_name, fields_needed, deterministic, move |conn, args| {
40 let args = build_sql_function_args::<ArgsSqlType, Args>(args, conn.internal_connection)?;
41
42 Ok(f(conn, args))
43 })?;
44 Ok(())
45}
46
47pub(super) fn register_noargs<RetSqlType, Ret, F>(
48 conn: &RawConnection,
49 fn_name: &str,
50 deterministic: bool,
51 mut f: F,
52) -> QueryResult<()>
53where
54 F: FnMut() -> Ret + std::panic::UnwindSafe + Send + 'static,
55 Ret: ToSql<RetSqlType, Sqlite>,
56 Sqlite: HasSqlType<RetSqlType>,
57{
58 conn.register_sql_function(fn_name, 0, deterministic, move |_, _| Ok(f()))?;
59 Ok(())
60}
61
62pub(super) fn register_aggregate<ArgsSqlType, RetSqlType, Args, Ret, A>(
63 conn: &RawConnection,
64 fn_name: &str,
65) -> QueryResult<()>
66where
67 A: SqliteAggregateFunction<Args, Output = Ret> + 'static + Send + std::panic::UnwindSafe,
68 Args: FromSqlRow<ArgsSqlType, Sqlite> + StaticallySizedRow<ArgsSqlType, Sqlite>,
69 Ret: ToSql<RetSqlType, Sqlite>,
70 Sqlite: HasSqlType<RetSqlType>,
71{
72 let fields_needed = Args::FIELD_COUNT;
73 if fields_needed > 127 {
74 return Err(Error::DatabaseError(
75 DatabaseErrorKind::UnableToSendCommand,
76 Box::new("SQLite functions cannot take more than 127 parameters".to_string()),
77 ));
78 }
79
80 conn.register_aggregate_function::<ArgsSqlType, RetSqlType, Args, Ret, A>(
81 fn_name,
82 fields_needed,
83 )?;
84
85 Ok(())
86}
87
88pub(super) fn build_sql_function_args<ArgsSqlType, Args>(
89 args: &mut [*mut ffi::sqlite3_value],
90 connection: core::ptr::NonNull<ffi::sqlite3>,
91) -> Result<Args, Error>
92where
93 Args: FromSqlRow<ArgsSqlType, Sqlite>,
94{
95 let row = FunctionRow::new(args, connection);
96 Args::build_from_row(&row).map_err(Error::DeserializationError)
97}
98
99#[allow(clippy::let_unit_value)]
102pub(super) fn process_sql_function_result<RetSqlType, Ret>(
103 result: &'_ Ret,
104) -> QueryResult<InternalSqliteBindValue<'_>>
105where
106 Ret: ToSql<RetSqlType, Sqlite>,
107 Sqlite: HasSqlType<RetSqlType>,
108{
109 let mut metadata_lookup = ();
110 let value = SqliteBindValue {
111 inner: InternalSqliteBindValue::Null,
112 };
113 let mut buf = Output::new(value, &mut metadata_lookup);
114 let is_null = result.to_sql(&mut buf).map_err(Error::SerializationError)?;
115
116 if let IsNull::Yes = is_null {
117 Ok(InternalSqliteBindValue::Null)
118 } else {
119 Ok(buf.into_inner().inner)
120 }
121}
122
123struct FunctionRow<'a> {
124 args: &'a [Option<OwnedSqliteValue>],
125 field_count: usize,
126 connection: core::ptr::NonNull<ffi::sqlite3>,
127}
128
129impl FunctionRow<'_> {
130 #[allow(unsafe_code)] fn new(
132 args: &mut [*mut ffi::sqlite3_value],
133 connection: core::ptr::NonNull<ffi::sqlite3>,
134 ) -> Self {
135 let lengths = args.len();
136 let args = unsafe {
137 core::slice::from_raw_parts(
138 args as *mut [*mut ffi::sqlite3_value] as *mut ffi::sqlite3_value
151 as *mut Option<OwnedSqliteValue>,
152 lengths,
153 )
154 };
155
156 Self {
157 field_count: lengths,
158 args,
159 connection,
160 }
161 }
162}
163
164impl RowSealed for FunctionRow<'_> {}
165
166impl<'a> Row<'a, Sqlite> for FunctionRow<'a> {
167 type Field<'f>
168 = FunctionArgument<'f>
169 where
170 'a: 'f,
171 Self: 'f;
172 type InnerPartialRow = Self;
173
174 fn field_count(&self) -> usize {
175 self.field_count
176 }
177
178 fn get<'b, I>(&'b self, idx: I) -> Option<Self::Field<'b>>
179 where
180 'a: 'b,
181 Self: crate::row::RowIndex<I>,
182 {
183 let col_idx = self.idx(idx)?;
184 Some(FunctionArgument {
185 args: self.args,
186 col_idx,
187 connection: self.connection,
188 })
189 }
190
191 fn partial_row(&self, range: std::ops::Range<usize>) -> PartialRow<'_, Self::InnerPartialRow> {
192 PartialRow::new(self, range)
193 }
194}
195
196impl RowIndex<usize> for FunctionRow<'_> {
197 fn idx(&self, idx: usize) -> Option<usize> {
198 if idx < self.field_count() {
199 Some(idx)
200 } else {
201 None
202 }
203 }
204}
205
206impl<'a> RowIndex<&'a str> for FunctionRow<'_> {
207 fn idx(&self, _idx: &'a str) -> Option<usize> {
208 None
209 }
210}
211
212struct FunctionArgument<'a> {
213 args: &'a [Option<OwnedSqliteValue>],
214 col_idx: usize,
215 connection: core::ptr::NonNull<ffi::sqlite3>,
216}
217
218impl<'a> Field<'a, Sqlite> for FunctionArgument<'a> {
219 fn field_name(&self) -> Option<&str> {
220 None
221 }
222
223 fn is_null(&self) -> bool {
224 self.value().is_none()
225 }
226
227 fn value(&self) -> Option<<Sqlite as Backend>::RawValue<'_>> {
228 SqliteValue::from_function_row(self.args, self.col_idx, self.connection)
229 }
230}