rusqlite/
params.rs

1use crate::{Result, Statement, ToSql};
2
3mod sealed {
4    /// This trait exists just to ensure that the only impls of `trait Params`
5    /// that are allowed are ones in this crate.
6    pub trait Sealed {}
7}
8use sealed::Sealed;
9
10/// Trait used for [sets of parameter][params] passed into SQL
11/// statements/queries.
12///
13/// [params]: https://www.sqlite.org/c3ref/bind_blob.html
14///
15/// Note: Currently, this trait can only be implemented inside this crate.
16/// Additionally, it's methods (which are `doc(hidden)`) should currently not be
17/// considered part of the stable API, although it's possible they will
18/// stabilize in the future.
19///
20/// # Passing parameters to SQLite
21///
22/// Many functions in this library let you pass parameters to SQLite. Doing this
23/// lets you avoid any risk of SQL injection, and is simpler than escaping
24/// things manually. Aside from deprecated functions and a few helpers, this is
25/// indicated by the function taking a generic argument that implements `Params`
26/// (this trait).
27///
28/// ## Positional parameters
29///
30/// For cases where you want to pass a list of parameters where the number of
31/// parameters is known at compile time, this can be done in one of the
32/// following ways:
33///
34/// - Using the [`rusqlite::params!`](crate::params!) macro, e.g.
35///   `thing.query(rusqlite::params![1, "foo", bar])`. This is mostly useful for
36///   heterogeneous lists of parameters, or lists where the number of parameters
37///   exceeds 32.
38///
39/// - For small heterogeneous lists of parameters, they can either be passed as:
40///
41///     - an array, as in `thing.query([1i32, 2, 3, 4])` or `thing.query(["foo",
42///       "bar", "baz"])`.
43///
44///     - a reference to an array of references, as in `thing.query(&["foo",
45///       "bar", "baz"])` or `thing.query(&[&1i32, &2, &3])`.
46///
47///         (Note: in this case we don't implement this for slices for coherence
48///         reasons, so it really is only for the "reference to array" types —
49///         hence why the number of parameters must be <= 32 or you need to
50///         reach for `rusqlite::params!`)
51///
52///     Unfortunately, in the current design it's not possible to allow this for
53///     references to arrays of non-references (e.g. `&[1i32, 2, 3]`). Code like
54///     this should instead either use `params!`, an array literal, a `&[&dyn
55///     ToSql]` or if none of those work, [`ParamsFromIter`].
56///
57/// - As a slice of `ToSql` trait object references, e.g. `&[&dyn ToSql]`. This
58///   is mostly useful for passing parameter lists around as arguments without
59///   having every function take a generic `P: Params`.
60///
61/// ### Example (positional)
62///
63/// ```rust,no_run
64/// # use rusqlite::{Connection, Result, params};
65/// fn update_rows(conn: &Connection) -> Result<()> {
66///     let mut stmt = conn.prepare("INSERT INTO test (a, b) VALUES (?, ?)")?;
67///
68///     // Using `rusqlite::params!`:
69///     stmt.execute(params![1i32, "blah"])?;
70///
71///     // array literal — non-references
72///     stmt.execute([2i32, 3i32])?;
73///
74///     // array literal — references
75///     stmt.execute(["foo", "bar"])?;
76///
77///     // Slice literal, references:
78///     stmt.execute(&[&2i32, &3i32])?;
79///
80///     // Note: The types behind the references don't have to be `Sized`
81///     stmt.execute(&["foo", "bar"])?;
82///
83///     // However, this doesn't work (see above):
84///     // stmt.execute(&[1i32, 2i32])?;
85///     Ok(())
86/// }
87/// ```
88///
89/// ## Named parameters
90///
91/// SQLite lets you name parameters using a number of conventions (":foo",
92/// "@foo", "$foo"). You can pass named parameters in to SQLite using rusqlite
93/// in a few ways:
94///
95/// - Using the [`rusqlite::named_params!`](crate::named_params!) macro, as in
96///   `stmt.execute(named_params!{ ":name": "foo", ":age": 99 })`. Similar to
97///   the `params` macro, this is most useful for heterogeneous lists of
98///   parameters, or lists where the number of parameters exceeds 32.
99///
100/// - As a slice of `&[(&str, &dyn ToSql)]`. This is what essentially all of
101///   these boil down to in the end, conceptually at least. In theory you can
102///   pass this as `stmt.
103///
104/// - As array references, similar to the positional params. This looks like
105///   `thing.query(&[(":foo", &1i32), (":bar", &2i32)])` or
106///   `thing.query(&[(":foo", "abc"), (":bar", "def")])`.
107///
108/// Note: Unbound named parameters will be left to the value they previously
109/// were bound with, falling back to `NULL` for parameters which have never been
110/// bound.
111///
112/// ### Example (named)
113///
114/// ```rust,no_run
115/// # use rusqlite::{Connection, Result, named_params};
116/// fn insert(conn: &Connection) -> Result<()> {
117///     let mut stmt = conn.prepare("INSERT INTO test (key, value) VALUES (:key, :value)")?;
118///     // Using `rusqlite::params!`:
119///     stmt.execute(named_params!{ ":key": "one", ":val": 2 })?;
120///     // Alternatively:
121///     stmt.execute(&[(":key", "three"), (":val", "four")])?;
122///     // Or:
123///     stmt.execute(&[(":key", &100), (":val", &200)])?;
124///     Ok(())
125/// }
126/// ```
127///
128/// ## No parameters
129///
130/// You can just use an empty array literal for no params. The
131/// `rusqlite::NO_PARAMS` constant which was so common in previous versions of
132/// this library is no longer needed (and is now deprecated).
133///
134/// ### Example (no parameters)
135///
136/// ```rust,no_run
137/// # use rusqlite::{Connection, Result, params};
138/// fn delete_all_users(conn: &Connection) -> Result<()> {
139///     // Just use an empty array (e.g. `[]`) for no params.
140///     conn.execute("DELETE FROM users", [])?;
141///     Ok(())
142/// }
143/// ```
144///
145/// ## Dynamic parameter list
146///
147/// If you have a number of parameters which is unknown at compile time (for
148/// example, building a dynamic query at runtime), you have two choices:
149///
150/// - Use a `&[&dyn ToSql]`, which is nice if you have one otherwise might be
151///   annoying.
152/// - Use the [`ParamsFromIter`] type. This essentially lets you wrap an
153///   iterator some `T: ToSql` with something that implements `Params`.
154///
155/// A lot of the considerations here are similar either way, so you should see
156/// the [`ParamsFromIter`] documentation for more info / examples.
157pub trait Params: Sealed {
158    // XXX not public api, might not need to expose.
159    //
160    // Binds the parameters to the statement. It is unlikely calling this
161    // explicitly will do what you want. Please use `Statement::query` or
162    // similar directly.
163    //
164    // For now, just hide the function in the docs...
165    #[doc(hidden)]
166    fn bind_in(self, stmt: &mut Statement<'_>) -> Result<()>;
167}
168
169// Explicitly impl for empty array. Critically, for `conn.execute([])` to be
170// unambiguous, this must be the *only* implementation for an empty array. This
171// avoids `NO_PARAMS` being a necessary part of the API.
172impl Sealed for [&dyn ToSql; 0] {}
173impl Params for [&dyn ToSql; 0] {
174    #[inline]
175    fn bind_in(self, stmt: &mut Statement<'_>) -> Result<()> {
176        // Note: Can't just return `Ok(())` — `Statement::bind_parameters`
177        // checks that the right number of params were passed too.
178        // TODO: we should have tests for `Error::InvalidParameterCount`...
179        stmt.bind_parameters(crate::params![])
180    }
181}
182
183impl Sealed for &[&dyn ToSql] {}
184impl Params for &[&dyn ToSql] {
185    #[inline]
186    fn bind_in(self, stmt: &mut Statement<'_>) -> Result<()> {
187        stmt.bind_parameters(self)
188    }
189}
190
191impl Sealed for &[(&str, &dyn ToSql)] {}
192impl Params for &[(&str, &dyn ToSql)] {
193    #[inline]
194    fn bind_in(self, stmt: &mut Statement<'_>) -> Result<()> {
195        stmt.bind_parameters_named(self)
196    }
197}
198
199macro_rules! impl_for_array_ref {
200    ($($N:literal)+) => {$(
201        // These are already generic, and theres a shitload of them, so lets
202        // avoid the compile time hit from making them all inline for now.
203        impl<T: ToSql + ?Sized> Sealed for &[&T; $N] {}
204        impl<T: ToSql + ?Sized> Params for &[&T; $N] {
205            fn bind_in(self, stmt: &mut Statement<'_>) -> Result<()> {
206                stmt.bind_parameters(self)
207            }
208        }
209        impl<T: ToSql + ?Sized> Sealed for &[(&str, &T); $N] {}
210        impl<T: ToSql + ?Sized> Params for &[(&str, &T); $N] {
211            fn bind_in(self, stmt: &mut Statement<'_>) -> Result<()> {
212                stmt.bind_parameters_named(self)
213            }
214        }
215        impl<T: ToSql> Sealed for [T; $N] {}
216        impl<T: ToSql> Params for [T; $N] {
217            fn bind_in(self, stmt: &mut Statement<'_>) -> Result<()> {
218                stmt.bind_parameters(&self)
219            }
220        }
221    )+};
222}
223
224// Following libstd/libcore's (old) lead, implement this for arrays up to `[_;
225// 32]`. Note `[_; 0]` is intentionally omitted for coherence reasons, see the
226// note above the impl of `[&dyn ToSql; 0]` for more information.
227impl_for_array_ref!(
228    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
229    18 19 20 21 22 23 24 25 26 27 29 30 31 32
230);
231
232/// Adapter type which allows any iterator over [`ToSql`] values to implement
233/// [`Params`].
234///
235/// This struct is created by the [`params_from_iter`] function.
236///
237/// This can be useful if you have something like an `&[String]` (of unknown
238/// length), and you want to use them with an API that wants something
239/// implementing `Params`. This way, you can avoid having to allocate storage
240/// for something like a `&[&dyn ToSql]`.
241///
242/// This essentially is only ever actually needed when dynamically generating
243/// SQL — static SQL (by definition) has the number of parameters known
244/// statically. As dynamically generating SQL is itself pretty advanced, this
245/// API is itself for advanced use cases (See "Realistic use case" in the
246/// examples).
247///
248/// # Example
249///
250/// ## Basic usage
251///
252/// ```rust,no_run
253/// use rusqlite::{Connection, Result, params_from_iter};
254/// use std::collections::BTreeSet;
255///
256/// fn query(conn: &Connection, ids: &BTreeSet<String>) -> Result<()> {
257///     assert_eq!(ids.len(), 3, "Unrealistic sample code");
258///
259///     let mut stmt = conn.prepare("SELECT * FROM users WHERE id IN (?, ?, ?)")?;
260///     let _rows = stmt.query(params_from_iter(ids.iter()))?;
261///
262///     // use _rows...
263///     Ok(())
264/// }
265/// ```
266///
267/// ## Realistic use case
268///
269/// Here's how you'd use `ParamsFromIter` to call [`Statement::exists`] with a
270/// dynamic number of parameters.
271///
272/// ```rust,no_run
273/// use rusqlite::{Connection, Result};
274///
275/// pub fn any_active_users(conn: &Connection, usernames: &[String]) -> Result<bool> {
276///     if usernames.is_empty() {
277///         return Ok(false);
278///     }
279///
280///     // Note: `repeat_vars` never returns anything attacker-controlled, so
281///     // it's fine to use it in a dynamically-built SQL string.
282///     let vars = repeat_vars(usernames.len());
283///
284///     let sql = format!(
285///         // In practice this would probably be better as an `EXISTS` query.
286///         "SELECT 1 FROM user WHERE is_active AND name IN ({}) LIMIT 1",
287///         vars,
288///     );
289///     let mut stmt = conn.prepare(&sql)?;
290///     stmt.exists(rusqlite::params_from_iter(usernames))
291/// }
292///
293/// // Helper function to return a comma-separated sequence of `?`.
294/// // - `repeat_vars(0) => panic!(...)`
295/// // - `repeat_vars(1) => "?"`
296/// // - `repeat_vars(2) => "?,?"`
297/// // - `repeat_vars(3) => "?,?,?"`
298/// // - ...
299/// fn repeat_vars(count: usize) -> String {
300///     assert_ne!(count, 0);
301///     let mut s = "?,".repeat(count);
302///     // Remove trailing comma
303///     s.pop();
304///     s
305/// }
306/// ```
307///
308/// That is fairly complex, and even so would need even more work to be fully
309/// production-ready:
310///
311/// - production code should ensure `usernames` isn't so large that it will
312///   surpass [`conn.limit(Limit::SQLITE_LIMIT_VARIABLE_NUMBER)`][limits]),
313///   chunking if too large. (Note that the limits api requires rusqlite to have
314///   the "limits" feature).
315///
316/// - `repeat_vars` can be implemented in a way that avoids needing to allocate
317///   a String.
318///
319/// - Etc...
320///
321/// [limits]: crate::Connection::limit
322///
323/// This complexity reflects the fact that `ParamsFromIter` is mainly intended
324/// for advanced use cases — most of the time you should know how many
325/// parameters you have statically (and if you don't, you're either doing
326/// something tricky, or should take a moment to think about the design).
327#[derive(Clone, Debug)]
328pub struct ParamsFromIter<I>(I);
329
330/// Constructor function for a [`ParamsFromIter`]. See its documentation for
331/// more.
332#[inline]
333pub fn params_from_iter<I>(iter: I) -> ParamsFromIter<I>
334where
335    I: IntoIterator,
336    I::Item: ToSql,
337{
338    ParamsFromIter(iter)
339}
340
341impl<I> Sealed for ParamsFromIter<I>
342where
343    I: IntoIterator,
344    I::Item: ToSql,
345{
346}
347
348impl<I> Params for ParamsFromIter<I>
349where
350    I: IntoIterator,
351    I::Item: ToSql,
352{
353    #[inline]
354    fn bind_in(self, stmt: &mut Statement<'_>) -> Result<()> {
355        stmt.bind_parameters(self.0)
356    }
357}