// Copyright 2019 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"
	"hash/crc32"
	"math"
	"strconv"

	"github.com/cznic/mathutil"
	"github.com/pingcap/parser/mysql"
	"github.com/pingcap/tidb/types"
	"github.com/pingcap/tidb/util/chunk"
)

func (b *builtinLog1ArgSig) vecEvalReal(input *chunk.Chunk, result *chunk.Column) error {
	if err := b.args[0].VecEvalReal(b.ctx, input, result); err != nil {
		return err
	}
	f64s := result.Float64s()
	for i := 0; i < len(f64s); i++ {
		if result.IsNull(i) {
			continue
		}
		if f64s[i] <= 0 {
			b.ctx.GetSessionVars().StmtCtx.AppendWarning(ErrInvalidArgumentForLogarithm)
			result.SetNull(i, true)
		} else {
			f64s[i] = math.Log(f64s[i])
		}
	}
	return nil
}

func (b *builtinLog1ArgSig) vectorized() bool {
	return true
}

func (b *builtinLog2Sig) vecEvalReal(input *chunk.Chunk, result *chunk.Column) error {
	if err := b.args[0].VecEvalReal(b.ctx, input, result); err != nil {
		return err
	}
	f64s := result.Float64s()
	for i := 0; i < len(f64s); i++ {
		if result.IsNull(i) {
			continue
		}
		if f64s[i] <= 0 {
			b.ctx.GetSessionVars().StmtCtx.AppendWarning(ErrInvalidArgumentForLogarithm)
			result.SetNull(i, true)
		} else {
			f64s[i] = math.Log2(f64s[i])
		}
	}
	return nil
}

func (b *builtinLog2Sig) vectorized() bool {
	return true
}

func (b *builtinLog10Sig) vecEvalReal(input *chunk.Chunk, result *chunk.Column) error {
	if err := b.args[0].VecEvalReal(b.ctx, input, result); err != nil {
		return err
	}
	f64s := result.Float64s()
	for i := 0; i < len(f64s); i++ {
		if result.IsNull(i) {
			continue
		}
		if f64s[i] <= 0 {
			b.ctx.GetSessionVars().StmtCtx.AppendWarning(ErrInvalidArgumentForLogarithm)
			result.SetNull(i, true)
		} else {
			f64s[i] = math.Log10(f64s[i])
		}
	}
	return nil
}

func (b *builtinLog10Sig) vectorized() bool {
	return true
}

func (b *builtinSqrtSig) vecEvalReal(input *chunk.Chunk, result *chunk.Column) error {
	if err := b.args[0].VecEvalReal(b.ctx, input, result); err != nil {
		return err
	}
	f64s := result.Float64s()
	for i := 0; i < len(f64s); i++ {
		if result.IsNull(i) {
			continue
		}
		if f64s[i] < 0 {
			result.SetNull(i, true)
		} else {
			f64s[i] = math.Sqrt(f64s[i])
		}
	}
	return nil
}

func (b *builtinSqrtSig) vectorized() bool {
	return true
}

func (b *builtinAcosSig) vecEvalReal(input *chunk.Chunk, result *chunk.Column) error {
	if err := b.args[0].VecEvalReal(b.ctx, input, result); err != nil {
		return err
	}
	f64s := result.Float64s()
	for i := 0; i < len(f64s); i++ {
		if result.IsNull(i) {
			continue
		}
		if f64s[i] < -1 || f64s[i] > 1 {
			result.SetNull(i, true)
		} else {
			f64s[i] = math.Acos(f64s[i])
		}
	}
	return nil
}

func (b *builtinAcosSig) vectorized() bool {
	return true
}

func (b *builtinAsinSig) vecEvalReal(input *chunk.Chunk, result *chunk.Column) error {
	if err := b.args[0].VecEvalReal(b.ctx, input, result); err != nil {
		return err
	}
	f64s := result.Float64s()
	for i := 0; i < len(f64s); i++ {
		if result.IsNull(i) {
			continue
		}
		if f64s[i] < -1 || f64s[i] > 1 {
			result.SetNull(i, true)
		} else {
			f64s[i] = math.Asin(f64s[i])
		}
	}
	return nil
}

func (b *builtinAsinSig) vectorized() bool {
	return true
}

