go icon indicating copy to clipboard operation
go copied to clipboard

database/sql: sql.Null[T] allows types incompatible with driver.Value, leading to runtime errors

Open nesty92 opened this issue 1 year ago • 4 comments

Go version

go1.23.1

Output of go env in your module/workspace:

Not relevant

What did you do?

See example

What did you see happen?

Additional Context:

The defaultConverter in Go's database/sql package already includes logic for converting some native types that are not directly supported as driver.Value types. For example:

  • Unsigned integers (uint, uint8, uint16, uint32) are converted to int64.
  • uint64 values are converted to int64 if they fit within the int64 range; otherwise, an error is returned.
  • Pointers are dereferenced recursively, and the underlying value is converted.
  • Floating-point numbers like float32 are converted to float64.

This conversion logic allows these types to be used with SQL drivers indirectly, even though they are not directly accepted as driver.Value.

However, when using sql.Null[T], if T is an unsupported type like uint, it results in the error non-Value type %T returned from Value because sql.Null[T].Value() does not automatically apply the same conversion logic.

What did you expect to see?

  • Documentation Update: Clarify in the sql.Null[T] documentation that T should be one of the types accepted by driver.Value.
  • Type Constraints: Introduce type constraints to sql.Null[T] to restrict T to acceptable types.
  • Type Conversion in Value(): Modify the Value() method of sql.Null[T] to use the DefaultParameterConverter in V

nesty92 avatar Oct 10 '24 14:10 nesty92

cc @bradfitz @kardianos @kevinburke

cherrymui avatar Oct 10 '24 20:10 cherrymui

this problem is also happened for me here's my example: https://go.dev/play/p/j8jGELERtNb

as you can see myType's underlying type is string (one of driver.Value accepted types) but still can not be converted

laontme avatar Oct 17 '24 14:10 laontme

Change https://go.dev/cl/620858 mentions this issue: database/sql: refactor Null[T].Value method, update doc for Null[T]

gopherbot avatar Oct 18 '24 20:10 gopherbot

CC @methane

ianlancetaylor avatar Oct 21 '24 00:10 ianlancetaylor

The documentation for driver.Value states:

Value is a value that drivers must be able to handle. It is either nil, a type handled by a database driver's NamedValueChecker interface, or an instance of one of these types: [...]

This change makes a sql.Null[uint64] outright invalid (if it overflows) with no option for the driver to chime in.

If Value is allowed to be a type handled by a specific driver then shouldn't sql.Null[T] be valid for any T the driver accepts?

This is based on the assumption that the point of sql.Null[T] is to be a general implementation, this change severely constraints its usefulness compared with existing sql.NullXXX types.

flga avatar Mar 06 '25 04:03 flga