You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Describe the bug
When using a struct that implements driver.Valuer but is backed by a nilable type, Value is never called when the value is nil. This is used by some types where a default should be stored within the DB. The default converter for database/sql will call this on a nil.
I'm using the stdlib compatibility layer. When tracing through the code, the database/sql code will call the CheckNamedValue method on *stdlib.Conn, which will then just pass through the values directly.
Later on, when the prepared statement is being built, anynil.NormalizeSlice is called on the arguments, which then sets the value of the arg as nil and erases any type information about the arg.
The nil value hits a nil check, preventing any Encode plan from being executed to convert the value / call Value on it.
To Reproduce
See code below. The first insert will result in a NULL value to be inserted, while the second one will insert an empty object of {}.
package main
import (
"database/sql""database/sql/driver""encoding/json""fmt""os""github.com/jackc/pgx/v5""github.com/jackc/pgx/v5/stdlib"
)
// JSONText code was copied from github.com/jmoiron/sqlx types.JSONText so there's not another import required outside of pgx and the Go stdlibtypeJSONText json.RawMessagevaremptyJSON=JSONText("{}")
func (jJSONText) Value() (driver.Value, error) {
varm json.RawMessagevarerr=j.Unmarshal(&m)
iferr!=nil {
return []byte{}, err
}
return []byte(j), nil
}
func (j*JSONText) Unmarshal(vinterface{}) error {
iflen(*j) ==0 {
*j=emptyJSON
}
returnjson.Unmarshal([]byte(*j), v)
}
funcmain() {
connConfig, err:=pgx.ParseConfig(os.Getenv("PGX_TEST_DATABASE"))
iferr!=nil {
fmt.Println("error parsing config: ", err)
return
}
dn:=stdlib.RegisterConnConfig(connConfig)
db, err:=sql.Open("pgx", dn)
iferr!=nil {
fmt.Println("error opening database: ", err)
return
}
_, err=db.Exec("CREATE TABLE IF NOT EXISTS pgx_nil_test_table (data jsonb)")
iferr!=nil {
fmt.Println("error creating table: ", err)
}
vardataJSONText_, err=db.Exec("INSERT INTO pgx_nil_test_table (data) VALUES ($1)", data)
iferr!=nil {
fmt.Println("error inserting data: ", err)
}
data=JSONText(make([]byte, 0))
_, err=db.Exec("INSERT INTO pgx_nil_test_table (data) VALUES ($1)", data)
iferr!=nil {
fmt.Println("error inserting data: ", err)
}
}
Please run your example with the race detector enabled. For example, go run -race main.go or go test -race.
Expected behavior
The Value method is called on a nil type that implements driver.Valuer to allow for any default value
Actual behavior
The Value method is not called / the value is not converted
Version
Go: $ go version -> go1.20.4 darwin/arm64
PostgreSQL: $ psql --no-psqlrc --tuples-only -c 'select version()' -> [e.g. PostgreSQL 14.4 on x86_64-apple-darwin21.5.0, compiled by Apple clang version 13.1.6 (clang-1316.0.21.2.5), 64-bit]
Describe the bug
When using a struct that implements
driver.Valuer
but is backed by a nilable type,Value
is never called when the value isnil
. This is used by some types where a default should be stored within the DB. The default converter fordatabase/sql
will call this on a nil.I'm using the stdlib compatibility layer. When tracing through the code, the
database/sql
code will call the CheckNamedValue method on*stdlib.Conn
, which will then just pass through the values directly.Later on, when the prepared statement is being built,
anynil.NormalizeSlice
is called on the arguments, which then sets the value of the arg as nil and erases any type information about the arg.The nil value hits a nil check, preventing any Encode plan from being executed to convert the value / call
Value
on it.To Reproduce
See code below. The first insert will result in a
NULL
value to be inserted, while the second one will insert an empty object of{}
.Please run your example with the race detector enabled. For example,
go run -race main.go
orgo test -race
.Expected behavior
The
Value
method is called on a nil type that implementsdriver.Valuer
to allow for any default valueActual behavior
The
Value
method is not called / the value is not convertedVersion
$ go version
-> go1.20.4 darwin/arm64$ psql --no-psqlrc --tuples-only -c 'select version()'
-> [e.g. PostgreSQL 14.4 on x86_64-apple-darwin21.5.0, compiled by Apple clang version 13.1.6 (clang-1316.0.21.2.5), 64-bit]$ grep 'github.com/jackc/pgx/v[0-9]' go.mod
-> v5.5.1Additional context
Add any other context about the problem here.
The text was updated successfully, but these errors were encountered: