json: add uint64 support. (#3648)

This commit is contained in:
qupeng
2017-07-07 11:02:33 +08:00
committed by GitHub
parent cf608d88f5
commit 6bd585f27c
8 changed files with 43 additions and 19 deletions

View File

@ -1239,9 +1239,12 @@ func (d *Datum) convertToMysqlJSON(sc *variable.StatementContext, target *FieldT
if j, err = json.ParseFromString(d.GetString()); err == nil {
ret.SetMysqlJSON(j)
}
case KindInt64, KindUint64:
case KindInt64:
i64 := d.GetInt64()
ret.SetMysqlJSON(json.CreateJSON(i64))
case KindUint64:
u64 := d.GetUint64()
ret.SetMysqlJSON(json.CreateJSON(u64))
case KindFloat32, KindFloat64:
f64 := d.GetFloat64()
ret.SetMysqlJSON(json.CreateJSON(f64))
@ -1521,8 +1524,10 @@ func (d *Datum) ToMysqlJSON() (j json.JSON, err error) {
case KindMysqlJSON:
j = d.x.(json.JSON)
return
case KindInt64, KindUint64:
case KindInt64:
in = d.GetInt64()
case KindUint64:
in = d.GetUint64()
case KindFloat32, KindFloat64:
in = d.GetFloat64()
case KindMysqlDecimal:

View File

@ -39,25 +39,29 @@ func compareFloat64PrecisionLoss(x, y float64) int {
// jsonTypePrecedences is for comparing two json.
// See: https://dev.mysql.com/doc/refman/5.7/en/json.html#json-comparison
var jsonTypePrecedences = map[string]int{
"BLOB": -1,
"BIT": -2,
"OPAQUE": -3,
"DATETIME": -4,
"TIME": -5,
"DATE": -6,
"BOOLEAN": -7,
"ARRAY": -8,
"OBJECT": -9,
"STRING": -10,
"INTEGER": -11,
"DOUBLE": -11,
"NULL": -12,
"BLOB": -1,
"BIT": -2,
"OPAQUE": -3,
"DATETIME": -4,
"TIME": -5,
"DATE": -6,
"BOOLEAN": -7,
"ARRAY": -8,
"OBJECT": -9,
"STRING": -10,
"INTEGER": -11,
"UNSIGNED INTEGER": -11,
"DOUBLE": -11,
"NULL": -12,
}
func i64AsFloat64(i64 int64, typeCode TypeCode) float64 {
switch typeCode {
case typeCodeLiteral, typeCodeInt64:
return float64(i64)
case typeCodeUint64:
u64 := *(*uint64)(unsafe.Pointer(&i64))
return float64(u64)
case typeCodeFloat64:
return *(*float64)(unsafe.Pointer(&i64))
default:

View File

@ -40,6 +40,8 @@ func (j JSON) Type() string {
}
case typeCodeInt64:
return "INTEGER"
case typeCodeUint64:
return "UNSIGNED INTEGER"
case typeCodeFloat64:
return "DOUBLE"
case typeCodeString:

View File

@ -35,6 +35,9 @@ func (s *testJSONSuite) TestJSONType(c *C) {
j := mustParseFromString(tt.In)
c.Assert(j.Type(), Equals, tt.Out)
}
// we can't parse '9223372036854775808' to JSON::Uint64 now,
// because go builtin JSON parser treats that as DOUBLE.
c.Assert(CreateJSON(uint64(1<<63)).Type(), Equals, "UNSIGNED INTEGER")
}
func (s *testJSONSuite) TestJSONExtract(c *C) {

View File

@ -33,6 +33,7 @@ const (
typeCodeArray TypeCode = 0x03
typeCodeLiteral TypeCode = 0x04
typeCodeInt64 TypeCode = 0x09
typeCodeUint64 TypeCode = 0x0a
typeCodeFloat64 TypeCode = 0x0b
typeCodeString TypeCode = 0x0c
)
@ -96,6 +97,9 @@ func (j JSON) MarshalJSON() ([]byte, error) {
}
case typeCodeInt64:
return json.Marshal(j.i64)
case typeCodeUint64:
u64 := *(*uint64)(unsafe.Pointer(&j.i64))
return json.Marshal(u64)
case typeCodeFloat64:
f64 := *(*float64)(unsafe.Pointer(&j.i64))
return json.Marshal(f64)

View File

@ -48,6 +48,7 @@ func (s *testJSONSuite) TestParseFromString(c *C) {
func (s *testJSONSuite) TestSerializeAndDeserialize(c *C) {
var jsonNilValue = CreateJSON(nil)
var jsonBoolValue = CreateJSON(true)
var jsonUintValue = CreateJSON(uint64(1 << 63))
var jsonDoubleValue = CreateJSON(3.24)
var jsonStringValue = CreateJSON("hello, 世界")
j1 := mustParseFromString(`{"aaaaaaaaaaa": [1, "2", {"aa": "bb"}, 4.0], "bbbbbbbbbb": true, "ccccccccc": "d"}`)
@ -60,6 +61,7 @@ func (s *testJSONSuite) TestSerializeAndDeserialize(c *C) {
}{
{In: jsonNilValue, Out: jsonNilValue, size: 2},
{In: jsonBoolValue, Out: jsonBoolValue, size: 2},
{In: jsonUintValue, Out: jsonUintValue, size: 9},
{In: jsonDoubleValue, Out: jsonDoubleValue, size: 9},
{In: jsonStringValue, Out: jsonStringValue, size: 15},
{In: j1, Out: j1, size: 144},
@ -86,7 +88,7 @@ func (s *testJSONSuite) TestCompareJSON(c *C) {
jNull := mustParseFromString(`null`)
jBoolTrue := mustParseFromString(`true`)
jBoolFalse := mustParseFromString(`false`)
jIntegerLarge := mustParseFromString(`5`)
jIntegerLarge := CreateJSON(uint64(1 << 63))
jIntegerSmall := mustParseFromString(`3`)
jStringLarge := mustParseFromString(`"hello, world"`)
jStringSmall := mustParseFromString(`"hello"`)

View File

@ -37,6 +37,9 @@ func normalize(in interface{}) (j JSON, err error) {
case int64:
j.typeCode = typeCodeInt64
j.i64 = t
case uint64:
j.typeCode = typeCodeUint64
j.i64 = *(*int64)(unsafe.Pointer(&t))
case float64:
j.typeCode = typeCodeFloat64
*(*float64)(unsafe.Pointer(&j.i64)) = t

View File

@ -127,7 +127,7 @@ func PeekBytesAsJSON(b []byte) (n int, err error) {
n = int(size) + int(reader.Size()) - int(reader.Len()) + typeCodeLen
return
}
case typeCodeInt64, typeCodeFloat64, typeCodeLiteral:
case typeCodeInt64, typeCodeUint64, typeCodeFloat64, typeCodeLiteral:
n = jsonTypeCodeLength[TypeCode(c)] + typeCodeLen
return
}
@ -151,7 +151,7 @@ func encode(j JSON, buffer *bytes.Buffer) {
encodeJSONArray(j.array, buffer)
case typeCodeLiteral:
encodeJSONLiteral(byte(j.i64), buffer)
case typeCodeInt64:
case typeCodeInt64, typeCodeUint64:
encodeJSONInt64(j.i64, buffer)
case typeCodeFloat64:
f64 := *(*float64)(unsafe.Pointer(&j.i64))
@ -179,7 +179,7 @@ func decode(typeCode byte, data []byte) (j JSON, err error) {
case typeCodeLiteral:
pbyte := (*byte)(unsafe.Pointer(&j.i64))
err = decodeJSONLiteral(pbyte, data)
case typeCodeInt64:
case typeCodeInt64, typeCodeUint64:
err = decodeJSONInt64(&j.i64, data)
case typeCodeFloat64:
pfloat := (*float64)(unsafe.Pointer(&j.i64))
@ -388,6 +388,7 @@ var jsonTypeCodeLength = map[TypeCode]int{
typeCodeArray: -1,
typeCodeLiteral: 1,
typeCodeInt64: 8,
typeCodeUint64: 8,
typeCodeFloat64: 8,
typeCodeString: -1,
}