From 042280e1bf6ec4f22157e4e0928e2bee13f5a044 Mon Sep 17 00:00:00 2001 From: Han Fei Date: Tue, 3 Jan 2017 11:21:14 +0800 Subject: [PATCH] expression: add baseFunctionClass (#2361) --- expression/builtin.go | 36 +++++++++++++++++++++++++++++++++++ expression/expression.go | 5 ++++- expression/scalar_function.go | 4 ++-- 3 files changed, 42 insertions(+), 3 deletions(-) diff --git a/expression/builtin.go b/expression/builtin.go index 98a52e6312..193ad24f63 100644 --- a/expression/builtin.go +++ b/expression/builtin.go @@ -100,6 +100,21 @@ type builtinFunc interface { getCtx() context.Context } +// baseFunctionClass will be contained in every struct that implement functionClass interface. +type baseFunctionClass struct { + funcName string + minArgs int + maxArgs int +} + +func (b *baseFunctionClass) verifyArgs(args []Expression) error { + l := len(args) + if l < b.minArgs || (b.maxArgs != -1 && l > b.maxArgs) { + return errIncorrectParameterCount.GenByArgs(b.funcName) + } + return nil +} + // builtinFunc stands for a class for a function which may contains multiple functions. type functionClass interface { // getFunction gets a function signature by the types and the counts of given arguments. @@ -286,6 +301,27 @@ var DynamicFuncs = map[string]int{ ast.Values: 0, } +// Function family for coalesce. +type coalesceFunctionClass struct { + baseFunctionClass +} + +func (c *coalesceFunctionClass) getFunction(args []Expression, ctx context.Context) (builtinFunc, error) { + return &builtinCoalesceSig{newBaseBuiltinFunc(args, ctx)}, errors.Trace(c.verifyArgs(args)) +} + +type builtinCoalesceSig struct { + baseBuiltinFunc +} + +func (b *builtinCoalesceSig) eval(row []types.Datum) (types.Datum, error) { + args, err := b.evalArgs(row) + if err != nil { + return types.Datum{}, errors.Trace(err) + } + return builtinCoalesce(args, b.ctx) +} + // See http://dev.mysql.com/doc/refman/5.7/en/comparison-operators.html#function_coalesce func builtinCoalesce(args []types.Datum, ctx context.Context) (d types.Datum, err error) { for _, d = range args { diff --git a/expression/expression.go b/expression/expression.go index 383fb1e2b4..89ffdd939e 100644 --- a/expression/expression.go +++ b/expression/expression.go @@ -31,13 +31,15 @@ import ( // Error instances. var ( errInvalidOperation = terror.ClassExpression.New(codeInvalidOperation, "invalid operation") - errIncorrectParameterCount = terror.ClassExpression.New(codeIncorrectParameterCount, "Incorrect parameter count") + errIncorrectParameterCount = terror.ClassExpression.New(codeIncorrectParameterCount, "Incorrect parameter count in the call to native function '%s'") + errFunctionNotExists = terror.ClassExpression.New(codeFunctionNotExists, "FUNCTION %s does not exist") ) // Error codes. const ( codeInvalidOperation terror.ErrCode = 1 codeIncorrectParameterCount = 1582 + codeFunctionNotExists = 1305 ) // EvalAstExpr evaluates ast expression directly. @@ -297,6 +299,7 @@ func NewValuesFunc(v *ast.ValuesExpr) *ScalarFunction { func init() { expressionMySQLErrCodes := map[terror.ErrCode]uint16{ codeIncorrectParameterCount: mysql.ErrWrongParamcountToNativeFct, + codeFunctionNotExists: mysql.ErrSpDoesNotExist, } terror.ErrClassToMySQLCodes[terror.ClassExpression] = expressionMySQLErrCodes } diff --git a/expression/scalar_function.go b/expression/scalar_function.go index eacb5e54a9..5abb597876 100644 --- a/expression/scalar_function.go +++ b/expression/scalar_function.go @@ -62,10 +62,10 @@ func (sf *ScalarFunction) MarshalJSON() ([]byte, error) { func NewFunction(funcName string, retType *types.FieldType, args ...Expression) (Expression, error) { f, ok := Funcs[funcName] if !ok { - return nil, errors.Errorf("Function %s is not implemented.", funcName) + return nil, errFunctionNotExists.GenByArgs(funcName) } if len(args) < f.MinArgs || (f.MaxArgs != -1 && len(args) > f.MaxArgs) { - return nil, errIncorrectParameterCount.Gen("Incorrect parameter count in the call to native function %s", funcName) + return nil, errIncorrectParameterCount.GenByArgs(funcName) } funcArgs := make([]Expression, len(args)) copy(funcArgs, args)