From 683ffe09f66f0834baf039deeabe16eec6b09daa Mon Sep 17 00:00:00 2001 From: Daniel Theophanes Date: Fri, 26 Apr 2019 12:49:23 -0700 Subject: database/sql: add support for decimal interface Add support for scanning decimal types into values. If the dest supports the decimal composer interface and the src supports the decimal decomposer, set the value of the decimal when Scanning. Add support for sending decimal decomposer interface values as parameters. For #30870 Change-Id: Ic5dbf9069df8d56405852b17542a9188d55c2947 Reviewed-on: https://go-review.googlesource.com/c/go/+/174181 Run-TryBot: Daniel Theophanes TryBot-Result: Gobot Gobot Reviewed-by: Ian Lance Taylor --- src/database/sql/driver/types.go | 16 +++++++++++++++- src/database/sql/driver/types_test.go | 14 ++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) (limited to 'src/database/sql/driver') diff --git a/src/database/sql/driver/types.go b/src/database/sql/driver/types.go index 64b41faaa8..24c3a45483 100644 --- a/src/database/sql/driver/types.go +++ b/src/database/sql/driver/types.go @@ -180,6 +180,8 @@ func IsValue(v interface{}) bool { switch v.(type) { case []byte, bool, float64, int64, string, time.Time: return true + case decimalDecompose: + return true } return false } @@ -236,7 +238,8 @@ func (defaultConverter) ConvertValue(v interface{}) (Value, error) { return v, nil } - if vr, ok := v.(Valuer); ok { + switch vr := v.(type) { + case Valuer: sv, err := callValuerValue(vr) if err != nil { return nil, err @@ -245,6 +248,10 @@ func (defaultConverter) ConvertValue(v interface{}) (Value, error) { return nil, fmt.Errorf("non-Value type %T returned from Value", sv) } return sv, nil + + // For now, continue to prefer the Valuer interface over the decimal decompose interface. + case decimalDecompose: + return vr, nil } rv := reflect.ValueOf(v) @@ -281,3 +288,10 @@ func (defaultConverter) ConvertValue(v interface{}) (Value, error) { } return nil, fmt.Errorf("unsupported type %T, a %s", v, rv.Kind()) } + +type decimalDecompose interface { + // Decompose returns the internal decimal state into parts. + // If the provided buf has sufficient capacity, buf may be returned as the coefficient with + // the value set and length set as appropriate. + Decompose(buf []byte) (form byte, negative bool, coefficient []byte, exponent int32) +} diff --git a/src/database/sql/driver/types_test.go b/src/database/sql/driver/types_test.go index 0379bf8892..4c2996da85 100644 --- a/src/database/sql/driver/types_test.go +++ b/src/database/sql/driver/types_test.go @@ -57,6 +57,7 @@ var valueConverterTests = []valueConverterTest{ {DefaultParameterConverter, bs{1}, []byte{1}, ""}, {DefaultParameterConverter, s("a"), "a", ""}, {DefaultParameterConverter, is{1}, nil, "unsupported type driver.is, a slice of int"}, + {DefaultParameterConverter, dec{exponent: -6}, dec{exponent: -6}, ""}, } func TestValueConverters(t *testing.T) { @@ -79,3 +80,16 @@ func TestValueConverters(t *testing.T) { } } } + +type dec struct { + form byte + neg bool + coefficient [16]byte + exponent int32 +} + +func (d dec) Decompose(buf []byte) (form byte, negative bool, coefficient []byte, exponent int32) { + coef := make([]byte, 16) + copy(coef, d.coefficient[:]) + return d.form, d.neg, coef, d.exponent +} -- cgit v1.3