592 lines
16 KiB
Go
592 lines
16 KiB
Go
// Copyright 2013 The ql Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSES/QL-LICENSE file.
|
|
|
|
// 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 (
|
|
"sort"
|
|
|
|
"github.com/pingcap/errors"
|
|
"github.com/pingcap/parser/mysql"
|
|
"github.com/pingcap/tidb/sessionctx"
|
|
"github.com/pingcap/tidb/types"
|
|
"github.com/pingcap/tidb/util/chunk"
|
|
"github.com/pingcap/tidb/util/printer"
|
|
)
|
|
|
|
var (
|
|
_ functionClass = &databaseFunctionClass{}
|
|
_ functionClass = &foundRowsFunctionClass{}
|
|
_ functionClass = ¤tUserFunctionClass{}
|
|
_ functionClass = ¤tRoleFunctionClass{}
|
|
_ functionClass = &userFunctionClass{}
|
|
_ functionClass = &connectionIDFunctionClass{}
|
|
_ functionClass = &lastInsertIDFunctionClass{}
|
|
_ functionClass = &versionFunctionClass{}
|
|
_ functionClass = &benchmarkFunctionClass{}
|
|
_ functionClass = &charsetFunctionClass{}
|
|
_ functionClass = &coercibilityFunctionClass{}
|
|
_ functionClass = &collationFunctionClass{}
|
|
_ functionClass = &rowCountFunctionClass{}
|
|
_ functionClass = &tidbVersionFunctionClass{}
|
|
_ functionClass = &tidbIsDDLOwnerFunctionClass{}
|
|
)
|
|
|
|
var (
|
|
_ builtinFunc = &builtinDatabaseSig{}
|
|
_ builtinFunc = &builtinFoundRowsSig{}
|
|
_ builtinFunc = &builtinCurrentUserSig{}
|
|
_ builtinFunc = &builtinUserSig{}
|
|
_ builtinFunc = &builtinConnectionIDSig{}
|
|
_ builtinFunc = &builtinLastInsertIDSig{}
|
|
_ builtinFunc = &builtinLastInsertIDWithIDSig{}
|
|
_ builtinFunc = &builtinVersionSig{}
|
|
_ builtinFunc = &builtinTiDBVersionSig{}
|
|
_ builtinFunc = &builtinRowCountSig{}
|
|
)
|
|
|
|
type databaseFunctionClass struct {
|
|
baseFunctionClass
|
|
}
|
|
|
|
func (c *databaseFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {
|
|
if err := c.verifyArgs(args); err != nil {
|
|
return nil, err
|
|
}
|
|
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETString)
|
|
bf.tp.Flen = 64
|
|
sig := &builtinDatabaseSig{bf}
|
|
return sig, nil
|
|
}
|
|
|
|
type builtinDatabaseSig struct {
|
|
baseBuiltinFunc
|
|
}
|
|
|
|
func (b *builtinDatabaseSig) Clone() builtinFunc {
|
|
newSig := &builtinDatabaseSig{}
|
|
newSig.cloneFrom(&b.baseBuiltinFunc)
|
|
return newSig
|
|
}
|
|
|
|
// evalString evals a builtinDatabaseSig.
|
|
// See https://dev.mysql.com/doc/refman/5.7/en/information-functions.html
|
|
func (b *builtinDatabaseSig) evalString(row chunk.Row) (string, bool, error) {
|
|
currentDB := b.ctx.GetSessionVars().CurrentDB
|
|
return currentDB, currentDB == "", nil
|
|
}
|
|
|
|
type foundRowsFunctionClass struct {
|
|
baseFunctionClass
|
|
}
|
|
|
|
func (c *foundRowsFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {
|
|
if err := c.verifyArgs(args); err != nil {
|
|
return nil, err
|
|
}
|
|
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETInt)
|
|
bf.tp.Flag |= mysql.UnsignedFlag
|
|
sig := &builtinFoundRowsSig{bf}
|
|
return sig, nil
|
|
}
|
|
|
|
type builtinFoundRowsSig struct {
|
|
baseBuiltinFunc
|
|
}
|
|
|
|
func (b *builtinFoundRowsSig) Clone() builtinFunc {
|
|
newSig := &builtinFoundRowsSig{}
|
|
newSig.cloneFrom(&b.baseBuiltinFunc)
|
|
return newSig
|
|
}
|
|
|
|
// evalInt evals a builtinFoundRowsSig.
|
|
// See https://dev.mysql.com/doc/refman/5.7/en/information-functions.html#function_found-rows
|
|
// TODO: SQL_CALC_FOUND_ROWS and LIMIT not support for now, We will finish in another PR.
|
|
func (b *builtinFoundRowsSig) evalInt(row chunk.Row) (int64, bool, error) {
|
|
data := b.ctx.GetSessionVars()
|
|
if data == nil {
|
|
return 0, true, errors.Errorf("Missing session variable when eval builtin")
|
|
}
|
|
return int64(data.LastFoundRows), false, nil
|
|
}
|
|
|
|
type currentUserFunctionClass struct {
|
|
baseFunctionClass
|
|
}
|
|
|
|
func (c *currentUserFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {
|
|
if err := c.verifyArgs(args); err != nil {
|
|
return nil, err
|
|
}
|
|
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETString)
|
|
bf.tp.Flen = 64
|
|
sig := &builtinCurrentUserSig{bf}
|
|
return sig, nil
|
|
}
|
|
|
|
type builtinCurrentUserSig struct {
|
|
baseBuiltinFunc
|
|
}
|
|
|
|
func (b *builtinCurrentUserSig) Clone() builtinFunc {
|
|
newSig := &builtinCurrentUserSig{}
|
|
newSig.cloneFrom(&b.baseBuiltinFunc)
|
|
return newSig
|
|
}
|
|
|
|
// evalString evals a builtinCurrentUserSig.
|
|
// See https://dev.mysql.com/doc/refman/5.7/en/information-functions.html#function_current-user
|
|
func (b *builtinCurrentUserSig) evalString(row chunk.Row) (string, bool, error) {
|
|
data := b.ctx.GetSessionVars()
|
|
if data == nil || data.User == nil {
|
|
return "", true, errors.Errorf("Missing session variable when eval builtin")
|
|
}
|
|
return data.User.AuthIdentityString(), false, nil
|
|
}
|
|
|
|
type currentRoleFunctionClass struct {
|
|
baseFunctionClass
|
|
}
|
|
|
|
func (c *currentRoleFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {
|
|
if err := c.verifyArgs(args); err != nil {
|
|
return nil, err
|
|
}
|
|
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETString)
|
|
bf.tp.Flen = 64
|
|
sig := &builtinCurrentRoleSig{bf}
|
|
return sig, nil
|
|
}
|
|
|
|
type builtinCurrentRoleSig struct {
|
|
baseBuiltinFunc
|
|
}
|
|
|
|
func (b *builtinCurrentRoleSig) Clone() builtinFunc {
|
|
newSig := &builtinCurrentRoleSig{}
|
|
newSig.cloneFrom(&b.baseBuiltinFunc)
|
|
return newSig
|
|
}
|
|
|
|
// evalString evals a builtinCurrentUserSig.
|
|
// See https://dev.mysql.com/doc/refman/5.7/en/information-functions.html#function_current-user
|
|
func (b *builtinCurrentRoleSig) evalString(row chunk.Row) (string, bool, error) {
|
|
data := b.ctx.GetSessionVars()
|
|
if data == nil || data.ActiveRoles == nil {
|
|
return "", true, errors.Errorf("Missing session variable when eval builtin")
|
|
}
|
|
if len(data.ActiveRoles) == 0 {
|
|
return "", false, nil
|
|
}
|
|
res := ""
|
|
sortedRes := make([]string, 0, 10)
|
|
for _, r := range data.ActiveRoles {
|
|
sortedRes = append(sortedRes, r.String())
|
|
}
|
|
sort.Strings(sortedRes)
|
|
for i, r := range sortedRes {
|
|
res += r
|
|
if i != len(data.ActiveRoles)-1 {
|
|
res += ","
|
|
}
|
|
}
|
|
return res, false, nil
|
|
}
|
|
|
|
type userFunctionClass struct {
|
|
baseFunctionClass
|
|
}
|
|
|
|
func (c *userFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {
|
|
if err := c.verifyArgs(args); err != nil {
|
|
return nil, err
|
|
}
|
|
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETString)
|
|
bf.tp.Flen = 64
|
|
sig := &builtinUserSig{bf}
|
|
return sig, nil
|
|
}
|
|
|
|
type builtinUserSig struct {
|
|
baseBuiltinFunc
|
|
}
|
|
|
|
func (b *builtinUserSig) Clone() builtinFunc {
|
|
newSig := &builtinUserSig{}
|
|
newSig.cloneFrom(&b.baseBuiltinFunc)
|
|
return newSig
|
|
}
|
|
|
|
// evalString evals a builtinUserSig.
|
|
// See https://dev.mysql.com/doc/refman/5.7/en/information-functions.html#function_user
|
|
func (b *builtinUserSig) evalString(row chunk.Row) (string, bool, error) {
|
|
data := b.ctx.GetSessionVars()
|
|
if data == nil || data.User == nil {
|
|
return "", true, errors.Errorf("Missing session variable when eval builtin")
|
|
}
|
|
|
|
return data.User.String(), false, nil
|
|
}
|
|
|
|
type connectionIDFunctionClass struct {
|
|
baseFunctionClass
|
|
}
|
|
|
|
func (c *connectionIDFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {
|
|
if err := c.verifyArgs(args); err != nil {
|
|
return nil, err
|
|
}
|
|
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETInt)
|
|
bf.tp.Flag |= mysql.UnsignedFlag
|
|
sig := &builtinConnectionIDSig{bf}
|
|
return sig, nil
|
|
}
|
|
|
|
type builtinConnectionIDSig struct {
|
|
baseBuiltinFunc
|
|
}
|
|
|
|
func (b *builtinConnectionIDSig) Clone() builtinFunc {
|
|
newSig := &builtinConnectionIDSig{}
|
|
newSig.cloneFrom(&b.baseBuiltinFunc)
|
|
return newSig
|
|
}
|
|
|
|
func (b *builtinConnectionIDSig) evalInt(_ chunk.Row) (int64, bool, error) {
|
|
data := b.ctx.GetSessionVars()
|
|
if data == nil {
|
|
return 0, true, errors.Errorf("Missing session variable when evalue builtin")
|
|
}
|
|
return int64(data.ConnectionID), false, nil
|
|
}
|
|
|
|
type lastInsertIDFunctionClass struct {
|
|
baseFunctionClass
|
|
}
|
|
|
|
func (c *lastInsertIDFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (sig builtinFunc, err error) {
|
|
if err = c.verifyArgs(args); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var argsTp []types.EvalType
|
|
if len(args) == 1 {
|
|
argsTp = append(argsTp, types.ETInt)
|
|
}
|
|
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETInt, argsTp...)
|
|
bf.tp.Flag |= mysql.UnsignedFlag
|
|
|
|
if len(args) == 1 {
|
|
sig = &builtinLastInsertIDWithIDSig{bf}
|
|
} else {
|
|
sig = &builtinLastInsertIDSig{bf}
|
|
}
|
|
return sig, err
|
|
}
|
|
|
|
type builtinLastInsertIDSig struct {
|
|
baseBuiltinFunc
|
|
}
|
|
|
|
func (b *builtinLastInsertIDSig) Clone() builtinFunc {
|
|
newSig := &builtinLastInsertIDSig{}
|
|
newSig.cloneFrom(&b.baseBuiltinFunc)
|
|
return newSig
|
|
}
|
|
|
|
// evalInt evals LAST_INSERT_ID().
|
|
// See https://dev.mysql.com/doc/refman/5.7/en/information-functions.html#function_last-insert-id.
|
|
func (b *builtinLastInsertIDSig) evalInt(row chunk.Row) (res int64, isNull bool, err error) {
|
|
res = int64(b.ctx.GetSessionVars().StmtCtx.PrevLastInsertID)
|
|
return res, false, nil
|
|
}
|
|
|
|
type builtinLastInsertIDWithIDSig struct {
|
|
baseBuiltinFunc
|
|
}
|
|
|
|
func (b *builtinLastInsertIDWithIDSig) Clone() builtinFunc {
|
|
newSig := &builtinLastInsertIDWithIDSig{}
|
|
newSig.cloneFrom(&b.baseBuiltinFunc)
|
|
return newSig
|
|
}
|
|
|
|
// evalInt evals LAST_INSERT_ID(expr).
|
|
// See https://dev.mysql.com/doc/refman/5.7/en/information-functions.html#function_last-insert-id.
|
|
func (b *builtinLastInsertIDWithIDSig) evalInt(row chunk.Row) (res int64, isNull bool, err error) {
|
|
res, isNull, err = b.args[0].EvalInt(b.ctx, row)
|
|
if isNull || err != nil {
|
|
return res, isNull, err
|
|
}
|
|
|
|
b.ctx.GetSessionVars().SetLastInsertID(uint64(res))
|
|
return res, false, nil
|
|
}
|
|
|
|
type versionFunctionClass struct {
|
|
baseFunctionClass
|
|
}
|
|
|
|
func (c *versionFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {
|
|
if err := c.verifyArgs(args); err != nil {
|
|
return nil, err
|
|
}
|
|
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETString)
|
|
bf.tp.Flen = 64
|
|
sig := &builtinVersionSig{bf}
|
|
return sig, nil
|
|
}
|
|
|
|
type builtinVersionSig struct {
|
|
baseBuiltinFunc
|
|
}
|
|
|
|
func (b *builtinVersionSig) Clone() builtinFunc {
|
|
newSig := &builtinVersionSig{}
|
|
newSig.cloneFrom(&b.baseBuiltinFunc)
|
|
return newSig
|
|
}
|
|
|
|
// evalString evals a builtinVersionSig.
|
|
// See https://dev.mysql.com/doc/refman/5.7/en/information-functions.html#function_version
|
|
func (b *builtinVersionSig) evalString(row chunk.Row) (string, bool, error) {
|
|
return mysql.ServerVersion, false, nil
|
|
}
|
|
|
|
type tidbVersionFunctionClass struct {
|
|
baseFunctionClass
|
|
}
|
|
|
|
func (c *tidbVersionFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {
|
|
if err := c.verifyArgs(args); err != nil {
|
|
return nil, err
|
|
}
|
|
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETString)
|
|
bf.tp.Flen = len(printer.GetTiDBInfo())
|
|
sig := &builtinTiDBVersionSig{bf}
|
|
return sig, nil
|
|
}
|
|
|
|
type builtinTiDBVersionSig struct {
|
|
baseBuiltinFunc
|
|
}
|
|
|
|
func (b *builtinTiDBVersionSig) Clone() builtinFunc {
|
|
newSig := &builtinTiDBVersionSig{}
|
|
newSig.cloneFrom(&b.baseBuiltinFunc)
|
|
return newSig
|
|
}
|
|
|
|
// evalString evals a builtinTiDBVersionSig.
|
|
// This will show git hash and build time for tidb-server.
|
|
func (b *builtinTiDBVersionSig) evalString(_ chunk.Row) (string, bool, error) {
|
|
return printer.GetTiDBInfo(), false, nil
|
|
}
|
|
|
|
type tidbIsDDLOwnerFunctionClass struct {
|
|
baseFunctionClass
|
|
}
|
|
|
|
func (c *tidbIsDDLOwnerFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {
|
|
if err := c.verifyArgs(args); err != nil {
|
|
return nil, err
|
|
}
|
|
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETInt)
|
|
sig := &builtinTiDBIsDDLOwnerSig{bf}
|
|
return sig, nil
|
|
}
|
|
|
|
type builtinTiDBIsDDLOwnerSig struct {
|
|
baseBuiltinFunc
|
|
}
|
|
|
|
func (b *builtinTiDBIsDDLOwnerSig) Clone() builtinFunc {
|
|
newSig := &builtinTiDBIsDDLOwnerSig{}
|
|
newSig.cloneFrom(&b.baseBuiltinFunc)
|
|
return newSig
|
|
}
|
|
|
|
// evalInt evals a builtinTiDBIsDDLOwnerSig.
|
|
func (b *builtinTiDBIsDDLOwnerSig) evalInt(_ chunk.Row) (res int64, isNull bool, err error) {
|
|
ddlOwnerChecker := b.ctx.DDLOwnerChecker()
|
|
if ddlOwnerChecker.IsOwner() {
|
|
res = 1
|
|
}
|
|
|
|
return res, false, nil
|
|
}
|
|
|
|
type benchmarkFunctionClass struct {
|
|
baseFunctionClass
|
|
}
|
|
|
|
func (c *benchmarkFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {
|
|
if err := c.verifyArgs(args); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Syntax: BENCHMARK(loop_count, expression)
|
|
// Define with same eval type of input arg to avoid unnecessary cast function.
|
|
sameEvalType := args[1].GetType().EvalType()
|
|
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETInt, types.ETInt, sameEvalType)
|
|
sig := &builtinBenchmarkSig{bf}
|
|
return sig, nil
|
|
}
|
|
|
|
type builtinBenchmarkSig struct {
|
|
baseBuiltinFunc
|
|
}
|
|
|
|
func (b *builtinBenchmarkSig) Clone() builtinFunc {
|
|
newSig := &builtinBenchmarkSig{}
|
|
newSig.cloneFrom(&b.baseBuiltinFunc)
|
|
return newSig
|
|
}
|
|
|
|
// evalInt evals a builtinBenchmarkSig. It will execute expression repeatedly count times.
|
|
// See https://dev.mysql.com/doc/refman/5.7/en/information-functions.html#function_benchmark
|
|
func (b *builtinBenchmarkSig) evalInt(row chunk.Row) (int64, bool, error) {
|
|
// Get loop count.
|
|
loopCount, isNull, err := b.args[0].EvalInt(b.ctx, row)
|
|
if isNull || err != nil {
|
|
return 0, isNull, err
|
|
}
|
|
|
|
// BENCHMARK() will return NULL if loop count < 0,
|
|
// behavior observed on MySQL 5.7.24.
|
|
if loopCount < 0 {
|
|
return 0, true, nil
|
|
}
|
|
|
|
// Eval loop count times based on arg type.
|
|
// BENCHMARK() will pass-through the eval error,
|
|
// behavior observed on MySQL 5.7.24.
|
|
var i int64
|
|
arg, ctx := b.args[1], b.ctx
|
|
switch evalType := arg.GetType().EvalType(); evalType {
|
|
case types.ETInt:
|
|
for ; i < loopCount; i++ {
|
|
_, isNull, err = arg.EvalInt(ctx, row)
|
|
if err != nil {
|
|
return 0, isNull, err
|
|
}
|
|
}
|
|
case types.ETReal:
|
|
for ; i < loopCount; i++ {
|
|
_, isNull, err = arg.EvalReal(ctx, row)
|
|
if err != nil {
|
|
return 0, isNull, err
|
|
}
|
|
}
|
|
case types.ETDecimal:
|
|
for ; i < loopCount; i++ {
|
|
_, isNull, err = arg.EvalDecimal(ctx, row)
|
|
if err != nil {
|
|
return 0, isNull, err
|
|
}
|
|
}
|
|
case types.ETString:
|
|
for ; i < loopCount; i++ {
|
|
_, isNull, err = arg.EvalString(ctx, row)
|
|
if err != nil {
|
|
return 0, isNull, err
|
|
}
|
|
}
|
|
case types.ETDatetime, types.ETTimestamp:
|
|
for ; i < loopCount; i++ {
|
|
_, isNull, err = arg.EvalTime(ctx, row)
|
|
if err != nil {
|
|
return 0, isNull, err
|
|
}
|
|
}
|
|
case types.ETDuration:
|
|
for ; i < loopCount; i++ {
|
|
_, isNull, err = arg.EvalDuration(ctx, row)
|
|
if err != nil {
|
|
return 0, isNull, err
|
|
}
|
|
}
|
|
case types.ETJson:
|
|
for ; i < loopCount; i++ {
|
|
_, isNull, err = arg.EvalJSON(ctx, row)
|
|
if err != nil {
|
|
return 0, isNull, err
|
|
}
|
|
}
|
|
default: // Should never go into here.
|
|
return 0, true, errors.Errorf("EvalType %v not implemented for builtin BENCHMARK()", evalType)
|
|
}
|
|
|
|
// Return value of BENCHMARK() is always 0.
|
|
return 0, false, nil
|
|
}
|
|
|
|
type charsetFunctionClass struct {
|
|
baseFunctionClass
|
|
}
|
|
|
|
func (c *charsetFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {
|
|
return nil, errFunctionNotExists.GenWithStackByArgs("FUNCTION", "CHARSET")
|
|
}
|
|
|
|
type coercibilityFunctionClass struct {
|
|
baseFunctionClass
|
|
}
|
|
|
|
func (c *coercibilityFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {
|
|
return nil, errFunctionNotExists.GenWithStackByArgs("FUNCTION", "COERCIBILITY")
|
|
}
|
|
|
|
type collationFunctionClass struct {
|
|
baseFunctionClass
|
|
}
|
|
|
|
func (c *collationFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {
|
|
return nil, errFunctionNotExists.GenWithStackByArgs("FUNCTION", "COLLATION")
|
|
}
|
|
|
|
type rowCountFunctionClass struct {
|
|
baseFunctionClass
|
|
}
|
|
|
|
func (c *rowCountFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (sig builtinFunc, err error) {
|
|
if err = c.verifyArgs(args); err != nil {
|
|
return nil, err
|
|
}
|
|
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETInt)
|
|
sig = &builtinRowCountSig{bf}
|
|
return sig, nil
|
|
}
|
|
|
|
type builtinRowCountSig struct {
|
|
baseBuiltinFunc
|
|
}
|
|
|
|
func (b *builtinRowCountSig) Clone() builtinFunc {
|
|
newSig := &builtinRowCountSig{}
|
|
newSig.cloneFrom(&b.baseBuiltinFunc)
|
|
return newSig
|
|
}
|
|
|
|
// evalInt evals ROW_COUNT().
|
|
// See https://dev.mysql.com/doc/refman/5.7/en/information-functions.html#function_row-count.
|
|
func (b *builtinRowCountSig) evalInt(_ chunk.Row) (res int64, isNull bool, err error) {
|
|
res = int64(b.ctx.GetSessionVars().StmtCtx.PrevAffectedRows)
|
|
return res, false, nil
|
|
}
|