1 Star 0 Fork 0

zhoujin826/tidb

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
builtin_other.go 18.77 KB
一键复制 编辑 原始数据 按行查看 历史
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671
// Copyright 2016 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 (
"strings"
"github.com/juju/errors"
"github.com/pingcap/tidb/mysql"
"github.com/pingcap/tidb/sessionctx"
"github.com/pingcap/tidb/types"
"github.com/pingcap/tidb/types/json"
"github.com/pingcap/tipb/go-tipb"
)
var (
_ functionClass = &inFunctionClass{}
_ functionClass = &rowFunctionClass{}
_ functionClass = &setVarFunctionClass{}
_ functionClass = &getVarFunctionClass{}
_ functionClass = &lockFunctionClass{}
_ functionClass = &releaseLockFunctionClass{}
_ functionClass = &valuesFunctionClass{}
_ functionClass = &bitCountFunctionClass{}
_ functionClass = &getParamFunctionClass{}
)
var (
_ builtinFunc = &builtinSleepSig{}
_ builtinFunc = &builtinInIntSig{}
_ builtinFunc = &builtinInStringSig{}
_ builtinFunc = &builtinInDecimalSig{}
_ builtinFunc = &builtinInRealSig{}
_ builtinFunc = &builtinInTimeSig{}
_ builtinFunc = &builtinInDurationSig{}
_ builtinFunc = &builtinInJSONSig{}
_ builtinFunc = &builtinRowSig{}
_ builtinFunc = &builtinSetVarSig{}
_ builtinFunc = &builtinGetVarSig{}
_ builtinFunc = &builtinLockSig{}
_ builtinFunc = &builtinReleaseLockSig{}
_ builtinFunc = &builtinValuesIntSig{}
_ builtinFunc = &builtinValuesRealSig{}
_ builtinFunc = &builtinValuesDecimalSig{}
_ builtinFunc = &builtinValuesStringSig{}
_ builtinFunc = &builtinValuesTimeSig{}
_ builtinFunc = &builtinValuesDurationSig{}
_ builtinFunc = &builtinValuesJSONSig{}
_ builtinFunc = &builtinBitCountSig{}
_ builtinFunc = &builtinGetParamStringSig{}
)
type inFunctionClass struct {
baseFunctionClass
}
func (c *inFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (sig builtinFunc, err error) {
if err := c.verifyArgs(args); err != nil {
return nil, errors.Trace(err)
}
argTps := make([]types.EvalType, len(args))
for i := range args {
argTps[i] = args[0].GetType().EvalType()
}
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETInt, argTps...)
bf.tp.Flen = 1
switch args[0].GetType().EvalType() {
case types.ETInt:
sig = &builtinInIntSig{baseBuiltinFunc: bf}
sig.setPbCode(tipb.ScalarFuncSig_InInt)
case types.ETString:
sig = &builtinInStringSig{baseBuiltinFunc: bf}
sig.setPbCode(tipb.ScalarFuncSig_InString)
case types.ETReal:
sig = &builtinInRealSig{baseBuiltinFunc: bf}
sig.setPbCode(tipb.ScalarFuncSig_InReal)
case types.ETDecimal:
sig = &builtinInDecimalSig{baseBuiltinFunc: bf}
sig.setPbCode(tipb.ScalarFuncSig_InDecimal)
case types.ETDatetime, types.ETTimestamp:
sig = &builtinInTimeSig{baseBuiltinFunc: bf}
sig.setPbCode(tipb.ScalarFuncSig_InTime)
case types.ETDuration:
sig = &builtinInDurationSig{baseBuiltinFunc: bf}
sig.setPbCode(tipb.ScalarFuncSig_InDuration)
case types.ETJson:
sig = &builtinInJSONSig{baseBuiltinFunc: bf}
sig.setPbCode(tipb.ScalarFuncSig_InJson)
}
return sig, nil
}
// See https://dev.mysql.com/doc/refman/5.7/en/comparison-operators.html#function_in
type builtinInIntSig struct {
baseBuiltinFunc
}
func (b *builtinInIntSig) evalInt(row types.Row) (int64, bool, error) {
arg0, isNull0, err := b.args[0].EvalInt(b.ctx, row)
if isNull0 || err != nil {
return 0, isNull0, errors.Trace(err)
}
isUnsigned0 := mysql.HasUnsignedFlag(b.args[0].GetType().Flag)
var hasNull bool
for _, arg := range b.args[1:] {
evaledArg, isNull, err := arg.EvalInt(b.ctx, row)
if err != nil {
return 0, true, errors.Trace(err)
}
if isNull {
hasNull = true
continue
}
isUnsigned := mysql.HasUnsignedFlag(arg.GetType().Flag)
if isUnsigned0 && isUnsigned {
if evaledArg == arg0 {
return 1, false, nil
}
} else if !isUnsigned0 && !isUnsigned {
if evaledArg == arg0 {
return 1, false, nil
}
} else if !isUnsigned0 && isUnsigned {
if arg0 >= 0 && evaledArg == arg0 {
return 1, false, nil
}
} else {
if evaledArg >= 0 && evaledArg == arg0 {
return 1, false, nil
}
}
}
return 0, hasNull, nil
}
// See https://dev.mysql.com/doc/refman/5.7/en/comparison-operators.html#function_in
type builtinInStringSig struct {
baseBuiltinFunc
}
func (b *builtinInStringSig) evalInt(row types.Row) (int64, bool, error) {
arg0, isNull0, err := b.args[0].EvalString(b.ctx, row)
if isNull0 || err != nil {
return 0, isNull0, errors.Trace(err)
}
var hasNull bool
for _, arg := range b.args[1:] {
evaledArg, isNull, err := arg.EvalString(b.ctx, row)
if err != nil {
return 0, true, errors.Trace(err)
}
if isNull {
hasNull = true
continue
}
if arg0 == evaledArg {
return 1, false, nil
}
}
return 0, hasNull, nil
}
// See https://dev.mysql.com/doc/refman/5.7/en/comparison-operators.html#function_in
type builtinInRealSig struct {
baseBuiltinFunc
}
func (b *builtinInRealSig) evalInt(row types.Row) (int64, bool, error) {
arg0, isNull0, err := b.args[0].EvalReal(b.ctx, row)
if isNull0 || err != nil {
return 0, isNull0, errors.Trace(err)
}
var hasNull bool
for _, arg := range b.args[1:] {
evaledArg, isNull, err := arg.EvalReal(b.ctx, row)
if err != nil {
return 0, true, errors.Trace(err)
}
if isNull {
hasNull = true
continue
}
if arg0 == evaledArg {
return 1, false, nil
}
}
return 0, hasNull, nil
}
// See https://dev.mysql.com/doc/refman/5.7/en/comparison-operators.html#function_in
type builtinInDecimalSig struct {
baseBuiltinFunc
}
func (b *builtinInDecimalSig) evalInt(row types.Row) (int64, bool, error) {
arg0, isNull0, err := b.args[0].EvalDecimal(b.ctx, row)
if isNull0 || err != nil {
return 0, isNull0, errors.Trace(err)
}
var hasNull bool
for _, arg := range b.args[1:] {
evaledArg, isNull, err := arg.EvalDecimal(b.ctx, row)
if err != nil {
return 0, true, errors.Trace(err)
}
if isNull {
hasNull = true
continue
}
if arg0.Compare(evaledArg) == 0 {
return 1, false, nil
}
}
return 0, hasNull, nil
}
// See https://dev.mysql.com/doc/refman/5.7/en/comparison-operators.html#function_in
type builtinInTimeSig struct {
baseBuiltinFunc
}
func (b *builtinInTimeSig) evalInt(row types.Row) (int64, bool, error) {
arg0, isNull0, err := b.args[0].EvalTime(b.ctx, row)
if isNull0 || err != nil {
return 0, isNull0, errors.Trace(err)
}
var hasNull bool
for _, arg := range b.args[1:] {
evaledArg, isNull, err := arg.EvalTime(b.ctx, row)
if err != nil {
return 0, true, errors.Trace(err)
}
if isNull {
hasNull = true
continue
}
if arg0.Compare(evaledArg) == 0 {
return 1, false, nil
}
}
return 0, hasNull, nil
}
// See https://dev.mysql.com/doc/refman/5.7/en/comparison-operators.html#function_in
type builtinInDurationSig struct {
baseBuiltinFunc
}
func (b *builtinInDurationSig) evalInt(row types.Row) (int64, bool, error) {
arg0, isNull0, err := b.args[0].EvalDuration(b.ctx, row)
if isNull0 || err != nil {
return 0, isNull0, errors.Trace(err)
}
var hasNull bool
for _, arg := range b.args[1:] {
evaledArg, isNull, err := arg.EvalDuration(b.ctx, row)
if err != nil {
return 0, true, errors.Trace(err)
}
if isNull {
hasNull = true
continue
}
if arg0.Compare(evaledArg) == 0 {
return 1, false, nil
}
}
return 0, hasNull, nil
}
// See https://dev.mysql.com/doc/refman/5.7/en/comparison-operators.html#function_in
type builtinInJSONSig struct {
baseBuiltinFunc
}
func (b *builtinInJSONSig) evalInt(row types.Row) (int64, bool, error) {
arg0, isNull0, err := b.args[0].EvalJSON(b.ctx, row)
if isNull0 || err != nil {
return 0, isNull0, errors.Trace(err)
}
var hasNull bool
for _, arg := range b.args[1:] {
evaledArg, isNull, err := arg.EvalJSON(b.ctx, row)
if err != nil {
return 0, true, errors.Trace(err)
}
if isNull {
hasNull = true
continue
}
result := json.CompareBinary(evaledArg, arg0)
if result == 0 {
return 1, false, nil
}
}
return 0, hasNull, nil
}
type rowFunctionClass struct {
baseFunctionClass
}
func (c *rowFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (sig builtinFunc, err error) {
if err = c.verifyArgs(args); err != nil {
return nil, errors.Trace(err)
}
argTps := make([]types.EvalType, len(args))
for i := range argTps {
argTps[i] = args[i].GetType().EvalType()
}
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETString, argTps...)
sig = &builtinRowSig{bf}
return sig, nil
}
type builtinRowSig struct {
baseBuiltinFunc
}
// evalString rowFunc should always be flattened in expression rewrite phrase.
func (b *builtinRowSig) evalString(row types.Row) (string, bool, error) {
panic("builtinRowSig.evalString() should never be called.")
}
type setVarFunctionClass struct {
baseFunctionClass
}
func (c *setVarFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (sig builtinFunc, err error) {
if err = errors.Trace(c.verifyArgs(args)); err != nil {
return nil, err
}
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETString, types.ETString, types.ETString)
bf.tp.Flen = args[1].GetType().Flen
// TODO: we should consider the type of the argument, but not take it as string for all situations.
sig = &builtinSetVarSig{bf}
return sig, errors.Trace(err)
}
type builtinSetVarSig struct {
baseBuiltinFunc
}
func (b *builtinSetVarSig) evalString(row types.Row) (res string, isNull bool, err error) {
var varName string
sessionVars := b.ctx.GetSessionVars()
varName, isNull, err = b.args[0].EvalString(b.ctx, row)
if isNull || err != nil {
return "", isNull, errors.Trace(err)
}
res, isNull, err = b.args[1].EvalString(b.ctx, row)
if isNull || err != nil {
return "", isNull, errors.Trace(err)
}
varName = strings.ToLower(varName)
sessionVars.UsersLock.Lock()
sessionVars.Users[varName] = res
sessionVars.UsersLock.Unlock()
return res, false, nil
}
type getVarFunctionClass struct {
baseFunctionClass
}
func (c *getVarFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (sig builtinFunc, err error) {
if err = errors.Trace(c.verifyArgs(args)); err != nil {
return nil, err
}
// TODO: we should consider the type of the argument, but not take it as string for all situations.
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETString, types.ETString)
bf.tp.Flen = mysql.MaxFieldVarCharLength
sig = &builtinGetVarSig{bf}
return sig, nil
}
type builtinGetVarSig struct {
baseBuiltinFunc
}
func (b *builtinGetVarSig) evalString(row types.Row) (string, bool, error) {
sessionVars := b.ctx.GetSessionVars()
varName, isNull, err := b.args[0].EvalString(b.ctx, row)
if isNull || err != nil {
return "", isNull, errors.Trace(err)
}
varName = strings.ToLower(varName)
sessionVars.UsersLock.RLock()
defer sessionVars.UsersLock.RUnlock()
if v, ok := sessionVars.Users[varName]; ok {
return v, false, nil
}
return "", true, nil
}
type valuesFunctionClass struct {
baseFunctionClass
offset int
tp *types.FieldType
}
func (c *valuesFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (sig builtinFunc, err error) {
if err = errors.Trace(c.verifyArgs(args)); err != nil {
return nil, err
}
bf := newBaseBuiltinFunc(ctx, args)
bf.tp = c.tp
switch c.tp.EvalType() {
case types.ETInt:
sig = &builtinValuesIntSig{bf, c.offset}
case types.ETReal:
sig = &builtinValuesRealSig{bf, c.offset}
case types.ETDecimal:
sig = &builtinValuesDecimalSig{bf, c.offset}
case types.ETString:
sig = &builtinValuesStringSig{bf, c.offset}
case types.ETDatetime, types.ETTimestamp:
sig = &builtinValuesTimeSig{bf, c.offset}
case types.ETDuration:
sig = &builtinValuesDurationSig{bf, c.offset}
case types.ETJson:
sig = &builtinValuesJSONSig{bf, c.offset}
}
return sig, nil
}
type builtinValuesIntSig struct {
baseBuiltinFunc
offset int
}
// evalInt evals a builtinValuesIntSig.
// See https://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html#function_values
func (b *builtinValuesIntSig) evalInt(_ types.Row) (int64, bool, error) {
values := b.ctx.GetSessionVars().CurrInsertValues
if values == nil {
return 0, true, errors.New("Session current insert values is nil")
}
row := values.(types.Row)
if b.offset < row.Len() {
if row.IsNull(b.offset) {
return 0, true, nil
}
return row.GetInt64(b.offset), false, nil
}
return 0, true, errors.Errorf("Session current insert values len %d and column's offset %v don't match", row.Len(), b.offset)
}
type builtinValuesRealSig struct {
baseBuiltinFunc
offset int
}
// evalReal evals a builtinValuesRealSig.
// See https://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html#function_values
func (b *builtinValuesRealSig) evalReal(_ types.Row) (float64, bool, error) {
values := b.ctx.GetSessionVars().CurrInsertValues
if values == nil {
return 0, true, errors.New("Session current insert values is nil")
}
row := values.(types.Row)
if b.offset < row.Len() {
if row.IsNull(b.offset) {
return 0, true, nil
}
return row.GetFloat64(b.offset), false, nil
}
return 0, true, errors.Errorf("Session current insert values len %d and column's offset %v don't match", row.Len(), b.offset)
}
type builtinValuesDecimalSig struct {
baseBuiltinFunc
offset int
}
// evalDecimal evals a builtinValuesDecimalSig.
// See https://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html#function_values
func (b *builtinValuesDecimalSig) evalDecimal(_ types.Row) (*types.MyDecimal, bool, error) {
values := b.ctx.GetSessionVars().CurrInsertValues
if values == nil {
return nil, true, errors.New("Session current insert values is nil")
}
row := values.(types.Row)
if b.offset < row.Len() {
if row.IsNull(b.offset) {
return nil, true, nil
}
return row.GetMyDecimal(b.offset), false, nil
}
return nil, true, errors.Errorf("Session current insert values len %d and column's offset %v don't match", row.Len(), b.offset)
}
type builtinValuesStringSig struct {
baseBuiltinFunc
offset int
}
// evalString evals a builtinValuesStringSig.
// See https://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html#function_values
func (b *builtinValuesStringSig) evalString(_ types.Row) (string, bool, error) {
values := b.ctx.GetSessionVars().CurrInsertValues
if values == nil {
return "", true, errors.New("Session current insert values is nil")
}
row := values.(types.Row)
if b.offset < row.Len() {
if row.IsNull(b.offset) {
return "", true, nil
}
return row.GetString(b.offset), false, nil
}
return "", true, errors.Errorf("Session current insert values len %d and column's offset %v don't match", row.Len(), b.offset)
}
type builtinValuesTimeSig struct {
baseBuiltinFunc
offset int
}
// evalTime evals a builtinValuesTimeSig.
// See https://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html#function_values
func (b *builtinValuesTimeSig) evalTime(_ types.Row) (types.Time, bool, error) {
values := b.ctx.GetSessionVars().CurrInsertValues
if values == nil {
return types.Time{}, true, errors.New("Session current insert values is nil")
}
row := values.(types.Row)
if b.offset < row.Len() {
if row.IsNull(b.offset) {
return types.Time{}, true, nil
}
return row.GetTime(b.offset), false, nil
}
return types.Time{}, true, errors.Errorf("Session current insert values len %d and column's offset %v don't match", row.Len(), b.offset)
}
type builtinValuesDurationSig struct {
baseBuiltinFunc
offset int
}
// evalDuration evals a builtinValuesDurationSig.
// See https://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html#function_values
func (b *builtinValuesDurationSig) evalDuration(_ types.Row) (types.Duration, bool, error) {
values := b.ctx.GetSessionVars().CurrInsertValues
if values == nil {
return types.Duration{}, true, errors.New("Session current insert values is nil")
}
row := values.(types.Row)
if b.offset < row.Len() {
if row.IsNull(b.offset) {
return types.Duration{}, true, nil
}
return row.GetDuration(b.offset), false, nil
}
return types.Duration{}, true, errors.Errorf("Session current insert values len %d and column's offset %v don't match", row.Len(), b.offset)
}
type builtinValuesJSONSig struct {
baseBuiltinFunc
offset int
}
// evalJSON evals a builtinValuesJSONSig.
// See https://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html#function_values
func (b *builtinValuesJSONSig) evalJSON(_ types.Row) (json.BinaryJSON, bool, error) {
values := b.ctx.GetSessionVars().CurrInsertValues
if values == nil {
return json.BinaryJSON{}, true, errors.New("Session current insert values is nil")
}
row := values.(types.Row)
if b.offset < row.Len() {
if row.IsNull(b.offset) {
return json.BinaryJSON{}, true, nil
}
return row.GetJSON(b.offset), false, nil
}
return json.BinaryJSON{}, true, errors.Errorf("Session current insert values len %d and column's offset %v don't match", row.Len(), b.offset)
}
type bitCountFunctionClass struct {
baseFunctionClass
}
func (c *bitCountFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {
if err := c.verifyArgs(args); err != nil {
return nil, errors.Trace(err)
}
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETInt, types.ETInt)
bf.tp.Flen = 2
sig := &builtinBitCountSig{bf}
return sig, nil
}
type builtinBitCountSig struct {
baseBuiltinFunc
}
// evalInt evals BIT_COUNT(N).
// See https://dev.mysql.com/doc/refman/5.7/en/bit-functions.html#function_bit-count
func (b *builtinBitCountSig) evalInt(row types.Row) (int64, bool, error) {
n, isNull, err := b.args[0].EvalInt(b.ctx, row)
if err != nil || isNull {
if err != nil && types.ErrOverflow.Equal(err) {
return 64, false, nil
}
return 0, true, errors.Trace(err)
}
var count int64
for ; n != 0; n = (n - 1) & n {
count++
}
return count, false, nil
}
// getParamFunctionClass for plan cache of prepared statements
type getParamFunctionClass struct {
baseFunctionClass
}
// getFunction gets function
// TODO: more typed functions will be added when typed parameters are supported.
func (c *getParamFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {
if err := c.verifyArgs(args); err != nil {
return nil, errors.Trace(err)
}
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETString, types.ETInt)
bf.tp.Flen = mysql.MaxFieldVarCharLength
sig := &builtinGetParamStringSig{bf}
return sig, nil
}
type builtinGetParamStringSig struct {
baseBuiltinFunc
}
func (b *builtinGetParamStringSig) evalString(row types.Row) (string, bool, error) {
sessionVars := b.ctx.GetSessionVars()
idx, isNull, err := b.args[0].EvalInt(b.ctx, row)
if isNull || err != nil {
return "", isNull, errors.Trace(err)
}
v := sessionVars.PreparedParams[idx]
dt := v.(types.Datum)
str, err := (&dt).ToString()
if err != nil {
return "", true, nil
}
return str, false, nil
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/zhoujin826/tidb.git
git@gitee.com:zhoujin826/tidb.git
zhoujin826
tidb
tidb
v1.1.0-beta

搜索帮助