Skip to content

database/sql/driver: DefaultParameterConverter breaks driver expectations when decimalDecompose is implemented #34315

Open
@richjddavis

Description

@richjddavis

What version of Go are you using (go version)?

$ go version
go version go1.13 darwin/amd64

Does this issue reproduce with the latest release?

Yes

What operating system and processor architecture are you using (go env)?

go env Output
$ go env
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/Users/richjddavis/Library/Caches/go-build"
GOENV="/Users/richjddavis/Library/Application Support/go/env"
GOEXE=""
GOFLAGS="-tags=noaws"
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GONOPROXY=""
GONOSUMDB=""
GOOS="darwin"
GOPATH="/Users/richjddavis/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/local/Cellar/go/1.13/libexec"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/Cellar/go/1.13/libexec/pkg/tool/darwin_amd64"
GCCGO="gccgo"
AR="ar"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/bq/603y7lh10433_w66hbr38t480000gn/T/go-build565497442=/tmp/go-build -gno-record-gcc-switches -fno-common"

What did you do?

Provided a "github.com/shopspring/decimal".Decimal as a query parameter, using the github.com/lib/pq driver.

You'll need a PostgreSQL server running somewhere so that sql.Open can do its thing and get to the problematic point. I'm running a 10.10 server locally, but it shouldn't matter, so long as it's able to be connected to.

package main

import (
	"database/sql"
	"fmt"
	"os"

	_ "github.com/lib/pq"
	"github.com/shopspring/decimal"
)

func main() {
	// Should `POSTGRES_CONNSTR` be not set, it'll check for a locally running instance on the default port of 5432
	db, err := sql.Open("postgres", os.Getenv("POSTGRES_CONNSTR"))
	if err != nil {
		panic(err)
	}

	in := decimal.New(101, -1)
	var out decimal.Decimal

	row := db.QueryRow("select $1", in)
	if err := row.Scan(&out); err != nil {
		panic(err)
	}

	fmt.Println(in, out, in.Equal(out))
}

What did you expect to see?

POSTGRES_CONNSTR='sslmode=disable' go run main.go
10.1 10.1 true

What did you see instead?

POSTGRES_CONNSTR='sslmode=disable' go run main.go
panic: pq: encode: unknown type for decimal.Decimal

goroutine 1 [running]:
main.main()
        ~/go/src/github.com/richjddavis/go-1-13-pq-decimal/main.go:23 +0x35f
exit status 2

This seems to happen because due to the intersection of a few different behaviours:

This comment in driver.defaultConverter.ConvertValue() seems to suggest that if a type implements Valuer (which "github.com/shopspring/decimal".Decimal does), then that implementation should be used over decimalDecompose. However, IsValue, which has a positive match for decimalDecompose, is checked prior to this, and early exits without any conversion. If I remove the case for decimalDecompose in driver.IsValue(), the sample program runs as expected (and as it did in Go 1.12).

I'm not really sure which layer is "at fault" here, but in response to someone else raising this in in shopspring/decimal#141 (comment), @kardianos had requested that an issue be created here and that they be mentioned.

Metadata

Metadata

Assignees

No one assigned

    Labels

    NeedsInvestigationSomeone must examine and confirm this is a valid issue and not a duplicate of an existing one.

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions