expression: add baseFunctionClass (#2361)
This commit is contained in:
@ -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 {
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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)
|
||||
|
||||
Reference in New Issue
Block a user