expression: add baseFunctionClass (#2361)

This commit is contained in:
Han Fei
2017-01-03 11:21:14 +08:00
committed by GitHub
parent 235a7979b9
commit 042280e1bf
3 changed files with 42 additions and 3 deletions

View File

@ -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 {

View File

@ -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
}

View File

@ -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)