• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::{Result, Statement, ToSql};
2 
3 mod 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 }
8 use 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.
157 pub 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)]
__bind_in(self, stmt: &mut Statement<'_>) -> Result<()>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.
172 impl Sealed for [&(dyn ToSql + Send + Sync); 0] {}
173 impl Params for [&(dyn ToSql + Send + Sync); 0] {
174     #[inline]
__bind_in(self, stmt: &mut Statement<'_>) -> Result<()>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(&[] as &[&dyn ToSql])
180     }
181 }
182 
183 impl Sealed for &[&dyn ToSql] {}
184 impl Params for &[&dyn ToSql] {
185     #[inline]
__bind_in(self, stmt: &mut Statement<'_>) -> Result<()>186     fn __bind_in(self, stmt: &mut Statement<'_>) -> Result<()> {
187         stmt.bind_parameters(self)
188     }
189 }
190 
191 impl Sealed for &[(&str, &dyn ToSql)] {}
192 impl Params for &[(&str, &dyn ToSql)] {
193     #[inline]
__bind_in(self, stmt: &mut Statement<'_>) -> Result<()>194     fn __bind_in(self, stmt: &mut Statement<'_>) -> Result<()> {
195         stmt.bind_parameters_named(self)
196     }
197 }
198 
199 macro_rules! impl_for_array_ref {
200     ($($N:literal)+) => {$(
201         // These are already generic, and there's a shedload 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             #[inline]
218             fn __bind_in(self, stmt: &mut Statement<'_>) -> Result<()> {
219                 stmt.bind_parameters(&self)
220             }
221         }
222     )+};
223 }
224 
225 // Following libstd/libcore's (old) lead, implement this for arrays up to `[_;
226 // 32]`. Note `[_; 0]` is intentionally omitted for coherence reasons, see the
227 // note above the impl of `[&dyn ToSql; 0]` for more information.
228 impl_for_array_ref!(
229     1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
230     18 19 20 21 22 23 24 25 26 27 29 30 31 32
231 );
232 
233 /// Adapter type which allows any iterator over [`ToSql`] values to implement
234 /// [`Params`].
235 ///
236 /// This struct is created by the [`params_from_iter`] function.
237 ///
238 /// This can be useful if you have something like an `&[String]` (of unknown
239 /// length), and you want to use them with an API that wants something
240 /// implementing `Params`. This way, you can avoid having to allocate storage
241 /// for something like a `&[&dyn ToSql]`.
242 ///
243 /// This essentially is only ever actually needed when dynamically generating
244 /// SQL — static SQL (by definition) has the number of parameters known
245 /// statically. As dynamically generating SQL is itself pretty advanced, this
246 /// API is itself for advanced use cases (See "Realistic use case" in the
247 /// examples).
248 ///
249 /// # Example
250 ///
251 /// ## Basic usage
252 ///
253 /// ```rust,no_run
254 /// use rusqlite::{params_from_iter, Connection, Result};
255 /// use std::collections::BTreeSet;
256 ///
257 /// fn query(conn: &Connection, ids: &BTreeSet<String>) -> Result<()> {
258 ///     assert_eq!(ids.len(), 3, "Unrealistic sample code");
259 ///
260 ///     let mut stmt = conn.prepare("SELECT * FROM users WHERE id IN (?, ?, ?)")?;
261 ///     let _rows = stmt.query(params_from_iter(ids.iter()))?;
262 ///
263 ///     // use _rows...
264 ///     Ok(())
265 /// }
266 /// ```
267 ///
268 /// ## Realistic use case
269 ///
270 /// Here's how you'd use `ParamsFromIter` to call [`Statement::exists`] with a
271 /// dynamic number of parameters.
272 ///
273 /// ```rust,no_run
274 /// use rusqlite::{Connection, Result};
275 ///
276 /// pub fn any_active_users(conn: &Connection, usernames: &[String]) -> Result<bool> {
277 ///     if usernames.is_empty() {
278 ///         return Ok(false);
279 ///     }
280 ///
281 ///     // Note: `repeat_vars` never returns anything attacker-controlled, so
282 ///     // it's fine to use it in a dynamically-built SQL string.
283 ///     let vars = repeat_vars(usernames.len());
284 ///
285 ///     let sql = format!(
286 ///         // In practice this would probably be better as an `EXISTS` query.
287 ///         "SELECT 1 FROM user WHERE is_active AND name IN ({}) LIMIT 1",
288 ///         vars,
289 ///     );
290 ///     let mut stmt = conn.prepare(&sql)?;
291 ///     stmt.exists(rusqlite::params_from_iter(usernames))
292 /// }
293 ///
294 /// // Helper function to return a comma-separated sequence of `?`.
295 /// // - `repeat_vars(0) => panic!(...)`
296 /// // - `repeat_vars(1) => "?"`
297 /// // - `repeat_vars(2) => "?,?"`
298 /// // - `repeat_vars(3) => "?,?,?"`
299 /// // - ...
300 /// fn repeat_vars(count: usize) -> String {
301 ///     assert_ne!(count, 0);
302 ///     let mut s = "?,".repeat(count);
303 ///     // Remove trailing comma
304 ///     s.pop();
305 ///     s
306 /// }
307 /// ```
308 ///
309 /// That is fairly complex, and even so would need even more work to be fully
310 /// production-ready:
311 ///
312 /// - production code should ensure `usernames` isn't so large that it will
313 ///   surpass [`conn.limit(Limit::SQLITE_LIMIT_VARIABLE_NUMBER)`][limits]),
314 ///   chunking if too large. (Note that the limits api requires rusqlite to have
315 ///   the "limits" feature).
316 ///
317 /// - `repeat_vars` can be implemented in a way that avoids needing to allocate
318 ///   a String.
319 ///
320 /// - Etc...
321 ///
322 /// [limits]: crate::Connection::limit
323 ///
324 /// This complexity reflects the fact that `ParamsFromIter` is mainly intended
325 /// for advanced use cases — most of the time you should know how many
326 /// parameters you have statically (and if you don't, you're either doing
327 /// something tricky, or should take a moment to think about the design).
328 #[derive(Clone, Debug)]
329 pub struct ParamsFromIter<I>(I);
330 
331 /// Constructor function for a [`ParamsFromIter`]. See its documentation for
332 /// more.
333 #[inline]
params_from_iter<I>(iter: I) -> ParamsFromIter<I> where I: IntoIterator, I::Item: ToSql,334 pub fn params_from_iter<I>(iter: I) -> ParamsFromIter<I>
335 where
336     I: IntoIterator,
337     I::Item: ToSql,
338 {
339     ParamsFromIter(iter)
340 }
341 
342 impl<I> Sealed for ParamsFromIter<I>
343 where
344     I: IntoIterator,
345     I::Item: ToSql,
346 {
347 }
348 
349 impl<I> Params for ParamsFromIter<I>
350 where
351     I: IntoIterator,
352     I::Item: ToSql,
353 {
354     #[inline]
__bind_in(self, stmt: &mut Statement<'_>) -> Result<()>355     fn __bind_in(self, stmt: &mut Statement<'_>) -> Result<()> {
356         stmt.bind_parameters(self.0)
357     }
358 }
359