Skip to main content

diesel/query_builder/
sql_query.rs

1use super::Query;
2use crate::backend::{Backend, DieselReserveSpecialization};
3use crate::query_builder::{AstPass, QueryFragment, QueryId};
4use crate::query_dsl::RunQueryDslSupport;
5use crate::result::QueryResult;
6use crate::serialize::ToSql;
7use crate::sql_types::{HasSqlType, Untyped};
8use alloc::boxed::Box;
9use alloc::string::String;
10use alloc::string::ToString;
11use alloc::sync::Arc;
12use alloc::vec::Vec;
13use core::marker::PhantomData;
14
15#[derive(#[automatically_derived]
impl<Inner: ::core::fmt::Debug> ::core::fmt::Debug for SqlQuery<Inner> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field2_finish(f, "SqlQuery",
            "inner", &self.inner, "query", &&self.query)
    }
}Debug, #[automatically_derived]
impl<Inner: ::core::clone::Clone> ::core::clone::Clone for SqlQuery<Inner> {
    #[inline]
    fn clone(&self) -> Self {
        Self {
            inner: ::core::clone::Clone::clone(&self.inner),
            query: ::core::clone::Clone::clone(&self.query),
        }
    }
}Clone)]
16#[must_use = "Queries are only executed when calling `load`, `get_result` or similar."]
17/// The return value of `sql_query`.
18///
19/// Unlike most queries in Diesel, `SqlQuery` loads its data by column name,
20/// rather than by index. This means that you cannot deserialize this query into
21/// a tuple, and any structs used must implement `QueryableByName`.
22///
23/// See [`sql_query`](crate::sql_query()) for examples.
24pub struct SqlQuery<Inner = self::private::Empty> {
25    inner: Inner,
26    query: String,
27}
28
29impl<Inner> SqlQuery<Inner> {
30    pub(crate) fn new(inner: Inner, query: String) -> Self {
31        SqlQuery { inner, query }
32    }
33
34    /// Bind a value for use with this SQL query. The given query should have
35    /// placeholders that vary based on the database type,
36    /// like [SQLite Parameter](https://sqlite.org/lang_expr.html#varparam) syntax,
37    /// [PostgreSQL PREPARE syntax](https://www.postgresql.org/docs/current/sql-prepare.html),
38    /// or [MySQL bind syntax](https://dev.mysql.com/doc/refman/8.0/en/mysql-stmt-bind-param.html).
39    ///
40    /// For binding a variable number of values in a loop, use `into_boxed` first.
41    ///
42    /// # Safety
43    ///
44    /// This function should be used with care, as Diesel cannot validate that
45    /// the value is of the right type nor can it validate that you have passed
46    /// the correct number of parameters.
47    ///
48    /// # Example
49    ///
50    /// ```
51    /// # include!("../doctest_setup.rs");
52    /// #
53    /// # use schema::users;
54    /// #
55    /// # #[derive(QueryableByName, Debug, PartialEq)]
56    /// # struct User {
57    /// #     id: i32,
58    /// #     name: String,
59    /// # }
60    /// #
61    /// # fn main() {
62    /// #     use diesel::sql_query;
63    /// #     use diesel::sql_types::{Integer, Text};
64    /// #
65    /// #     let connection = &mut establish_connection();
66    /// #     diesel::insert_into(users::table)
67    /// #         .values(users::name.eq("Jim"))
68    /// #         .execute(connection).unwrap();
69    /// # #[cfg(feature = "postgres")]
70    /// # let users = sql_query("SELECT * FROM users WHERE id > $1 AND name != $2");
71    /// # #[cfg(not(feature = "postgres"))]
72    /// // sqlite/mysql bind syntax
73    /// let users = sql_query("SELECT * FROM users WHERE id > ? AND name <> ?")
74    /// # ;
75    /// # let users = users
76    ///     .bind::<Integer, _>(1)
77    ///     .bind::<Text, _>("Tess")
78    ///     .get_results(connection);
79    /// let expected_users = vec![User {
80    ///     id: 3,
81    ///     name: "Jim".into(),
82    /// }];
83    /// assert_eq!(Ok(expected_users), users);
84    /// # }
85    /// ```
86    pub fn bind<ST, Value>(self, value: Value) -> UncheckedBind<Self, Value, ST> {
87        UncheckedBind::new(self, value)
88    }
89
90    /// Internally boxes the query, which allows to  calls `bind` and `sql` so that they don't
91    /// change the type nor the instance. This allows to call `bind` or `sql`
92    /// in a loop, e.g.:
93    ///
94    /// ```
95    /// # include!("../doctest_setup.rs");
96    /// #
97    /// # use schema::users;
98    /// #
99    /// # #[derive(QueryableByName, Debug, PartialEq)]
100    /// # struct User {
101    /// #     id: i32,
102    /// #     name: String,
103    /// # }
104    /// #
105    /// # fn main() {
106    /// #     use diesel::sql_query;
107    /// #     use diesel::sql_types::{Integer};
108    /// #
109    /// #     let connection = &mut establish_connection();
110    /// #     diesel::insert_into(users::table)
111    /// #         .values(users::name.eq("Jim"))
112    /// #         .execute(connection).unwrap();
113    /// let mut q = diesel::sql_query("SELECT * FROM users WHERE id IN(").into_boxed();
114    /// for (idx, user_id) in [3, 4, 5].into_iter().enumerate() {
115    ///     if idx != 0 {
116    ///         q = q.sql(", ");
117    ///     }
118    /// # #[cfg(feature = "postgres")]
119    /// # {
120    ///     q = q
121    ///         // postgresql bind syntax
122    ///         .sql(format!("${}", idx + 1))
123    ///         .bind::<Integer, _>(user_id);
124    /// # }
125    /// # #[cfg(not(feature = "postgres"))]
126    /// # {
127    /// #   q = q
128    /// #       .sql(format!("?"))
129    /// #       .bind::<Integer, _>(user_id);
130    /// # }
131    /// }
132    /// let users = q.sql(");").get_results(connection);
133    /// let expected_users = vec![User {
134    ///     id: 3,
135    ///     name: "Jim".into(),
136    /// }];
137    /// assert_eq!(Ok(expected_users), users);
138    /// # }
139    /// ```
140    ///
141    /// This allows doing things you otherwise couldn't do, e.g. `bind`ing in a
142    /// loop.
143    ///
144    /// Boxed queries are not cloneable.
145    /// If you need cloning, use [`into_boxed_clone`] to create a [`BoxedCloneSqlQuery`].
146    ///
147    /// [`into_boxed_clone`]: SqlQuery::into_boxed_clone()
148    pub fn into_boxed<'f, DB: Backend>(self) -> BoxedSqlQuery<'f, DB, Self> {
149        BoxedSqlQuery::new(self)
150    }
151
152    /// Internally wraps the query in an [`Arc`], which allows to  calls `bind` and `sql` so that
153    /// they don't change the type nor the instance. This allows to clone the query and call
154    /// `bind` or `sql` in a loop, e.g.:
155    ///
156    /// ```
157    /// # include!("../doctest_setup.rs");
158    /// #
159    /// # use schema::users;
160    /// #
161    /// # #[derive(QueryableByName, Debug, PartialEq)]
162    /// # struct User {
163    /// #     id: i32,
164    /// #     name: String,
165    /// # }
166    /// #
167    /// # fn main() {
168    /// #     use diesel::sql_query;
169    /// #     use diesel::sql_types::{Integer};
170    /// #
171    /// #     let connection = &mut establish_connection();
172    /// #     diesel::insert_into(users::table)
173    /// #         .values(users::name.eq("Jim"))
174    /// #         .execute(connection).unwrap();
175    /// let q = diesel::sql_query("SELECT * FROM users WHERE id IN(").into_boxed_clone();
176    /// let mut q = q.clone();
177    /// for (idx, user_id) in [3, 4, 5].into_iter().enumerate() {
178    ///     if idx != 0 {
179    ///         q = q.sql(", ");
180    ///     }
181    /// # #[cfg(feature = "postgres")]
182    /// # {
183    ///     q = q
184    ///         // postgresql bind syntax
185    ///         .sql(format!("${}", idx + 1))
186    ///         .bind::<Integer, _>(user_id);
187    /// # }
188    /// # #[cfg(not(feature = "postgres"))]
189    /// # {
190    /// #   q = q
191    /// #       .sql(format!("?"))
192    /// #       .bind::<Integer, _>(user_id);
193    /// # }
194    /// }
195    /// let users = q.sql(");").get_results(connection);
196    /// let expected_users = vec![User {
197    ///     id: 3,
198    ///     name: "Jim".into(),
199    /// }];
200    /// assert_eq!(Ok(expected_users), users);
201    /// # }
202    /// ```
203    ///
204    /// This allows doing things you otherwise couldn't do, e.g. `bind`ing in a
205    /// loop.
206    ///
207    /// In cases where the query does not need to be cloned, [`BoxedSqlQuery`] (created with
208    /// [`into_boxed`]) provides better performance.
209    ///
210    /// [`into_boxed`]: SqlQuery::into_boxed()
211    pub fn into_boxed_clone<'f, DB: Backend>(self) -> BoxedCloneSqlQuery<'f, DB, Self> {
212        BoxedCloneSqlQuery::new(self)
213    }
214
215    /// Appends a piece of SQL code at the end.
216    ///
217    /// # Safety
218    ///
219    /// Diesel passes the given string to the database as written. It must
220    /// therefore never contain values that come from outside your own code,
221    /// because anything interpolated into the SQL text can carry an SQL
222    /// injection. Pass such values with [`bind`] instead.
223    ///
224    /// [`bind`]: SqlQuery::bind()
225    pub fn sql<T: AsRef<str>>(mut self, sql: T) -> Self {
226        self.query += sql.as_ref();
227        self
228    }
229}
230
231impl SqlQuery {
232    pub(crate) fn from_sql(query: String) -> SqlQuery {
233        Self {
234            inner: self::private::Empty,
235            query,
236        }
237    }
238}
239
240impl<DB, Inner> QueryFragment<DB> for SqlQuery<Inner>
241where
242    DB: Backend + DieselReserveSpecialization,
243    Inner: QueryFragment<DB>,
244{
245    fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
246        out.unsafe_to_cache_prepared();
247        self.inner.walk_ast(out.reborrow())?;
248        out.push_sql(&self.query);
249        Ok(())
250    }
251}
252
253impl<Inner> QueryId for SqlQuery<Inner> {
254    type QueryId = ();
255
256    const HAS_STATIC_QUERY_ID: bool = false;
257}
258
259impl<Inner> Query for SqlQuery<Inner> {
260    type SqlType = Untyped;
261}
262
263impl<Inner> RunQueryDslSupport for SqlQuery<Inner> {}
264
265#[derive(#[automatically_derived]
impl<Query: ::core::fmt::Debug, Value: ::core::fmt::Debug,
    ST: ::core::fmt::Debug> ::core::fmt::Debug for
    UncheckedBind<Query, Value, ST> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field3_finish(f, "UncheckedBind",
            "query", &self.query, "value", &self.value, "_marker",
            &&self._marker)
    }
}Debug, #[automatically_derived]
impl<Query: ::core::clone::Clone, Value: ::core::clone::Clone,
    ST: ::core::clone::Clone> ::core::clone::Clone for
    UncheckedBind<Query, Value, ST> {
    #[inline]
    fn clone(&self) -> Self {
        Self {
            query: ::core::clone::Clone::clone(&self.query),
            value: ::core::clone::Clone::clone(&self.value),
            _marker: ::core::clone::Clone::clone(&self._marker),
        }
    }
}Clone, #[automatically_derived]
impl<Query: ::core::marker::Copy, Value: ::core::marker::Copy,
    ST: ::core::marker::Copy> ::core::marker::Copy for
    UncheckedBind<Query, Value, ST> {
}Copy)]
266#[must_use = "Queries are only executed when calling `load`, `get_result` or similar."]
267/// Returned by the [`SqlQuery::bind()`] method when binding a value to a fragment of SQL.
268pub struct UncheckedBind<Query, Value, ST> {
269    query: Query,
270    value: Value,
271    _marker: PhantomData<ST>,
272}
273
274impl<Query, Value, ST> UncheckedBind<Query, Value, ST> {
275    pub fn new(query: Query, value: Value) -> Self {
276        UncheckedBind {
277            query,
278            value,
279            _marker: PhantomData,
280        }
281    }
282
283    pub fn bind<ST2, Value2>(self, value: Value2) -> UncheckedBind<Self, Value2, ST2> {
284        UncheckedBind::new(self, value)
285    }
286
287    pub fn into_boxed<'f, DB: Backend>(self) -> BoxedSqlQuery<'f, DB, Self> {
288        BoxedSqlQuery::new(self)
289    }
290
291    pub fn into_boxed_clone<'f, DB: Backend>(self) -> BoxedCloneSqlQuery<'f, DB, Self> {
292        BoxedCloneSqlQuery::new(self)
293    }
294
295    /// Append raw SQL after this query and the values bound to it.
296    ///
297    /// The wrapped query renders first, then the given SQL text. This allows
298    /// interleaving raw SQL fragments with [`bind`] calls when the query
299    /// builder cannot express the statement as a whole.
300    ///
301    /// # Safety
302    ///
303    /// Diesel passes the given string to the database as written. It must
304    /// therefore never contain values that come from outside your own code,
305    /// because anything interpolated into the SQL text can carry an SQL
306    /// injection. Pass such values with [`bind`] instead.
307    ///
308    /// # Examples
309    ///
310    /// ```rust
311    /// # include!("../doctest_setup.rs");
312    /// #
313    /// # use schema::users;
314    /// #
315    /// # #[derive(QueryableByName, Debug, PartialEq)]
316    /// # struct User {
317    /// #     id: i32,
318    /// #     name: String,
319    /// # }
320    /// #
321    /// # fn main() {
322    /// #     use diesel::sql_query;
323    /// #     use diesel::sql_types::Integer;
324    /// #
325    /// #     let connection = &mut establish_connection();
326    /// # #[cfg(feature = "postgres")]
327    /// # let base = sql_query("SELECT id, name FROM users WHERE id >= $1");
328    /// # #[cfg(not(feature = "postgres"))]
329    /// // Checkout the documentation of your database for the correct
330    /// // bind placeholder
331    /// let base = sql_query("SELECT id, name FROM users WHERE id >= ?");
332    /// // The appended fragment decides the order of the returned rows.
333    /// let users = base
334    ///     .bind::<Integer, _>(1)
335    ///     .sql(" ORDER BY id DESC")
336    ///     .load::<User>(connection);
337    /// assert_eq!(
338    ///     Ok(vec![
339    ///         User {
340    ///             id: 2,
341    ///             name: "Tess".into()
342    ///         },
343    ///         User {
344    ///             id: 1,
345    ///             name: "Sean".into()
346    ///         }
347    ///     ]),
348    ///     users
349    /// );
350    /// # }
351    /// ```
352    ///
353    /// [`bind`]: Self::bind()
354    pub fn sql<T: Into<String>>(self, sql: T) -> SqlQuery<Self> {
355        SqlQuery::new(self, sql.into())
356    }
357}
358
359impl<Query, Value, ST> QueryId for UncheckedBind<Query, Value, ST>
360where
361    Query: QueryId,
362    ST: QueryId,
363{
364    type QueryId = UncheckedBind<Query::QueryId, (), ST::QueryId>;
365
366    const HAS_STATIC_QUERY_ID: bool = Query::HAS_STATIC_QUERY_ID && ST::HAS_STATIC_QUERY_ID;
367}
368
369impl<Query, Value, ST, DB> QueryFragment<DB> for UncheckedBind<Query, Value, ST>
370where
371    DB: Backend + HasSqlType<ST> + DieselReserveSpecialization,
372    Query: QueryFragment<DB>,
373    Value: ToSql<ST, DB>,
374{
375    fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
376        self.query.walk_ast(out.reborrow())?;
377        out.push_bind_param_value_only(&self.value)?;
378        Ok(())
379    }
380}
381
382impl<Q, Value, ST> Query for UncheckedBind<Q, Value, ST> {
383    type SqlType = Untyped;
384}
385
386impl<Query, Value, ST> RunQueryDslSupport for UncheckedBind<Query, Value, ST> {}
387
388#[must_use = "Queries are only executed when calling `load`, `get_result`, or similar."]
389/// See [`SqlQuery::into_boxed`].
390///
391/// [`SqlQuery::into_boxed`]: SqlQuery::into_boxed()
392#[allow(missing_debug_implementations)]
393pub struct BoxedSqlQuery<'f, DB: Backend, Query> {
394    query: Query,
395    sql: String,
396    binds: Vec<Box<dyn QueryFragment<DB> + Send + 'f>>,
397}
398
399#[derive(#[automatically_derived]
#[allow(missing_debug_implementations)]
impl<'f, DB: ::core::clone::Clone + Backend, Query: ::core::clone::Clone>
    ::core::clone::Clone for BoxedCloneSqlQuery<'f, DB, Query> {
    #[inline]
    fn clone(&self) -> Self {
        Self {
            query: ::core::clone::Clone::clone(&self.query),
            sql: ::core::clone::Clone::clone(&self.sql),
            binds: ::core::clone::Clone::clone(&self.binds),
        }
    }
}Clone)]
400#[must_use = "Queries are only executed when calling `load`, `get_result`, or similar."]
401/// See [`SqlQuery::into_boxed_clone`].
402///
403/// [`SqlQuery::into_boxed_clone`]: SqlQuery::into_boxed_clone()
404#[allow(missing_debug_implementations)]
405pub struct BoxedCloneSqlQuery<'f, DB: Backend, Query> {
406    query: Query,
407    sql: String,
408    binds: Vec<Arc<dyn QueryFragment<DB> + Send + Sync + 'f>>,
409}
410
411struct RawBind<ST, U> {
412    value: U,
413    p: PhantomData<ST>,
414}
415
416impl<ST, U, DB> QueryFragment<DB> for RawBind<ST, U>
417where
418    DB: Backend + HasSqlType<ST>,
419    U: ToSql<ST, DB>,
420{
421    fn walk_ast<'b>(&'b self, mut pass: AstPass<'_, 'b, DB>) -> QueryResult<()> {
422        pass.push_bind_param_value_only(&self.value)
423    }
424}
425
426impl<'f, DB: Backend, Query> BoxedSqlQuery<'f, DB, Query> {
427    pub(crate) fn new(query: Query) -> Self {
428        BoxedSqlQuery {
429            query,
430            sql: "".to_string(),
431            binds: ::alloc::vec::Vec::new()alloc::vec![],
432        }
433    }
434
435    /// See [`SqlQuery::bind`].
436    ///
437    /// [`SqlQuery::bind`]: SqlQuery::bind()
438    pub fn bind<BindSt, Value>(mut self, b: Value) -> Self
439    where
440        DB: HasSqlType<BindSt>,
441        Value: ToSql<BindSt, DB> + Send + 'f,
442        BindSt: Send + 'f,
443    {
444        self.binds.push(Box::new(RawBind {
445            value: b,
446            p: PhantomData,
447        }) as Box<_>);
448        self
449    }
450
451    /// See [`SqlQuery::sql`].
452    ///
453    /// [`SqlQuery::sql`]: SqlQuery::sql()
454    pub fn sql<T: AsRef<str>>(mut self, sql: T) -> Self {
455        self.sql += sql.as_ref();
456        self
457    }
458}
459
460impl<DB, Query> QueryFragment<DB> for BoxedSqlQuery<'_, DB, Query>
461where
462    DB: Backend + DieselReserveSpecialization,
463    Query: QueryFragment<DB>,
464{
465    fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
466        out.unsafe_to_cache_prepared();
467        self.query.walk_ast(out.reborrow())?;
468        out.push_sql(&self.sql);
469
470        for b in &self.binds {
471            b.walk_ast(out.reborrow())?;
472        }
473        Ok(())
474    }
475}
476
477impl<DB: Backend, Query> QueryId for BoxedSqlQuery<'_, DB, Query> {
478    type QueryId = ();
479
480    const HAS_STATIC_QUERY_ID: bool = false;
481}
482
483impl<DB, Q> Query for BoxedSqlQuery<'_, DB, Q>
484where
485    DB: Backend,
486{
487    type SqlType = Untyped;
488}
489
490impl<DB: Backend, Query> RunQueryDslSupport for BoxedSqlQuery<'_, DB, Query> {}
491
492impl<'f, DB: Backend, Query> BoxedCloneSqlQuery<'f, DB, Query> {
493    pub(crate) fn new(query: Query) -> Self {
494        BoxedCloneSqlQuery {
495            query,
496            sql: "".to_string(),
497            binds: ::alloc::vec::Vec::new()alloc::vec![],
498        }
499    }
500
501    /// See [`SqlQuery::bind`].
502    ///
503    /// [`SqlQuery::bind`]: SqlQuery::bind()
504    pub fn bind<BindSt, Value>(mut self, b: Value) -> Self
505    where
506        DB: HasSqlType<BindSt>,
507        Value: ToSql<BindSt, DB> + Send + Sync + 'f,
508        BindSt: Send + Sync + 'f,
509    {
510        self.binds.push(Arc::new(RawBind {
511            value: b,
512            p: PhantomData,
513        }) as Arc<_>);
514        self
515    }
516
517    /// See [`SqlQuery::sql`].
518    ///
519    /// [`SqlQuery::sql`]: SqlQuery::sql()
520    pub fn sql<T: AsRef<str>>(mut self, sql: T) -> Self {
521        self.sql += sql.as_ref();
522        self
523    }
524}
525
526impl<DB, Query> QueryFragment<DB> for BoxedCloneSqlQuery<'_, DB, Query>
527where
528    DB: Backend + DieselReserveSpecialization,
529    Query: QueryFragment<DB>,
530{
531    fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
532        out.unsafe_to_cache_prepared();
533        self.query.walk_ast(out.reborrow())?;
534        out.push_sql(&self.sql);
535
536        for b in &self.binds {
537            b.walk_ast(out.reborrow())?;
538        }
539        Ok(())
540    }
541}
542
543impl<DB: Backend, Query> QueryId for BoxedCloneSqlQuery<'_, DB, Query> {
544    type QueryId = ();
545
546    const HAS_STATIC_QUERY_ID: bool = false;
547}
548
549impl<DB, Q> Query for BoxedCloneSqlQuery<'_, DB, Q>
550where
551    DB: Backend,
552{
553    type SqlType = Untyped;
554}
555
556impl<DB: Backend, Query> RunQueryDslSupport for BoxedCloneSqlQuery<'_, DB, Query> {}
557
558mod private {
559    use crate::backend::{Backend, DieselReserveSpecialization};
560    use crate::query_builder::{QueryFragment, QueryId};
561
562    #[derive(#[automatically_derived]
impl ::core::fmt::Debug for Empty {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f, "Empty")
    }
}Debug, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for Empty { }
#[automatically_derived]
impl ::core::clone::Clone for Empty {
    #[inline]
    fn clone(&self) -> Self { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for Empty { }Copy, const _: () =
    {
        use diesel;
        #[allow(non_camel_case_types)]
        impl diesel::query_builder::QueryId for Empty {
            type QueryId = Empty<>;
            const HAS_STATIC_QUERY_ID: bool = true;
            const IS_WINDOW_FUNCTION: bool = false;
        }
    };QueryId)]
563    pub struct Empty;
564
565    impl<DB> QueryFragment<DB> for Empty
566    where
567        DB: Backend + DieselReserveSpecialization,
568    {
569        fn walk_ast<'b>(
570            &'b self,
571            _pass: crate::query_builder::AstPass<'_, 'b, DB>,
572        ) -> crate::QueryResult<()> {
573            Ok(())
574        }
575    }
576}
577
578#[cfg(test)]
579mod tests {
580    fn assert_send<S: Send>(_: S) {}
581
582    #[diesel_test_helper::test]
583    fn check_boxed_sql_query_is_send() {
584        let query = crate::sql_query("SELECT 1")
585            .into_boxed::<<crate::test_helpers::TestConnection as crate::Connection>::Backend>(
586        );
587
588        assert_send(query);
589    }
590}