func (b *builtinAtan1ArgSig) vecEvalReal(input *chunk.Chunk, result *chunk.Column) error {
	if err := b.args[0].VecEvalReal(b.ctx, input, result); err != nil {
		return err
	}
	f64s := result.Float64s()
	for i := 0; i < len(f64s); i++ {
		if result.IsNull(i) {
			continue
		}
		f64s[i] = math.Atan(f64s[i])
	}
	return nil
}

func (b *builtinAtan1ArgSig) vectorized() bool {
	return true
}

func (b *builtinAtan2ArgsSig) vecEvalReal(input *chunk.Chunk, result *chunk.Column) error {
	n := input.NumRows()
	if err := b.args[0].VecEvalReal(b.ctx, input, result); err != nil {
		return err
	}

	buf, err := b.bufAllocator.get(types.ETReal, n)
	if err != nil {
		return err
	}
	defer b.bufAllocator.put(buf)
	if err := b.args[1].VecEvalReal(b.ctx, input, buf); err != nil {
		return err
	}

	f64s := result.Float64s()
	arg := buf.Float64s()

	result.MergeNulls(buf)

	for i := 0; i < n; i++ {
		if result.IsNull(i) {
			continue
		}
		f64s[i] = math.Atan2(f64s[i], arg[i])
	}
	return nil
}

func (b *builtinAtan2ArgsSig) vectorized() bool {
	return true
}

func (b *builtinCosSig) vecEvalReal(input *chunk.Chunk, result *chunk.Column) error {
	if err := b.args[0].VecEvalReal(b.ctx, input, result); err != nil {
		return err
	}
	f64s := result.Float64s()
	for i := 0; i < len(f64s); i++ {
		if result.IsNull(i) {
			continue
		}
		f64s[i] = math.Cos(f64s[i])
	}
	return nil
}

func (b *builtinCosSig) vectorized() bool {
	return true
}

func (b *builtinCotSig) vecEvalReal(input *chunk.Chunk, result *chunk.Column) error {
	if err := b.args[0].VecEvalReal(b.ctx, input, result); err != nil {
		return err
	}
	f64s := result.Float64s()
	for i := 0; i < len(f64s); i++ {
		if result.IsNull(i) {
			continue
		}
		tan := math.Tan(f64s[i])
		if tan != 0 {
			cot := 1 / tan
			if !math.IsInf(cot, 0) && !math.IsNaN(cot) {
				f64s[i] = cot
			}
			continue
		}
		if err := types.ErrOverflow.GenWithStackByArgs("DOUBLE", fmt.Sprintf("cot(%s)", strconv.FormatFloat(f64s[i], 'f', -1, 64))); err != nil {
			return err
		}
	}
	return nil
}

func (b *builtinCotSig) vectorized() bool {
	return true
}

func (b *builtinDegreesSig) vecEvalReal(input *chunk.Chunk, result *chunk.Column) error {
	if err := b.args[0].VecEvalReal(b.ctx, input, result); err != nil {
		return err
	}
	f64s := result.Float64s()
	for i := 0; i < len(f64s); i++ {
		if result.IsNull(i) {
			continue
		}
		f64s[i] = f64s[i] * 180 / math.Pi
	}
	return nil
}

func (b *builtinDegreesSig) vectorized() bool {
	return true
}

func (b *builtinExpSig) vecEvalReal(input *chunk.Chunk, result *chunk.Column) error {
	if err := b.args[0].VecEvalReal(b.ctx, input, result); err != nil {
		return err
	}
	f64s := result.Float64s()
	for i := 0; i < len(f64s); i++ {
		if result.IsNull(i) {
			continue
		}
		exp := math.Exp(f64s[i])
		if math.IsInf(exp, 0) || math.IsNaN(exp) {
			s := fmt.Sprintf("exp(%s)", b.args[0].String())
			if err := types.ErrOverflow.GenWithStackByArgs("DOUBLE", s); err != nil {
				return err
			}
		}
		f64s[i] = exp
	}
	return nil
}

func (b *builtinExpSig) vectorized() bool {
	return true
}

func (b *builtinRadiansSig) vecEvalReal(input *chunk.Chunk, result *chunk.Column) error {
	if err := b.args[0].VecEvalReal(b.ctx, input, result); err != nil {
		return err
	}
	f64s := result.Float64s()
	for i := 0; i < len(f64s); i++ {
		if result.IsNull(i) {
			continue
		}
		f64s[i] = f64s[i] * math.Pi / 180
	}
	return nil
}

func (b *builtinRadiansSig) vectorized() bool {
	return true
}

