Просмотр исходного кода

feat(function): add hex/int conversion functions (#2013)

feat(function): add hex/int conversion functions



feat(function): add hex/int conversion functions



feat(function): add hex/int conversion functions

Signed-off-by: L-607 <i@1l.fit>
L 1 год назад
Родитель
Сommit
ffdad17a0a

+ 16 - 0
docs/en_US/sqls/functions/transform_functions.md

@@ -73,3 +73,19 @@ chr(col)
 ```
 
 Returns the ASCII character that corresponds to the given Int argument.
+
+## HEX2DEC
+
+```text
+hex2dec(col)
+```
+
+Returns the decimal value of the given hexadecimal string. The data type of the parameter needs to be string. If the parameter is `"0x10"` or `"10"`, convert it to `16`.
+
+## DEC2HEX
+
+```text
+dec2hex(col)
+```
+
+Returns the hexadecimal string of the given Int type decimal, if the parameter is `16`, convert it to `"0x10"`.

+ 16 - 1
docs/zh_CN/sqls/functions/transform_functions.md

@@ -6,7 +6,6 @@
 
 ```text
 cast(col,  "bigint")
-``
 ```
 
 将值从一种数据类型转换为另一种数据类型。 支持的类型包括:bigint,float,string,boolean,bytea 和 datetime。
@@ -67,3 +66,19 @@ decompress(input, "zlib")
 ```
 
 解压缩输入的字符串或二进制值。目前支持 'zlib', 'gzip', 'flate' 和 'zstd' 压缩算法。
+
+## HEX2DEC
+
+```text
+hex2dec(col)
+```
+
+返回给定16进制字符串的10进制数值, 参数的数据类型需要是 string, 如果参数是 `"0x10"` 或 `"10"`,则将其转换为 `16`。
+
+## DEC2HEX
+
+```text
+dec2hex(col)
+```
+
+返回给定 Int 类型10进制的16进制字符串,如果参数为 `16`,则将其转换为 `"0x10"`。

+ 31 - 0
internal/binder/function/funcs_misc.go

@@ -25,6 +25,7 @@ import (
 	"io"
 	"math"
 	"reflect"
+	"strconv"
 	"strings"
 	"time"
 
@@ -578,6 +579,36 @@ func registerMiscFunc() {
 		},
 		check: returnNilIfHasAnyNil,
 	}
+	builtins["hex2dec"] = builtinFunc{
+		fType: ast.FuncTypeScalar,
+		exec: func(ctx api.FunctionContext, args []interface{}) (interface{}, bool) {
+			hex, ok := args[0].(string)
+			if !ok {
+				return fmt.Errorf("invalid input type: %v please input hex string", args[0]), false
+			}
+			hex = strings.TrimPrefix(hex, "0x")
+			dec, err := strconv.ParseInt(hex, 16, 64)
+			if err != nil {
+				return fmt.Errorf("invalid hexadecimal value: %v", hex), false
+			}
+			return dec, true
+		},
+		val:   ValidateOneStrArg,
+		check: returnNilIfHasAnyNil,
+	}
+	builtins["dec2hex"] = builtinFunc{
+		fType: ast.FuncTypeScalar,
+		exec: func(ctx api.FunctionContext, args []interface{}) (interface{}, bool) {
+			dec, err := cast.ToInt(args[0], cast.STRICT)
+			if err != nil {
+				return err, false
+			}
+			hex := "0x" + strconv.FormatInt(int64(dec), 16)
+			return hex, true
+		},
+		val:   ValidateOneStrArg,
+		check: returnNilIfHasAnyNil,
+	}
 }
 
 func round(num float64) int {

+ 37 - 0
internal/binder/function/funcs_misc_test.go

@@ -381,6 +381,43 @@ func TestKeyedStateExec(t *testing.T) {
 	_ = keyedstate.ClearKeyedState()
 }
 
+func TestHexIntFunctions(t *testing.T) {
+	contextLogger := conf.Log.WithField("rule", "testExec")
+	ctx := kctx.WithValue(kctx.Background(), kctx.LoggerKey, contextLogger)
+	tempStore, _ := state.CreateStore("mockRule0", api.AtMostOnce)
+	fctx := kctx.NewDefaultFuncContext(ctx.WithMeta("mockRule0", "test", tempStore), 2)
+	tests := []struct {
+		name   string
+		args   []interface{}
+		result interface{}
+	}{
+		{
+			name: "hex2dec",
+			args: []interface{}{
+				"0x10",
+			},
+			result: int64(16),
+		},
+		{
+			name: "dec2hex",
+			args: []interface{}{
+				16,
+			},
+			result: "0x10",
+		},
+	}
+	for i, tt := range tests {
+		f, ok := builtins[tt.name]
+		if !ok {
+			t.Fatal(fmt.Sprintf("builtin %v not found", tt.name))
+		}
+		result, _ := f.exec(fctx, tt.args)
+		if !reflect.DeepEqual(result, tt.result) {
+			t.Errorf("%d result mismatch,\ngot:\t%v \nwant:\t%v", i, result, tt.result)
+		}
+	}
+}
+
 func TestMiscFuncNil(t *testing.T) {
 	contextLogger := conf.Log.WithField("rule", "testExec")
 	ctx := kctx.WithValue(kctx.Background(), kctx.LoggerKey, contextLogger)