Skip to main content

diesel/sqlite/connection/
functions.rs

1#[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// clippy is wrong here, the let binding is required
100// for lifetime reasons
101#[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)] // complicated ptr cast
131    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                // This cast is safe because:
139                // * Casting from a pointer to an array to a pointer to the first array
140                // element is safe
141                // * Casting from a raw pointer to `NonNull<T>` is safe,
142                // because `NonNull` is #[repr(transparent)]
143                // * Casting from `NonNull<T>` to `OwnedSqliteValue` is safe,
144                // as the struct is `#[repr(transparent)]
145                // * Casting from `NonNull<T>` to `Option<NonNull<T>>` as the documentation
146                // states: "This is so that enums may use this forbidden value as a discriminant –
147                // Option<NonNull<T>> has the same size as *mut T"
148                // * The last point remains true for `OwnedSqliteValue` as `#[repr(transparent)]
149                // guarantees the same layout as the inner type
150                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}