func (b *builtinSinSig) vecEvalReal(input *chunk.Chunk, result *chunk.Column) error {
	if err := b.args[0].VecEvalReal(b.ctx, input, result); err != nil {
		return err
	}
	f64s := result.Float64s()
	for i := 0; i < len(f64s); i++ {
		if result.IsNull(i) {
			continue
		}
		f64s[i] = math.Sin(f64s[i])
	}
	return nil
}

func (b *builtinSinSig) vectorized() bool {
	return true
}

func (b *builtinTanSig) vecEvalReal(input *chunk.Chunk, result *chunk.Column) error {
	if err := b.args[0].VecEvalReal(b.ctx, input, result); err != nil {
		return err
	}
	f64s := result.Float64s()
	for i := 0; i < len(f64s); i++ {
		if result.IsNull(i) {
			continue
		}
		f64s[i] = math.Tan(f64s[i])
	}
	return nil
}

func (b *builtinTanSig) vectorized() bool {
	return true
}

func (b *builtinAbsDecSig) vecEvalDecimal(input *chunk.Chunk, result *chunk.Column) error {
	if err := b.args[0].VecEvalDecimal(b.ctx, input, result); err != nil {
		return err
	}
	zero := new(types.MyDecimal)
	buf := new(types.MyDecimal)
	d64s := result.Decimals()
	for i := 0; i < len(d64s); i++ {
		if result.IsNull(i) {
			continue
		}
		if d64s[i].IsNegative() {
			if err := types.DecimalSub(zero, &d64s[i], buf); err != nil {
				return err
			}
			d64s[i] = *buf
		}
	}
	return nil
}

func (b *builtinAbsDecSig) vectorized() bool {
	return true
}

func (b *builtinRoundDecSig) vecEvalDecimal(input *chunk.Chunk, result *chunk.Column) error {
	if err := b.args[0].VecEvalDecimal(b.ctx, input, result); err != nil {
		return err
	}
	d64s := result.Decimals()
	buf := new(types.MyDecimal)
	for i := 0; i < len(d64s); i++ {
		if result.IsNull(i) {
			continue
		}
		if err := d64s[i].Round(buf, 0, types.ModeHalfEven); err != nil {
			return err
		}
		d64s[i] = *buf
	}
	return nil
}

func (b *builtinRoundDecSig) vectorized() bool {
	return true
}

func (b *builtinPowSig) vecEvalReal(input *chunk.Chunk, result *chunk.Column) error {
	n := input.NumRows()
	buf1, err := b.bufAllocator.get(types.ETReal, n)
	if err != nil {
		return err
	}
	defer b.bufAllocator.put(buf1)
	if err := b.args[0].VecEvalReal(b.ctx, input, buf1); err != nil {
		return err
	}

	if err := b.args[1].VecEvalReal(b.ctx, input, result); err != nil {
		return err
	}

	x := buf1.Float64s()
	y := result.Float64s()
	result.MergeNulls(buf1)
	f64s := result.Float64s()
	for i := 0; i < n; i++ {
		if result.IsNull(i) {
			continue
		}
		power := math.Pow(x[i], y[i])
		if math.IsInf(power, -1) || math.IsInf(power, 1) || math.IsNaN(power) {
			return types.ErrOverflow.GenWithStackByArgs("DOUBLE", fmt.Sprintf("pow(%s, %s)", strconv.FormatFloat(x[i], 'f', -1, 64), strconv.FormatFloat(y[i], 'f', -1, 64)))
		}
		f64s[i] = power
	}
	return nil
}

func (b *builtinPowSig) vectorized() bool {
	return true
}

func (b *builtinFloorRealSig) vecEvalReal(input *chunk.Chunk, result *chunk.Column) error {
	if err := b.args[0].VecEvalReal(b.ctx, input, result); err != nil {
		return err
	}
	f64s := result.Float64s()
	for i := 0; i < len(f64s); i++ {
		if result.IsNull(i) {
			continue
		}
		f64s[i] = math.Floor(f64s[i])
	}
	return nil
}

func (b *builtinFloorRealSig) vectorized() bool {
	return true
}

