Skip to main content

diesel/mysql_like/query_builder/
limit_offset.rs

1use crate::mysql_like::MysqlLikeBackend;
2use crate::query_builder::limit_clause::{LimitClause, NoLimitClause};
3use crate::query_builder::limit_offset_clause::{
4    BoxedCloneLimitOffsetClause, BoxedLimitOffsetClause, LimitOffsetClause,
5};
6use crate::query_builder::offset_clause::{NoOffsetClause, OffsetClause};
7use crate::query_builder::{AstPass, IntoBoxedClause, IntoBoxedCloneClause, QueryFragment};
8use crate::result::QueryResult;
9use alloc::sync::Arc;
10
11//#[diagnostic::do_not_recommend]
12impl<DB: MysqlLikeBackend> QueryFragment<DB> for LimitOffsetClause<NoLimitClause, NoOffsetClause> {
13    fn walk_ast<'b>(&'b self, _out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
14        Ok(())
15    }
16}
17
18//#[diagnostic::do_not_recommend]
19impl<DB: MysqlLikeBackend, L> QueryFragment<DB>
20    for LimitOffsetClause<LimitClause<L>, NoOffsetClause>
21where
22    LimitClause<L>: QueryFragment<DB>,
23{
24    fn walk_ast<'b>(&'b self, out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
25        self.limit_clause.walk_ast(out)?;
26        Ok(())
27    }
28}
29
30//#[diagnostic::do_not_recommend]
31impl<DB: MysqlLikeBackend, L, O> QueryFragment<DB>
32    for LimitOffsetClause<LimitClause<L>, OffsetClause<O>>
33where
34    LimitClause<L>: QueryFragment<DB>,
35    OffsetClause<O>: QueryFragment<DB>,
36{
37    fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
38        self.limit_clause.walk_ast(out.reborrow())?;
39        self.offset_clause.walk_ast(out.reborrow())?;
40        Ok(())
41    }
42}
43
44/// Walk the limit and the offset of a boxed limit/offset clause, whichever pointer holds them.
45fn walk_boxed_limit_offset<'b, DB, P>(
46    limit: Option<&'b P>,
47    offset: Option<&'b P>,
48    mut out: AstPass<'_, 'b, DB>,
49) -> QueryResult<()>
50where
51    DB: MysqlLikeBackend,
52    P: QueryFragment<DB>,
53{
54    match (limit, offset) {
55        (Some(limit), Some(offset)) => {
56            limit.walk_ast(out.reborrow())?;
57            offset.walk_ast(out.reborrow())?;
58        }
59        (Some(limit), None) => {
60            limit.walk_ast(out.reborrow())?;
61        }
62        (None, Some(offset)) => {
63            // Mysql requires a limit clause in front of any offset clause
64            // The documentation proposes the following:
65            // > To retrieve all rows from a certain offset up to the end of the
66            // > result set, you can use some large number for the second parameter.
67            // https://dev.mysql.com/doc/refman/8.0/en/select.html
68            // Therefore we just use u64::MAX as limit here
69            // That does not result in any limitations because Mysql only supports
70            // up to 64TB of data per table. Assuming 1 bit per row this means
71            // 1024 * 1024 * 1024 * 1024 * 8 = 562.949.953.421.312 rows which is smaller
72            // than 2^64 = 18.446.744.073.709.551.615
73            out.push_sql(" LIMIT 18446744073709551615 ");
74            offset.walk_ast(out.reborrow())?;
75        }
76        (None, None) => {}
77    }
78    Ok(())
79}
80
81#[diagnostic::do_not_recommend]
82impl<DB: MysqlLikeBackend> QueryFragment<DB> for BoxedLimitOffsetClause<'_, DB> {
83    fn walk_ast<'b>(&'b self, out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
84        walk_boxed_limit_offset(self.limit.as_ref(), self.offset.as_ref(), out)
85    }
86}
87
88#[diagnostic::do_not_recommend]
89impl<'a, DB: MysqlLikeBackend> IntoBoxedClause<'a, DB>
90    for LimitOffsetClause<NoLimitClause, NoOffsetClause>
91{
92    type BoxedClause = BoxedLimitOffsetClause<'a, DB>;
93
94    fn into_boxed(self) -> Self::BoxedClause {
95        BoxedLimitOffsetClause {
96            limit: None,
97            offset: None,
98        }
99    }
100}
101
102#[diagnostic::do_not_recommend]
103impl<'a, DB: MysqlLikeBackend, L> IntoBoxedClause<'a, DB>
104    for LimitOffsetClause<LimitClause<L>, NoOffsetClause>
105where
106    L: QueryFragment<DB> + Send + 'a,
107{
108    type BoxedClause = BoxedLimitOffsetClause<'a, DB>;
109
110    fn into_boxed(self) -> Self::BoxedClause {
111        BoxedLimitOffsetClause {
112            limit: Some(Box::new(self.limit_clause)),
113            offset: None,
114        }
115    }
116}
117
118#[diagnostic::do_not_recommend]
119impl<'a, DB: MysqlLikeBackend, L, O> IntoBoxedClause<'a, DB>
120    for LimitOffsetClause<LimitClause<L>, OffsetClause<O>>
121where
122    L: QueryFragment<DB> + Send + 'a,
123    O: QueryFragment<DB> + Send + 'a,
124{
125    type BoxedClause = BoxedLimitOffsetClause<'a, DB>;
126
127    fn into_boxed(self) -> Self::BoxedClause {
128        BoxedLimitOffsetClause {
129            limit: Some(Box::new(self.limit_clause)),
130            offset: Some(Box::new(self.offset_clause)),
131        }
132    }
133}
134
135impl<DB: MysqlLikeBackend> QueryFragment<DB> for BoxedCloneLimitOffsetClause<'_, DB> {
136    fn walk_ast<'b>(&'b self, out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
137        walk_boxed_limit_offset(self.limit.as_ref(), self.offset.as_ref(), out)
138    }
139}
140
141impl<'a, DB: MysqlLikeBackend> IntoBoxedCloneClause<'a, DB>
142    for LimitOffsetClause<NoLimitClause, NoOffsetClause>
143{
144    type BoxedCloneClause = BoxedCloneLimitOffsetClause<'a, DB>;
145
146    fn into_boxed_clone(self) -> Self::BoxedCloneClause {
147        BoxedCloneLimitOffsetClause {
148            limit: None,
149            offset: None,
150        }
151    }
152}
153
154impl<'a, DB: MysqlLikeBackend, L> IntoBoxedCloneClause<'a, DB>
155    for LimitOffsetClause<LimitClause<L>, NoOffsetClause>
156where
157    L: QueryFragment<DB> + Send + Sync + 'a,
158{
159    type BoxedCloneClause = BoxedCloneLimitOffsetClause<'a, DB>;
160
161    fn into_boxed_clone(self) -> Self::BoxedCloneClause {
162        BoxedCloneLimitOffsetClause {
163            limit: Some(Arc::new(self.limit_clause)),
164            offset: None,
165        }
166    }
167}
168
169impl<'a, DB: MysqlLikeBackend, L, O> IntoBoxedCloneClause<'a, DB>
170    for LimitOffsetClause<LimitClause<L>, OffsetClause<O>>
171where
172    L: QueryFragment<DB> + Send + Sync + 'a,
173    O: QueryFragment<DB> + Send + Sync + 'a,
174{
175    type BoxedCloneClause = BoxedCloneLimitOffsetClause<'a, DB>;
176
177    fn into_boxed_clone(self) -> Self::BoxedCloneClause {
178        BoxedCloneLimitOffsetClause {
179            limit: Some(Arc::new(self.limit_clause)),
180            offset: Some(Arc::new(self.offset_clause)),
181        }
182    }
183}