summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/lib
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/lib')
-rw-r--r--vendor/github.com/lib/pq/.travis.yml14
-rw-r--r--vendor/github.com/lib/pq/array.go45
-rw-r--r--vendor/github.com/lib/pq/array_test.go164
-rw-r--r--vendor/github.com/lib/pq/conn.go189
-rw-r--r--vendor/github.com/lib/pq/conn_go18.go92
-rw-r--r--vendor/github.com/lib/pq/copy.go27
-rw-r--r--vendor/github.com/lib/pq/encode.go8
-rw-r--r--vendor/github.com/lib/pq/encode_test.go52
-rw-r--r--vendor/github.com/lib/pq/go18_test.go99
-rw-r--r--vendor/github.com/lib/pq/ssl.go175
-rw-r--r--vendor/github.com/lib/pq/ssl_go1.7.go14
-rw-r--r--vendor/github.com/lib/pq/ssl_permissions.go16
-rw-r--r--vendor/github.com/lib/pq/ssl_renegotiation.go8
-rw-r--r--vendor/github.com/lib/pq/ssl_windows.go9
-rw-r--r--vendor/github.com/lib/pq/uuid.go23
-rw-r--r--vendor/github.com/lib/pq/uuid_test.go46
16 files changed, 796 insertions, 185 deletions
diff --git a/vendor/github.com/lib/pq/.travis.yml b/vendor/github.com/lib/pq/.travis.yml
index d7b60f899..1a4656c53 100644
--- a/vendor/github.com/lib/pq/.travis.yml
+++ b/vendor/github.com/lib/pq/.travis.yml
@@ -1,10 +1,11 @@
language: go
go:
- - 1.5
- - 1.6
- - 1.7
- - tip
+ - 1.5.x
+ - 1.6.x
+ - 1.7.x
+ - 1.8.x
+ - master
sudo: true
@@ -15,6 +16,7 @@ env:
- PQSSLCERTTEST_PATH=$PWD/certs
- PGHOST=127.0.0.1
matrix:
+ - PGVERSION=9.6
- PGVERSION=9.5
- PGVERSION=9.4
- PGVERSION=9.3
@@ -39,5 +41,5 @@ script:
- >
goimports -d -e $(find -name '*.go') | awk '{ print } END { exit NR == 0 ? 0 : 1 }'
- go vet ./...
- - PQTEST_BINARY_PARAMETERS=no go test -v ./...
- - PQTEST_BINARY_PARAMETERS=yes go test -v ./...
+ - PQTEST_BINARY_PARAMETERS=no go test -race -v ./...
+ - PQTEST_BINARY_PARAMETERS=yes go test -race -v ./...
diff --git a/vendor/github.com/lib/pq/array.go b/vendor/github.com/lib/pq/array.go
index 27eb07a9e..e7b2145d6 100644
--- a/vendor/github.com/lib/pq/array.go
+++ b/vendor/github.com/lib/pq/array.go
@@ -70,6 +70,9 @@ func (a *BoolArray) Scan(src interface{}) error {
return a.scanBytes(src)
case string:
return a.scanBytes([]byte(src))
+ case nil:
+ *a = nil
+ return nil
}
return fmt.Errorf("pq: cannot convert %T to BoolArray", src)
@@ -80,7 +83,7 @@ func (a *BoolArray) scanBytes(src []byte) error {
if err != nil {
return err
}
- if len(elems) == 0 {
+ if *a != nil && len(elems) == 0 {
*a = (*a)[:0]
} else {
b := make(BoolArray, len(elems))
@@ -141,6 +144,9 @@ func (a *ByteaArray) Scan(src interface{}) error {
return a.scanBytes(src)
case string:
return a.scanBytes([]byte(src))
+ case nil:
+ *a = nil
+ return nil
}
return fmt.Errorf("pq: cannot convert %T to ByteaArray", src)
@@ -151,7 +157,7 @@ func (a *ByteaArray) scanBytes(src []byte) error {
if err != nil {
return err
}
- if len(elems) == 0 {
+ if *a != nil && len(elems) == 0 {
*a = (*a)[:0]
} else {
b := make(ByteaArray, len(elems))
@@ -210,6 +216,9 @@ func (a *Float64Array) Scan(src interface{}) error {
return a.scanBytes(src)
case string:
return a.scanBytes([]byte(src))
+ case nil:
+ *a = nil
+ return nil
}
return fmt.Errorf("pq: cannot convert %T to Float64Array", src)
@@ -220,7 +229,7 @@ func (a *Float64Array) scanBytes(src []byte) error {
if err != nil {
return err
}
- if len(elems) == 0 {
+ if *a != nil && len(elems) == 0 {
*a = (*a)[:0]
} else {
b := make(Float64Array, len(elems))
@@ -320,6 +329,11 @@ func (a GenericArray) Scan(src interface{}) error {
return a.scanBytes(src, dv)
case string:
return a.scanBytes([]byte(src), dv)
+ case nil:
+ if dv.Kind() == reflect.Slice {
+ dv.Set(reflect.Zero(dv.Type()))
+ return nil
+ }
}
return fmt.Errorf("pq: cannot convert %T to %s", src, dv.Type())
@@ -386,7 +400,13 @@ func (a GenericArray) Value() (driver.Value, error) {
rv := reflect.ValueOf(a.A)
- if k := rv.Kind(); k != reflect.Array && k != reflect.Slice {
+ switch rv.Kind() {
+ case reflect.Slice:
+ if rv.IsNil() {
+ return nil, nil
+ }
+ case reflect.Array:
+ default:
return nil, fmt.Errorf("pq: Unable to convert %T to array", a.A)
}
@@ -412,6 +432,9 @@ func (a *Int64Array) Scan(src interface{}) error {
return a.scanBytes(src)
case string:
return a.scanBytes([]byte(src))
+ case nil:
+ *a = nil
+ return nil
}
return fmt.Errorf("pq: cannot convert %T to Int64Array", src)
@@ -422,7 +445,7 @@ func (a *Int64Array) scanBytes(src []byte) error {
if err != nil {
return err
}
- if len(elems) == 0 {
+ if *a != nil && len(elems) == 0 {
*a = (*a)[:0]
} else {
b := make(Int64Array, len(elems))
@@ -470,6 +493,9 @@ func (a *StringArray) Scan(src interface{}) error {
return a.scanBytes(src)
case string:
return a.scanBytes([]byte(src))
+ case nil:
+ *a = nil
+ return nil
}
return fmt.Errorf("pq: cannot convert %T to StringArray", src)
@@ -480,7 +506,7 @@ func (a *StringArray) scanBytes(src []byte) error {
if err != nil {
return err
}
- if len(elems) == 0 {
+ if *a != nil && len(elems) == 0 {
*a = (*a)[:0]
} else {
b := make(StringArray, len(elems))
@@ -639,6 +665,9 @@ Element:
for i < len(src) {
switch src[i] {
case '{':
+ if depth == len(dims) {
+ break Element
+ }
depth++
dims[depth-1] = 0
i++
@@ -680,11 +709,11 @@ Element:
}
for i < len(src) {
- if bytes.HasPrefix(src[i:], del) {
+ if bytes.HasPrefix(src[i:], del) && depth > 0 {
dims[depth-1]++
i += len(del)
goto Element
- } else if src[i] == '}' {
+ } else if src[i] == '}' && depth > 0 {
dims[depth-1]++
depth--
i++
diff --git a/vendor/github.com/lib/pq/array_test.go b/vendor/github.com/lib/pq/array_test.go
index 96402fd4a..10b843184 100644
--- a/vendor/github.com/lib/pq/array_test.go
+++ b/vendor/github.com/lib/pq/array_test.go
@@ -70,6 +70,10 @@ func TestParseArrayError(t *testing.T) {
{`{,}`, "unexpected ',' at offset 1"},
{`{,x}`, "unexpected ',' at offset 1"},
{`{x,}`, "unexpected '}' at offset 3"},
+ {`{x,{`, "unexpected '{' at offset 3"},
+ {`{x},`, "unexpected ',' at offset 3"},
+ {`{x}}`, "unexpected '}' at offset 3"},
+ {`{{x}`, "expected '}' at offset 4"},
{`{""x}`, "unexpected 'x' at offset 3"},
{`{{a},{b,c}}`, "multidimensional arrays must have elements with matching dimensions"},
} {
@@ -171,6 +175,30 @@ func TestBoolArrayScanUnsupported(t *testing.T) {
}
}
+func TestBoolArrayScanEmpty(t *testing.T) {
+ var arr BoolArray
+ err := arr.Scan(`{}`)
+
+ if err != nil {
+ t.Fatalf("Expected no error, got %v", err)
+ }
+ if arr == nil || len(arr) != 0 {
+ t.Errorf("Expected empty, got %#v", arr)
+ }
+}
+
+func TestBoolArrayScanNil(t *testing.T) {
+ arr := BoolArray{true, true, true}
+ err := arr.Scan(nil)
+
+ if err != nil {
+ t.Fatalf("Expected no error, got %v", err)
+ }
+ if arr != nil {
+ t.Errorf("Expected nil, got %+v", arr)
+ }
+}
+
var BoolArrayStringTests = []struct {
str string
arr BoolArray
@@ -300,6 +328,30 @@ func TestByteaArrayScanUnsupported(t *testing.T) {
}
}
+func TestByteaArrayScanEmpty(t *testing.T) {
+ var arr ByteaArray
+ err := arr.Scan(`{}`)
+
+ if err != nil {
+ t.Fatalf("Expected no error, got %v", err)
+ }
+ if arr == nil || len(arr) != 0 {
+ t.Errorf("Expected empty, got %#v", arr)
+ }
+}
+
+func TestByteaArrayScanNil(t *testing.T) {
+ arr := ByteaArray{{2}, {6}, {0, 0}}
+ err := arr.Scan(nil)
+
+ if err != nil {
+ t.Fatalf("Expected no error, got %v", err)
+ }
+ if arr != nil {
+ t.Errorf("Expected nil, got %+v", arr)
+ }
+}
+
var ByteaArrayStringTests = []struct {
str string
arr ByteaArray
@@ -430,6 +482,30 @@ func TestFloat64ArrayScanUnsupported(t *testing.T) {
}
}
+func TestFloat64ArrayScanEmpty(t *testing.T) {
+ var arr Float64Array
+ err := arr.Scan(`{}`)
+
+ if err != nil {
+ t.Fatalf("Expected no error, got %v", err)
+ }
+ if arr == nil || len(arr) != 0 {
+ t.Errorf("Expected empty, got %#v", arr)
+ }
+}
+
+func TestFloat64ArrayScanNil(t *testing.T) {
+ arr := Float64Array{5, 5, 5}
+ err := arr.Scan(nil)
+
+ if err != nil {
+ t.Fatalf("Expected no error, got %v", err)
+ }
+ if arr != nil {
+ t.Errorf("Expected nil, got %+v", arr)
+ }
+}
+
var Float64ArrayStringTests = []struct {
str string
arr Float64Array
@@ -560,6 +636,30 @@ func TestInt64ArrayScanUnsupported(t *testing.T) {
}
}
+func TestInt64ArrayScanEmpty(t *testing.T) {
+ var arr Int64Array
+ err := arr.Scan(`{}`)
+
+ if err != nil {
+ t.Fatalf("Expected no error, got %v", err)
+ }
+ if arr == nil || len(arr) != 0 {
+ t.Errorf("Expected empty, got %#v", arr)
+ }
+}
+
+func TestInt64ArrayScanNil(t *testing.T) {
+ arr := Int64Array{5, 5, 5}
+ err := arr.Scan(nil)
+
+ if err != nil {
+ t.Fatalf("Expected no error, got %v", err)
+ }
+ if arr != nil {
+ t.Errorf("Expected nil, got %+v", arr)
+ }
+}
+
var Int64ArrayStringTests = []struct {
str string
arr Int64Array
@@ -689,6 +789,30 @@ func TestStringArrayScanUnsupported(t *testing.T) {
}
}
+func TestStringArrayScanEmpty(t *testing.T) {
+ var arr StringArray
+ err := arr.Scan(`{}`)
+
+ if err != nil {
+ t.Fatalf("Expected no error, got %v", err)
+ }
+ if arr == nil || len(arr) != 0 {
+ t.Errorf("Expected empty, got %#v", arr)
+ }
+}
+
+func TestStringArrayScanNil(t *testing.T) {
+ arr := StringArray{"x", "x", "x"}
+ err := arr.Scan(nil)
+
+ if err != nil {
+ t.Fatalf("Expected no error, got %v", err)
+ }
+ if arr != nil {
+ t.Errorf("Expected nil, got %+v", arr)
+ }
+}
+
var StringArrayStringTests = []struct {
str string
arr StringArray
@@ -811,6 +935,7 @@ func BenchmarkStringArrayValue(b *testing.B) {
func TestGenericArrayScanUnsupported(t *testing.T) {
var s string
var ss []string
+ var nsa [1]sql.NullString
for _, tt := range []struct {
src, dest interface{}
@@ -820,6 +945,7 @@ func TestGenericArrayScanUnsupported(t *testing.T) {
{nil, true, "destination bool is not a pointer to array or slice"},
{nil, &s, "destination *string is not a pointer to array or slice"},
{nil, ss, "destination []string is not a pointer to array or slice"},
+ {nil, &nsa, "<nil> to [1]sql.NullString"},
{true, &ss, "bool to []string"},
{`{{x}}`, &ss, "multidimensional ARRAY[1][1] is not implemented"},
{`{{x},{x}}`, &ss, "multidimensional ARRAY[2][1] is not implemented"},
@@ -862,6 +988,28 @@ func TestGenericArrayScanScannerArrayString(t *testing.T) {
}
}
+func TestGenericArrayScanScannerSliceEmpty(t *testing.T) {
+ var nss []sql.NullString
+
+ if err := (GenericArray{&nss}).Scan(`{}`); err != nil {
+ t.Fatalf("Expected no error, got %v", err)
+ }
+ if nss == nil || len(nss) != 0 {
+ t.Errorf("Expected empty, got %#v", nss)
+ }
+}
+
+func TestGenericArrayScanScannerSliceNil(t *testing.T) {
+ nss := []sql.NullString{{String: ``, Valid: true}, {}}
+
+ if err := (GenericArray{&nss}).Scan(nil); err != nil {
+ t.Fatalf("Expected no error, got %v", err)
+ }
+ if nss != nil {
+ t.Errorf("Expected nil, got %+v", nss)
+ }
+}
+
func TestGenericArrayScanScannerSliceBytes(t *testing.T) {
src, expected, nss := []byte(`{NULL,abc,"\""}`),
[]sql.NullString{{}, {String: `abc`, Valid: true}, {String: `"`, Valid: true}},
@@ -977,6 +1125,22 @@ func TestGenericArrayValue(t *testing.T) {
t.Errorf("Expected nil, got %q", result)
}
+ for _, tt := range []interface{}{
+ []bool(nil),
+ [][]int(nil),
+ []*int(nil),
+ []sql.NullString(nil),
+ } {
+ result, err := GenericArray{tt}.Value()
+
+ if err != nil {
+ t.Fatalf("Expected no error for %#v, got %v", tt, err)
+ }
+ if result != nil {
+ t.Errorf("Expected nil for %#v, got %q", tt, result)
+ }
+ }
+
Tilde := func(v driver.Value) FuncArrayValuer {
return FuncArrayValuer{
func() string { return "~" },
diff --git a/vendor/github.com/lib/pq/conn.go b/vendor/github.com/lib/pq/conn.go
index ca88dc8c6..3c8f77cb6 100644
--- a/vendor/github.com/lib/pq/conn.go
+++ b/vendor/github.com/lib/pq/conn.go
@@ -3,15 +3,12 @@ package pq
import (
"bufio"
"crypto/md5"
- "crypto/tls"
- "crypto/x509"
"database/sql"
"database/sql/driver"
"encoding/binary"
"errors"
"fmt"
"io"
- "io/ioutil"
"net"
"os"
"os/user"
@@ -101,6 +98,15 @@ type conn struct {
namei int
scratch [512]byte
txnStatus transactionStatus
+ txnClosed chan<- struct{}
+
+ // Save connection arguments to use during CancelRequest.
+ dialer Dialer
+ opts values
+
+ // Cancellation key data for use with CancelRequest messages.
+ processID int
+ secretKey int
parameterStatus parameterStatus
@@ -310,7 +316,10 @@ func DialOpen(d Dialer, name string) (_ driver.Conn, err error) {
}
}
- cn := &conn{}
+ cn := &conn{
+ opts: o,
+ dialer: d,
+ }
err = cn.handleDriverSettings(o)
if err != nil {
return nil, err
@@ -532,7 +541,15 @@ func (cn *conn) Begin() (_ driver.Tx, err error) {
return cn, nil
}
+func (cn *conn) closeTxn() {
+ if cn.txnClosed != nil {
+ close(cn.txnClosed)
+ cn.txnClosed = nil
+ }
+}
+
func (cn *conn) Commit() (err error) {
+ defer cn.closeTxn()
if cn.bad {
return driver.ErrBadConn
}
@@ -568,6 +585,7 @@ func (cn *conn) Commit() (err error) {
}
func (cn *conn) Rollback() (err error) {
+ defer cn.closeTxn()
if cn.bad {
return driver.ErrBadConn
}
@@ -718,6 +736,8 @@ func decideColumnFormats(colTyps []oid.Oid, forceText bool) (colFmts []format, c
case oid.T_int4:
fallthrough
case oid.T_int2:
+ fallthrough
+ case oid.T_uuid:
colFmts[i] = formatBinary
allText = false
@@ -797,7 +817,11 @@ func (cn *conn) Close() (err error) {
}
// Implement the "Queryer" interface
-func (cn *conn) Query(query string, args []driver.Value) (_ driver.Rows, err error) {
+func (cn *conn) Query(query string, args []driver.Value) (driver.Rows, error) {
+ return cn.query(query, args)
+}
+
+func (cn *conn) query(query string, args []driver.Value) (_ *rows, err error) {
if cn.bad {
return nil, driver.ErrBadConn
}
@@ -1000,42 +1024,12 @@ func (cn *conn) recv1() (t byte, r *readBuf) {
}
func (cn *conn) ssl(o values) {
- verifyCaOnly := false
- tlsConf := tls.Config{}
- switch mode := o.Get("sslmode"); mode {
- // "require" is the default.
- case "", "require":
- // We must skip TLS's own verification since it requires full
- // verification since Go 1.3.
- tlsConf.InsecureSkipVerify = true
-
- // From http://www.postgresql.org/docs/current/static/libpq-ssl.html:
- // Note: For backwards compatibility with earlier versions of PostgreSQL, if a
- // root CA file exists, the behavior of sslmode=require will be the same as
- // that of verify-ca, meaning the server certificate is validated against the
- // CA. Relying on this behavior is discouraged, and applications that need
- // certificate validation should always use verify-ca or verify-full.
- if _, err := os.Stat(o.Get("sslrootcert")); err == nil {
- verifyCaOnly = true
- } else {
- o.Set("sslrootcert", "")
- }
- case "verify-ca":
- // We must skip TLS's own verification since it requires full
- // verification since Go 1.3.
- tlsConf.InsecureSkipVerify = true
- verifyCaOnly = true
- case "verify-full":
- tlsConf.ServerName = o.Get("host")
- case "disable":
+ upgrade := ssl(o)
+ if upgrade == nil {
+ // Nothing to do
return
- default:
- errorf(`unsupported sslmode %q; only "require" (default), "verify-full", "verify-ca", and "disable" supported`, mode)
}
- cn.setupSSLClientCertificates(&tlsConf, o)
- cn.setupSSLCA(&tlsConf, o)
-
w := cn.writeBuf(0)
w.int32(80877103)
cn.sendStartupPacket(w)
@@ -1050,114 +1044,7 @@ func (cn *conn) ssl(o values) {
panic(ErrSSLNotSupported)
}
- client := tls.Client(cn.c, &tlsConf)
- if verifyCaOnly {
- cn.verifyCA(client, &tlsConf)
- }
- cn.c = client
-}
-
-// verifyCA carries out a TLS handshake to the server and verifies the
-// presented certificate against the effective CA, i.e. the one specified in
-// sslrootcert or the system CA if sslrootcert was not specified.
-func (cn *conn) verifyCA(client *tls.Conn, tlsConf *tls.Config) {
- err := client.Handshake()
- if err != nil {
- panic(err)
- }
- certs := client.ConnectionState().PeerCertificates
- opts := x509.VerifyOptions{
- DNSName: client.ConnectionState().ServerName,
- Intermediates: x509.NewCertPool(),
- Roots: tlsConf.RootCAs,
- }
- for i, cert := range certs {
- if i == 0 {
- continue
- }
- opts.Intermediates.AddCert(cert)
- }
- _, err = certs[0].Verify(opts)
- if err != nil {
- panic(err)
- }
-}
-
-// This function sets up SSL client certificates based on either the "sslkey"
-// and "sslcert" settings (possibly set via the environment variables PGSSLKEY
-// and PGSSLCERT, respectively), or if they aren't set, from the .postgresql
-// directory in the user's home directory. If the file paths are set
-// explicitly, the files must exist. The key file must also not be
-// world-readable, or this function will panic with
-// ErrSSLKeyHasWorldPermissions.
-func (cn *conn) setupSSLClientCertificates(tlsConf *tls.Config, o values) {
- var missingOk bool
-
- sslkey := o.Get("sslkey")
- sslcert := o.Get("sslcert")
- if sslkey != "" && sslcert != "" {
- // If the user has set an sslkey and sslcert, they *must* exist.
- missingOk = false
- } else {
- // Automatically load certificates from ~/.postgresql.
- user, err := user.Current()
- if err != nil {
- // user.Current() might fail when cross-compiling. We have to
- // ignore the error and continue without client certificates, since
- // we wouldn't know where to load them from.
- return
- }
-
- sslkey = filepath.Join(user.HomeDir, ".postgresql", "postgresql.key")
- sslcert = filepath.Join(user.HomeDir, ".postgresql", "postgresql.crt")
- missingOk = true
- }
-
- // Check that both files exist, and report the error or stop, depending on
- // which behaviour we want. Note that we don't do any more extensive
- // checks than this (such as checking that the paths aren't directories);
- // LoadX509KeyPair() will take care of the rest.
- keyfinfo, err := os.Stat(sslkey)
- if err != nil && missingOk {
- return
- } else if err != nil {
- panic(err)
- }
- _, err = os.Stat(sslcert)
- if err != nil && missingOk {
- return
- } else if err != nil {
- panic(err)
- }
-
- // If we got this far, the key file must also have the correct permissions
- kmode := keyfinfo.Mode()
- if kmode != kmode&0600 {
- panic(ErrSSLKeyHasWorldPermissions)
- }
-
- cert, err := tls.LoadX509KeyPair(sslcert, sslkey)
- if err != nil {
- panic(err)
- }
- tlsConf.Certificates = []tls.Certificate{cert}
-}
-
-// Sets up RootCAs in the TLS configuration if sslrootcert is set.
-func (cn *conn) setupSSLCA(tlsConf *tls.Config, o values) {
- if sslrootcert := o.Get("sslrootcert"); sslrootcert != "" {
- tlsConf.RootCAs = x509.NewCertPool()
-
- cert, err := ioutil.ReadFile(sslrootcert)
- if err != nil {
- panic(err)
- }
-
- ok := tlsConf.RootCAs.AppendCertsFromPEM(cert)
- if !ok {
- errorf("couldn't parse pem in sslrootcert")
- }
- }
+ cn.c = upgrade(cn.c)
}
// isDriverSetting returns true iff a setting is purely for configuring the
@@ -1212,6 +1099,7 @@ func (cn *conn) startup(o values) {
t, r := cn.recv()
switch t {
case 'K':
+ cn.processBackendKeyData(r)
case 'S':
cn.processParameterStatus(r)
case 'R':
@@ -1439,6 +1327,7 @@ func (cn *conn) parseComplete(commandTag string) (driver.Result, string) {
type rows struct {
cn *conn
+ closed chan<- struct{}
colNames []string
colTyps []oid.Oid
colFmts []format
@@ -1447,6 +1336,9 @@ type rows struct {
}
func (rs *rows) Close() error {
+ if rs.closed != nil {
+ defer close(rs.closed)
+ }
// no need to look at cn.bad as Next() will
for {
err := rs.Next(nil)
@@ -1651,6 +1543,11 @@ func (cn *conn) readReadyForQuery() {
}
}
+func (c *conn) processBackendKeyData(r *readBuf) {
+ c.processID = r.int32()
+ c.secretKey = r.int32()
+}
+
func (cn *conn) readParseResponse() {
t, r := cn.recv1()
switch t {
diff --git a/vendor/github.com/lib/pq/conn_go18.go b/vendor/github.com/lib/pq/conn_go18.go
new file mode 100644
index 000000000..0aca1d002
--- /dev/null
+++ b/vendor/github.com/lib/pq/conn_go18.go
@@ -0,0 +1,92 @@
+// +build go1.8
+
+package pq
+
+import (
+ "context"
+ "database/sql/driver"
+ "errors"
+)
+
+// Implement the "QueryerContext" interface
+func (cn *conn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) {
+ list := make([]driver.Value, len(args))
+ for i, nv := range args {
+ list[i] = nv.Value
+ }
+ var closed chan<- struct{}
+ if ctx.Done() != nil {
+ closed = watchCancel(ctx, cn.cancel)
+ }
+ r, err := cn.query(query, list)
+ if err != nil {
+ return nil, err
+ }
+ r.closed = closed
+ return r, nil
+}
+
+// Implement the "ExecerContext" interface
+func (cn *conn) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) {
+ list := make([]driver.Value, len(args))
+ for i, nv := range args {
+ list[i] = nv.Value
+ }
+
+ if ctx.Done() != nil {
+ closed := watchCancel(ctx, cn.cancel)
+ defer close(closed)
+ }
+
+ return cn.Exec(query, list)
+}
+
+// Implement the "ConnBeginTx" interface
+func (cn *conn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) {
+ if opts.Isolation != 0 {
+ return nil, errors.New("isolation levels not supported")
+ }
+ if opts.ReadOnly {
+ return nil, errors.New("read-only transactions not supported")
+ }
+ tx, err := cn.Begin()
+ if err != nil {
+ return nil, err
+ }
+ if ctx.Done() != nil {
+ cn.txnClosed = watchCancel(ctx, cn.cancel)
+ }
+ return tx, nil
+}
+
+func watchCancel(ctx context.Context, cancel func()) chan<- struct{} {
+ closed := make(chan struct{})
+ go func() {
+ select {
+ case <-ctx.Done():
+ cancel()
+ case <-closed:
+ }
+ }()
+ return closed
+}
+
+func (cn *conn) cancel() {
+ var err error
+ can := &conn{}
+ can.c, err = dial(cn.dialer, cn.opts)
+ if err != nil {
+ return
+ }
+ can.ssl(cn.opts)
+
+ defer can.errRecover(&err)
+
+ w := can.writeBuf(0)
+ w.int32(80877102) // cancel request code
+ w.int32(cn.processID)
+ w.int32(cn.secretKey)
+
+ can.sendStartupPacket(w)
+ _ = can.c.Close()
+}
diff --git a/vendor/github.com/lib/pq/copy.go b/vendor/github.com/lib/pq/copy.go
index 86a7127e1..345c2398f 100644
--- a/vendor/github.com/lib/pq/copy.go
+++ b/vendor/github.com/lib/pq/copy.go
@@ -97,13 +97,13 @@ awaitCopyInResponse:
err = parseError(r)
case 'Z':
if err == nil {
- cn.bad = true
+ ci.setBad()
errorf("unexpected ReadyForQuery in response to COPY")
}
cn.processReadyForQuery(r)
return nil, err
default:
- cn.bad = true
+ ci.setBad()
errorf("unknown response for copy query: %q", t)
}
}
@@ -122,7 +122,7 @@ awaitCopyInResponse:
cn.processReadyForQuery(r)
return nil, err
default:
- cn.bad = true
+ ci.setBad()
errorf("unknown response for CopyFail: %q", t)
}
}
@@ -143,7 +143,7 @@ func (ci *copyin) resploop() {
var r readBuf
t, err := ci.cn.recvMessage(&r)
if err != nil {
- ci.cn.bad = true
+ ci.setBad()
ci.setError(err)
ci.done <- true
return
@@ -161,7 +161,7 @@ func (ci *copyin) resploop() {
err := parseError(&r)
ci.setError(err)
default:
- ci.cn.bad = true
+ ci.setBad()
ci.setError(fmt.Errorf("unknown response during CopyIn: %q", t))
ci.done <- true
return
@@ -169,6 +169,19 @@ func (ci *copyin) resploop() {
}
}
+func (ci *copyin) setBad() {
+ ci.Lock()
+ ci.cn.bad = true
+ ci.Unlock()
+}
+
+func (ci *copyin) isBad() bool {
+ ci.Lock()
+ b := ci.cn.bad
+ ci.Unlock()
+ return b
+}
+
func (ci *copyin) isErrorSet() bool {
ci.Lock()
isSet := (ci.err != nil)
@@ -206,7 +219,7 @@ func (ci *copyin) Exec(v []driver.Value) (r driver.Result, err error) {
return nil, errCopyInClosed
}
- if ci.cn.bad {
+ if ci.isBad() {
return nil, driver.ErrBadConn
}
defer ci.cn.errRecover(&err)
@@ -244,7 +257,7 @@ func (ci *copyin) Close() (err error) {
}
ci.closed = true
- if ci.cn.bad {
+ if ci.isBad() {
return driver.ErrBadConn
}
defer ci.cn.errRecover(&err)
diff --git a/vendor/github.com/lib/pq/encode.go b/vendor/github.com/lib/pq/encode.go
index 29e8f6ff7..88a322cda 100644
--- a/vendor/github.com/lib/pq/encode.go
+++ b/vendor/github.com/lib/pq/encode.go
@@ -76,6 +76,12 @@ func binaryDecode(parameterStatus *parameterStatus, s []byte, typ oid.Oid) inter
return int64(int32(binary.BigEndian.Uint32(s)))
case oid.T_int2:
return int64(int16(binary.BigEndian.Uint16(s)))
+ case oid.T_uuid:
+ b, err := decodeUUIDBinary(s)
+ if err != nil {
+ panic(err)
+ }
+ return b
default:
errorf("don't know how to decode binary parameter of type %d", uint32(typ))
@@ -471,7 +477,7 @@ func FormatTimestamp(t time.Time) []byte {
t = t.AddDate((-t.Year())*2+1, 0, 0)
bc = true
}
- b := []byte(t.Format(time.RFC3339Nano))
+ b := []byte(t.Format("2006-01-02 15:04:05.999999999Z07:00"))
_, offset := t.Zone()
offset = offset % 60
diff --git a/vendor/github.com/lib/pq/encode_test.go b/vendor/github.com/lib/pq/encode_test.go
index 1e89f7f6f..b1531ec29 100644
--- a/vendor/github.com/lib/pq/encode_test.go
+++ b/vendor/github.com/lib/pq/encode_test.go
@@ -141,22 +141,22 @@ var formatTimeTests = []struct {
time time.Time
expected string
}{
- {time.Time{}, "0001-01-01T00:00:00Z"},
- {time.Date(2001, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", 0)), "2001-02-03T04:05:06.123456789Z"},
- {time.Date(2001, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", 2*60*60)), "2001-02-03T04:05:06.123456789+02:00"},
- {time.Date(2001, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", -6*60*60)), "2001-02-03T04:05:06.123456789-06:00"},
- {time.Date(2001, time.February, 3, 4, 5, 6, 0, time.FixedZone("", -(7*60*60+30*60+9))), "2001-02-03T04:05:06-07:30:09"},
-
- {time.Date(1, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", 0)), "0001-02-03T04:05:06.123456789Z"},
- {time.Date(1, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", 2*60*60)), "0001-02-03T04:05:06.123456789+02:00"},
- {time.Date(1, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", -6*60*60)), "0001-02-03T04:05:06.123456789-06:00"},
-
- {time.Date(0, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", 0)), "0001-02-03T04:05:06.123456789Z BC"},
- {time.Date(0, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", 2*60*60)), "0001-02-03T04:05:06.123456789+02:00 BC"},
- {time.Date(0, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", -6*60*60)), "0001-02-03T04:05:06.123456789-06:00 BC"},
-
- {time.Date(1, time.February, 3, 4, 5, 6, 0, time.FixedZone("", -(7*60*60+30*60+9))), "0001-02-03T04:05:06-07:30:09"},
- {time.Date(0, time.February, 3, 4, 5, 6, 0, time.FixedZone("", -(7*60*60+30*60+9))), "0001-02-03T04:05:06-07:30:09 BC"},
+ {time.Time{}, "0001-01-01 00:00:00Z"},
+ {time.Date(2001, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", 0)), "2001-02-03 04:05:06.123456789Z"},
+ {time.Date(2001, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", 2*60*60)), "2001-02-03 04:05:06.123456789+02:00"},
+ {time.Date(2001, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", -6*60*60)), "2001-02-03 04:05:06.123456789-06:00"},
+ {time.Date(2001, time.February, 3, 4, 5, 6, 0, time.FixedZone("", -(7*60*60+30*60+9))), "2001-02-03 04:05:06-07:30:09"},
+
+ {time.Date(1, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", 0)), "0001-02-03 04:05:06.123456789Z"},
+ {time.Date(1, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", 2*60*60)), "0001-02-03 04:05:06.123456789+02:00"},
+ {time.Date(1, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", -6*60*60)), "0001-02-03 04:05:06.123456789-06:00"},
+
+ {time.Date(0, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", 0)), "0001-02-03 04:05:06.123456789Z BC"},
+ {time.Date(0, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", 2*60*60)), "0001-02-03 04:05:06.123456789+02:00 BC"},
+ {time.Date(0, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", -6*60*60)), "0001-02-03 04:05:06.123456789-06:00 BC"},
+
+ {time.Date(1, time.February, 3, 4, 5, 6, 0, time.FixedZone("", -(7*60*60+30*60+9))), "0001-02-03 04:05:06-07:30:09"},
+ {time.Date(0, time.February, 3, 4, 5, 6, 0, time.FixedZone("", -(7*60*60+30*60+9))), "0001-02-03 04:05:06-07:30:09 BC"},
}
func TestFormatTs(t *testing.T) {
@@ -168,6 +168,26 @@ func TestFormatTs(t *testing.T) {
}
}
+func TestFormatTsBackend(t *testing.T) {
+ db := openTestConn(t)
+ defer db.Close()
+
+ var str string
+ err := db.QueryRow("SELECT '2001-02-03T04:05:06.007-08:09:10'::time::text").Scan(&str)
+ if err == nil {
+ t.Fatalf("PostgreSQL is accepting an ISO timestamp input for time")
+ }
+
+ for i, tt := range formatTimeTests {
+ for _, typ := range []string{"date", "time", "timetz", "timestamp", "timestamptz"} {
+ err = db.QueryRow("SELECT $1::"+typ+"::text", tt.time).Scan(&str)
+ if err != nil {
+ t.Errorf("%d: incorrect time format for %v on the backend: %v", i, typ, err)
+ }
+ }
+ }
+}
+
func TestTimestampWithTimeZone(t *testing.T) {
db := openTestConn(t)
defer db.Close()
diff --git a/vendor/github.com/lib/pq/go18_test.go b/vendor/github.com/lib/pq/go18_test.go
index df3e496b5..15546d865 100644
--- a/vendor/github.com/lib/pq/go18_test.go
+++ b/vendor/github.com/lib/pq/go18_test.go
@@ -2,7 +2,12 @@
package pq
-import "testing"
+import (
+ "context"
+ "database/sql"
+ "testing"
+ "time"
+)
func TestMultipleSimpleQuery(t *testing.T) {
db := openTestConn(t)
@@ -66,3 +71,95 @@ func TestMultipleSimpleQuery(t *testing.T) {
t.Fatal("unexpected result set")
}
}
+
+func TestContextCancelExec(t *testing.T) {
+ db := openTestConn(t)
+ defer db.Close()
+
+ ctx, cancel := context.WithCancel(context.Background())
+
+ // Delay execution for just a bit until db.ExecContext has begun.
+ go func() {
+ time.Sleep(time.Millisecond * 10)
+ cancel()
+ }()
+
+ // Not canceled until after the exec has started.
+ if _, err := db.ExecContext(ctx, "select pg_sleep(1)"); err == nil {
+ t.Fatal("expected error")
+ } else if err.Error() != "pq: canceling statement due to user request" {
+ t.Fatalf("unexpected error: %s", err)
+ }
+
+ // Context is already canceled, so error should come before execution.
+ if _, err := db.ExecContext(ctx, "select pg_sleep(1)"); err == nil {
+ t.Fatal("expected error")
+ } else if err.Error() != "context canceled" {
+ t.Fatalf("unexpected error: %s", err)
+ }
+}
+
+func TestContextCancelQuery(t *testing.T) {
+ db := openTestConn(t)
+ defer db.Close()
+
+ ctx, cancel := context.WithCancel(context.Background())
+
+ // Delay execution for just a bit until db.QueryContext has begun.
+ go func() {
+ time.Sleep(time.Millisecond * 10)
+ cancel()
+ }()
+
+ // Not canceled until after the exec has started.
+ if _, err := db.QueryContext(ctx, "select pg_sleep(1)"); err == nil {
+ t.Fatal("expected error")
+ } else if err.Error() != "pq: canceling statement due to user request" {
+ t.Fatalf("unexpected error: %s", err)
+ }
+
+ // Context is already canceled, so error should come before execution.
+ if _, err := db.QueryContext(ctx, "select pg_sleep(1)"); err == nil {
+ t.Fatal("expected error")
+ } else if err.Error() != "context canceled" {
+ t.Fatalf("unexpected error: %s", err)
+ }
+}
+
+func TestContextCancelBegin(t *testing.T) {
+ db := openTestConn(t)
+ defer db.Close()
+
+ ctx, cancel := context.WithCancel(context.Background())
+ tx, err := db.BeginTx(ctx, nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Delay execution for just a bit until tx.Exec has begun.
+ go func() {
+ time.Sleep(time.Millisecond * 10)
+ cancel()
+ }()
+
+ // Not canceled until after the exec has started.
+ if _, err := tx.Exec("select pg_sleep(1)"); err == nil {
+ t.Fatal("expected error")
+ } else if err.Error() != "pq: canceling statement due to user request" {
+ t.Fatalf("unexpected error: %s", err)
+ }
+
+ // Transaction is canceled, so expect an error.
+ if _, err := tx.Query("select pg_sleep(1)"); err == nil {
+ t.Fatal("expected error")
+ } else if err != sql.ErrTxDone {
+ t.Fatalf("unexpected error: %s", err)
+ }
+
+ // Context is canceled, so cannot begin a transaction.
+ if _, err := db.BeginTx(ctx, nil); err == nil {
+ t.Fatal("expected error")
+ } else if err.Error() != "context canceled" {
+ t.Fatalf("unexpected error: %s", err)
+ }
+}
diff --git a/vendor/github.com/lib/pq/ssl.go b/vendor/github.com/lib/pq/ssl.go
new file mode 100644
index 000000000..b282ebd92
--- /dev/null
+++ b/vendor/github.com/lib/pq/ssl.go
@@ -0,0 +1,175 @@
+package pq
+
+import (
+ "crypto/tls"
+ "crypto/x509"
+ "io/ioutil"
+ "net"
+ "os"
+ "os/user"
+ "path/filepath"
+)
+
+// ssl generates a function to upgrade a net.Conn based on the "sslmode" and
+// related settings. The function is nil when no upgrade should take place.
+func ssl(o values) func(net.Conn) net.Conn {
+ verifyCaOnly := false
+ tlsConf := tls.Config{}
+ switch mode := o.Get("sslmode"); mode {
+ // "require" is the default.
+ case "", "require":
+ // We must skip TLS's own verification since it requires full
+ // verification since Go 1.3.
+ tlsConf.InsecureSkipVerify = true
+
+ // From http://www.postgresql.org/docs/current/static/libpq-ssl.html:
+ // Note: For backwards compatibility with earlier versions of PostgreSQL, if a
+ // root CA file exists, the behavior of sslmode=require will be the same as
+ // that of verify-ca, meaning the server certificate is validated against the
+ // CA. Relying on this behavior is discouraged, and applications that need
+ // certificate validation should always use verify-ca or verify-full.
+ if _, err := os.Stat(o.Get("sslrootcert")); err == nil {
+ verifyCaOnly = true
+ } else {
+ o.Set("sslrootcert", "")
+ }
+ case "verify-ca":
+ // We must skip TLS's own verification since it requires full
+ // verification since Go 1.3.
+ tlsConf.InsecureSkipVerify = true
+ verifyCaOnly = true
+ case "verify-full":
+ tlsConf.ServerName = o.Get("host")
+ case "disable":
+ return nil
+ default:
+ errorf(`unsupported sslmode %q; only "require" (default), "verify-full", "verify-ca", and "disable" supported`, mode)
+ }
+
+ sslClientCertificates(&tlsConf, o)
+ sslCertificateAuthority(&tlsConf, o)
+ sslRenegotiation(&tlsConf)
+
+ return func(conn net.Conn) net.Conn {
+ client := tls.Client(conn, &tlsConf)
+ if verifyCaOnly {
+ sslVerifyCertificateAuthority(client, &tlsConf)
+ }
+ return client
+ }
+}
+
+// sslClientCertificates adds the certificate specified in the "sslcert" and
+// "sslkey" settings, or if they aren't set, from the .postgresql directory
+// in the user's home directory. The configured files must exist and have
+// the correct permissions.
+func sslClientCertificates(tlsConf *tls.Config, o values) {
+ sslkey := o.Get("sslkey")
+ sslcert := o.Get("sslcert")
+
+ var cinfo, kinfo os.FileInfo
+ var err error
+
+ if sslcert != "" && sslkey != "" {
+ // Check that both files exist. Note that we don't do any more extensive
+ // checks than this (such as checking that the paths aren't directories);
+ // LoadX509KeyPair() will take care of the rest.
+ cinfo, err = os.Stat(sslcert)
+ if err != nil {
+ panic(err)
+ }
+
+ kinfo, err = os.Stat(sslkey)
+ if err != nil {
+ panic(err)
+ }
+ } else {
+ // Automatically find certificates from ~/.postgresql
+ sslcert, sslkey, cinfo, kinfo = sslHomeCertificates()
+
+ if cinfo == nil || kinfo == nil {
+ // No certificates to load
+ return
+ }
+ }
+
+ // The files must also have the correct permissions
+ sslCertificatePermissions(cinfo, kinfo)
+
+ cert, err := tls.LoadX509KeyPair(sslcert, sslkey)
+ if err != nil {
+ panic(err)
+ }
+ tlsConf.Certificates = []tls.Certificate{cert}
+}
+
+// sslCertificateAuthority adds the RootCA specified in the "sslrootcert" setting.
+func sslCertificateAuthority(tlsConf *tls.Config, o values) {
+ if sslrootcert := o.Get("sslrootcert"); sslrootcert != "" {
+ tlsConf.RootCAs = x509.NewCertPool()
+
+ cert, err := ioutil.ReadFile(sslrootcert)
+ if err != nil {
+ panic(err)
+ }
+
+ ok := tlsConf.RootCAs.AppendCertsFromPEM(cert)
+ if !ok {
+ errorf("couldn't parse pem in sslrootcert")
+ }
+ }
+}
+
+// sslHomeCertificates returns the path and stats of certificates in the current
+// user's home directory.
+func sslHomeCertificates() (cert, key string, cinfo, kinfo os.FileInfo) {
+ user, err := user.Current()
+
+ if err != nil {
+ // user.Current() might fail when cross-compiling. We have to ignore the
+ // error and continue without client certificates, since we wouldn't know
+ // from where to load them.
+ return
+ }
+
+ cert = filepath.Join(user.HomeDir, ".postgresql", "postgresql.crt")
+ key = filepath.Join(user.HomeDir, ".postgresql", "postgresql.key")
+
+ cinfo, err = os.Stat(cert)
+ if err != nil {
+ cinfo = nil
+ }
+
+ kinfo, err = os.Stat(key)
+ if err != nil {
+ kinfo = nil
+ }
+
+ return
+}
+
+// sslVerifyCertificateAuthority carries out a TLS handshake to the server and
+// verifies the presented certificate against the CA, i.e. the one specified in
+// sslrootcert or the system CA if sslrootcert was not specified.
+func sslVerifyCertificateAuthority(client *tls.Conn, tlsConf *tls.Config) {
+ err := client.Handshake()
+ if err != nil {
+ panic(err)
+ }
+ certs := client.ConnectionState().PeerCertificates
+ opts := x509.VerifyOptions{
+ DNSName: client.ConnectionState().ServerName,
+ Intermediates: x509.NewCertPool(),
+ Roots: tlsConf.RootCAs,
+ }
+ for i, cert := range certs {
+ if i == 0 {
+ continue
+ }
+ opts.Intermediates.AddCert(cert)
+ }
+ _, err = certs[0].Verify(opts)
+ if err != nil {
+ panic(err)
+ }
+}
diff --git a/vendor/github.com/lib/pq/ssl_go1.7.go b/vendor/github.com/lib/pq/ssl_go1.7.go
new file mode 100644
index 000000000..d7ba43b32
--- /dev/null
+++ b/vendor/github.com/lib/pq/ssl_go1.7.go
@@ -0,0 +1,14 @@
+// +build go1.7
+
+package pq
+
+import "crypto/tls"
+
+// Accept renegotiation requests initiated by the backend.
+//
+// Renegotiation was deprecated then removed from PostgreSQL 9.5, but
+// the default configuration of older versions has it enabled. Redshift
+// also initiates renegotiations and cannot be reconfigured.
+func sslRenegotiation(conf *tls.Config) {
+ conf.Renegotiation = tls.RenegotiateFreelyAsClient
+}
diff --git a/vendor/github.com/lib/pq/ssl_permissions.go b/vendor/github.com/lib/pq/ssl_permissions.go
new file mode 100644
index 000000000..33076a8da
--- /dev/null
+++ b/vendor/github.com/lib/pq/ssl_permissions.go
@@ -0,0 +1,16 @@
+// +build !windows
+
+package pq
+
+import "os"
+
+// sslCertificatePermissions checks the permissions on user-supplied certificate
+// files. The key file should have very little access.
+//
+// libpq does not check key file permissions on Windows.
+func sslCertificatePermissions(cert, key os.FileInfo) {
+ kmode := key.Mode()
+ if kmode != kmode&0600 {
+ panic(ErrSSLKeyHasWorldPermissions)
+ }
+}
diff --git a/vendor/github.com/lib/pq/ssl_renegotiation.go b/vendor/github.com/lib/pq/ssl_renegotiation.go
new file mode 100644
index 000000000..85ed5e437
--- /dev/null
+++ b/vendor/github.com/lib/pq/ssl_renegotiation.go
@@ -0,0 +1,8 @@
+// +build !go1.7
+
+package pq
+
+import "crypto/tls"
+
+// Renegotiation is not supported by crypto/tls until Go 1.7.
+func sslRenegotiation(*tls.Config) {}
diff --git a/vendor/github.com/lib/pq/ssl_windows.go b/vendor/github.com/lib/pq/ssl_windows.go
new file mode 100644
index 000000000..529daed22
--- /dev/null
+++ b/vendor/github.com/lib/pq/ssl_windows.go
@@ -0,0 +1,9 @@
+// +build windows
+
+package pq
+
+import "os"
+
+// sslCertificatePermissions checks the permissions on user-supplied certificate
+// files. In libpq, this is a no-op on Windows.
+func sslCertificatePermissions(cert, key os.FileInfo) {}
diff --git a/vendor/github.com/lib/pq/uuid.go b/vendor/github.com/lib/pq/uuid.go
new file mode 100644
index 000000000..9a1b9e074
--- /dev/null
+++ b/vendor/github.com/lib/pq/uuid.go
@@ -0,0 +1,23 @@
+package pq
+
+import (
+ "encoding/hex"
+ "fmt"
+)
+
+// decodeUUIDBinary interprets the binary format of a uuid, returning it in text format.
+func decodeUUIDBinary(src []byte) ([]byte, error) {
+ if len(src) != 16 {
+ return nil, fmt.Errorf("pq: unable to decode uuid; bad length: %d", len(src))
+ }
+
+ dst := make([]byte, 36)
+ dst[8], dst[13], dst[18], dst[23] = '-', '-', '-', '-'
+ hex.Encode(dst[0:], src[0:4])
+ hex.Encode(dst[9:], src[4:6])
+ hex.Encode(dst[14:], src[6:8])
+ hex.Encode(dst[19:], src[8:10])
+ hex.Encode(dst[24:], src[10:16])
+
+ return dst, nil
+}
diff --git a/vendor/github.com/lib/pq/uuid_test.go b/vendor/github.com/lib/pq/uuid_test.go
new file mode 100644
index 000000000..9df4a79b0
--- /dev/null
+++ b/vendor/github.com/lib/pq/uuid_test.go
@@ -0,0 +1,46 @@
+package pq
+
+import (
+ "reflect"
+ "strings"
+ "testing"
+)
+
+func TestDecodeUUIDBinaryError(t *testing.T) {
+ t.Parallel()
+ _, err := decodeUUIDBinary([]byte{0x12, 0x34})
+
+ if err == nil {
+ t.Fatal("Expected error, got none")
+ }
+ if !strings.HasPrefix(err.Error(), "pq:") {
+ t.Errorf("Expected error to start with %q, got %q", "pq:", err.Error())
+ }
+ if !strings.Contains(err.Error(), "bad length: 2") {
+ t.Errorf("Expected error to contain length, got %q", err.Error())
+ }
+}
+
+func BenchmarkDecodeUUIDBinary(b *testing.B) {
+ x := []byte{0x03, 0xa3, 0x52, 0x2f, 0x89, 0x28, 0x49, 0x87, 0x84, 0xd6, 0x93, 0x7b, 0x36, 0xec, 0x27, 0x6f}
+
+ for i := 0; i < b.N; i++ {
+ decodeUUIDBinary(x)
+ }
+}
+
+func TestDecodeUUIDBackend(t *testing.T) {
+ db := openTestConn(t)
+ defer db.Close()
+
+ var s string = "a0ecc91d-a13f-4fe4-9fce-7e09777cc70a"
+ var scanned interface{}
+
+ err := db.QueryRow(`SELECT $1::uuid`, s).Scan(&scanned)
+ if err != nil {
+ t.Fatalf("Expected no error, got %v", err)
+ }
+ if !reflect.DeepEqual(scanned, []byte(s)) {
+ t.Errorf("Expected []byte(%q), got %T(%q)", s, scanned, scanned)
+ }
+}