drizzle_core/expr/math.rs
1//! Math functions: `ABS`, `ROUND`, `CEIL`, `FLOOR`, `SQRT`, `POWER`, `LN`, ...
2//!
3//! Every function needs numeric arguments; passing text does not compile.
4//! Results keep the input's nullability and aggregate kind unless the function
5//! says otherwise.
6//!
7//! On SQLite, `CEIL`, `FLOOR`, `TRUNC`, `SQRT`, `POWER`, `EXP`, `LN`, `LOG`,
8//! `LOG10`, `LOG2` and `PI` exist only when SQLite was built with
9//! `SQLITE_ENABLE_MATH_FUNCTIONS`. Those functions compile for SQLite only
10//! with this crate's `math` feature (see [`MathExt`]).
11
12use crate::dialect::DialectTypes;
13use crate::sql::{SQL, Token};
14use crate::traits::SQLParam;
15use crate::types::{DataType, Integral, Numeric};
16use crate::{Dialect, MySQLDialect, PostgresDialect, SQLiteDialect};
17use drizzle_types::mysql::types::{
18 BigInt as MyBigInt, BigIntUnsigned as MyBigIntUnsigned, Decimal as MyDecimal,
19 Double as MyDouble, Float as MyFloat, Int as MyInt, IntUnsigned as MyIntUnsigned,
20 MediumInt as MyMediumInt, MediumIntUnsigned as MyMediumIntUnsigned, SmallInt as MySmallInt,
21 SmallIntUnsigned as MySmallIntUnsigned, TinyInt as MyTinyInt,
22 TinyIntUnsigned as MyTinyIntUnsigned, Year as MyYear,
23};
24use drizzle_types::postgres::types::{Float4, Float8, Int2, Int4, Int8, Numeric as PgNumeric};
25use drizzle_types::sqlite::types::{
26 Integer as SqliteInteger, Numeric as SqliteNumeric, Real as SqliteReal,
27};
28
29use super::{AggregateKind, Expr, Nullability, SQLExpr, Scalar};
30
31/// Dialects that provide the optional math functions.
32///
33/// `CEIL`, `FLOOR`, `TRUNC`, `SQRT`, `POWER`, `EXP`, `LN`, `LOG`, `LOG10`,
34/// `LOG2` and `PI` are built into PostgreSQL and MySQL. SQLite has them only
35/// when it is compiled with `SQLITE_ENABLE_MATH_FUNCTIONS`, which the bundled
36/// `rusqlite` and `libsql` builds do not set. Enabling the `math` cargo
37/// feature says that the linked SQLite has them. Without it, these functions
38/// do not compile for SQLite, instead of failing at runtime with "no such
39/// function".
40#[diagnostic::on_unimplemented(
41 message = "`{Self}` does not provide this math function",
42 label = "SQLite only has CEIL/FLOOR/TRUNC/SQRT/POWER/EXP/LN/LOG*/PI with SQLITE_ENABLE_MATH_FUNCTIONS",
43 note = "enable drizzle's `math` feature and build SQLite with the math functions, e.g. `LIBSQLITE3_FLAGS=\"-DSQLITE_ENABLE_MATH_FUNCTIONS\"` for bundled rusqlite"
44)]
45pub trait MathExt {}
46
47impl MathExt for PostgresDialect {}
48impl MathExt for MySQLDialect {}
49#[cfg(feature = "math")]
50impl MathExt for SQLiteDialect {}
51
52#[diagnostic::on_unimplemented(
53 message = "this math function is not available for this dialect",
54 label = "use a dialect-specific alternative"
55)]
56/// Dialects that provide `LOG2`, and the nullability of its result.
57///
58/// Implemented for SQLite and MySQL, which both return NULL outside the
59/// logarithm's domain. PostgreSQL has no `LOG2`.
60pub trait Log2Policy {
61 /// Nullability of the `LOG2` result.
62 type Nullable: Nullability;
63}
64
65impl Log2Policy for SQLiteDialect {
66 type Nullable = super::Null;
67}
68impl Log2Policy for MySQLDialect {
69 type Nullable = super::Null;
70}
71
72#[diagnostic::on_unimplemented(
73 message = "no rounding policy for `{Self}` on this dialect",
74 label = "round/ceil/floor/trunc return type is not defined for this SQL type/dialect"
75)]
76/// Result type of [`round`], [`round_to`], [`ceil`], [`floor`] and [`trunc`]
77/// for a numeric SQL type on dialect `D`.
78///
79/// | Dialect | Input | Result |
80/// |---|---|---|
81/// | SQLite | any numeric | `REAL` |
82/// | PostgreSQL | any numeric | `float8` (the call is cast to `DOUBLE PRECISION`) |
83/// | MySQL | signed integers | `BIGINT` |
84/// | MySQL | unsigned integers, `YEAR` | `BIGINT UNSIGNED` |
85/// | MySQL | `FLOAT`, `DOUBLE` | `DOUBLE` |
86/// | MySQL | `DECIMAL` | `DECIMAL` |
87pub trait RoundingPolicy<D>: Numeric {
88 /// Result type of the rounding functions.
89 type Output: DataType;
90
91 /// Prepares the operand of `ROUND(expr, precision)`.
92 ///
93 /// PostgreSQL only defines the two-argument `ROUND` for `numeric`, and
94 /// `double precision` does not cast to it implicitly.
95 fn precision_operand<'a, V: SQLParam + 'a>(expr: SQL<'a, V>) -> SQL<'a, V> {
96 expr
97 }
98
99 /// Coerces a rounding function's result to [`Self::Output`].
100 ///
101 /// PostgreSQL returns `numeric` for every rounding function unless the
102 /// argument is `double precision`; the declared output is `float8`.
103 fn coerce_result<'a, V: SQLParam + 'a>(sql: SQL<'a, V>) -> SQL<'a, V> {
104 sql
105 }
106}
107
108/// Casts a math function's result to `DOUBLE PRECISION` on PostgreSQL.
109///
110/// PostgreSQL resolves `SQRT`, `EXP`, `LN`, `LOG`, `POWER` and `SIGN` to their
111/// `numeric` overloads for integer or `numeric` arguments, while the declared
112/// result type is the dialect's double. The cast is a no-op for `float8`.
113pub(super) fn pg_double<'a, V: SQLParam + 'a>(sql: SQL<'a, V>) -> SQL<'a, V> {
114 match V::DIALECT {
115 Dialect::PostgreSQL => pg_cast(sql, "DOUBLE PRECISION"),
116 Dialect::SQLite | Dialect::MySQL => sql,
117 }
118}
119
120/// Renders `CAST(expr AS type_name)`.
121pub(super) fn pg_cast<'a, V: SQLParam + 'a>(
122 expr: SQL<'a, V>,
123 type_name: &'static str,
124) -> SQL<'a, V> {
125 SQL::func("CAST", expr.push(Token::AS).append(SQL::raw(type_name)))
126}
127
128impl RoundingPolicy<SQLiteDialect> for SqliteInteger {
129 type Output = SqliteReal;
130}
131impl RoundingPolicy<SQLiteDialect> for SqliteReal {
132 type Output = Self;
133}
134impl RoundingPolicy<SQLiteDialect> for SqliteNumeric {
135 type Output = SqliteReal;
136}
137
138// Integers and NUMERIC round through NUMERIC on PostgreSQL; the result is
139// cast to DOUBLE PRECISION so it decodes as the declared `Float8`.
140macro_rules! postgres_numeric_rounding_policy {
141 ($($ty:ty),+ $(,)?) => {
142 $(
143 impl RoundingPolicy<PostgresDialect> for $ty {
144 type Output = Float8;
145
146 fn coerce_result<'a, V: SQLParam + 'a>(sql: SQL<'a, V>) -> SQL<'a, V> {
147 pg_cast(sql, "DOUBLE PRECISION")
148 }
149 }
150 )+
151 };
152}
153postgres_numeric_rounding_policy!(Int2, Int4, Int8, PgNumeric);
154
155// Floats round natively, but `ROUND(float, n)` only exists for NUMERIC, so the
156// precision form casts in and back out.
157macro_rules! postgres_float_rounding_policy {
158 ($($ty:ty),+ $(,)?) => {
159 $(
160 impl RoundingPolicy<PostgresDialect> for $ty {
161 type Output = Float8;
162
163 fn precision_operand<'a, V: SQLParam + 'a>(expr: SQL<'a, V>) -> SQL<'a, V> {
164 pg_cast(expr, "NUMERIC")
165 }
166
167 fn coerce_result<'a, V: SQLParam + 'a>(sql: SQL<'a, V>) -> SQL<'a, V> {
168 pg_cast(sql, "DOUBLE PRECISION")
169 }
170 }
171 )+
172 };
173}
174postgres_float_rounding_policy!(Float4, Float8);
175
176macro_rules! mysql_rounding_policy {
177 ($output:ty; $($ty:ty),+ $(,)?) => {
178 $(
179 impl RoundingPolicy<MySQLDialect> for $ty {
180 type Output = $output;
181 }
182 )+
183 };
184}
185
186mysql_rounding_policy!(MyBigInt; MyTinyInt, MySmallInt, MyMediumInt, MyInt, MyBigInt,);
187mysql_rounding_policy!(MyBigIntUnsigned;
188 MyTinyIntUnsigned,
189 MySmallIntUnsigned,
190 MyMediumIntUnsigned,
191 MyIntUnsigned,
192 MyBigIntUnsigned,
193 MyYear,
194);
195
196impl RoundingPolicy<MySQLDialect> for MyFloat {
197 type Output = MyDouble;
198}
199impl RoundingPolicy<MySQLDialect> for MyDouble {
200 type Output = Self;
201}
202impl RoundingPolicy<MySQLDialect> for MyDecimal {
203 type Output = Self;
204}
205
206// =============================================================================
207// ABSOLUTE VALUE
208// =============================================================================
209
210/// Absolute value (`ABS`).
211///
212/// The argument must be numeric. The result keeps the argument's SQL type,
213/// nullability and aggregate kind.
214///
215/// # Examples
216///
217/// ```rust
218/// # use drizzle_core::dialect::{Dialect, DialectTypes, SQLiteDialect as D};
219/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
220/// # #[derive(Clone, Debug)] struct Value(String);
221/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::SQLite; type DialectMarker = D; }
222/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
223/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
224/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
225/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
226/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
227/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
228/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
229/// assert_eq!(abs(users.score).sql(), r#"ABS ("users"."score")"#);
230/// ```
231///
232/// # Type safety
233///
234/// `ABS` of a text column does not compile:
235///
236/// ```rust,compile_fail
237/// # use drizzle_core::dialect::{Dialect, DialectTypes, SQLiteDialect as D};
238/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
239/// # #[derive(Clone, Debug)] struct Value(String);
240/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::SQLite; type DialectMarker = D; }
241/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
242/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
243/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
244/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
245/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
246/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
247/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
248/// let wrong = abs(users.name);
249/// ```
250pub fn abs<'a, V, E>(expr: E) -> SQLExpr<'a, V, E::SQLType, E::Nullable, E::Aggregate, E::Sources>
251where
252 V: SQLParam + 'a,
253 E: Expr<'a, V>,
254 E::SQLType: Numeric,
255{
256 SQLExpr::new(SQL::func("ABS", expr.into_sql()))
257}
258
259// =============================================================================
260// ROUNDING FUNCTIONS
261// =============================================================================
262
263/// Rounds to the nearest integer (`ROUND(expr)`).
264///
265/// The argument must be numeric. The result type comes from
266/// [`RoundingPolicy`] (`REAL` on SQLite, `float8` on PostgreSQL, the
267/// matching integer or decimal type on MySQL) and keeps the argument's
268/// nullability.
269///
270/// # Examples
271///
272/// ```rust
273/// # use drizzle_core::dialect::{Dialect, DialectTypes, SQLiteDialect as D};
274/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
275/// # #[derive(Clone, Debug)] struct Value(String);
276/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::SQLite; type DialectMarker = D; }
277/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
278/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
279/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
280/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
281/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
282/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
283/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
284/// assert_eq!(round(users.score).sql(), r#"ROUND ("users"."score")"#);
285/// ```
286#[allow(clippy::type_complexity)]
287pub fn round<'a, V, E>(
288 expr: E,
289) -> SQLExpr<
290 'a,
291 V,
292 <E::SQLType as RoundingPolicy<V::DialectMarker>>::Output,
293 E::Nullable,
294 E::Aggregate,
295 E::Sources,
296>
297where
298 V: SQLParam + 'a,
299 E: Expr<'a, V>,
300 E::SQLType: RoundingPolicy<V::DialectMarker>,
301{
302 SQLExpr::new(
303 <E::SQLType as RoundingPolicy<V::DialectMarker>>::coerce_result(SQL::func(
304 "ROUND",
305 expr.into_sql(),
306 )),
307 )
308}
309
310/// Rounds to `precision` decimal places (`ROUND(expr, precision)`).
311///
312/// `expr` must be numeric and `precision` an integer. The result type comes
313/// from [`RoundingPolicy`]; it is nullable if either argument is. On
314/// PostgreSQL a float argument is cast to `NUMERIC` first, because only
315/// `ROUND(numeric, int)` exists there.
316///
317/// # Examples
318///
319/// ```rust
320/// # use drizzle_core::dialect::{Dialect, DialectTypes, SQLiteDialect as D};
321/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
322/// # #[derive(Clone, Debug)] struct Value(String);
323/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::SQLite; type DialectMarker = D; }
324/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
325/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
326/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
327/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
328/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
329/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
330/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
331/// assert_eq!(round_to(users.score, 2).sql(), r#"ROUND ("users"."score", ?)"#);
332/// ```
333#[allow(clippy::type_complexity)]
334pub fn round_to<'a, V, E, P>(
335 expr: E,
336 precision: P,
337) -> SQLExpr<
338 'a,
339 V,
340 <E::SQLType as RoundingPolicy<V::DialectMarker>>::Output,
341 <E::Nullable as Nullability>::Or<P::Nullable>,
342 <E::Aggregate as AggregateKind>::Or<P::Aggregate>,
343 (E::Sources, P::Sources),
344>
345where
346 V: SQLParam + 'a,
347 E: Expr<'a, V>,
348 E::SQLType: RoundingPolicy<V::DialectMarker>,
349 P: Expr<'a, V>,
350 P::SQLType: Integral,
351 P::Nullable: Nullability,
352{
353 SQLExpr::new(
354 <E::SQLType as RoundingPolicy<V::DialectMarker>>::coerce_result(SQL::func(
355 "ROUND",
356 <E::SQLType as RoundingPolicy<V::DialectMarker>>::precision_operand(expr.into_sql())
357 .push(Token::COMMA)
358 .append(precision.into_sql()),
359 )),
360 )
361}
362
363/// Rounds up to the nearest integer (`CEIL`).
364///
365/// The argument must be numeric. The result type comes from
366/// [`RoundingPolicy`] and keeps the argument's nullability. On SQLite this
367/// needs the `math` feature (see [`MathExt`]).
368///
369/// # Examples
370///
371/// ```rust
372/// # use drizzle_core::dialect::{Dialect, DialectTypes, PostgresDialect as D};
373/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
374/// # #[derive(Clone, Debug)] struct Value(String);
375/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::PostgreSQL; type DialectMarker = D; }
376/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
377/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
378/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
379/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
380/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
381/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
382/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
383/// assert_eq!(
384/// ceil(users.score).sql(),
385/// r#"CAST (CEIL ("users"."score") AS DOUBLE PRECISION)"#
386/// );
387/// ```
388#[allow(clippy::type_complexity)]
389pub fn ceil<'a, V, E>(
390 expr: E,
391) -> SQLExpr<
392 'a,
393 V,
394 <E::SQLType as RoundingPolicy<V::DialectMarker>>::Output,
395 E::Nullable,
396 E::Aggregate,
397 E::Sources,
398>
399where
400 V: SQLParam + 'a,
401 V::DialectMarker: MathExt,
402 E: Expr<'a, V>,
403 E::SQLType: RoundingPolicy<V::DialectMarker>,
404{
405 SQLExpr::new(
406 <E::SQLType as RoundingPolicy<V::DialectMarker>>::coerce_result(SQL::func(
407 "CEIL",
408 expr.into_sql(),
409 )),
410 )
411}
412
413/// Rounds down to the nearest integer (`FLOOR`).
414///
415/// The argument must be numeric. The result type comes from
416/// [`RoundingPolicy`] and keeps the argument's nullability. On SQLite this
417/// needs the `math` feature (see [`MathExt`]).
418///
419/// # Examples
420///
421/// ```rust
422/// # use drizzle_core::dialect::{Dialect, DialectTypes, PostgresDialect as D};
423/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
424/// # #[derive(Clone, Debug)] struct Value(String);
425/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::PostgreSQL; type DialectMarker = D; }
426/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
427/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
428/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
429/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
430/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
431/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
432/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
433/// assert_eq!(
434/// floor(users.score).sql(),
435/// r#"CAST (FLOOR ("users"."score") AS DOUBLE PRECISION)"#
436/// );
437/// ```
438#[allow(clippy::type_complexity)]
439pub fn floor<'a, V, E>(
440 expr: E,
441) -> SQLExpr<
442 'a,
443 V,
444 <E::SQLType as RoundingPolicy<V::DialectMarker>>::Output,
445 E::Nullable,
446 E::Aggregate,
447 E::Sources,
448>
449where
450 V: SQLParam + 'a,
451 V::DialectMarker: MathExt,
452 E: Expr<'a, V>,
453 E::SQLType: RoundingPolicy<V::DialectMarker>,
454{
455 SQLExpr::new(
456 <E::SQLType as RoundingPolicy<V::DialectMarker>>::coerce_result(SQL::func(
457 "FLOOR",
458 expr.into_sql(),
459 )),
460 )
461}
462
463/// Truncates toward zero.
464///
465/// Renders `TRUNC(expr)` on SQLite and PostgreSQL and `TRUNCATE(expr, 0)` on
466/// MySQL. The argument must be numeric. The result type comes from
467/// [`RoundingPolicy`] and keeps the argument's nullability. On SQLite this
468/// needs the `math` feature (see [`MathExt`]).
469///
470/// # Examples
471///
472/// ```rust
473/// # use drizzle_core::dialect::{Dialect, DialectTypes, PostgresDialect as D};
474/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
475/// # #[derive(Clone, Debug)] struct Value(String);
476/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::PostgreSQL; type DialectMarker = D; }
477/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
478/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
479/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
480/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
481/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
482/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
483/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
484/// assert_eq!(
485/// trunc(users.score).sql(),
486/// r#"CAST (TRUNC ("users"."score") AS DOUBLE PRECISION)"#
487/// );
488/// ```
489#[allow(clippy::type_complexity)]
490pub fn trunc<'a, V, E>(
491 expr: E,
492) -> SQLExpr<
493 'a,
494 V,
495 <E::SQLType as RoundingPolicy<V::DialectMarker>>::Output,
496 E::Nullable,
497 E::Aggregate,
498 E::Sources,
499>
500where
501 V: SQLParam + 'a,
502 V::DialectMarker: MathExt,
503 E: Expr<'a, V>,
504 E::SQLType: RoundingPolicy<V::DialectMarker>,
505{
506 let expr = expr.into_sql();
507 let truncated = match V::DIALECT {
508 Dialect::MySQL => SQL::func("TRUNCATE", expr.push(Token::COMMA).append(SQL::raw("0"))),
509 Dialect::SQLite | Dialect::PostgreSQL => SQL::func("TRUNC", expr),
510 };
511 SQLExpr::new(<E::SQLType as RoundingPolicy<V::DialectMarker>>::coerce_result(truncated))
512}
513
514// =============================================================================
515// POWER AND ROOT FUNCTIONS
516// =============================================================================
517
518/// Square root (`SQRT`).
519///
520/// The argument must be numeric. The result is the dialect's double type. On
521/// SQLite and MySQL a negative argument gives NULL, so the result is
522/// nullable there; PostgreSQL raises an error instead and keeps the
523/// argument's nullability. On SQLite this needs the `math` feature.
524///
525/// # Examples
526///
527/// ```rust
528/// # use drizzle_core::dialect::{Dialect, DialectTypes, PostgresDialect as D};
529/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
530/// # #[derive(Clone, Debug)] struct Value(String);
531/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::PostgreSQL; type DialectMarker = D; }
532/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
533/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
534/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
535/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
536/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
537/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
538/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
539/// assert_eq!(
540/// sqrt(users.score).sql(),
541/// r#"CAST (SQRT ("users"."score") AS DOUBLE PRECISION)"#
542/// );
543/// ```
544#[allow(clippy::type_complexity)]
545pub fn sqrt<'a, V, E>(
546 expr: E,
547) -> SQLExpr<
548 'a,
549 V,
550 <V::DialectMarker as DialectTypes>::Double,
551 <V::DialectMarker as DialectTypes>::DomainNullable<E::Nullable>,
552 E::Aggregate,
553 E::Sources,
554>
555where
556 V: SQLParam + 'a,
557 V::DialectMarker: MathExt,
558 E: Expr<'a, V>,
559 E::SQLType: Numeric,
560{
561 SQLExpr::new(pg_double(SQL::func("SQRT", expr.into_sql())))
562}
563
564/// `base` raised to `exponent` (`POWER`).
565///
566/// Both arguments must be numeric. The result is the dialect's double type,
567/// nullable if either argument is. On SQLite this needs the `math` feature.
568///
569/// # Examples
570///
571/// ```rust
572/// # use drizzle_core::dialect::{Dialect, DialectTypes, PostgresDialect as D};
573/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
574/// # #[derive(Clone, Debug)] struct Value(String);
575/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::PostgreSQL; type DialectMarker = D; }
576/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
577/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
578/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
579/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
580/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
581/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
582/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
583/// assert_eq!(
584/// power(users.age, 2).sql(),
585/// r#"CAST (POWER ("users"."age", $1) AS DOUBLE PRECISION)"#
586/// );
587/// ```
588#[allow(clippy::type_complexity)]
589pub fn power<'a, V, E1, E2>(
590 base: E1,
591 exponent: E2,
592) -> SQLExpr<
593 'a,
594 V,
595 <V::DialectMarker as DialectTypes>::Double,
596 <E1::Nullable as Nullability>::Or<E2::Nullable>,
597 <E1::Aggregate as AggregateKind>::Or<E2::Aggregate>,
598 (E1::Sources, E2::Sources),
599>
600where
601 V: SQLParam + 'a,
602 V::DialectMarker: MathExt,
603 E1: Expr<'a, V>,
604 E1::SQLType: Numeric,
605 E2: Expr<'a, V>,
606 E2::SQLType: Numeric,
607 E2::Nullable: Nullability,
608{
609 SQLExpr::new(pg_double(SQL::func(
610 "POWER",
611 base.into_sql()
612 .push(Token::COMMA)
613 .append(exponent.into_sql()),
614 )))
615}
616
617// =============================================================================
618// LOGARITHMIC AND EXPONENTIAL FUNCTIONS
619// =============================================================================
620
621/// e raised to the argument (`EXP`).
622///
623/// The argument must be numeric. The result is the dialect's double type and
624/// keeps the argument's nullability. On SQLite this needs the `math` feature.
625///
626/// # Examples
627///
628/// ```rust
629/// # use drizzle_core::dialect::{Dialect, DialectTypes, PostgresDialect as D};
630/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
631/// # #[derive(Clone, Debug)] struct Value(String);
632/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::PostgreSQL; type DialectMarker = D; }
633/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
634/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
635/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
636/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
637/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
638/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
639/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
640/// assert_eq!(
641/// exp(users.score).sql(),
642/// r#"CAST (EXP ("users"."score") AS DOUBLE PRECISION)"#
643/// );
644/// ```
645#[allow(clippy::type_complexity)]
646pub fn exp<'a, V, E>(
647 expr: E,
648) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Double, E::Nullable, E::Aggregate, E::Sources>
649where
650 V: SQLParam + 'a,
651 V::DialectMarker: MathExt,
652 E: Expr<'a, V>,
653 E::SQLType: Numeric,
654{
655 SQLExpr::new(pg_double(SQL::func("EXP", expr.into_sql())))
656}
657
658/// Natural logarithm (`LN`).
659///
660/// The argument must be numeric. The result is the dialect's double type. On
661/// SQLite and MySQL an argument outside the domain (zero or negative) gives
662/// NULL, so the result is nullable there; PostgreSQL raises an error instead
663/// and keeps the argument's nullability. On SQLite this needs the `math`
664/// feature.
665///
666/// # Examples
667///
668/// ```rust
669/// # use drizzle_core::dialect::{Dialect, DialectTypes, PostgresDialect as D};
670/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
671/// # #[derive(Clone, Debug)] struct Value(String);
672/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::PostgreSQL; type DialectMarker = D; }
673/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
674/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
675/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
676/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
677/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
678/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
679/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
680/// assert_eq!(
681/// ln(users.score).sql(),
682/// r#"CAST (LN ("users"."score") AS DOUBLE PRECISION)"#
683/// );
684/// ```
685#[allow(clippy::type_complexity)]
686pub fn ln<'a, V, E>(
687 expr: E,
688) -> SQLExpr<
689 'a,
690 V,
691 <V::DialectMarker as DialectTypes>::Double,
692 <V::DialectMarker as DialectTypes>::DomainNullable<E::Nullable>,
693 E::Aggregate,
694 E::Sources,
695>
696where
697 V: SQLParam + 'a,
698 V::DialectMarker: MathExt,
699 E: Expr<'a, V>,
700 E::SQLType: Numeric,
701{
702 SQLExpr::new(pg_double(SQL::func("LN", expr.into_sql())))
703}
704
705/// Base-10 logarithm (`LOG10`).
706///
707/// The argument must be numeric. The result is the dialect's double type. On
708/// SQLite and MySQL an argument outside the domain (zero or negative) gives
709/// NULL, so the result is nullable there; PostgreSQL raises an error instead
710/// and keeps the argument's nullability. On SQLite this needs the `math`
711/// feature.
712///
713/// # Examples
714///
715/// ```rust
716/// # use drizzle_core::dialect::{Dialect, DialectTypes, PostgresDialect as D};
717/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
718/// # #[derive(Clone, Debug)] struct Value(String);
719/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::PostgreSQL; type DialectMarker = D; }
720/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
721/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
722/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
723/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
724/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
725/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
726/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
727/// assert_eq!(
728/// log10(users.score).sql(),
729/// r#"CAST (LOG10 ("users"."score") AS DOUBLE PRECISION)"#
730/// );
731/// ```
732#[allow(clippy::type_complexity)]
733pub fn log10<'a, V, E>(
734 expr: E,
735) -> SQLExpr<
736 'a,
737 V,
738 <V::DialectMarker as DialectTypes>::Double,
739 <V::DialectMarker as DialectTypes>::DomainNullable<E::Nullable>,
740 E::Aggregate,
741 E::Sources,
742>
743where
744 V: SQLParam + 'a,
745 V::DialectMarker: MathExt,
746 E: Expr<'a, V>,
747 E::SQLType: Numeric,
748{
749 SQLExpr::new(pg_double(SQL::func("LOG10", expr.into_sql())))
750}
751
752/// Logarithm of `value` in base `base` (`LOG(base, value)`).
753///
754/// Both arguments must be numeric. The result is the dialect's double type.
755/// It is nullable if either argument is, and always nullable on SQLite and
756/// MySQL, which return NULL outside the domain. On PostgreSQL both arguments
757/// are cast to `NUMERIC`, since only `LOG(numeric, numeric)` exists there. On
758/// SQLite this needs the `math` feature.
759///
760/// # Examples
761///
762/// ```rust
763/// # use drizzle_core::dialect::{Dialect, DialectTypes, PostgresDialect as D};
764/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
765/// # #[derive(Clone, Debug)] struct Value(String);
766/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::PostgreSQL; type DialectMarker = D; }
767/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
768/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
769/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
770/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
771/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
772/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
773/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
774/// assert_eq!(
775/// log(2, users.score).sql(),
776/// r#"CAST (LOG (CAST ($1 AS NUMERIC), CAST ("users"."score" AS NUMERIC)) AS DOUBLE PRECISION)"#
777/// );
778/// ```
779#[allow(clippy::type_complexity)]
780pub fn log<'a, V, E1, E2>(
781 base: E1,
782 value: E2,
783) -> SQLExpr<
784 'a,
785 V,
786 <V::DialectMarker as DialectTypes>::Double,
787 <V::DialectMarker as DialectTypes>::DomainNullable<
788 <E1::Nullable as Nullability>::Or<E2::Nullable>,
789 >,
790 <E1::Aggregate as AggregateKind>::Or<E2::Aggregate>,
791 (E1::Sources, E2::Sources),
792>
793where
794 V: SQLParam + 'a,
795 V::DialectMarker: MathExt,
796 E1: Expr<'a, V>,
797 E1::SQLType: Numeric,
798 E2: Expr<'a, V>,
799 E2::SQLType: Numeric,
800 E2::Nullable: Nullability,
801{
802 let (base, value) = (base.into_sql(), value.into_sql());
803 // PostgreSQL only defines the two-argument LOG for NUMERIC operands.
804 let (base, value) = match V::DIALECT {
805 Dialect::PostgreSQL => (pg_cast(base, "NUMERIC"), pg_cast(value, "NUMERIC")),
806 Dialect::SQLite | Dialect::MySQL => (base, value),
807 };
808 SQLExpr::new(pg_double(SQL::func(
809 "LOG",
810 base.push(Token::COMMA).append(value),
811 )))
812}
813
814// =============================================================================
815// SIGN AND MODULO
816// =============================================================================
817
818/// Sign of a number: -1, 0 or 1 (`SIGN`).
819///
820/// The argument must be numeric. The result is the dialect's
821/// [`Sign`](DialectTypes::Sign) type: an integer on SQLite and MySQL,
822/// `float8` on PostgreSQL. It keeps the argument's nullability.
823///
824/// # Examples
825///
826/// ```rust
827/// # use drizzle_core::dialect::{Dialect, DialectTypes, SQLiteDialect as D};
828/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
829/// # #[derive(Clone, Debug)] struct Value(String);
830/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::SQLite; type DialectMarker = D; }
831/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
832/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
833/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
834/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
835/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
836/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
837/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
838/// assert_eq!(sign(users.score).sql(), r#"SIGN ("users"."score")"#);
839/// ```
840#[allow(clippy::type_complexity)]
841pub fn sign<'a, V, E>(
842 expr: E,
843) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Sign, E::Nullable, E::Aggregate, E::Sources>
844where
845 V: SQLParam + 'a,
846 E: Expr<'a, V>,
847 E::SQLType: Numeric,
848{
849 SQLExpr::new(pg_double(SQL::func("SIGN", expr.into_sql())))
850}
851
852/// Remainder of a division, rendered with the `%` operator.
853///
854/// Both arguments must be numeric. The result has the dividend's SQL type and
855/// is nullable if either argument is. Named `mod_` because `mod` is a Rust
856/// keyword. `expr % n` on an [`SQLExpr`] renders the same SQL, but types the
857/// result through [`ArithmeticOutput`](crate::types::ArithmeticOutput), which
858/// also marks it nullable on SQLite and MySQL (where `x % 0` is NULL).
859///
860/// # Examples
861///
862/// ```rust
863/// # use drizzle_core::dialect::{Dialect, DialectTypes, SQLiteDialect as D};
864/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
865/// # #[derive(Clone, Debug)] struct Value(String);
866/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::SQLite; type DialectMarker = D; }
867/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
868/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
869/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
870/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
871/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
872/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
873/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
874/// assert_eq!(mod_(users.age, 10).sql(), r#""users"."age" % ?"#);
875/// ```
876#[allow(clippy::type_complexity)]
877pub fn mod_<'a, V, E1, E2>(
878 dividend: E1,
879 divisor: E2,
880) -> SQLExpr<
881 'a,
882 V,
883 E1::SQLType,
884 <E1::Nullable as Nullability>::Or<E2::Nullable>,
885 <E1::Aggregate as AggregateKind>::Or<E2::Aggregate>,
886 (E1::Sources, E2::Sources),
887>
888where
889 V: SQLParam + 'a,
890 E1: Expr<'a, V>,
891 E1::SQLType: Numeric,
892 E2: Expr<'a, V>,
893 E2::SQLType: Numeric,
894 E2::Nullable: Nullability,
895{
896 SQLExpr::new(super::ops::binary_operator_sql(
897 dividend.into_expr_sql(),
898 Token::REM,
899 divisor.into_expr_sql(),
900 ))
901}
902
903// =============================================================================
904// CONSTANTS AND RANDOM
905// =============================================================================
906
907/// The constant pi (`PI()`).
908///
909/// The result is the dialect's double type and never NULL. Available on
910/// PostgreSQL and MySQL, and on SQLite with the `math` feature.
911///
912/// # Examples
913///
914/// ```rust
915/// # use drizzle_core::dialect::{Dialect, DialectTypes, PostgresDialect as D};
916/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
917/// # #[derive(Clone, Debug)] struct Value(String);
918/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::PostgreSQL; type DialectMarker = D; }
919/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
920/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
921/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
922/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
923/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
924/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
925/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
926/// assert_eq!(pi::<Value>().sql(), "PI()");
927/// ```
928#[must_use]
929pub fn pi<'a, V>()
930-> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Double, super::NonNull, Scalar, ()>
931where
932 V: SQLParam + 'a,
933 V::DialectMarker: MathExt,
934 V::DialectMarker: MathExt,
935{
936 SQLExpr::new(SQL::raw("PI()"))
937}
938
939/// A random value.
940///
941/// Renders `RANDOM()` on SQLite and PostgreSQL and `RAND()` on MySQL. The
942/// result type depends on the dialect: SQLite returns a 64-bit integer,
943/// PostgreSQL and MySQL a float in `[0, 1)`. It is never NULL.
944///
945/// # Examples
946///
947/// ```rust
948/// # use drizzle_core::dialect::{Dialect, DialectTypes, SQLiteDialect as D};
949/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
950/// # #[derive(Clone, Debug)] struct Value(String);
951/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::SQLite; type DialectMarker = D; }
952/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
953/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
954/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
955/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
956/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
957/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
958/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
959/// assert_eq!(random::<Value>().sql(), "RANDOM()");
960/// ```
961#[must_use]
962pub fn random<'a, V>()
963-> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Random, super::NonNull, Scalar, ()>
964where
965 V: SQLParam + 'a,
966{
967 SQLExpr::new(SQL::raw(match V::DIALECT {
968 Dialect::MySQL => "RAND()",
969 Dialect::SQLite | Dialect::PostgreSQL => "RANDOM()",
970 }))
971}
972
973// =============================================================================
974// Dialect-gated Math Functions
975// =============================================================================
976
977/// Base-2 logarithm (`LOG2`), on SQLite and MySQL.
978///
979/// The argument must be numeric. The result is the dialect's double type and
980/// always nullable, since both dialects return NULL outside the domain.
981/// SQLite needs the `math` feature. PostgreSQL has no `LOG2`, so this does not
982/// compile for PostgreSQL; use [`log`] with base 2 there.
983///
984/// # Examples
985///
986/// ```rust
987/// # use drizzle_core::dialect::{Dialect, DialectTypes, MySQLDialect as D};
988/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
989/// # #[derive(Clone, Debug)] struct Value(String);
990/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::MySQL; type DialectMarker = D; }
991/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
992/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
993/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
994/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
995/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
996/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
997/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
998/// assert_eq!(log2(users.score).sql(), "LOG2(`users`.`score`)");
999/// ```
1000#[allow(clippy::type_complexity)]
1001pub fn log2<'a, V, E>(
1002 expr: E,
1003) -> SQLExpr<
1004 'a,
1005 V,
1006 <V::DialectMarker as DialectTypes>::Double,
1007 <V::DialectMarker as Log2Policy>::Nullable,
1008 E::Aggregate,
1009 E::Sources,
1010>
1011where
1012 V: SQLParam + 'a,
1013 V::DialectMarker: MathExt,
1014 V::DialectMarker: Log2Policy,
1015 E: Expr<'a, V>,
1016 E::SQLType: Numeric,
1017{
1018 SQLExpr::new(SQL::func("LOG2", expr.into_sql()))
1019}