Allow NUMERIC value scan into any number type
This commit is contained in:
parent
cecdab1c67
commit
17e5e34111
3 changed files with 103 additions and 3 deletions
16
qrm/utill.go
16
qrm/utill.go
|
|
@ -183,6 +183,10 @@ func isIntegerType(value reflect.Type) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isNumber(valueType reflect.Type) bool {
|
||||||
|
return isIntegerType(valueType) || valueType == float64Type || valueType == float32Type
|
||||||
|
}
|
||||||
|
|
||||||
func tryAssign(source, destination reflect.Value) bool {
|
func tryAssign(source, destination reflect.Value) bool {
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
|
|
@ -196,13 +200,18 @@ func tryAssign(source, destination reflect.Value) bool {
|
||||||
} else if intValue == 0 {
|
} else if intValue == 0 {
|
||||||
source = reflect.ValueOf(false)
|
source = reflect.ValueOf(false)
|
||||||
}
|
}
|
||||||
case source.Type() == stringType && destination.Type() == float64Type:
|
case source.Type() == stringType && isNumber(destination.Type()):
|
||||||
strValue := source.String()
|
// if source is string and destination is a number(int8, int32, float32, ...), we first parse string to float64 number
|
||||||
f, err := strconv.ParseFloat(strValue, 64)
|
// and then parsed number is converted into destination type
|
||||||
|
f, err := strconv.ParseFloat(source.String(), 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
source = reflect.ValueOf(f)
|
source = reflect.ValueOf(f)
|
||||||
|
|
||||||
|
if source.Type().ConvertibleTo(destination.Type()) {
|
||||||
|
source = source.Convert(destination.Type())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if source.Type().AssignableTo(destination.Type()) {
|
if source.Type().AssignableTo(destination.Type()) {
|
||||||
|
|
@ -289,6 +298,7 @@ var int32Type = reflect.TypeOf(int32(1))
|
||||||
var uint32Type = reflect.TypeOf(uint32(1))
|
var uint32Type = reflect.TypeOf(uint32(1))
|
||||||
var int64Type = reflect.TypeOf(int64(1))
|
var int64Type = reflect.TypeOf(int64(1))
|
||||||
var uint64Type = reflect.TypeOf(uint64(1))
|
var uint64Type = reflect.TypeOf(uint64(1))
|
||||||
|
var float32Type = reflect.TypeOf(float32(1))
|
||||||
var float64Type = reflect.TypeOf(float64(1))
|
var float64Type = reflect.TypeOf(float64(1))
|
||||||
var stringType = reflect.TypeOf("")
|
var stringType = reflect.TypeOf("")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -927,3 +927,48 @@ func TestRowsScan(t *testing.T) {
|
||||||
|
|
||||||
requireLogged(t, stmt)
|
requireLogged(t, stmt)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestScanNumericToNumber(t *testing.T) {
|
||||||
|
type Number struct {
|
||||||
|
Int8 int8
|
||||||
|
UInt8 uint8
|
||||||
|
Int16 int16
|
||||||
|
UInt16 uint16
|
||||||
|
Int32 int32
|
||||||
|
UInt32 uint32
|
||||||
|
Int64 int64
|
||||||
|
UInt64 uint64
|
||||||
|
Float32 float32
|
||||||
|
Float64 float64
|
||||||
|
}
|
||||||
|
|
||||||
|
numeric := CAST(Decimal("1234567890.111")).AS_DECIMAL()
|
||||||
|
|
||||||
|
stmt := SELECT(
|
||||||
|
numeric.AS("number.int8"),
|
||||||
|
numeric.AS("number.uint8"),
|
||||||
|
numeric.AS("number.int16"),
|
||||||
|
numeric.AS("number.uint16"),
|
||||||
|
numeric.AS("number.int32"),
|
||||||
|
numeric.AS("number.uint32"),
|
||||||
|
numeric.AS("number.int64"),
|
||||||
|
numeric.AS("number.uint64"),
|
||||||
|
numeric.AS("number.float32"),
|
||||||
|
numeric.AS("number.float64"),
|
||||||
|
)
|
||||||
|
|
||||||
|
var number Number
|
||||||
|
err := stmt.Query(db, &number)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.Equal(t, number.Int8, int8(-46)) // overflow
|
||||||
|
require.Equal(t, number.UInt8, uint8(210)) // overflow
|
||||||
|
require.Equal(t, number.Int16, int16(722)) // overflow
|
||||||
|
require.Equal(t, number.UInt16, uint16(722)) // overflow
|
||||||
|
require.Equal(t, number.Int32, int32(1234567890))
|
||||||
|
require.Equal(t, number.UInt32, uint32(1234567890))
|
||||||
|
require.Equal(t, number.Int64, int64(1234567890))
|
||||||
|
require.Equal(t, number.UInt64, uint64(1234567890))
|
||||||
|
require.Equal(t, number.Float32, float32(1.234568e+09))
|
||||||
|
require.Equal(t, number.Float64, float64(1.23456789e+09))
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -764,6 +764,51 @@ func TestRowsScan(t *testing.T) {
|
||||||
requireLogged(t, stmt)
|
requireLogged(t, stmt)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestScanNumericToNumber(t *testing.T) {
|
||||||
|
type Number struct {
|
||||||
|
Int8 int8
|
||||||
|
UInt8 uint8
|
||||||
|
Int16 int16
|
||||||
|
UInt16 uint16
|
||||||
|
Int32 int32
|
||||||
|
UInt32 uint32
|
||||||
|
Int64 int64
|
||||||
|
UInt64 uint64
|
||||||
|
Float32 float32
|
||||||
|
Float64 float64
|
||||||
|
}
|
||||||
|
|
||||||
|
numeric := CAST(Decimal("1234567890.111")).AS_NUMERIC()
|
||||||
|
|
||||||
|
stmt := SELECT(
|
||||||
|
numeric.AS("number.int8"),
|
||||||
|
numeric.AS("number.uint8"),
|
||||||
|
numeric.AS("number.int16"),
|
||||||
|
numeric.AS("number.uint16"),
|
||||||
|
numeric.AS("number.int32"),
|
||||||
|
numeric.AS("number.uint32"),
|
||||||
|
numeric.AS("number.int64"),
|
||||||
|
numeric.AS("number.uint64"),
|
||||||
|
numeric.AS("number.float32"),
|
||||||
|
numeric.AS("number.float64"),
|
||||||
|
)
|
||||||
|
|
||||||
|
var number Number
|
||||||
|
err := stmt.Query(db, &number)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.Equal(t, number.Int8, int8(-46)) // overflow
|
||||||
|
require.Equal(t, number.UInt8, uint8(210)) // overflow
|
||||||
|
require.Equal(t, number.Int16, int16(722)) // overflow
|
||||||
|
require.Equal(t, number.UInt16, uint16(722)) // overflow
|
||||||
|
require.Equal(t, number.Int32, int32(1234567890))
|
||||||
|
require.Equal(t, number.UInt32, uint32(1234567890))
|
||||||
|
require.Equal(t, number.Int64, int64(1234567890))
|
||||||
|
require.Equal(t, number.UInt64, uint64(1234567890))
|
||||||
|
require.Equal(t, number.Float32, float32(1.234568e+09))
|
||||||
|
require.Equal(t, number.Float64, float64(1.234567890111e+09))
|
||||||
|
}
|
||||||
|
|
||||||
var address256 = model.Address{
|
var address256 = model.Address{
|
||||||
AddressID: 256,
|
AddressID: 256,
|
||||||
Address: "1497 Yuzhou Drive",
|
Address: "1497 Yuzhou Drive",
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue