Przeglądaj źródła

Merge branch 'v4.4.x'

Torkel Ödegaard 8 lat temu
rodzic
commit
addeccb4f0

+ 3 - 1
conf/defaults.ini

@@ -76,8 +76,10 @@ password =
 # Example: mysql://user:secret@host:port/database
 url =
 
+# Max idle conn setting default is 2
+max_idle_conn = 2
+
 # Max conn setting default is 0 (mean not set)
-max_idle_conn =
 max_open_conn =
 
 # For "postgres", use either "disable", "require" or "verify-full"

+ 3 - 1
conf/sample.ini

@@ -85,8 +85,10 @@
 # For "sqlite3" only, path relative to data_path setting
 ;path = grafana.db
 
+# Max idle conn setting default is 2
+;max_idle_conn = 2
+
 # Max conn setting default is 0 (mean not set)
-;max_idle_conn =
 ;max_open_conn =
 
 

+ 1 - 0
docker/blocks/postgres/fig

@@ -6,3 +6,4 @@ postgrestest:
     POSTGRES_DATABASE: grafana
   ports:
     - "5432:5432"
+  command: postgres -c log_connections=on -c logging_collector=on -c log_destination=stderr -c log_directory=/var/log/postgresql

+ 0 - 4
vendor/github.com/lib/pq/.gitignore

@@ -1,4 +0,0 @@
-.db
-*.test
-*~
-*.swp

+ 0 - 61
vendor/github.com/lib/pq/.travis.yml

@@ -1,61 +0,0 @@
-language: go
-
-go:
-  - 1.1
-  - 1.2
-  - 1.3
-  - 1.4
-  - tip
-
-before_install:
-  - psql --version
-  - sudo /etc/init.d/postgresql stop
-  - sudo apt-get -y --purge remove postgresql libpq-dev libpq5 postgresql-client-common postgresql-common
-  - sudo rm -rf /var/lib/postgresql
-  - wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
-  - sudo sh -c "echo deb http://apt.postgresql.org/pub/repos/apt/ $(lsb_release -cs)-pgdg main $PGVERSION >> /etc/apt/sources.list.d/postgresql.list"
-  - sudo apt-get update -qq
-  - sudo apt-get -y -o Dpkg::Options::=--force-confdef -o Dpkg::Options::="--force-confnew" install postgresql-$PGVERSION postgresql-server-dev-$PGVERSION postgresql-contrib-$PGVERSION
-  - sudo chmod 777 /etc/postgresql/$PGVERSION/main/pg_hba.conf
-  - echo "local     all         postgres                          trust" > /etc/postgresql/$PGVERSION/main/pg_hba.conf
-  - echo "local     all         all                               trust" >> /etc/postgresql/$PGVERSION/main/pg_hba.conf
-  - echo "hostnossl all         pqgossltest 127.0.0.1/32          reject" >> /etc/postgresql/$PGVERSION/main/pg_hba.conf
-  - echo "hostnossl all         pqgosslcert 127.0.0.1/32          reject" >> /etc/postgresql/$PGVERSION/main/pg_hba.conf
-  - echo "hostssl   all         pqgossltest 127.0.0.1/32          trust"  >> /etc/postgresql/$PGVERSION/main/pg_hba.conf
-  - echo "hostssl   all         pqgosslcert 127.0.0.1/32          cert"  >> /etc/postgresql/$PGVERSION/main/pg_hba.conf
-  - echo "host      all         all         127.0.0.1/32          trust" >> /etc/postgresql/$PGVERSION/main/pg_hba.conf
-  - echo "hostnossl all         pqgossltest ::1/128               reject" >> /etc/postgresql/$PGVERSION/main/pg_hba.conf
-  - echo "hostnossl all         pqgosslcert ::1/128               reject" >> /etc/postgresql/$PGVERSION/main/pg_hba.conf
-  - echo "hostssl   all         pqgossltest ::1/128               trust" >> /etc/postgresql/$PGVERSION/main/pg_hba.conf
-  - echo "hostssl   all         pqgosslcert ::1/128               cert" >> /etc/postgresql/$PGVERSION/main/pg_hba.conf
-  - echo "host      all         all         ::1/128               trust" >> /etc/postgresql/$PGVERSION/main/pg_hba.conf
-  - sudo install -o postgres -g postgres -m 600 -t /var/lib/postgresql/$PGVERSION/main/ certs/server.key certs/server.crt certs/root.crt
-  - sudo bash -c "[[ '${PGVERSION}' < '9.2' ]] || (echo \"ssl_cert_file = 'server.crt'\" >> /etc/postgresql/$PGVERSION/main/postgresql.conf)"
-  - sudo bash -c "[[ '${PGVERSION}' < '9.2' ]] || (echo \"ssl_key_file = 'server.key'\" >> /etc/postgresql/$PGVERSION/main/postgresql.conf)"
-  - sudo bash -c "[[ '${PGVERSION}' < '9.2' ]] || (echo \"ssl_ca_file = 'root.crt'\" >> /etc/postgresql/$PGVERSION/main/postgresql.conf)"
-  - sudo sh -c "echo 127.0.0.1 postgres >> /etc/hosts"
-  - sudo ls -l /var/lib/postgresql/$PGVERSION/main/
-  - sudo cat /etc/postgresql/$PGVERSION/main/postgresql.conf
-  - sudo chmod 600 $PQSSLCERTTEST_PATH/postgresql.key
-  - sudo /etc/init.d/postgresql restart
-
-env:
-  global:
-    - PGUSER=postgres
-    - PQGOSSLTESTS=1
-    - PQSSLCERTTEST_PATH=$PWD/certs
-  matrix:
-    - PGVERSION=9.4
-    - PGVERSION=9.3
-    - PGVERSION=9.2
-    - PGVERSION=9.1
-    - PGVERSION=9.0
-    - PGVERSION=8.4
-
-script:
- - go test -v ./...
-
-before_script:
- - psql -c 'create database pqgotest' -U postgres
- - psql -c 'create user pqgossltest' -U postgres
- - psql -c 'create user pqgosslcert' -U postgres

+ 11 - 4
vendor/github.com/lib/pq/README.md

@@ -1,6 +1,6 @@
 # pq - A pure Go postgres driver for Go's database/sql package
 
