mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-08-28 02:44:59 +00:00
FB-1862: Implement Str() scalar string function (#2215)
* Implement STR()
This commit is contained in:
parent
3dcc55203f
commit
5c6361918a
4 changed files with 217 additions and 0 deletions
|
|
@ -1558,6 +1558,8 @@ func (n *callPlanExpression) Evaluate(currentRow []interface{}) (interface{}, er
|
|||
return n.EvaluateFormat(currentRow)
|
||||
case "CHARINDEX":
|
||||
return n.EvaluateCharIndex(currentRow)
|
||||
case "STR":
|
||||
return n.EvaluateStr(currentRow)
|
||||
default:
|
||||
return nil, sql3.NewErrInternalf("unhandled function name '%s'", n.name)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -278,6 +278,8 @@ func (p *ExecutionPlanner) analyzeCallExpression(ctx context.Context, call *pars
|
|||
return p.analyseFunctionFormat(call, scope)
|
||||
case "CHARINDEX":
|
||||
return p.analyseFunctionCharIndex(call, scope)
|
||||
case "STR":
|
||||
return p.analyseFunctionStr(call, scope)
|
||||
default:
|
||||
return nil, sql3.NewErrCallUnknownFunction(call.Name.NamePos.Line, call.Name.NamePos.Column, call.Name.Name)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import (
|
|||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/featurebasedb/featurebase/v3/pql"
|
||||
"github.com/featurebasedb/featurebase/v3/sql3"
|
||||
"github.com/featurebasedb/featurebase/v3/sql3/parser"
|
||||
)
|
||||
|
|
@ -783,3 +784,85 @@ func (n *callPlanExpression) EvaluateCharIndex(currentRow []interface{}) (interf
|
|||
}
|
||||
return int64(res), nil
|
||||
}
|
||||
|
||||
func (p *ExecutionPlanner) analyseFunctionStr(call *parser.Call, scope parser.Statement) (parser.Expr, error) {
|
||||
if len(call.Args) < 1 || len(call.Args) > 3 {
|
||||
return nil, sql3.NewErrCallParameterCountMismatch(call.Rparen.Line, call.Rparen.Column, call.Name.Name, 1, len(call.Args))
|
||||
}
|
||||
targetType := parser.NewDataTypeDecimal(4)
|
||||
if !typesAreAssignmentCompatible(targetType, call.Args[0].DataType()) {
|
||||
return nil, sql3.NewErrTypeAssignmentIncompatible(call.Args[0].Pos().Line, call.Args[0].Pos().Column, call.Args[0].DataType().TypeDescription(), targetType.TypeDescription())
|
||||
}
|
||||
|
||||
// the second and third parameters are optional
|
||||
for i := 1; i < len(call.Args); i++ {
|
||||
if typeIsVoid(call.Args[i].DataType()) {
|
||||
return nil, sql3.NewErrLiteralNullNotAllowed(call.Args[i].Pos().Line, call.Args[i].Pos().Column)
|
||||
}
|
||||
if !typeIsInteger(call.Args[i].DataType()) {
|
||||
return nil, sql3.NewErrIntExpressionExpected(call.Args[i].Pos().Line, call.Args[i].Pos().Column)
|
||||
}
|
||||
}
|
||||
|
||||
call.ResultDataType = parser.NewDataTypeString()
|
||||
|
||||
return call, nil
|
||||
}
|
||||
|
||||
func (n *callPlanExpression) EvaluateStr(currentRow []interface{}) (interface{}, error) {
|
||||
argOneEval, err := n.args[0].Evaluate(currentRow)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if argOneEval == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
coercedValue, err := coerceValue(n.args[0].Type(), parser.NewDataTypeDecimal(4), argOneEval, parser.Pos{})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
decimalArgOne, ok := coercedValue.(pql.Decimal)
|
||||
if !ok {
|
||||
return nil, sql3.NewErrUnexpectedTypeConversion(0, 0, coercedValue)
|
||||
}
|
||||
|
||||
intArgTwo := int64(10)
|
||||
if len(n.args) > 1 {
|
||||
argEval, err := n.args[1].Evaluate(currentRow)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
intArgTwo, ok = argEval.(int64)
|
||||
if !ok {
|
||||
return nil, sql3.NewErrUnexpectedTypeConversion(0, 0, argEval)
|
||||
}
|
||||
}
|
||||
|
||||
intArgThree := int64(0)
|
||||
if len(n.args) > 2 {
|
||||
argEval, err := n.args[2].Evaluate(currentRow)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
intArgThree, ok = argEval.(int64)
|
||||
if !ok {
|
||||
return nil, sql3.NewErrUnexpectedTypeConversion(0, 0, argEval)
|
||||
}
|
||||
}
|
||||
|
||||
floatValue := decimalArgOne.Float64()
|
||||
strFormat := fmt.Sprintf("%%%d.%df", intArgTwo, intArgThree)
|
||||
decimalString := fmt.Sprintf(strFormat, floatValue)
|
||||
|
||||
// check if value can be displayed within allocated length
|
||||
if int64(len(decimalString)) > intArgTwo {
|
||||
decimalString = ""
|
||||
for i := int64(0); i < intArgTwo; i++ {
|
||||
decimalString += "*"
|
||||
}
|
||||
}
|
||||
|
||||
return decimalString, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -982,5 +982,135 @@ var stringScalarFunctionsTests = TableTest{
|
|||
),
|
||||
Compare: CompareExactOrdered,
|
||||
},
|
||||
{
|
||||
name: "StrIntValue",
|
||||
SQLs: sqls(
|
||||
"select str(12345)",
|
||||
),
|
||||
ExpHdrs: hdrs(
|
||||
hdr("", fldTypeString),
|
||||
),
|
||||
ExpRows: rows(
|
||||
row(string(" 12345")),
|
||||
),
|
||||
Compare: CompareExactOrdered,
|
||||
},
|
||||
{
|
||||
name: "StrIntValueAtEdge",
|
||||
SQLs: sqls(
|
||||
"select str(12345, 5)",
|
||||
),
|
||||
ExpHdrs: hdrs(
|
||||
hdr("", fldTypeString),
|
||||
),
|
||||
ExpRows: rows(
|
||||
row(string("12345")),
|
||||
),
|
||||
Compare: CompareExactOrdered,
|
||||
},
|
||||
{
|
||||
name: "StrIntValueWithPrecision",
|
||||
SQLs: sqls(
|
||||
"select str(12345, 5, 5)",
|
||||
),
|
||||
ExpHdrs: hdrs(
|
||||
hdr("", fldTypeString),
|
||||
),
|
||||
ExpRows: rows(
|
||||
row(string("*****")),
|
||||
),
|
||||
Compare: CompareExactOrdered,
|
||||
},
|
||||
{
|
||||
name: "StrDecimalValue",
|
||||
SQLs: sqls(
|
||||
"select str(12345.678)",
|
||||
),
|
||||
ExpHdrs: hdrs(
|
||||
hdr("", fldTypeString),
|
||||
),
|
||||
ExpRows: rows(
|
||||
row(string(" 12346")),
|
||||
),
|
||||
Compare: CompareExactOrdered,
|
||||
},
|
||||
{
|
||||
name: "StrDecimalValueAtEdge",
|
||||
SQLs: sqls(
|
||||
"select str(12345.19, 5)",
|
||||
),
|
||||
ExpHdrs: hdrs(
|
||||
hdr("", fldTypeString),
|
||||
),
|
||||
ExpRows: rows(
|
||||
row(string("12345")),
|
||||
),
|
||||
Compare: CompareExactOrdered,
|
||||
},
|
||||
{
|
||||
name: "StrDecimalValueWithPrecision",
|
||||
SQLs: sqls(
|
||||
"select str(12345.789, 8, 2)",
|
||||
),
|
||||
ExpHdrs: hdrs(
|
||||
hdr("", fldTypeString),
|
||||
),
|
||||
ExpRows: rows(
|
||||
row(string("12345.79")),
|
||||
),
|
||||
Compare: CompareExactOrdered,
|
||||
},
|
||||
{
|
||||
name: "StrNegativeDecimalValueWithPrecision",
|
||||
SQLs: sqls(
|
||||
"select str(-2345.789, 8, 2)",
|
||||
),
|
||||
ExpHdrs: hdrs(
|
||||
hdr("", fldTypeString),
|
||||
),
|
||||
ExpRows: rows(
|
||||
row(string("-2345.79")),
|
||||
),
|
||||
Compare: CompareExactOrdered,
|
||||
},
|
||||
{
|
||||
name: "TooFewArgumentsforStr",
|
||||
SQLs: sqls(
|
||||
"select str()",
|
||||
),
|
||||
ExpErr: "'str': count of formal parameters (1) does not match count of actual parameters (0)",
|
||||
},
|
||||
{
|
||||
name: "TooManyArgumentsforStr",
|
||||
SQLs: sqls(
|
||||
"select str(1, 1, 1, 1)",
|
||||
),
|
||||
ExpErr: "'str': count of formal parameters (1) does not match count of actual parameters (4)",
|
||||
},
|
||||
{
|
||||
name: "StrPrecisionLargerThanValue",
|
||||
SQLs: sqls(
|
||||
"select str(1234.99, 10, 200)",
|
||||
),
|
||||
ExpHdrs: hdrs(
|
||||
hdr("", fldTypeString),
|
||||
),
|
||||
ExpRows: rows(
|
||||
row(string("**********")),
|
||||
),
|
||||
Compare: CompareExactOrdered,
|
||||
}, {
|
||||
name: "StrNull",
|
||||
SQLs: sqls(
|
||||
"select str(null)",
|
||||
),
|
||||
ExpHdrs: hdrs(
|
||||
hdr("", fldTypeString),
|
||||
),
|
||||
ExpRows: rows(
|
||||
row(nil),
|
||||
),
|
||||
Compare: CompareExactUnordered,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue