Skip to main content

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}