From c6dbe589fd77e75cad9f651b6129eb2dd15d4bc9 Mon Sep 17 00:00:00 2001 From: Jason Lyu Date: Mon, 10 Jul 2023 19:03:56 +0800 Subject: [PATCH] feat(math): add common SQL math funcs/aliases (#2082) * feat(math): add common SQL math funcs/aliases Signed-off-by: xjasonlyu * fix test errors for pow Signed-off-by: xjasonlyu * add test cases for new funcs Signed-off-by: xjasonlyu --------- Signed-off-by: xjasonlyu --- .../sqls/functions/mathematical_functions.md | 26 ++++++++++++++++++- .../sqls/functions/mathematical_functions.md | 26 ++++++++++++++++++- internal/binder/function/funcs_array_test.go | 2 +- internal/binder/function/funcs_math.go | 24 ++++++++++++++++- internal/binder/function/funcs_math_test.go | 26 +++++++++++++++++++ 5 files changed, 100 insertions(+), 4 deletions(-) diff --git a/docs/en_US/sqls/functions/mathematical_functions.md b/docs/en_US/sqls/functions/mathematical_functions.md index 2acedde6d5..19ce2dee41 100644 --- a/docs/en_US/sqls/functions/mathematical_functions.md +++ b/docs/en_US/sqls/functions/mathematical_functions.md @@ -77,8 +77,12 @@ Performs a bitwise NOT on the bit representations of the Int(-converted) argumen ## CEIL +`CEIL()` is a synonym for [`CEILING()`](#ceiling). + +## CEILING + ```text -ceil(col) +ceiling(col) ``` The smallest integer value that is greater than or equal to the argument. @@ -107,6 +111,14 @@ exp(col) Returns Euler's number e raised to the power of a double value. +## FLOOR + +```text +floor(col) +``` + +Returns the largest integer value not greater than X. + ## LN ```text @@ -131,6 +143,18 @@ mod(col1, col2) Returns the remainder of the division of the first argument by the second argument. +## PI + +```text +pi() +``` + +Returns the value of π (pi). + +## POW + +`POW()` is a synonym for [`POWER()`](#power). + ## POWER ```text diff --git a/docs/zh_CN/sqls/functions/mathematical_functions.md b/docs/zh_CN/sqls/functions/mathematical_functions.md index 43477a425a..4641c1b1bf 100644 --- a/docs/zh_CN/sqls/functions/mathematical_functions.md +++ b/docs/zh_CN/sqls/functions/mathematical_functions.md @@ -76,8 +76,12 @@ bitnot(col) ## CEIL +`CEIL()` 是 [`CEILING()`](#ceiling) 的别名。 + +## CEILING + ```text -ceil(col) +ceiling(col) ``` 将值舍入到最接近的 BIGINT 值。 @@ -106,6 +110,14 @@ exp(col) 返回小数点参数的 e。 +## FLOOR + +```text +floor(col) +``` + +返回小于 X 的最大整数值。 + ## LN ```text @@ -130,6 +142,18 @@ mod(col1, col2) 返回第一个参数除以第二个参数的余数。 +## PI + +```text +pi() +``` + +返回 π (pi) 的值。 + +## POW + +`POW()` 是函数 [`POWER()`](#power) 的别名。 + ## POWER ```text diff --git a/internal/binder/function/funcs_array_test.go b/internal/binder/function/funcs_array_test.go index fb2bdb429d..5da61debf0 100644 --- a/internal/binder/function/funcs_array_test.go +++ b/internal/binder/function/funcs_array_test.go @@ -562,7 +562,7 @@ func TestArrayCommonFunctions(t *testing.T) { args: []interface{}{ "pow", []interface{}{0, -0.4, 1.2}, }, - result: fmt.Errorf("unknown built-in function: pow."), + result: fmt.Errorf("validate function arguments failed."), }, { name: "array_map", diff --git a/internal/binder/function/funcs_math.go b/internal/binder/function/funcs_math.go index 4b7de9cdd6..ced0dc609d 100644 --- a/internal/binder/function/funcs_math.go +++ b/internal/binder/function/funcs_math.go @@ -188,7 +188,7 @@ func registerMathFunc() { }, check: returnNilIfHasAnyNil, } - builtins["ceil"] = builtinFunc{ + builtins["ceiling"] = builtinFunc{ fType: ast.FuncTypeScalar, exec: func(ctx api.FunctionContext, args []interface{}) (interface{}, bool) { if v, e := cast.ToFloat64(args[0], cast.CONVERT_SAMEKIND); e == nil { @@ -200,6 +200,7 @@ func registerMathFunc() { val: ValidateOneNumberArg, check: returnNilIfHasAnyNil, } + builtins["ceil"] = builtins["ceiling"] // Synonym for CEILING. builtins["cos"] = builtinFunc{ fType: ast.FuncTypeScalar, exec: func(ctx api.FunctionContext, args []interface{}) (interface{}, bool) { @@ -251,6 +252,18 @@ func registerMathFunc() { val: ValidateOneNumberArg, check: returnNilIfHasAnyNil, } + builtins["floor"] = builtinFunc{ + fType: ast.FuncTypeScalar, + exec: func(ctx api.FunctionContext, args []interface{}) (interface{}, bool) { + if v, e := cast.ToFloat64(args[0], cast.CONVERT_SAMEKIND); e == nil { + return math.Floor(v), true + } else { + return e, false + } + }, + val: ValidateOneNumberArg, + check: returnNilIfHasAnyNil, + } builtins["ln"] = builtinFunc{ fType: ast.FuncTypeScalar, exec: func(ctx api.FunctionContext, args []interface{}) (interface{}, bool) { @@ -301,6 +314,14 @@ func registerMathFunc() { val: ValidateTwoNumberArg, check: returnNilIfHasAnyNil, } + builtins["pi"] = builtinFunc{ + fType: ast.FuncTypeScalar, + exec: func(_ api.FunctionContext, _ []interface{}) (interface{}, bool) { + return math.Pi, true + }, + val: ValidateNoArg, + check: returnNilIfHasAnyNil, + } builtins["power"] = builtinFunc{ fType: ast.FuncTypeScalar, exec: func(ctx api.FunctionContext, args []interface{}) (interface{}, bool) { @@ -317,6 +338,7 @@ func registerMathFunc() { val: ValidateTwoNumberArg, check: returnNilIfHasAnyNil, } + builtins["pow"] = builtins["power"] // Synonym for POWER. builtins["rand"] = builtinFunc{ fType: ast.FuncTypeScalar, exec: func(ctx api.FunctionContext, args []interface{}) (interface{}, bool) { diff --git a/internal/binder/function/funcs_math_test.go b/internal/binder/function/funcs_math_test.go index 5ec20a1661..e390afa250 100644 --- a/internal/binder/function/funcs_math_test.go +++ b/internal/binder/function/funcs_math_test.go @@ -41,6 +41,10 @@ func TestFuncMath(t *testing.T) { if !ok { t.Fatal("builtin not found") } + fFloor, ok := builtins["floor"] + if !ok { + t.Fatal("builtin not found") + } fLn, ok := builtins["ln"] if !ok { t.Fatal("builtin not found") @@ -101,6 +105,10 @@ func TestFuncMath(t *testing.T) { if !ok { t.Fatal("builtin not found") } + fPi, ok := builtins["pi"] + if !ok { + t.Fatal("builtin not found") + } fRound, ok := builtins["round"] if !ok { t.Fatal("builtin not found") @@ -162,6 +170,8 @@ func TestFuncMath(t *testing.T) { math.Sinh(-10), math.Tan(-10), math.Tanh(-10), + math.Floor(-10), + math.Pi, }, }, { // 1 args: []interface{}{ @@ -192,6 +202,8 @@ func TestFuncMath(t *testing.T) { math.Sinh(10), math.Tan(10), math.Tanh(10), + math.Floor(10), + math.Pi, }, }, { // 2 args: []interface{}{ @@ -222,6 +234,8 @@ func TestFuncMath(t *testing.T) { math.Sinh(-10.5), math.Tan(-10.5), math.Tanh(-10.5), + math.Floor(-10.5), + math.Pi, }, }, { // 3 args: []interface{}{ @@ -252,6 +266,8 @@ func TestFuncMath(t *testing.T) { math.Sinh(10.5), math.Tan(10.5), math.Tanh(10.5), + math.Floor(10.5), + math.Pi, }, }, { // 4 args: []interface{}{ @@ -282,6 +298,8 @@ func TestFuncMath(t *testing.T) { math.Sinh(0), math.Tan(0), math.Tanh(0), + float64(0), + math.Pi, }, }, } @@ -382,6 +400,14 @@ func TestFuncMath(t *testing.T) { if !reflect.DeepEqual(rTanh, tt.res[23]) { t.Errorf("%d.23 tanh result mismatch,\ngot:\t%v \nwant:\t%v", i, rTanh, tt.res[23]) } + rFloor, _ := fFloor.exec(fctx, tt.args) + if !reflect.DeepEqual(rFloor, tt.res[24]) { + t.Errorf("%d.24 exp result mismatch,\ngot:\t%v \nwant:\t%v", i, rFloor, tt.res[24]) + } + rPi, _ := fPi.exec(fctx, tt.args) + if !reflect.DeepEqual(rPi, tt.res[25]) { + t.Errorf("%d.25 exp result mismatch,\ngot:\t%v \nwant:\t%v", i, rPi, tt.res[25]) + } } }