Skip to content

Commit 91f4c5b

Browse files
committed
evalEngine: Implement INSTR
Signed-off-by: Noble Mittal <noblemittal@outlook.com>
1 parent 77dc0c9 commit 91f4c5b

File tree

5 files changed

+142
-0
lines changed

5 files changed

+142
-0
lines changed

go/vt/vtgate/evalengine/cached_size.go

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

go/vt/vtgate/evalengine/compiler_asm.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1418,6 +1418,18 @@ func (asm *assembler) Mod_dd() {
14181418
}, "MOD DECIMAL(SP-2), DECIMAL(SP-1)")
14191419
}
14201420

1421+
func (asm *assembler) Fn_INSTR() {
1422+
asm.adjustStack(-1)
1423+
1424+
asm.emit(func(env *ExpressionEnv) int {
1425+
str := env.vm.stack[env.vm.sp-2].(*evalBytes)
1426+
substr := env.vm.stack[env.vm.sp-1].(*evalBytes)
1427+
1428+
env.vm.stack[env.vm.sp-1] = env.vm.arena.newEvalInt64(instrIndex(str, substr))
1429+
return 1
1430+
}, "FN INSTR VARCHAR(SP-2) VARCHAR(SP-1)")
1431+
}
1432+
14211433
func (asm *assembler) Fn_ASCII() {
14221434
asm.emit(func(env *ExpressionEnv) int {
14231435
arg := env.vm.stack[env.vm.sp-1].(*evalBytes)

go/vt/vtgate/evalengine/fn_string.go

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@ type (
4343
CallExpr
4444
}
4545

46+
builtinInstr struct {
47+
CallExpr
48+
collate collations.ID
49+
}
50+
4651
builtinASCII struct {
4752
CallExpr
4853
}
@@ -99,6 +104,7 @@ type (
99104
var _ IR = (*builtinChangeCase)(nil)
100105
var _ IR = (*builtinCharLength)(nil)
101106
var _ IR = (*builtinLength)(nil)
107+
var _ IR = (*builtinInstr)(nil)
102108
var _ IR = (*builtinASCII)(nil)
103109
var _ IR = (*builtinOrd)(nil)
104110
var _ IR = (*builtinBitLength)(nil)
@@ -199,6 +205,77 @@ func (call *builtinLength) compile(c *compiler) (ctype, error) {
199205
return c.compileFn_length(call.Arguments[0], c.asm.Fn_LENGTH)
200206
}
201207

208+
func instrIndex(str *evalBytes, substr *evalBytes) int64 {
209+
// Case sensitive if one of the strings is binary string
210+
if !str.isBinary() && !substr.isBinary() {
211+
str.bytes = bytes.ToLower(str.bytes)
212+
substr.bytes = bytes.ToLower(substr.bytes)
213+
}
214+
215+
pos := bytes.Index(str.bytes, substr.bytes) + 1
216+
return int64(pos)
217+
}
218+
219+
func (call *builtinInstr) eval(env *ExpressionEnv) (eval, error) {
220+
arg1, arg2, err := call.arg2(env)
221+
if err != nil {
222+
return nil, err
223+
}
224+
if arg1 == nil || arg2 == nil {
225+
return nil, nil
226+
}
227+
228+
str, ok := arg1.(*evalBytes)
229+
if !ok {
230+
str, err = evalToVarchar(arg1, call.collate, true)
231+
if err != nil {
232+
return nil, err
233+
}
234+
}
235+
236+
substr, ok := arg2.(*evalBytes)
237+
if !ok {
238+
substr, err = evalToVarchar(arg2, call.collate, true)
239+
if err != nil {
240+
return nil, err
241+
}
242+
}
243+
244+
return newEvalInt64(instrIndex(str, substr)), nil
245+
}
246+
247+
func (call *builtinInstr) compile(c *compiler) (ctype, error) {
248+
arg1, err := call.Arguments[0].compile(c)
249+
if err != nil {
250+
return ctype{}, err
251+
}
252+
253+
skip1 := c.compileNullCheck1(arg1)
254+
255+
switch {
256+
case arg1.isTextual():
257+
default:
258+
c.asm.Convert_xce(1, sqltypes.VarChar, call.collate)
259+
}
260+
261+
arg2, err := call.Arguments[1].compile(c)
262+
if err != nil {
263+
return ctype{}, err
264+
}
265+
266+
skip2 := c.compileNullCheck1(arg2)
267+
268+
switch {
269+
case arg2.isTextual():
270+
default:
271+
c.asm.Convert_xce(1, sqltypes.VarChar, call.collate)
272+
}
273+
274+
c.asm.Fn_INSTR()
275+
c.asm.jumpDestination(skip1, skip2)
276+
return ctype{Type: sqltypes.Int64, Col: collationNumeric}, nil
277+
}
278+
202279
func (call *builtinBitLength) eval(env *ExpressionEnv) (eval, error) {
203280
arg, err := call.arg1(env)
204281
if err != nil {

go/vt/vtgate/evalengine/testcases/cases.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ var Cases = []TestCase{
6767
{Run: FnUpper},
6868
{Run: FnCharLength},
6969
{Run: FnLength},
70+
{Run: FnInstr},
7071
{Run: FnBitLength},
7172
{Run: FnAscii},
7273
{Run: FnOrd},
@@ -1339,6 +1340,41 @@ func FnLength(yield Query) {
13391340
}
13401341
}
13411342

1343+
func FnInstr(yield Query) {
1344+
for _, str := range inputStrings {
1345+
for _, substr := range inputStrings {
1346+
yield(fmt.Sprintf("INSTR(%s, %s)", str, substr), nil)
1347+
}
1348+
}
1349+
1350+
cases := []struct {
1351+
str string
1352+
substr string
1353+
}{
1354+
{"'ACABAB'", "'AB'"},
1355+
{"'ABABAB'", "'AB'"},
1356+
{"'ABABAB'", "'ab'"},
1357+
{"'ABABAB'", "'ba'"},
1358+
{"'CBDASD'", "'ab'"},
1359+
{"'ABABAB'", "''"},
1360+
{"'ABABAB'", ""},
1361+
{"1233", "23"},
1362+
{"0x616162", "0x6162"},
1363+
{"0x616162", "0x4141"},
1364+
{"'AAB'", "123"},
1365+
{"123", "'ABC'"},
1366+
{"_binary'FOOBAR'", "'AR'"},
1367+
{"_binary'FOOBAR'", "BINARY 'AR'"},
1368+
{"BINARY 'FOOBAR'", "'ar'"},
1369+
{"'foobarbar'", "'bar'"},
1370+
{"'xbar'", "'foobar'"},
1371+
}
1372+
1373+
for _, tc := range cases {
1374+
yield(fmt.Sprintf("INSTR(%s, %s)", tc.str, tc.substr), nil)
1375+
}
1376+
}
1377+
13421378
func FnBitLength(yield Query) {
13431379
for _, str := range inputStrings {
13441380
yield(fmt.Sprintf("BIT_LENGTH(%s)", str), nil)

go/vt/vtgate/evalengine/translate_builtin.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,11 @@ func (ast *astCompiler) translateFuncExpr(fn *sqlparser.FuncExpr) (IR, error) {
285285
return nil, argError(method)
286286
}
287287
return &builtinLength{CallExpr: call}, nil
288+
case "instr":
289+
if len(args) != 2 {
290+
return nil, argError(method)
291+
}
292+
return &builtinInstr{CallExpr: call, collate: ast.cfg.Collation}, nil
288293
case "bit_length":
289294
if len(args) != 1 {
290295
return nil, argError(method)

0 commit comments

Comments
 (0)