@@ -137,10 +137,15 @@ func (c converter) ConvertValue(v interface{}) (driver.Value, error) {
137
137
return v , nil
138
138
}
139
139
140
- if v != nil {
141
- if valuer , ok := v .(driver.Valuer ); ok {
142
- return valuer .Value ()
140
+ if vr , ok := v .(driver.Valuer ); ok {
141
+ sv , err := callValuerValue (vr )
142
+ if err != nil {
143
+ return nil , err
144
+ }
145
+ if ! driver .IsValue (sv ) {
146
+ return nil , fmt .Errorf ("non-Value type %T returned from Value" , sv )
143
147
}
148
+ return sv , nil
144
149
}
145
150
146
151
rv := reflect .ValueOf (v )
@@ -149,8 +154,9 @@ func (c converter) ConvertValue(v interface{}) (driver.Value, error) {
149
154
// indirect pointers
150
155
if rv .IsNil () {
151
156
return nil , nil
157
+ } else {
158
+ return c .ConvertValue (rv .Elem ().Interface ())
152
159
}
153
- return c .ConvertValue (rv .Elem ().Interface ())
154
160
case reflect .Int , reflect .Int8 , reflect .Int16 , reflect .Int32 , reflect .Int64 :
155
161
return rv .Int (), nil
156
162
case reflect .Uint , reflect .Uint8 , reflect .Uint16 , reflect .Uint32 :
@@ -176,3 +182,24 @@ func (c converter) ConvertValue(v interface{}) (driver.Value, error) {
176
182
}
177
183
return nil , fmt .Errorf ("unsupported type %T, a %s" , v , rv .Kind ())
178
184
}
185
+
186
+ var valuerReflectType = reflect .TypeOf ((* driver .Valuer )(nil )).Elem ()
187
+
188
+ // callValuerValue returns vr.Value(), with one exception:
189
+ // If vr.Value is an auto-generated method on a pointer type and the
190
+ // pointer is nil, it would panic at runtime in the panicwrap
191
+ // method. Treat it like nil instead.
192
+ //
193
+ // This is so people can implement driver.Value on value types and
194
+ // still use nil pointers to those types to mean nil/NULL, just like
195
+ // string/*string.
196
+ //
197
+ // This function is copied from the database/sql package.
198
+ func callValuerValue (vr driver.Valuer ) (v driver.Value , err error ) {
199
+ if rv := reflect .ValueOf (vr ); rv .Kind () == reflect .Ptr &&
200
+ rv .IsNil () &&
201
+ rv .Type ().Elem ().Implements (valuerReflectType ) {
202
+ return nil , nil
203
+ }
204
+ return vr .Value ()
205
+ }
0 commit comments