1use crate::expression::{Expression, ValidGrouping};
2use crate::pg::Pg;
3use crate::query_builder::{AsQuery, AstPass, FromClause, QueryFragment, QueryId, SelectStatement};
4use crate::query_source::private::PlainQuerySource;
5use crate::query_source::{QueryRelation, QuerySource, TableNotEqual};
6use crate::result::QueryResult;
7use crate::sql_types::{Double, SmallInt};
8use crate::{JoinTo, SelectableExpression, Table};
9use std::marker::PhantomData;
10
11#[doc(hidden)]
12pub trait TablesampleMethod: Clone {
13 fn method_name_sql() -> &'static str;
14}
15
16#[derive(#[automatically_derived]
impl ::core::clone::Clone for BernoulliMethod {
#[inline]
fn clone(&self) -> BernoulliMethod { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for BernoulliMethod { }Copy, #[automatically_derived]
impl ::core::fmt::Debug for BernoulliMethod {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f, "BernoulliMethod")
}
}Debug)]
17pub struct BernoulliMethod;
19
20impl TablesampleMethod for BernoulliMethod {
21 fn method_name_sql() -> &'static str {
22 "BERNOULLI"
23 }
24}
25
26#[derive(#[automatically_derived]
impl ::core::clone::Clone for SystemMethod {
#[inline]
fn clone(&self) -> SystemMethod { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for SystemMethod { }Copy, #[automatically_derived]
impl ::core::fmt::Debug for SystemMethod {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f, "SystemMethod")
}
}Debug)]
27pub struct SystemMethod;
29
30impl TablesampleMethod for SystemMethod {
31 fn method_name_sql() -> &'static str {
32 "SYSTEM"
33 }
34}
35
36#[derive(#[automatically_derived]
impl<S: ::core::fmt::Debug, TSM: ::core::fmt::Debug> ::core::fmt::Debug for
Tablesample<S, TSM> where TSM: TablesampleMethod {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field4_finish(f, "Tablesample",
"source", &self.source, "method", &self.method, "portion",
&self.portion, "seed", &&self.seed)
}
}Debug, #[automatically_derived]
impl<S: ::core::clone::Clone, TSM: ::core::clone::Clone> ::core::clone::Clone
for Tablesample<S, TSM> where TSM: TablesampleMethod {
#[inline]
fn clone(&self) -> Tablesample<S, TSM> {
Tablesample {
source: ::core::clone::Clone::clone(&self.source),
method: ::core::clone::Clone::clone(&self.method),
portion: ::core::clone::Clone::clone(&self.portion),
seed: ::core::clone::Clone::clone(&self.seed),
}
}
}Clone, #[automatically_derived]
impl<S: ::core::marker::Copy, TSM: ::core::marker::Copy> ::core::marker::Copy
for Tablesample<S, TSM> where TSM: TablesampleMethod {
}Copy)]
38pub struct Tablesample<S, TSM>
39where
40 TSM: TablesampleMethod,
41{
42 source: S,
43 method: PhantomData<TSM>,
44 portion: i16,
45 seed: Option<f64>,
46}
47
48impl<S, TSM> Tablesample<S, TSM>
49where
50 TSM: TablesampleMethod,
51{
52 pub(crate) fn new(source: S, portion: i16) -> Tablesample<S, TSM> {
53 Tablesample {
54 source,
55 method: PhantomData,
56 portion,
57 seed: None,
58 }
59 }
60
61 pub fn with_seed(self, seed: f64) -> Tablesample<S, TSM> {
64 Tablesample {
65 source: self.source,
66 method: self.method,
67 portion: self.portion,
68 seed: Some(seed),
69 }
70 }
71}
72
73#[diagnostic::do_not_recommend]
74impl<T1, T2, TSM> TableNotEqual<T1> for Tablesample<T2, TSM>
75where
76 T1: QueryRelation,
77 T2: TableNotEqual<T1>,
78 TSM: TablesampleMethod,
79 Self: Table,
80{
81}
82
83#[diagnostic::do_not_recommend]
84impl<T1, T2, TSM> TableNotEqual<Tablesample<T1, TSM>> for T2
85where
86 T1: QueryRelation,
87 T2: PlainQuerySource + TableNotEqual<T1>,
88 Tablesample<T1, TSM>: Table,
89 TSM: TablesampleMethod,
90{
91}
92
93impl<S, TSM> QueryId for Tablesample<S, TSM>
94where
95 S: QueryId,
96 TSM: TablesampleMethod,
97{
98 type QueryId = ();
99 const HAS_STATIC_QUERY_ID: bool = false;
100}
101
102impl<S, TSM> QuerySource for Tablesample<S, TSM>
103where
104 S: Table + Clone,
105 TSM: TablesampleMethod,
106 <S as QuerySource>::DefaultSelection:
107 ValidGrouping<()> + SelectableExpression<Tablesample<S, TSM>>,
108{
109 type FromClause = Self;
110 type DefaultSelection = <S as QuerySource>::DefaultSelection;
111
112 fn from_clause(&self) -> Self::FromClause {
113 self.clone()
114 }
115
116 fn default_selection(&self) -> Self::DefaultSelection {
117 self.source.default_selection()
118 }
119}
120
121impl<S, TSM> QueryFragment<Pg> for Tablesample<S, TSM>
122where
123 S: QueryFragment<Pg>,
124 TSM: TablesampleMethod,
125{
126 fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, Pg>) -> QueryResult<()> {
127 self.source.walk_ast(out.reborrow())?;
128 out.push_sql(" TABLESAMPLE ");
129 out.push_sql(TSM::method_name_sql());
130 out.push_sql("(");
131 out.push_bind_param::<SmallInt, _>(&self.portion)?;
132 out.push_sql(")");
133 if let Some(f) = &self.seed {
134 out.push_sql(" REPEATABLE(");
135 out.push_bind_param::<Double, _>(f)?;
136 out.push_sql(")");
137 }
138 Ok(())
139 }
140}
141
142impl<S, TSM> AsQuery for Tablesample<S, TSM>
143where
144 S: Table + Clone,
145 TSM: TablesampleMethod,
146 <S as QuerySource>::DefaultSelection:
147 ValidGrouping<()> + SelectableExpression<Tablesample<S, TSM>>,
148{
149 type SqlType = <<Self as QuerySource>::DefaultSelection as Expression>::SqlType;
150 type Query = SelectStatement<FromClause<Self>>;
151 fn as_query(self) -> Self::Query {
152 SelectStatement::simple(self)
153 }
154}
155
156impl<S, T, TSM> JoinTo<T> for Tablesample<S, TSM>
157where
158 S: JoinTo<T>,
159 T: Table,
160 S: Table,
161 TSM: TablesampleMethod,
162{
163 type FromClause = <S as JoinTo<T>>::FromClause;
164 type OnClause = <S as JoinTo<T>>::OnClause;
165
166 fn join_target(rhs: T) -> (Self::FromClause, Self::OnClause) {
167 <S as JoinTo<T>>::join_target(rhs)
168 }
169}
170
171impl<S, TSM> Table for Tablesample<S, TSM>
172where
173 S: Table + Clone + AsQuery,
174 TSM: TablesampleMethod,
175
176 <S as Table>::PrimaryKey: SelectableExpression<Tablesample<S, TSM>>,
177 <S as Table>::AllColumns: SelectableExpression<Tablesample<S, TSM>>,
178 <S as QuerySource>::DefaultSelection:
179 ValidGrouping<()> + SelectableExpression<Tablesample<S, TSM>>,
180{
181 type PrimaryKey = <S as Table>::PrimaryKey;
182 type AllColumns = <S as Table>::AllColumns;
183
184 fn primary_key(&self) -> Self::PrimaryKey {
185 self.source.primary_key()
186 }
187
188 fn all_columns() -> Self::AllColumns {
189 S::all_columns()
190 }
191}
192
193#[cfg(test)]
194mod test {
195 use super::*;
196 use crate::backend::Backend;
197 use crate::query_builder::QueryBuilder;
198 use diesel::dsl::*;
199 use diesel::*;
200
201 macro_rules! assert_sql {
202 ($query:expr, $sql:expr) => {
203 let mut query_builder = <Pg as Backend>::QueryBuilder::default();
204 $query.to_sql(&mut query_builder, &Pg).unwrap();
205 let sql = query_builder.finish();
206 assert_eq!(sql, $sql);
207 };
208 }
209
210 table! {
211 users {
212 id -> Integer,
213 name -> VarChar,
214 }
215 }
216
217 #[diesel_test_helper::test]
218 fn test_generated_tablesample_sql() {
219 assert_sql!(
220 users::table.tablesample_bernoulli(10),
221 "\"users\" TABLESAMPLE BERNOULLI($1)"
222 );
223
224 assert_sql!(
225 users::table.tablesample_system(10),
226 "\"users\" TABLESAMPLE SYSTEM($1)"
227 );
228
229 assert_sql!(
230 users::table.tablesample_system(10).with_seed(42.0),
231 "\"users\" TABLESAMPLE SYSTEM($1) REPEATABLE($2)"
232 );
233 }
234}