func (b *builtinLog2ArgsSig) vecEvalReal(input *chunk.Chunk, result *chunk.Column) error {
	if err := b.args[0].VecEvalReal(b.ctx, input, result); err != nil {
		return err
	}
	n := input.NumRows()
	buf1, err := b.bufAllocator.get(types.ETReal, n)
	if err != nil {
		return err
	}
	defer b.bufAllocator.put(buf1)
	if err := b.args[1].VecEvalReal(b.ctx, input, buf1); err != nil {
		return err
	}

	d := result.Float64s()
	x := buf1.Float64s()
	result.MergeNulls(buf1)
	for i := 0; i < n; i++ {
		if result.IsNull(i) {
			continue
		}
		if d[i] <= 0 || d[i] == 1 || x[i] <= 0 {
			b.ctx.GetSessionVars().StmtCtx.AppendWarning(ErrInvalidArgumentForLogarithm)
			result.SetNull(i, true)
		}
		d[i] = math.Log(x[i]) / math.Log(d[i])
	}
	return nil
}

func (b *builtinLog2ArgsSig) vectorized() bool {
	return true
}

func (b *builtinCeilRealSig) vecEvalReal(input *chunk.Chunk, result *chunk.Column) error {
	if err := b.args[0].VecEvalReal(b.ctx, input, result); err != nil {
		return err
	}
	f64s := result.Float64s()
	for i := 0; i < len(f64s); i++ {
		if result.IsNull(i) {
			continue
		}
		f64s[i] = math.Ceil(f64s[i])
	}
	return nil
}

func (b *builtinCeilRealSig) vectorized() bool {
	return true
}

func (b *builtinRoundRealSig) vecEvalReal(input *chunk.Chunk, result *chunk.Column) error {
	if err := b.args[0].VecEvalReal(b.ctx, input, result); err != nil {
		return err
	}
	f64s := result.Float64s()
	for i := 0; i < len(f64s); i++ {
		if result.IsNull(i) {
			continue
		}
		f64s[i] = types.Round(f64s[i], 0)
	}
	return nil
}

func (b *builtinRoundRealSig) vectorized() bool {
	return true
}

func (b *builtinRoundWithFracRealSig) vecEvalReal(input *chunk.Chunk, result *chunk.Column) error {
	if err := b.args[0].VecEvalReal(b.ctx, input, result); err != nil {
		return err
	}
	n := input.NumRows()
	buf1, err := b.bufAllocator.get(types.ETInt, n)
	if err != nil {
		return err
	}
	defer b.bufAllocator.put(buf1)
	if err := b.args[1].VecEvalInt(b.ctx, input, buf1); err != nil {
		return err
	}

	x := result.Float64s()
	d := buf1.Int64s()
	result.MergeNulls(buf1)
	for i := 0; i < n; i++ {
		if result.IsNull(i) {
			continue
		}
		x[i] = types.Round(x[i], int(d[i]))
	}
	return nil
}

func (b *builtinRoundWithFracRealSig) vectorized() bool {
	return true
}

func (b *builtinTruncateRealSig) vecEvalReal(input *chunk.Chunk, result *chunk.Column) error {
	if err := b.args[0].VecEvalReal(b.ctx, input, result); err != nil {
		return err
	}
	n := input.NumRows()
	buf1, err := b.bufAllocator.get(types.ETInt, n)
	if err != nil {
		return err
	}
	defer b.bufAllocator.put(buf1)
	if err := b.args[1].VecEvalInt(b.ctx, input, buf1); err != nil {
		return err
	}

	result.MergeNulls(buf1)
	x := result.Float64s()
	d := buf1.Int64s()
	for i := 0; i < n; i++ {
		if result.IsNull(i) {
			continue
		}
		x[i] = types.Truncate(x[i], int(d[i]))
	}
	return nil
}

func (b *builtinTruncateRealSig) vectorized() bool {
	return true
}

func (b *builtinAbsRealSig) vecEvalReal(input *chunk.Chunk, result *chunk.Column) error {
	if err := b.args[0].VecEvalReal(b.ctx, input, result); err != nil {
		return err
	}
	f64s := result.Float64s()
	for i := 0; i < len(f64s); i++ {
		f64s[i] = math.Abs(f64s[i])
	}
	return nil
}

func (b *builtinAbsRealSig) vectorized() bool {
	return true
}

func (b *builtinAbsIntSig) vecEvalInt(input *chunk.Chunk, result *chunk.Column) error {
	if err := b.args[0].VecEvalInt(b.ctx, input, result); err != nil {
		return err
	}
	i64s := result.Int64s()
	for i := 0; i < len(i64s); i++ {
		if result.IsNull(i) {
			continue
		}
		if i64s[i] == math.MinInt64 {
			return types.ErrOverflow.GenWithStackByArgs("BIGINT", fmt.Sprintf("abs(%d)", i64s[i]))
		}
		if i64s[i] < 0 {
			i64s[i] = -i64s[i]
		}
	}
	return nil
}

