updated postgres dependency to fix #1259
This commit is contained in:
parent
d85fd78bf1
commit
56ba42d9a9
27 changed files with 2196 additions and 517 deletions
11
vendor/github.com/lib/pq/README.md
generated
vendored
11
vendor/github.com/lib/pq/README.md
generated
vendored
|
@ -55,9 +55,15 @@ code still exists in here.
|
||||||
* Bjørn Madsen (aeons)
|
* Bjørn Madsen (aeons)
|
||||||
* Blake Gentry (bgentry)
|
* Blake Gentry (bgentry)
|
||||||
* Brad Fitzpatrick (bradfitz)
|
* Brad Fitzpatrick (bradfitz)
|
||||||
|
* Charlie Melbye (cmelbye)
|
||||||
|
* Chris Bandy (cbandy)
|
||||||
|
* Chris Gilling (cgilling)
|
||||||
* Chris Walsh (cwds)
|
* Chris Walsh (cwds)
|
||||||
|
* Dan Sosedoff (sosedoff)
|
||||||
* Daniel Farina (fdr)
|
* Daniel Farina (fdr)
|
||||||
* Eric Chlebek (echlebek)
|
* Eric Chlebek (echlebek)
|
||||||
|
* Eric Garrido (minusnine)
|
||||||
|
* Eric Urban (hydrogen18)
|
||||||
* Everyone at The Go Team
|
* Everyone at The Go Team
|
||||||
* Evan Shaw (edsrzf)
|
* Evan Shaw (edsrzf)
|
||||||
* Ewan Chou (coocood)
|
* Ewan Chou (coocood)
|
||||||
|
@ -65,10 +71,12 @@ code still exists in here.
|
||||||
* Fumin (fumin)
|
* Fumin (fumin)
|
||||||
* Gary Burd (garyburd)
|
* Gary Burd (garyburd)
|
||||||
* Heroku (heroku)
|
* Heroku (heroku)
|
||||||
|
* James Pozdena (jpoz)
|
||||||
* Jason McVetta (jmcvetta)
|
* Jason McVetta (jmcvetta)
|
||||||
* Jeremy Jay (pbnjay)
|
* Jeremy Jay (pbnjay)
|
||||||
* Joakim Sernbrant (serbaut)
|
* Joakim Sernbrant (serbaut)
|
||||||
* John Gallagher (jgallagher)
|
* John Gallagher (jgallagher)
|
||||||
|
* Jonathan Rudenberg (titanous)
|
||||||
* Joël Stemmer (jstemmer)
|
* Joël Stemmer (jstemmer)
|
||||||
* Kamil Kisiel (kisielk)
|
* Kamil Kisiel (kisielk)
|
||||||
* Kelly Dunn (kellydunn)
|
* Kelly Dunn (kellydunn)
|
||||||
|
@ -89,4 +97,7 @@ code still exists in here.
|
||||||
* Ryan Smith (ryandotsmith)
|
* Ryan Smith (ryandotsmith)
|
||||||
* Samuel Stauffer (samuel)
|
* Samuel Stauffer (samuel)
|
||||||
* Timothée Peignier (cyberdelia)
|
* Timothée Peignier (cyberdelia)
|
||||||
|
* Travis Cline (tmc)
|
||||||
|
* TruongSinh Tran-Nguyen (truongsinh)
|
||||||
|
* Yaismel Miranda (ympons)
|
||||||
* notedit (notedit)
|
* notedit (notedit)
|
||||||
|
|
15
vendor/github.com/lib/pq/bench_test.go
generated
vendored
15
vendor/github.com/lib/pq/bench_test.go
generated
vendored
|
@ -7,7 +7,6 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"database/sql/driver"
|
"database/sql/driver"
|
||||||
"github.com/lib/pq/oid"
|
|
||||||
"io"
|
"io"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net"
|
"net"
|
||||||
|
@ -17,6 +16,8 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/lib/pq/oid"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -35,7 +36,6 @@ func BenchmarkSelectSeries(b *testing.B) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func benchQuery(b *testing.B, query string, result interface{}) {
|
func benchQuery(b *testing.B, query string, result interface{}) {
|
||||||
b.Skip("current pq database-backed benchmarks are inconsistent")
|
|
||||||
b.StopTimer()
|
b.StopTimer()
|
||||||
db := openTestConn(b)
|
db := openTestConn(b)
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
@ -183,7 +183,6 @@ func BenchmarkPreparedSelectSeries(b *testing.B) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func benchPreparedQuery(b *testing.B, query string, result interface{}) {
|
func benchPreparedQuery(b *testing.B, query string, result interface{}) {
|
||||||
b.Skip("current pq database-backed benchmarks are inconsistent")
|
|
||||||
b.StopTimer()
|
b.StopTimer()
|
||||||
db := openTestConn(b)
|
db := openTestConn(b)
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
@ -326,7 +325,7 @@ var testIntBytes = []byte("1234")
|
||||||
|
|
||||||
func BenchmarkDecodeInt64(b *testing.B) {
|
func BenchmarkDecodeInt64(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
decode(¶meterStatus{}, testIntBytes, oid.T_int8)
|
decode(¶meterStatus{}, testIntBytes, oid.T_int8, formatText)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -334,7 +333,7 @@ var testFloatBytes = []byte("3.14159")
|
||||||
|
|
||||||
func BenchmarkDecodeFloat64(b *testing.B) {
|
func BenchmarkDecodeFloat64(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
decode(¶meterStatus{}, testFloatBytes, oid.T_float8)
|
decode(¶meterStatus{}, testFloatBytes, oid.T_float8, formatText)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -342,7 +341,7 @@ var testBoolBytes = []byte{'t'}
|
||||||
|
|
||||||
func BenchmarkDecodeBool(b *testing.B) {
|
func BenchmarkDecodeBool(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
decode(¶meterStatus{}, testBoolBytes, oid.T_bool)
|
decode(¶meterStatus{}, testBoolBytes, oid.T_bool, formatText)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -359,7 +358,7 @@ var testTimestamptzBytes = []byte("2013-09-17 22:15:32.360754-07")
|
||||||
|
|
||||||
func BenchmarkDecodeTimestamptz(b *testing.B) {
|
func BenchmarkDecodeTimestamptz(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
decode(¶meterStatus{}, testTimestamptzBytes, oid.T_timestamptz)
|
decode(¶meterStatus{}, testTimestamptzBytes, oid.T_timestamptz, formatText)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -372,7 +371,7 @@ func BenchmarkDecodeTimestamptzMultiThread(b *testing.B) {
|
||||||
f := func(wg *sync.WaitGroup, loops int) {
|
f := func(wg *sync.WaitGroup, loops int) {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
for i := 0; i < loops; i++ {
|
for i := 0; i < loops; i++ {
|
||||||
decode(¶meterStatus{}, testTimestamptzBytes, oid.T_timestamptz)
|
decode(¶meterStatus{}, testTimestamptzBytes, oid.T_timestamptz, formatText)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
30
vendor/github.com/lib/pq/buf.go
generated
vendored
30
vendor/github.com/lib/pq/buf.go
generated
vendored
|
@ -3,6 +3,7 @@ package pq
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
|
||||||
"github.com/lib/pq/oid"
|
"github.com/lib/pq/oid"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -20,6 +21,7 @@ func (b *readBuf) oid() (n oid.Oid) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// N.B: this is actually an unsigned 16-bit integer, unlike int32
|
||||||
func (b *readBuf) int16() (n int) {
|
func (b *readBuf) int16() (n int) {
|
||||||
n = int(binary.BigEndian.Uint16(*b))
|
n = int(binary.BigEndian.Uint16(*b))
|
||||||
*b = (*b)[2:]
|
*b = (*b)[2:]
|
||||||
|
@ -46,28 +48,44 @@ func (b *readBuf) byte() byte {
|
||||||
return b.next(1)[0]
|
return b.next(1)[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
type writeBuf []byte
|
type writeBuf struct {
|
||||||
|
buf []byte
|
||||||
|
pos int
|
||||||
|
}
|
||||||
|
|
||||||
func (b *writeBuf) int32(n int) {
|
func (b *writeBuf) int32(n int) {
|
||||||
x := make([]byte, 4)
|
x := make([]byte, 4)
|
||||||
binary.BigEndian.PutUint32(x, uint32(n))
|
binary.BigEndian.PutUint32(x, uint32(n))
|
||||||
*b = append(*b, x...)
|
b.buf = append(b.buf, x...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *writeBuf) int16(n int) {
|
func (b *writeBuf) int16(n int) {
|
||||||
x := make([]byte, 2)
|
x := make([]byte, 2)
|
||||||
binary.BigEndian.PutUint16(x, uint16(n))
|
binary.BigEndian.PutUint16(x, uint16(n))
|
||||||
*b = append(*b, x...)
|
b.buf = append(b.buf, x...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *writeBuf) string(s string) {
|
func (b *writeBuf) string(s string) {
|
||||||
*b = append(*b, (s + "\000")...)
|
b.buf = append(b.buf, (s + "\000")...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *writeBuf) byte(c byte) {
|
func (b *writeBuf) byte(c byte) {
|
||||||
*b = append(*b, c)
|
b.buf = append(b.buf, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *writeBuf) bytes(v []byte) {
|
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)
|
||||||
}
|
}
|
||||||
|
|
3
vendor/github.com/lib/pq/certs/README
generated
vendored
Normal file
3
vendor/github.com/lib/pq/certs/README
generated
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
This directory contains certificates and private keys for testing some
|
||||||
|
SSL-related functionality in Travis. Do NOT use these certificates for
|
||||||
|
anything other than testing.
|
69
vendor/github.com/lib/pq/certs/postgresql.crt
generated
vendored
Normal file
69
vendor/github.com/lib/pq/certs/postgresql.crt
generated
vendored
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
Certificate:
|
||||||
|
Data:
|
||||||
|
Version: 3 (0x2)
|
||||||
|
Serial Number: 2 (0x2)
|
||||||
|
Signature Algorithm: sha256WithRSAEncryption
|
||||||
|
Issuer: C=US, ST=Nevada, L=Las Vegas, O=github.com/lib/pq, CN=pq CA
|
||||||
|
Validity
|
||||||
|
Not Before: Oct 11 15:10:11 2014 GMT
|
||||||
|
Not After : Oct 8 15:10:11 2024 GMT
|
||||||
|
Subject: C=US, ST=Nevada, L=Las Vegas, O=github.com/lib/pq, CN=pqgosslcert
|
||||||
|
Subject Public Key Info:
|
||||||
|
Public Key Algorithm: rsaEncryption
|
||||||
|
RSA Public Key: (1024 bit)
|
||||||
|
Modulus (1024 bit):
|
||||||
|
00:e3:8c:06:9a:70:54:51:d1:34:34:83:39:cd:a2:
|
||||||
|
59:0f:05:ed:8d:d8:0e:34:d0:92:f4:09:4d:ee:8c:
|
||||||
|
78:55:49:24:f8:3c:e0:34:58:02:b2:e7:94:58:c1:
|
||||||
|
e8:e5:bb:d1:af:f6:54:c1:40:b1:90:70:79:0d:35:
|
||||||
|
54:9c:8f:16:e9:c2:f0:92:e6:64:49:38:c1:76:f8:
|
||||||
|
47:66:c4:5b:4a:b6:a9:43:ce:c8:be:6c:4d:2b:94:
|
||||||
|
97:3c:55:bc:d1:d0:6e:b7:53:ae:89:5c:4b:6b:86:
|
||||||
|
40:be:c1:ae:1e:64:ce:9c:ae:87:0a:69:e5:c8:21:
|
||||||
|
12:be:ae:1d:f6:45:df:16:a7
|
||||||
|
Exponent: 65537 (0x10001)
|
||||||
|
X509v3 extensions:
|
||||||
|
X509v3 Subject Key Identifier:
|
||||||
|
9B:25:31:63:A2:D8:06:FF:CB:E3:E9:96:FF:0D:BA:DC:12:7D:04:CF
|
||||||
|
X509v3 Authority Key Identifier:
|
||||||
|
keyid:52:93:ED:1E:76:0A:9F:65:4F:DE:19:66:C1:D5:22:40:35:CB:A0:72
|
||||||
|
|
||||||
|
X509v3 Basic Constraints:
|
||||||
|
CA:FALSE
|
||||||
|
X509v3 Key Usage:
|
||||||
|
Digital Signature, Non Repudiation, Key Encipherment
|
||||||
|
Signature Algorithm: sha256WithRSAEncryption
|
||||||
|
3e:f5:f8:0b:4e:11:bd:00:86:1f:ce:dc:97:02:98:91:11:f5:
|
||||||
|
65:f6:f2:8a:b2:3e:47:92:05:69:28:c9:e9:b4:f7:cf:93:d1:
|
||||||
|
2d:81:5d:00:3c:23:be:da:70:ea:59:e1:2c:d3:25:49:ae:a6:
|
||||||
|
95:54:c1:10:df:23:e3:fe:d6:e4:76:c7:6b:73:ad:1b:34:7c:
|
||||||
|
e2:56:cc:c0:37:ae:c5:7a:11:20:6c:3d:05:0e:99:cd:22:6c:
|
||||||
|
cf:59:a1:da:28:d4:65:ba:7d:2f:2b:3d:69:6d:a6:c1:ae:57:
|
||||||
|
bf:56:64:13:79:f8:48:46:65:eb:81:67:28:0b:7b:de:47:10:
|
||||||
|
b3:80:3c:31:d1:58:94:01:51:4a:c7:c8:1a:01:a8:af:c4:cd:
|
||||||
|
bb:84:a5:d9:8b:b4:b9:a1:64:3e:95:d9:90:1d:d5:3f:67:cc:
|
||||||
|
3b:ba:f5:b4:d1:33:77:ee:c2:d2:3e:7e:c5:66:6e:b7:35:4c:
|
||||||
|
60:57:b0:b8:be:36:c8:f3:d3:95:8c:28:4a:c9:f7:27:a4:0d:
|
||||||
|
e5:96:99:eb:f5:c8:bd:f3:84:6d:ef:02:f9:8a:36:7d:6b:5f:
|
||||||
|
36:68:37:41:d9:74:ae:c6:78:2e:44:86:a1:ad:43:ca:fb:b5:
|
||||||
|
3e:ba:10:23:09:02:ac:62:d1:d0:83:c8:95:b9:e3:5e:30:ff:
|
||||||
|
5b:2b:38:fa
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDEzCCAfugAwIBAgIBAjANBgkqhkiG9w0BAQsFADBeMQswCQYDVQQGEwJVUzEP
|
||||||
|
MA0GA1UECBMGTmV2YWRhMRIwEAYDVQQHEwlMYXMgVmVnYXMxGjAYBgNVBAoTEWdp
|
||||||
|
dGh1Yi5jb20vbGliL3BxMQ4wDAYDVQQDEwVwcSBDQTAeFw0xNDEwMTExNTEwMTFa
|
||||||
|
Fw0yNDEwMDgxNTEwMTFaMGQxCzAJBgNVBAYTAlVTMQ8wDQYDVQQIEwZOZXZhZGEx
|
||||||
|
EjAQBgNVBAcTCUxhcyBWZWdhczEaMBgGA1UEChMRZ2l0aHViLmNvbS9saWIvcHEx
|
||||||
|
FDASBgNVBAMTC3BxZ29zc2xjZXJ0MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB
|
||||||
|
gQDjjAaacFRR0TQ0gznNolkPBe2N2A400JL0CU3ujHhVSST4POA0WAKy55RYwejl
|
||||||
|
u9Gv9lTBQLGQcHkNNVScjxbpwvCS5mRJOMF2+EdmxFtKtqlDzsi+bE0rlJc8VbzR
|
||||||
|
0G63U66JXEtrhkC+wa4eZM6crocKaeXIIRK+rh32Rd8WpwIDAQABo1owWDAdBgNV
|
||||||
|
HQ4EFgQUmyUxY6LYBv/L4+mW/w263BJ9BM8wHwYDVR0jBBgwFoAUUpPtHnYKn2VP
|
||||||
|
3hlmwdUiQDXLoHIwCQYDVR0TBAIwADALBgNVHQ8EBAMCBeAwDQYJKoZIhvcNAQEL
|
||||||
|
BQADggEBAD71+AtOEb0Ahh/O3JcCmJER9WX28oqyPkeSBWkoyem098+T0S2BXQA8
|
||||||
|
I77acOpZ4SzTJUmuppVUwRDfI+P+1uR2x2tzrRs0fOJWzMA3rsV6ESBsPQUOmc0i
|
||||||
|
bM9Zodoo1GW6fS8rPWltpsGuV79WZBN5+EhGZeuBZygLe95HELOAPDHRWJQBUUrH
|
||||||
|
yBoBqK/EzbuEpdmLtLmhZD6V2ZAd1T9nzDu69bTRM3fuwtI+fsVmbrc1TGBXsLi+
|
||||||
|
Nsjz05WMKErJ9yekDeWWmev1yL3zhG3vAvmKNn1rXzZoN0HZdK7GeC5EhqGtQ8r7
|
||||||
|
tT66ECMJAqxi0dCDyJW5414w/1srOPo=
|
||||||
|
-----END CERTIFICATE-----
|
15
vendor/github.com/lib/pq/certs/postgresql.key
generated
vendored
Normal file
15
vendor/github.com/lib/pq/certs/postgresql.key
generated
vendored
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIICWwIBAAKBgQDjjAaacFRR0TQ0gznNolkPBe2N2A400JL0CU3ujHhVSST4POA0
|
||||||
|
WAKy55RYwejlu9Gv9lTBQLGQcHkNNVScjxbpwvCS5mRJOMF2+EdmxFtKtqlDzsi+
|
||||||
|
bE0rlJc8VbzR0G63U66JXEtrhkC+wa4eZM6crocKaeXIIRK+rh32Rd8WpwIDAQAB
|
||||||
|
AoGAM5dM6/kp9P700i8qjOgRPym96Zoh5nGfz/rIE5z/r36NBkdvIg8OVZfR96nH
|
||||||
|
b0b9TOMR5lsPp0sI9yivTWvX6qyvLJRWy2vvx17hXK9NxXUNTAm0PYZUTvCtcPeX
|
||||||
|
RnJpzQKNZQPkFzF0uXBc4CtPK2Vz0+FGvAelrhYAxnw1dIkCQQD+9qaW5QhXjsjb
|
||||||
|
Nl85CmXgxPmGROcgLQCO+omfrjf9UXrituU9Dz6auym5lDGEdMFnkzfr+wpasEy9
|
||||||
|
mf5ZZOhDAkEA5HjXfVGaCtpydOt6hDon/uZsyssCK2lQ7NSuE3vP+sUsYMzIpEoy
|
||||||
|
t3VWXqKbo+g9KNDTP4WEliqp1aiSIylzzQJANPeqzihQnlgEdD4MdD4rwhFJwVIp
|
||||||
|
Le8Lcais1KaN7StzOwxB/XhgSibd2TbnPpw+3bSg5n5lvUdo+e62/31OHwJAU1jS
|
||||||
|
I+F09KikQIr28u3UUWT2IzTT4cpVv1AHAQyV3sG3YsjSGT0IK20eyP9BEBZU2WL0
|
||||||
|
7aNjrvR5aHxKc5FXsQJABsFtyGpgI5X4xufkJZVZ+Mklz2n7iXa+XPatMAHFxAtb
|
||||||
|
EEMt60rngwMjXAzBSC6OYuYogRRAY3UCacNC5VhLYQ==
|
||||||
|
-----END RSA PRIVATE KEY-----
|
24
vendor/github.com/lib/pq/certs/root.crt
generated
vendored
Normal file
24
vendor/github.com/lib/pq/certs/root.crt
generated
vendored
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIEAzCCAuugAwIBAgIJANmheROCdW1NMA0GCSqGSIb3DQEBBQUAMF4xCzAJBgNV
|
||||||
|
BAYTAlVTMQ8wDQYDVQQIEwZOZXZhZGExEjAQBgNVBAcTCUxhcyBWZWdhczEaMBgG
|
||||||
|
A1UEChMRZ2l0aHViLmNvbS9saWIvcHExDjAMBgNVBAMTBXBxIENBMB4XDTE0MTAx
|
||||||
|
MTE1MDQyOVoXDTI0MTAwODE1MDQyOVowXjELMAkGA1UEBhMCVVMxDzANBgNVBAgT
|
||||||
|
Bk5ldmFkYTESMBAGA1UEBxMJTGFzIFZlZ2FzMRowGAYDVQQKExFnaXRodWIuY29t
|
||||||
|
L2xpYi9wcTEOMAwGA1UEAxMFcHEgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
|
||||||
|
ggEKAoIBAQCV4PxP7ShzWBzUCThcKk3qZtOLtHmszQVtbqhvgTpm1kTRtKBdVMu0
|
||||||
|
pLAHQ3JgJCnAYgH0iZxVGoMP16T3irdgsdC48+nNTFM2T0cCdkfDURGIhSFN47cb
|
||||||
|
Pgy306BcDUD2q7ucW33+dlFSRuGVewocoh4BWM/vMtMvvWzdi4Ag/L/jhb+5wZxZ
|
||||||
|
sWymsadOVSDePEMKOvlCa3EdVwVFV40TVyDb+iWBUivDAYsS2a3KajuJrO6MbZiE
|
||||||
|
Sp2RCIkZS2zFmzWxVRi9ZhzIZhh7EVF9JAaNC3T52jhGUdlRq3YpBTMnd89iOh74
|
||||||
|
6jWXG7wSuPj3haFzyNhmJ0ZUh+2Ynoh1AgMBAAGjgcMwgcAwHQYDVR0OBBYEFFKT
|
||||||
|
7R52Cp9lT94ZZsHVIkA1y6ByMIGQBgNVHSMEgYgwgYWAFFKT7R52Cp9lT94ZZsHV
|
||||||
|
IkA1y6ByoWKkYDBeMQswCQYDVQQGEwJVUzEPMA0GA1UECBMGTmV2YWRhMRIwEAYD
|
||||||
|
VQQHEwlMYXMgVmVnYXMxGjAYBgNVBAoTEWdpdGh1Yi5jb20vbGliL3BxMQ4wDAYD
|
||||||
|
VQQDEwVwcSBDQYIJANmheROCdW1NMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEF
|
||||||
|
BQADggEBAAEhCLWkqJNMI8b4gkbmj5fqQ/4+oO83bZ3w2Oqf6eZ8I8BC4f2NOyE6
|
||||||
|
tRUlq5+aU7eqC1cOAvGjO+YHN/bF/DFpwLlzvUSXt+JP/pYcUjL7v+pIvwqec9hD
|
||||||
|
ndvM4iIbkD/H/OYQ3L+N3W+G1x7AcFIX+bGCb3PzYVQAjxreV6//wgKBosMGFbZo
|
||||||
|
HPxT9RPMun61SViF04H5TNs0derVn1+5eiiYENeAhJzQNyZoOOUuX1X/Inx9bEPh
|
||||||
|
C5vFBtSMgIytPgieRJVWAiMLYsfpIAStrHztRAbBs2DU01LmMgRvHdxgFEKinC/d
|
||||||
|
UHZZQDP+6pT+zADrGhQGXe4eThaO6f0=
|
||||||
|
-----END CERTIFICATE-----
|
81
vendor/github.com/lib/pq/certs/server.crt
generated
vendored
Normal file
81
vendor/github.com/lib/pq/certs/server.crt
generated
vendored
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
Certificate:
|
||||||
|
Data:
|
||||||
|
Version: 3 (0x2)
|
||||||
|
Serial Number: 1 (0x1)
|
||||||
|
Signature Algorithm: sha256WithRSAEncryption
|
||||||
|
Issuer: C=US, ST=Nevada, L=Las Vegas, O=github.com/lib/pq, CN=pq CA
|
||||||
|
Validity
|
||||||
|
Not Before: Oct 11 15:05:15 2014 GMT
|
||||||
|
Not After : Oct 8 15:05:15 2024 GMT
|
||||||
|
Subject: C=US, ST=Nevada, L=Las Vegas, O=github.com/lib/pq, CN=postgres
|
||||||
|
Subject Public Key Info:
|
||||||
|
Public Key Algorithm: rsaEncryption
|
||||||
|
RSA Public Key: (2048 bit)
|
||||||
|
Modulus (2048 bit):
|
||||||
|
00:d7:8a:4c:85:fb:17:a5:3c:8f:e0:72:11:29:ce:
|
||||||
|
3f:b0:1f:3f:7d:c6:ee:7f:a7:fc:02:2b:35:47:08:
|
||||||
|
a6:3d:90:df:5c:56:14:94:00:c7:6d:d1:d2:e2:61:
|
||||||
|
95:77:b8:e3:a6:66:31:f9:1f:21:7d:62:e1:27:da:
|
||||||
|
94:37:61:4a:ea:63:53:a0:61:b8:9c:bb:a5:e2:e7:
|
||||||
|
b7:a6:d8:0f:05:04:c7:29:e2:ea:49:2b:7f:de:15:
|
||||||
|
00:a6:18:70:50:c7:0c:de:9a:f9:5a:96:b0:e1:94:
|
||||||
|
06:c6:6d:4a:21:3b:b4:0f:a5:6d:92:86:34:b2:4e:
|
||||||
|
d7:0e:a7:19:c0:77:0b:7b:87:c8:92:de:42:ff:86:
|
||||||
|
d2:b7:9a:a4:d4:15:23:ca:ad:a5:69:21:b8:ce:7e:
|
||||||
|
66:cb:85:5d:b9:ed:8b:2d:09:8d:94:e4:04:1e:72:
|
||||||
|
ec:ef:d0:76:90:15:5a:a4:f7:91:4b:e9:ce:4e:9d:
|
||||||
|
5d:9a:70:17:9c:d8:e9:73:83:ea:3d:61:99:a6:cd:
|
||||||
|
ac:91:40:5a:88:77:e5:4e:2a:8e:3d:13:f3:f9:38:
|
||||||
|
6f:81:6b:8a:95:ca:0e:07:ab:6f:da:b4:8c:d9:ff:
|
||||||
|
aa:78:03:aa:c7:c2:cf:6f:64:92:d3:d8:83:d5:af:
|
||||||
|
f1:23:18:a7:2e:7b:17:0b:e7:7d:f1:fa:a8:41:a3:
|
||||||
|
04:57
|
||||||
|
Exponent: 65537 (0x10001)
|
||||||
|
X509v3 extensions:
|
||||||
|
X509v3 Subject Key Identifier:
|
||||||
|
EE:F0:B3:46:DC:C7:09:EB:0E:B6:2F:E5:FE:62:60:45:44:9F:59:CC
|
||||||
|
X509v3 Authority Key Identifier:
|
||||||
|
keyid:52:93:ED:1E:76:0A:9F:65:4F:DE:19:66:C1:D5:22:40:35:CB:A0:72
|
||||||
|
|
||||||
|
X509v3 Basic Constraints:
|
||||||
|
CA:FALSE
|
||||||
|
X509v3 Key Usage:
|
||||||
|
Digital Signature, Non Repudiation, Key Encipherment
|
||||||
|
Signature Algorithm: sha256WithRSAEncryption
|
||||||
|
7e:5a:6e:be:bf:d2:6c:c1:d6:fa:b6:fb:3f:06:53:36:08:87:
|
||||||
|
9d:95:b1:39:af:9e:f6:47:38:17:39:da:25:7c:f2:ad:0c:e3:
|
||||||
|
ab:74:19:ca:fb:8c:a0:50:c0:1d:19:8a:9c:21:ed:0f:3a:d1:
|
||||||
|
96:54:2e:10:09:4f:b8:70:f7:2b:99:43:d2:c6:15:bc:3f:24:
|
||||||
|
7d:28:39:32:3f:8d:a4:4f:40:75:7f:3e:0d:1c:d1:69:f2:4e:
|
||||||
|
98:83:47:97:d2:25:ac:c9:36:86:2f:04:a6:c4:86:c7:c4:00:
|
||||||
|
5f:7f:b9:ad:fc:bf:e9:f5:78:d7:82:1a:51:0d:fc:ab:9e:92:
|
||||||
|
1d:5f:0c:18:d1:82:e0:14:c9:ce:91:89:71:ff:49:49:ff:35:
|
||||||
|
bf:7b:44:78:42:c1:d0:66:65:bb:28:2e:60:ca:9b:20:12:a9:
|
||||||
|
90:61:b1:96:ec:15:46:c9:37:f7:07:90:8a:89:45:2a:3f:37:
|
||||||
|
ec:dc:e3:e5:8f:c3:3a:57:80:a5:54:60:0c:e1:b2:26:99:2b:
|
||||||
|
40:7e:36:d1:9a:70:02:ec:63:f4:3b:72:ae:81:fb:30:20:6d:
|
||||||
|
cb:48:46:c6:b5:8f:39:b1:84:05:25:55:8d:f5:62:f6:1b:46:
|
||||||
|
2e:da:a3:4c:26:12:44:d7:56:b6:b8:a9:ca:d3:ab:71:45:7c:
|
||||||
|
9f:48:6d:1e
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDlDCCAnygAwIBAgIBATANBgkqhkiG9w0BAQsFADBeMQswCQYDVQQGEwJVUzEP
|
||||||
|
MA0GA1UECBMGTmV2YWRhMRIwEAYDVQQHEwlMYXMgVmVnYXMxGjAYBgNVBAoTEWdp
|
||||||
|
dGh1Yi5jb20vbGliL3BxMQ4wDAYDVQQDEwVwcSBDQTAeFw0xNDEwMTExNTA1MTVa
|
||||||
|
Fw0yNDEwMDgxNTA1MTVaMGExCzAJBgNVBAYTAlVTMQ8wDQYDVQQIEwZOZXZhZGEx
|
||||||
|
EjAQBgNVBAcTCUxhcyBWZWdhczEaMBgGA1UEChMRZ2l0aHViLmNvbS9saWIvcHEx
|
||||||
|
ETAPBgNVBAMTCHBvc3RncmVzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
|
||||||
|
AQEA14pMhfsXpTyP4HIRKc4/sB8/fcbuf6f8Ais1RwimPZDfXFYUlADHbdHS4mGV
|
||||||
|
d7jjpmYx+R8hfWLhJ9qUN2FK6mNToGG4nLul4ue3ptgPBQTHKeLqSSt/3hUAphhw
|
||||||
|
UMcM3pr5Wpaw4ZQGxm1KITu0D6VtkoY0sk7XDqcZwHcLe4fIkt5C/4bSt5qk1BUj
|
||||||
|
yq2laSG4zn5my4Vdue2LLQmNlOQEHnLs79B2kBVapPeRS+nOTp1dmnAXnNjpc4Pq
|
||||||
|
PWGZps2skUBaiHflTiqOPRPz+ThvgWuKlcoOB6tv2rSM2f+qeAOqx8LPb2SS09iD
|
||||||
|
1a/xIxinLnsXC+d98fqoQaMEVwIDAQABo1owWDAdBgNVHQ4EFgQU7vCzRtzHCesO
|
||||||
|
ti/l/mJgRUSfWcwwHwYDVR0jBBgwFoAUUpPtHnYKn2VP3hlmwdUiQDXLoHIwCQYD
|
||||||
|
VR0TBAIwADALBgNVHQ8EBAMCBeAwDQYJKoZIhvcNAQELBQADggEBAH5abr6/0mzB
|
||||||
|
1vq2+z8GUzYIh52VsTmvnvZHOBc52iV88q0M46t0Gcr7jKBQwB0Zipwh7Q860ZZU
|
||||||
|
LhAJT7hw9yuZQ9LGFbw/JH0oOTI/jaRPQHV/Pg0c0WnyTpiDR5fSJazJNoYvBKbE
|
||||||
|
hsfEAF9/ua38v+n1eNeCGlEN/Kuekh1fDBjRguAUyc6RiXH/SUn/Nb97RHhCwdBm
|
||||||
|
ZbsoLmDKmyASqZBhsZbsFUbJN/cHkIqJRSo/N+zc4+WPwzpXgKVUYAzhsiaZK0B+
|
||||||
|
NtGacALsY/Q7cq6B+zAgbctIRsa1jzmxhAUlVY31YvYbRi7ao0wmEkTXVra4qcrT
|
||||||
|
q3FFfJ9IbR4=
|
||||||
|
-----END CERTIFICATE-----
|
27
vendor/github.com/lib/pq/certs/server.key
generated
vendored
Normal file
27
vendor/github.com/lib/pq/certs/server.key
generated
vendored
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIIEogIBAAKCAQEA14pMhfsXpTyP4HIRKc4/sB8/fcbuf6f8Ais1RwimPZDfXFYU
|
||||||
|
lADHbdHS4mGVd7jjpmYx+R8hfWLhJ9qUN2FK6mNToGG4nLul4ue3ptgPBQTHKeLq
|
||||||
|
SSt/3hUAphhwUMcM3pr5Wpaw4ZQGxm1KITu0D6VtkoY0sk7XDqcZwHcLe4fIkt5C
|
||||||
|
/4bSt5qk1BUjyq2laSG4zn5my4Vdue2LLQmNlOQEHnLs79B2kBVapPeRS+nOTp1d
|
||||||
|
mnAXnNjpc4PqPWGZps2skUBaiHflTiqOPRPz+ThvgWuKlcoOB6tv2rSM2f+qeAOq
|
||||||
|
x8LPb2SS09iD1a/xIxinLnsXC+d98fqoQaMEVwIDAQABAoIBAF3ZoihUhJ82F4+r
|
||||||
|
Gz4QyDpv4L1reT2sb1aiabhcU8ZK5nbWJG+tRyjSS/i2dNaEcttpdCj9HR/zhgZM
|
||||||
|
bm0OuAgG58rVwgS80CZUruq++Qs+YVojq8/gWPTiQD4SNhV2Fmx3HkwLgUk3oxuT
|
||||||
|
SsvdqzGE3okGVrutCIcgy126eA147VPMoej1Bb3fO6npqK0pFPhZfAc0YoqJuM+k
|
||||||
|
obRm5pAnGUipyLCFXjA9HYPKwYZw2RtfdA3CiImHeanSdqS+ctrC9y8BV40Th7gZ
|
||||||
|
haXdKUNdjmIxV695QQ1mkGqpKLZFqhzKioGQ2/Ly2d1iaKN9fZltTusu8unepWJ2
|
||||||
|
tlT9qMECgYEA9uHaF1t2CqE+AJvWTihHhPIIuLxoOQXYea1qvxfcH/UMtaLKzCNm
|
||||||
|
lQ5pqCGsPvp+10f36yttO1ZehIvlVNXuJsjt0zJmPtIolNuJY76yeussfQ9jHheB
|
||||||
|
5uPEzCFlHzxYbBUyqgWaF6W74okRGzEGJXjYSP0yHPPdU4ep2q3bGiUCgYEA34Af
|
||||||
|
wBSuQSK7uLxArWHvQhyuvi43ZGXls6oRGl+Ysj54s8BP6XGkq9hEJ6G4yxgyV+BR
|
||||||
|
DUOs5X8/TLT8POuIMYvKTQthQyCk0eLv2FLdESDuuKx0kBVY3s8lK3/z5HhrdOiN
|
||||||
|
VMNZU+xDKgKc3hN9ypkk8vcZe6EtH7Y14e0rVcsCgYBTgxi8F/M5K0wG9rAqphNz
|
||||||
|
VFBA9XKn/2M33cKjO5X5tXIEKzpAjaUQvNxexG04rJGljzG8+mar0M6ONahw5yD1
|
||||||
|
O7i/XWgazgpuOEkkVYiYbd8RutfDgR4vFVMn3hAP3eDnRtBplRWH9Ec3HTiNIys6
|
||||||
|
F8PKBOQjyRZQQC7jyzW3hQKBgACe5HeuFwXLSOYsb6mLmhR+6+VPT4wR1F95W27N
|
||||||
|
USk9jyxAnngxfpmTkiziABdgS9N+pfr5cyN4BP77ia/Jn6kzkC5Cl9SN5KdIkA3z
|
||||||
|
vPVtN/x/ThuQU5zaymmig1ThGLtMYggYOslG4LDfLPxY5YKIhle+Y+259twdr2yf
|
||||||
|
Mf2dAoGAaGv3tWMgnIdGRk6EQL/yb9PKHo7ShN+tKNlGaK7WwzBdKs+Fe8jkgcr7
|
||||||
|
pz4Ne887CmxejdISzOCcdT+Zm9Bx6I/uZwWOtDvWpIgIxVX9a9URj/+D1MxTE/y4
|
||||||
|
d6H+c89yDY62I2+drMpdjCd3EtCaTlxpTbRS+s1eAHMH7aEkcCE=
|
||||||
|
-----END RSA PRIVATE KEY-----
|
1007
vendor/github.com/lib/pq/conn.go
generated
vendored
1007
vendor/github.com/lib/pq/conn.go
generated
vendored
File diff suppressed because it is too large
Load diff
163
vendor/github.com/lib/pq/conn_test.go
generated
vendored
163
vendor/github.com/lib/pq/conn_test.go
generated
vendored
|
@ -7,7 +7,6 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
"runtime"
|
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
@ -17,21 +16,31 @@ type Fatalistic interface {
|
||||||
Fatal(args ...interface{})
|
Fatal(args ...interface{})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func forceBinaryParameters() bool {
|
||||||
|
bp := os.Getenv("PQTEST_BINARY_PARAMETERS")
|
||||||
|
if bp == "yes" {
|
||||||
|
return true
|
||||||
|
} else if bp == "" || bp == "no" {
|
||||||
|
return false
|
||||||
|
} else {
|
||||||
|
panic("unexpected value for PQTEST_BINARY_PARAMETERS")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func openTestConnConninfo(conninfo string) (*sql.DB, error) {
|
func openTestConnConninfo(conninfo string) (*sql.DB, error) {
|
||||||
datname := os.Getenv("PGDATABASE")
|
defaultTo := func(envvar string, value string) {
|
||||||
sslmode := os.Getenv("PGSSLMODE")
|
if os.Getenv(envvar) == "" {
|
||||||
timeout := os.Getenv("PGCONNECT_TIMEOUT")
|
os.Setenv(envvar, value)
|
||||||
|
}
|
||||||
if datname == "" {
|
|
||||||
os.Setenv("PGDATABASE", "pqgotest")
|
|
||||||
}
|
}
|
||||||
|
defaultTo("PGDATABASE", "pqgotest")
|
||||||
|
defaultTo("PGSSLMODE", "disable")
|
||||||
|
defaultTo("PGCONNECT_TIMEOUT", "20")
|
||||||
|
|
||||||
if sslmode == "" {
|
if forceBinaryParameters() &&
|
||||||
os.Setenv("PGSSLMODE", "disable")
|
!strings.HasPrefix(conninfo, "postgres://") &&
|
||||||
}
|
!strings.HasPrefix(conninfo, "postgresql://") {
|
||||||
|
conninfo = conninfo + " binary_parameters=yes"
|
||||||
if timeout == "" {
|
|
||||||
os.Setenv("PGCONNECT_TIMEOUT", "20")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return sql.Open("postgres", conninfo)
|
return sql.Open("postgres", conninfo)
|
||||||
|
@ -56,12 +65,6 @@ func getServerVersion(t *testing.T, db *sql.DB) int {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestReconnect(t *testing.T) {
|
func TestReconnect(t *testing.T) {
|
||||||
if runtime.Version() == "go1.0.2" {
|
|
||||||
fmt.Println("Skipping failing test; " +
|
|
||||||
"fixed in database/sql on go1.0.3+")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
db1 := openTestConn(t)
|
db1 := openTestConn(t)
|
||||||
defer db1.Close()
|
defer db1.Close()
|
||||||
tx, err := db1.Begin()
|
tx, err := db1.Begin()
|
||||||
|
@ -114,18 +117,22 @@ func TestCommitInFailedTransaction(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestOpenURL(t *testing.T) {
|
func TestOpenURL(t *testing.T) {
|
||||||
db, err := openTestConnConninfo("postgres://")
|
testURL := func(url string) {
|
||||||
if err != nil {
|
db, err := openTestConnConninfo(url)
|
||||||
t.Fatal(err)
|
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()
|
||||||
}
|
}
|
||||||
defer db.Close()
|
testURL("postgres://")
|
||||||
// database/sql might not call our Open at all unless we do something with
|
testURL("postgresql://")
|
||||||
// the connection
|
|
||||||
txn, err := db.Begin()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
txn.Rollback()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestExec(t *testing.T) {
|
func TestExec(t *testing.T) {
|
||||||
|
@ -350,6 +357,7 @@ func TestEncodeDecode(t *testing.T) {
|
||||||
'2000-1-1 01:02:03.04-7'::timestamptz,
|
'2000-1-1 01:02:03.04-7'::timestamptz,
|
||||||
0::boolean,
|
0::boolean,
|
||||||
123,
|
123,
|
||||||
|
-321,
|
||||||
3.14::float8
|
3.14::float8
|
||||||
WHERE
|
WHERE
|
||||||
E'\\000\\001\\002'::bytea = $1
|
E'\\000\\001\\002'::bytea = $1
|
||||||
|
@ -378,9 +386,9 @@ func TestEncodeDecode(t *testing.T) {
|
||||||
var got2 string
|
var got2 string
|
||||||
var got3 = sql.NullInt64{Valid: true}
|
var got3 = sql.NullInt64{Valid: true}
|
||||||
var got4 time.Time
|
var got4 time.Time
|
||||||
var got5, got6, got7 interface{}
|
var got5, got6, got7, got8 interface{}
|
||||||
|
|
||||||
err = r.Scan(&got1, &got2, &got3, &got4, &got5, &got6, &got7)
|
err = r.Scan(&got1, &got2, &got3, &got4, &got5, &got6, &got7, &got8)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -409,8 +417,12 @@ func TestEncodeDecode(t *testing.T) {
|
||||||
t.Fatalf("expected 123, got %d", got6)
|
t.Fatalf("expected 123, got %d", got6)
|
||||||
}
|
}
|
||||||
|
|
||||||
if got7 != float64(3.14) {
|
if got7 != int64(-321) {
|
||||||
t.Fatalf("expected 3.14, got %f", got7)
|
t.Fatalf("expected -321, got %d", got7)
|
||||||
|
}
|
||||||
|
|
||||||
|
if got8 != float64(3.14) {
|
||||||
|
t.Fatalf("expected 3.14, got %f", got8)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -465,32 +477,38 @@ func TestErrorDuringStartup(t *testing.T) {
|
||||||
e, ok := err.(*Error)
|
e, ok := err.(*Error)
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Fatalf("expected Error, got %#v", err)
|
t.Fatalf("expected Error, got %#v", err)
|
||||||
} else if e.Code.Name() != "invalid_authorization_specification" {
|
} else if e.Code.Name() != "invalid_authorization_specification" && e.Code.Name() != "invalid_password" {
|
||||||
t.Fatalf("expected invalid_authorization_specification, got %s (%+v)", e.Code.Name(), err)
|
t.Fatalf("expected invalid_authorization_specification or invalid_password, got %s (%+v)", e.Code.Name(), err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBadConn(t *testing.T) {
|
func TestBadConn(t *testing.T) {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
|
cn := conn{}
|
||||||
func() {
|
func() {
|
||||||
defer errRecover(&err)
|
defer cn.errRecover(&err)
|
||||||
panic(io.EOF)
|
panic(io.EOF)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if err != driver.ErrBadConn {
|
if err != driver.ErrBadConn {
|
||||||
t.Fatalf("expected driver.ErrBadConn, got: %#v", err)
|
t.Fatalf("expected driver.ErrBadConn, got: %#v", err)
|
||||||
}
|
}
|
||||||
|
if !cn.bad {
|
||||||
|
t.Fatalf("expected cn.bad")
|
||||||
|
}
|
||||||
|
|
||||||
|
cn = conn{}
|
||||||
func() {
|
func() {
|
||||||
defer errRecover(&err)
|
defer cn.errRecover(&err)
|
||||||
e := &Error{Severity: Efatal}
|
e := &Error{Severity: Efatal}
|
||||||
panic(e)
|
panic(e)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if err != driver.ErrBadConn {
|
if err != driver.ErrBadConn {
|
||||||
t.Fatalf("expected driver.ErrBadConn, got: %#v", err)
|
t.Fatalf("expected driver.ErrBadConn, got: %#v", err)
|
||||||
}
|
}
|
||||||
|
if !cn.bad {
|
||||||
|
t.Fatalf("expected cn.bad")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestErrorOnExec(t *testing.T) {
|
func TestErrorOnExec(t *testing.T) {
|
||||||
|
@ -832,11 +850,6 @@ func TestIssue196(t *testing.T) {
|
||||||
// Test that any CommandComplete messages sent before the query results are
|
// Test that any CommandComplete messages sent before the query results are
|
||||||
// ignored.
|
// ignored.
|
||||||
func TestIssue282(t *testing.T) {
|
func TestIssue282(t *testing.T) {
|
||||||
if strings.HasPrefix(runtime.Version(), "go1.0") {
|
|
||||||
fmt.Println("Skipping test due to lack of Queryer implementation")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
db := openTestConn(t)
|
db := openTestConn(t)
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
|
||||||
|
@ -872,6 +885,60 @@ func TestReadFloatPrecision(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 {
|
var envParseTests = []struct {
|
||||||
Expected map[string]string
|
Expected map[string]string
|
||||||
Env []string
|
Env []string
|
||||||
|
@ -908,7 +975,8 @@ func TestParseComplete(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
res, c := parseComplete(commandTag)
|
cn := &conn{}
|
||||||
|
res, c := cn.parseComplete(commandTag)
|
||||||
if c != command {
|
if c != command {
|
||||||
t.Errorf("Expected %v, got %v", command, c)
|
t.Errorf("Expected %v, got %v", command, c)
|
||||||
}
|
}
|
||||||
|
@ -1161,14 +1229,15 @@ func TestRuntimeParameters(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
defer db.Close()
|
|
||||||
|
|
||||||
// application_name didn't exist before 9.0
|
// application_name didn't exist before 9.0
|
||||||
if test.param == "application_name" && getServerVersion(t, db) < 90000 {
|
if test.param == "application_name" && getServerVersion(t, db) < 90000 {
|
||||||
|
db.Close()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
tryGetParameterValue := func() (value string, outcome RuntimeTestResult) {
|
tryGetParameterValue := func() (value string, outcome RuntimeTestResult) {
|
||||||
|
defer db.Close()
|
||||||
row := db.QueryRow("SELECT current_setting($1)", test.param)
|
row := db.QueryRow("SELECT current_setting($1)", test.param)
|
||||||
err = row.Scan(&value)
|
err = row.Scan(&value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
61
vendor/github.com/lib/pq/conn_xact_test.go
generated
vendored
61
vendor/github.com/lib/pq/conn_xact_test.go
generated
vendored
|
@ -1,61 +0,0 @@
|
||||||
// +build go1.1
|
|
||||||
|
|
||||||
package pq
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
76
vendor/github.com/lib/pq/copy.go
generated
vendored
76
vendor/github.com/lib/pq/copy.go
generated
vendored
|
@ -4,7 +4,8 @@ import (
|
||||||
"database/sql/driver"
|
"database/sql/driver"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
"sync/atomic"
|
"fmt"
|
||||||
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -48,9 +49,10 @@ type copyin struct {
|
||||||
rowData chan []byte
|
rowData chan []byte
|
||||||
done chan bool
|
done chan bool
|
||||||
|
|
||||||
closed bool
|
closed bool
|
||||||
err error
|
|
||||||
errorset int32
|
sync.Mutex // guards err
|
||||||
|
err error
|
||||||
}
|
}
|
||||||
|
|
||||||
const ciBufferSize = 64 * 1024
|
const ciBufferSize = 64 * 1024
|
||||||
|
@ -59,8 +61,6 @@ const ciBufferSize = 64 * 1024
|
||||||
const ciBufferFlushSize = 63 * 1024
|
const ciBufferFlushSize = 63 * 1024
|
||||||
|
|
||||||
func (cn *conn) prepareCopyIn(q string) (_ driver.Stmt, err error) {
|
func (cn *conn) prepareCopyIn(q string) (_ driver.Stmt, err error) {
|
||||||
defer errRecover(&err)
|
|
||||||
|
|
||||||
if !cn.isInTransaction() {
|
if !cn.isInTransaction() {
|
||||||
return nil, errCopyNotSupportedOutsideTxn
|
return nil, errCopyNotSupportedOutsideTxn
|
||||||
}
|
}
|
||||||
|
@ -69,7 +69,7 @@ func (cn *conn) prepareCopyIn(q string) (_ driver.Stmt, err error) {
|
||||||
cn: cn,
|
cn: cn,
|
||||||
buffer: make([]byte, 0, ciBufferSize),
|
buffer: make([]byte, 0, ciBufferSize),
|
||||||
rowData: make(chan []byte),
|
rowData: make(chan []byte),
|
||||||
done: make(chan bool),
|
done: make(chan bool, 1),
|
||||||
}
|
}
|
||||||
// add CopyData identifier + 4 bytes for message length
|
// add CopyData identifier + 4 bytes for message length
|
||||||
ci.buffer = append(ci.buffer, 'd', 0, 0, 0, 0)
|
ci.buffer = append(ci.buffer, 'd', 0, 0, 0, 0)
|
||||||
|
@ -96,11 +96,13 @@ awaitCopyInResponse:
|
||||||
err = parseError(r)
|
err = parseError(r)
|
||||||
case 'Z':
|
case 'Z':
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
cn.bad = true
|
||||||
errorf("unexpected ReadyForQuery in response to COPY")
|
errorf("unexpected ReadyForQuery in response to COPY")
|
||||||
}
|
}
|
||||||
cn.processReadyForQuery(r)
|
cn.processReadyForQuery(r)
|
||||||
return nil, err
|
return nil, err
|
||||||
default:
|
default:
|
||||||
|
cn.bad = true
|
||||||
errorf("unknown response for copy query: %q", t)
|
errorf("unknown response for copy query: %q", t)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -119,11 +121,10 @@ awaitCopyInResponse:
|
||||||
cn.processReadyForQuery(r)
|
cn.processReadyForQuery(r)
|
||||||
return nil, err
|
return nil, err
|
||||||
default:
|
default:
|
||||||
|
cn.bad = true
|
||||||
errorf("unknown response for CopyFail: %q", t)
|
errorf("unknown response for CopyFail: %q", t)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
panic("not reached")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ci *copyin) flush(buf []byte) {
|
func (ci *copyin) flush(buf []byte) {
|
||||||
|
@ -138,30 +139,50 @@ func (ci *copyin) flush(buf []byte) {
|
||||||
|
|
||||||
func (ci *copyin) resploop() {
|
func (ci *copyin) resploop() {
|
||||||
for {
|
for {
|
||||||
t, r := ci.cn.recv1()
|
var r readBuf
|
||||||
|
t, err := ci.cn.recvMessage(&r)
|
||||||
|
if err != nil {
|
||||||
|
ci.cn.bad = true
|
||||||
|
ci.setError(err)
|
||||||
|
ci.done <- true
|
||||||
|
return
|
||||||
|
}
|
||||||
switch t {
|
switch t {
|
||||||
case 'C':
|
case 'C':
|
||||||
// complete
|
// complete
|
||||||
|
case 'N':
|
||||||
|
// NoticeResponse
|
||||||
case 'Z':
|
case 'Z':
|
||||||
ci.cn.processReadyForQuery(r)
|
ci.cn.processReadyForQuery(&r)
|
||||||
ci.done <- true
|
ci.done <- true
|
||||||
return
|
return
|
||||||
case 'E':
|
case 'E':
|
||||||
err := parseError(r)
|
err := parseError(&r)
|
||||||
ci.setError(err)
|
ci.setError(err)
|
||||||
default:
|
default:
|
||||||
errorf("unknown response: %q", t)
|
ci.cn.bad = true
|
||||||
|
ci.setError(fmt.Errorf("unknown response during CopyIn: %q", t))
|
||||||
|
ci.done <- true
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ci *copyin) isErrorSet() bool {
|
func (ci *copyin) isErrorSet() bool {
|
||||||
return atomic.LoadInt32(&ci.errorset) != 0
|
ci.Lock()
|
||||||
|
isSet := (ci.err != nil)
|
||||||
|
ci.Unlock()
|
||||||
|
return isSet
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// setError() sets ci.err if one has not been set already. Caller must not be
|
||||||
|
// holding ci.Mutex.
|
||||||
func (ci *copyin) setError(err error) {
|
func (ci *copyin) setError(err error) {
|
||||||
ci.err = err
|
ci.Lock()
|
||||||
atomic.StoreInt32(&ci.errorset, 1)
|
if ci.err == nil {
|
||||||
|
ci.err = err
|
||||||
|
}
|
||||||
|
ci.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ci *copyin) NumInput() int {
|
func (ci *copyin) NumInput() int {
|
||||||
|
@ -180,20 +201,21 @@ func (ci *copyin) Query(v []driver.Value) (r driver.Rows, err error) {
|
||||||
// errors from pending data, since Stmt.Close() doesn't return errors
|
// errors from pending data, since Stmt.Close() doesn't return errors
|
||||||
// to the user.
|
// to the user.
|
||||||
func (ci *copyin) Exec(v []driver.Value) (r driver.Result, err error) {
|
func (ci *copyin) Exec(v []driver.Value) (r driver.Result, err error) {
|
||||||
defer errRecover(&err)
|
|
||||||
|
|
||||||
if ci.closed {
|
if ci.closed {
|
||||||
return nil, errCopyInClosed
|
return nil, errCopyInClosed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ci.cn.bad {
|
||||||
|
return nil, driver.ErrBadConn
|
||||||
|
}
|
||||||
|
defer ci.cn.errRecover(&err)
|
||||||
|
|
||||||
if ci.isErrorSet() {
|
if ci.isErrorSet() {
|
||||||
return nil, ci.err
|
return nil, ci.err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(v) == 0 {
|
if len(v) == 0 {
|
||||||
err = ci.Close()
|
return nil, ci.Close()
|
||||||
ci.closed = true
|
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
numValues := len(v)
|
numValues := len(v)
|
||||||
|
@ -216,11 +238,15 @@ func (ci *copyin) Exec(v []driver.Value) (r driver.Result, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ci *copyin) Close() (err error) {
|
func (ci *copyin) Close() (err error) {
|
||||||
defer errRecover(&err)
|
if ci.closed { // Don't do anything, we're already closed
|
||||||
|
return nil
|
||||||
if ci.closed {
|
|
||||||
return errCopyInClosed
|
|
||||||
}
|
}
|
||||||
|
ci.closed = true
|
||||||
|
|
||||||
|
if ci.cn.bad {
|
||||||
|
return driver.ErrBadConn
|
||||||
|
}
|
||||||
|
defer ci.cn.errRecover(&err)
|
||||||
|
|
||||||
if len(ci.buffer) > 0 {
|
if len(ci.buffer) > 0 {
|
||||||
ci.flush(ci.buffer)
|
ci.flush(ci.buffer)
|
||||||
|
|
138
vendor/github.com/lib/pq/copy_test.go
generated
vendored
138
vendor/github.com/lib/pq/copy_test.go
generated
vendored
|
@ -94,6 +94,86 @@ func TestCopyInMultipleValues(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCopyInRaiseStmtTrigger(t *testing.T) {
|
||||||
|
db := openTestConn(t)
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
|
if getServerVersion(t, db) < 90000 {
|
||||||
|
var exists int
|
||||||
|
err := db.QueryRow("SELECT 1 FROM pg_language WHERE lanname = 'plpgsql'").Scan(&exists)
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
t.Skip("language PL/PgSQL does not exist; skipping TestCopyInRaiseStmtTrigger")
|
||||||
|
} else if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = txn.Exec(`
|
||||||
|
CREATE OR REPLACE FUNCTION pg_temp.temptest()
|
||||||
|
RETURNS trigger AS
|
||||||
|
$BODY$ begin
|
||||||
|
raise notice 'Hello world';
|
||||||
|
return new;
|
||||||
|
end $BODY$
|
||||||
|
LANGUAGE plpgsql`)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = txn.Exec(`
|
||||||
|
CREATE TRIGGER temptest_trigger
|
||||||
|
BEFORE INSERT
|
||||||
|
ON temp
|
||||||
|
FOR EACH ROW
|
||||||
|
EXECUTE PROCEDURE pg_temp.temptest()`)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
stmt, err := txn.Prepare(CopyIn("temp", "a", "b"))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
longString := strings.Repeat("#", 500)
|
||||||
|
|
||||||
|
_, err = stmt.Exec(int64(1), 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 != 1 {
|
||||||
|
t.Fatalf("expected 1 items, not %d", num)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestCopyInTypes(t *testing.T) {
|
func TestCopyInTypes(t *testing.T) {
|
||||||
db := openTestConn(t)
|
db := openTestConn(t)
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
@ -275,6 +355,64 @@ func TestCopySyntaxError(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
if getServerVersion(t, db) < 90500 {
|
||||||
|
// We have to try and send something over, since postgres before
|
||||||
|
// version 9.5 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) {
|
func BenchmarkCopyIn(b *testing.B) {
|
||||||
db := openTestConn(b)
|
db := openTestConn(b)
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
|
9
vendor/github.com/lib/pq/doc.go
generated
vendored
9
vendor/github.com/lib/pq/doc.go
generated
vendored
|
@ -5,8 +5,9 @@ In most cases clients will use the database/sql package instead of
|
||||||
using this package directly. For example:
|
using this package directly. For example:
|
||||||
|
|
||||||
import (
|
import (
|
||||||
_ "github.com/lib/pq"
|
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
|
||||||
|
_ "github.com/lib/pq"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
@ -47,12 +48,16 @@ supported:
|
||||||
* sslmode - Whether or not to use SSL (default is require, this is not the default for libpq)
|
* sslmode - Whether or not to use SSL (default is require, this is not the default for libpq)
|
||||||
* fallback_application_name - An application_name to fall back to if one isn't provided.
|
* fallback_application_name - An application_name to fall back to if one isn't provided.
|
||||||
* connect_timeout - Maximum wait for connection, in seconds. Zero or not specified means wait indefinitely.
|
* connect_timeout - Maximum wait for connection, in seconds. Zero or not specified means wait indefinitely.
|
||||||
|
* sslcert - Cert file location. The file must contain PEM encoded data.
|
||||||
|
* sslkey - Key file location. The file must contain PEM encoded data.
|
||||||
|
* sslrootcert - The location of the root certificate file. The file must contain PEM encoded data.
|
||||||
|
|
||||||
Valid values for sslmode are:
|
Valid values for sslmode are:
|
||||||
|
|
||||||
* disable - No SSL
|
* disable - No SSL
|
||||||
* require - Always SSL (skip verification)
|
* require - Always SSL (skip verification)
|
||||||
* verify-full - Always SSL (require verification)
|
* verify-ca - Always SSL (verify that the certificate presented by the server was signed by a trusted CA)
|
||||||
|
* verify-full - Always SSL (verify that the certification presented by the server was signed by a trusted CA and the server host name matches the one in the certificate)
|
||||||
|
|
||||||
See http://www.postgresql.org/docs/current/static/libpq-connect.html#LIBPQ-CONNSTRING
|
See http://www.postgresql.org/docs/current/static/libpq-connect.html#LIBPQ-CONNSTRING
|
||||||
for more information about connection string parameters.
|
for more information about connection string parameters.
|
||||||
|
|
184
vendor/github.com/lib/pq/encode.go
generated
vendored
184
vendor/github.com/lib/pq/encode.go
generated
vendored
|
@ -3,24 +3,34 @@ package pq
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"database/sql/driver"
|
"database/sql/driver"
|
||||||
|
"encoding/binary"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/lib/pq/oid"
|
|
||||||
"math"
|
"math"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"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)
|
||||||
|
}
|
||||||
|
panic("not reached")
|
||||||
|
}
|
||||||
|
|
||||||
func encode(parameterStatus *parameterStatus, x interface{}, pgtypOid oid.Oid) []byte {
|
func encode(parameterStatus *parameterStatus, x interface{}, pgtypOid oid.Oid) []byte {
|
||||||
switch v := x.(type) {
|
switch v := x.(type) {
|
||||||
case int64:
|
case int64:
|
||||||
return []byte(fmt.Sprintf("%d", v))
|
return strconv.AppendInt(nil, v, 10)
|
||||||
case float32:
|
|
||||||
return []byte(fmt.Sprintf("%.9f", v))
|
|
||||||
case float64:
|
case float64:
|
||||||
return []byte(fmt.Sprintf("%.17f", v))
|
return strconv.AppendFloat(nil, v, 'f', -1, 64)
|
||||||
case []byte:
|
case []byte:
|
||||||
if pgtypOid == oid.T_bytea {
|
if pgtypOid == oid.T_bytea {
|
||||||
return encodeBytea(parameterStatus.serverVersion, v)
|
return encodeBytea(parameterStatus.serverVersion, v)
|
||||||
|
@ -34,7 +44,7 @@ func encode(parameterStatus *parameterStatus, x interface{}, pgtypOid oid.Oid) [
|
||||||
|
|
||||||
return []byte(v)
|
return []byte(v)
|
||||||
case bool:
|
case bool:
|
||||||
return []byte(fmt.Sprintf("%t", v))
|
return strconv.AppendBool(nil, v)
|
||||||
case time.Time:
|
case time.Time:
|
||||||
return formatTs(v)
|
return formatTs(v)
|
||||||
|
|
||||||
|
@ -45,7 +55,33 @@ func encode(parameterStatus *parameterStatus, x interface{}, pgtypOid oid.Oid) [
|
||||||
panic("not reached")
|
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{} {
|
||||||
|
if f == formatBinary {
|
||||||
|
return binaryDecode(parameterStatus, s, typ)
|
||||||
|
} else {
|
||||||
|
return textDecode(parameterStatus, s, typ)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func binaryDecode(parameterStatus *parameterStatus, s []byte, typ oid.Oid) interface{} {
|
||||||
|
switch typ {
|
||||||
|
case oid.T_bytea:
|
||||||
|
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)))
|
||||||
|
|
||||||
|
default:
|
||||||
|
errorf("don't know how to decode binary parameter of type %u", uint32(typ))
|
||||||
|
}
|
||||||
|
|
||||||
|
panic("not reached")
|
||||||
|
}
|
||||||
|
|
||||||
|
func textDecode(parameterStatus *parameterStatus, s []byte, typ oid.Oid) interface{} {
|
||||||
switch typ {
|
switch typ {
|
||||||
case oid.T_bytea:
|
case oid.T_bytea:
|
||||||
return parseBytea(s)
|
return parseBytea(s)
|
||||||
|
@ -59,7 +95,7 @@ func decode(parameterStatus *parameterStatus, s []byte, typ oid.Oid) interface{}
|
||||||
return mustParse("15:04:05-07", typ, s)
|
return mustParse("15:04:05-07", typ, s)
|
||||||
case oid.T_bool:
|
case oid.T_bool:
|
||||||
return s[0] == 't'
|
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)
|
i, err := strconv.ParseInt(string(s), 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorf("%s", err)
|
errorf("%s", err)
|
||||||
|
@ -86,8 +122,6 @@ func appendEncodedText(parameterStatus *parameterStatus, buf []byte, x interface
|
||||||
switch v := x.(type) {
|
switch v := x.(type) {
|
||||||
case int64:
|
case int64:
|
||||||
return strconv.AppendInt(buf, v, 10)
|
return strconv.AppendInt(buf, v, 10)
|
||||||
case float32:
|
|
||||||
return strconv.AppendFloat(buf, float64(v), 'f', -1, 32)
|
|
||||||
case float64:
|
case float64:
|
||||||
return strconv.AppendFloat(buf, v, 'f', -1, 64)
|
return strconv.AppendFloat(buf, v, 'f', -1, 64)
|
||||||
case []byte:
|
case []byte:
|
||||||
|
@ -149,12 +183,6 @@ func appendEscapedText(buf []byte, text string) []byte {
|
||||||
func mustParse(f string, typ oid.Oid, s []byte) time.Time {
|
func mustParse(f string, typ oid.Oid, s []byte) time.Time {
|
||||||
str := string(s)
|
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
|
// check for a 30-minute-offset timezone
|
||||||
if (typ == oid.T_timestamptz || typ == oid.T_timetz) &&
|
if (typ == oid.T_timestamptz || typ == oid.T_timetz) &&
|
||||||
str[len(str)-3] == ':' {
|
str[len(str)-3] == ':' {
|
||||||
|
@ -212,12 +240,75 @@ func (c *locationCache) getLocation(offset int) *time.Location {
|
||||||
return 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"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 preceeds 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
|
// This is a time function specific to the Postgres default DateStyle
|
||||||
// setting ("ISO, MDY"), the only one we currently support. This
|
// setting ("ISO, MDY"), the only one we currently support. This
|
||||||
// accounts for the discrepancies between the parsing available with
|
// accounts for the discrepancies between the parsing available with
|
||||||
// time.Parse and the Postgres date formatting quirks.
|
// 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)
|
||||||
|
}
|
||||||
|
|
||||||
monSep := strings.IndexRune(str, '-')
|
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 := mustAtoi(str[:monSep])
|
||||||
daySep := monSep + 3
|
daySep := monSep + 3
|
||||||
month := mustAtoi(str[monSep+1 : daySep])
|
month := mustAtoi(str[monSep+1 : daySep])
|
||||||
|
@ -245,7 +336,6 @@ func parseTs(currentLocation *time.Location, str string) (result time.Time) {
|
||||||
|
|
||||||
nanoSec := 0
|
nanoSec := 0
|
||||||
tzOff := 0
|
tzOff := 0
|
||||||
bcSign := 1
|
|
||||||
|
|
||||||
if remainderIdx < len(str) && str[remainderIdx:remainderIdx+1] == "." {
|
if remainderIdx < len(str) && str[remainderIdx:remainderIdx+1] == "." {
|
||||||
fracStart := remainderIdx + 1
|
fracStart := remainderIdx + 1
|
||||||
|
@ -281,14 +371,17 @@ func parseTs(currentLocation *time.Location, str string) (result time.Time) {
|
||||||
}
|
}
|
||||||
tzOff = tzSign * ((tzHours * 60 * 60) + (tzMin * 60) + tzSec)
|
tzOff = tzSign * ((tzHours * 60 * 60) + (tzMin * 60) + tzSec)
|
||||||
}
|
}
|
||||||
|
var isoYear int
|
||||||
if remainderIdx < len(str) && str[remainderIdx:remainderIdx+3] == " BC" {
|
if remainderIdx < len(str) && str[remainderIdx:remainderIdx+3] == " BC" {
|
||||||
bcSign = -1
|
isoYear = 1 - year
|
||||||
remainderIdx += 3
|
remainderIdx += 3
|
||||||
|
} else {
|
||||||
|
isoYear = year
|
||||||
}
|
}
|
||||||
if remainderIdx < len(str) {
|
if remainderIdx < len(str) {
|
||||||
errorf("expected end of input, got %v", str[remainderIdx:])
|
errorf("expected end of input, got %v", str[remainderIdx:])
|
||||||
}
|
}
|
||||||
t := time.Date(bcSign*year, time.Month(month), day,
|
t := time.Date(isoYear, time.Month(month), day,
|
||||||
hour, minute, second, nanoSec,
|
hour, minute, second, nanoSec,
|
||||||
globalLocationCache.getLocation(tzOff))
|
globalLocationCache.getLocation(tzOff))
|
||||||
|
|
||||||
|
@ -306,26 +399,48 @@ func parseTs(currentLocation *time.Location, str string) (result time.Time) {
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
// formatTs formats t as time.RFC3339Nano and appends time zone seconds if
|
// formatTs formats t into a format postgres understands.
|
||||||
// needed.
|
|
||||||
func formatTs(t time.Time) (b []byte) {
|
func formatTs(t time.Time) (b []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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 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
|
||||||
|
bc := false
|
||||||
|
if t.Year() <= 0 {
|
||||||
|
// flip year sign, and add 1, e.g: "0" will be "1", and "-10" will be "11"
|
||||||
|
t = t.AddDate((-t.Year())*2+1, 0, 0)
|
||||||
|
bc = true
|
||||||
|
}
|
||||||
b = []byte(t.Format(time.RFC3339Nano))
|
b = []byte(t.Format(time.RFC3339Nano))
|
||||||
|
|
||||||
_, offset := t.Zone()
|
_, offset := t.Zone()
|
||||||
offset = offset % 60
|
offset = offset % 60
|
||||||
if offset == 0 {
|
if offset != 0 {
|
||||||
return b
|
// RFC3339Nano already printed the minus sign
|
||||||
|
if offset < 0 {
|
||||||
|
offset = -offset
|
||||||
|
}
|
||||||
|
|
||||||
|
b = append(b, ':')
|
||||||
|
if offset < 10 {
|
||||||
|
b = append(b, '0')
|
||||||
|
}
|
||||||
|
b = strconv.AppendInt(b, int64(offset), 10)
|
||||||
}
|
}
|
||||||
|
|
||||||
if offset < 0 {
|
if bc {
|
||||||
offset = -offset
|
b = append(b, " BC"...)
|
||||||
}
|
}
|
||||||
|
return b
|
||||||
b = append(b, ':')
|
|
||||||
if offset < 10 {
|
|
||||||
b = append(b, '0')
|
|
||||||
}
|
|
||||||
return strconv.AppendInt(b, int64(offset), 10)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse a bytea value received from the server. Both "hex" and the legacy
|
// Parse a bytea value received from the server. Both "hex" and the legacy
|
||||||
|
@ -380,7 +495,10 @@ func parseBytea(s []byte) (result []byte) {
|
||||||
func encodeBytea(serverVersion int, v []byte) (result []byte) {
|
func encodeBytea(serverVersion int, v []byte) (result []byte) {
|
||||||
if serverVersion >= 90000 {
|
if serverVersion >= 90000 {
|
||||||
// Use the hex format if we know that the server supports it
|
// 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 {
|
} else {
|
||||||
// .. or resort to "escape"
|
// .. or resort to "escape"
|
||||||
for _, b := range v {
|
for _, b := range v {
|
||||||
|
|
370
vendor/github.com/lib/pq/encode_test.go
generated
vendored
370
vendor/github.com/lib/pq/encode_test.go
generated
vendored
|
@ -1,12 +1,13 @@
|
||||||
package pq
|
package pq
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/lib/pq/oid"
|
|
||||||
|
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/lib/pq/oid"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestScanTimestamp(t *testing.T) {
|
func TestScanTimestamp(t *testing.T) {
|
||||||
|
@ -30,8 +31,8 @@ func TestScanNilTimestamp(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var timeTests = []struct {
|
var timeTests = []struct {
|
||||||
str string
|
str string
|
||||||
expected time.Time
|
timeval time.Time
|
||||||
}{
|
}{
|
||||||
{"22001-02-03", time.Date(22001, time.February, 3, 0, 0, 0, 0, time.FixedZone("", 0))},
|
{"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", time.Date(2001, time.February, 3, 0, 0, 0, 0, time.FixedZone("", 0))},
|
||||||
|
@ -57,13 +58,20 @@ var timeTests = []struct {
|
||||||
time.FixedZone("", -(7*60*60+30*60+9)))},
|
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,
|
{"2001-02-03 04:05:06+07", time.Date(2001, time.February, 3, 4, 5, 6, 0,
|
||||||
time.FixedZone("", 7*60*60))},
|
time.FixedZone("", 7*60*60))},
|
||||||
{"10000-02-03 04:05:06 BC", time.Date(-10000, time.February, 3, 4, 5, 6, 0, time.FixedZone("", 0))},
|
{"0011-02-03 04:05:06 BC", time.Date(-10, time.February, 3, 4, 5, 6, 0, time.FixedZone("", 0))},
|
||||||
{"0010-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))},
|
||||||
{"0010-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,
|
||||||
{"0010-02-03 04:05:06.123-07 BC", time.Date(-10, time.February, 3, 4, 5, 6, 123000000,
|
|
||||||
time.FixedZone("", -7*60*60))},
|
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) {
|
func tryParse(str string) (t time.Time, err error) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if p := recover(); p != nil {
|
if p := recover(); p != nil {
|
||||||
|
@ -71,19 +79,52 @@ func tryParse(str string) (t time.Time, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
t = parseTs(nil, str)
|
i := parseTs(nil, str)
|
||||||
|
t, ok := i.(time.Time)
|
||||||
|
if !ok {
|
||||||
|
err = fmt.Errorf("Not a time.Time type, got %#v", i)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test that parsing the string results in the expected value.
|
||||||
func TestParseTs(t *testing.T) {
|
func TestParseTs(t *testing.T) {
|
||||||
for i, tt := range timeTests {
|
for i, tt := range timeTests {
|
||||||
val, err := tryParse(tt.str)
|
val, err := tryParse(tt.str)
|
||||||
if val.String() != tt.expected.String() {
|
|
||||||
t.Errorf("%d: expected to parse %q into %q; got %q",
|
|
||||||
i, tt.str, tt.expected, val)
|
|
||||||
}
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("%d: got error: %v", i, err)
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,8 +137,18 @@ var formatTimeTests = []struct {
|
||||||
{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("", 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("", 2*60*60)), "2001-02-03T04:05:06.123456789+02:00"},
|
||||||
{time.Date(2001, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", -6*60*60)), "2001-02-03T04:05:06.123456789-06:00"},
|
{time.Date(2001, time.February, 3, 4, 5, 6, 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"},
|
{time.Date(2001, time.February, 3, 4, 5, 6, 0, time.FixedZone("", -(7*60*60+30*60+9))), "2001-02-03T04:05:06-07:30:09"},
|
||||||
|
|
||||||
|
{time.Date(1, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", 0)), "0001-02-03T04:05:06.123456789Z"},
|
||||||
|
{time.Date(1, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", 2*60*60)), "0001-02-03T04:05:06.123456789+02:00"},
|
||||||
|
{time.Date(1, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", -6*60*60)), "0001-02-03T04:05:06.123456789-06:00"},
|
||||||
|
|
||||||
|
{time.Date(0, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", 0)), "0001-02-03T04:05:06.123456789Z BC"},
|
||||||
|
{time.Date(0, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", 2*60*60)), "0001-02-03T04:05:06.123456789+02:00 BC"},
|
||||||
|
{time.Date(0, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", -6*60*60)), "0001-02-03T04:05:06.123456789-06:00 BC"},
|
||||||
|
|
||||||
|
{time.Date(1, time.February, 3, 4, 5, 6, 0, time.FixedZone("", -(7*60*60+30*60+9))), "0001-02-03T04:05:06-07:30:09"},
|
||||||
|
{time.Date(0, time.February, 3, 4, 5, 6, 0, time.FixedZone("", -(7*60*60+30*60+9))), "0001-02-03T04:05:06-07:30:09 BC"},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFormatTs(t *testing.T) {
|
func TestFormatTs(t *testing.T) {
|
||||||
|
@ -213,6 +264,131 @@ func TestTimestampWithOutTimezone(t *testing.T) {
|
||||||
test("2013-01-04T20:14:58.80033Z", "2013-01-04 20:14:58.80033")
|
test("2013-01-04T20:14:58.80033Z", "2013-01-04 20:14:58.80033")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestInfinityTimestamp(t *testing.T) {
|
||||||
|
db := openTestConn(t)
|
||||||
|
defer db.Close()
|
||||||
|
var err error
|
||||||
|
var resultT time.Time
|
||||||
|
|
||||||
|
expectedError := fmt.Errorf(`sql: Scan error on column index 0: unsupported driver -> Scan pair: []uint8 -> *time.Time`)
|
||||||
|
type testCases []struct {
|
||||||
|
Query string
|
||||||
|
Param string
|
||||||
|
ExpectedErr error
|
||||||
|
ExpectedVal interface{}
|
||||||
|
}
|
||||||
|
tc := testCases{
|
||||||
|
{"SELECT $1::timestamp", "-infinity", expectedError, "-infinity"},
|
||||||
|
{"SELECT $1::timestamptz", "-infinity", expectedError, "-infinity"},
|
||||||
|
{"SELECT $1::timestamp", "infinity", expectedError, "infinity"},
|
||||||
|
{"SELECT $1::timestamptz", "infinity", expectedError, "infinity"},
|
||||||
|
}
|
||||||
|
// try to assert []byte to time.Time
|
||||||
|
for _, q := range tc {
|
||||||
|
err = db.QueryRow(q.Query, q.Param).Scan(&resultT)
|
||||||
|
if err.Error() != q.ExpectedErr.Error() {
|
||||||
|
t.Errorf("Scanning -/+infinity, expected error, %q, got %q", q.ExpectedErr, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// yield []byte
|
||||||
|
for _, q := range tc {
|
||||||
|
var resultI interface{}
|
||||||
|
err = db.QueryRow(q.Query, q.Param).Scan(&resultI)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Scanning -/+infinity, expected no error, got %q", err)
|
||||||
|
}
|
||||||
|
result, ok := resultI.([]byte)
|
||||||
|
if !ok {
|
||||||
|
t.Errorf("Scanning -/+infinity, expected []byte, got %#v", resultI)
|
||||||
|
}
|
||||||
|
if string(result) != q.ExpectedVal {
|
||||||
|
t.Errorf("Scanning -/+infinity, expected %q, got %q", q.ExpectedVal, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
y1500 := time.Date(1500, time.January, 1, 0, 0, 0, 0, time.UTC)
|
||||||
|
y2500 := time.Date(2500, time.January, 1, 0, 0, 0, 0, time.UTC)
|
||||||
|
EnableInfinityTs(y1500, y2500)
|
||||||
|
|
||||||
|
err = db.QueryRow("SELECT $1::timestamp", "infinity").Scan(&resultT)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Scanning infinity, expected no error, got %q", err)
|
||||||
|
}
|
||||||
|
if !resultT.Equal(y2500) {
|
||||||
|
t.Errorf("Scanning infinity, expected %q, got %q", y2500, resultT)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = db.QueryRow("SELECT $1::timestamptz", "infinity").Scan(&resultT)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Scanning infinity, expected no error, got %q", err)
|
||||||
|
}
|
||||||
|
if !resultT.Equal(y2500) {
|
||||||
|
t.Errorf("Scanning Infinity, expected time %q, got %q", y2500, resultT.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
err = db.QueryRow("SELECT $1::timestamp", "-infinity").Scan(&resultT)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Scanning -infinity, expected no error, got %q", err)
|
||||||
|
}
|
||||||
|
if !resultT.Equal(y1500) {
|
||||||
|
t.Errorf("Scanning -infinity, expected time %q, got %q", y1500, resultT.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
err = db.QueryRow("SELECT $1::timestamptz", "-infinity").Scan(&resultT)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Scanning -infinity, expected no error, got %q", err)
|
||||||
|
}
|
||||||
|
if !resultT.Equal(y1500) {
|
||||||
|
t.Errorf("Scanning -infinity, expected time %q, got %q", y1500, resultT.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
y_1500 := time.Date(-1500, time.January, 1, 0, 0, 0, 0, time.UTC)
|
||||||
|
y11500 := time.Date(11500, time.January, 1, 0, 0, 0, 0, time.UTC)
|
||||||
|
var s string
|
||||||
|
err = db.QueryRow("SELECT $1::timestamp::text", y_1500).Scan(&s)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Encoding -infinity, expected no error, got %q", err)
|
||||||
|
}
|
||||||
|
if s != "-infinity" {
|
||||||
|
t.Errorf("Encoding -infinity, expected %q, got %q", "-infinity", s)
|
||||||
|
}
|
||||||
|
err = db.QueryRow("SELECT $1::timestamptz::text", y_1500).Scan(&s)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Encoding -infinity, expected no error, got %q", err)
|
||||||
|
}
|
||||||
|
if s != "-infinity" {
|
||||||
|
t.Errorf("Encoding -infinity, expected %q, got %q", "-infinity", s)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = db.QueryRow("SELECT $1::timestamp::text", y11500).Scan(&s)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Encoding infinity, expected no error, got %q", err)
|
||||||
|
}
|
||||||
|
if s != "infinity" {
|
||||||
|
t.Errorf("Encoding infinity, expected %q, got %q", "infinity", s)
|
||||||
|
}
|
||||||
|
err = db.QueryRow("SELECT $1::timestamptz::text", y11500).Scan(&s)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Encoding infinity, expected no error, got %q", err)
|
||||||
|
}
|
||||||
|
if s != "infinity" {
|
||||||
|
t.Errorf("Encoding infinity, expected %q, got %q", "infinity", s)
|
||||||
|
}
|
||||||
|
|
||||||
|
disableInfinityTs()
|
||||||
|
|
||||||
|
var panicErrorString string
|
||||||
|
func() {
|
||||||
|
defer func() {
|
||||||
|
panicErrorString, _ = recover().(string)
|
||||||
|
}()
|
||||||
|
EnableInfinityTs(y2500, y1500)
|
||||||
|
}()
|
||||||
|
if panicErrorString != infinityTsNegativeMustBeSmaller {
|
||||||
|
t.Errorf("Expected error, %q, got %q", infinityTsNegativeMustBeSmaller, panicErrorString)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestStringWithNul(t *testing.T) {
|
func TestStringWithNul(t *testing.T) {
|
||||||
db := openTestConn(t)
|
db := openTestConn(t)
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
@ -225,7 +401,7 @@ func TestStringWithNul(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestByteaToText(t *testing.T) {
|
func TestByteSliceToText(t *testing.T) {
|
||||||
db := openTestConn(t)
|
db := openTestConn(t)
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
|
||||||
|
@ -243,7 +419,7 @@ func TestByteaToText(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTextToBytea(t *testing.T) {
|
func TestStringToBytea(t *testing.T) {
|
||||||
db := openTestConn(t)
|
db := openTestConn(t)
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
|
||||||
|
@ -261,6 +437,136 @@ func TestTextToBytea(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTextByteSliceToUUID(t *testing.T) {
|
||||||
|
db := openTestConn(t)
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
|
b := []byte("a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11")
|
||||||
|
row := db.QueryRow("SELECT $1::uuid", b)
|
||||||
|
|
||||||
|
var result string
|
||||||
|
err := row.Scan(&result)
|
||||||
|
if forceBinaryParameters() {
|
||||||
|
pqErr := err.(*Error)
|
||||||
|
if pqErr == nil {
|
||||||
|
t.Errorf("Expected to get error")
|
||||||
|
} else if pqErr.Code != "22P03" {
|
||||||
|
t.Fatalf("Expected to get invalid binary encoding error (22P03), got %s", pqErr.Code)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if result != string(b) {
|
||||||
|
t.Fatalf("expected %v but got %v", b, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBinaryByteSlicetoUUID(t *testing.T) {
|
||||||
|
db := openTestConn(t)
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
|
b := []byte{'\xa0','\xee','\xbc','\x99',
|
||||||
|
'\x9c', '\x0b',
|
||||||
|
'\x4e', '\xf8',
|
||||||
|
'\xbb', '\x00', '\x6b',
|
||||||
|
'\xb9', '\xbd', '\x38', '\x0a', '\x11'}
|
||||||
|
row := db.QueryRow("SELECT $1::uuid", b)
|
||||||
|
|
||||||
|
var result string
|
||||||
|
err := row.Scan(&result)
|
||||||
|
if forceBinaryParameters() {
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if result != string("a0eebc99-9c0b-4ef8-bb00-6bb9bd380a11") {
|
||||||
|
t.Fatalf("expected %v but got %v", b, result)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pqErr := err.(*Error)
|
||||||
|
if pqErr == nil {
|
||||||
|
t.Errorf("Expected to get error")
|
||||||
|
} else if pqErr.Code != "22021" {
|
||||||
|
t.Fatalf("Expected to get invalid byte sequence for encoding error (22021), got %s", pqErr.Code)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStringToUUID(t *testing.T) {
|
||||||
|
db := openTestConn(t)
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
|
s := "a0eebc99-9c0b-4ef8-bb00-6bb9bd380a11"
|
||||||
|
row := db.QueryRow("SELECT $1::uuid", s)
|
||||||
|
|
||||||
|
var result string
|
||||||
|
err := row.Scan(&result)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if result != s {
|
||||||
|
t.Fatalf("expected %v but got %v", s, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTextByteSliceToInt(t *testing.T) {
|
||||||
|
db := openTestConn(t)
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
|
expected := 12345678
|
||||||
|
b := []byte(fmt.Sprintf("%d", expected))
|
||||||
|
row := db.QueryRow("SELECT $1::int", b)
|
||||||
|
|
||||||
|
var result int
|
||||||
|
err := row.Scan(&result)
|
||||||
|
if forceBinaryParameters() {
|
||||||
|
pqErr := err.(*Error)
|
||||||
|
if pqErr == nil {
|
||||||
|
t.Errorf("Expected to get error")
|
||||||
|
} else if pqErr.Code != "22P03" {
|
||||||
|
t.Fatalf("Expected to get invalid binary encoding error (22P03), got %s", pqErr.Code)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if result != expected {
|
||||||
|
t.Fatalf("expected %v but got %v", expected, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBinaryByteSliceToInt(t *testing.T) {
|
||||||
|
db := openTestConn(t)
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
|
expected := 12345678
|
||||||
|
b := []byte{'\x00', '\xbc', '\x61', '\x4e'}
|
||||||
|
row := db.QueryRow("SELECT $1::int", b)
|
||||||
|
|
||||||
|
var result int
|
||||||
|
err := row.Scan(&result)
|
||||||
|
if forceBinaryParameters() {
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if result != expected {
|
||||||
|
t.Fatalf("expected %v but got %v", expected, result)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pqErr := err.(*Error)
|
||||||
|
if pqErr == nil {
|
||||||
|
t.Errorf("Expected to get error")
|
||||||
|
} else if pqErr.Code != "22021" {
|
||||||
|
t.Fatalf("Expected to get invalid byte sequence for encoding error (22021), got %s", pqErr.Code)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestByteaOutputFormatEncoding(t *testing.T) {
|
func TestByteaOutputFormatEncoding(t *testing.T) {
|
||||||
input := []byte("\\x\x00\x01\x02\xFF\xFEabcdefg0123")
|
input := []byte("\\x\x00\x01\x02\xFF\xFEabcdefg0123")
|
||||||
want := []byte("\\x5c78000102fffe6162636465666730313233")
|
want := []byte("\\x5c78000102fffe6162636465666730313233")
|
||||||
|
@ -285,7 +591,7 @@ func TestByteaOutputFormats(t *testing.T) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
testByteaOutputFormat := func(f string) {
|
testByteaOutputFormat := func(f string, usePrepared bool) {
|
||||||
expectedData := []byte("\x5c\x78\x00\xff\x61\x62\x63\x01\x08")
|
expectedData := []byte("\x5c\x78\x00\xff\x61\x62\x63\x01\x08")
|
||||||
sqlQuery := "SELECT decode('5c7800ff6162630108', 'hex')"
|
sqlQuery := "SELECT decode('5c7800ff6162630108', 'hex')"
|
||||||
|
|
||||||
|
@ -302,8 +608,18 @@ func TestByteaOutputFormats(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
// use Query; QueryRow would hide the actual error
|
var rows *sql.Rows
|
||||||
rows, err := txn.Query(sqlQuery)
|
var stmt *sql.Stmt
|
||||||
|
if usePrepared {
|
||||||
|
stmt, err = txn.Prepare(sqlQuery)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
rows, err = stmt.Query()
|
||||||
|
} else {
|
||||||
|
// use Query; QueryRow would hide the actual error
|
||||||
|
rows, err = txn.Query(sqlQuery)
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -321,13 +637,21 @@ func TestByteaOutputFormats(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
if stmt != nil {
|
||||||
|
err = stmt.Close()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
if !bytes.Equal(data, expectedData) {
|
if !bytes.Equal(data, expectedData) {
|
||||||
t.Errorf("unexpected bytea value %v for format %s; expected %v", data, f, expectedData)
|
t.Errorf("unexpected bytea value %v for format %s; expected %v", data, f, expectedData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
testByteaOutputFormat("hex")
|
testByteaOutputFormat("hex", false)
|
||||||
testByteaOutputFormat("escape")
|
testByteaOutputFormat("escape", false)
|
||||||
|
testByteaOutputFormat("hex", true)
|
||||||
|
testByteaOutputFormat("escape", true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAppendEncodedText(t *testing.T) {
|
func TestAppendEncodedText(t *testing.T) {
|
||||||
|
@ -335,15 +659,13 @@ func TestAppendEncodedText(t *testing.T) {
|
||||||
|
|
||||||
buf = appendEncodedText(¶meterStatus{serverVersion: 90000}, buf, int64(10))
|
buf = appendEncodedText(¶meterStatus{serverVersion: 90000}, buf, int64(10))
|
||||||
buf = append(buf, '\t')
|
buf = append(buf, '\t')
|
||||||
buf = appendEncodedText(¶meterStatus{serverVersion: 90000}, buf, float32(42.0000000001))
|
|
||||||
buf = append(buf, '\t')
|
|
||||||
buf = appendEncodedText(¶meterStatus{serverVersion: 90000}, buf, 42.0000000001)
|
buf = appendEncodedText(¶meterStatus{serverVersion: 90000}, buf, 42.0000000001)
|
||||||
buf = append(buf, '\t')
|
buf = append(buf, '\t')
|
||||||
buf = appendEncodedText(¶meterStatus{serverVersion: 90000}, buf, "hello\tworld")
|
buf = appendEncodedText(¶meterStatus{serverVersion: 90000}, buf, "hello\tworld")
|
||||||
buf = append(buf, '\t')
|
buf = append(buf, '\t')
|
||||||
buf = appendEncodedText(¶meterStatus{serverVersion: 90000}, buf, []byte{0, 128, 255})
|
buf = appendEncodedText(¶meterStatus{serverVersion: 90000}, buf, []byte{0, 128, 255})
|
||||||
|
|
||||||
if string(buf) != "10\t42\t42.0000000001\thello\\tworld\t\\\\x0080ff" {
|
if string(buf) != "10\t42.0000000001\thello\\tworld\t\\\\x0080ff" {
|
||||||
t.Fatal(string(buf))
|
t.Fatal(string(buf))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
23
vendor/github.com/lib/pq/error.go
generated
vendored
23
vendor/github.com/lib/pq/error.go
generated
vendored
|
@ -459,12 +459,26 @@ func errorf(s string, args ...interface{}) {
|
||||||
panic(fmt.Errorf("pq: %s", fmt.Sprintf(s, args...)))
|
panic(fmt.Errorf("pq: %s", fmt.Sprintf(s, args...)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func errRecover(err *error) {
|
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()
|
e := recover()
|
||||||
switch v := e.(type) {
|
switch v := e.(type) {
|
||||||
case nil:
|
case nil:
|
||||||
// Do nothing
|
// Do nothing
|
||||||
case runtime.Error:
|
case runtime.Error:
|
||||||
|
c.bad = true
|
||||||
panic(v)
|
panic(v)
|
||||||
case *Error:
|
case *Error:
|
||||||
if v.Fatal() {
|
if v.Fatal() {
|
||||||
|
@ -482,6 +496,13 @@ func errRecover(err *error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
c.bad = true
|
||||||
panic(fmt.Sprintf("unknown error: %#v", e))
|
panic(fmt.Sprintf("unknown error: %#v", e))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Any time we return ErrBadConn, we need to remember it since *Tx doesn't
|
||||||
|
// mark the connection bad in database/sql.
|
||||||
|
if *err == driver.ErrBadConn {
|
||||||
|
c.bad = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
6
vendor/github.com/lib/pq/hstore/hstore_test.go
generated
vendored
6
vendor/github.com/lib/pq/hstore/hstore_test.go
generated
vendored
|
@ -2,9 +2,10 @@ package hstore
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
_ "github.com/lib/pq"
|
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
_ "github.com/lib/pq"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Fatalistic interface {
|
type Fatalistic interface {
|
||||||
|
@ -38,8 +39,7 @@ func TestHstore(t *testing.T) {
|
||||||
// quitely create hstore if it doesn't exist
|
// quitely create hstore if it doesn't exist
|
||||||
_, err := db.Exec("CREATE EXTENSION IF NOT EXISTS hstore")
|
_, err := db.Exec("CREATE EXTENSION IF NOT EXISTS hstore")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Log("Skipping hstore tests - hstore extension create failed. " + err.Error())
|
t.Skipf("Skipping hstore tests - hstore extension create failed: %s", err.Error())
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
hs := Hstore{}
|
hs := Hstore{}
|
||||||
|
|
4
vendor/github.com/lib/pq/listen_example/doc.go
generated
vendored
4
vendor/github.com/lib/pq/listen_example/doc.go
generated
vendored
|
@ -18,11 +18,11 @@ mechanism to avoid polling the database while waiting for more work to arrive.
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/lib/pq"
|
|
||||||
|
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/lib/pq"
|
||||||
)
|
)
|
||||||
|
|
||||||
func doWork(db *sql.DB, work int64) {
|
func doWork(db *sql.DB, work int64) {
|
||||||
|
|
62
vendor/github.com/lib/pq/notify.go
generated
vendored
62
vendor/github.com/lib/pq/notify.go
generated
vendored
|
@ -6,7 +6,6 @@ package pq
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
@ -87,12 +86,16 @@ func NewListenerConn(name string, notificationChan chan<- *Notification) (*Liste
|
||||||
// Returns an error if an unrecoverable error has occurred and the ListenerConn
|
// Returns an error if an unrecoverable error has occurred and the ListenerConn
|
||||||
// should be abandoned.
|
// should be abandoned.
|
||||||
func (l *ListenerConn) acquireSenderLock() error {
|
func (l *ListenerConn) acquireSenderLock() error {
|
||||||
l.connectionLock.Lock()
|
// we must acquire senderLock first to avoid deadlocks; see ExecSimpleQuery
|
||||||
defer l.connectionLock.Unlock()
|
|
||||||
if l.err != nil {
|
|
||||||
return l.err
|
|
||||||
}
|
|
||||||
l.senderLock.Lock()
|
l.senderLock.Lock()
|
||||||
|
|
||||||
|
l.connectionLock.Lock()
|
||||||
|
err := l.err
|
||||||
|
l.connectionLock.Unlock()
|
||||||
|
if err != nil {
|
||||||
|
l.senderLock.Unlock()
|
||||||
|
return err
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,10 +128,11 @@ func (l *ListenerConn) setState(newState int32) bool {
|
||||||
// away or should be discarded because we couldn't agree on the state with the
|
// away or should be discarded because we couldn't agree on the state with the
|
||||||
// server backend.
|
// server backend.
|
||||||
func (l *ListenerConn) listenerConnLoop() (err error) {
|
func (l *ListenerConn) listenerConnLoop() (err error) {
|
||||||
defer errRecover(&err)
|
defer errRecoverNoErrBadConn(&err)
|
||||||
|
|
||||||
|
r := &readBuf{}
|
||||||
for {
|
for {
|
||||||
t, r, err := l.cn.recvMessage()
|
t, err := l.cn.recvMessage(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -139,6 +143,9 @@ func (l *ListenerConn) listenerConnLoop() (err error) {
|
||||||
// about the scratch buffer being overwritten.
|
// about the scratch buffer being overwritten.
|
||||||
l.notificationChan <- recvNotification(r)
|
l.notificationChan <- recvNotification(r)
|
||||||
|
|
||||||
|
case 'T', 'D':
|
||||||
|
// only used by tests; ignore
|
||||||
|
|
||||||
case 'E':
|
case 'E':
|
||||||
// We might receive an ErrorResponse even when not in a query; it
|
// We might receive an ErrorResponse even when not in a query; it
|
||||||
// is expected that the server will close the connection after
|
// is expected that the server will close the connection after
|
||||||
|
@ -169,8 +176,6 @@ func (l *ListenerConn) listenerConnLoop() (err error) {
|
||||||
return fmt.Errorf("unexpected message %q from server in listenerConnLoop", t)
|
return fmt.Errorf("unexpected message %q from server in listenerConnLoop", t)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
panic("not reached")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is the main routine for the goroutine receiving on the database
|
// This is the main routine for the goroutine receiving on the database
|
||||||
|
@ -239,7 +244,7 @@ func (l *ListenerConn) Ping() error {
|
||||||
// The caller must be holding senderLock (see acquireSenderLock and
|
// The caller must be holding senderLock (see acquireSenderLock and
|
||||||
// releaseSenderLock).
|
// releaseSenderLock).
|
||||||
func (l *ListenerConn) sendSimpleQuery(q string) (err error) {
|
func (l *ListenerConn) sendSimpleQuery(q string) (err error) {
|
||||||
defer errRecover(&err)
|
defer errRecoverNoErrBadConn(&err)
|
||||||
|
|
||||||
// must set connection state before sending the query
|
// must set connection state before sending the query
|
||||||
if !l.setState(connStateExpectResponse) {
|
if !l.setState(connStateExpectResponse) {
|
||||||
|
@ -248,8 +253,10 @@ func (l *ListenerConn) sendSimpleQuery(q string) (err error) {
|
||||||
|
|
||||||
// Can't use l.cn.writeBuf here because it uses the scratch buffer which
|
// Can't use l.cn.writeBuf here because it uses the scratch buffer which
|
||||||
// might get overwritten by listenerConnLoop.
|
// might get overwritten by listenerConnLoop.
|
||||||
data := writeBuf([]byte("Q\x00\x00\x00\x00"))
|
b := &writeBuf{
|
||||||
b := &data
|
buf: []byte("Q\x00\x00\x00\x00"),
|
||||||
|
pos: 1,
|
||||||
|
}
|
||||||
b.string(q)
|
b.string(q)
|
||||||
l.cn.send(b)
|
l.cn.send(b)
|
||||||
|
|
||||||
|
@ -278,13 +285,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
|
// We can't know what state the protocol is in, so we need to abandon
|
||||||
// this connection.
|
// this connection.
|
||||||
l.connectionLock.Lock()
|
l.connectionLock.Lock()
|
||||||
defer l.connectionLock.Unlock()
|
|
||||||
// Set the error pointer if it hasn't been set already; see
|
// Set the error pointer if it hasn't been set already; see
|
||||||
// listenerConnMain.
|
// listenerConnMain.
|
||||||
if l.err == nil {
|
if l.err == nil {
|
||||||
l.err = err
|
l.err = err
|
||||||
}
|
}
|
||||||
l.cn.Close()
|
l.connectionLock.Unlock()
|
||||||
|
l.cn.c.Close()
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -293,8 +300,11 @@ func (l *ListenerConn) ExecSimpleQuery(q string) (executed bool, err error) {
|
||||||
m, ok := <-l.replyChan
|
m, ok := <-l.replyChan
|
||||||
if !ok {
|
if !ok {
|
||||||
// We lost the connection to server, don't bother waiting for a
|
// We lost the connection to server, don't bother waiting for a
|
||||||
// a response.
|
// a response. err should have been set already.
|
||||||
return false, io.EOF
|
l.connectionLock.Lock()
|
||||||
|
err := l.err
|
||||||
|
l.connectionLock.Unlock()
|
||||||
|
return false, err
|
||||||
}
|
}
|
||||||
switch m.typ {
|
switch m.typ {
|
||||||
case 'Z':
|
case 'Z':
|
||||||
|
@ -317,18 +327,19 @@ func (l *ListenerConn) ExecSimpleQuery(q string) (executed bool, err error) {
|
||||||
return false, fmt.Errorf("unknown response for simple query: %q", m.typ)
|
return false, fmt.Errorf("unknown response for simple query: %q", m.typ)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
panic("not reached")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *ListenerConn) Close() error {
|
func (l *ListenerConn) Close() error {
|
||||||
l.connectionLock.Lock()
|
l.connectionLock.Lock()
|
||||||
defer l.connectionLock.Unlock()
|
|
||||||
if l.err != nil {
|
if l.err != nil {
|
||||||
|
l.connectionLock.Unlock()
|
||||||
return errListenerConnClosed
|
return errListenerConnClosed
|
||||||
}
|
}
|
||||||
l.err = 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
|
// Err() returns the reason the connection was closed. It is not safe to call
|
||||||
|
@ -427,6 +438,13 @@ func NewListener(name string,
|
||||||
return l
|
return l
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns the notification channel for this listener. This is the same
|
||||||
|
// channel as Notify, and will not be recreated during the life time of the
|
||||||
|
// Listener.
|
||||||
|
func (l *Listener) NotificationChannel() <-chan *Notification {
|
||||||
|
return l.Notify
|
||||||
|
}
|
||||||
|
|
||||||
// Listen starts listening for notifications on a channel. Calls to this
|
// Listen starts listening for notifications on a channel. Calls to this
|
||||||
// function will block until an acknowledgement has been received from the
|
// function will block until an acknowledgement has been received from the
|
||||||
// server. Note that Listener automatically re-establishes the connection
|
// server. Note that Listener automatically re-establishes the connection
|
||||||
|
@ -630,8 +648,6 @@ func (l *Listener) resync(cn *ListenerConn, notificationChan <-chan *Notificatio
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
panic("not reached")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// caller should NOT be holding l.lock
|
// caller should NOT be holding l.lock
|
||||||
|
|
84
vendor/github.com/lib/pq/notify_test.go
generated
vendored
84
vendor/github.com/lib/pq/notify_test.go
generated
vendored
|
@ -5,6 +5,9 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
"runtime"
|
||||||
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
@ -24,7 +27,6 @@ func expectNotification(t *testing.T, ch <-chan *Notification, relname string, e
|
||||||
case <-time.After(1500 * time.Millisecond):
|
case <-time.After(1500 * time.Millisecond):
|
||||||
return fmt.Errorf("timeout")
|
return fmt.Errorf("timeout")
|
||||||
}
|
}
|
||||||
panic("not reached")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func expectNoNotification(t *testing.T, ch <-chan *Notification) error {
|
func expectNoNotification(t *testing.T, ch <-chan *Notification) error {
|
||||||
|
@ -34,7 +36,6 @@ func expectNoNotification(t *testing.T, ch <-chan *Notification) error {
|
||||||
case <-time.After(100 * time.Millisecond):
|
case <-time.After(100 * time.Millisecond):
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
panic("not reached")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func expectEvent(t *testing.T, eventch <-chan ListenerEventType, et ListenerEventType) error {
|
func expectEvent(t *testing.T, eventch <-chan ListenerEventType, et ListenerEventType) error {
|
||||||
|
@ -45,9 +46,8 @@ func expectEvent(t *testing.T, eventch <-chan ListenerEventType, et ListenerEven
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
case <-time.After(1500 * time.Millisecond):
|
case <-time.After(1500 * time.Millisecond):
|
||||||
return fmt.Errorf("timeout")
|
panic("expectEvent timeout")
|
||||||
}
|
}
|
||||||
panic("not reached")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func expectNoEvent(t *testing.T, eventch <-chan ListenerEventType) error {
|
func expectNoEvent(t *testing.T, eventch <-chan ListenerEventType) error {
|
||||||
|
@ -57,7 +57,6 @@ func expectNoEvent(t *testing.T, eventch <-chan ListenerEventType) error {
|
||||||
case <-time.After(100 * time.Millisecond):
|
case <-time.After(100 * time.Millisecond):
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
panic("not reached")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTestListenerConn(t *testing.T) (*ListenerConn, <-chan *Notification) {
|
func newTestListenerConn(t *testing.T) (*ListenerConn, <-chan *Notification) {
|
||||||
|
@ -214,13 +213,82 @@ func TestConnPing(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test for deadlock where a query fails while another one is queued
|
||||||
|
func TestConnExecDeadlock(t *testing.T) {
|
||||||
|
l, _ := newTestListenerConn(t)
|
||||||
|
defer l.Close()
|
||||||
|
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
wg.Add(2)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
l.ExecSimpleQuery("SELECT pg_sleep(60)")
|
||||||
|
wg.Done()
|
||||||
|
}()
|
||||||
|
runtime.Gosched()
|
||||||
|
go func() {
|
||||||
|
l.ExecSimpleQuery("SELECT 1")
|
||||||
|
wg.Done()
|
||||||
|
}()
|
||||||
|
// give the two goroutines some time to get into position
|
||||||
|
runtime.Gosched()
|
||||||
|
// calls Close on the net.Conn; equivalent to a network failure
|
||||||
|
l.Close()
|
||||||
|
|
||||||
|
var done int32 = 0
|
||||||
|
go func() {
|
||||||
|
time.Sleep(10 * time.Second)
|
||||||
|
if atomic.LoadInt32(&done) != 1 {
|
||||||
|
panic("timed out")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
wg.Wait()
|
||||||
|
atomic.StoreInt32(&done, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test for ListenerConn being closed while a slow query is executing
|
||||||
|
func TestListenerConnCloseWhileQueryIsExecuting(t *testing.T) {
|
||||||
|
l, _ := newTestListenerConn(t)
|
||||||
|
defer l.Close()
|
||||||
|
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
wg.Add(1)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
sent, err := l.ExecSimpleQuery("SELECT pg_sleep(60)")
|
||||||
|
if sent {
|
||||||
|
panic("expected sent=false")
|
||||||
|
}
|
||||||
|
// could be any of a number of errors
|
||||||
|
if err == nil {
|
||||||
|
panic("expected error")
|
||||||
|
}
|
||||||
|
wg.Done()
|
||||||
|
}()
|
||||||
|
// give the above goroutine some time to get into position
|
||||||
|
runtime.Gosched()
|
||||||
|
err := l.Close()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
var done int32 = 0
|
||||||
|
go func() {
|
||||||
|
time.Sleep(10 * time.Second)
|
||||||
|
if atomic.LoadInt32(&done) != 1 {
|
||||||
|
panic("timed out")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
wg.Wait()
|
||||||
|
atomic.StoreInt32(&done, 1)
|
||||||
|
}
|
||||||
|
|
||||||
func TestNotifyExtra(t *testing.T) {
|
func TestNotifyExtra(t *testing.T) {
|
||||||
db := openTestConn(t)
|
db := openTestConn(t)
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
|
||||||
//if getServerVersion(t, db) < 90000 {
|
if getServerVersion(t, db) < 90000 {
|
||||||
return
|
t.Skip("skipping NOTIFY payload test since the server does not appear to support it")
|
||||||
//}
|
}
|
||||||
|
|
||||||
l, channel := newTestListenerConn(t)
|
l, channel := newTestListenerConn(t)
|
||||||
defer l.Close()
|
defer l.Close()
|
||||||
|
|
2
vendor/github.com/lib/pq/oid/gen.go
generated
vendored
2
vendor/github.com/lib/pq/oid/gen.go
generated
vendored
|
@ -5,12 +5,12 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
|
||||||
"database/sql"
|
|
||||||
_ "github.com/lib/pq"
|
_ "github.com/lib/pq"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
226
vendor/github.com/lib/pq/ssl_test.go
generated
vendored
Normal file
226
vendor/github.com/lib/pq/ssl_test.go
generated
vendored
Normal file
|
@ -0,0 +1,226 @@
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
2
vendor/github.com/lib/pq/url.go
generated
vendored
2
vendor/github.com/lib/pq/url.go
generated
vendored
|
@ -34,7 +34,7 @@ func ParseURL(url string) (string, error) {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
if u.Scheme != "postgres" {
|
if u.Scheme != "postgres" && u.Scheme != "postgresql" {
|
||||||
return "", fmt.Errorf("invalid connection protocol: %s", u.Scheme)
|
return "", fmt.Errorf("invalid connection protocol: %s", u.Scheme)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
19
vendor/github.com/lib/pq/user_posix.go
generated
vendored
19
vendor/github.com/lib/pq/user_posix.go
generated
vendored
|
@ -1,15 +1,24 @@
|
||||||
// Package pq is a pure Go Postgres driver for the database/sql package.
|
// Package pq is a pure Go Postgres driver for the database/sql package.
|
||||||
|
|
||||||
// +build darwin freebsd linux nacl netbsd openbsd solaris
|
// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
|
||||||
|
|
||||||
package pq
|
package pq
|
||||||
|
|
||||||
import "os/user"
|
import (
|
||||||
|
"os"
|
||||||
|
"os/user"
|
||||||
|
)
|
||||||
|
|
||||||
func userCurrent() (string, error) {
|
func userCurrent() (string, error) {
|
||||||
u, err := user.Current()
|
u, err := user.Current()
|
||||||
if err != nil {
|
if err == nil {
|
||||||
return "", err
|
return u.Username, nil
|
||||||
}
|
}
|
||||||
return u.Username, nil
|
|
||||||
|
name := os.Getenv("USER")
|
||||||
|
if name != "" {
|
||||||
|
return name, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", ErrCouldNotDetectUsername
|
||||||
}
|
}
|
||||||
|
|
2
vendor/github.com/lib/pq/user_windows.go
generated
vendored
2
vendor/github.com/lib/pq/user_windows.go
generated
vendored
|
@ -19,7 +19,7 @@ func userCurrent() (string, error) {
|
||||||
pwname_size := uint32(len(pw_name)) - 1
|
pwname_size := uint32(len(pw_name)) - 1
|
||||||
err := syscall.GetUserNameEx(syscall.NameSamCompatible, &pw_name[0], &pwname_size)
|
err := syscall.GetUserNameEx(syscall.NameSamCompatible, &pw_name[0], &pwname_size)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", ErrCouldNotDetectUsername
|
||||||
}
|
}
|
||||||
s := syscall.UTF16ToString(pw_name)
|
s := syscall.UTF16ToString(pw_name)
|
||||||
u := filepath.Base(s)
|
u := filepath.Base(s)
|
||||||
|
|
Loading…
Reference in a new issue