executor: convert json numeric value to float64 in hash (#38065)
close pingcap/tidb#38049
This commit is contained in:
@ -189,8 +189,7 @@ func distinctUpdateMemDeltaGens(srcChk *chunk.Chunk, dataType *types.FieldType)
|
||||
case mysql.TypeJSON:
|
||||
jsonVal := row.GetJSON(0)
|
||||
bytes := make([]byte, 0)
|
||||
bytes = append(bytes, jsonVal.TypeCode)
|
||||
bytes = append(bytes, jsonVal.Value...)
|
||||
bytes = jsonVal.HashValue(bytes)
|
||||
val = string(bytes)
|
||||
memDelta = int64(len(val))
|
||||
default:
|
||||
|
||||
@ -402,7 +402,7 @@ func evalAndEncode(
|
||||
if err != nil || isNull {
|
||||
break
|
||||
}
|
||||
encodedBytes = appendJSON(encodedBytes, buf, val)
|
||||
encodedBytes = val.HashValue(encodedBytes)
|
||||
case types.ETString:
|
||||
var val string
|
||||
val, isNull, err = arg.EvalString(sctx, row)
|
||||
|
||||
@ -5981,6 +5981,40 @@ func TestIsFastPlan(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestCountDistinctJSON(t *testing.T) {
|
||||
store := testkit.CreateMockStore(t)
|
||||
|
||||
tk := testkit.NewTestKit(t, store)
|
||||
tk.MustExec("use test")
|
||||
|
||||
tk.MustExec("drop table if exists t")
|
||||
tk.MustExec("create table t(j JSON)")
|
||||
tk.MustExec("insert into t values('2010')")
|
||||
tk.MustExec("insert into t values('2011')")
|
||||
tk.MustExec("insert into t values('2012')")
|
||||
tk.MustExec("insert into t values('2010.000')")
|
||||
tk.MustExec("insert into t values(cast(? as JSON))", uint64(math.MaxUint64))
|
||||
tk.MustExec("insert into t values(cast(? as JSON))", float64(math.MaxUint64))
|
||||
|
||||
tk.MustQuery("select count(distinct j) from t").Check(testkit.Rows("5"))
|
||||
}
|
||||
|
||||
func TestHashJoinJSON(t *testing.T) {
|
||||
store := testkit.CreateMockStore(t)
|
||||
|
||||
tk := testkit.NewTestKit(t, store)
|
||||
tk.MustExec("use test")
|
||||
|
||||
tk.MustExec("drop table if exists t")
|
||||
tk.MustExec("create table t(id int(11), j JSON, d DOUBLE)")
|
||||
tk.MustExec("insert into t values(0, '2010', 2010)")
|
||||
tk.MustExec("insert into t values(1, '2011', 2011)")
|
||||
tk.MustExec("insert into t values(2, '2012', 2012)")
|
||||
tk.MustExec("insert into t values(3, cast(? as JSON), ?)", uint64(math.MaxUint64), float64(math.MaxUint64))
|
||||
|
||||
tk.MustQuery("select /*+inl_hash_join(t2)*/ t1.id, t2.id from t t1 join t t2 on t1.j = t2.d;").Check(testkit.Rows("0 0", "1 1", "2 2"))
|
||||
}
|
||||
|
||||
func TestBinaryStrNumericOperator(t *testing.T) {
|
||||
store := testkit.CreateMockStore(t)
|
||||
|
||||
|
||||
@ -538,6 +538,12 @@ func (bj BinaryJSON) HashValue(buf []byte) []byte {
|
||||
} else {
|
||||
buf = append(buf, bj.Value...)
|
||||
}
|
||||
case JSONTypeCodeUint64:
|
||||
if bj.GetUint64() == uint64(float64(bj.GetUint64())) {
|
||||
buf = appendBinaryFloat64(buf, float64(bj.GetUint64()))
|
||||
} else {
|
||||
buf = append(buf, bj.Value...)
|
||||
}
|
||||
case JSONTypeCodeArray:
|
||||
elemCount := int(jsonEndian.Uint32(bj.Value))
|
||||
for i := 0; i < elemCount; i++ {
|
||||
|
||||
@ -386,7 +386,8 @@ func encodeHashChunkRowIdx(sc *stmtctx.StatementContext, row chunk.Row, tp *type
|
||||
b = (*[unsafe.Sizeof(v)]byte)(unsafe.Pointer(&v))[:]
|
||||
case mysql.TypeJSON:
|
||||
flag = jsonFlag
|
||||
b = row.GetBytes(idx)
|
||||
json := row.GetJSON(idx)
|
||||
b = json.HashValue(b)
|
||||
default:
|
||||
return 0, nil, errors.Errorf("unsupport column type for encode %d", tp.GetType())
|
||||
}
|
||||
@ -645,7 +646,9 @@ func HashChunkSelected(sc *stmtctx.StatementContext, h []hash.Hash64, chk *chunk
|
||||
isNull[i] = !ignoreNull
|
||||
} else {
|
||||
buf[0] = jsonFlag
|
||||
b = column.GetBytes(i)
|
||||
json := column.GetJSON(i)
|
||||
b = b[:0]
|
||||
b = json.HashValue(b)
|
||||
}
|
||||
|
||||
// As the golang doc described, `Hash.Write` never returns an error..
|
||||
|
||||
@ -1187,6 +1187,9 @@ func TestHashChunkRow(t *testing.T) {
|
||||
|
||||
testHashChunkRowEqual(t, "x", []byte("x"), true)
|
||||
testHashChunkRowEqual(t, "x", []byte("y"), false)
|
||||
|
||||
testHashChunkRowEqual(t, types.CreateBinaryJSON(int64(1)), types.CreateBinaryJSON(float64(1.0)), true)
|
||||
testHashChunkRowEqual(t, types.CreateBinaryJSON(uint64(math.MaxUint64)), types.CreateBinaryJSON(float64(math.MaxUint64)), false)
|
||||
}
|
||||
|
||||
func TestValueSizeOfSignedInt(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user