func (b *builtinAbsIntSig) vectorized() bool {
	return true
}

func (b *builtinRoundIntSig) vecEvalInt(input *chunk.Chunk, result *chunk.Column) error {
	return b.args[0].VecEvalInt(b.ctx, input, result)
}

func (b *builtinRoundIntSig) vectorized() bool {
	return true
}

func (b *builtinRoundWithFracIntSig) vecEvalInt(input *chunk.Chunk, result *chunk.Column) error {
	if err := b.args[0].VecEvalInt(b.ctx, input, result); err != nil {
		return err
	}

	n := input.NumRows()
	buf, err := b.bufAllocator.get(types.ETInt, n)
	if err != nil {
		return err
	}
	defer b.bufAllocator.put(buf)
	if err := b.args[1].VecEvalInt(b.ctx, input, buf); err != nil {
		return err
	}

	i64s := result.Int64s()
	frac := buf.Int64s()
	result.MergeNulls(buf)
	for i := 0; i < n; i++ {
		if result.IsNull(i) {
			continue
		}
		i64s[i] = int64(types.Round(float64(i64s[i]), int(frac[i])))
	}
	return nil
}

func (b *builtinRoundWithFracIntSig) vectorized() bool {
	return true
}
func (b *builtinCRC32Sig) vectorized() bool {
	return true
}

func (b *builtinCRC32Sig) vecEvalInt(input *chunk.Chunk, result *chunk.Column) error {
	n := input.NumRows()
	buf, err := b.bufAllocator.get(types.ETString, n)
	if err != nil {
		return err
	}
	defer b.bufAllocator.put(buf)
	if err := b.args[0].VecEvalString(b.ctx, input, buf); err != nil {
		return err
	}
	result.ResizeInt64(n, false)
	i64s := result.Int64s()
	result.MergeNulls(buf)
	for i := range i64s {
		if !buf.IsNull(i) {
			i64s[i] = int64(crc32.ChecksumIEEE(buf.GetBytes(i)))
		}
	}
	return nil
}

func (b *builtinPISig) vectorized() bool {
	return true
}

func (b *builtinPISig) vecEvalReal(input *chunk.Chunk, result *chunk.Column) error {
	n := input.NumRows()
	result.ResizeFloat64(n, false)
	f64s := result.Float64s()
	for i := range f64s {
		f64s[i] = math.Pi
	}
	return nil
}

func (b *builtinRandSig) vectorized() bool {
	return true
}

func (b *builtinRandSig) vecEvalReal(input *chunk.Chunk, result *chunk.Column) error {
	n := input.NumRows()
	result.ResizeFloat64(n, false)
	f64s := result.Float64s()
	b.mu.Lock()
	for i := range f64s {
		f64s[i] = b.mysqlRng.Gen()
	}
	b.mu.Unlock()
	return nil
}

func (b *builtinRandWithSeedFirstGenSig) vectorized() bool {
	return true
}

func (b *builtinRandWithSeedFirstGenSig) vecEvalReal(input *chunk.Chunk, result *chunk.Column) error {
	n := input.NumRows()
	buf, err := b.bufAllocator.get(types.ETInt, n)
	if err != nil {
		return err
	}
	defer b.bufAllocator.put(buf)
	if err = b.args[0].VecEvalInt(b.ctx, input, buf); err != nil {
		return err
	}

	result.ResizeFloat64(n, false)
	i64s := buf.Int64s()
	f64s := result.Float64s()
	for i := 0; i < n; i++ {
		// When the seed is null we need to use 0 as the seed.
		// The behavior same as MySQL.
		rng := NewWithSeed(0)
		if !buf.IsNull(i) {
			rng = NewWithSeed(i64s[i])
		}
		f64s[i] = rng.Gen()
	}
	return nil
}

func (b *builtinCeilIntToDecSig) vectorized() bool {
	return true
}

