Skip to content

Commit

Permalink
feat(expr): support pow function (#7789)
Browse files Browse the repository at this point in the history
As per the title.

Right now, both x and y are casted into Float64 when pow(x, y).
By PG's standard, we also need to support Decimal but Decimal has no built-in pow and we may also change the underlying crate for Decimal. So we leave it aside for now.

Urgently requested by user.

#7725

Approved-By: st1page
Approved-By: TennyZhuang
  • Loading branch information
lmatz authored Feb 8, 2023
1 parent e1408c4 commit fc2f1c9
Show file tree
Hide file tree
Showing 10 changed files with 147 additions and 3 deletions.
6 changes: 6 additions & 0 deletions dashboard/proto/gen/expr.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

51 changes: 51 additions & 0 deletions e2e_test/batch/functions/pow.slt.part
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
query R
select pow(2.0, 3.0)
----
8

query R
select pow(2.0::decimal, 3.0::decimal)
----
8

query R
select pow(2.0::double, 3.0::double)
----
8

query R
select pow(2.0::smallint, 3.0::smallint)
----
8

query R
select pow(2.0::bigint, 3.0::bigint)
----
8

query R
select pow(2.0, -2);
----
0.25

query R
select pow(2.23, -2.33);
----
0.15432975583772085

query R
select pow(100000, 0);
----
1

query R
select pow(100000, -200000000000000);
----
0

statement error QueryError: Expr error: Numeric out of range
select pow(100000, 200000000000000);


statement error QueryError: Expr error: Numeric out of range
select pow(-100000, 200000000000001);
1 change: 1 addition & 0 deletions proto/expr.proto
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ message ExprNode {
BIT_LENGTH = 230;
OVERLAY = 231;
REGEXP_MATCH = 232;
POW = 233;

// Boolean comparison
IS_TRUE = 301;
Expand Down
13 changes: 12 additions & 1 deletion src/common/src/types/ordered_float.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ use core::str::FromStr;
pub use num_traits::Float;
use num_traits::{
AsPrimitive, Bounded, CheckedAdd, CheckedDiv, CheckedMul, CheckedNeg, CheckedRem, CheckedSub,
FromPrimitive, Num, NumCast, One, Signed, ToPrimitive, Zero,
FromPrimitive, Num, NumCast, One, Pow, Signed, ToPrimitive, Zero,
};

// masks for the parts of the IEEE 754 float
Expand Down Expand Up @@ -389,6 +389,17 @@ impl_ordered_float_binop! {Mul, mul, MulAssign, mul_assign}
impl_ordered_float_binop! {Div, div, DivAssign, div_assign}
impl_ordered_float_binop! {Rem, rem, RemAssign, rem_assign}

impl<T> Pow<OrderedFloat<T>> for OrderedFloat<T>
where
T: Float,
{
type Output = OrderedFloat<T>;

fn pow(self, rhs: Self) -> Self::Output {
OrderedFloat(self.0.powf(rhs.0))
}
}

impl<T> CheckedAdd for OrderedFloat<T>
where
T: Float,
Expand Down
57 changes: 57 additions & 0 deletions src/expr/src/expr/expr_binary_nonnull.rs
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,56 @@ macro_rules! gen_binary_expr_atm {
};
}

/// `gen_binary_expr_atm` is similar to `gen_binary_expr_cmp`.
/// `atm` means arithmetic here.
/// They are differentiate cuz one type may not support atm and cmp at the same time. For example,
/// Varchar can support compare but not arithmetic.
/// * `$general_f`: generic atm function (require a common ``TryInto`` type for two input)
/// * `$i1`, `$i2`, `$rt`, `$func`: extra list passed to `$macro` directly
macro_rules! gen_binary_expr_pow {
($macro:ident, $l:expr, $r:expr, $ret:expr, $general_f:ident,) => {
$macro! {
[$l, $r, $ret],
{ int16, int16, float64, $general_f },
{ int16, int32, float64, $general_f },
{ int16, int64, float64, $general_f },
{ int16, float32, float64, $general_f },
{ int16, float64, float64, $general_f },
{ int32, int16, float64, $general_f },
{ int32, int32, float64, $general_f },
{ int32, int64, float64, $general_f },
{ int32, float32, float64, $general_f },
{ int32, float64, float64, $general_f },
{ int64, int16, float64, $general_f },
{ int64, int32, float64, $general_f },
{ int64, int64, float64, $general_f },
{ int64, float32, float64 , $general_f},
{ int64, float64, float64, $general_f },
{ float32, int16, float64, $general_f },
{ float32, int32, float64, $general_f },
{ float32, int64, float64 , $general_f},
{ float32, float32, float64, $general_f },
{ float32, float64, float64, $general_f },
{ float64, int16, float64, $general_f },
{ float64, int32, float64, $general_f },
{ float64, int64, float64, $general_f },
{ float64, float32, float64, $general_f },
{ float64, float64, float64, $general_f },
{ decimal, int16, float64, $general_f },
{ decimal, int32, float64, $general_f },
{ decimal, int64, float64, $general_f },
{ decimal, float32, float64, $general_f },
{ decimal, float64, float64, $general_f },
{ int16, decimal, float64, $general_f },
{ int32, decimal, float64, $general_f },
{ int64, decimal, float64, $general_f },
{ decimal, decimal, float64, $general_f },
{ float32, decimal, float64, $general_f },
{ float64, decimal, float64, $general_f },
}
};
}

/// `gen_binary_expr_bitwise` is similar to `gen_binary_expr_atm`.
/// They are differentiate because bitwise operation only supports integral datatype.
/// * `$general_f`: generic atm function (require a common ``TryInto`` type for two input)
Expand Down Expand Up @@ -662,6 +712,13 @@ pub fn new_binary_expr(
},
}
}
Type::Pow => {
gen_binary_expr_pow! {
gen_atm_impl,
l, r, ret,
general_pow,
}
}
Type::Extract => build_extract_expr(ret, l, r)?,
Type::AtTimeZone => build_at_time_zone_expr(ret, l, r)?,
Type::CastWithTimeZone => build_cast_with_time_zone_expr(ret, l, r)?,
Expand Down
2 changes: 1 addition & 1 deletion src/expr/src/expr/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ pub fn build_from_prost(prost: &ExprNode) -> Result<BoxedExpression> {
| IsNotNull | Neg | Ascii | Abs | Ceil | Floor | Round | BitwiseNot | CharLength
| BoolOut | OctetLength | BitLength | ToTimestamp => build_unary_expr_prost(prost),
Equal | NotEqual | LessThan | LessThanOrEqual | GreaterThan | GreaterThanOrEqual | Add
| Subtract | Multiply | Divide | Modulus | Extract | RoundDigit | TumbleStart
| Subtract | Multiply | Divide | Modulus | Extract | RoundDigit | Pow | TumbleStart
| Position | BitwiseShiftLeft | BitwiseShiftRight | BitwiseAnd | BitwiseOr | BitwiseXor
| ConcatOp | AtTimeZone | CastWithTimeZone => build_binary_expr_prost(prost),
And | Or | IsDistinctFrom | IsNotDistinctFrom | ArrayAccess => {
Expand Down
1 change: 1 addition & 0 deletions src/expr/src/sig/func.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ fn build_type_derive_map() -> FuncSigMap {
&[T::Int16, T::Int32, T::Int64, T::Decimal],
);
map.insert(E::RoundDigit, vec![T::Decimal, T::Int32], T::Decimal);
map.insert(E::Pow, vec![T::Float64, T::Float64], T::Float64);

// build bitwise operator
// bitwise operator
Expand Down
17 changes: 16 additions & 1 deletion src/expr/src/vector_op/arithmetic_op.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use std::convert::TryInto;
use std::fmt::Debug;

use chrono::{Duration, NaiveDateTime};
use num_traits::{CheckedDiv, CheckedMul, CheckedNeg, CheckedRem, CheckedSub, Signed, Zero};
use num_traits::{CheckedDiv, CheckedMul, CheckedNeg, CheckedRem, CheckedSub, Pow, Signed, Zero};
use risingwave_common::types::{
CheckedAdd, Decimal, IntervalUnit, NaiveDateTimeWrapper, NaiveDateWrapper, NaiveTimeWrapper,
OrderedF64,
Expand Down Expand Up @@ -108,6 +108,21 @@ pub fn decimal_abs(decimal: Decimal) -> Result<Decimal> {
Ok(Decimal::abs(&decimal))
}

#[inline(always)]
pub fn general_pow<T1, T2, T3>(l: T1, r: T2) -> Result<T3>
where
T1: Into<T3> + Debug,
T2: Into<T3> + Debug,
T3: Pow<T3> + num_traits::Float,
{
let res = l.into().powf(r.into());
if res.is_infinite() {
Err(ExprError::NumericOutOfRange)
} else {
Ok(res)
}
}

#[inline(always)]
pub fn general_atm<T1, T2, T3, F>(l: T1, r: T2, atm: F) -> Result<T3>
where
Expand Down
1 change: 1 addition & 0 deletions src/frontend/src/binder/expr/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,7 @@ impl Binder {
(1, raw_call(ExprType::Round)),
]),
),
("pow", raw_call(ExprType::Pow)),
("ceil", raw_call(ExprType::Ceil)),
("floor", raw_call(ExprType::Floor)),
("abs", raw_call(ExprType::Abs)),
Expand Down
1 change: 1 addition & 0 deletions src/tests/sqlsmith/src/sql_gen/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,7 @@ fn make_general_expr(func: ExprType, exprs: Vec<Expr>) -> Option<Expr> {
E::IsNotFalse => Some(Expr::IsNotFalse(Box::new(exprs[0].clone()))),
E::Position => Some(Expr::Function(make_simple_func("position", &exprs))),
E::RoundDigit => Some(Expr::Function(make_simple_func("round", &exprs))),
E::Pow => Some(Expr::Function(make_simple_func("pow", &exprs))),
E::Repeat => Some(Expr::Function(make_simple_func("repeat", &exprs))),
E::CharLength => Some(Expr::Function(make_simple_func("char_length", &exprs))),
E::Substr => Some(Expr::Function(make_simple_func("substr", &exprs))),
Expand Down

0 comments on commit fc2f1c9

Please sign in to comment.