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