func (b *builtinCeilIntToDecSig) vecEvalDecimal(input *chunk.Chunk, result *chunk.Column) error {
	n := input.NumRows()
	buf, err := b.bufAllocator.get(types.ETInt, n)
	if err != nil {
		return err
	}
	defer b.bufAllocator.put(buf)
	if err := b.args[0].VecEvalInt(b.ctx, input, buf); err != nil {
		return err
	}

	result.ResizeDecimal(n, false)
	result.MergeNulls(buf)

	i64s := buf.Int64s()
	d := result.Decimals()
	isUnsigned := mysql.HasUnsignedFlag(b.args[0].GetType().Flag)
	for i := 0; i < n; i++ {
		if result.IsNull(i) {
			continue
		}
		if isUnsigned || i64s[i] >= 0 {
			d[i] = *types.NewDecFromUint(uint64(i64s[i]))
			continue
		}
		d[i] = *types.NewDecFromInt(i64s[i])
	}
	return nil
}

func (b *builtinTruncateIntSig) vectorized() bool {
	return true
}

func (b *builtinTruncateIntSig) vecEvalInt(input *chunk.Chunk, result *chunk.Column) error {
	if err := b.args[0].VecEvalInt(b.ctx, input, result); err != nil {
		return err
	}

	n := input.NumRows()
	buf, err := b.bufAllocator.get(types.ETInt, n)
	if err != nil {
		return err
	}
	defer b.bufAllocator.put(buf)

	if err := b.args[1].VecEvalInt(b.ctx, input, buf); err != nil {
		return err
	}
	result.MergeNulls(buf)
	i64s := result.Int64s()
	buf64s := buf.Int64s()

	if mysql.HasUnsignedFlag(b.args[1].GetType().Flag) {
		return nil
	}

	for i := 0; i < len(i64s); i++ {
		if result.IsNull(i) {
			continue
		}
		if buf64s[i] < 0 {
			// -MinInt = MinInt, special case
			if buf64s[i] == mathutil.MinInt {
				i64s[i] = 0
			} else {
				shift := int64(math.Pow10(int(-buf64s[i])))
				i64s[i] = i64s[i] / shift * shift
			}
		}
	}
	return nil
}

func (b *builtinTruncateUintSig) vectorized() bool {
	return true
}

func (b *builtinTruncateUintSig) vecEvalInt(input *chunk.Chunk, result *chunk.Column) error {
	if err := b.args[0].VecEvalInt(b.ctx, input, result); err != nil {
		return err
	}

	n := input.NumRows()
	buf, err := b.bufAllocator.get(types.ETInt, n)
	if err != nil {
		return err
	}
	defer b.bufAllocator.put(buf)

	if err := b.args[1].VecEvalInt(b.ctx, input, buf); err != nil {
		return err
	}
	result.MergeNulls(buf)
	i64s := result.Int64s()
	buf64s := buf.Int64s()

	if mysql.HasUnsignedFlag(b.args[1].GetType().Flag) {
		return nil
	}

	for i := 0; i < n; i++ {
		if result.IsNull(i) {
			continue
		}

		if buf64s[i] < 0 {
			// -MinInt = MinInt, special case
			if buf64s[i] == mathutil.MinInt {
				i64s[i] = 0
			} else {
				shift := uint64(math.Pow10(int(-buf64s[i])))
				i64s[i] = int64(uint64(i64s[i]) / shift * shift)
			}
		}
	}
	return nil
}

func (b *builtinCeilDecToDecSig) vectorized() bool {
	return true
}

func (b *builtinCeilDecToDecSig) vecEvalDecimal(input *chunk.Chunk, result *chunk.Column) error {
	n := input.NumRows()
	if err := b.args[0].VecEvalDecimal(b.ctx, input, result); err != nil {
		return err
	}
	ds := result.Decimals()

	for i := 0; i < n; i++ {
		if result.IsNull(i) {
			continue
		}
		rst := new(types.MyDecimal)
		if err := ds[i].Round(rst, 0, types.ModeTruncate); err != nil {
			return err
		}
		if !ds[i].IsNegative() && rst.Compare(&ds[i]) != 0 {
			if err := types.DecimalAdd(rst, types.NewDecFromInt(1), rst); err != nil {
				return err
			}
		}
		ds[i] = *rst
	}
	return nil
}

func (b *builtinFloorDecToDecSig) vectorized() bool {
	return true
}

func (b *builtinFloorDecToDecSig) vecEvalDecimal(input *chunk.Chunk, result *chunk.Column) error {
	n := input.NumRows()
	if err := b.args[0].VecEvalDecimal(b.ctx, input, result); err != nil {
		return err
	}
	ds := result.Decimals()

	for i := 0; i < n; i++ {
		if result.IsNull(i) {
			continue
		}
		rst := new(types.MyDecimal)
		if !ds[i].IsNegative() {
			if err := ds[i].Round(rst, 0, types.ModeTruncate); err != nil {
				return err
			}
		} else {
			if err := ds[i].Round(rst, 0, types.ModeTruncate); err != nil {
				return err
			}
			if rst.Compare(&ds[i]) != 0 {
				if err := types.DecimalSub(rst, types.NewDecFromInt(1), rst); err != nil {
					return err
				}
			}
		}
		ds[i] = *rst
	}
	return nil
}

