115 lines
3.2 KiB
Go
115 lines
3.2 KiB
Go
// Copyright 2015 PingCAP, Inc.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package expression
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/juju/errors"
|
|
"github.com/pingcap/tidb/context"
|
|
)
|
|
|
|
// FunctionSubstring returns the substring as specified.
|
|
// See: https://dev.mysql.com/doc/refman/5.7/en/string-functions.html#function_substring
|
|
type FunctionSubstring struct {
|
|
StrExpr Expression
|
|
Pos Expression
|
|
Len Expression
|
|
}
|
|
|
|
// Clone implements the Expression Clone interface.
|
|
func (f *FunctionSubstring) Clone() Expression {
|
|
expr := f.StrExpr.Clone()
|
|
nf := &FunctionSubstring{
|
|
StrExpr: expr,
|
|
Pos: f.Pos,
|
|
Len: f.Len,
|
|
}
|
|
return nf
|
|
}
|
|
|
|
// IsStatic implements the Expression IsStatic interface.
|
|
func (f *FunctionSubstring) IsStatic() bool {
|
|
return f.StrExpr.IsStatic()
|
|
}
|
|
|
|
// String implements the Expression String interface.
|
|
func (f *FunctionSubstring) String() string {
|
|
if f.Len != nil {
|
|
return fmt.Sprintf("SUBSTRING(%s, %s, %s)", f.StrExpr.String(), f.Pos.String(), f.Len.String())
|
|
}
|
|
return fmt.Sprintf("SUBSTRING(%s, %s)", f.StrExpr.String(), f.Pos.String())
|
|
}
|
|
|
|
// Eval implements the Expression Eval interface.
|
|
func (f *FunctionSubstring) Eval(ctx context.Context, args map[interface{}]interface{}) (interface{}, error) {
|
|
fs, err := f.StrExpr.Eval(ctx, args)
|
|
if err != nil {
|
|
return nil, errors.Trace(err)
|
|
}
|
|
str, ok := fs.(string)
|
|
if !ok {
|
|
return nil, errors.Errorf("Substring invalid args, need string but get %T", fs)
|
|
}
|
|
|
|
t, err := f.Pos.Eval(ctx, args)
|
|
if err != nil {
|
|
return nil, errors.Trace(err)
|
|
}
|
|
p, ok := t.(int64)
|
|
if !ok {
|
|
return nil, errors.Errorf("Substring invalid pos args, need int but get %T", t)
|
|
}
|
|
pos := int(p)
|
|
|
|
length := -1
|
|
if f.Len != nil {
|
|
t, err := f.Len.Eval(ctx, args)
|
|
if err != nil {
|
|
return nil, errors.Trace(err)
|
|
}
|
|
p, ok := t.(int64)
|
|
if !ok {
|
|
return nil, errors.Errorf("Substring invalid len args, need int but get %T", t)
|
|
}
|
|
length = int(p)
|
|
}
|
|
// The forms without a len argument return a substring from string str starting at position pos.
|
|
// The forms with a len argument return a substring len characters long from string str, starting at position pos.
|
|
// The forms that use FROM are standard SQL syntax. It is also possible to use a negative value for pos.
|
|
// In this case, the beginning of the substring is pos characters from the end of the string, rather than the beginning.
|
|
// A negative value may be used for pos in any of the forms of this function.
|
|
if pos < 0 {
|
|
pos = len(str) + pos
|
|
} else {
|
|
pos--
|
|
}
|
|
if pos > len(str) || pos <= 0 {
|
|
pos = len(str)
|
|
}
|
|
end := len(str)
|
|
if length != -1 {
|
|
end = pos + length
|
|
}
|
|
if end > len(str) {
|
|
end = len(str)
|
|
}
|
|
return str[pos:end], nil
|
|
}
|
|
|
|
// Accept implements Expression Accept interface.
|
|
func (f *FunctionSubstring) Accept(v Visitor) (Expression, error) {
|
|
return v.VisitFunctionSubstring(f)
|
|
}
|