-[![Build Status](https://travis-ci.org/lib/pq.png?branch=master)](https://travis-ci.org/lib/pq)
+[![Build Status](https://travis-ci.org/lib/pq.svg?branch=master)](https://travis-ci.org/lib/pq)
 
 ## Install
 
@@ -20,11 +20,11 @@ variables.
 
 Example:
 
-	PGHOST=/var/run/postgresql go test github.com/lib/pq
+	PGHOST=/run/postgresql go test github.com/lib/pq
 
 Optionally, a benchmark suite can be run as part of the tests:
 
-	PGHOST=/var/run/postgresql go test -bench .
+	PGHOST=/run/postgresql go test -bench .
 
 ## Features
 
@@ -38,6 +38,7 @@ Optionally, a benchmark suite can be run as part of the tests:
 * Many libpq compatible environment variables
 * Unix socket support
 * Notifications: `LISTEN`/`NOTIFY`
+* pgpass support
 
 ## Future / Things you can help with
 
@@ -57,13 +58,17 @@ code still exists in here.
 * Brad Fitzpatrick (bradfitz)
 * Charlie Melbye (cmelbye)
 * Chris Bandy (cbandy)
+* Chris Gilling (cgilling)
 * Chris Walsh (cwds)
 * Dan Sosedoff (sosedoff)
 * Daniel Farina (fdr)
 * Eric Chlebek (echlebek)
+* Eric Garrido (minusnine)
+* Eric Urban (hydrogen18)
 * Everyone at The Go Team
 * Evan Shaw (edsrzf)
 * Ewan Chou (coocood)
+* Fazal Majid (fazalmajid)
 * Federico Romero (federomero)
 * Fumin (fumin)
 * Gary Burd (garyburd)
@@ -80,7 +85,7 @@ code still exists in here.
 * Keith Rarick (kr)
 * Kir Shatrov (kirs)
 * Lann Martin (lann)
-* Maciek Sakrejda (deafbybeheading)
+* Maciek Sakrejda (uhoh-itsmaciek)
 * Marc Brinkmann (mbr)
 * Marko Tiikkaja (johto)
 * Matt Newberry (MattNewberry)
@@ -94,5 +99,7 @@ code still exists in here.
 * Ryan Smith (ryandotsmith)
 * Samuel Stauffer (samuel)
 * Timothée Peignier (cyberdelia)
+* Travis Cline (tmc)
 * TruongSinh Tran-Nguyen (truongsinh)
+* Yaismel Miranda (ympons)
 * notedit (notedit)

+ 756 - 0
vendor/github.com/lib/pq/array.go

@@ -0,0 +1,756 @@
+package pq
+
+import (
+	"bytes"
+	"database/sql"
+	"database/sql/driver"
+	"encoding/hex"
+	"fmt"
+	"reflect"
+	"strconv"
+	"strings"
+)
+
+var typeByteSlice = reflect.TypeOf([]byte{})
+var typeDriverValuer = reflect.TypeOf((*driver.Valuer)(nil)).Elem()
+var typeSqlScanner = reflect.TypeOf((*sql.Scanner)(nil)).Elem()
+
+// Array returns the optimal driver.Valuer and sql.Scanner for an array or
+// slice of any dimension.
+//
+// For example:
+//  db.Query(`SELECT * FROM t WHERE id = ANY($1)`, pq.Array([]int{235, 401}))
+//
+//  var x []sql.NullInt64
+//  db.QueryRow('SELECT ARRAY[235, 401]').Scan(pq.Array(&x))
+//
+// Scanning multi-dimensional arrays is not supported.  Arrays where the lower
+// bound is not one (such as `[0:0]={1}') are not supported.
+func Array(a interface{}) interface {
+	driver.Valuer
+	sql.Scanner
+} {
+	switch a := a.(type) {
+	case []bool:
+		return (*BoolArray)(&a)
+	case []float64:
+		return (*Float64Array)(&a)
+	case []int64:
+		return (*Int64Array)(&a)
+	case []string:
+		return (*StringArray)(&a)
+
+	case *[]bool:
+		return (*BoolArray)(a)
+	case *[]float64:
+		return (*Float64Array)(a)
+	case *[]int64:
+		return (*Int64Array)(a)
+	case *[]string:
+		return (*StringArray)(a)
+	}
+
+	return GenericArray{a}
+}
+
+// ArrayDelimiter may be optionally implemented by driver.Valuer or sql.Scanner
+// to override the array delimiter used by GenericArray.
+type ArrayDelimiter interface {
+	// ArrayDelimiter returns the delimiter character(s) for this element's type.
+	ArrayDelimiter() string
+}
+
+// BoolArray represents a one-dimensional array of the PostgreSQL boolean type.
+type BoolArray []bool
+
+// Scan implements the sql.Scanner interface.
+func (a *BoolArray) Scan(src interface{}) error {
+	switch src := src.(type) {
+	case []byte:
+		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)
+}
+
+func (a *BoolArray) scanBytes(src []byte) error {
+	elems, err := scanLinearArray(src, []byte{','}, "BoolArray")
+	if err != nil {
+		return err
+	}
+	if *a != nil && len(elems) == 0 {
+		*a = (*a)[:0]
+	} else {
+		b := make(BoolArray, len(elems))
+		for i, v := range elems {
+			if len(v) != 1 {
+				return fmt.Errorf("pq: could not parse boolean array index %d: invalid boolean %q", i, v)
+			}
+			switch v[0] {
+			case 't':
+				b[i] = true
+			case 'f':
+				b[i] = false
+			default:
+				return fmt.Errorf("pq: could not parse boolean array index %d: invalid boolean %q", i, v)
+			}
+		}
+		*a = b
+	}
+	return nil
+}
+
+// Value implements the driver.Valuer interface.
+func (a BoolArray) Value() (driver.Value, error) {
+	if a == nil {
+		return nil, nil
+	}
+
+	if n := len(a); n > 0 {
+		// There will be exactly two curly brackets, N bytes of values,
+		// and N-1 bytes of delimiters.
+		b := make([]byte, 1+2*n)
+
+		for i := 0; i < n; i++ {
+			b[2*i] = ','
+			if a[i] {
+				b[1+2*i] = 't'
+			} else {
+				b[1+2*i] = 'f'
+			}
+		}
+
+		b[0] = '{'
+		b[2*n] = '}'
+
+		return string(b), nil
+	}
+
+	return "{}", nil
+}
+
+// ByteaArray represents a one-dimensional array of the PostgreSQL bytea type.
+type ByteaArray [][]byte
+
+// Scan implements the sql.Scanner interface.
+func (a *ByteaArray) Scan(src interface{}) error {
+	switch src := src.(type) {
+	case []byte:
+		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)
+}
+
+func (a *ByteaArray) scanBytes(src []byte) error {
+	elems, err := scanLinearArray(src, []byte{','}, "ByteaArray")
+	if err != nil {
+		return err
+	}
+	if *a != nil && len(elems) == 0 {
+		*a = (*a)[:0]
+	} else {
+		b := make(ByteaArray, len(elems))
+		for i, v := range elems {
+			b[i], err = parseBytea(v)
+			if err != nil {
+				return fmt.Errorf("could not parse bytea array index %d: %s", i, err.Error())
+			}
+		}
+		*a = b
+	}
+	return nil
+}
+
+// Value implements the driver.Valuer interface. It uses the "hex" format which
+// is only supported on PostgreSQL 9.0 or newer.
+func (a ByteaArray) Value() (driver.Value, error) {
+	if a == nil {
+		return nil, nil
+	}
+
+	if n := len(a); n > 0 {
+		// There will be at least two curly brackets, 2*N bytes of quotes,
+		// 3*N bytes of hex formatting, and N-1 bytes of delimiters.
+		size := 1 + 6*n
+		for _, x := range a {
+			size += hex.EncodedLen(len(x))
+		}
+
+		b := make([]byte, size)
+
+		for i, s := 0, b; i < n; i++ {
+			o := copy(s, `,"\\x`)
+			o += hex.Encode(s[o:], a[i])
+			s[o] = '"'
+			s = s[o+1:]
+		}
+
+		b[0] = '{'
+		b[size-1] = '}'
+
+		return string(b), nil
+	}
+
+	return "{}", nil
+}
+
+// Float64Array represents a one-dimensional array of the PostgreSQL double
+// precision type.
+type Float64Array []float64
+
+// Scan implements the sql.Scanner interface.
+func (a *Float64Array) Scan(src interface{}) error {
+	switch src := src.(type) {
+	case []byte:
+		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)
+}
+
+func (a *Float64Array) scanBytes(src []byte) error {
+	elems, err := scanLinearArray(src, []byte{','}, "Float64Array")
+	if err != nil {
+		return err
+	}
+	if *a != nil && len(elems) == 0 {
+		*a = (*a)[:0]
+	} else {
+		b := make(Float64Array, len(elems))
+		for i, v := range elems {
+			if b[i], err = strconv.ParseFloat(string(v), 64); err != nil {
+				return fmt.Errorf("pq: parsing array element index %d: %v", i, err)
+			}
+		}
+		*a = b
+	}
+	return nil
+}
+
+// Value implements the driver.Valuer interface.
+func (a Float64Array) Value() (driver.Value, error) {
+	if a == nil {
+		return nil, nil
+	}
+
+	if n := len(a); n > 0 {
+		// There will be at least two curly brackets, N bytes of values,
+		// and N-1 bytes of delimiters.
+		b := make([]byte, 1, 1+2*n)
+		b[0] = '{'
+
+		b = strconv.AppendFloat(b, a[0], 'f', -1, 64)
+		for i := 1; i < n; i++ {
+			b = append(b, ',')
+			b = strconv.AppendFloat(b, a[i], 'f', -1, 64)
+		}
+
+		return string(append(b, '}')), nil
+	}
+
+	return "{}", nil
+}
+
+// GenericArray implements the driver.Valuer and sql.Scanner interfaces for
+// an array or slice of any dimension.
+type GenericArray struct{ A interface{} }
+
+func (GenericArray) evaluateDestination(rt reflect.Type) (reflect.Type, func([]byte, reflect.Value) error, string) {
+	var assign func([]byte, reflect.Value) error
+	var del = ","
+
+	// TODO calculate the assign function for other types
+	// TODO repeat this section on the element type of arrays or slices (multidimensional)
+	{
+		if reflect.PtrTo(rt).Implements(typeSqlScanner) {
+			// dest is always addressable because it is an element of a slice.
+			assign = func(src []byte, dest reflect.Value) (err error) {
+				ss := dest.Addr().Interface().(sql.Scanner)
+				if src == nil {
+					err = ss.Scan(nil)
+				} else {
+					err = ss.Scan(src)
+				}
+				return
+			}
+			goto FoundType
+		}
+
+		assign = func([]byte, reflect.Value) error {
+			return fmt.Errorf("pq: scanning to %s is not implemented; only sql.Scanner", rt)
+		}
+	}
+
+FoundType:
+
+	if ad, ok := reflect.Zero(rt).Interface().(ArrayDelimiter); ok {
+		del = ad.ArrayDelimiter()
+	}
+
+	return rt, assign, del
+}
+
+// Scan implements the sql.Scanner interface.
+func (a GenericArray) Scan(src interface{}) error {
+	dpv := reflect.ValueOf(a.A)
+	switch {
+	case dpv.Kind() != reflect.Ptr:
+		return fmt.Errorf("pq: destination %T is not a pointer to array or slice", a.A)
+	case dpv.IsNil():
+		return fmt.Errorf("pq: destination %T is nil", a.A)
+	}
+
+	dv := dpv.Elem()
+	switch dv.Kind() {
+	case reflect.Slice:
+	case reflect.Array:
+	default:
+		return fmt.Errorf("pq: destination %T is not a pointer to array or slice", a.A)
+	}
+
+	switch src := src.(type) {
+	case []byte:
+		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())
+}
+
+func (a GenericArray) scanBytes(src []byte, dv reflect.Value) error {
+	dtype, assign, del := a.evaluateDestination(dv.Type().Elem())
+	dims, elems, err := parseArray(src, []byte(del))
+	if err != nil {
+		return err
+	}
+
+	// TODO allow multidimensional
+
+	if len(dims) > 1 {
+		return fmt.Errorf("pq: scanning from multidimensional ARRAY%s is not implemented",
+			strings.Replace(fmt.Sprint(dims), " ", "][", -1))
+	}
+
+	// Treat a zero-dimensional array like an array with a single dimension of zero.
+	if len(dims) == 0 {
+		dims = append(dims, 0)
+	}
+
+	for i, rt := 0, dv.Type(); i < len(dims); i, rt = i+1, rt.Elem() {
+		switch rt.Kind() {
+		case reflect.Slice:
+		case reflect.Array:
+			if rt.Len() != dims[i] {
+				return fmt.Errorf("pq: cannot convert ARRAY%s to %s",
+					strings.Replace(fmt.Sprint(dims), " ", "][", -1), dv.Type())
+			}
+		default:
+			// TODO handle multidimensional
+		}
+	}
+
+	values := reflect.MakeSlice(reflect.SliceOf(dtype), len(elems), len(elems))
+	for i, e := range elems {
+		if err := assign(e, values.Index(i)); err != nil {
+			return fmt.Errorf("pq: parsing array element index %d: %v", i, err)
+		}
+	}
+
+	// TODO handle multidimensional
+
+	switch dv.Kind() {
+	case reflect.Slice:
+		dv.Set(values.Slice(0, dims[0]))
+	case reflect.Array:
+		for i := 0; i < dims[0]; i++ {
+			dv.Index(i).Set(values.Index(i))
+		}
+	}
+
+	return nil
+}
+
+// Value implements the driver.Valuer interface.
+func (a GenericArray) Value() (driver.Value, error) {
+	if a.A == nil {
+		return nil, nil
+	}
+
+	rv := reflect.ValueOf(a.A)
+
+	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)
+	}
+
+	if n := rv.Len(); n > 0 {
+		// There will be at least two curly brackets, N bytes of values,
+		// and N-1 bytes of delimiters.
+		b := make([]byte, 0, 1+2*n)
+
+		b, _, err := appendArray(b, rv, n)
+		return string(b), err
+	}
+
+	return "{}", nil
+}
+
+// Int64Array represents a one-dimensional array of the PostgreSQL integer types.
+type Int64Array []int64
+
+// Scan implements the sql.Scanner interface.
+func (a *Int64Array) Scan(src interface{}) error {
+	switch src := src.(type) {
+	case []byte:
+		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)
+}
+
+func (a *Int64Array) scanBytes(src []byte) error {
+	elems, err := scanLinearArray(src, []byte{','}, "Int64Array")
+	if err != nil {
+		return err
+	}
+	if *a != nil && len(elems) == 0 {
+		*a = (*a)[:0]
+	} else {
+		b := make(Int64Array, len(elems))
+		for i, v := range elems {
+			if b[i], err = strconv.ParseInt(string(v), 10, 64); err != nil {
+				return fmt.Errorf("pq: parsing array element index %d: %v", i, err)
+			}
+		}
+		*a = b
+	}
+	return nil
+}
+
+// Value implements the driver.Valuer interface.
+func (a Int64Array) Value() (driver.Value, error) {
+	if a == nil {
+		return nil, nil
+	}
+
+	if n := len(a); n > 0 {
+		// There will be at least two curly brackets, N bytes of values,
+		// and N-1 bytes of delimiters.
+		b := make([]byte, 1, 1+2*n)
+		b[0] = '{'
+
+		b = strconv.AppendInt(b, a[0], 10)
+		for i := 1; i < n; i++ {
+			b = append(b, ',')
+			b = strconv.AppendInt(b, a[i], 10)
+		}
+
+		return string(append(b, '}')), nil
+	}
+
+	return "{}", nil
+}
+
+// StringArray represents a one-dimensional array of the PostgreSQL character types.
+type StringArray []string
+
+// Scan implements the sql.Scanner interface.
+func (a *StringArray) Scan(src interface{}) error {
+	switch src := src.(type) {
+	case []byte:
+		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)
+}
+
+func (a *StringArray) scanBytes(src []byte) error {
+	elems, err := scanLinearArray(src, []byte{','}, "StringArray")
+	if err != nil {
+		return err
+	}
+	if *a != nil && len(elems) == 0 {
+		*a = (*a)[:0]
+	} else {
+		b := make(StringArray, len(elems))
+		for i, v := range elems {
+			if b[i] = string(v); v == nil {
+				return fmt.Errorf("pq: parsing array element index %d: cannot convert nil to string", i)
+			}
+		}
+		*a = b
+	}
+	return nil
+}
+
+// Value implements the driver.Valuer interface.
+func (a StringArray) Value() (driver.Value, error) {
+	if a == nil {
+		return nil, nil
+	}
+
+	if n := len(a); n > 0 {
+		// There will be at least two curly brackets, 2*N bytes of quotes,
+		// and N-1 bytes of delimiters.
+		b := make([]byte, 1, 1+3*n)
+		b[0] = '{'
+
+		b = appendArrayQuotedBytes(b, []byte(a[0]))
+		for i := 1; i < n; i++ {
+			b = append(b, ',')
+			b = appendArrayQuotedBytes(b, []byte(a[i]))
+		}
+
+		return string(append(b, '}')), nil
+	}
+
+	return "{}", nil
+}
+
+// appendArray appends rv to the buffer, returning the extended buffer and
+// the delimiter used between elements.
+//
+// It panics when n <= 0 or rv's Kind is not reflect.Array nor reflect.Slice.
+func appendArray(b []byte, rv reflect.Value, n int) ([]byte, string, error) {
+	var del string
+	var err error
+
+	b = append(b, '{')
+
+	if b, del, err = appendArrayElement(b, rv.Index(0)); err != nil {
+		return b, del, err
+	}
+
+	for i := 1; i < n; i++ {
+		b = append(b, del...)
+		if b, del, err = appendArrayElement(b, rv.Index(i)); err != nil {
+			return b, del, err
+		}
+	}
+
+	return append(b, '}'), del, nil
+}
+
+// appendArrayElement appends rv to the buffer, returning the extended buffer
+// and the delimiter to use before the next element.
+//
+// When rv's Kind is neither reflect.Array nor reflect.Slice, it is converted
+// using driver.DefaultParameterConverter and the resulting []byte or string
+// is double-quoted.
+//
+// See http://www.postgresql.org/docs/current/static/arrays.html#ARRAYS-IO
+func appendArrayElement(b []byte, rv reflect.Value) ([]byte, string, error) {
+	if k := rv.Kind(); k == reflect.Array || k == reflect.Slice {
+		if t := rv.Type(); t != typeByteSlice && !t.Implements(typeDriverValuer) {
+			if n := rv.Len(); n > 0 {
+				return appendArray(b, rv, n)
+			}
+
+			return b, "", nil
+		}
+	}
+
+	var del string = ","
+	var err error
+	var iv interface{} = rv.Interface()
+
+	if ad, ok := iv.(ArrayDelimiter); ok {
+		del = ad.ArrayDelimiter()
+	}
+
+	if iv, err = driver.DefaultParameterConverter.ConvertValue(iv); err != nil {
+		return b, del, err
+	}
+
+	switch v := iv.(type) {
+	case nil:
+		return append(b, "NULL"...), del, nil
+	case []byte:
+		return appendArrayQuotedBytes(b, v), del, nil
+	case string:
+		return appendArrayQuotedBytes(b, []byte(v)), del, nil
+	}
+
+	b, err = appendValue(b, iv)
+	return b, del, err
+}
+
+func appendArrayQuotedBytes(b, v []byte) []byte {
+	b = append(b, '"')
+	for {
+		i := bytes.IndexAny(v, `"\`)
+		if i < 0 {
+			b = append(b, v...)
+			break
+		}
+		if i > 0 {
+			b = append(b, v[:i]...)
+		}
+		b = append(b, '\\', v[i])
+		v = v[i+1:]
+	}
+	return append(b, '"')
+}
+
+func appendValue(b []byte, v driver.Value) ([]byte, error) {
+	return append(b, encode(nil, v, 0)...), nil
+}
+
+// parseArray extracts the dimensions and elements of an array represented in
+// text format. Only representations emitted by the backend are supported.
+// Notably, whitespace around brackets and delimiters is significant, and NULL
+// is case-sensitive.
+//
+// See http://www.postgresql.org/docs/current/static/arrays.html#ARRAYS-IO
+func parseArray(src, del []byte) (dims []int, elems [][]byte, err error) {
+	var depth, i int
+
+	if len(src) < 1 || src[0] != '{' {
+		return nil, nil, fmt.Errorf("pq: unable to parse array; expected %q at offset %d", '{', 0)
+	}
+
+Open:
+	for i < len(src) {
+		switch src[i] {
+		case '{':
+			depth++
+			i++
+		case '}':
+			elems = make([][]byte, 0)
+			goto Close
+		default:
+			break Open
+		}
+	}
+	dims = make([]int, i)
+
+Element:
+	for i < len(src) {
+		switch src[i] {
+		case '{':
+			if depth == len(dims) {
+				break Element
+			}
+			depth++
+			dims[depth-1] = 0
+			i++
+		case '"':
+			var elem = []byte{}
+			var escape bool
+			for i++; i < len(src); i++ {
+				if escape {
+					elem = append(elem, src[i])
+					escape = false
+				} else {
+					switch src[i] {
+					default:
+						elem = append(elem, src[i])
+					case '\\':
+						escape = true
+					case '"':
+						elems = append(elems, elem)
+						i++
+						break Element
+					}
+				}
+			}
+		default:
+			for start := i; i < len(src); i++ {
+				if bytes.HasPrefix(src[i:], del) || src[i] == '}' {
+					elem := src[start:i]
+					if len(elem) == 0 {
+						return nil, nil, fmt.Errorf("pq: unable to parse array; unexpected %q at offset %d", src[i], i)
+					}
+					if bytes.Equal(elem, []byte("NULL")) {
+						elem = nil
+					}
+					elems = append(elems, elem)
+					break Element
+				}
+			}
+		}
+	}
+
+	for i < len(src) {
+		if bytes.HasPrefix(src[i:], del) && depth > 0 {
+			dims[depth-1]++
+			i += len(del)
+			goto Element
+		} else if src[i] == '}' && depth > 0 {
+			dims[depth-1]++
+			depth--
+			i++
+		} else {
+			return nil, nil, fmt.Errorf("pq: unable to parse array; unexpected %q at offset %d", src[i], i)
+		}
+	}
+
+Close:
+	for i < len(src) {
+		if src[i] == '}' && depth > 0 {
+			depth--
+			i++
+		} else {
+			return nil, nil, fmt.Errorf("pq: unable to parse array; unexpected %q at offset %d", src[i], i)
+		}
+	}
+	if depth > 0 {
+		err = fmt.Errorf("pq: unable to parse array; expected %q at offset %d", '}', i)
+	}
+	if err == nil {
+		for _, d := range dims {
+			if (len(elems) % d) != 0 {
+				err = fmt.Errorf("pq: multidimensional arrays must have elements with matching dimensions")
+			}
+		}
+	}
+	return
+}
+
+func scanLinearArray(src, del []byte, typ string) (elems [][]byte, err error) {
+	dims, elems, err := parseArray(src, del)
+	if err != nil {
+		return nil, err
+	}
+	if len(dims) > 1 {
+		return nil, fmt.Errorf("pq: cannot convert ARRAY%s to %s", strings.Replace(fmt.Sprint(dims), " ", "][", -1), typ)
+	}
+	return elems, err
+}

+ 0 - 434
vendor/github.com/lib/pq/bench_test.go

@@ -1,434 +0,0 @@
-// +build go1.1
-
-package pq
-
-import (
-	"bufio"
-	"bytes"
-	"database/sql"
-	"database/sql/driver"
-	"github.com/lib/pq/oid"
-	"io"
-	"math/rand"
-	"net"
-	"runtime"
-	"strconv"
-	"strings"
-	"sync"
-	"testing"
-	"time"
-)
-
-var (
-	selectStringQuery = "SELECT '" + strings.Repeat("0123456789", 10) + "'"
-	selectSeriesQuery = "SELECT generate_series(1, 100)"
-)
-
-func BenchmarkSelectString(b *testing.B) {
-	var result string
-	benchQuery(b, selectStringQuery, &result)
-}
-
-func BenchmarkSelectSeries(b *testing.B) {
-	var result int
-	benchQuery(b, selectSeriesQuery, &result)
-}
-
-func benchQuery(b *testing.B, query string, result interface{}) {
-	b.StopTimer()
-	db := openTestConn(b)
-	defer db.Close()
-	b.StartTimer()
-
-	for i := 0; i < b.N; i++ {
-		benchQueryLoop(b, db, query, result)
-	}
-}
-
-func benchQueryLoop(b *testing.B, db *sql.DB, query string, result interface{}) {
-	rows, err := db.Query(query)
-	if err != nil {
-		b.Fatal(err)
-	}
-	defer rows.Close()
-	for rows.Next() {
-		err = rows.Scan(result)
-		if err != nil {
-			b.Fatal("failed to scan", err)
-		}
-	}
-}
-
-// reading from circularConn yields content[:prefixLen] once, followed by
-// content[prefixLen:] over and over again. It never returns EOF.
-type circularConn struct {
-	content   string
-	prefixLen int
-	pos       int
-	net.Conn  // for all other net.Conn methods that will never be called
-}
-
-func (r *circularConn) Read(b []byte) (n int, err error) {
-	n = copy(b, r.content[r.pos:])
-	r.pos += n
-	if r.pos >= len(r.content) {
-		r.pos = r.prefixLen
-	}
-	return
-}
-
-func (r *circularConn) Write(b []byte) (n int, err error) { return len(b), nil }
-
-func (r *circularConn) Close() error { return nil }
-
-func fakeConn(content string, prefixLen int) *conn {
-	c := &circularConn{content: content, prefixLen: prefixLen}
-	return &conn{buf: bufio.NewReader(c), c: c}
-}
-
-// This benchmark is meant to be the same as BenchmarkSelectString, but takes
-// out some of the factors this package can't control. The numbers are less noisy,
-// but also the costs of network communication aren't accurately represented.
-func BenchmarkMockSelectString(b *testing.B) {
-	b.StopTimer()
-	// taken from a recorded run of BenchmarkSelectString
-	// See: http://www.postgresql.org/docs/current/static/protocol-message-formats.html
-	const response = "1\x00\x00\x00\x04" +
-		"t\x00\x00\x00\x06\x00\x00" +
-		"T\x00\x00\x00!\x00\x01?column?\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\xc1\xff\xfe\xff\xff\xff\xff\x00\x00" +
-		"Z\x00\x00\x00\x05I" +
-		"2\x00\x00\x00\x04" +
-		"D\x00\x00\x00n\x00\x01\x00\x00\x00d0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" +
-		"C\x00\x00\x00\rSELECT 1\x00" +
-		"Z\x00\x00\x00\x05I" +
-		"3\x00\x00\x00\x04" +
-		"Z\x00\x00\x00\x05I"
-	c := fakeConn(response, 0)
-	b.StartTimer()
-
-	for i := 0; i < b.N; i++ {
-		benchMockQuery(b, c, selectStringQuery)
-	}
-}
-
-var seriesRowData = func() string {
-	var buf bytes.Buffer
-	for i := 1; i <= 100; i++ {
-		digits := byte(2)
-		if i >= 100 {
-			digits = 3
-		} else if i < 10 {
-			digits = 1
-		}
-		buf.WriteString("D\x00\x00\x00")
-		buf.WriteByte(10 + digits)
-		buf.WriteString("\x00\x01\x00\x00\x00")
-		buf.WriteByte(digits)
-		buf.WriteString(strconv.Itoa(i))
-	}
-	return buf.String()
-}()
-
-func BenchmarkMockSelectSeries(b *testing.B) {
-	b.StopTimer()
-	var response = "1\x00\x00\x00\x04" +
-		"t\x00\x00\x00\x06\x00\x00" +
-		"T\x00\x00\x00!\x00\x01?column?\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\xc1\xff\xfe\xff\xff\xff\xff\x00\x00" +
-		"Z\x00\x00\x00\x05I" +
-		"2\x00\x00\x00\x04" +
-		seriesRowData +
-		"C\x00\x00\x00\x0fSELECT 100\x00" +
-		"Z\x00\x00\x00\x05I" +
-		"3\x00\x00\x00\x04" +
-		"Z\x00\x00\x00\x05I"
-	c := fakeConn(response, 0)
-	b.StartTimer()
-
-	for i := 0; i < b.N; i++ {
-		benchMockQuery(b, c, selectSeriesQuery)
-	}
-}
-
-func benchMockQuery(b *testing.B, c *conn, query string) {
-	stmt, err := c.Prepare(query)
-	if err != nil {
-		b.Fatal(err)
-	}
-	defer stmt.Close()
-	rows, err := stmt.Query(nil)
-	if err != nil {
-		b.Fatal(err)
-	}
-	defer rows.Close()
-	var dest [1]driver.Value
-	for {
-		if err := rows.Next(dest[:]); err != nil {
-			if err == io.EOF {
-				break
-			}
-			b.Fatal(err)
-		}
-	}
-}
-
-func BenchmarkPreparedSelectString(b *testing.B) {
-	var result string
-	benchPreparedQuery(b, selectStringQuery, &result)
-}
-
-func BenchmarkPreparedSelectSeries(b *testing.B) {
-	var result int
-	benchPreparedQuery(b, selectSeriesQuery, &result)
-}
-
-func benchPreparedQuery(b *testing.B, query string, result interface{}) {
-	b.StopTimer()
-	db := openTestConn(b)
-	defer db.Close()
-	stmt, err := db.Prepare(query)
-	if err != nil {
-		b.Fatal(err)
-	}
-	defer stmt.Close()
-	b.StartTimer()
-
-	for i := 0; i < b.N; i++ {
-		benchPreparedQueryLoop(b, db, stmt, result)
-	}
-}
-
-func benchPreparedQueryLoop(b *testing.B, db *sql.DB, stmt *sql.Stmt, result interface{}) {
-	rows, err := stmt.Query()
-	if err != nil {
-		b.Fatal(err)
-	}
-	if !rows.Next() {
-		rows.Close()
-		b.Fatal("no rows")
-	}
-	defer rows.Close()
-	for rows.Next() {
-		err = rows.Scan(&result)
-		if err != nil {
-			b.Fatal("failed to scan")
-		}
-	}
-}
-
-// See the comment for BenchmarkMockSelectString.
-func BenchmarkMockPreparedSelectString(b *testing.B) {
-	b.StopTimer()
-	const parseResponse = "1\x00\x00\x00\x04" +
-		"t\x00\x00\x00\x06\x00\x00" +
-		"T\x00\x00\x00!\x00\x01?column?\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\xc1\xff\xfe\xff\xff\xff\xff\x00\x00" +
-		"Z\x00\x00\x00\x05I"
-	const responses = parseResponse +
-		"2\x00\x00\x00\x04" +
-		"D\x00\x00\x00n\x00\x01\x00\x00\x00d0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" +
-		"C\x00\x00\x00\rSELECT 1\x00" +
-		"Z\x00\x00\x00\x05I"
-	c := fakeConn(responses, len(parseResponse))
-
-	stmt, err := c.Prepare(selectStringQuery)
-	if err != nil {
-		b.Fatal(err)
-	}
-	b.StartTimer()
-
-	for i := 0; i < b.N; i++ {
-		benchPreparedMockQuery(b, c, stmt)
-	}
-}
-
-func BenchmarkMockPreparedSelectSeries(b *testing.B) {
-	b.StopTimer()
-	const parseResponse = "1\x00\x00\x00\x04" +
-		"t\x00\x00\x00\x06\x00\x00" +
-		"T\x00\x00\x00!\x00\x01?column?\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\xc1\xff\xfe\xff\xff\xff\xff\x00\x00" +
-		"Z\x00\x00\x00\x05I"
-	var responses = parseResponse +
-		"2\x00\x00\x00\x04" +
-		seriesRowData +
-		"C\x00\x00\x00\x0fSELECT 100\x00" +
-		"Z\x00\x00\x00\x05I"
-	c := fakeConn(responses, len(parseResponse))
-
-	stmt, err := c.Prepare(selectSeriesQuery)
-	if err != nil {
-		b.Fatal(err)
-	}
-	b.StartTimer()
-
-	for i := 0; i < b.N; i++ {
-		benchPreparedMockQuery(b, c, stmt)
-	}
-}
-
-func benchPreparedMockQuery(b *testing.B, c *conn, stmt driver.Stmt) {
-	rows, err := stmt.Query(nil)
-	if err != nil {
-		b.Fatal(err)
-	}
-	defer rows.Close()
-	var dest [1]driver.Value
-	for {
-		if err := rows.Next(dest[:]); err != nil {
-			if err == io.EOF {
-				break
-			}
-			b.Fatal(err)
-		}
-	}
-}
-
-func BenchmarkEncodeInt64(b *testing.B) {
-	for i := 0; i < b.N; i++ {
-		encode(&parameterStatus{}, int64(1234), oid.T_int8)
-	}
-}
-
-func BenchmarkEncodeFloat64(b *testing.B) {
-	for i := 0; i < b.N; i++ {
-		encode(&parameterStatus{}, 3.14159, oid.T_float8)
-	}
-}
-
-var testByteString = []byte("abcdefghijklmnopqrstuvwxyz")
-
-func BenchmarkEncodeByteaHex(b *testing.B) {
-	for i := 0; i < b.N; i++ {
-		encode(&parameterStatus{serverVersion: 90000}, testByteString, oid.T_bytea)
-	}
-}
-func BenchmarkEncodeByteaEscape(b *testing.B) {
-	for i := 0; i < b.N; i++ {
-		encode(&parameterStatus{serverVersion: 84000}, testByteString, oid.T_bytea)
-	}
-}
-
-func BenchmarkEncodeBool(b *testing.B) {
-	for i := 0; i < b.N; i++ {
-		encode(&parameterStatus{}, true, oid.T_bool)
-	}
-}
-
-var testTimestamptz = time.Date(2001, time.January, 1, 0, 0, 0, 0, time.Local)
-
-func BenchmarkEncodeTimestamptz(b *testing.B) {
-	for i := 0; i < b.N; i++ {
-		encode(&parameterStatus{}, testTimestamptz, oid.T_timestamptz)
-	}
-}
-
-var testIntBytes = []byte("1234")
-
-func BenchmarkDecodeInt64(b *testing.B) {
-	for i := 0; i < b.N; i++ {
-		decode(&parameterStatus{}, testIntBytes, oid.T_int8)
-	}
-}
-
-var testFloatBytes = []byte("3.14159")
-
-func BenchmarkDecodeFloat64(b *testing.B) {
-	for i := 0; i < b.N; i++ {
-		decode(&parameterStatus{}, testFloatBytes, oid.T_float8)
-	}
-}
-
-var testBoolBytes = []byte{'t'}
-
-func BenchmarkDecodeBool(b *testing.B) {
-	for i := 0; i < b.N; i++ {
-		decode(&parameterStatus{}, testBoolBytes, oid.T_bool)
-	}
-}
-
-func TestDecodeBool(t *testing.T) {
-	db := openTestConn(t)
-	rows, err := db.Query("select true")
-	if err != nil {
-		t.Fatal(err)
-	}
-	rows.Close()
-}
-
-var testTimestamptzBytes = []byte("2013-09-17 22:15:32.360754-07")
-
-func BenchmarkDecodeTimestamptz(b *testing.B) {
-	for i := 0; i < b.N; i++ {
-		decode(&parameterStatus{}, testTimestamptzBytes, oid.T_timestamptz)
-	}
-}
-
-func BenchmarkDecodeTimestamptzMultiThread(b *testing.B) {
-	oldProcs := runtime.GOMAXPROCS(0)
-	defer runtime.GOMAXPROCS(oldProcs)
-	runtime.GOMAXPROCS(runtime.NumCPU())
-	globalLocationCache = newLocationCache()
-
-	f := func(wg *sync.WaitGroup, loops int) {
-		defer wg.Done()
-		for i := 0; i < loops; i++ {
-			decode(&parameterStatus{}, testTimestamptzBytes, oid.T_timestamptz)
-		}
-	}
-
-	wg := &sync.WaitGroup{}
-	b.ResetTimer()
-	for j := 0; j < 10; j++ {
-		wg.Add(1)
-		go f(wg, b.N/10)
-	}
-	wg.Wait()
-}
-
-func BenchmarkLocationCache(b *testing.B) {
-	globalLocationCache = newLocationCache()
-	for i := 0; i < b.N; i++ {
-		globalLocationCache.getLocation(rand.Intn(10000))
-	}
-}
-
-func BenchmarkLocationCacheMultiThread(b *testing.B) {
-	oldProcs := runtime.GOMAXPROCS(0)
-	defer runtime.GOMAXPROCS(oldProcs)
-	runtime.GOMAXPROCS(runtime.NumCPU())
-	globalLocationCache = newLocationCache()
-
-	f := func(wg *sync.WaitGroup, loops int) {
-		defer wg.Done()
-		for i := 0; i < loops; i++ {
-			globalLocationCache.getLocation(rand.Intn(10000))
-		}
-	}
-
-	wg := &sync.WaitGroup{}
-	b.ResetTimer()
-	for j := 0; j < 10; j++ {
-		wg.Add(1)
-		go f(wg, b.N/10)
-	}
-	wg.Wait()
-}
-
-// Stress test the performance of parsing results from the wire.
-func BenchmarkResultParsing(b *testing.B) {
-	b.StopTimer()
-
-	db := openTestConn(b)
-	defer db.Close()
-	_, err := db.Exec("BEGIN")
-	if err != nil {
-		b.Fatal(err)
-	}
-
-	b.StartTimer()
-	for i := 0; i < b.N; i++ {
-		res, err := db.Query("SELECT generate_series(1, 50000)")
-		if err != nil {
-			b.Fatal(err)
-		}
-		res.Close()
-	}
-}

+ 24 - 6
vendor/github.com/lib/pq/buf.go

@@ -3,6 +3,7 @@ package pq
 import (
 	"bytes"
 	"encoding/binary"
+
 	"github.com/lib/pq/oid"
 )
 
@@ -20,6 +21,7 @@ func (b *readBuf) oid() (n oid.Oid) {
 	return
 }
 
+// N.B: this is actually an unsigned 16-bit integer, unlike int32
 func (b *readBuf) int16() (n int) {
 	n = int(binary.BigEndian.Uint16(*b))
 	*b = (*b)[2:]
@@ -46,28 +48,44 @@ func (b *readBuf) byte() byte {
 	return b.next(1)[0]
 }
 
-type writeBuf []byte
+type writeBuf struct {
+	buf []byte
+	pos int
+}
 
 func (b *writeBuf) int32(n int) {
 	x := make([]byte, 4)
 	binary.BigEndian.PutUint32(x, uint32(n))
-	*b = append(*b, x...)
+	b.buf = append(b.buf, x...)
 }
 
 func (b *writeBuf) int16(n int) {
 	x := make([]byte, 2)
 	binary.BigEndian.PutUint16(x, uint16(n))
-	*b = append(*b, x...)
+	b.buf = append(b.buf, x...)
 }
 
 func (b *writeBuf) string(s string) {
-	*b = append(*b, (s + "\000")...)
+	b.buf = append(b.buf, (s + "\000")...)
 }
 
 func (b *writeBuf) byte(c byte) {
-	*b = append(*b, c)
+	b.buf = append(b.buf, c)
 }
 
 func (b *writeBuf) bytes(v []byte) {
-	*b = append(*b, v...)
+	b.buf = append(b.buf, v...)
+}
+
+func (b *writeBuf) wrap() []byte {
+	p := b.buf[b.pos:]
+	binary.BigEndian.PutUint32(p, uint32(len(p)))
+	return b.buf
+}
+
+func (b *writeBuf) next(c byte) {
+	p := b.buf[b.pos:]
+	binary.BigEndian.PutUint32(p, uint32(len(p)))
+	b.pos = len(b.buf) + 1
+	b.buf = append(b.buf, c, 0, 0, 0, 0)
 }

Plik diff jest za duży
+ 393 - 277
vendor/github.com/lib/pq/conn.go


+ 128 - 0
vendor/github.com/lib/pq/conn_go18.go

@@ -0,0 +1,128 @@
+// +build go1.8
+
+package pq
+
+import (
+	"context"
+	"database/sql"
+	"database/sql/driver"
+	"fmt"
+	"io"
+	"io/ioutil"
+)
+
+// 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
+	}
+	finish := cn.watchCancel(ctx)
+	r, err := cn.query(query, list)
+	if err != nil {
+		if finish != nil {
+			finish()
+		}
+		return nil, err
+	}
+	r.finish = finish
+	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 finish := cn.watchCancel(ctx); finish != nil {
+		defer finish()
+	}
+
+	return cn.Exec(query, list)
+}
+
+// Implement the "ConnBeginTx" interface
+func (cn *conn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) {
+	var mode string
+
+	switch sql.IsolationLevel(opts.Isolation) {
+	case sql.LevelDefault:
+		// Don't touch mode: use the server's default
+	case sql.LevelReadUncommitted:
+		mode = " ISOLATION LEVEL READ UNCOMMITTED"
+	case sql.LevelReadCommitted:
+		mode = " ISOLATION LEVEL READ COMMITTED"
+	case sql.LevelRepeatableRead:
+		mode = " ISOLATION LEVEL REPEATABLE READ"
+	case sql.LevelSerializable:
+		mode = " ISOLATION LEVEL SERIALIZABLE"
+	default:
+		return nil, fmt.Errorf("pq: isolation level not supported: %d", opts.Isolation)
+	}
+
+	if opts.ReadOnly {
+		mode += " READ ONLY"
+	} else {
+		mode += " READ WRITE"
+	}
+
+	tx, err := cn.begin(mode)
+	if err != nil {
+		return nil, err
+	}
+	cn.txnFinish = cn.watchCancel(ctx)
+	return tx, nil
+}
+
+func (cn *conn) watchCancel(ctx context.Context) func() {
+	if done := ctx.Done(); done != nil {
+		finished := make(chan struct{})
+		go func() {
+			select {
+			case <-done:
+				_ = cn.cancel()
+				finished <- struct{}{}
+			case <-finished:
+			}
+		}()
+		return func() {
+			select {
+			case <-finished:
+			case finished <- struct{}{}:
+			}
+		}
+	}
+	return nil
+}
+
+func (cn *conn) cancel() error {
+	c, err := dial(cn.dialer, cn.opts)
+	if err != nil {
+		return err
+	}
+	defer c.Close()
+
+	{
+		can := conn{
+			c: c,
+		}
+		can.ssl(cn.opts)
+
+		w := can.writeBuf(0)
+		w.int32(80877102) // cancel request code
+		w.int32(cn.processID)
+		w.int32(cn.secretKey)
+
+		if err := can.sendStartupPacket(w); err != nil {
+			return err
+		}
+	}
+
+	// Read until EOF to ensure that the server received the cancel.
+	{
+		_, err := io.Copy(ioutil.Discard, c)
+		return err
+	}
+}

+ 0 - 1286
vendor/github.com/lib/pq/conn_test.go

@@ -1,1286 +0,0 @@
-package pq
-
-import (
-	"database/sql"
-	"database/sql/driver"
-	"fmt"
-	"io"
-	"os"
-	"reflect"
-	"testing"
-	"time"
-)
-
-type Fatalistic interface {
-	Fatal(args ...interface{})
-}
-
-func openTestConnConninfo(conninfo string) (*sql.DB, error) {
-	datname := os.Getenv("PGDATABASE")
-	sslmode := os.Getenv("PGSSLMODE")
-	timeout := os.Getenv("PGCONNECT_TIMEOUT")
-
-	if datname == "" {
-		os.Setenv("PGDATABASE", "pqgotest")
-	}
-
-	if sslmode == "" {
-		os.Setenv("PGSSLMODE", "disable")
-	}
-
-	if timeout == "" {
-		os.Setenv("PGCONNECT_TIMEOUT", "20")
-	}
-
-	return sql.Open("postgres", conninfo)
-}
-
-func openTestConn(t Fatalistic) *sql.DB {
-	conn, err := openTestConnConninfo("")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	return conn
-}
-
-func getServerVersion(t *testing.T, db *sql.DB) int {
-	var version int
-	err := db.QueryRow("SHOW server_version_num").Scan(&version)
-	if err != nil {
-		t.Fatal(err)
-	}
-	return version
-}
-
-func TestReconnect(t *testing.T) {
-	db1 := openTestConn(t)
-	defer db1.Close()
-	tx, err := db1.Begin()
-	if err != nil {
-		t.Fatal(err)
-	}
-	var pid1 int
-	err = tx.QueryRow("SELECT pg_backend_pid()").Scan(&pid1)
-	if err != nil {
-		t.Fatal(err)
-	}
-	db2 := openTestConn(t)
-	defer db2.Close()
-	_, err = db2.Exec("SELECT pg_terminate_backend($1)", pid1)
-	if err != nil {
-		t.Fatal(err)
-	}
-	// The rollback will probably "fail" because we just killed
-	// its connection above
-	_ = tx.Rollback()
-
-	const expected int = 42
-	var result int
-	err = db1.QueryRow(fmt.Sprintf("SELECT %d", expected)).Scan(&result)
-	if err != nil {
-		t.Fatal(err)
-	}
-	if result != expected {
-		t.Errorf("got %v; expected %v", result, expected)
-	}
-}
-
-func TestCommitInFailedTransaction(t *testing.T) {
-	db := openTestConn(t)
-	defer db.Close()
-
-	txn, err := db.Begin()
-	if err != nil {
-		t.Fatal(err)
-	}
-	rows, err := txn.Query("SELECT error")
-	if err == nil {
-		rows.Close()
-		t.Fatal("expected failure")
-	}
-	err = txn.Commit()
-	if err != ErrInFailedTransaction {
-		t.Fatalf("expected ErrInFailedTransaction; got %#v", err)
-	}
-}
-
-func TestOpenURL(t *testing.T) {
-	db, err := openTestConnConninfo("postgres://")
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer db.Close()
-	// database/sql might not call our Open at all unless we do something with
-	// the connection
-	txn, err := db.Begin()
-	if err != nil {
-		t.Fatal(err)
-	}
-	txn.Rollback()
-}
-
-func TestExec(t *testing.T) {
-	db := openTestConn(t)
-	defer db.Close()
-
-	_, err := db.Exec("CREATE TEMP TABLE temp (a int)")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	r, err := db.Exec("INSERT INTO temp VALUES (1)")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	if n, _ := r.RowsAffected(); n != 1 {
-		t.Fatalf("expected 1 row affected, not %d", n)
-	}
-
-	r, err = db.Exec("INSERT INTO temp VALUES ($1), ($2), ($3)", 1, 2, 3)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	if n, _ := r.RowsAffected(); n != 3 {
-		t.Fatalf("expected 3 rows affected, not %d", n)
-	}
-
-	// SELECT doesn't send the number of returned rows in the command tag
-	// before 9.0
-	if getServerVersion(t, db) >= 90000 {
-		r, err = db.Exec("SELECT g FROM generate_series(1, 2) g")
-		if err != nil {
-			t.Fatal(err)
-		}
-		if n, _ := r.RowsAffected(); n != 2 {
-			t.Fatalf("expected 2 rows affected, not %d", n)
-		}
-
-		r, err = db.Exec("SELECT g FROM generate_series(1, $1) g", 3)
-		if err != nil {
-			t.Fatal(err)
-		}
-		if n, _ := r.RowsAffected(); n != 3 {
-			t.Fatalf("expected 3 rows affected, not %d", n)
-		}
-	}
-}
-
-func TestStatment(t *testing.T) {
-	db := openTestConn(t)
-	defer db.Close()
-
-	st, err := db.Prepare("SELECT 1")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	st1, err := db.Prepare("SELECT 2")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	r, err := st.Query()
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer r.Close()
-
-	if !r.Next() {
-		t.Fatal("expected row")
-	}
-
-	var i int
-	err = r.Scan(&i)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	if i != 1 {
-		t.Fatalf("expected 1, got %d", i)
-	}
-
-	// st1
-
-	r1, err := st1.Query()
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer r1.Close()
-
-	if !r1.Next() {
-		if r.Err() != nil {
-			t.Fatal(r1.Err())
-		}
-		t.Fatal("expected row")
-	}
-
-	err = r1.Scan(&i)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	if i != 2 {
-		t.Fatalf("expected 2, got %d", i)
-	}
-}
-
-func TestRowsCloseBeforeDone(t *testing.T) {
-	db := openTestConn(t)
-	defer db.Close()
-
-	r, err := db.Query("SELECT 1")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	err = r.Close()
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	if r.Next() {
-		t.Fatal("unexpected row")
-	}
-
-	if r.Err() != nil {
-		t.Fatal(r.Err())
-	}
-}
-
-func TestParameterCountMismatch(t *testing.T) {
-	db := openTestConn(t)
-	defer db.Close()
-
-	var notused int
-	err := db.QueryRow("SELECT false", 1).Scan(&notused)
-	if err == nil {
-		t.Fatal("expected err")
-	}
-	// make sure we clean up correctly
-	err = db.QueryRow("SELECT 1").Scan(&notused)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	err = db.QueryRow("SELECT $1").Scan(&notused)
-	if err == nil {
-		t.Fatal("expected err")
-	}
-	// make sure we clean up correctly
-	err = db.QueryRow("SELECT 1").Scan(&notused)
-	if err != nil {
-		t.Fatal(err)
-	}
-}
-
-// Test that EmptyQueryResponses are handled correctly.
-func TestEmptyQuery(t *testing.T) {
-	db := openTestConn(t)
-	defer db.Close()
-
-	_, err := db.Exec("")
-	if err != nil {
-		t.Fatal(err)
-	}
-	rows, err := db.Query("")
-	if err != nil {
-		t.Fatal(err)
-	}
-	cols, err := rows.Columns()
-	if err != nil {
-		t.Fatal(err)
-	}
-	if len(cols) != 0 {
-		t.Fatalf("unexpected number of columns %d in response to an empty query", len(cols))
-	}
-	if rows.Next() {
-		t.Fatal("unexpected row")
-	}
-	if rows.Err() != nil {
-		t.Fatal(rows.Err())
-	}
-
-	stmt, err := db.Prepare("")
-	if err != nil {
-		t.Fatal(err)
-	}
-	_, err = stmt.Exec()
-	if err != nil {
-		t.Fatal(err)
-	}
-	rows, err = stmt.Query()
-	if err != nil {
-		t.Fatal(err)
-	}
-	cols, err = rows.Columns()
-	if err != nil {
-		t.Fatal(err)
-	}
-	if len(cols) != 0 {
-		t.Fatalf("unexpected number of columns %d in response to an empty query", len(cols))
-	}
-	if rows.Next() {
-		t.Fatal("unexpected row")
-	}
-	if rows.Err() != nil {
-		t.Fatal(rows.Err())
-	}
-}
-
-func TestEncodeDecode(t *testing.T) {
-	db := openTestConn(t)
-	defer db.Close()
-
-	q := `
-		SELECT
-			E'\\000\\001\\002'::bytea,
-			'foobar'::text,
-			NULL::integer,
-			'2000-1-1 01:02:03.04-7'::timestamptz,
-			0::boolean,
-			123,
-			3.14::float8
-		WHERE
-			    E'\\000\\001\\002'::bytea = $1
-			AND 'foobar'::text = $2
-			AND $3::integer is NULL
-	`
-	// AND '2000-1-1 12:00:00.000000-7'::timestamp = $3
-
-	exp1 := []byte{0, 1, 2}
-	exp2 := "foobar"
-
-	r, err := db.Query(q, exp1, exp2, nil)
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer r.Close()
-
-	if !r.Next() {
-		if r.Err() != nil {
-			t.Fatal(r.Err())
-		}
-		t.Fatal("expected row")
-	}
-
-	var got1 []byte
-	var got2 string
-	var got3 = sql.NullInt64{Valid: true}
-	var got4 time.Time
-	var got5, got6, got7 interface{}
-
-	err = r.Scan(&got1, &got2, &got3, &got4, &got5, &got6, &got7)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	if !reflect.DeepEqual(exp1, got1) {
-		t.Errorf("expected %q byte: %q", exp1, got1)
-	}
-
-	if !reflect.DeepEqual(exp2, got2) {
-		t.Errorf("expected %q byte: %q", exp2, got2)
-	}
-
-	if got3.Valid {
-		t.Fatal("expected invalid")
-	}
-
-	if got4.Year() != 2000 {
-		t.Fatal("wrong year")
-	}
-
-	if got5 != false {
-		t.Fatalf("expected false, got %q", got5)
-	}
-
-	if got6 != int64(123) {
-		t.Fatalf("expected 123, got %d", got6)
-	}
-
-	if got7 != float64(3.14) {
-		t.Fatalf("expected 3.14, got %f", got7)
-	}
-}
-
-func TestNoData(t *testing.T) {
-	db := openTestConn(t)
-	defer db.Close()
-
-	st, err := db.Prepare("SELECT 1 WHERE true = false")
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer st.Close()
-
-	r, err := st.Query()
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer r.Close()
-
-	if r.Next() {
-		if r.Err() != nil {
-			t.Fatal(r.Err())
-		}
-		t.Fatal("unexpected row")
-	}
-
-	_, err = db.Query("SELECT * FROM nonexistenttable WHERE age=$1", 20)
-	if err == nil {
-		t.Fatal("Should have raised an error on non existent table")
-	}
-
-	_, err = db.Query("SELECT * FROM nonexistenttable")
-	if err == nil {
-		t.Fatal("Should have raised an error on non existent table")
-	}
-}
-
-func TestErrorDuringStartup(t *testing.T) {
-	// Don't use the normal connection setup, this is intended to
-	// blow up in the startup packet from a non-existent user.
-	db, err := openTestConnConninfo("user=thisuserreallydoesntexist")
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer db.Close()
-
-	_, err = db.Begin()
-	if err == nil {
-		t.Fatal("expected error")
-	}
-
-	e, ok := err.(*Error)
-	if !ok {
-		t.Fatalf("expected Error, got %#v", err)
-	} else if e.Code.Name() != "invalid_authorization_specification" && e.Code.Name() != "invalid_password" {
-		t.Fatalf("expected invalid_authorization_specification or invalid_password, got %s (%+v)", e.Code.Name(), err)
-	}
-}
-
-func TestBadConn(t *testing.T) {
-	var err error
-
-	cn := conn{}
-	func() {
-		defer cn.errRecover(&err)
-		panic(io.EOF)
-	}()
-	if err != driver.ErrBadConn {
-		t.Fatalf("expected driver.ErrBadConn, got: %#v", err)
-	}
-	if !cn.bad {
-		t.Fatalf("expected cn.bad")
-	}
-
-	cn = conn{}
-	func() {
-		defer cn.errRecover(&err)
-		e := &Error{Severity: Efatal}
-		panic(e)
-	}()
-	if err != driver.ErrBadConn {
-		t.Fatalf("expected driver.ErrBadConn, got: %#v", err)
-	}
-	if !cn.bad {
-		t.Fatalf("expected cn.bad")
-	}
-}
-
-func TestErrorOnExec(t *testing.T) {
-	db := openTestConn(t)
-	defer db.Close()
-
-	txn, err := db.Begin()
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer txn.Rollback()
-
-	_, err = txn.Exec("CREATE TEMPORARY TABLE foo(f1 int PRIMARY KEY)")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	_, err = txn.Exec("INSERT INTO foo VALUES (0), (0)")
-	if err == nil {
-		t.Fatal("Should have raised error")
-	}
-
-	e, ok := err.(*Error)
-	if !ok {
-		t.Fatalf("expected Error, got %#v", err)
-	} else if e.Code.Name() != "unique_violation" {
-		t.Fatalf("expected unique_violation, got %s (%+v)", e.Code.Name(), err)
-	}
-}
-
-func TestErrorOnQuery(t *testing.T) {
-	db := openTestConn(t)
-	defer db.Close()
-
-	txn, err := db.Begin()
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer txn.Rollback()
-
-	_, err = txn.Exec("CREATE TEMPORARY TABLE foo(f1 int PRIMARY KEY)")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	_, err = txn.Query("INSERT INTO foo VALUES (0), (0)")
-	if err == nil {
-		t.Fatal("Should have raised error")
-	}
-
-	e, ok := err.(*Error)
-	if !ok {
-		t.Fatalf("expected Error, got %#v", err)
-	} else if e.Code.Name() != "unique_violation" {
-		t.Fatalf("expected unique_violation, got %s (%+v)", e.Code.Name(), err)
-	}
-}
-
-func TestErrorOnQueryRowSimpleQuery(t *testing.T) {
-	db := openTestConn(t)
-	defer db.Close()
-
-	txn, err := db.Begin()
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer txn.Rollback()
-
-	_, err = txn.Exec("CREATE TEMPORARY TABLE foo(f1 int PRIMARY KEY)")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	var v int
-	err = txn.QueryRow("INSERT INTO foo VALUES (0), (0)").Scan(&v)
-	if err == nil {
-		t.Fatal("Should have raised error")
-	}
-
-	e, ok := err.(*Error)
-	if !ok {
-		t.Fatalf("expected Error, got %#v", err)
-	} else if e.Code.Name() != "unique_violation" {
-		t.Fatalf("expected unique_violation, got %s (%+v)", e.Code.Name(), err)
-	}
-}
-
-// Test the QueryRow bug workarounds in stmt.exec() and simpleQuery()
-func TestQueryRowBugWorkaround(t *testing.T) {
-	db := openTestConn(t)
-	defer db.Close()
-
-	// stmt.exec()
-	_, err := db.Exec("CREATE TEMP TABLE notnulltemp (a varchar(10) not null)")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	var a string
-	err = db.QueryRow("INSERT INTO notnulltemp(a) values($1) RETURNING a", nil).Scan(&a)
-	if err == sql.ErrNoRows {
-		t.Fatalf("expected constraint violation error; got: %v", err)
-	}
-	pge, ok := err.(*Error)
-	if !ok {
-		t.Fatalf("expected *Error; got: %#v", err)
-	}
-	if pge.Code.Name() != "not_null_violation" {
-		t.Fatalf("expected not_null_violation; got: %s (%+v)", pge.Code.Name(), err)
-	}
-
-	// Test workaround in simpleQuery()
-	tx, err := db.Begin()
-	if err != nil {
-		t.Fatalf("unexpected error %s in Begin", err)
-	}
-	defer tx.Rollback()
-
-	_, err = tx.Exec("SET LOCAL check_function_bodies TO FALSE")
-	if err != nil {
-		t.Fatalf("could not disable check_function_bodies: %s", err)
-	}
-	_, err = tx.Exec(`
-CREATE OR REPLACE FUNCTION bad_function()
-RETURNS integer
--- hack to prevent the function from being inlined
-SET check_function_bodies TO TRUE
-AS $$
-	SELECT text 'bad'
-$$ LANGUAGE sql`)
-	if err != nil {
-		t.Fatalf("could not create function: %s", err)
-	}
-
-	err = tx.QueryRow("SELECT * FROM bad_function()").Scan(&a)
-	if err == nil {
-		t.Fatalf("expected error")
-	}
-	pge, ok = err.(*Error)
-	if !ok {
-		t.Fatalf("expected *Error; got: %#v", err)
-	}
-	if pge.Code.Name() != "invalid_function_definition" {
-		t.Fatalf("expected invalid_function_definition; got: %s (%+v)", pge.Code.Name(), err)
-	}
-
-	err = tx.Rollback()
-	if err != nil {
-		t.Fatalf("unexpected error %s in Rollback", err)
-	}
-
-	// Also test that simpleQuery()'s workaround works when the query fails
-	// after a row has been received.
-	rows, err := db.Query(`
-select
-	(select generate_series(1, ss.i))
-from (select gs.i
-      from generate_series(1, 2) gs(i)
-      order by gs.i limit 2) ss`)
-	if err != nil {
-		t.Fatalf("query failed: %s", err)
-	}
-	if !rows.Next() {
-		t.Fatalf("expected at least one result row; got %s", rows.Err())
-	}
-	var i int
-	err = rows.Scan(&i)
-	if err != nil {
-		t.Fatalf("rows.Scan() failed: %s", err)
-	}
-	if i != 1 {
-		t.Fatalf("unexpected value for i: %d", i)
-	}
-	if rows.Next() {
-		t.Fatalf("unexpected row")
-	}
-	pge, ok = rows.Err().(*Error)
-	if !ok {
-		t.Fatalf("expected *Error; got: %#v", err)
-	}
-	if pge.Code.Name() != "cardinality_violation" {
-		t.Fatalf("expected cardinality_violation; got: %s (%+v)", pge.Code.Name(), rows.Err())
-	}
-}
-
-func TestSimpleQuery(t *testing.T) {
-	db := openTestConn(t)
-	defer db.Close()
-
-	r, err := db.Query("select 1")
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer r.Close()
-
-	if !r.Next() {
-		t.Fatal("expected row")
-	}
-}
-
-func TestBindError(t *testing.T) {
-	db := openTestConn(t)
-	defer db.Close()
-
-	_, err := db.Exec("create temp table test (i integer)")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	_, err = db.Query("select * from test where i=$1", "hhh")
-	if err == nil {
-		t.Fatal("expected an error")
-	}
-
-	// Should not get error here
-	r, err := db.Query("select * from test where i=$1", 1)
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer r.Close()
-}
-
-func TestParseErrorInExtendedQuery(t *testing.T) {
-	db := openTestConn(t)
-	defer db.Close()
-
-	rows, err := db.Query("PARSE_ERROR $1", 1)
-	if err == nil {
-		t.Fatal("expected error")
-	}
-
-	rows, err = db.Query("SELECT 1")
-	if err != nil {
-		t.Fatal(err)
-	}
-	rows.Close()
-}
-
-// TestReturning tests that an INSERT query using the RETURNING clause returns a row.
-func TestReturning(t *testing.T) {
-	db := openTestConn(t)
-	defer db.Close()
-
-	_, err := db.Exec("CREATE TEMP TABLE distributors (did integer default 0, dname text)")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	rows, err := db.Query("INSERT INTO distributors (did, dname) VALUES (DEFAULT, 'XYZ Widgets') " +
-		"RETURNING did;")
-	if err != nil {
-		t.Fatal(err)
-	}
-	if !rows.Next() {
-		t.Fatal("no rows")
-	}
-	var did int
-	err = rows.Scan(&did)
-	if err != nil {
-		t.Fatal(err)
-	}
-	if did != 0 {
-		t.Fatalf("bad value for did: got %d, want %d", did, 0)
-	}
-
-	if rows.Next() {
-		t.Fatal("unexpected next row")
-	}
-	err = rows.Err()
-	if err != nil {
-		t.Fatal(err)
-	}
-}
-
-func TestIssue186(t *testing.T) {
-	db := openTestConn(t)
-	defer db.Close()
-
-	// Exec() a query which returns results
-	_, err := db.Exec("VALUES (1), (2), (3)")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	_, err = db.Exec("VALUES ($1), ($2), ($3)", 1, 2, 3)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	// Query() a query which doesn't return any results
-	txn, err := db.Begin()
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer txn.Rollback()
-
-	rows, err := txn.Query("CREATE TEMP TABLE foo(f1 int)")
-	if err != nil {
-		t.Fatal(err)
-	}
-	if err = rows.Close(); err != nil {
-		t.Fatal(err)
-	}
-
-	// small trick to get NoData from a parameterized query
-	_, err = txn.Exec("CREATE RULE nodata AS ON INSERT TO foo DO INSTEAD NOTHING")
-	if err != nil {
-		t.Fatal(err)
-	}
-	rows, err = txn.Query("INSERT INTO foo VALUES ($1)", 1)
-	if err != nil {
-		t.Fatal(err)
-	}
-	if err = rows.Close(); err != nil {
-		t.Fatal(err)
-	}
-}
-
-func TestIssue196(t *testing.T) {
-	db := openTestConn(t)
-	defer db.Close()
-
-	row := db.QueryRow("SELECT float4 '0.10000122' = $1, float8 '35.03554004971999' = $2",
-		float32(0.10000122), float64(35.03554004971999))
-
-	var float4match, float8match bool
-	err := row.Scan(&float4match, &float8match)
-	if err != nil {
-		t.Fatal(err)
-	}
-	if !float4match {
-		t.Errorf("Expected float4 fidelity to be maintained; got no match")
-	}
-	if !float8match {
-		t.Errorf("Expected float8 fidelity to be maintained; got no match")
-	}
-}
-
-// Test that any CommandComplete messages sent before the query results are
-// ignored.
-func TestIssue282(t *testing.T) {
-	db := openTestConn(t)
-	defer db.Close()
-
-	var search_path string
-	err := db.QueryRow(`
-		SET LOCAL search_path TO pg_catalog;
-		SET LOCAL search_path TO pg_catalog;
-		SHOW search_path`).Scan(&search_path)
-	if err != nil {
-		t.Fatal(err)
-	}
-	if search_path != "pg_catalog" {
-		t.Fatalf("unexpected search_path %s", search_path)
-	}
-}
-
-func TestReadFloatPrecision(t *testing.T) {
-	db := openTestConn(t)
-	defer db.Close()
-
-	row := db.QueryRow("SELECT float4 '0.10000122', float8 '35.03554004971999'")
-	var float4val float32
-	var float8val float64
-	err := row.Scan(&float4val, &float8val)
-	if err != nil {
-		t.Fatal(err)
-	}
-	if float4val != float32(0.10000122) {
-		t.Errorf("Expected float4 fidelity to be maintained; got no match")
-	}
-	if float8val != float64(35.03554004971999) {
-		t.Errorf("Expected float8 fidelity to be maintained; got no match")
-	}
-}
-
-func TestXactMultiStmt(t *testing.T) {
-	// minified test case based on bug reports from
-	// pico303@gmail.com and rangelspam@gmail.com
-	t.Skip("Skipping failing test")
-	db := openTestConn(t)
-	defer db.Close()
-
-	tx, err := db.Begin()
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer tx.Commit()
-
-	rows, err := tx.Query("select 1")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	if rows.Next() {
-		var val int32
-		if err = rows.Scan(&val); err != nil {
-			t.Fatal(err)
-		}
-	} else {
-		t.Fatal("Expected at least one row in first query in xact")
-	}
-
-	rows2, err := tx.Query("select 2")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	if rows2.Next() {
-		var val2 int32
-		if err := rows2.Scan(&val2); err != nil {
-			t.Fatal(err)
-		}
-	} else {
-		t.Fatal("Expected at least one row in second query in xact")
-	}
-
-	if err = rows.Err(); err != nil {
-		t.Fatal(err)
-	}
-
-	if err = rows2.Err(); err != nil {
-		t.Fatal(err)
-	}
-
-	if err = tx.Commit(); err != nil {
-		t.Fatal(err)
-	}
-}
-
-var envParseTests = []struct {
-	Expected map[string]string
-	Env      []string
-}{
-	{
-		Env:      []string{"PGDATABASE=hello", "PGUSER=goodbye"},
-		Expected: map[string]string{"dbname": "hello", "user": "goodbye"},
-	},
-	{
-		Env:      []string{"PGDATESTYLE=ISO, MDY"},
-		Expected: map[string]string{"datestyle": "ISO, MDY"},
-	},
-	{
-		Env:      []string{"PGCONNECT_TIMEOUT=30"},
-		Expected: map[string]string{"connect_timeout": "30"},
-	},
-}
-
-func TestParseEnviron(t *testing.T) {
-	for i, tt := range envParseTests {
-		results := parseEnviron(tt.Env)
-		if !reflect.DeepEqual(tt.Expected, results) {
-			t.Errorf("%d: Expected: %#v Got: %#v", i, tt.Expected, results)
-		}
-	}
-}
-
-func TestParseComplete(t *testing.T) {
-	tpc := func(commandTag string, command string, affectedRows int64, shouldFail bool) {
-		defer func() {
-			if p := recover(); p != nil {
-				if !shouldFail {
-					t.Error(p)
-				}
-			}
-		}()
-		cn := &conn{}
-		res, c := cn.parseComplete(commandTag)
-		if c != command {
-			t.Errorf("Expected %v, got %v", command, c)
-		}
-		n, err := res.RowsAffected()
-		if err != nil {
-			t.Fatal(err)
-		}
-		if n != affectedRows {
-			t.Errorf("Expected %d, got %d", affectedRows, n)
-		}
-	}
-
-	tpc("ALTER TABLE", "ALTER TABLE", 0, false)
-	tpc("INSERT 0 1", "INSERT", 1, false)
-	tpc("UPDATE 100", "UPDATE", 100, false)
-	tpc("SELECT 100", "SELECT", 100, false)
-	tpc("FETCH 100", "FETCH", 100, false)
-	// allow COPY (and others) without row count
-	tpc("COPY", "COPY", 0, false)
-	// don't fail on command tags we don't recognize
-	tpc("UNKNOWNCOMMANDTAG", "UNKNOWNCOMMANDTAG", 0, false)
-
-	// failure cases
-	tpc("INSERT 1", "", 0, true)   // missing oid
-	tpc("UPDATE 0 1", "", 0, true) // too many numbers
-	tpc("SELECT foo", "", 0, true) // invalid row count
-}
-
-func TestExecerInterface(t *testing.T) {
-	// Gin up a straw man private struct just for the type check
-	cn := &conn{c: nil}
-	var cni interface{} = cn
-
-	_, ok := cni.(driver.Execer)
-	if !ok {
-		t.Fatal("Driver doesn't implement Execer")
-	}
-}
-
-func TestNullAfterNonNull(t *testing.T) {
-	db := openTestConn(t)
-	defer db.Close()
-
-	r, err := db.Query("SELECT 9::integer UNION SELECT NULL::integer")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	var n sql.NullInt64
-
-	if !r.Next() {
-		if r.Err() != nil {
-			t.Fatal(err)
-		}
-		t.Fatal("expected row")
-	}
-
-	if err := r.Scan(&n); err != nil {
-		t.Fatal(err)
-	}
-
-	if n.Int64 != 9 {
-		t.Fatalf("expected 2, not %d", n.Int64)
-	}
-
-	if !r.Next() {
-		if r.Err() != nil {
-			t.Fatal(err)
-		}
-		t.Fatal("expected row")
-	}
-
-	if err := r.Scan(&n); err != nil {
-		t.Fatal(err)
-	}
-
-	if n.Valid {
-		t.Fatal("expected n to be invalid")
-	}
-
-	if n.Int64 != 0 {
-		t.Fatalf("expected n to 2, not %d", n.Int64)
-	}
-}
-
-func Test64BitErrorChecking(t *testing.T) {
-	defer func() {
-		if err := recover(); err != nil {
-			t.Fatal("panic due to 0xFFFFFFFF != -1 " +
-				"when int is 64 bits")
-		}
-	}()
-
-	db := openTestConn(t)
-	defer db.Close()
-
-	r, err := db.Query(`SELECT *
-FROM (VALUES (0::integer, NULL::text), (1, 'test string')) AS t;`)
-
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	defer r.Close()
-
-	for r.Next() {
-	}
-}
-
-func TestCommit(t *testing.T) {
-	db := openTestConn(t)
-	defer db.Close()
-
-	_, err := db.Exec("CREATE TEMP TABLE temp (a int)")
-	if err != nil {
-		t.Fatal(err)
-	}
-	sqlInsert := "INSERT INTO temp VALUES (1)"
-	sqlSelect := "SELECT * FROM temp"
-	tx, err := db.Begin()
-	if err != nil {
-		t.Fatal(err)
-	}
-	_, err = tx.Exec(sqlInsert)
-	if err != nil {
-		t.Fatal(err)
-	}
-	err = tx.Commit()
-	if err != nil {
-		t.Fatal(err)
-	}
-	var i int
-	err = db.QueryRow(sqlSelect).Scan(&i)
-	if err != nil {
-		t.Fatal(err)
-	}
-	if i != 1 {
-		t.Fatalf("expected 1, got %d", i)
-	}
-}
-
-func TestErrorClass(t *testing.T) {
-	db := openTestConn(t)
-	defer db.Close()
-
-	_, err := db.Query("SELECT int 'notint'")
-	if err == nil {
-		t.Fatal("expected error")
-	}
-	pge, ok := err.(*Error)
-	if !ok {
-		t.Fatalf("expected *pq.Error, got %#+v", err)
-	}
-	if pge.Code.Class() != "22" {
-		t.Fatalf("expected class 28, got %v", pge.Code.Class())
-	}
-	if pge.Code.Class().Name() != "data_exception" {
-		t.Fatalf("expected data_exception, got %v", pge.Code.Class().Name())
-	}
-}
-
-func TestParseOpts(t *testing.T) {
-	tests := []struct {
-		in       string
-		expected values
-		valid    bool
-	}{
-		{"dbname=hello user=goodbye", values{"dbname": "hello", "user": "goodbye"}, true},
-		{"dbname=hello user=goodbye  ", values{"dbname": "hello", "user": "goodbye"}, true},
-		{"dbname = hello user=goodbye", values{"dbname": "hello", "user": "goodbye"}, true},
-		{"dbname=hello user =goodbye", values{"dbname": "hello", "user": "goodbye"}, true},
-		{"dbname=hello user= goodbye", values{"dbname": "hello", "user": "goodbye"}, true},
-		{"host=localhost password='correct horse battery staple'", values{"host": "localhost", "password": "correct horse battery staple"}, true},
-		{"dbname=データベース password=パスワード", values{"dbname": "データベース", "password": "パスワード"}, true},
-		{"dbname=hello user=''", values{"dbname": "hello", "user": ""}, true},
-		{"user='' dbname=hello", values{"dbname": "hello", "user": ""}, true},
-		// The last option value is an empty string if there's no non-whitespace after its =
-		{"dbname=hello user=   ", values{"dbname": "hello", "user": ""}, true},
-
-		// The parser ignores spaces after = and interprets the next set of non-whitespace characters as the value.
-		{"user= password=foo", values{"user": "password=foo"}, true},
-
-		// Backslash escapes next char
-		{`user=a\ \'\\b`, values{"user": `a '\b`}, true},
-		{`user='a \'b'`, values{"user": `a 'b`}, true},
-
-		// Incomplete escape
-		{`user=x\`, values{}, false},
-
-		// No '=' after the key
-		{"postgre://marko@internet", values{}, false},
-		{"dbname user=goodbye", values{}, false},
-		{"user=foo blah", values{}, false},
-		{"user=foo blah   ", values{}, false},
-
-		// Unterminated quoted value
-		{"dbname=hello user='unterminated", values{}, false},
-	}
-
-	for _, test := range tests {
-		o := make(values)
-		err := parseOpts(test.in, o)
-
-		switch {
-		case err != nil && test.valid:
-			t.Errorf("%q got unexpected error: %s", test.in, err)
-		case err == nil && test.valid && !reflect.DeepEqual(test.expected, o):
-			t.Errorf("%q got: %#v want: %#v", test.in, o, test.expected)
-		case err == nil && !test.valid:
-			t.Errorf("%q expected an error", test.in)
-		}
-	}
-}
-
-func TestRuntimeParameters(t *testing.T) {
-	type RuntimeTestResult int
-	const (
-		ResultUnknown RuntimeTestResult = iota
-		ResultSuccess
-		ResultError // other error
-	)
-
-	tests := []struct {
-		conninfo        string
-		param           string
-		expected        string
-		expectedOutcome RuntimeTestResult
-	}{
-		// invalid parameter
-		{"DOESNOTEXIST=foo", "", "", ResultError},
-		// we can only work with a specific value for these two
-		{"client_encoding=SQL_ASCII", "", "", ResultError},
-		{"datestyle='ISO, YDM'", "", "", ResultError},
-		// "options" should work exactly as it does in libpq
-		{"options='-c search_path=pqgotest'", "search_path", "pqgotest", ResultSuccess},
-		// pq should override client_encoding in this case
-		{"options='-c client_encoding=SQL_ASCII'", "client_encoding", "UTF8", ResultSuccess},
-		// allow client_encoding to be set explicitly
-		{"client_encoding=UTF8", "client_encoding", "UTF8", ResultSuccess},
-		// test a runtime parameter not supported by libpq
-		{"work_mem='139kB'", "work_mem", "139kB", ResultSuccess},
-		// test fallback_application_name
-		{"application_name=foo fallback_application_name=bar", "application_name", "foo", ResultSuccess},
-		{"application_name='' fallback_application_name=bar", "application_name", "", ResultSuccess},
-		{"fallback_application_name=bar", "application_name", "bar", ResultSuccess},
-	}
-
-	for _, test := range tests {
-		db, err := openTestConnConninfo(test.conninfo)
-		if err != nil {
-			t.Fatal(err)
-		}
-
-		// application_name didn't exist before 9.0
-		if test.param == "application_name" && getServerVersion(t, db) < 90000 {
-			db.Close()
-			continue
-		}
-
-		tryGetParameterValue := func() (value string, outcome RuntimeTestResult) {
-			defer db.Close()
-			row := db.QueryRow("SELECT current_setting($1)", test.param)
-			err = row.Scan(&value)
-			if err != nil {
-				return "", ResultError
-			}
-			return value, ResultSuccess
-		}
-
-		value, outcome := tryGetParameterValue()
-		if outcome != test.expectedOutcome && outcome == ResultError {
-			t.Fatalf("%v: unexpected error: %v", test.conninfo, err)
-		}
-		if outcome != test.expectedOutcome {
-			t.Fatalf("unexpected outcome %v (was expecting %v) for conninfo \"%s\"",
-				outcome, test.expectedOutcome, test.conninfo)
-		}
-		if value != test.expected {
-			t.Fatalf("bad value for %s: got %s, want %s with conninfo \"%s\"",
-				test.param, value, test.expected, test.conninfo)
-		}
-	}
-}
-
-func TestIsUTF8(t *testing.T) {
-	var cases = []struct {
-		name string
-		want bool
-	}{
-		{"unicode", true},
-		{"utf-8", true},
-		{"utf_8", true},
-		{"UTF-8", true},
-		{"UTF8", true},
-		{"utf8", true},
-		{"u n ic_ode", true},
-		{"ut_f%8", true},
-		{"ubf8", false},
-		{"punycode", false},
-	}
-
-	for _, test := range cases {
-		if g := isUTF8(test.name); g != test.want {
-			t.Errorf("isUTF8(%q) = %v want %v", test.name, g, test.want)
-		}
-	}
-}
-
-func TestQuoteIdentifier(t *testing.T) {
-	var cases = []struct {
-		input string
-		want  string
-	}{
-		{`foo`, `"foo"`},
-		{`foo bar baz`, `"foo bar baz"`},
-		{`foo"bar`, `"foo""bar"`},
-		{"foo\x00bar", `"foo"`},
-		{"\x00foo", `""`},
-	}
-
-	for _, test := range cases {
-		got := QuoteIdentifier(test.input)
-		if got != test.want {
-			t.Errorf("QuoteIdentifier(%q) = %v want %v", test.input, got, test.want)
-		}
-	}
-}

+ 28 - 12
vendor/github.com/lib/pq/copy.go

@@ -13,6 +13,7 @@ var (
 	errBinaryCopyNotSupported     = errors.New("pq: only text format supported for COPY")
 	errCopyToNotSupported         = errors.New("pq: COPY TO is not supported")
 	errCopyNotSupportedOutsideTxn = errors.New("pq: COPY is only allowed inside a transaction")
+	errCopyInProgress             = errors.New("pq: COPY in progress")
 )
 
 // CopyIn creates a COPY FROM statement which can be prepared with
@@ -96,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)
 		}
 	}
@@ -121,7 +122,7 @@ awaitCopyInResponse:
 			cn.processReadyForQuery(r)
 			return nil, err
 		default:
-			cn.bad = true
+			ci.setBad()
 			errorf("unknown response for CopyFail: %q", t)
 		}
 	}