func (b *builtinTruncateDecimalSig) vectorized() bool {
	return true
}

func (b *builtinTruncateDecimalSig) vecEvalDecimal(input *chunk.Chunk, result *chunk.Column) error {
	n := input.NumRows()
	if err := b.args[0].VecEvalDecimal(b.ctx, input, result); err != nil {
		return err
	}
	buf, err := b.bufAllocator.get(types.ETInt, n)
	if err != nil {
		return err
	}
	defer b.bufAllocator.put(buf)
	if err := b.args[1].VecEvalInt(b.ctx, input, buf); err != nil {
		return err
	}
	result.MergeNulls(buf)
	ds := result.Decimals()
	i64s := buf.Int64s()
	ft := b.getRetTp().Decimal
	for i := 0; i < n; i++ {
		if result.IsNull(i) {
			continue
		}
		result := new(types.MyDecimal)
		if err := ds[i].Round(result, mathutil.Min(int(i64s[i]), ft), types.ModeTruncate); err != nil {
			return err
		}
		ds[i] = *result
	}
	return nil
}

func (b *builtinRoundWithFracDecSig) vectorized() bool {
	return true
}

func (b *builtinRoundWithFracDecSig) vecEvalDecimal(input *chunk.Chunk, result *chunk.Column) error {
	n := input.NumRows()
	if err := b.args[0].VecEvalDecimal(b.ctx, input, result); err != nil {
		return err
	}
	buf, err := b.bufAllocator.get(types.ETInt, n)
	if err != nil {
		return err
	}
	defer b.bufAllocator.put(buf)
	if err := b.args[1].VecEvalInt(b.ctx, input, buf); err != nil {
		return err
	}

	result.MergeNulls(buf)
	tmp := new(types.MyDecimal)
	d64s := result.Decimals()
	i64s := buf.Int64s()
	for i := 0; i < n; i++ {
		if result.IsNull(i) {
			continue
		}
		// TODO: reuse d64[i] and remove the temporary variable tmp.
		if err := d64s[i].Round(tmp, mathutil.Min(int(i64s[i]), b.tp.Decimal), types.ModeHalfEven); err != nil {
			return err
		}
		d64s[i] = *tmp
	}
	return nil
}

func (b *builtinFloorIntToDecSig) vectorized() bool {
	return true
}

func (b *builtinFloorIntToDecSig) vecEvalDecimal(input *chunk.Chunk, result *chunk.Column) error {
	n := input.NumRows()
	buf, err := b.bufAllocator.get(types.ETInt, n)
	if err != nil {
		return err
	}
	defer b.bufAllocator.put(buf)
	if err := b.args[0].VecEvalInt(b.ctx, input, buf); err != nil {
		return err
	}

	result.ResizeDecimal(n, false)
	result.MergeNulls(buf)

	i64s := buf.Int64s()
	d := result.Decimals()
	isUnsigned := mysql.HasUnsignedFlag(b.args[0].GetType().Flag)
	for i := 0; i < n; i++ {
		if result.IsNull(i) {
			continue
		}
		if isUnsigned || i64s[i] >= 0 {
			d[i] = *types.NewDecFromUint(uint64(i64s[i]))
			continue
		}
		d[i] = *types.NewDecFromInt(i64s[i])
	}
	return nil
}

func (b *builtinSignSig) vectorized() bool {
	return true
}

func (b *builtinSignSig) vecEvalInt(input *chunk.Chunk, result *chunk.Column) error {
	n := input.NumRows()
	buf, err := b.bufAllocator.get(types.ETReal, n)
	if err != nil {
		return err
	}
	defer b.bufAllocator.put(buf)
	if err := b.args[0].VecEvalReal(b.ctx, input, buf); err != nil {
		return err
	}
	args := buf.Float64s()
	result.ResizeInt64(n, false)
	result.MergeNulls(buf)
	i64s := result.Int64s()
	for i := 0; i < len(i64s); i++ {
		if result.IsNull(i) {
			continue
		}
		if args[i] > 0 {
			i64s[i] = 1
		} else if args[i] < 0 {
			i64s[i] = -1
		} else {
			i64s[i] = 0
		}
	}
	return nil
}

