Skip to content

Commit

Permalink
evalEngine: Implement SPACE, REVERSE (#15173)
Browse files Browse the repository at this point in the history
Signed-off-by: Noble Mittal <[email protected]>
  • Loading branch information
beingnoble03 authored Feb 9, 2024
1 parent 4e31f60 commit 00b2728
Show file tree
Hide file tree
Showing 5 changed files with 193 additions and 0 deletions.
24 changes: 24 additions & 0 deletions go/vt/vtgate/evalengine/cached_size.go

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

23 changes: 23 additions & 0 deletions go/vt/vtgate/evalengine/compiler_asm.go
Original file line number Diff line number Diff line change
Expand Up @@ -1430,6 +1430,29 @@ func (asm *assembler) Fn_ASCII() {
}, "FN ASCII VARCHAR(SP-1)")
}

func (asm *assembler) Fn_REVERSE() {
asm.emit(func(env *ExpressionEnv) int {
arg := env.vm.stack[env.vm.sp-1].(*evalBytes)

arg.tt = int16(sqltypes.VarChar)
arg.bytes = reverse(arg)
return 1
}, "FN REVERSE VARCHAR(SP-1)")
}

func (asm *assembler) Fn_SPACE(col collations.TypedCollation) {
asm.emit(func(env *ExpressionEnv) int {
arg := env.vm.stack[env.vm.sp-1].(*evalInt64).i

if !validMaxLength(1, arg) {
env.vm.stack[env.vm.sp-1] = nil
return 1
}
env.vm.stack[env.vm.sp-1] = env.vm.arena.newEvalText(space(arg), col)
return 1
}, "FN SPACE INT64(SP-1)")
}

func (asm *assembler) Fn_ORD(col collations.ID) {
asm.emit(func(env *ExpressionEnv) int {
arg := env.vm.stack[env.vm.sp-1].(*evalBytes)
Expand Down
106 changes: 106 additions & 0 deletions go/vt/vtgate/evalengine/fn_string.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,16 @@ type (
CallExpr
}

builtinReverse struct {
CallExpr
collate collations.ID
}

builtinSpace struct {
CallExpr
collate collations.ID
}

builtinOrd struct {
CallExpr
collate collations.ID
Expand Down Expand Up @@ -100,6 +110,8 @@ var _ IR = (*builtinChangeCase)(nil)
var _ IR = (*builtinCharLength)(nil)
var _ IR = (*builtinLength)(nil)
var _ IR = (*builtinASCII)(nil)
var _ IR = (*builtinReverse)(nil)
var _ IR = (*builtinSpace)(nil)
var _ IR = (*builtinOrd)(nil)
var _ IR = (*builtinBitLength)(nil)
var _ IR = (*builtinCollation)(nil)
Expand Down Expand Up @@ -253,6 +265,100 @@ func (call *builtinASCII) compile(c *compiler) (ctype, error) {
return ctype{Type: sqltypes.Int64, Col: collationNumeric, Flag: nullableFlags(str.Flag)}, nil
}

func reverse(in *evalBytes) []byte {
cs := colldata.Lookup(in.col.Collation).Charset()
b := in.bytes

out, end := make([]byte, len(b)), len(b)
for len(b) > 0 {
_, size := cs.DecodeRune(b)
copy(out[end-size:end], b[:size])
b = b[size:]
end -= size
}
return out
}

func (call *builtinReverse) eval(env *ExpressionEnv) (eval, error) {
arg, err := call.arg1(env)
if err != nil {
return nil, err
}
if arg == nil {
return nil, nil
}

b, ok := arg.(*evalBytes)
if !ok {
b, err = evalToVarchar(arg, call.collate, true)
if err != nil {
return nil, err
}
}

return newEvalText(reverse(b), b.col), nil
}

func (call *builtinReverse) compile(c *compiler) (ctype, error) {
arg, err := call.Arguments[0].compile(c)
if err != nil {
return ctype{}, err
}

skip := c.compileNullCheck1(arg)

switch {
case arg.isTextual():
default:
c.asm.Convert_xc(1, sqltypes.VarChar, c.collation, 0, false)
}

c.asm.Fn_REVERSE()
c.asm.jumpDestination(skip)
return ctype{Type: sqltypes.VarChar, Col: arg.Col, Flag: flagNullable}, nil
}

func space(num int64) []byte {
num = max(num, 0)

spaces := bytes.Repeat([]byte{0x20}, int(num))
return spaces
}

func (call *builtinSpace) eval(env *ExpressionEnv) (eval, error) {
arg, err := call.arg1(env)
if err != nil {
return nil, err
}
if arg == nil {
return nil, nil
}

num := evalToInt64(arg).i

if !validMaxLength(1, num) {
return nil, nil
}
col := typedCoercionCollation(sqltypes.VarChar, call.collate)
return newEvalText(space(num), col), nil
}

func (call *builtinSpace) compile(c *compiler) (ctype, error) {
arg, err := call.Arguments[0].compile(c)
if err != nil {
return ctype{}, err
}

skip := c.compileNullCheck1(arg)

_ = c.compileToInt64(arg, 1)

col := typedCoercionCollation(sqltypes.VarChar, call.collate)
c.asm.Fn_SPACE(col)
c.asm.jumpDestination(skip)
return ctype{Type: sqltypes.VarChar, Col: col, Flag: flagNullable}, nil
}

func charOrd(b []byte, coll collations.ID) int64 {
if len(b) == 0 {
return 0
Expand Down
30 changes: 30 additions & 0 deletions go/vt/vtgate/evalengine/testcases/cases.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ var Cases = []TestCase{
{Run: FnLength},
{Run: FnBitLength},
{Run: FnAscii},
{Run: FnReverse},
{Run: FnSpace},
{Run: FnOrd},
{Run: FnRepeat},
{Run: FnLeft},
Expand Down Expand Up @@ -1352,6 +1354,34 @@ func FnAscii(yield Query) {
}
}

func FnReverse(yield Query) {
for _, str := range inputStrings {
yield(fmt.Sprintf("REVERSE(%s)", str), nil)
}
}

func FnSpace(yield Query) {
counts := []string{
"0",
"12",
"23",
"-1",
"-12393128120",
"-432766734237843674326423876243876234786",
"'-432766734237843674326423876243876234786'",
"432766734237843674326423876243876234786",
"1073741825",
"1.5",
"-3.2",
"'jhgjhg'",
"6",
}

for _, c := range counts {
yield(fmt.Sprintf("SPACE(%s)", c), nil)
}
}

func FnOrd(yield Query) {
for _, str := range inputStrings {
yield(fmt.Sprintf("ORD(%s)", str), nil)
Expand Down
10 changes: 10 additions & 0 deletions go/vt/vtgate/evalengine/translate_builtin.go
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,16 @@ func (ast *astCompiler) translateFuncExpr(fn *sqlparser.FuncExpr) (IR, error) {
return nil, argError(method)
}
return &builtinASCII{CallExpr: call}, nil
case "reverse":
if len(args) != 1 {
return nil, argError(method)
}
return &builtinReverse{CallExpr: call, collate: ast.cfg.Collation}, nil
case "space":
if len(args) != 1 {
return nil, argError(method)
}
return &builtinSpace{CallExpr: call, collate: ast.cfg.Collation}, nil
case "ord":
if len(args) != 1 {
return nil, argError(method)
Expand Down

0 comments on commit 00b2728

Please sign in to comment.