فهرست منبع

feat(math): support log func with base (#2086)

Signed-off-by: xjasonlyu <xjasonlyu@gmail.com>
Jason Lyu 1 سال پیش
والد
کامیت
98865cb22d

+ 5 - 1
docs/en_US/sqls/functions/mathematical_functions.md

@@ -131,9 +131,13 @@ Returns the natural logarithm of a double value.
 
 
 ```text
 ```text
 log(col)
 log(col)
+
+or
+
+log(b, col)
 ```
 ```
 
 
-Returns the base 10 logarithm of a double value.
+If called with one argument, the function returns the decimal logarithm of X. If X is less than or equal to 0, the function returns nil; if called with two arguments, the function returns the base B logarithm of X. Returns nil if X is less than or equal to 0, or if B is less than or equal to 1.
 
 
 ## MOD
 ## MOD
 
 

+ 5 - 1
docs/zh_CN/sqls/functions/mathematical_functions.md

@@ -130,9 +130,13 @@ ln(col)
 
 
 ```text
 ```text
 log(col)
 log(col)
+
+or
+
+log(b, col)
 ```
 ```
 
 
-返回参数的以10为底的对数。
+如果使用一个参数调用,该函数将返回 X 的十进制对数。如果 X 小于或等于 0,则该函数返回 nil;如果使用两个参数调用,该函数返回 X 的 B 底对数。如果 X 小于或等于 0,或者 B 小于或等于 1,则返回 nil
 
 
 ## MOD
 ## MOD
 
 

+ 28 - 9
internal/binder/function/funcs_math.go

@@ -15,6 +15,7 @@
 package function
 package function
 
 
 import (
 import (
+	"errors"
 	"fmt"
 	"fmt"
 	"math"
 	"math"
 	"math/rand"
 	"math/rand"
@@ -284,18 +285,36 @@ func registerMathFunc() {
 	builtins["log"] = builtinFunc{
 	builtins["log"] = builtinFunc{
 		fType: ast.FuncTypeScalar,
 		fType: ast.FuncTypeScalar,
 		exec: func(ctx api.FunctionContext, args []interface{}) (interface{}, bool) {
 		exec: func(ctx api.FunctionContext, args []interface{}) (interface{}, bool) {
-			if v, e := cast.ToFloat64(args[0], cast.CONVERT_SAMEKIND); e == nil {
-				r := math.Log10(v)
-				if math.IsNaN(r) {
-					return nil, true
-				} else {
-					return r, true
-				}
-			} else {
+			v, e := cast.ToFloat64(args[0], cast.CONVERT_SAMEKIND)
+			if e != nil {
 				return e, false
 				return e, false
 			}
 			}
+
+			var r float64
+			if len(args) == 1 {
+				r = math.Log10(v)
+			} else {
+				x, e := cast.ToFloat64(args[1], cast.CONVERT_SAMEKIND)
+				if e != nil {
+					return e, false
+				}
+				r = math.Log(x) / math.Log(v)
+			}
+
+			if !math.IsNaN(r) {
+				return r, true
+			}
+			return nil, true
+		},
+		val: func(_ api.FunctionContext, args []ast.Expr) error {
+			if len(args) != 1 && len(args) != 2 {
+				return errors.New("Expect 1 or 2 arguments only")
+			}
+			if ast.IsStringArg(args[0]) || ast.IsTimeArg(args[0]) || ast.IsBooleanArg(args[0]) {
+				return ProduceErrInfo(0, "number - float or int")
+			}
+			return nil
 		},
 		},
-		val:   ValidateOneNumberArg,
 		check: returnNilIfHasAnyNil,
 		check: returnNilIfHasAnyNil,
 	}
 	}
 	builtins["mod"] = builtinFunc{
 	builtins["mod"] = builtinFunc{

+ 1 - 1
internal/binder/function/funcs_math_test.go

@@ -320,7 +320,7 @@ func TestFuncMath(t *testing.T) {
 		if !reflect.DeepEqual(rLn, tt.res[3]) {
 		if !reflect.DeepEqual(rLn, tt.res[3]) {
 			t.Errorf("%d.3 ln result mismatch,\ngot:\t%v \nwant:\t%v", i, rLn, tt.res[3])
 			t.Errorf("%d.3 ln result mismatch,\ngot:\t%v \nwant:\t%v", i, rLn, tt.res[3])
 		}
 		}
-		rLog10, _ := fLog10.exec(fctx, tt.args)
+		rLog10, _ := fLog10.exec(fctx, tt.args[:1])
 		if !reflect.DeepEqual(rLog10, tt.res[4]) {
 		if !reflect.DeepEqual(rLog10, tt.res[4]) {
 			t.Errorf("%d.4 log result mismatch,\ngot:\t%v \nwant:\t%v", i, rLog10, tt.res[4])
 			t.Errorf("%d.4 log result mismatch,\ngot:\t%v \nwant:\t%v", i, rLog10, tt.res[4])
 		}
 		}