From b9d6c987466805fa2162480183ba2da7c9463f16 Mon Sep 17 00:00:00 2001 From: felixYing Date: Thu, 2 Feb 2023 17:03:46 +0800 Subject: [PATCH] expression: add builtinValuesBitSig (#40653) --- expression/builtin_other.go | 43 +++++++++++++++++++++++++++++++++- expression/integration_test.go | 13 ++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/expression/builtin_other.go b/expression/builtin_other.go index c5bd6738aa9df..df3a8657c759b 100644 --- a/expression/builtin_other.go +++ b/expression/builtin_other.go @@ -1163,7 +1163,11 @@ func (c *valuesFunctionClass) getFunction(ctx sessionctx.Context, args []Express } switch c.tp.EvalType() { case types.ETInt: - sig = &builtinValuesIntSig{bf, c.offset} + if c.tp.GetType() == mysql.TypeBit { + sig = &builtinValuesBitSig{bf, c.offset} + } else { + sig = &builtinValuesIntSig{bf, c.offset} + } case types.ETReal: sig = &builtinValuesRealSig{bf, c.offset} case types.ETDecimal: @@ -1221,6 +1225,43 @@ func (b *builtinValuesIntSig) evalInt(_ chunk.Row) (int64, bool, error) { return 0, true, errors.Errorf("Session current insert values len %d and column's offset %v don't match", row.Len(), b.offset) } +type builtinValuesBitSig struct { + baseBuiltinFunc + offset int +} + +func (b *builtinValuesBitSig) Clone() builtinFunc { + newSig := &builtinValuesBitSig{offset: b.offset} + newSig.cloneFrom(&b.baseBuiltinFunc) + return newSig +} + +// evalInt evals a builtinValuesBitSig. +// See https://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html#function_values +func (b *builtinValuesBitSig) evalInt(_ chunk.Row) (int64, bool, error) { + row := b.ctx.GetSessionVars().CurrInsertValues + if row.IsEmpty() { + return 0, true, nil + } + if b.offset < row.Len() { + if row.IsNull(b.offset) { + return 0, true, nil + } + // For BinaryLiteral, see issue #15310 + val := row.GetRaw(b.offset) + if len(val) > 8 { + return 0, true, errors.New("Session current insert values is too long") + } + var binary types.BinaryLiteral = val + v, err := binary.ToInt(b.ctx.GetSessionVars().StmtCtx) + if err != nil { + return 0, true, errors.Trace(err) + } + return int64(v), 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 diff --git a/expression/integration_test.go b/expression/integration_test.go index 5555de7e0aa62..d29a61197dea1 100644 --- a/expression/integration_test.go +++ b/expression/integration_test.go @@ -4303,6 +4303,19 @@ func TestValuesForBinaryLiteral(t *testing.T) { tk.MustExec("drop table testValuesBinary;") } +func TestValuesForBinaryLiteral2(t *testing.T) { + // See issue #40653 + store := testkit.CreateMockStore(t) + + tk := testkit.NewTestKit(t, store) + tk.MustExec("use test") + tk.MustExec("drop table if exists testValuesBit") + tk.MustExec("create table testValuesBit (id bigint(20) NOT NULL AUTO_INCREMENT, test_bit bit(64) DEFAULT NULL, PRIMARY KEY(id))") + tk.MustExec("insert into testValuesBit (id,test_bit) values(1,x'AAFF')") + tk.MustExec("insert into testValuesBit (id,test_bit) values(1,x'AAFF') on duplicate key update test_bit=values(test_bit)") + tk.MustQuery("select hex(test_bit) from testValuesBit").Check(testkit.Rows("AAFF")) +} + func TestIssue14159(t *testing.T) { store := testkit.CreateMockStore(t)