From 838bc2dadb6fcbc04add7abc2d7fd8e60aeac30e Mon Sep 17 00:00:00 2001 From: Bruce Baranowski <92940816+bruce-b-molecula@users.noreply.github.com> Date: Tue, 13 Dec 2022 14:59:05 -0500 Subject: [PATCH] FB-1719: implement SQL3 lower() (#2358) * Implemented SQL3 LOWER() (cherry picked from commit 4773aabc4ebe71e21e549fafb3d6ca6f4ba4e3e6) --- sql3/planner/expression.go | 2 ++ sql3/planner/expressionanalyzercall.go | 2 ++ sql3/planner/inbuiltfunctionsstring.go | 25 ++++++++++++++++++++++- sql3/test/defs/defs_string_functions.go | 27 +++++++++++++++++++++++++ 4 files changed, 55 insertions(+), 1 deletion(-) diff --git a/sql3/planner/expression.go b/sql3/planner/expression.go index ed6f4e087..617f3a9bf 100644 --- a/sql3/planner/expression.go +++ b/sql3/planner/expression.go @@ -1482,6 +1482,8 @@ func (n *callPlanExpression) Evaluate(currentRow []interface{}) (interface{}, er return n.EvaluateUpper(currentRow) case "SUBSTRING": return n.EvaluateSubstring(currentRow) + case "LOWER": + return n.EvaluateLower(currentRow) case "REPLACEALL": return n.EvaluateReplaceAll(currentRow) case "TRIM": diff --git a/sql3/planner/expressionanalyzercall.go b/sql3/planner/expressionanalyzercall.go index ad6dd991f..7e881c40f 100644 --- a/sql3/planner/expressionanalyzercall.go +++ b/sql3/planner/expressionanalyzercall.go @@ -247,6 +247,8 @@ func (p *ExecutionPlanner) analyzeCallExpression(call *parser.Call, scope parser return p.analyzeFunctionUpper(call, scope) case "SUBSTRING": return p.analyseFunctionSubstring(call, scope) + case "LOWER": + return p.analyzeFunctionLower(call, scope) case "REPLACEALL": return p.analyseFunctionReplaceAll(call, scope) case "TRIM": diff --git a/sql3/planner/inbuiltfunctionsstring.go b/sql3/planner/inbuiltfunctionsstring.go index 0718a542d..1cc63c863 100644 --- a/sql3/planner/inbuiltfunctionsstring.go +++ b/sql3/planner/inbuiltfunctionsstring.go @@ -44,6 +44,20 @@ func (p *ExecutionPlanner) analyseFunctionSubstring(call *parser.Call, scope par return call, nil } +func (p *ExecutionPlanner) analyzeFunctionLower(call *parser.Call, scope parser.Statement) (parser.Expr, error) { + 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 +} + func (p *ExecutionPlanner) analyseFunctionReplaceAll(call *parser.Call, scope parser.Statement) (parser.Expr, error) { if len(call.Args) != 3 { return nil, sql3.NewErrCallParameterCountMismatch(call.Rparen.Line, call.Rparen.Column, call.Name.Name, 3, len(call.Args)) @@ -146,6 +160,15 @@ func (n *callPlanExpression) EvaluateSubstring(currentRow []interface{}) (interf return stringArgOne[startIndex:endIndex], nil } +func (n *callPlanExpression) EvaluateLower(currentRow []interface{}) (interface{}, error) { + stringArgOne, err := evaluateStringArg(n.args[0], currentRow) + if err != nil { + return nil, err + } + + return strings.ToLower(stringArgOne), nil +} + // takes string, findstring, replacestring. // replaces all occurances of findstring with replacestring func (n *callPlanExpression) EvaluateReplaceAll(currentRow []interface{}) (interface{}, error) { @@ -177,7 +200,7 @@ func evaluateStringArg(n types.PlanExpression, currentRow []interface{}) (string return stringArgOne, nil } -//Analyze function for Trim +// Analyze function for Trim func (p *ExecutionPlanner) analyseFunctionTrim(call *parser.Call, scope parser.Statement) (parser.Expr, error) { //one argument for Trim Function if len(call.Args) != 1 { diff --git a/sql3/test/defs/defs_string_functions.go b/sql3/test/defs/defs_string_functions.go index 1002597e0..5c1992242 100644 --- a/sql3/test/defs/defs_string_functions.go +++ b/sql3/test/defs/defs_string_functions.go @@ -135,6 +135,33 @@ var stringScalarFunctionsTests = TableTest{ ), ExpErr: "string expression expected", }, + { + name: "StringLower", + SQLs: sqls( + "select lower('AaBbCcDdEeFfGg-_0123')", + ), + ExpHdrs: hdrs( + hdr("", fldTypeString), + ), + ExpRows: rows( + row(string("aabbccddeeffgg-_0123")), + ), + Compare: CompareExactOrdered, + }, + { + name: "IncorrectArgumentsforLower", + SQLs: sqls( + "select lower('LOWER','lower')", + ), + ExpErr: "'lower': count of formal parameters (1) does not match count of actual parameters (2)", + }, + { + name: "IncorrectInputforLower", + SQLs: sqls( + "select lower(1234)", + ), + ExpErr: "string expression expected", + }, { name: "ReplaceAllString", SQLs: sqls(