mirror of https://github.com/jackc/pgx.git
parent
21ef449944
commit
82cd87d502
|
@ -79,6 +79,7 @@ skip tests for connection types that are not configured.
|
||||||
|
|
||||||
To setup the normal test environment, first install these dependencies:
|
To setup the normal test environment, first install these dependencies:
|
||||||
|
|
||||||
|
go get github.com/cockroachdb/apd
|
||||||
go get github.com/hashicorp/go-version
|
go get github.com/hashicorp/go-version
|
||||||
go get github.com/jackc/fake
|
go get github.com/jackc/fake
|
||||||
go get github.com/lib/pq
|
go get github.com/lib/pq
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
package pgx
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql/driver"
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
// This file contains code copied from the Go standard library due to the
|
||||||
|
// required function not being public.
|
||||||
|
|
||||||
|
// Copyright (c) 2009 The Go Authors. All rights reserved.
|
||||||
|
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
// From database/sql/convert.go
|
||||||
|
|
||||||
|
var valuerReflectType = reflect.TypeOf((*driver.Valuer)(nil)).Elem()
|
||||||
|
|
||||||
|
// 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 mirrored in the database/sql/driver package.
|
||||||
|
func callValuerValue(vr driver.Valuer) (v driver.Value, err error) {
|
||||||
|
if rv := reflect.ValueOf(vr); rv.Kind() == reflect.Ptr &&
|
||||||
|
rv.IsNil() &&
|
||||||
|
rv.Type().Elem().Implements(valuerReflectType) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return vr.Value()
|
||||||
|
}
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/cockroachdb/apd"
|
||||||
"github.com/jackc/pgx"
|
"github.com/jackc/pgx"
|
||||||
"github.com/jackc/pgx/pgtype"
|
"github.com/jackc/pgx/pgtype"
|
||||||
satori "github.com/jackc/pgx/pgtype/ext/satori-uuid"
|
satori "github.com/jackc/pgx/pgtype/ext/satori-uuid"
|
||||||
|
@ -1001,6 +1002,27 @@ func TestConnQueryDatabaseSQLDriverValuer(t *testing.T) {
|
||||||
ensureConnValid(t, conn)
|
ensureConnValid(t, conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://github.com/jackc/pgx/issues/339
|
||||||
|
func TestConnQueryDatabaseSQLDriverValuerWithAutoGeneratedPointerReceiver(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
conn := mustConnect(t, *defaultConnConfig)
|
||||||
|
defer closeConn(t, conn)
|
||||||
|
|
||||||
|
mustExec(t, conn, "create temporary table t(n numeric)")
|
||||||
|
|
||||||
|
var d *apd.Decimal
|
||||||
|
commandTag, err := conn.Exec(`insert into t(n) values($1)`, d)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if commandTag != "INSERT 0 1" {
|
||||||
|
t.Fatalf("want %s, got %s", "INSERT 0 1", commandTag)
|
||||||
|
}
|
||||||
|
|
||||||
|
ensureConnValid(t, conn)
|
||||||
|
}
|
||||||
|
|
||||||
func TestConnQueryDatabaseSQLDriverValuerWithBinaryPgTypeThatAcceptsSameType(t *testing.T) {
|
func TestConnQueryDatabaseSQLDriverValuerWithBinaryPgTypeThatAcceptsSameType(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,7 @@ func convertSimpleArgument(ci *pgtype.ConnInfo, arg interface{}) (interface{}, e
|
||||||
|
|
||||||
switch arg := arg.(type) {
|
switch arg := arg.(type) {
|
||||||
case driver.Valuer:
|
case driver.Valuer:
|
||||||
return arg.Value()
|
return callValuerValue(arg)
|
||||||
case pgtype.TextEncoder:
|
case pgtype.TextEncoder:
|
||||||
buf, err := arg.EncodeText(ci, nil)
|
buf, err := arg.EncodeText(ci, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -150,7 +150,7 @@ func encodePreparedStatementArgument(ci *pgtype.ConnInfo, buf []byte, oid pgtype
|
||||||
if err != nil {
|
if err != nil {
|
||||||
{
|
{
|
||||||
if arg, ok := arg.(driver.Valuer); ok {
|
if arg, ok := arg.(driver.Valuer); ok {
|
||||||
v, err := arg.Value()
|
v, err := callValuerValue(arg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -175,7 +175,7 @@ func encodePreparedStatementArgument(ci *pgtype.ConnInfo, buf []byte, oid pgtype
|
||||||
}
|
}
|
||||||
|
|
||||||
if arg, ok := arg.(driver.Valuer); ok {
|
if arg, ok := arg.(driver.Valuer); ok {
|
||||||
v, err := arg.Value()
|
v, err := callValuerValue(arg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -203,7 +203,7 @@ func chooseParameterFormatCode(ci *pgtype.ConnInfo, oid pgtype.OID, arg interfac
|
||||||
if _, ok := dt.Value.(pgtype.BinaryEncoder); ok {
|
if _, ok := dt.Value.(pgtype.BinaryEncoder); ok {
|
||||||
if arg, ok := arg.(driver.Valuer); ok {
|
if arg, ok := arg.(driver.Valuer); ok {
|
||||||
if err := dt.Value.Set(arg); err != nil {
|
if err := dt.Value.Set(arg); err != nil {
|
||||||
if value, err := arg.Value(); err == nil {
|
if value, err := callValuerValue(arg); err == nil {
|
||||||
if _, ok := value.(string); ok {
|
if _, ok := value.(string); ok {
|
||||||
return TextFormatCode
|
return TextFormatCode
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue