Skip to content

Commit e8153fb

Browse files
yareidmethane
authored andcommitted
Update ConvertValue() to match the database/sql/driver implementation except for uint64 (go-sql-driver#760)
This simply copies recent changes to ConvertValue from database/sql/driver to ensure that our behaviour only differs for uint64. Fixes go-sql-driver#739
1 parent 02eb68a commit e8153fb

File tree

3 files changed

+46
-4
lines changed

3 files changed

+46
-4
lines changed

AUTHORS

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
Aaron Hopkins <go-sql-driver at die.net>
1515
Achille Roussel <achille.roussel at gmail.com>
1616
Alexey Palazhchenko <alexey.palazhchenko at gmail.com>
17+
Andrew Reid <andrew.reid at tixtrack.com>
1718
Arne Hormann <arnehormann at gmail.com>
1819
Asta Xie <xiemengjun at gmail.com>
1920
Bulat Gaifullin <gaifullinbf at gmail.com>

driver_go18_test.go

+8
Original file line numberDiff line numberDiff line change
@@ -796,3 +796,11 @@ func TestRowsColumnTypes(t *testing.T) {
796796
})
797797
}
798798
}
799+
800+
func TestValuerWithValueReceiverGivenNilValue(t *testing.T) {
801+
runTests(t, dsn, func(dbt *DBTest) {
802+
dbt.mustExec("CREATE TABLE test (value VARCHAR(255))")
803+
dbt.db.Exec("INSERT INTO test VALUES (?)", (*testValuer)(nil))
804+
// This test will panic on the INSERT if ConvertValue() does not check for typed nil before calling Value()
805+
})
806+
}

statement.go

+37-4
Original file line numberDiff line numberDiff line change
@@ -132,15 +132,25 @@ func (stmt *mysqlStmt) query(args []driver.Value) (*binaryRows, error) {
132132

133133
type converter struct{}
134134

135+
// ConvertValue mirrors the reference/default converter in database/sql/driver
136+
// with _one_ exception. We support uint64 with their high bit and the default
137+
// implementation does not. This function should be kept in sync with
138+
// database/sql/driver defaultConverter.ConvertValue() except for that
139+
// deliberate difference.
135140
func (c converter) ConvertValue(v interface{}) (driver.Value, error) {
136141
if driver.IsValue(v) {
137142
return v, nil
138143
}
139144

140-
if v != nil {
141-
if valuer, ok := v.(driver.Valuer); ok {
142-
return valuer.Value()
145+
if vr, ok := v.(driver.Valuer); ok {
146+
sv, err := callValuerValue(vr)
147+
if err != nil {
148+
return nil, err
149+
}
150+
if !driver.IsValue(sv) {
151+
return nil, fmt.Errorf("non-Value type %T returned from Value", sv)
143152
}
153+
return sv, nil
144154
}
145155

146156
rv := reflect.ValueOf(v)
@@ -149,8 +159,9 @@ func (c converter) ConvertValue(v interface{}) (driver.Value, error) {
149159
// indirect pointers
150160
if rv.IsNil() {
151161
return nil, nil
162+
} else {
163+
return c.ConvertValue(rv.Elem().Interface())
152164
}
153-
return c.ConvertValue(rv.Elem().Interface())
154165
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
155166
return rv.Int(), nil
156167
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32:
@@ -176,3 +187,25 @@ func (c converter) ConvertValue(v interface{}) (driver.Value, error) {
176187
}
177188
return nil, fmt.Errorf("unsupported type %T, a %s", v, rv.Kind())
178189
}
190+
191+
var valuerReflectType = reflect.TypeOf((*driver.Valuer)(nil)).Elem()
192+
193+
// callValuerValue returns vr.Value(), with one exception:
194+
// If vr.Value is an auto-generated method on a pointer type and the
195+
// pointer is nil, it would panic at runtime in the panicwrap
196+
// method. Treat it like nil instead.
197+
//
198+
// This is so people can implement driver.Value on value types and
199+
// still use nil pointers to those types to mean nil/NULL, just like
200+
// string/*string.
201+
//
202+
// This is an exact copy of the same-named unexported function from the
203+
// database/sql package.
204+
func callValuerValue(vr driver.Valuer) (v driver.Value, err error) {
205+
if rv := reflect.ValueOf(vr); rv.Kind() == reflect.Ptr &&
206+
rv.IsNil() &&
207+
rv.Type().Elem().Implements(valuerReflectType) {
208+
return nil, nil
209+
}
210+
return vr.Value()
211+
}

0 commit comments

Comments
 (0)