From b214b1991a9bcd32d971012eef817caae253dd93 Mon Sep 17 00:00:00 2001 From: Alexandre Thomas Date: Fri, 18 Oct 2024 15:07:55 +0200 Subject: [PATCH] Fix failing test on call to sqlx.In with (driver.Valuer)(nil) --- bind.go | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/bind.go b/bind.go index e698039..4c5b3d4 100644 --- a/bind.go +++ b/bind.go @@ -163,7 +163,7 @@ func In(query string, args ...interface{}) (string, []interface{}, error) { for i, arg := range args { if a, ok := arg.(driver.Valuer); ok { var err error - arg, err = a.Value() + arg, err = callValuerValue(a) if err != nil { return "", nil, err } @@ -263,3 +263,24 @@ func appendReflectSlice(args []interface{}, v reflect.Value, vlen int) []interfa return args } + +// callValuerValue returns vr.Value(), with one exception: +// If vr.Value is an auto-generated method on a pointer type and the +// pointer is nil, it would panic at runtime in the panicwrap +// method. Treat it like nil instead. +// Issue 8415. +// +// This is so people can implement driver.Value on value types and +// still use nil pointers to those types to mean nil/NULL, just like +// string/*string. +// +// This function is copied from database/sql/driver package +// and mirrored in the database/sql package. +func callValuerValue(vr driver.Valuer) (v driver.Value, err error) { + if rv := reflect.ValueOf(vr); rv.Kind() == reflect.Pointer && + rv.IsNil() && + rv.Type().Elem().Implements(reflect.TypeOf((*driver.Valuer)(nil)).Elem()) { + return nil, nil + } + return vr.Value() +}