From e33426d0cf6f8f3503ca5ac7f117b749ec4f9acf Mon Sep 17 00:00:00 2001 From: rachithrr Date: Thu, 8 Dec 2022 04:01:30 +0530 Subject: [PATCH] FB-1795: Implement REVERSE() scalar string function (#2335) (cherry picked from commit d33bf4811f9803ae626f88ecbd183fd804b4b76a) --- sql3/planner/expression.go | 2 ++ sql3/planner/expressionanalyzercall.go | 2 ++ sql3/planner/inbuiltfunctionsstring.go | 41 +++++++++++++++++++++++++ sql3/test/defs/defs.go | 1 + sql3/test/defs/defs_string_functions.go | 32 +++++++++++++++++++ 5 files changed, 78 insertions(+) create mode 100644 sql3/planner/inbuiltfunctionsstring.go create mode 100644 sql3/test/defs/defs_string_functions.go diff --git a/sql3/planner/expression.go b/sql3/planner/expression.go index 5ebbd3360..d4ee5a042 100644 --- a/sql3/planner/expression.go +++ b/sql3/planner/expression.go @@ -1476,6 +1476,8 @@ func (n *callPlanExpression) Evaluate(currentRow []interface{}) (interface{}, er return n.EvaluateSetContainsAll(currentRow) case "DATEPART": return n.EvaluateDatepart(currentRow) + case "REVERSE": + return n.EvaluateReverse(currentRow) default: return nil, sql3.NewErrInternalf("unhandled function name '%s'", n.name) } diff --git a/sql3/planner/expressionanalyzercall.go b/sql3/planner/expressionanalyzercall.go index 8581df641..6e8a41169 100644 --- a/sql3/planner/expressionanalyzercall.go +++ b/sql3/planner/expressionanalyzercall.go @@ -241,6 +241,8 @@ func (p *ExecutionPlanner) analyzeCallExpression(call *parser.Call, scope parser case "SUBTABLE": return p.analyzeFunctionSubtable(call, scope) + case "REVERSE": + return p.analyseFunctionReverse(call, scope) default: return nil, sql3.NewErrCallUnknownFunction(call.Name.NamePos.Line, call.Name.NamePos.Column, call.Name.Name) diff --git a/sql3/planner/inbuiltfunctionsstring.go b/sql3/planner/inbuiltfunctionsstring.go new file mode 100644 index 000000000..71143a96c --- /dev/null +++ b/sql3/planner/inbuiltfunctionsstring.go @@ -0,0 +1,41 @@ +package planner + +import ( + "github.com/molecula/featurebase/v3/sql3" + "github.com/molecula/featurebase/v3/sql3/parser" +) + +func (p *ExecutionPlanner) analyseFunctionReverse(call *parser.Call, scope parser.Statement) (parser.Expr, error) { + //one argument + if len(call.Args) != 1 { + return nil, sql3.NewErrCallParameterCountMismatch(call.Rparen.Line, call.Rparen.Column, call.Name.Name, 1, len(call.Args)) + } + + if !typeIsString(call.Args[0].DataType()) { + return nil, sql3.NewErrStringExpressionExpected(call.Args[0].Pos().Line, call.Args[0].Pos().Column) + } + + call.ResultDataType = parser.NewDataTypeString() + + return call, nil +} + +// reverses the string +func (n *callPlanExpression) EvaluateReverse(currentRow []interface{}) (interface{}, error) { + argOneEval, err := n.args[0].Evaluate(currentRow) + if err != nil { + return nil, err + } + + stringArgOne, ok := argOneEval.(string) + if !ok { + return nil, sql3.NewErrInternalf("unexpected type converion %T", argOneEval) + } + + // reverse the string + runes := []rune(stringArgOne) + for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 { + runes[i], runes[j] = runes[j], runes[i] + } + return string(runes), nil +} diff --git a/sql3/test/defs/defs.go b/sql3/test/defs/defs.go index c4a7f5fd5..c6c8d0d69 100644 --- a/sql3/test/defs/defs.go +++ b/sql3/test/defs/defs.go @@ -23,6 +23,7 @@ var TableTests []TableTest = []TableTest{ setFunctionTests, setParameterTests, datePartTests, + stringScalarFunctionsTests, insertTest, keyedInsertTest, diff --git a/sql3/test/defs/defs_string_functions.go b/sql3/test/defs/defs_string_functions.go new file mode 100644 index 000000000..4e4fc560c --- /dev/null +++ b/sql3/test/defs/defs_string_functions.go @@ -0,0 +1,32 @@ +package defs + +// string function tests +var stringScalarFunctionsTests = TableTest{ + + Table: tbl( + "stringscalarfunctions", + srcHdrs( + srcHdr("_id", fldTypeID), + srcHdr("a", fldTypeInt, "min 0", "max 1000"), + srcHdr("b", fldTypeInt, "min 0", "max 1000"), + srcHdr("ts", fldTypeTimestamp), + ), + srcRows( + srcRow(int64(1), int64(10), int64(100), knownTimestamp()), + ), + ), + SQLTests: []SQLTest{ + { + SQLs: sqls( + "select reverse('this')", + ), + ExpHdrs: hdrs( + hdr("", fldTypeString), + ), + ExpRows: rows( + row(string("siht")), + ), + Compare: CompareExactUnordered, + }, + }, +}