diesel/mysql/query_builder/
limit_offset.rs

1use crate::mysql::Mysql;
2use crate::query_builder::limit_clause::{LimitClause, NoLimitClause};
3use crate::query_builder::limit_offset_clause::{BoxedLimitOffsetClause, LimitOffsetClause};
4use crate::query_builder::offset_clause::{NoOffsetClause, OffsetClause};
5use crate::query_builder::{AstPass, IntoBoxedClause, QueryFragment};
6use crate::result::QueryResult;
7
8impl QueryFragment<Mysql> for LimitOffsetClause<NoLimitClause, NoOffsetClause> {
9    fn walk_ast<'b>(&'b self, _out: AstPass<'_, 'b, Mysql>) -> QueryResult<()> {
10        Ok(())
11    }
12}
13
14impl<L> QueryFragment<Mysql> for LimitOffsetClause<LimitClause<L>, NoOffsetClause>
15where
16    LimitClause<L>: QueryFragment<Mysql>,
17{
18    fn walk_ast<'b>(&'b self, out: AstPass<'_, 'b, Mysql>) -> QueryResult<()> {
19        self.limit_clause.walk_ast(out)?;
20        Ok(())
21    }
22}
23
24impl<L, O> QueryFragment<Mysql> for LimitOffsetClause<LimitClause<L>, OffsetClause<O>>
25where
26    LimitClause<L>: QueryFragment<Mysql>,
27    OffsetClause<O>: QueryFragment<Mysql>,
28{
29    fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, Mysql>) -> QueryResult<()> {
30        self.limit_clause.walk_ast(out.reborrow())?;
31        self.offset_clause.walk_ast(out.reborrow())?;
32        Ok(())
33    }
34}
35
36impl QueryFragment<Mysql> for BoxedLimitOffsetClause<'_, Mysql> {
37    fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, Mysql>) -> QueryResult<()> {
38        match (self.limit.as_ref(), self.offset.as_ref()) {
39            (Some(limit), Some(offset)) => {
40                limit.walk_ast(out.reborrow())?;
41                offset.walk_ast(out.reborrow())?;
42            }
43            (Some(limit), None) => {
44                limit.walk_ast(out.reborrow())?;
45            }
46            (None, Some(offset)) => {
47                // Mysql requires a limit clause in front of any offset clause
48                // The documentation proposes the following:
49                // > To retrieve all rows from a certain offset up to the end of the
50                // > result set, you can use some large number for the second parameter.
51                // https://dev.mysql.com/doc/refman/8.0/en/select.html
52                // Therefore we just use u64::MAX as limit here
53                // That does not result in any limitations because mysql only supports
54                // up to 64TB of data per table. Assuming 1 bit per row this means
55                // 1024 * 1024 * 1024 * 1024 * 8 = 562.949.953.421.312 rows which is smaller
56                // than 2^64 = 18.446.744.073.709.551.615
57                out.push_sql(" LIMIT 18446744073709551615 ");
58                offset.walk_ast(out.reborrow())?;
59            }
60            (None, None) => {}
61        }
62        Ok(())
63    }
64}
65
66impl<'a> IntoBoxedClause<'a, Mysql> for LimitOffsetClause<NoLimitClause, NoOffsetClause> {
67    type BoxedClause = BoxedLimitOffsetClause<'a, Mysql>;
68
69    fn into_boxed(self) -> Self::BoxedClause {
70        BoxedLimitOffsetClause {
71            limit: None,
72            offset: None,
73        }
74    }
75}
76
77impl<'a, L> IntoBoxedClause<'a, Mysql> for LimitOffsetClause<LimitClause<L>, NoOffsetClause>
78where
79    L: QueryFragment<Mysql> + Send + 'a,
80{
81    type BoxedClause = BoxedLimitOffsetClause<'a, Mysql>;
82
83    fn into_boxed(self) -> Self::BoxedClause {
84        BoxedLimitOffsetClause {
85            limit: Some(Box::new(self.limit_clause)),
86            offset: None,
87        }
88    }
89}
90
91impl<'a, L, O> IntoBoxedClause<'a, Mysql> for LimitOffsetClause<LimitClause<L>, OffsetClause<O>>
92where
93    L: QueryFragment<Mysql> + Send + 'a,
94    O: QueryFragment<Mysql> + Send + 'a,
95{
96    type BoxedClause = BoxedLimitOffsetClause<'a, Mysql>;
97
98    fn into_boxed(self) -> Self::BoxedClause {
99        BoxedLimitOffsetClause {
100            limit: Some(Box::new(self.limit_clause)),
101            offset: Some(Box::new(self.offset_clause)),
102        }
103    }
104}