func (b *builtinConvSig) vectorized() bool {
	return true
}

func (b *builtinConvSig) vecEvalString(input *chunk.Chunk, result *chunk.Column) error {
	n := input.NumRows()
	buf1, err := b.bufAllocator.get(types.ETString, n)
	if err != nil {
		return err
	}
	defer b.bufAllocator.put(buf1)
	buf2, err := b.bufAllocator.get(types.ETInt, n)
	if err != nil {
		return err
	}
	defer b.bufAllocator.put(buf2)
	buf3, err := b.bufAllocator.get(types.ETInt, n)
	if err != nil {
		return err
	}
	defer b.bufAllocator.put(buf3)
	if err := b.args[0].VecEvalString(b.ctx, input, buf1); err != nil {
		return err
	}
	if err := b.args[1].VecEvalInt(b.ctx, input, buf2); err != nil {
		return err
	}
	if err := b.args[2].VecEvalInt(b.ctx, input, buf3); err != nil {
		return err
	}
	result.ReserveString(n)
	fromBase := buf2.Int64s()
	toBase := buf3.Int64s()
	for i := 0; i < n; i++ {
		if buf1.IsNull(i) || buf2.IsNull(i) || buf3.IsNull(i) {
			result.AppendNull()
			continue
		}
		res, isNull, err := b.conv(buf1.GetString(i), fromBase[i], toBase[i])
		if err != nil {
			return err
		}
		if isNull {
			result.AppendNull()
			continue
		}
		result.AppendString(res)
	}
	return nil
}

func (b *builtinAbsUIntSig) vectorized() bool {
	return true
}

func (b *builtinAbsUIntSig) vecEvalInt(input *chunk.Chunk, result *chunk.Column) error {
	return b.args[0].VecEvalInt(b.ctx, input, result)
}

func (b *builtinCeilDecToIntSig) vectorized() bool {
	return true
}

func (b *builtinCeilDecToIntSig) vecEvalInt(input *chunk.Chunk, result *chunk.Column) error {
	n := input.NumRows()
	buf, err := b.bufAllocator.get(types.ETDecimal, n)
	if err != nil {
		return err
	}
	defer b.bufAllocator.put(buf)
	if err := b.args[0].VecEvalDecimal(b.ctx, input, buf); err != nil {
		return err
	}
	result.ResizeInt64(n, false)
	result.MergeNulls(buf)

	d := buf.Decimals()
	i64s := result.Int64s()
	for i := 0; i < n; i++ {
		if result.IsNull(i) {
			continue
		}
		i64s[i], err = d[i].ToInt()
		if err == types.ErrTruncated {
			err = nil
			if !d[i].IsNegative() {
				i64s[i] = i64s[i] + 1
			}
		}
		if err != nil {
			return err
		}
	}

	return nil
}

func (b *builtinCeilIntToIntSig) vectorized() bool {
	return true
}

func (b *builtinCeilIntToIntSig) vecEvalInt(input *chunk.Chunk, result *chunk.Column) error {
	return b.args[0].VecEvalInt(b.ctx, input, result)
}

func (b *builtinFloorIntToIntSig) vectorized() bool {
	return true
}

func (b *builtinFloorIntToIntSig) vecEvalInt(input *chunk.Chunk, result *chunk.Column) error {
	return b.args[0].VecEvalInt(b.ctx, input, result)
}

func (b *builtinFloorDecToIntSig) vectorized() bool {
	return true
}

func (b *builtinFloorDecToIntSig) vecEvalInt(input *chunk.Chunk, result *chunk.Column) error {
	n := input.NumRows()
	buf, err := b.bufAllocator.get(types.ETDecimal, n)
	if err != nil {
		return err
	}
	defer b.bufAllocator.put(buf)
	if err := b.args[0].VecEvalDecimal(b.ctx, input, buf); err != nil {
		return err
	}
	result.ResizeInt64(n, false)
	result.MergeNulls(buf)

	d := buf.Decimals()
	i64s := result.Int64s()
	for i := 0; i < n; i++ {
		if result.IsNull(i) {
			continue
		}
		i64s[i], err = d[i].ToInt()
		if err == types.ErrTruncated {
			err = nil
			if d[i].IsNegative() {
				i64s[i]--
			}
		}
		if err != nil {
			return err
		}
	}
	return nil
}