@@ -142,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
@@ -150,6 +151,8 @@ func (ci *copyin) resploop() {
 		switch t {
 		case 'C':
 			// complete
+		case 'N':
+			// NoticeResponse
 		case 'Z':
 			ci.cn.processReadyForQuery(&r)
 			ci.done <- true
@@ -158,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
@@ -166,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)
@@ -203,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)
@@ -213,9 +229,7 @@ func (ci *copyin) Exec(v []driver.Value) (r driver.Result, err error) {
 	}
 
 	if len(v) == 0 {
-		err = ci.Close()
-		ci.closed = true
-		return nil, err
+		return nil, ci.Close()
 	}
 
 	numValues := len(v)
@@ -238,11 +252,12 @@ func (ci *copyin) Exec(v []driver.Value) (r driver.Result, err error) {
 }
 
 func (ci *copyin) Close() (err error) {
-	if ci.closed {
-		return errCopyInClosed
+	if ci.closed { // Don't do anything, we're already closed
+		return nil
 	}
+	ci.closed = true
 
-	if ci.cn.bad {
+	if ci.isBad() {
 		return driver.ErrBadConn
 	}
 	defer ci.cn.errRecover(&err)
@@ -257,6 +272,7 @@ func (ci *copyin) Close() (err error) {
 	}
 
 	<-ci.done
+	ci.cn.inCopy = false
 
 	if ci.isErrorSet() {
 		err = ci.err

+ 0 - 380
vendor/github.com/lib/pq/copy_test.go

@@ -1,380 +0,0 @@
-package pq
-
-import (
-	"bytes"
-	"database/sql"
-	"strings"
-	"testing"
-)
-
-func TestCopyInStmt(t *testing.T) {
-	var stmt string
-	stmt = CopyIn("table name")
-	if stmt != `COPY "table name" () FROM STDIN` {
-		t.Fatal(stmt)
-	}
-
-	stmt = CopyIn("table name", "column 1", "column 2")
-	if stmt != `COPY "table name" ("column 1", "column 2") FROM STDIN` {
-		t.Fatal(stmt)
-	}
-
-	stmt = CopyIn(`table " name """`, `co"lumn""`)
-	if stmt != `COPY "table "" name """"""" ("co""lumn""""") FROM STDIN` {
-		t.Fatal(stmt)
-	}
-}
-
-func TestCopyInSchemaStmt(t *testing.T) {
-	var stmt string
-	stmt = CopyInSchema("schema name", "table name")
-	if stmt != `COPY "schema name"."table name" () FROM STDIN` {
-		t.Fatal(stmt)
-	}
-
-	stmt = CopyInSchema("schema name", "table name", "column 1", "column 2")
-	if stmt != `COPY "schema name"."table name" ("column 1", "column 2") FROM STDIN` {
-		t.Fatal(stmt)
-	}
-
-	stmt = CopyInSchema(`schema " name """`, `table " name """`, `co"lumn""`)
-	if stmt != `COPY "schema "" name """"""".`+
-		`"table "" name """"""" ("co""lumn""""") FROM STDIN` {
-		t.Fatal(stmt)
-	}
-}
-
-func TestCopyInMultipleValues(t *testing.T) {
-	db := openTestConn(t)
-	defer db.Close()
-
-	txn, err := db.Begin()
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer txn.Rollback()
-
-	_, err = txn.Exec("CREATE TEMP TABLE temp (a int, b varchar)")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	stmt, err := txn.Prepare(CopyIn("temp", "a", "b"))
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	longString := strings.Repeat("#", 500)
-
-	for i := 0; i < 500; i++ {
-		_, err = stmt.Exec(int64(i), longString)
-		if err != nil {
-			t.Fatal(err)
-		}
-	}
-
-	_, err = stmt.Exec()
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	err = stmt.Close()
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	var num int
-	err = txn.QueryRow("SELECT COUNT(*) FROM temp").Scan(&num)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	if num != 500 {
-		t.Fatalf("expected 500 items, not %d", num)
-	}
-}
-
-func TestCopyInTypes(t *testing.T) {
-	db := openTestConn(t)
-	defer db.Close()
-
-	txn, err := db.Begin()
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer txn.Rollback()
-
-	_, err = txn.Exec("CREATE TEMP TABLE temp (num INTEGER, text VARCHAR, blob BYTEA, nothing VARCHAR)")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	stmt, err := txn.Prepare(CopyIn("temp", "num", "text", "blob", "nothing"))
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	_, err = stmt.Exec(int64(1234567890), "Héllö\n ☃!\r\t\\", []byte{0, 255, 9, 10, 13}, nil)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	_, err = stmt.Exec()
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	err = stmt.Close()
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	var num int
-	var text string
-	var blob []byte
-	var nothing sql.NullString
-
-	err = txn.QueryRow("SELECT * FROM temp").Scan(&num, &text, &blob, &nothing)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	if num != 1234567890 {
-		t.Fatal("unexpected result", num)
-	}
-	if text != "Héllö\n ☃!\r\t\\" {
-		t.Fatal("unexpected result", text)
-	}
-	if bytes.Compare(blob, []byte{0, 255, 9, 10, 13}) != 0 {
-		t.Fatal("unexpected result", blob)
-	}
-	if nothing.Valid {
-		t.Fatal("unexpected result", nothing.String)
-	}
-}
-
-func TestCopyInWrongType(t *testing.T) {
-	db := openTestConn(t)
-	defer db.Close()
-
-	txn, err := db.Begin()
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer txn.Rollback()
-
-	_, err = txn.Exec("CREATE TEMP TABLE temp (num INTEGER)")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	stmt, err := txn.Prepare(CopyIn("temp", "num"))
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer stmt.Close()
-
-	_, err = stmt.Exec("Héllö\n ☃!\r\t\\")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	_, err = stmt.Exec()
-	if err == nil {
-		t.Fatal("expected error")
-	}
-	if pge := err.(*Error); pge.Code.Name() != "invalid_text_representation" {
-		t.Fatalf("expected 'invalid input syntax for integer' error, got %s (%+v)", pge.Code.Name(), pge)
-	}
-}
-
-func TestCopyOutsideOfTxnError(t *testing.T) {
-	db := openTestConn(t)
-	defer db.Close()
-
-	_, err := db.Prepare(CopyIn("temp", "num"))
-	if err == nil {
-		t.Fatal("COPY outside of transaction did not return an error")
-	}
-	if err != errCopyNotSupportedOutsideTxn {
-		t.Fatalf("expected %s, got %s", err, err.Error())
-	}
-}
-
-func TestCopyInBinaryError(t *testing.T) {
-	db := openTestConn(t)
-	defer db.Close()
-
-	txn, err := db.Begin()
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer txn.Rollback()
-
-	_, err = txn.Exec("CREATE TEMP TABLE temp (num INTEGER)")
-	if err != nil {
-		t.Fatal(err)
-	}
-	_, err = txn.Prepare("COPY temp (num) FROM STDIN WITH binary")
-	if err != errBinaryCopyNotSupported {
-		t.Fatalf("expected %s, got %+v", errBinaryCopyNotSupported, err)
-	}
-	// check that the protocol is in a valid state
-	err = txn.Rollback()
-	if err != nil {
-		t.Fatal(err)
-	}
-}
-
-func TestCopyFromError(t *testing.T) {
-	db := openTestConn(t)
-	defer db.Close()
-
-	txn, err := db.Begin()
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer txn.Rollback()
-
-	_, err = txn.Exec("CREATE TEMP TABLE temp (num INTEGER)")
-	if err != nil {
-		t.Fatal(err)
-	}
-	_, err = txn.Prepare("COPY temp (num) TO STDOUT")
-	if err != errCopyToNotSupported {
-		t.Fatalf("expected %s, got %+v", errCopyToNotSupported, err)
-	}
-	// check that the protocol is in a valid state
-	err = txn.Rollback()
-	if err != nil {
-		t.Fatal(err)
-	}
-}
-
-func TestCopySyntaxError(t *testing.T) {
-	db := openTestConn(t)
-	defer db.Close()
-
-	txn, err := db.Begin()
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer txn.Rollback()
-
-	_, err = txn.Prepare("COPY ")
-	if err == nil {
-		t.Fatal("expected error")
-	}
-	if pge := err.(*Error); pge.Code.Name() != "syntax_error" {
-		t.Fatalf("expected syntax error, got %s (%+v)", pge.Code.Name(), pge)
-	}
-	// check that the protocol is in a valid state
-	err = txn.Rollback()
-	if err != nil {
-		t.Fatal(err)
-	}
-}
-
-// Tests for connection errors in copyin.resploop()
-func TestCopyRespLoopConnectionError(t *testing.T) {
-	db := openTestConn(t)
-	defer db.Close()
-
-	txn, err := db.Begin()
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer txn.Rollback()
-
-	var pid int
-	err = txn.QueryRow("SELECT pg_backend_pid()").Scan(&pid)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	_, err = txn.Exec("CREATE TEMP TABLE temp (a int)")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	stmt, err := txn.Prepare(CopyIn("temp", "a"))
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	_, err = db.Exec("SELECT pg_terminate_backend($1)", pid)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	// We have to try and send something over, since postgres won't process
-	// SIGTERMs while it's waiting for CopyData/CopyEnd messages; see
-	// tcop/postgres.c.
-	_, err = stmt.Exec(1)
-	if err != nil {
-		t.Fatal(err)
-	}
-	_, err = stmt.Exec()
-	if err == nil {
-		t.Fatalf("expected error")
-	}
-	pge, ok := err.(*Error)
-	if !ok {
-		t.Fatalf("expected *pq.Error, got %+#v", err)
-	} else if pge.Code.Name() != "admin_shutdown" {
-		t.Fatalf("expected admin_shutdown, got %s", pge.Code.Name())
-	}
-
-	err = stmt.Close()
-	if err != nil {
-		t.Fatal(err)
-	}
-}
-
-func BenchmarkCopyIn(b *testing.B) {
-	db := openTestConn(b)
-	defer db.Close()
-
-	txn, err := db.Begin()
-	if err != nil {
-		b.Fatal(err)
-	}
-	defer txn.Rollback()
-
-	_, err = txn.Exec("CREATE TEMP TABLE temp (a int, b varchar)")
-	if err != nil {
-		b.Fatal(err)
-	}
-
-	stmt, err := txn.Prepare(CopyIn("temp", "a", "b"))
-	if err != nil {
-		b.Fatal(err)
-	}
-
-	for i := 0; i < b.N; i++ {
-		_, err = stmt.Exec(int64(i), "hello world!")
-		if err != nil {
-			b.Fatal(err)
-		}
-	}
-
-	_, err = stmt.Exec()
-	if err != nil {
-		b.Fatal(err)
-	}
-
-	err = stmt.Close()
-	if err != nil {
-		b.Fatal(err)
-	}
-
-	var num int
-	err = txn.QueryRow("SELECT COUNT(*) FROM temp").Scan(&num)
-	if err != nil {
-		b.Fatal(err)
-	}
-
-	if num != b.N {
-		b.Fatalf("expected %d items, not %d", b.N, num)
-	}
-}

+ 27 - 1
vendor/github.com/lib/pq/doc.go

@@ -5,8 +5,9 @@ In most cases clients will use the database/sql package instead of
 using this package directly. For example:
 
 	import (
-		_ "github.com/lib/pq"
 		"database/sql"
+
+		_ "github.com/lib/pq"
 	)
 
 	func main() {
@@ -85,9 +86,13 @@ variables not supported by pq are set, pq will panic during connection
 establishment.  Environment variables have a lower precedence than explicitly
 provided connection parameters.
 
+The pgpass mechanism as described in http://www.postgresql.org/docs/current/static/libpq-pgpass.html
+is supported, but on Windows PGPASSFILE must be specified explicitly.
+
 
 Queries
 
+
 database/sql does not dictate any specific format for parameter
 markers in query strings, and pq uses the Postgres-native ordinal markers,
 as shown above. The same marker can be reused for the same parameter:
@@ -111,8 +116,29 @@ For more details on RETURNING, see the Postgres documentation:
 
 For additional instructions on querying see the documentation for the database/sql package.
 
+
+Data Types
+
+
+Parameters pass through driver.DefaultParameterConverter before they are handled
+by this package. When the binary_parameters connection option is enabled,
+[]byte values are sent directly to the backend as data in binary format.
+
+This package returns the following types for values from the PostgreSQL backend:
+
+	- integer types smallint, integer, and bigint are returned as int64
+	- floating-point types real and double precision are returned as float64
+	- character types char, varchar, and text are returned as string
+	- temporal types date, time, timetz, timestamp, and timestamptz are returned as time.Time
+	- the boolean type is returned as bool
+	- the bytea type is returned as []byte
+
+All other types are returned directly from the backend as []byte values in text format.
+
+
 Errors
 
+
 pq may return errors of type *pq.Error which can be interrogated for error details:
 
         if err, ok := err.(*pq.Error); ok {

+ 231 - 73
vendor/github.com/lib/pq/encode.go

@@ -3,24 +3,34 @@ package pq
 import (
 	"bytes"
 	"database/sql/driver"
+	"encoding/binary"
 	"encoding/hex"
+	"errors"
 	"fmt"
-	"github.com/lib/pq/oid"
 	"math"
 	"strconv"
 	"strings"
 	"sync"
 	"time"
+
+	"github.com/lib/pq/oid"
 )
 
+func binaryEncode(parameterStatus *parameterStatus, x interface{}) []byte {
+	switch v := x.(type) {
+	case []byte:
+		return v
+	default:
+		return encode(parameterStatus, x, oid.T_unknown)
+	}
+}
+
 func encode(parameterStatus *parameterStatus, x interface{}, pgtypOid oid.Oid) []byte {
 	switch v := x.(type) {
 	case int64:
-		return []byte(fmt.Sprintf("%d", v))
-	case float32:
-		return []byte(fmt.Sprintf("%.9f", v))
+		return strconv.AppendInt(nil, v, 10)
 	case float64:
-		return []byte(fmt.Sprintf("%.17f", v))
+		return strconv.AppendFloat(nil, v, 'f', -1, 64)
 	case []byte:
 		if pgtypOid == oid.T_bytea {
 			return encodeBytea(parameterStatus.serverVersion, v)
@@ -34,7 +44,7 @@ func encode(parameterStatus *parameterStatus, x interface{}, pgtypOid oid.Oid) [
 
 		return []byte(v)
 	case bool:
-		return []byte(fmt.Sprintf("%t", v))
+		return strconv.AppendBool(nil, v)
 	case time.Time:
 		return formatTs(v)
 
@@ -45,10 +55,51 @@ func encode(parameterStatus *parameterStatus, x interface{}, pgtypOid oid.Oid) [
 	panic("not reached")
 }
 
-func decode(parameterStatus *parameterStatus, s []byte, typ oid.Oid) interface{} {
+func decode(parameterStatus *parameterStatus, s []byte, typ oid.Oid, f format) interface{} {
+	switch f {
+	case formatBinary:
+		return binaryDecode(parameterStatus, s, typ)
+	case formatText:
+		return textDecode(parameterStatus, s, typ)
+	default:
+		panic("not reached")
+	}
+}
+
+func binaryDecode(parameterStatus *parameterStatus, s []byte, typ oid.Oid) interface{} {
 	switch typ {
 	case oid.T_bytea:
-		return parseBytea(s)
+		return s
+	case oid.T_int8:
+		return int64(binary.BigEndian.Uint64(s))
+	case oid.T_int4:
+		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))
+	}
+
+	panic("not reached")
+}
+
+func textDecode(parameterStatus *parameterStatus, s []byte, typ oid.Oid) interface{} {
+	switch typ {
+	case oid.T_char, oid.T_varchar, oid.T_text:
+		return string(s)
+	case oid.T_bytea:
+		b, err := parseBytea(s)
+		if err != nil {
+			errorf("%s", err)
+		}
+		return b
 	case oid.T_timestamptz:
 		return parseTs(parameterStatus.currentLocation, string(s))
 	case oid.T_timestamp, oid.T_date:
@@ -59,7 +110,7 @@ func decode(parameterStatus *parameterStatus, s []byte, typ oid.Oid) interface{}
 		return mustParse("15:04:05-07", typ, s)
 	case oid.T_bool:
 		return s[0] == 't'
-	case oid.T_int8, oid.T_int2, oid.T_int4:
+	case oid.T_int8, oid.T_int4, oid.T_int2:
 		i, err := strconv.ParseInt(string(s), 10, 64)
 		if err != nil {
 			errorf("%s", err)
@@ -86,8 +137,6 @@ func appendEncodedText(parameterStatus *parameterStatus, buf []byte, x interface
 	switch v := x.(type) {
 	case int64:
 		return strconv.AppendInt(buf, v, 10)
-	case float32:
-		return strconv.AppendFloat(buf, float64(v), 'f', -1, 32)
 	case float64:
 		return strconv.AppendFloat(buf, v, 'f', -1, 64)
 	case []byte:
@@ -149,12 +198,6 @@ func appendEscapedText(buf []byte, text string) []byte {
 func mustParse(f string, typ oid.Oid, s []byte) time.Time {
 	str := string(s)
 
-	// Special case until time.Parse bug is fixed:
-	// http://code.google.com/p/go/issues/detail?id=3487
-	if str[len(str)-2] == '.' {
-		str += "0"
-	}
-
 	// check for a 30-minute-offset timezone
 	if (typ == oid.T_timestamptz || typ == oid.T_timetz) &&
 		str[len(str)-3] == ':' {
@@ -167,16 +210,39 @@ func mustParse(f string, typ oid.Oid, s []byte) time.Time {
 	return t
 }
 
-func expect(str, char string, pos int) {
-	if c := str[pos : pos+1]; c != char {
-		errorf("expected '%v' at position %v; got '%v'", char, pos, c)
+var errInvalidTimestamp = errors.New("invalid timestamp")
+
+type timestampParser struct {
+	err error
+}
+
+func (p *timestampParser) expect(str string, char byte, pos int) {
+	if p.err != nil {
+		return
+	}
+	if pos+1 > len(str) {
+		p.err = errInvalidTimestamp
+		return
+	}
+	if c := str[pos]; c != char && p.err == nil {
+		p.err = fmt.Errorf("expected '%v' at position %v; got '%v'", char, pos, c)
 	}
 }
 
-func mustAtoi(str string) int {
-	result, err := strconv.Atoi(str)
+func (p *timestampParser) mustAtoi(str string, begin int, end int) int {
+	if p.err != nil {
+		return 0
+	}
+	if begin < 0 || end < 0 || begin > end || end > len(str) {
+		p.err = errInvalidTimestamp
+		return 0
+	}
+	result, err := strconv.Atoi(str[begin:end])
 	if err != nil {
-		errorf("expected number; got '%v'", str)
+		if p.err == nil {
+			p.err = fmt.Errorf("expected number; got '%v'", str)
+		}
+		return 0
 	}
 	return result
 }
@@ -191,7 +257,7 @@ type locationCache struct {
 // about 5% speed could be gained by putting the cache in the connection and
 // losing the mutex, at the cost of a small amount of memory and a somewhat
 // significant increase in code complexity.
-var globalLocationCache *locationCache = newLocationCache()
+var globalLocationCache = newLocationCache()
 
 func newLocationCache() *locationCache {
 	return &locationCache{cache: make(map[int]*time.Location)}
@@ -212,32 +278,106 @@ func (c *locationCache) getLocation(offset int) *time.Location {
 	return location
 }
 
+var infinityTsEnabled = false
+var infinityTsNegative time.Time
+var infinityTsPositive time.Time
+
+const (
+	infinityTsEnabledAlready        = "pq: infinity timestamp enabled already"
+	infinityTsNegativeMustBeSmaller = "pq: infinity timestamp: negative value must be smaller (before) than positive"
+)
+
+// EnableInfinityTs controls the handling of Postgres' "-infinity" and
+// "infinity" "timestamp"s.
+//
+// If EnableInfinityTs is not called, "-infinity" and "infinity" will return
+// []byte("-infinity") and []byte("infinity") respectively, and potentially
+// cause error "sql: Scan error on column index 0: unsupported driver -> Scan
+// pair: []uint8 -> *time.Time", when scanning into a time.Time value.
+//
+// Once EnableInfinityTs has been called, all connections created using this
+// driver will decode Postgres' "-infinity" and "infinity" for "timestamp",
+// "timestamp with time zone" and "date" types to the predefined minimum and
+// maximum times, respectively.  When encoding time.Time values, any time which
+// equals or precedes the predefined minimum time will be encoded to
+// "-infinity".  Any values at or past the maximum time will similarly be
+// encoded to "infinity".
+//
+// If EnableInfinityTs is called with negative >= positive, it will panic.
+// Calling EnableInfinityTs after a connection has been established results in
+// undefined behavior.  If EnableInfinityTs is called more than once, it will
+// panic.
+func EnableInfinityTs(negative time.Time, positive time.Time) {
+	if infinityTsEnabled {
+		panic(infinityTsEnabledAlready)
+	}
+	if !negative.Before(positive) {
+		panic(infinityTsNegativeMustBeSmaller)
+	}
+	infinityTsEnabled = true
+	infinityTsNegative = negative
+	infinityTsPositive = positive
+}
+
+/*
+ * Testing might want to toggle infinityTsEnabled
+ */
+func disableInfinityTs() {
+	infinityTsEnabled = false
+}
+
 // This is a time function specific to the Postgres default DateStyle
 // setting ("ISO, MDY"), the only one we currently support. This
 // accounts for the discrepancies between the parsing available with
 // time.Parse and the Postgres date formatting quirks.
-func parseTs(currentLocation *time.Location, str string) (result time.Time) {
+func parseTs(currentLocation *time.Location, str string) interface{} {
+	switch str {
+	case "-infinity":
+		if infinityTsEnabled {
+			return infinityTsNegative
+		}
+		return []byte(str)
+	case "infinity":
+		if infinityTsEnabled {
+			return infinityTsPositive
+		}
+		return []byte(str)
+	}
+	t, err := ParseTimestamp(currentLocation, str)
+	if err != nil {
+		panic(err)
+	}
+	return t
+}
+
+// ParseTimestamp parses Postgres' text format. It returns a time.Time in
+// currentLocation iff that time's offset agrees with the offset sent from the
+// Postgres server. Otherwise, ParseTimestamp returns a time.Time with the
+// fixed offset offset provided by the Postgres server.
+func ParseTimestamp(currentLocation *time.Location, str string) (time.Time, error) {
+	p := timestampParser{}
+
 	monSep := strings.IndexRune(str, '-')
 	// this is Gregorian year, not ISO Year
 	// In Gregorian system, the year 1 BC is followed by AD 1
-	year := mustAtoi(str[:monSep])
+	year := p.mustAtoi(str, 0, monSep)
 	daySep := monSep + 3
-	month := mustAtoi(str[monSep+1 : daySep])
-	expect(str, "-", daySep)
+	month := p.mustAtoi(str, monSep+1, daySep)
+	p.expect(str, '-', daySep)
 	timeSep := daySep + 3
-	day := mustAtoi(str[daySep+1 : timeSep])
+	day := p.mustAtoi(str, daySep+1, timeSep)
 
 	var hour, minute, second int
 	if len(str) > monSep+len("01-01")+1 {
-		expect(str, " ", timeSep)
+		p.expect(str, ' ', timeSep)
 		minSep := timeSep + 3
-		expect(str, ":", minSep)
-		hour = mustAtoi(str[timeSep+1 : minSep])
+		p.expect(str, ':', minSep)
+		hour = p.mustAtoi(str, timeSep+1, minSep)
 		secSep := minSep + 3
-		expect(str, ":", secSep)
-		minute = mustAtoi(str[minSep+1 : secSep])
+		p.expect(str, ':', secSep)
+		minute = p.mustAtoi(str, minSep+1, secSep)
 		secEnd := secSep + 3
-		second = mustAtoi(str[secSep+1 : secEnd])
+		second = p.mustAtoi(str, secSep+1, secEnd)
 	}
 	remainderIdx := monSep + len("01-01 00:00:00") + 1
 	// Three optional (but ordered) sections follow: the
@@ -248,49 +388,50 @@ func parseTs(currentLocation *time.Location, str string) (result time.Time) {
 	nanoSec := 0
 	tzOff := 0
 
-	if remainderIdx < len(str) && str[remainderIdx:remainderIdx+1] == "." {
+	if remainderIdx < len(str) && str[remainderIdx] == '.' {
 		fracStart := remainderIdx + 1
 		fracOff := strings.IndexAny(str[fracStart:], "-+ ")
 		if fracOff < 0 {
 			fracOff = len(str) - fracStart
 		}
-		fracSec := mustAtoi(str[fracStart : fracStart+fracOff])
+		fracSec := p.mustAtoi(str, fracStart, fracStart+fracOff)
 		nanoSec = fracSec * (1000000000 / int(math.Pow(10, float64(fracOff))))
 
 		remainderIdx += fracOff + 1
 	}
-	if tzStart := remainderIdx; tzStart < len(str) && (str[tzStart:tzStart+1] == "-" || str[tzStart:tzStart+1] == "+") {
+	if tzStart := remainderIdx; tzStart < len(str) && (str[tzStart] == '-' || str[tzStart] == '+') {
 		// time zone separator is always '-' or '+' (UTC is +00)
 		var tzSign int
-		if c := str[tzStart : tzStart+1]; c == "-" {
+		switch c := str[tzStart]; c {
+		case '-':
 			tzSign = -1
-		} else if c == "+" {
+		case '+':
 			tzSign = +1
-		} else {
-			errorf("expected '-' or '+' at position %v; got %v", tzStart, c)
+		default:
+			return time.Time{}, fmt.Errorf("expected '-' or '+' at position %v; got %v", tzStart, c)
 		}
-		tzHours := mustAtoi(str[tzStart+1 : tzStart+3])
+		tzHours := p.mustAtoi(str, tzStart+1, tzStart+3)
 		remainderIdx += 3
 		var tzMin, tzSec int
-		if tzStart+3 < len(str) && str[tzStart+3:tzStart+4] == ":" {
-			tzMin = mustAtoi(str[tzStart+4 : tzStart+6])
+		if remainderIdx < len(str) && str[remainderIdx] == ':' {
+			tzMin = p.mustAtoi(str, remainderIdx+1, remainderIdx+3)
 			remainderIdx += 3
 		}
-		if tzStart+6 < len(str) && str[tzStart+6:tzStart+7] == ":" {
-			tzSec = mustAtoi(str[tzStart+7 : tzStart+9])
+		if remainderIdx < len(str) && str[remainderIdx] == ':' {
+			tzSec = p.mustAtoi(str, remainderIdx+1, remainderIdx+3)
 			remainderIdx += 3
 		}
 		tzOff = tzSign * ((tzHours * 60 * 60) + (tzMin * 60) + tzSec)
 	}
 	var isoYear int
-	if remainderIdx < len(str) && str[remainderIdx:remainderIdx+3] == " BC" {
+	if remainderIdx+3 <= len(str) && str[remainderIdx:remainderIdx+3] == " BC" {
 		isoYear = 1 - year
 		remainderIdx += 3
 	} else {
 		isoYear = year
 	}
 	if remainderIdx < len(str) {
-		errorf("expected end of input, got %v", str[remainderIdx:])
+		return time.Time{}, fmt.Errorf("expected end of input, got %v", str[remainderIdx:])
 	}
 	t := time.Date(isoYear, time.Month(month), day,
 		hour, minute, second, nanoSec,
@@ -307,13 +448,26 @@ func parseTs(currentLocation *time.Location, str string) (result time.Time) {
 		}
 	}
 
-	return t
+	return t, p.err
+}
+
+// formatTs formats t into a format postgres understands.
+func formatTs(t time.Time) []byte {
+	if infinityTsEnabled {
+		// t <= -infinity : ! (t > -infinity)
+		if !t.After(infinityTsNegative) {
+			return []byte("-infinity")
+		}
+		// t >= infinity : ! (!t < infinity)
+		if !t.Before(infinityTsPositive) {
+			return []byte("infinity")
+		}
+	}
+	return FormatTimestamp(t)
 }
 
-// formatTs formats t as time.RFC3339Nano and appends time zone seconds if
-// needed.
-func formatTs(t time.Time) (b []byte) {
-	b = []byte(t.Format(time.RFC3339Nano))
+// FormatTimestamp formats t into Postgres' text format for timestamps.
+func FormatTimestamp(t time.Time) []byte {
 	// Need to send dates before 0001 A.D. with " BC" suffix, instead of the
 	// minus sign preferred by Go.
 	// Beware, "0000" in ISO is "1 BC", "-0001" is "2 BC" and so on
@@ -323,38 +477,39 @@ func formatTs(t time.Time) (b []byte) {
 		t = t.AddDate((-t.Year())*2+1, 0, 0)
 		bc = true
 	}
-	b = []byte(t.Format(time.RFC3339Nano))
-	if bc {
-		b = append(b, "  BC"...)
-	}
+	b := []byte(t.Format("2006-01-02 15:04:05.999999999Z07:00"))
 
 	_, offset := t.Zone()
 	offset = offset % 60
-	if offset == 0 {
-		return b
-	}
+	if offset != 0 {
+		// RFC3339Nano already printed the minus sign
+		if offset < 0 {
+			offset = -offset
+		}
 
-	if offset < 0 {
-		offset = -offset
+		b = append(b, ':')
+		if offset < 10 {
+			b = append(b, '0')
+		}
+		b = strconv.AppendInt(b, int64(offset), 10)
 	}
 
-	b = append(b, ':')
-	if offset < 10 {
-		b = append(b, '0')
+	if bc {
+		b = append(b, " BC"...)
 	}
-	return strconv.AppendInt(b, int64(offset), 10)
+	return b
 }
 
 // Parse a bytea value received from the server.  Both "hex" and the legacy
 // "escape" format are supported.
-func parseBytea(s []byte) (result []byte) {
+func parseBytea(s []byte) (result []byte, err error) {
 	if len(s) >= 2 && bytes.Equal(s[:2], []byte("\\x")) {
 		// bytea_output = hex
 		s = s[2:] // trim off leading "\\x"
 		result = make([]byte, hex.DecodedLen(len(s)))
 		_, err := hex.Decode(result, s)
 		if err != nil {
-			errorf("%s", err)
+			return nil, err
 		}
 	} else {
 		// bytea_output = escape
@@ -369,11 +524,11 @@ func parseBytea(s []byte) (result []byte) {
 
 				// '\\' followed by an octal number
 				if len(s) < 4 {
-					errorf("invalid bytea sequence %v", s)
+					return nil, fmt.Errorf("invalid bytea sequence %v", s)
 				}
 				r, err := strconv.ParseInt(string(s[1:4]), 8, 9)
 				if err != nil {
-					errorf("could not parse bytea value: %s", err.Error())
+					return nil, fmt.Errorf("could not parse bytea value: %s", err.Error())
 				}
 				result = append(result, byte(r))
 				s = s[4:]
@@ -391,13 +546,16 @@ func parseBytea(s []byte) (result []byte) {
 		}
 	}
 
-	return result
+	return result, nil
 }
 
 func encodeBytea(serverVersion int, v []byte) (result []byte) {
 	if serverVersion >= 90000 {
 		// Use the hex format if we know that the server supports it
-		result = []byte(fmt.Sprintf("\\x%x", v))
+		result = make([]byte, 2+hex.EncodedLen(len(v)))
+		result[0] = '\\'
+		result[1] = 'x'
+		hex.Encode(result[2:], v)
 	} else {
 		// .. or resort to "escape"
 		for _, b := range v {

+ 0 - 433
vendor/github.com/lib/pq/encode_test.go

@@ -1,433 +0,0 @@
-package pq
-
-import (
-	"github.com/lib/pq/oid"
-
-	"bytes"
-	"fmt"
-	"testing"
-	"time"
-)
-
-func TestScanTimestamp(t *testing.T) {
-	var nt NullTime
-	tn := time.Now()
-	nt.Scan(tn)
-	if !nt.Valid {
-		t.Errorf("Expected Valid=false")
-	}
-	if nt.Time != tn {
-		t.Errorf("Time value mismatch")
-	}
-}
-
-func TestScanNilTimestamp(t *testing.T) {
-	var nt NullTime
-	nt.Scan(nil)
-	if nt.Valid {
-		t.Errorf("Expected Valid=false")
-	}
-}
-
-var timeTests = []struct {
-	str     string
-	timeval time.Time
-}{
-	{"22001-02-03", time.Date(22001, time.February, 3, 0, 0, 0, 0, time.FixedZone("", 0))},
-	{"2001-02-03", time.Date(2001, time.February, 3, 0, 0, 0, 0, time.FixedZone("", 0))},
-	{"2001-02-03 04:05:06", time.Date(2001, time.February, 3, 4, 5, 6, 0, time.FixedZone("", 0))},
-	{"2001-02-03 04:05:06.000001", time.Date(2001, time.February, 3, 4, 5, 6, 1000, time.FixedZone("", 0))},
-	{"2001-02-03 04:05:06.00001", time.Date(2001, time.February, 3, 4, 5, 6, 10000, time.FixedZone("", 0))},
-	{"2001-02-03 04:05:06.0001", time.Date(2001, time.February, 3, 4, 5, 6, 100000, time.FixedZone("", 0))},
-	{"2001-02-03 04:05:06.001", time.Date(2001, time.February, 3, 4, 5, 6, 1000000, time.FixedZone("", 0))},
-	{"2001-02-03 04:05:06.01", time.Date(2001, time.February, 3, 4, 5, 6, 10000000, time.FixedZone("", 0))},
-	{"2001-02-03 04:05:06.1", time.Date(2001, time.February, 3, 4, 5, 6, 100000000, time.FixedZone("", 0))},
-	{"2001-02-03 04:05:06.12", time.Date(2001, time.February, 3, 4, 5, 6, 120000000, time.FixedZone("", 0))},
-	{"2001-02-03 04:05:06.123", time.Date(2001, time.February, 3, 4, 5, 6, 123000000, time.FixedZone("", 0))},
-	{"2001-02-03 04:05:06.1234", time.Date(2001, time.February, 3, 4, 5, 6, 123400000, time.FixedZone("", 0))},
-	{"2001-02-03 04:05:06.12345", time.Date(2001, time.February, 3, 4, 5, 6, 123450000, time.FixedZone("", 0))},
-	{"2001-02-03 04:05:06.123456", time.Date(2001, time.February, 3, 4, 5, 6, 123456000, time.FixedZone("", 0))},
-	{"2001-02-03 04:05:06.123-07", time.Date(2001, time.February, 3, 4, 5, 6, 123000000,
-		time.FixedZone("", -7*60*60))},
-	{"2001-02-03 04:05:06-07", time.Date(2001, time.February, 3, 4, 5, 6, 0,
-		time.FixedZone("", -7*60*60))},
-	{"2001-02-03 04:05:06-07:42", time.Date(2001, time.February, 3, 4, 5, 6, 0,
-		time.FixedZone("", -(7*60*60+42*60)))},
-	{"2001-02-03 04:05:06-07:30:09", 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", time.Date(2001, time.February, 3, 4, 5, 6, 0,
-		time.FixedZone("", 7*60*60))},
-	{"0011-02-03 04:05:06 BC", time.Date(-10, time.February, 3, 4, 5, 6, 0, time.FixedZone("", 0))},
-	{"0011-02-03 04:05:06.123 BC", time.Date(-10, time.February, 3, 4, 5, 6, 123000000, time.FixedZone("", 0))},
-	{"0011-02-03 04:05:06.123-07 BC", time.Date(-10, time.February, 3, 4, 5, 6, 123000000,
-		time.FixedZone("", -7*60*60))},
-	{"0001-02-03 04:05:06.123", time.Date(1, time.February, 3, 4, 5, 6, 123000000, time.FixedZone("", 0))},
-	{"0001-02-03 04:05:06.123 BC", time.Date(1, time.February, 3, 4, 5, 6, 123000000, time.FixedZone("", 0)).AddDate(-1, 0, 0)},
-	{"0001-02-03 04:05:06.123 BC", time.Date(0, time.February, 3, 4, 5, 6, 123000000, time.FixedZone("", 0))},
-	{"0002-02-03 04:05:06.123 BC", time.Date(0, time.February, 3, 4, 5, 6, 123000000, time.FixedZone("", 0)).AddDate(-1, 0, 0)},
-	{"0002-02-03 04:05:06.123 BC", time.Date(-1, time.February, 3, 4, 5, 6, 123000000, time.FixedZone("", 0))},
-	{"12345-02-03 04:05:06.1", time.Date(12345, time.February, 3, 4, 5, 6, 100000000, time.FixedZone("", 0))},
-	{"123456-02-03 04:05:06.1", time.Date(123456, time.February, 3, 4, 5, 6, 100000000, time.FixedZone("", 0))},
-}
-
-// Helper function for the two tests below
-func tryParse(str string) (t time.Time, err error) {
-	defer func() {
-		if p := recover(); p != nil {
-			err = fmt.Errorf("%v", p)
-			return
-		}
-	}()
-	t = parseTs(nil, str)
-	return
-}
-
-// Test that parsing the string results in the expected value.
-func TestParseTs(t *testing.T) {
-	for i, tt := range timeTests {
-		val, err := tryParse(tt.str)
-		if err != nil {
-			t.Errorf("%d: got error: %v", i, err)
-		} else if val.String() != tt.timeval.String() {
-			t.Errorf("%d: expected to parse %q into %q; got %q",
-				i, tt.str, tt.timeval, val)
-		}
-	}
-}
-
-// Now test that sending the value into the database and parsing it back
-// returns the same time.Time value.
-func TestEncodeAndParseTs(t *testing.T) {
-	db, err := openTestConnConninfo("timezone='Etc/UTC'")
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer db.Close()
-
-	for i, tt := range timeTests {
-		var dbstr string
-		err = db.QueryRow("SELECT ($1::timestamptz)::text", tt.timeval).Scan(&dbstr)
-		if err != nil {
-			t.Errorf("%d: could not send value %q to the database: %s", i, tt.timeval, err)
-			continue
-		}
-
-		val, err := tryParse(dbstr)
-		if err != nil {
-			t.Errorf("%d: could not parse value %q: %s", i, dbstr, err)
-			continue
-		}
-		val = val.In(tt.timeval.Location())
-		if val.String() != tt.timeval.String() {
-			t.Errorf("%d: expected to parse %q into %q; got %q", i, dbstr, tt.timeval, val)
-		}
-	}
-}
-
-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(1, time.January, 1, 0, 0, 0, 0, time.FixedZone("", 19*60+32)), "0001-01-01T00:00:00+00:19:32"},
-	{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"},
-}
-
-func TestFormatTs(t *testing.T) {
-	for i, tt := range formatTimeTests {
-		val := string(formatTs(tt.time))
-		if val != tt.expected {
-			t.Errorf("%d: incorrect time format %q, want %q", i, val, tt.expected)
-		}
-	}
-}
-
-func TestTimestampWithTimeZone(t *testing.T) {
-	db := openTestConn(t)
-	defer db.Close()
-
-	tx, err := db.Begin()
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer tx.Rollback()
-
-	// try several different locations, all included in Go's zoneinfo.zip
-	for _, locName := range []string{
-		"UTC",
-		"America/Chicago",
-		"America/New_York",
-		"Australia/Darwin",
-		"Australia/Perth",
-	} {
-		loc, err := time.LoadLocation(locName)
-		if err != nil {
-			t.Logf("Could not load time zone %s - skipping", locName)
-			continue
-		}
-
-		// Postgres timestamps have a resolution of 1 microsecond, so don't
-		// use the full range of the Nanosecond argument
-		refTime := time.Date(2012, 11, 6, 10, 23, 42, 123456000, loc)
-
-		for _, pgTimeZone := range []string{"US/Eastern", "Australia/Darwin"} {
-			// Switch Postgres's timezone to test different output timestamp formats
-			_, err = tx.Exec(fmt.Sprintf("set time zone '%s'", pgTimeZone))
-			if err != nil {
-				t.Fatal(err)
-			}
-
-			var gotTime time.Time
-			row := tx.QueryRow("select $1::timestamp with time zone", refTime)
-			err = row.Scan(&gotTime)
-			if err != nil {
-				t.Fatal(err)
-			}
-
-			if !refTime.Equal(gotTime) {
-				t.Errorf("timestamps not equal: %s != %s", refTime, gotTime)
-			}
-
-			// check that the time zone is set correctly based on TimeZone
-			pgLoc, err := time.LoadLocation(pgTimeZone)
-			if err != nil {
-				t.Logf("Could not load time zone %s - skipping", pgLoc)
-				continue
-			}
-			translated := refTime.In(pgLoc)
-			if translated.String() != gotTime.String() {
-				t.Errorf("timestamps not equal: %s != %s", translated, gotTime)
-			}
-		}
-	}
-}
-
-func TestTimestampWithOutTimezone(t *testing.T) {
-	db := openTestConn(t)
-	defer db.Close()
-
-	test := func(ts, pgts string) {
-		r, err := db.Query("SELECT $1::timestamp", pgts)
-		if err != nil {
-			t.Fatalf("Could not run query: %v", err)
-		}
-
-		n := r.Next()
-
-		if n != true {
-			t.Fatal("Expected at least one row")
-		}
-
-		var result time.Time
-		err = r.Scan(&result)
-		if err != nil {
-			t.Fatalf("Did not expect error scanning row: %v", err)
-		}
-
-		expected, err := time.Parse(time.RFC3339, ts)
-		if err != nil {
-			t.Fatalf("Could not parse test time literal: %v", err)
-		}
-
-		if !result.Equal(expected) {
-			t.Fatalf("Expected time to match %v: got mismatch %v",
-				expected, result)
-		}
-
-		n = r.Next()
-		if n != false {
-			t.Fatal("Expected only one row")
-		}
-	}
-
-	test("2000-01-01T00:00:00Z", "2000-01-01T00:00:00")
-
-	// Test higher precision time
-	test("2013-01-04T20:14:58.80033Z", "2013-01-04 20:14:58.80033")
-}
-
-func TestStringWithNul(t *testing.T) {
-	db := openTestConn(t)
-	defer db.Close()
-
-	hello0world := string("hello\x00world")
-	_, err := db.Query("SELECT $1::text", &hello0world)
-	if err == nil {
-		t.Fatal("Postgres accepts a string with nul in it; " +
-			"injection attacks may be plausible")
-	}
-}
-
-func TestByteaToText(t *testing.T) {
-	db := openTestConn(t)
-	defer db.Close()
-
-	b := []byte("hello world")
-	row := db.QueryRow("SELECT $1::text", b)
-
-	var result []byte
-	err := row.Scan(&result)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	if string(result) != string(b) {
-		t.Fatalf("expected %v but got %v", b, result)
-	}
-}
-
-func TestTextToBytea(t *testing.T) {
-	db := openTestConn(t)
-	defer db.Close()
-
-	b := "hello world"
-	row := db.QueryRow("SELECT $1::bytea", b)
-
-	var result []byte
-	err := row.Scan(&result)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	if !bytes.Equal(result, []byte(b)) {
-		t.Fatalf("expected %v but got %v", b, result)
-	}
-}
-
-func TestByteaOutputFormatEncoding(t *testing.T) {
-	input := []byte("\\x\x00\x01\x02\xFF\xFEabcdefg0123")
-	want := []byte("\\x5c78000102fffe6162636465666730313233")
-	got := encode(&parameterStatus{serverVersion: 90000}, input, oid.T_bytea)
-	if !bytes.Equal(want, got) {
-		t.Errorf("invalid hex bytea output, got %v but expected %v", got, want)
-	}
-
-	want = []byte("\\\\x\\000\\001\\002\\377\\376abcdefg0123")
-	got = encode(&parameterStatus{serverVersion: 84000}, input, oid.T_bytea)
-	if !bytes.Equal(want, got) {
-		t.Errorf("invalid escape bytea output, got %v but expected %v", got, want)
-	}
-}
-
-func TestByteaOutputFormats(t *testing.T) {
-	db := openTestConn(t)
-	defer db.Close()
-
-	if getServerVersion(t, db) < 90000 {
-		// skip
-		return
-	}
-
-	testByteaOutputFormat := func(f string) {
-		expectedData := []byte("\x5c\x78\x00\xff\x61\x62\x63\x01\x08")
-		sqlQuery := "SELECT decode('5c7800ff6162630108', 'hex')"
-
-		var data []byte
-
-		// use a txn to avoid relying on getting the same connection
-		txn, err := db.Begin()
-		if err != nil {
-			t.Fatal(err)
-		}
-		defer txn.Rollback()
-
-		_, err = txn.Exec("SET LOCAL bytea_output TO " + f)
-		if err != nil {
-			t.Fatal(err)
-		}
-		// use Query; QueryRow would hide the actual error
-		rows, err := txn.Query(sqlQuery)
-		if err != nil {
-			t.Fatal(err)
-		}
-		if !rows.Next() {
-			if rows.Err() != nil {
-				t.Fatal(rows.Err())
-			}
-			t.Fatal("shouldn't happen")
-		}
-		err = rows.Scan(&data)
-		if err != nil {
-			t.Fatal(err)
-		}
-		err = rows.Close()
-		if err != nil {
-			t.Fatal(err)
-		}
-		if !bytes.Equal(data, expectedData) {
-			t.Errorf("unexpected bytea value %v for format %s; expected %v", data, f, expectedData)
-		}
-	}
-
-	testByteaOutputFormat("hex")
-	testByteaOutputFormat("escape")
-}
-
-func TestAppendEncodedText(t *testing.T) {
-	var buf []byte
-
-	buf = appendEncodedText(&parameterStatus{serverVersion: 90000}, buf, int64(10))
-	buf = append(buf, '\t')
-	buf = appendEncodedText(&parameterStatus{serverVersion: 90000}, buf, float32(42.0000000001))
-	buf = append(buf, '\t')
-	buf = appendEncodedText(&parameterStatus{serverVersion: 90000}, buf, 42.0000000001)
-	buf = append(buf, '\t')
-	buf = appendEncodedText(&parameterStatus{serverVersion: 90000}, buf, "hello\tworld")
-	buf = append(buf, '\t')
-	buf = appendEncodedText(&parameterStatus{serverVersion: 90000}, buf, []byte{0, 128, 255})
-
-	if string(buf) != "10\t42\t42.0000000001\thello\\tworld\t\\\\x0080ff" {
-		t.Fatal(string(buf))
-	}
-}
-
-func TestAppendEscapedText(t *testing.T) {
-	if esc := appendEscapedText(nil, "hallo\tescape"); string(esc) != "hallo\\tescape" {
-		t.Fatal(string(esc))
-	}
-	if esc := appendEscapedText(nil, "hallo\\tescape\n"); string(esc) != "hallo\\\\tescape\\n" {
-		t.Fatal(string(esc))
-	}
-	if esc := appendEscapedText(nil, "\n\r\t\f"); string(esc) != "\\n\\r\\t\f" {
-		t.Fatal(string(esc))
-	}
-}
-
-func TestAppendEscapedTextExistingBuffer(t *testing.T) {
-	var buf []byte
-	buf = []byte("123\t")
-	if esc := appendEscapedText(buf, "hallo\tescape"); string(esc) != "123\thallo\\tescape" {
-		t.Fatal(string(esc))
-	}
-	buf = []byte("123\t")
-	if esc := appendEscapedText(buf, "hallo\\tescape\n"); string(esc) != "123\thallo\\\\tescape\\n" {
-		t.Fatal(string(esc))
-	}
-	buf = []byte("123\t")
-	if esc := appendEscapedText(buf, "\n\r\t\f"); string(esc) != "123\t\\n\\r\\t\f" {
-		t.Fatal(string(esc))
-	}
-}
-
-func BenchmarkAppendEscapedText(b *testing.B) {
-	longString := ""
-	for i := 0; i < 100; i++ {
-		longString += "123456789\n"
-	}
-	for i := 0; i < b.N; i++ {
-		appendEscapedText(nil, longString)
-	}
-}
-
-func BenchmarkAppendEscapedTextNoEscape(b *testing.B) {
-	longString := ""
-	for i := 0; i < 100; i++ {
-		longString += "1234567890"
-	}
-	for i := 0; i < b.N; i++ {
-		appendEscapedText(nil, longString)
-	}
-}

+ 13 - 0
vendor/github.com/lib/pq/error.go

@@ -459,6 +459,19 @@ func errorf(s string, args ...interface{}) {
 	panic(fmt.Errorf("pq: %s", fmt.Sprintf(s, args...)))
 }
 
+func errRecoverNoErrBadConn(err *error) {
+	e := recover()
+	if e == nil {
+		// Do nothing
+		return
+	}
+	var ok bool
+	*err, ok = e.(error)
+	if !ok {
+		*err = fmt.Errorf("pq: unexpected error: %#v", e)
+	}
+}
+
 func (c *conn) errRecover(err *error) {
 	e := recover()
 	switch v := e.(type) {

+ 48 - 18
vendor/github.com/lib/pq/notify.go

@@ -6,7 +6,6 @@ package pq
 import (
 	"errors"
 	"fmt"
-	"io"
 	"sync"
 	"sync/atomic"
 	"time"
@@ -63,14 +62,18 @@ type ListenerConn struct {
 
 // Creates a new ListenerConn.  Use NewListener instead.
 func NewListenerConn(name string, notificationChan chan<- *Notification) (*ListenerConn, error) {
-	cn, err := Open(name)
+	return newDialListenerConn(defaultDialer{}, name, notificationChan)
+}
+
+func newDialListenerConn(d Dialer, name string, c chan<- *Notification) (*ListenerConn, error) {
+	cn, err := DialOpen(d, name)
 	if err != nil {
 		return nil, err
 	}
 
 	l := &ListenerConn{
 		cn:               cn.(*conn),
-		notificationChan: notificationChan,
+		notificationChan: c,
 		connState:        connStateIdle,
 		replyChan:        make(chan message, 2),
 	}
@@ -87,12 +90,16 @@ func NewListenerConn(name string, notificationChan chan<- *Notification) (*Liste
 // Returns an error if an unrecoverable error has occurred and the ListenerConn
 // should be abandoned.
 func (l *ListenerConn) acquireSenderLock() error {
+	// we must acquire senderLock first to avoid deadlocks; see ExecSimpleQuery
+	l.senderLock.Lock()
+
 	l.connectionLock.Lock()
-	defer l.connectionLock.Unlock()
-	if l.err != nil {
-		return l.err
+	err := l.err
+	l.connectionLock.Unlock()
+	if err != nil {
+		l.senderLock.Unlock()
+		return err
 	}
-	l.senderLock.Lock()
 	return nil
 }
 
@@ -125,7 +132,7 @@ func (l *ListenerConn) setState(newState int32) bool {
 // away or should be discarded because we couldn't agree on the state with the
 // server backend.
 func (l *ListenerConn) listenerConnLoop() (err error) {
-	defer l.cn.errRecover(&err)
+	defer errRecoverNoErrBadConn(&err)
 
 	r := &readBuf{}
 	for {
@@ -140,6 +147,9 @@ func (l *ListenerConn) listenerConnLoop() (err error) {
 			// about the scratch buffer being overwritten.
 			l.notificationChan <- recvNotification(r)
 
+		case 'T', 'D':
+			// only used by tests; ignore
+
 		case 'E':
 			// We might receive an ErrorResponse even when not in a query; it
 			// is expected that the server will close the connection after
@@ -238,7 +248,7 @@ func (l *ListenerConn) Ping() error {
 // The caller must be holding senderLock (see acquireSenderLock and
 // releaseSenderLock).
 func (l *ListenerConn) sendSimpleQuery(q string) (err error) {
-	defer l.cn.errRecover(&err)
+	defer errRecoverNoErrBadConn(&err)
 
 	// must set connection state before sending the query
 	if !l.setState(connStateExpectResponse) {
@@ -247,8 +257,10 @@ func (l *ListenerConn) sendSimpleQuery(q string) (err error) {
 
 	// Can't use l.cn.writeBuf here because it uses the scratch buffer which
 	// might get overwritten by listenerConnLoop.
-	data := writeBuf([]byte("Q\x00\x00\x00\x00"))
-	b := &data
+	b := &writeBuf{
+		buf: []byte("Q\x00\x00\x00\x00"),
+		pos: 1,
+	}
 	b.string(q)
 	l.cn.send(b)
 
@@ -277,13 +289,13 @@ func (l *ListenerConn) ExecSimpleQuery(q string) (executed bool, err error) {
 		// We can't know what state the protocol is in, so we need to abandon
 		// this connection.
 		l.connectionLock.Lock()
-		defer l.connectionLock.Unlock()
 		// Set the error pointer if it hasn't been set already; see
 		// listenerConnMain.
 		if l.err == nil {
 			l.err = err
 		}
-		l.cn.Close()
+		l.connectionLock.Unlock()
+		l.cn.c.Close()
 		return false, err
 	}
 
@@ -292,8 +304,11 @@ func (l *ListenerConn) ExecSimpleQuery(q string) (executed bool, err error) {
 		m, ok := <-l.replyChan
 		if !ok {
 			// We lost the connection to server, don't bother waiting for a
-			// a response.
-			return false, io.EOF
+			// a response.  err should have been set already.
+			l.connectionLock.Lock()
+			err := l.err
+			l.connectionLock.Unlock()
+			return false, err
 		}
 		switch m.typ {
 		case 'Z':
@@ -320,12 +335,15 @@ func (l *ListenerConn) ExecSimpleQuery(q string) (executed bool, err error) {
 
 func (l *ListenerConn) Close() error {
 	l.connectionLock.Lock()
-	defer l.connectionLock.Unlock()
 	if l.err != nil {
+		l.connectionLock.Unlock()
 		return errListenerConnClosed
 	}
 	l.err = errListenerConnClosed
-	return l.cn.Close()
+	l.connectionLock.Unlock()
+	// We can't send anything on the connection without holding senderLock.
+	// Simply close the net.Conn to wake up everyone operating on it.
+	return l.cn.c.Close()
 }
 
 // Err() returns the reason the connection was closed.  It is not safe to call
@@ -377,6 +395,7 @@ type Listener struct {
 	name                 string
 	minReconnectInterval time.Duration
 	maxReconnectInterval time.Duration
+	dialer               Dialer
 	eventCallback        EventCallbackType
 
 	lock                 sync.Mutex
@@ -407,10 +426,21 @@ func NewListener(name string,
 	minReconnectInterval time.Duration,
 	maxReconnectInterval time.Duration,
 	eventCallback EventCallbackType) *Listener {
+	return NewDialListener(defaultDialer{}, name, minReconnectInterval, maxReconnectInterval, eventCallback)
+}
+
+// NewDialListener is like NewListener but it takes a Dialer.
+func NewDialListener(d Dialer,
+	name string,
+	minReconnectInterval time.Duration,
+	maxReconnectInterval time.Duration,
+	eventCallback EventCallbackType) *Listener {
+
 	l := &Listener{
 		name:                 name,
 		minReconnectInterval: minReconnectInterval,
 		maxReconnectInterval: maxReconnectInterval,
+		dialer:               d,
 		eventCallback:        eventCallback,
 
 		channels: make(map[string]struct{}),
@@ -646,7 +676,7 @@ func (l *Listener) closed() bool {
 
 func (l *Listener) connect() error {
 	notificationChan := make(chan *Notification, 32)
-	cn, err := NewListenerConn(l.name, notificationChan)
+	cn, err := newDialListenerConn(l.dialer, l.name, notificationChan)
 	if err != nil {
 		return err
 	}

+ 0 - 502
vendor/github.com/lib/pq/notify_test.go

@@ -1,502 +0,0 @@
-package pq
-
-import (
-	"errors"
-	"fmt"
-	"io"
-	"os"
-	"testing"
-	"time"
-)
-
-var errNilNotification = errors.New("nil notification")
-
-func expectNotification(t *testing.T, ch <-chan *Notification, relname string, extra string) error {
-	select {
-	case n := <-ch:
-		if n == nil {
-			return errNilNotification
-		}
-		if n.Channel != relname || n.Extra != extra {
-			return fmt.Errorf("unexpected notification %v", n)
-		}
-		return nil
-	case <-time.After(1500 * time.Millisecond):
-		return fmt.Errorf("timeout")
-	}
-}
-
-func expectNoNotification(t *testing.T, ch <-chan *Notification) error {
-	select {
-	case n := <-ch:
-		return fmt.Errorf("unexpected notification %v", n)
-	case <-time.After(100 * time.Millisecond):
-		return nil
-	}
-}
-
-func expectEvent(t *testing.T, eventch <-chan ListenerEventType, et ListenerEventType) error {
-	select {
-	case e := <-eventch:
-		if e != et {
-			return fmt.Errorf("unexpected event %v", e)
-		}
-		return nil
-	case <-time.After(1500 * time.Millisecond):
-		return fmt.Errorf("timeout")
-	}
-}
-
-func expectNoEvent(t *testing.T, eventch <-chan ListenerEventType) error {
-	select {
-	case e := <-eventch:
-		return fmt.Errorf("unexpected event %v", e)
-	case <-time.After(100 * time.Millisecond):
-		return nil
-	}
-}
-
-func newTestListenerConn(t *testing.T) (*ListenerConn, <-chan *Notification) {
-	datname := os.Getenv("PGDATABASE")
-	sslmode := os.Getenv("PGSSLMODE")
-
-	if datname == "" {
-		os.Setenv("PGDATABASE", "pqgotest")
-	}
-
-	if sslmode == "" {
-		os.Setenv("PGSSLMODE", "disable")
-	}
-
-	notificationChan := make(chan *Notification)
-	l, err := NewListenerConn("", notificationChan)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	return l, notificationChan
-}
-
-func TestNewListenerConn(t *testing.T) {
-	l, _ := newTestListenerConn(t)
-
-	defer l.Close()
-}
-
-func TestConnListen(t *testing.T) {
-	l, channel := newTestListenerConn(t)
-
-	defer l.Close()
-
-	db := openTestConn(t)
-	defer db.Close()
-
-	ok, err := l.Listen("notify_test")
-	if !ok || err != nil {
-		t.Fatal(err)
-	}
-
-	_, err = db.Exec("NOTIFY notify_test")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	err = expectNotification(t, channel, "notify_test", "")
-	if err != nil {
-		t.Fatal(err)
-	}
-}
-
-func TestConnUnlisten(t *testing.T) {
-	l, channel := newTestListenerConn(t)
-
-	defer l.Close()
-
-	db := openTestConn(t)
-	defer db.Close()
-
-	ok, err := l.Listen("notify_test")
-	if !ok || err != nil {
-		t.Fatal(err)
-	}
-
-	_, err = db.Exec("NOTIFY notify_test")
-
-	err = expectNotification(t, channel, "notify_test", "")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	ok, err = l.Unlisten("notify_test")
-	if !ok || err != nil {
-		t.Fatal(err)
-	}
-
-	_, err = db.Exec("NOTIFY notify_test")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	err = expectNoNotification(t, channel)
-	if err != nil {
-		t.Fatal(err)
-	}
-}
-
-func TestConnUnlistenAll(t *testing.T) {
-	l, channel := newTestListenerConn(t)
-
-	defer l.Close()
-
-	db := openTestConn(t)
-	defer db.Close()
-
-	ok, err := l.Listen("notify_test")
-	if !ok || err != nil {
-		t.Fatal(err)
-	}
-
-	_, err = db.Exec("NOTIFY notify_test")
-
-	err = expectNotification(t, channel, "notify_test", "")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	ok, err = l.UnlistenAll()
-	if !ok || err != nil {
-		t.Fatal(err)
-	}
-
-	_, err = db.Exec("NOTIFY notify_test")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	err = expectNoNotification(t, channel)
-	if err != nil {
-		t.Fatal(err)
-	}
-}
-
-func TestConnClose(t *testing.T) {
-	l, _ := newTestListenerConn(t)
-	defer l.Close()
-
-	err := l.Close()
-	if err != nil {
-		t.Fatal(err)
-	}
-	err = l.Close()
-	if err != errListenerConnClosed {
-		t.Fatalf("expected errListenerConnClosed; got %v", err)
-	}
-}
-
-func TestConnPing(t *testing.T) {
-	l, _ := newTestListenerConn(t)
-	defer l.Close()
-	err := l.Ping()
-	if err != nil {
-		t.Fatal(err)
-	}
-	err = l.Close()
-	if err != nil {
-		t.Fatal(err)
-	}
-	err = l.Ping()
-	if err != errListenerConnClosed {
-		t.Fatalf("expected errListenerConnClosed; got %v", err)
-	}
-}
-
-func TestNotifyExtra(t *testing.T) {
-	db := openTestConn(t)
-	defer db.Close()
-
-	if getServerVersion(t, db) < 90000 {
-		t.Skip("skipping NOTIFY payload test since the server does not appear to support it")
-	}
-
-	l, channel := newTestListenerConn(t)
-	defer l.Close()
-
-	ok, err := l.Listen("notify_test")
-	if !ok || err != nil {
-		t.Fatal(err)
-	}
-
-	_, err = db.Exec("NOTIFY notify_test, 'something'")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	err = expectNotification(t, channel, "notify_test", "something")
-	if err != nil {
-		t.Fatal(err)
-	}
-}
-
-// create a new test listener and also set the timeouts
-func newTestListenerTimeout(t *testing.T, min time.Duration, max time.Duration) (*Listener, <-chan ListenerEventType) {
-	datname := os.Getenv("PGDATABASE")
-	sslmode := os.Getenv("PGSSLMODE")
-
-	if datname == "" {
-		os.Setenv("PGDATABASE", "pqgotest")
-	}
-
-	if sslmode == "" {
-		os.Setenv("PGSSLMODE", "disable")
-	}
-
-	eventch := make(chan ListenerEventType, 16)
-	l := NewListener("", min, max, func(t ListenerEventType, err error) { eventch <- t })
-	err := expectEvent(t, eventch, ListenerEventConnected)
-	if err != nil {
-		t.Fatal(err)
-	}
-	return l, eventch
-}
-
-func newTestListener(t *testing.T) (*Listener, <-chan ListenerEventType) {
-	return newTestListenerTimeout(t, time.Hour, time.Hour)
-}
-
-func TestListenerListen(t *testing.T) {
-	l, _ := newTestListener(t)
-	defer l.Close()
-
-	db := openTestConn(t)
-	defer db.Close()
-
-	err := l.Listen("notify_listen_test")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	_, err = db.Exec("NOTIFY notify_listen_test")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	err = expectNotification(t, l.Notify, "notify_listen_test", "")
-	if err != nil {
-		t.Fatal(err)
-	}
-}
-
-func TestListenerUnlisten(t *testing.T) {
-	l, _ := newTestListener(t)
-	defer l.Close()
-
-	db := openTestConn(t)
-	defer db.Close()
-
-	err := l.Listen("notify_listen_test")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	_, err = db.Exec("NOTIFY notify_listen_test")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	err = l.Unlisten("notify_listen_test")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	err = expectNotification(t, l.Notify, "notify_listen_test", "")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	_, err = db.Exec("NOTIFY notify_listen_test")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	err = expectNoNotification(t, l.Notify)
-	if err != nil {
-		t.Fatal(err)
-	}
-}
-
-func TestListenerUnlistenAll(t *testing.T) {
-	l, _ := newTestListener(t)
-	defer l.Close()
-
-	db := openTestConn(t)
-	defer db.Close()
-
-	err := l.Listen("notify_listen_test")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	_, err = db.Exec("NOTIFY notify_listen_test")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	err = l.UnlistenAll()
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	err = expectNotification(t, l.Notify, "notify_listen_test", "")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	_, err = db.Exec("NOTIFY notify_listen_test")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	err = expectNoNotification(t, l.Notify)
-	if err != nil {
-		t.Fatal(err)
-	}
-}
-
-func TestListenerFailedQuery(t *testing.T) {
-	l, eventch := newTestListener(t)
-	defer l.Close()
-
-	db := openTestConn(t)
-	defer db.Close()
-
-	err := l.Listen("notify_listen_test")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	_, err = db.Exec("NOTIFY notify_listen_test")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	err = expectNotification(t, l.Notify, "notify_listen_test", "")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	// shouldn't cause a disconnect
-	ok, err := l.cn.ExecSimpleQuery("SELECT error")
-	if !ok {
-		t.Fatalf("could not send query to server: %v", err)
-	}
-	_, ok = err.(PGError)
-	if !ok {
-		t.Fatalf("unexpected error %v", err)
-	}
-	err = expectNoEvent(t, eventch)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	// should still work
-	_, err = db.Exec("NOTIFY notify_listen_test")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	err = expectNotification(t, l.Notify, "notify_listen_test", "")
-	if err != nil {
-		t.Fatal(err)
-	}
-}
-
-func TestListenerReconnect(t *testing.T) {
-	l, eventch := newTestListenerTimeout(t, 20*time.Millisecond, time.Hour)
-	defer l.Close()
-
-	db := openTestConn(t)
-	defer db.Close()
-
-	err := l.Listen("notify_listen_test")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	_, err = db.Exec("NOTIFY notify_listen_test")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	err = expectNotification(t, l.Notify, "notify_listen_test", "")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	// kill the connection and make sure it comes back up
-	ok, err := l.cn.ExecSimpleQuery("SELECT pg_terminate_backend(pg_backend_pid())")
-	if ok {
-		t.Fatalf("could not kill the connection: %v", err)
-	}
-	if err != io.EOF {
-		t.Fatalf("unexpected error %v", err)
-	}
-	err = expectEvent(t, eventch, ListenerEventDisconnected)
-	if err != nil {
-		t.Fatal(err)
-	}
-	err = expectEvent(t, eventch, ListenerEventReconnected)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	// should still work
-	_, err = db.Exec("NOTIFY notify_listen_test")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	// should get nil after Reconnected
-	err = expectNotification(t, l.Notify, "", "")
-	if err != errNilNotification {
-		t.Fatal(err)
-	}
-
-	err = expectNotification(t, l.Notify, "notify_listen_test", "")
-	if err != nil {
-		t.Fatal(err)
-	}
-}
-
-func TestListenerClose(t *testing.T) {
-	l, _ := newTestListenerTimeout(t, 20*time.Millisecond, time.Hour)
-	defer l.Close()
-
-	err := l.Close()
-	if err != nil {
-		t.Fatal(err)
-	}
-	err = l.Close()
-	if err != errListenerClosed {
-		t.Fatalf("expected errListenerClosed; got %v", err)
-	}
-}
-
-func TestListenerPing(t *testing.T) {
-	l, _ := newTestListenerTimeout(t, 20*time.Millisecond, time.Hour)
-	defer l.Close()
-
-	err := l.Ping()
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	err = l.Close()
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	err = l.Ping()
-	if err != errListenerClosed {
-		t.Fatalf("expected errListenerClosed; got %v", err)
-	}
-}

+ 158 - 0
vendor/github.com/lib/pq/ssl.go

@@ -0,0 +1,158 @@
+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["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 sslrootcert, ok := o["sslrootcert"]; ok {
+			if _, err := os.Stat(sslrootcert); err == nil {
+				verifyCaOnly = true
+			} else {
+				delete(o, "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["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) {
+	// user.Current() might fail when cross-compiling. We have to ignore the
+	// error and continue without home directory defaults, since we wouldn't
+	// know from where to load them.
+	user, _ := user.Current()
+
+	// In libpq, the client certificate is only loaded if the setting is not blank.
+	//
+	// https://github.com/postgres/postgres/blob/REL9_6_2/src/interfaces/libpq/fe-secure-openssl.c#L1036-L1037
+	sslcert := o["sslcert"]
+	if len(sslcert) == 0 && user != nil {
+		sslcert = filepath.Join(user.HomeDir, ".postgresql", "postgresql.crt")
+	}
+	// https://github.com/postgres/postgres/blob/REL9_6_2/src/interfaces/libpq/fe-secure-openssl.c#L1045
+	if len(sslcert) == 0 {
+		return
+	}
+	// https://github.com/postgres/postgres/blob/REL9_6_2/src/interfaces/libpq/fe-secure-openssl.c#L1050:L1054
+	if _, err := os.Stat(sslcert); os.IsNotExist(err) {
+		return
+	} else if err != nil {
+		panic(err)
+	}
+
+	// In libpq, the ssl key is only loaded if the setting is not blank.
+	//
+	// https://github.com/postgres/postgres/blob/REL9_6_2/src/interfaces/libpq/fe-secure-openssl.c#L1123-L1222
+	sslkey := o["sslkey"]
+	if len(sslkey) == 0 && user != nil {
+		sslkey = filepath.Join(user.HomeDir, ".postgresql", "postgresql.key")
+	}
+
+	if len(sslkey) > 0 {
+		if err := sslKeyPermissions(sslkey); err != nil {
+			panic(err)
+		}
+	}
+
+	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) {
+	// In libpq, the root certificate is only loaded if the setting is not blank.
+	//
+	// https://github.com/postgres/postgres/blob/REL9_6_2/src/interfaces/libpq/fe-secure-openssl.c#L950-L951
+	if sslrootcert := o["sslrootcert"]; len(sslrootcert) > 0 {
+		tlsConf.RootCAs = x509.NewCertPool()
+
+		cert, err := ioutil.ReadFile(sslrootcert)
+		if err != nil {
+			panic(err)
+		}
+
+		if !tlsConf.RootCAs.AppendCertsFromPEM(cert) {
+			errorf("couldn't parse pem in sslrootcert")
+		}
+	}
+}
+
+// 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)
+	}
+}

+ 14 - 0
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
+}

+ 20 - 0
vendor/github.com/lib/pq/ssl_permissions.go

@@ -0,0 +1,20 @@
+// +build !windows
+
+package pq
+
+import "os"
+
+// sslKeyPermissions checks the permissions on user-supplied ssl key files.
+// The key file should have very little access.
+//
+// libpq does not check key file permissions on Windows.
+func sslKeyPermissions(sslkey string) error {
+	info, err := os.Stat(sslkey)
+	if err != nil {
+		return err
+	}
+	if info.Mode().Perm()&0077 != 0 {
+		return ErrSSLKeyHasWorldPermissions
+	}
+	return nil
+}

+ 8 - 0
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) {}

+ 0 - 226
vendor/github.com/lib/pq/ssl_test.go

@@ -1,226 +0,0 @@
-package pq
-
-// This file contains SSL tests
-
-import (
-	_ "crypto/sha256"
-	"crypto/x509"
-	"database/sql"
-	"fmt"
-	"os"
-	"path/filepath"
-	"testing"
-)
-
-func maybeSkipSSLTests(t *testing.T) {
-	// Require some special variables for testing certificates
-	if os.Getenv("PQSSLCERTTEST_PATH") == "" {
-		t.Skip("PQSSLCERTTEST_PATH not set, skipping SSL tests")
-	}
-
-	value := os.Getenv("PQGOSSLTESTS")
-	if value == "" || value == "0" {
-		t.Skip("PQGOSSLTESTS not enabled, skipping SSL tests")
-	} else if value != "1" {
-		t.Fatalf("unexpected value %q for PQGOSSLTESTS", value)
-	}
-}
-
-func openSSLConn(t *testing.T, conninfo string) (*sql.DB, error) {
-	db, err := openTestConnConninfo(conninfo)
-	if err != nil {
-		// should never fail
-		t.Fatal(err)
-	}
-	// Do something with the connection to see whether it's working or not.
-	tx, err := db.Begin()
-	if err == nil {
-		return db, tx.Rollback()
-	}
-	_ = db.Close()
-	return nil, err
-}
-
-func checkSSLSetup(t *testing.T, conninfo string) {
-	db, err := openSSLConn(t, conninfo)
-	if err == nil {
-		db.Close()
-		t.Fatalf("expected error with conninfo=%q", conninfo)
-	}
-}
-
-// Connect over SSL and run a simple query to test the basics
-func TestSSLConnection(t *testing.T) {
-	maybeSkipSSLTests(t)
-	// Environment sanity check: should fail without SSL
-	checkSSLSetup(t, "sslmode=disable user=pqgossltest")
-
-	db, err := openSSLConn(t, "sslmode=require user=pqgossltest")
-	if err != nil {
-		t.Fatal(err)
-	}
-	rows, err := db.Query("SELECT 1")
-	if err != nil {
-		t.Fatal(err)
-	}
-	rows.Close()
-}
-
-// Test sslmode=verify-full
-func TestSSLVerifyFull(t *testing.T) {
-	maybeSkipSSLTests(t)
-	// Environment sanity check: should fail without SSL
-	checkSSLSetup(t, "sslmode=disable user=pqgossltest")
-
-	// Not OK according to the system CA
-	_, err := openSSLConn(t, "host=postgres sslmode=verify-full user=pqgossltest")
-	if err == nil {
-		t.Fatal("expected error")
-	}
-	_, ok := err.(x509.UnknownAuthorityError)
-	if !ok {
-		t.Fatalf("expected x509.UnknownAuthorityError, got %#+v", err)
-	}
-
-	rootCertPath := filepath.Join(os.Getenv("PQSSLCERTTEST_PATH"), "root.crt")
-	rootCert := "sslrootcert=" + rootCertPath + " "
-	// No match on Common Name
-	_, err = openSSLConn(t, rootCert+"host=127.0.0.1 sslmode=verify-full user=pqgossltest")
-	if err == nil {
-		t.Fatal("expected error")
-	}
-	_, ok = err.(x509.HostnameError)
-	if !ok {
-		t.Fatalf("expected x509.HostnameError, got %#+v", err)
-	}
-	// OK
-	_, err = openSSLConn(t, rootCert+"host=postgres sslmode=verify-full user=pqgossltest")
-	if err != nil {
-		t.Fatal(err)
-	}
-}
-
-// Test sslmode=verify-ca
-func TestSSLVerifyCA(t *testing.T) {
-	maybeSkipSSLTests(t)
-	// Environment sanity check: should fail without SSL
-	checkSSLSetup(t, "sslmode=disable user=pqgossltest")
-
-	// Not OK according to the system CA
-	_, err := openSSLConn(t, "host=postgres sslmode=verify-ca user=pqgossltest")
-	if err == nil {
-		t.Fatal("expected error")
-	}
-	_, ok := err.(x509.UnknownAuthorityError)
-	if !ok {
-		t.Fatalf("expected x509.UnknownAuthorityError, got %#+v", err)
-	}
-
-	rootCertPath := filepath.Join(os.Getenv("PQSSLCERTTEST_PATH"), "root.crt")
-	rootCert := "sslrootcert=" + rootCertPath + " "
-	// No match on Common Name, but that's OK
-	_, err = openSSLConn(t, rootCert+"host=127.0.0.1 sslmode=verify-ca user=pqgossltest")
-	if err != nil {
-		t.Fatal(err)
-	}
-	// Everything OK
-	_, err = openSSLConn(t, rootCert+"host=postgres sslmode=verify-ca user=pqgossltest")
-	if err != nil {
-		t.Fatal(err)
-	}
-}
-
-func getCertConninfo(t *testing.T, source string) string {
-	var sslkey string
-	var sslcert string
-
-	certpath := os.Getenv("PQSSLCERTTEST_PATH")
-
-	switch source {
-	case "missingkey":
-		sslkey = "/tmp/filedoesnotexist"
-		sslcert = filepath.Join(certpath, "postgresql.crt")
-	case "missingcert":
-		sslkey = filepath.Join(certpath, "postgresql.key")
-		sslcert = "/tmp/filedoesnotexist"
-	case "certtwice":
-		sslkey = filepath.Join(certpath, "postgresql.crt")
-		sslcert = filepath.Join(certpath, "postgresql.crt")
-	case "valid":
-		sslkey = filepath.Join(certpath, "postgresql.key")
-		sslcert = filepath.Join(certpath, "postgresql.crt")
-	default:
-		t.Fatalf("invalid source %q", source)
-	}
-	return fmt.Sprintf("sslmode=require user=pqgosslcert sslkey=%s sslcert=%s", sslkey, sslcert)
-}
-
-// Authenticate over SSL using client certificates
-func TestSSLClientCertificates(t *testing.T) {
-	maybeSkipSSLTests(t)
-	// Environment sanity check: should fail without SSL
-	checkSSLSetup(t, "sslmode=disable user=pqgossltest")
-
-	// Should also fail without a valid certificate
-	db, err := openSSLConn(t, "sslmode=require user=pqgosslcert")
-	if err == nil {
-		db.Close()
-		t.Fatal("expected error")
-	}
-	pge, ok := err.(*Error)
-	if !ok {
-		t.Fatal("expected pq.Error")
-	}
-	if pge.Code.Name() != "invalid_authorization_specification" {
-		t.Fatalf("unexpected error code %q", pge.Code.Name())
-	}
-
-	// Should work
-	db, err = openSSLConn(t, getCertConninfo(t, "valid"))
-	if err != nil {
-		t.Fatal(err)
-	}
-	rows, err := db.Query("SELECT 1")
-	if err != nil {
-		t.Fatal(err)
-	}
-	rows.Close()
-}
-
-// Test errors with ssl certificates
-func TestSSLClientCertificatesMissingFiles(t *testing.T) {
-	maybeSkipSSLTests(t)
-	// Environment sanity check: should fail without SSL
-	checkSSLSetup(t, "sslmode=disable user=pqgossltest")
-
-	// Key missing, should fail
-	_, err := openSSLConn(t, getCertConninfo(t, "missingkey"))
-	if err == nil {
-		t.Fatal("expected error")
-	}
-	// should be a PathError
-	_, ok := err.(*os.PathError)
-	if !ok {
-		t.Fatalf("expected PathError, got %#+v", err)
-	}
-
-	// Cert missing, should fail
-	_, err = openSSLConn(t, getCertConninfo(t, "missingcert"))
-	if err == nil {
-		t.Fatal("expected error")
-	}
-	// should be a PathError
-	_, ok = err.(*os.PathError)
-	if !ok {
-		t.Fatalf("expected PathError, got %#+v", err)
-	}
-
-	// Key has wrong permissions, should fail
-	_, err = openSSLConn(t, getCertConninfo(t, "certtwice"))
-	if err == nil {
-		t.Fatal("expected error")
-	}
-	if err != ErrSSLKeyHasWorldPermissions {
-		t.Fatalf("expected ErrSSLKeyHasWorldPermissions, got %#+v", err)
-	}
-}

+ 9 - 0
vendor/github.com/lib/pq/ssl_windows.go

@@ -0,0 +1,9 @@
+// +build windows
+
+package pq
+
+// sslKeyPermissions checks the permissions on user-supplied ssl key files.
+// The key file should have very little access.
+//
+// libpq does not check key file permissions on Windows.
+func sslKeyPermissions(string) error { return nil }

+ 5 - 5
vendor/github.com/lib/pq/url.go

@@ -2,6 +2,7 @@ package pq
 
 import (
 	"fmt"
+	"net"
 	nurl "net/url"
 	"sort"
 	"strings"
@@ -34,7 +35,7 @@ func ParseURL(url string) (string, error) {
 		return "", err
 	}
 
-	if u.Scheme != "postgres" {
+	if u.Scheme != "postgres" && u.Scheme != "postgresql" {
 		return "", fmt.Errorf("invalid connection protocol: %s", u.Scheme)
 	}
 
@@ -54,12 +55,11 @@ func ParseURL(url string) (string, error) {
 		accrue("password", v)
 	}
 
-	i := strings.Index(u.Host, ":")
-	if i < 0 {
+	if host, port, err := net.SplitHostPort(u.Host); err != nil {
 		accrue("host", u.Host)
 	} else {
-		accrue("host", u.Host[:i])
-		accrue("port", u.Host[i+1:])
+		accrue("host", host)
+		accrue("port", port)
 	}
 
 	if u.Path != "" {

+ 0 - 54
vendor/github.com/lib/pq/url_test.go

@@ -1,54 +0,0 @@
-package pq
-
-import (
-	"testing"
-)
-
-func TestSimpleParseURL(t *testing.T) {
-	expected := "host=hostname.remote"
-	str, err := ParseURL("postgres://hostname.remote")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	if str != expected {
-		t.Fatalf("unexpected result from ParseURL:\n+ %v\n- %v", str, expected)
-	}
-}
-
-func TestFullParseURL(t *testing.T) {
-	expected := `dbname=database host=hostname.remote password=top\ secret port=1234 user=username`
-	str, err := ParseURL("postgres://username:top%20secret@hostname.remote:1234/database")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	if str != expected {
-		t.Fatalf("unexpected result from ParseURL:\n+ %s\n- %s", str, expected)
-	}
-}
-
-func TestInvalidProtocolParseURL(t *testing.T) {
-	_, err := ParseURL("http://hostname.remote")
-	switch err {
-	case nil:
-		t.Fatal("Expected an error from parsing invalid protocol")
-	default:
-		msg := "invalid connection protocol: http"
-		if err.Error() != msg {
-			t.Fatalf("Unexpected error message:\n+ %s\n- %s",
-				err.Error(), msg)
-		}
-	}
-}
-
-func TestMinimalURL(t *testing.T) {
-	cs, err := ParseURL("postgres://")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	if cs != "" {
-		t.Fatalf("expected blank connection string, got: %q", cs)
-	}
-}

+ 1 - 1
vendor/github.com/lib/pq/user_posix.go

@@ -1,6 +1,6 @@
 // Package pq is a pure Go Postgres driver for the database/sql package.
 
-// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris rumprun
 
 package pq
 

+ 23 - 0
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
+}

+ 6 - 0
vendor/vendor.json

@@ -448,6 +448,12 @@
 			"revision": "1bab8b35b6bb565f92cbc97939610af9369f942a",
 			"revisionTime": "2017-02-10T14:05:23Z"
 		},
+		{
+			"checksumSHA1": "ZAj/o03zG8Ui4mZ4XmzU4yyKC04=",
+			"path": "github.com/lib/pq",
+			"revision": "dd1fe2071026ce53f36a39112e645b4d4f5793a4",
+			"revisionTime": "2017-07-07T05:36:02Z"
+		},
 		{
 			"checksumSHA1": "8z32QKTSDusa4QQyunKE4kyYXZ8=",
 			"path": "github.com/patrickmn/go-cache",

Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików