2
0

Add simple protocol suuport with (Query|Exec)Ex

This commit is contained in:
Jack Christensen
2017-04-10 08:58:51 -05:00
parent 68fd815778
commit 7ff405ff84
6 changed files with 84 additions and 7 deletions
+15 -2
View File
@@ -8,10 +8,23 @@ import (
) )
func TestCidTranscode(t *testing.T) { func TestCidTranscode(t *testing.T) {
testSuccessfulTranscode(t, "cid", []interface{}{ pgTypeName := "cid"
values := []interface{}{
pgtype.Cid{Uint: 42, Status: pgtype.Present}, pgtype.Cid{Uint: 42, Status: pgtype.Present},
pgtype.Cid{Status: pgtype.Null}, pgtype.Cid{Status: pgtype.Null},
}) }
eqFunc := func(a, b interface{}) bool {
return reflect.DeepEqual(a, b)
}
testPgxSuccessfulTranscodeEqFunc(t, pgTypeName, values, eqFunc)
// No direct conversion from int to cid, convert through text
testPgxSimpleProtocolSuccessfulTranscodeEqFunc(t, "text::"+pgTypeName, values, eqFunc)
for _, driverName := range []string{"github.com/lib/pq", "github.com/jackc/pgx/stdlib"} {
testDatabaseSQLSuccessfulTranscodeEqFunc(t, driverName, pgTypeName, values, eqFunc)
}
} }
func TestCidSet(t *testing.T) { func TestCidSet(t *testing.T) {
+1 -1
View File
@@ -145,7 +145,7 @@ func (dst *Json) Scan(src interface{}) error {
func (src Json) Value() (driver.Value, error) { func (src Json) Value() (driver.Value, error) {
switch src.Status { switch src.Status {
case Present: case Present:
return src.Bytes, nil return string(src.Bytes), nil
case Null: case Null:
return nil, nil return nil, nil
default: default:
+19 -2
View File
@@ -121,13 +121,13 @@ func (src *Numeric) AssignTo(dst interface{}) error {
case Present: case Present:
switch v := dst.(type) { switch v := dst.(type) {
case *float32: case *float32:
f, err := strconv.ParseFloat(src.Int.String(), 64) f, err := src.toFloat64()
if err != nil { if err != nil {
return err return err
} }
return float64AssignTo(f, src.Status, dst) return float64AssignTo(f, src.Status, dst)
case *float64: case *float64:
f, err := strconv.ParseFloat(src.Int.String(), 64) f, err := src.toFloat64()
if err != nil { if err != nil {
return err return err
} }
@@ -283,6 +283,23 @@ func (dst *Numeric) toBigInt() (*big.Int, error) {
return num, nil return num, nil
} }
func (src *Numeric) toFloat64() (float64, error) {
f, err := strconv.ParseFloat(src.Int.String(), 64)
if err != nil {
return 0, err
}
if src.Exp > 0 {
for i := 0; i < int(src.Exp); i++ {
f *= 10
}
} else if src.Exp < 0 {
for i := 0; i > int(src.Exp); i-- {
f /= 10
}
}
return f, nil
}
func (dst *Numeric) DecodeText(ci *ConnInfo, src []byte) error { func (dst *Numeric) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil { if src == nil {
*dst = Numeric{Status: Null} *dst = Numeric{Status: Null}
+3
View File
@@ -247,9 +247,12 @@ func TestNumericAssignTo(t *testing.T) {
}{ }{
{src: &pgtype.Numeric{Int: big.NewInt(42), Status: pgtype.Present}, dst: &f32, expected: float32(42)}, {src: &pgtype.Numeric{Int: big.NewInt(42), Status: pgtype.Present}, dst: &f32, expected: float32(42)},
{src: &pgtype.Numeric{Int: big.NewInt(42), Status: pgtype.Present}, dst: &f64, expected: float64(42)}, {src: &pgtype.Numeric{Int: big.NewInt(42), Status: pgtype.Present}, dst: &f64, expected: float64(42)},
{src: &pgtype.Numeric{Int: big.NewInt(42), Exp: -1, Status: pgtype.Present}, dst: &f32, expected: float32(4.2)},
{src: &pgtype.Numeric{Int: big.NewInt(42), Exp: -1, Status: pgtype.Present}, dst: &f64, expected: float64(4.2)},
{src: &pgtype.Numeric{Int: big.NewInt(42), Status: pgtype.Present}, dst: &i16, expected: int16(42)}, {src: &pgtype.Numeric{Int: big.NewInt(42), Status: pgtype.Present}, dst: &i16, expected: int16(42)},
{src: &pgtype.Numeric{Int: big.NewInt(42), Status: pgtype.Present}, dst: &i32, expected: int32(42)}, {src: &pgtype.Numeric{Int: big.NewInt(42), Status: pgtype.Present}, dst: &i32, expected: int32(42)},
{src: &pgtype.Numeric{Int: big.NewInt(42), Status: pgtype.Present}, dst: &i64, expected: int64(42)}, {src: &pgtype.Numeric{Int: big.NewInt(42), Status: pgtype.Present}, dst: &i64, expected: int64(42)},
{src: &pgtype.Numeric{Int: big.NewInt(42), Exp: 3, Status: pgtype.Present}, dst: &i64, expected: int64(42000)},
{src: &pgtype.Numeric{Int: big.NewInt(42), Status: pgtype.Present}, dst: &i, expected: int(42)}, {src: &pgtype.Numeric{Int: big.NewInt(42), Status: pgtype.Present}, dst: &i, expected: int(42)},
{src: &pgtype.Numeric{Int: big.NewInt(42), Status: pgtype.Present}, dst: &ui8, expected: uint8(42)}, {src: &pgtype.Numeric{Int: big.NewInt(42), Status: pgtype.Present}, dst: &ui8, expected: uint8(42)},
{src: &pgtype.Numeric{Int: big.NewInt(42), Status: pgtype.Present}, dst: &ui16, expected: uint16(42)}, {src: &pgtype.Numeric{Int: big.NewInt(42), Status: pgtype.Present}, dst: &ui16, expected: uint16(42)},
+31
View File
@@ -1,6 +1,7 @@
package pgtype_test package pgtype_test
import ( import (
"context"
"database/sql" "database/sql"
"fmt" "fmt"
"io" "io"
@@ -125,6 +126,7 @@ func testSuccessfulTranscode(t testing.TB, pgTypeName string, values []interface
func testSuccessfulTranscodeEqFunc(t testing.TB, pgTypeName string, values []interface{}, eqFunc func(a, b interface{}) bool) { func testSuccessfulTranscodeEqFunc(t testing.TB, pgTypeName string, values []interface{}, eqFunc func(a, b interface{}) bool) {
testPgxSuccessfulTranscodeEqFunc(t, pgTypeName, values, eqFunc) testPgxSuccessfulTranscodeEqFunc(t, pgTypeName, values, eqFunc)
testPgxSimpleProtocolSuccessfulTranscodeEqFunc(t, pgTypeName, values, eqFunc)
for _, driverName := range []string{"github.com/lib/pq", "github.com/jackc/pgx/stdlib"} { for _, driverName := range []string{"github.com/lib/pq", "github.com/jackc/pgx/stdlib"} {
testDatabaseSQLSuccessfulTranscodeEqFunc(t, driverName, pgTypeName, values, eqFunc) testDatabaseSQLSuccessfulTranscodeEqFunc(t, driverName, pgTypeName, values, eqFunc)
} }
@@ -175,6 +177,35 @@ func testPgxSuccessfulTranscodeEqFunc(t testing.TB, pgTypeName string, values []
} }
} }
func testPgxSimpleProtocolSuccessfulTranscodeEqFunc(t testing.TB, pgTypeName string, values []interface{}, eqFunc func(a, b interface{}) bool) {
conn := mustConnectPgx(t)
defer mustClose(t, conn)
for i, v := range values {
// Derefence value if it is a pointer
derefV := v
refVal := reflect.ValueOf(v)
if refVal.Kind() == reflect.Ptr {
derefV = refVal.Elem().Interface()
}
result := reflect.New(reflect.TypeOf(derefV))
err := conn.QueryRowEx(
context.Background(),
fmt.Sprintf("select ($1)::%s", pgTypeName),
&pgx.QueryExOptions{SimpleProtocol: true},
v,
).Scan(result.Interface())
if err != nil {
t.Errorf("Simple protocol %d: %v", i, err)
}
if !eqFunc(result.Elem().Interface(), derefV) {
t.Errorf("Simple protocol %d: expected %v, got %v", i, derefV, result.Elem().Interface())
}
}
}
func testDatabaseSQLSuccessfulTranscodeEqFunc(t testing.TB, driverName, pgTypeName string, values []interface{}, eqFunc func(a, b interface{}) bool) { func testDatabaseSQLSuccessfulTranscodeEqFunc(t testing.TB, driverName, pgTypeName string, values []interface{}, eqFunc func(a, b interface{}) bool) {
conn := mustConnectDatabaseSQL(t, driverName) conn := mustConnectDatabaseSQL(t, driverName)
defer mustClose(t, conn) defer mustClose(t, conn)
+15 -2
View File
@@ -8,10 +8,23 @@ import (
) )
func TestXidTranscode(t *testing.T) { func TestXidTranscode(t *testing.T) {
testSuccessfulTranscode(t, "xid", []interface{}{ pgTypeName := "xid"
values := []interface{}{
pgtype.Xid{Uint: 42, Status: pgtype.Present}, pgtype.Xid{Uint: 42, Status: pgtype.Present},
pgtype.Xid{Status: pgtype.Null}, pgtype.Xid{Status: pgtype.Null},
}) }
eqFunc := func(a, b interface{}) bool {
return reflect.DeepEqual(a, b)
}
testPgxSuccessfulTranscodeEqFunc(t, pgTypeName, values, eqFunc)
// No direct conversion from int to xid, convert through text
testPgxSimpleProtocolSuccessfulTranscodeEqFunc(t, "text::"+pgTypeName, values, eqFunc)
for _, driverName := range []string{"github.com/lib/pq", "github.com/jackc/pgx/stdlib"} {
testDatabaseSQLSuccessfulTranscodeEqFunc(t, driverName, pgTypeName, values, eqFunc)
}
} }
func TestXidSet(t *testing.T) { func TestXidSet(t *testing.T) {