vendor: revendor
This commit is contained in:
		
							
								
								
									
										4
									
								
								vendor/github.com/lib/pq/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/lib/pq/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,4 +0,0 @@ | ||||
| .db | ||||
| *.test | ||||
| *~ | ||||
| *.swp | ||||
							
								
								
									
										73
									
								
								vendor/github.com/lib/pq/.travis.sh
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										73
									
								
								vendor/github.com/lib/pq/.travis.sh
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,73 +0,0 @@ | ||||
| #!/bin/bash | ||||
|  | ||||
| set -eu | ||||
|  | ||||
| client_configure() { | ||||
| 	sudo chmod 600 $PQSSLCERTTEST_PATH/postgresql.key | ||||
| } | ||||
|  | ||||
| pgdg_repository() { | ||||
| 	local sourcelist='sources.list.d/postgresql.list' | ||||
|  | ||||
| 	curl -sS 'https://www.postgresql.org/media/keys/ACCC4CF8.asc' | sudo apt-key add - | ||||
| 	echo deb http://apt.postgresql.org/pub/repos/apt/ $(lsb_release -cs)-pgdg main $PGVERSION | sudo tee "/etc/apt/$sourcelist" | ||||
| 	sudo apt-get -o Dir::Etc::sourcelist="$sourcelist" -o Dir::Etc::sourceparts='-' -o APT::Get::List-Cleanup='0' update | ||||
| } | ||||
|  | ||||
| postgresql_configure() { | ||||
| 	sudo tee /etc/postgresql/$PGVERSION/main/pg_hba.conf > /dev/null <<-config | ||||
| 		local     all         all                               trust | ||||
| 		hostnossl all         pqgossltest 127.0.0.1/32          reject | ||||
| 		hostnossl all         pqgosslcert 127.0.0.1/32          reject | ||||
| 		hostssl   all         pqgossltest 127.0.0.1/32          trust | ||||
| 		hostssl   all         pqgosslcert 127.0.0.1/32          cert | ||||
| 		host      all         all         127.0.0.1/32          trust | ||||
| 		hostnossl all         pqgossltest ::1/128               reject | ||||
| 		hostnossl all         pqgosslcert ::1/128               reject | ||||
| 		hostssl   all         pqgossltest ::1/128               trust | ||||
| 		hostssl   all         pqgosslcert ::1/128               cert | ||||
| 		host      all         all         ::1/128               trust | ||||
| 	config | ||||
|  | ||||
| 	xargs sudo install -o postgres -g postgres -m 600 -t /var/lib/postgresql/$PGVERSION/main/ <<-certificates | ||||
| 		certs/root.crt | ||||
| 		certs/server.crt | ||||
| 		certs/server.key | ||||
| 	certificates | ||||
|  | ||||
| 	sort -VCu <<-versions || | ||||
| 		$PGVERSION | ||||
| 		9.2 | ||||
| 	versions | ||||
| 	sudo tee -a /etc/postgresql/$PGVERSION/main/postgresql.conf > /dev/null <<-config | ||||
| 		ssl_ca_file   = 'root.crt' | ||||
| 		ssl_cert_file = 'server.crt' | ||||
| 		ssl_key_file  = 'server.key' | ||||
| 	config | ||||
|  | ||||
| 	echo 127.0.0.1 postgres | sudo tee -a /etc/hosts > /dev/null | ||||
|  | ||||
| 	sudo service postgresql restart | ||||
| } | ||||
|  | ||||
| postgresql_install() { | ||||
| 	xargs sudo apt-get -y -o Dpkg::Options::='--force-confdef' -o Dpkg::Options::='--force-confnew' install <<-packages | ||||
| 		postgresql-$PGVERSION | ||||
| 		postgresql-server-dev-$PGVERSION | ||||
| 		postgresql-contrib-$PGVERSION | ||||
| 	packages | ||||
| } | ||||
|  | ||||
| postgresql_uninstall() { | ||||
| 	sudo service postgresql stop | ||||
| 	xargs sudo apt-get -y --purge remove <<-packages | ||||
| 		libpq-dev | ||||
| 		libpq5 | ||||
| 		postgresql | ||||
| 		postgresql-client-common | ||||
| 		postgresql-common | ||||
| 	packages | ||||
| 	sudo rm -rf /var/lib/postgresql | ||||
| } | ||||
|  | ||||
| $1 | ||||
							
								
								
									
										43
									
								
								vendor/github.com/lib/pq/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										43
									
								
								vendor/github.com/lib/pq/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,43 +0,0 @@ | ||||
| language: go | ||||
|  | ||||
| go: | ||||
|   - 1.5 | ||||
|   - 1.6 | ||||
|   - 1.7 | ||||
|   - tip | ||||
|  | ||||
| sudo: true | ||||
|  | ||||
| env: | ||||
|   global: | ||||
|     - PGUSER=postgres | ||||
|     - PQGOSSLTESTS=1 | ||||
|     - PQSSLCERTTEST_PATH=$PWD/certs | ||||
|     - PGHOST=127.0.0.1 | ||||
|   matrix: | ||||
|     - PGVERSION=9.5 | ||||
|     - PGVERSION=9.4 | ||||
|     - PGVERSION=9.3 | ||||
|     - PGVERSION=9.2 | ||||
|     - PGVERSION=9.1 | ||||
|     - PGVERSION=9.0 | ||||
|  | ||||
| before_install: | ||||
|   - ./.travis.sh postgresql_uninstall | ||||
|   - ./.travis.sh pgdg_repository | ||||
|   - ./.travis.sh postgresql_install | ||||
|   - ./.travis.sh postgresql_configure | ||||
|   - ./.travis.sh client_configure | ||||
|   - go get golang.org/x/tools/cmd/goimports | ||||
|  | ||||
| before_script: | ||||
|   - createdb pqgotest | ||||
|   - createuser -DRS pqgossltest | ||||
|   - createuser -DRS pqgosslcert | ||||
|  | ||||
| script: | ||||
|   - > | ||||
|     goimports -d -e $(find -name '*.go') | awk '{ print } END { exit NR == 0 ? 0 : 1 }' | ||||
|   - go vet ./... | ||||
|   - PQTEST_BINARY_PARAMETERS=no  go test -v ./... | ||||
|   - PQTEST_BINARY_PARAMETERS=yes go test -v ./... | ||||
							
								
								
									
										29
									
								
								vendor/github.com/lib/pq/CONTRIBUTING.md
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										29
									
								
								vendor/github.com/lib/pq/CONTRIBUTING.md
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,29 +0,0 @@ | ||||
| ## Contributing to pq | ||||
|  | ||||
| `pq` has a backlog of pull requests, but contributions are still very | ||||
| much welcome. You can help with patch review, submitting bug reports, | ||||
| or adding new functionality. There is no formal style guide, but | ||||
| please conform to the style of existing code and general Go formatting | ||||
| conventions when submitting patches. | ||||
|  | ||||
| ### Patch review | ||||
|  | ||||
| Help review existing open pull requests by commenting on the code or | ||||
| proposed functionality. | ||||
|  | ||||
| ### Bug reports | ||||
|  | ||||
| We appreciate any bug reports, but especially ones with self-contained | ||||
| (doesn't depend on code outside of pq), minimal (can't be simplified | ||||
| further) test cases. It's especially helpful if you can submit a pull | ||||
| request with just the failing test case (you'll probably want to | ||||
| pattern it after the tests in | ||||
| [conn_test.go](https://github.com/lib/pq/blob/master/conn_test.go). | ||||
|  | ||||
| ### New functionality | ||||
|  | ||||
| There are a number of pending patches for new functionality, so | ||||
| additional feature patches will take a while to merge. Still, patches | ||||
| are generally reviewed based on usefulness and complexity in addition | ||||
| to time-in-queue, so if you have a knockout idea, take a shot. Feel | ||||
| free to open an issue discussion your proposed patch beforehand. | ||||
							
								
								
									
										105
									
								
								vendor/github.com/lib/pq/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										105
									
								
								vendor/github.com/lib/pq/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,105 +0,0 @@ | ||||
| # pq - A pure Go postgres driver for Go's database/sql package | ||||
|  | ||||
| [](https://travis-ci.org/lib/pq) | ||||
|  | ||||
| ## Install | ||||
|  | ||||
| 	go get github.com/lib/pq | ||||
|  | ||||
| ## Docs | ||||
|  | ||||
| For detailed documentation and basic usage examples, please see the package | ||||
| documentation at <http://godoc.org/github.com/lib/pq>. | ||||
|  | ||||
| ## Tests | ||||
|  | ||||
| `go test` is used for testing.  A running PostgreSQL server is | ||||
| required, with the ability to log in.  The default database to connect | ||||
| to test with is "pqgotest," but it can be overridden using environment | ||||
| variables. | ||||
|  | ||||
| Example: | ||||
|  | ||||
| 	PGHOST=/run/postgresql go test github.com/lib/pq | ||||
|  | ||||
| Optionally, a benchmark suite can be run as part of the tests: | ||||
|  | ||||
| 	PGHOST=/run/postgresql go test -bench . | ||||
|  | ||||
| ## Features | ||||
|  | ||||
| * SSL | ||||
| * Handles bad connections for `database/sql` | ||||
| * Scan `time.Time` correctly (i.e. `timestamp[tz]`, `time[tz]`, `date`) | ||||
| * Scan binary blobs correctly (i.e. `bytea`) | ||||
| * Package for `hstore` support | ||||
| * COPY FROM support | ||||
| * pq.ParseURL for converting urls to connection strings for sql.Open. | ||||
| * Many libpq compatible environment variables | ||||
| * Unix socket support | ||||
| * Notifications: `LISTEN`/`NOTIFY` | ||||
| * pgpass support | ||||
|  | ||||
| ## Future / Things you can help with | ||||
|  | ||||
| * Better COPY FROM / COPY TO (see discussion in #181) | ||||
|  | ||||
| ## Thank you (alphabetical) | ||||
|  | ||||
| Some of these contributors are from the original library `bmizerany/pq.go` whose | ||||
| code still exists in here. | ||||
|  | ||||
| * Andy Balholm (andybalholm) | ||||
| * Ben Berkert (benburkert) | ||||
| * Benjamin Heatwole (bheatwole) | ||||
| * Bill Mill (llimllib) | ||||
| * Bjørn Madsen (aeons) | ||||
| * Blake Gentry (bgentry) | ||||
| * Brad Fitzpatrick (bradfitz) | ||||
| * Charlie Melbye (cmelbye) | ||||
| * Chris Bandy (cbandy) | ||||
| * Chris Gilling (cgilling) | ||||
| * Chris Walsh (cwds) | ||||
| * Dan Sosedoff (sosedoff) | ||||
| * Daniel Farina (fdr) | ||||
| * Eric Chlebek (echlebek) | ||||
| * Eric Garrido (minusnine) | ||||
| * Eric Urban (hydrogen18) | ||||
| * Everyone at The Go Team | ||||
| * Evan Shaw (edsrzf) | ||||
| * Ewan Chou (coocood) | ||||
| * Fazal Majid (fazalmajid) | ||||
| * Federico Romero (federomero) | ||||
| * Fumin (fumin) | ||||
| * Gary Burd (garyburd) | ||||
| * Heroku (heroku) | ||||
| * James Pozdena (jpoz) | ||||
| * Jason McVetta (jmcvetta) | ||||
| * Jeremy Jay (pbnjay) | ||||
| * Joakim Sernbrant (serbaut) | ||||
| * John Gallagher (jgallagher) | ||||
| * Jonathan Rudenberg (titanous) | ||||
| * Joël Stemmer (jstemmer) | ||||
| * Kamil Kisiel (kisielk) | ||||
| * Kelly Dunn (kellydunn) | ||||
| * Keith Rarick (kr) | ||||
| * Kir Shatrov (kirs) | ||||
| * Lann Martin (lann) | ||||
| * Maciek Sakrejda (uhoh-itsmaciek) | ||||
| * Marc Brinkmann (mbr) | ||||
| * Marko Tiikkaja (johto) | ||||
| * Matt Newberry (MattNewberry) | ||||
| * Matt Robenolt (mattrobenolt) | ||||
| * Martin Olsen (martinolsen) | ||||
| * Mike Lewis (mikelikespie) | ||||
| * Nicolas Patry (Narsil) | ||||
| * Oliver Tonnhofer (olt) | ||||
| * Patrick Hayes (phayes) | ||||
| * Paul Hammond (paulhammond) | ||||
| * Ryan Smith (ryandotsmith) | ||||
| * Samuel Stauffer (samuel) | ||||
| * Timothée Peignier (cyberdelia) | ||||
| * Travis Cline (tmc) | ||||
| * TruongSinh Tran-Nguyen (truongsinh) | ||||
| * Yaismel Miranda (ympons) | ||||
| * notedit (notedit) | ||||
							
								
								
									
										1153
									
								
								vendor/github.com/lib/pq/array_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										1153
									
								
								vendor/github.com/lib/pq/array_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										435
									
								
								vendor/github.com/lib/pq/bench_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										435
									
								
								vendor/github.com/lib/pq/bench_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,435 +0,0 @@ | ||||
| // +build go1.1 | ||||
|  | ||||
| package pq | ||||
|  | ||||
| import ( | ||||
| 	"bufio" | ||||
| 	"bytes" | ||||
| 	"database/sql" | ||||
| 	"database/sql/driver" | ||||
| 	"io" | ||||
| 	"math/rand" | ||||
| 	"net" | ||||
| 	"runtime" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
| 	"testing" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/lib/pq/oid" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	selectStringQuery = "SELECT '" + strings.Repeat("0123456789", 10) + "'" | ||||
| 	selectSeriesQuery = "SELECT generate_series(1, 100)" | ||||
| ) | ||||
|  | ||||
| func BenchmarkSelectString(b *testing.B) { | ||||
| 	var result string | ||||
| 	benchQuery(b, selectStringQuery, &result) | ||||
| } | ||||
|  | ||||
| func BenchmarkSelectSeries(b *testing.B) { | ||||
| 	var result int | ||||
| 	benchQuery(b, selectSeriesQuery, &result) | ||||
| } | ||||
|  | ||||
| func benchQuery(b *testing.B, query string, result interface{}) { | ||||
| 	b.StopTimer() | ||||
| 	db := openTestConn(b) | ||||
| 	defer db.Close() | ||||
| 	b.StartTimer() | ||||
|  | ||||
| 	for i := 0; i < b.N; i++ { | ||||
| 		benchQueryLoop(b, db, query, result) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func benchQueryLoop(b *testing.B, db *sql.DB, query string, result interface{}) { | ||||
| 	rows, err := db.Query(query) | ||||
| 	if err != nil { | ||||
| 		b.Fatal(err) | ||||
| 	} | ||||
| 	defer rows.Close() | ||||
| 	for rows.Next() { | ||||
| 		err = rows.Scan(result) | ||||
| 		if err != nil { | ||||
| 			b.Fatal("failed to scan", err) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // reading from circularConn yields content[:prefixLen] once, followed by | ||||
| // content[prefixLen:] over and over again. It never returns EOF. | ||||
| type circularConn struct { | ||||
| 	content   string | ||||
| 	prefixLen int | ||||
| 	pos       int | ||||
| 	net.Conn  // for all other net.Conn methods that will never be called | ||||
| } | ||||
|  | ||||
| func (r *circularConn) Read(b []byte) (n int, err error) { | ||||
| 	n = copy(b, r.content[r.pos:]) | ||||
| 	r.pos += n | ||||
| 	if r.pos >= len(r.content) { | ||||
| 		r.pos = r.prefixLen | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func (r *circularConn) Write(b []byte) (n int, err error) { return len(b), nil } | ||||
|  | ||||
| func (r *circularConn) Close() error { return nil } | ||||
|  | ||||
| func fakeConn(content string, prefixLen int) *conn { | ||||
| 	c := &circularConn{content: content, prefixLen: prefixLen} | ||||
| 	return &conn{buf: bufio.NewReader(c), c: c} | ||||
| } | ||||
|  | ||||
| // This benchmark is meant to be the same as BenchmarkSelectString, but takes | ||||
| // out some of the factors this package can't control. The numbers are less noisy, | ||||
| // but also the costs of network communication aren't accurately represented. | ||||
| func BenchmarkMockSelectString(b *testing.B) { | ||||
| 	b.StopTimer() | ||||
| 	// taken from a recorded run of BenchmarkSelectString | ||||
| 	// See: http://www.postgresql.org/docs/current/static/protocol-message-formats.html | ||||
| 	const response = "1\x00\x00\x00\x04" + | ||||
| 		"t\x00\x00\x00\x06\x00\x00" + | ||||
| 		"T\x00\x00\x00!\x00\x01?column?\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\xc1\xff\xfe\xff\xff\xff\xff\x00\x00" + | ||||
| 		"Z\x00\x00\x00\x05I" + | ||||
| 		"2\x00\x00\x00\x04" + | ||||
| 		"D\x00\x00\x00n\x00\x01\x00\x00\x00d0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" + | ||||
| 		"C\x00\x00\x00\rSELECT 1\x00" + | ||||
| 		"Z\x00\x00\x00\x05I" + | ||||
| 		"3\x00\x00\x00\x04" + | ||||
| 		"Z\x00\x00\x00\x05I" | ||||
| 	c := fakeConn(response, 0) | ||||
| 	b.StartTimer() | ||||
|  | ||||
| 	for i := 0; i < b.N; i++ { | ||||
| 		benchMockQuery(b, c, selectStringQuery) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| var seriesRowData = func() string { | ||||
| 	var buf bytes.Buffer | ||||
| 	for i := 1; i <= 100; i++ { | ||||
| 		digits := byte(2) | ||||
| 		if i >= 100 { | ||||
| 			digits = 3 | ||||
| 		} else if i < 10 { | ||||
| 			digits = 1 | ||||
| 		} | ||||
| 		buf.WriteString("D\x00\x00\x00") | ||||
| 		buf.WriteByte(10 + digits) | ||||
| 		buf.WriteString("\x00\x01\x00\x00\x00") | ||||
| 		buf.WriteByte(digits) | ||||
| 		buf.WriteString(strconv.Itoa(i)) | ||||
| 	} | ||||
| 	return buf.String() | ||||
| }() | ||||
|  | ||||
| func BenchmarkMockSelectSeries(b *testing.B) { | ||||
| 	b.StopTimer() | ||||
| 	var response = "1\x00\x00\x00\x04" + | ||||
| 		"t\x00\x00\x00\x06\x00\x00" + | ||||
| 		"T\x00\x00\x00!\x00\x01?column?\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\xc1\xff\xfe\xff\xff\xff\xff\x00\x00" + | ||||
| 		"Z\x00\x00\x00\x05I" + | ||||
| 		"2\x00\x00\x00\x04" + | ||||
| 		seriesRowData + | ||||
| 		"C\x00\x00\x00\x0fSELECT 100\x00" + | ||||
| 		"Z\x00\x00\x00\x05I" + | ||||
| 		"3\x00\x00\x00\x04" + | ||||
| 		"Z\x00\x00\x00\x05I" | ||||
| 	c := fakeConn(response, 0) | ||||
| 	b.StartTimer() | ||||
|  | ||||
| 	for i := 0; i < b.N; i++ { | ||||
| 		benchMockQuery(b, c, selectSeriesQuery) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func benchMockQuery(b *testing.B, c *conn, query string) { | ||||
| 	stmt, err := c.Prepare(query) | ||||
| 	if err != nil { | ||||
| 		b.Fatal(err) | ||||
| 	} | ||||
| 	defer stmt.Close() | ||||
| 	rows, err := stmt.Query(nil) | ||||
| 	if err != nil { | ||||
| 		b.Fatal(err) | ||||
| 	} | ||||
| 	defer rows.Close() | ||||
| 	var dest [1]driver.Value | ||||
| 	for { | ||||
| 		if err := rows.Next(dest[:]); err != nil { | ||||
| 			if err == io.EOF { | ||||
| 				break | ||||
| 			} | ||||
| 			b.Fatal(err) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func BenchmarkPreparedSelectString(b *testing.B) { | ||||
| 	var result string | ||||
| 	benchPreparedQuery(b, selectStringQuery, &result) | ||||
| } | ||||
|  | ||||
| func BenchmarkPreparedSelectSeries(b *testing.B) { | ||||
| 	var result int | ||||
| 	benchPreparedQuery(b, selectSeriesQuery, &result) | ||||
| } | ||||
|  | ||||
| func benchPreparedQuery(b *testing.B, query string, result interface{}) { | ||||
| 	b.StopTimer() | ||||
| 	db := openTestConn(b) | ||||
| 	defer db.Close() | ||||
| 	stmt, err := db.Prepare(query) | ||||
| 	if err != nil { | ||||
| 		b.Fatal(err) | ||||
| 	} | ||||
| 	defer stmt.Close() | ||||
| 	b.StartTimer() | ||||
|  | ||||
| 	for i := 0; i < b.N; i++ { | ||||
| 		benchPreparedQueryLoop(b, db, stmt, result) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func benchPreparedQueryLoop(b *testing.B, db *sql.DB, stmt *sql.Stmt, result interface{}) { | ||||
| 	rows, err := stmt.Query() | ||||
| 	if err != nil { | ||||
| 		b.Fatal(err) | ||||
| 	} | ||||
| 	if !rows.Next() { | ||||
| 		rows.Close() | ||||
| 		b.Fatal("no rows") | ||||
| 	} | ||||
| 	defer rows.Close() | ||||
| 	for rows.Next() { | ||||
| 		err = rows.Scan(&result) | ||||
| 		if err != nil { | ||||
| 			b.Fatal("failed to scan") | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // See the comment for BenchmarkMockSelectString. | ||||
| func BenchmarkMockPreparedSelectString(b *testing.B) { | ||||
| 	b.StopTimer() | ||||
| 	const parseResponse = "1\x00\x00\x00\x04" + | ||||
| 		"t\x00\x00\x00\x06\x00\x00" + | ||||
| 		"T\x00\x00\x00!\x00\x01?column?\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\xc1\xff\xfe\xff\xff\xff\xff\x00\x00" + | ||||
| 		"Z\x00\x00\x00\x05I" | ||||
| 	const responses = parseResponse + | ||||
| 		"2\x00\x00\x00\x04" + | ||||
| 		"D\x00\x00\x00n\x00\x01\x00\x00\x00d0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" + | ||||
| 		"C\x00\x00\x00\rSELECT 1\x00" + | ||||
| 		"Z\x00\x00\x00\x05I" | ||||
| 	c := fakeConn(responses, len(parseResponse)) | ||||
|  | ||||
| 	stmt, err := c.Prepare(selectStringQuery) | ||||
| 	if err != nil { | ||||
| 		b.Fatal(err) | ||||
| 	} | ||||
| 	b.StartTimer() | ||||
|  | ||||
| 	for i := 0; i < b.N; i++ { | ||||
| 		benchPreparedMockQuery(b, c, stmt) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func BenchmarkMockPreparedSelectSeries(b *testing.B) { | ||||
| 	b.StopTimer() | ||||
| 	const parseResponse = "1\x00\x00\x00\x04" + | ||||
| 		"t\x00\x00\x00\x06\x00\x00" + | ||||
| 		"T\x00\x00\x00!\x00\x01?column?\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\xc1\xff\xfe\xff\xff\xff\xff\x00\x00" + | ||||
| 		"Z\x00\x00\x00\x05I" | ||||
| 	var responses = parseResponse + | ||||
| 		"2\x00\x00\x00\x04" + | ||||
| 		seriesRowData + | ||||
| 		"C\x00\x00\x00\x0fSELECT 100\x00" + | ||||
| 		"Z\x00\x00\x00\x05I" | ||||
| 	c := fakeConn(responses, len(parseResponse)) | ||||
|  | ||||
| 	stmt, err := c.Prepare(selectSeriesQuery) | ||||
| 	if err != nil { | ||||
| 		b.Fatal(err) | ||||
| 	} | ||||
| 	b.StartTimer() | ||||
|  | ||||
| 	for i := 0; i < b.N; i++ { | ||||
| 		benchPreparedMockQuery(b, c, stmt) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func benchPreparedMockQuery(b *testing.B, c *conn, stmt driver.Stmt) { | ||||
| 	rows, err := stmt.Query(nil) | ||||
| 	if err != nil { | ||||
| 		b.Fatal(err) | ||||
| 	} | ||||
| 	defer rows.Close() | ||||
| 	var dest [1]driver.Value | ||||
| 	for { | ||||
| 		if err := rows.Next(dest[:]); err != nil { | ||||
| 			if err == io.EOF { | ||||
| 				break | ||||
| 			} | ||||
| 			b.Fatal(err) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func BenchmarkEncodeInt64(b *testing.B) { | ||||
| 	for i := 0; i < b.N; i++ { | ||||
| 		encode(¶meterStatus{}, int64(1234), oid.T_int8) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func BenchmarkEncodeFloat64(b *testing.B) { | ||||
| 	for i := 0; i < b.N; i++ { | ||||
| 		encode(¶meterStatus{}, 3.14159, oid.T_float8) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| var testByteString = []byte("abcdefghijklmnopqrstuvwxyz") | ||||
|  | ||||
| func BenchmarkEncodeByteaHex(b *testing.B) { | ||||
| 	for i := 0; i < b.N; i++ { | ||||
| 		encode(¶meterStatus{serverVersion: 90000}, testByteString, oid.T_bytea) | ||||
| 	} | ||||
| } | ||||
| func BenchmarkEncodeByteaEscape(b *testing.B) { | ||||
| 	for i := 0; i < b.N; i++ { | ||||
| 		encode(¶meterStatus{serverVersion: 84000}, testByteString, oid.T_bytea) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func BenchmarkEncodeBool(b *testing.B) { | ||||
| 	for i := 0; i < b.N; i++ { | ||||
| 		encode(¶meterStatus{}, true, oid.T_bool) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| var testTimestamptz = time.Date(2001, time.January, 1, 0, 0, 0, 0, time.Local) | ||||
|  | ||||
| func BenchmarkEncodeTimestamptz(b *testing.B) { | ||||
| 	for i := 0; i < b.N; i++ { | ||||
| 		encode(¶meterStatus{}, testTimestamptz, oid.T_timestamptz) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| var testIntBytes = []byte("1234") | ||||
|  | ||||
| func BenchmarkDecodeInt64(b *testing.B) { | ||||
| 	for i := 0; i < b.N; i++ { | ||||
| 		decode(¶meterStatus{}, testIntBytes, oid.T_int8, formatText) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| var testFloatBytes = []byte("3.14159") | ||||
|  | ||||
| func BenchmarkDecodeFloat64(b *testing.B) { | ||||
| 	for i := 0; i < b.N; i++ { | ||||
| 		decode(¶meterStatus{}, testFloatBytes, oid.T_float8, formatText) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| var testBoolBytes = []byte{'t'} | ||||
|  | ||||
| func BenchmarkDecodeBool(b *testing.B) { | ||||
| 	for i := 0; i < b.N; i++ { | ||||
| 		decode(¶meterStatus{}, testBoolBytes, oid.T_bool, formatText) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestDecodeBool(t *testing.T) { | ||||
| 	db := openTestConn(t) | ||||
| 	rows, err := db.Query("select true") | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	rows.Close() | ||||
| } | ||||
|  | ||||
| var testTimestamptzBytes = []byte("2013-09-17 22:15:32.360754-07") | ||||
|  | ||||
| func BenchmarkDecodeTimestamptz(b *testing.B) { | ||||
| 	for i := 0; i < b.N; i++ { | ||||
| 		decode(¶meterStatus{}, testTimestamptzBytes, oid.T_timestamptz, formatText) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func BenchmarkDecodeTimestamptzMultiThread(b *testing.B) { | ||||
| 	oldProcs := runtime.GOMAXPROCS(0) | ||||
| 	defer runtime.GOMAXPROCS(oldProcs) | ||||
| 	runtime.GOMAXPROCS(runtime.NumCPU()) | ||||
| 	globalLocationCache = newLocationCache() | ||||
|  | ||||
| 	f := func(wg *sync.WaitGroup, loops int) { | ||||
| 		defer wg.Done() | ||||
| 		for i := 0; i < loops; i++ { | ||||
| 			decode(¶meterStatus{}, testTimestamptzBytes, oid.T_timestamptz, formatText) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	wg := &sync.WaitGroup{} | ||||
| 	b.ResetTimer() | ||||
| 	for j := 0; j < 10; j++ { | ||||
| 		wg.Add(1) | ||||
| 		go f(wg, b.N/10) | ||||
| 	} | ||||
| 	wg.Wait() | ||||
| } | ||||
|  | ||||
| func BenchmarkLocationCache(b *testing.B) { | ||||
| 	globalLocationCache = newLocationCache() | ||||
| 	for i := 0; i < b.N; i++ { | ||||
| 		globalLocationCache.getLocation(rand.Intn(10000)) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func BenchmarkLocationCacheMultiThread(b *testing.B) { | ||||
| 	oldProcs := runtime.GOMAXPROCS(0) | ||||
| 	defer runtime.GOMAXPROCS(oldProcs) | ||||
| 	runtime.GOMAXPROCS(runtime.NumCPU()) | ||||
| 	globalLocationCache = newLocationCache() | ||||
|  | ||||
| 	f := func(wg *sync.WaitGroup, loops int) { | ||||
| 		defer wg.Done() | ||||
| 		for i := 0; i < loops; i++ { | ||||
| 			globalLocationCache.getLocation(rand.Intn(10000)) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	wg := &sync.WaitGroup{} | ||||
| 	b.ResetTimer() | ||||
| 	for j := 0; j < 10; j++ { | ||||
| 		wg.Add(1) | ||||
| 		go f(wg, b.N/10) | ||||
| 	} | ||||
| 	wg.Wait() | ||||
| } | ||||
|  | ||||
| // Stress test the performance of parsing results from the wire. | ||||
| func BenchmarkResultParsing(b *testing.B) { | ||||
| 	b.StopTimer() | ||||
|  | ||||
| 	db := openTestConn(b) | ||||
| 	defer db.Close() | ||||
| 	_, err := db.Exec("BEGIN") | ||||
| 	if err != nil { | ||||
| 		b.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	b.StartTimer() | ||||
| 	for i := 0; i < b.N; i++ { | ||||
| 		res, err := db.Query("SELECT generate_series(1, 50000)") | ||||
| 		if err != nil { | ||||
| 			b.Fatal(err) | ||||
| 		} | ||||
| 		res.Close() | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										1448
									
								
								vendor/github.com/lib/pq/conn_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										1448
									
								
								vendor/github.com/lib/pq/conn_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										465
									
								
								vendor/github.com/lib/pq/copy_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										465
									
								
								vendor/github.com/lib/pq/copy_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,465 +0,0 @@ | ||||
| package pq | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"database/sql" | ||||
| 	"database/sql/driver" | ||||
| 	"strings" | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| func TestCopyInStmt(t *testing.T) { | ||||
| 	var stmt string | ||||
| 	stmt = CopyIn("table name") | ||||
| 	if stmt != `COPY "table name" () FROM STDIN` { | ||||
| 		t.Fatal(stmt) | ||||
| 	} | ||||
|  | ||||
| 	stmt = CopyIn("table name", "column 1", "column 2") | ||||
| 	if stmt != `COPY "table name" ("column 1", "column 2") FROM STDIN` { | ||||
| 		t.Fatal(stmt) | ||||
| 	} | ||||
|  | ||||
| 	stmt = CopyIn(`table " name """`, `co"lumn""`) | ||||
| 	if stmt != `COPY "table "" name """"""" ("co""lumn""""") FROM STDIN` { | ||||
| 		t.Fatal(stmt) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestCopyInSchemaStmt(t *testing.T) { | ||||
| 	var stmt string | ||||
| 	stmt = CopyInSchema("schema name", "table name") | ||||
| 	if stmt != `COPY "schema name"."table name" () FROM STDIN` { | ||||
| 		t.Fatal(stmt) | ||||
| 	} | ||||
|  | ||||
| 	stmt = CopyInSchema("schema name", "table name", "column 1", "column 2") | ||||
| 	if stmt != `COPY "schema name"."table name" ("column 1", "column 2") FROM STDIN` { | ||||
| 		t.Fatal(stmt) | ||||
| 	} | ||||
|  | ||||
| 	stmt = CopyInSchema(`schema " name """`, `table " name """`, `co"lumn""`) | ||||
| 	if stmt != `COPY "schema "" name """"""".`+ | ||||
| 		`"table "" name """"""" ("co""lumn""""") FROM STDIN` { | ||||
| 		t.Fatal(stmt) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestCopyInMultipleValues(t *testing.T) { | ||||
| 	db := openTestConn(t) | ||||
| 	defer db.Close() | ||||
|  | ||||
| 	txn, err := db.Begin() | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	defer txn.Rollback() | ||||
|  | ||||
| 	_, err = txn.Exec("CREATE TEMP TABLE temp (a int, b varchar)") | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	stmt, err := txn.Prepare(CopyIn("temp", "a", "b")) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	longString := strings.Repeat("#", 500) | ||||
|  | ||||
| 	for i := 0; i < 500; i++ { | ||||
| 		_, err = stmt.Exec(int64(i), longString) | ||||
| 		if err != nil { | ||||
| 			t.Fatal(err) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	_, err = stmt.Exec() | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	err = stmt.Close() | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	var num int | ||||
| 	err = txn.QueryRow("SELECT COUNT(*) FROM temp").Scan(&num) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	if num != 500 { | ||||
| 		t.Fatalf("expected 500 items, not %d", num) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func 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) { | ||||
| 	db := openTestConn(t) | ||||
| 	defer db.Close() | ||||
|  | ||||
| 	txn, err := db.Begin() | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	defer txn.Rollback() | ||||
|  | ||||
| 	_, err = txn.Exec("CREATE TEMP TABLE temp (num INTEGER, text VARCHAR, blob BYTEA, nothing VARCHAR)") | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	stmt, err := txn.Prepare(CopyIn("temp", "num", "text", "blob", "nothing")) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	_, err = stmt.Exec(int64(1234567890), "Héllö\n ☃!\r\t\\", []byte{0, 255, 9, 10, 13}, nil) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	_, err = stmt.Exec() | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	err = stmt.Close() | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	var num int | ||||
| 	var text string | ||||
| 	var blob []byte | ||||
| 	var nothing sql.NullString | ||||
|  | ||||
| 	err = txn.QueryRow("SELECT * FROM temp").Scan(&num, &text, &blob, ¬hing) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	if num != 1234567890 { | ||||
| 		t.Fatal("unexpected result", num) | ||||
| 	} | ||||
| 	if text != "Héllö\n ☃!\r\t\\" { | ||||
| 		t.Fatal("unexpected result", text) | ||||
| 	} | ||||
| 	if bytes.Compare(blob, []byte{0, 255, 9, 10, 13}) != 0 { | ||||
| 		t.Fatal("unexpected result", blob) | ||||
| 	} | ||||
| 	if nothing.Valid { | ||||
| 		t.Fatal("unexpected result", nothing.String) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestCopyInWrongType(t *testing.T) { | ||||
| 	db := openTestConn(t) | ||||
| 	defer db.Close() | ||||
|  | ||||
| 	txn, err := db.Begin() | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	defer txn.Rollback() | ||||
|  | ||||
| 	_, err = txn.Exec("CREATE TEMP TABLE temp (num INTEGER)") | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	stmt, err := txn.Prepare(CopyIn("temp", "num")) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	defer stmt.Close() | ||||
|  | ||||
| 	_, err = stmt.Exec("Héllö\n ☃!\r\t\\") | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	_, err = stmt.Exec() | ||||
| 	if err == nil { | ||||
| 		t.Fatal("expected error") | ||||
| 	} | ||||
| 	if pge := err.(*Error); pge.Code.Name() != "invalid_text_representation" { | ||||
| 		t.Fatalf("expected 'invalid input syntax for integer' error, got %s (%+v)", pge.Code.Name(), pge) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestCopyOutsideOfTxnError(t *testing.T) { | ||||
| 	db := openTestConn(t) | ||||
| 	defer db.Close() | ||||
|  | ||||
| 	_, err := db.Prepare(CopyIn("temp", "num")) | ||||
| 	if err == nil { | ||||
| 		t.Fatal("COPY outside of transaction did not return an error") | ||||
| 	} | ||||
| 	if err != errCopyNotSupportedOutsideTxn { | ||||
| 		t.Fatalf("expected %s, got %s", err, err.Error()) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestCopyInBinaryError(t *testing.T) { | ||||
| 	db := openTestConn(t) | ||||
| 	defer db.Close() | ||||
|  | ||||
| 	txn, err := db.Begin() | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	defer txn.Rollback() | ||||
|  | ||||
| 	_, err = txn.Exec("CREATE TEMP TABLE temp (num INTEGER)") | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	_, err = txn.Prepare("COPY temp (num) FROM STDIN WITH binary") | ||||
| 	if err != errBinaryCopyNotSupported { | ||||
| 		t.Fatalf("expected %s, got %+v", errBinaryCopyNotSupported, err) | ||||
| 	} | ||||
| 	// check that the protocol is in a valid state | ||||
| 	err = txn.Rollback() | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestCopyFromError(t *testing.T) { | ||||
| 	db := openTestConn(t) | ||||
| 	defer db.Close() | ||||
|  | ||||
| 	txn, err := db.Begin() | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	defer txn.Rollback() | ||||
|  | ||||
| 	_, err = txn.Exec("CREATE TEMP TABLE temp (num INTEGER)") | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	_, err = txn.Prepare("COPY temp (num) TO STDOUT") | ||||
| 	if err != errCopyToNotSupported { | ||||
| 		t.Fatalf("expected %s, got %+v", errCopyToNotSupported, err) | ||||
| 	} | ||||
| 	// check that the protocol is in a valid state | ||||
| 	err = txn.Rollback() | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestCopySyntaxError(t *testing.T) { | ||||
| 	db := openTestConn(t) | ||||
| 	defer db.Close() | ||||
|  | ||||
| 	txn, err := db.Begin() | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	defer txn.Rollback() | ||||
|  | ||||
| 	_, err = txn.Prepare("COPY ") | ||||
| 	if err == nil { | ||||
| 		t.Fatal("expected error") | ||||
| 	} | ||||
| 	if pge := err.(*Error); pge.Code.Name() != "syntax_error" { | ||||
| 		t.Fatalf("expected syntax error, got %s (%+v)", pge.Code.Name(), pge) | ||||
| 	} | ||||
| 	// check that the protocol is in a valid state | ||||
| 	err = txn.Rollback() | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Tests for connection errors in copyin.resploop() | ||||
| func TestCopyRespLoopConnectionError(t *testing.T) { | ||||
| 	db := openTestConn(t) | ||||
| 	defer db.Close() | ||||
|  | ||||
| 	txn, err := db.Begin() | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	defer txn.Rollback() | ||||
|  | ||||
| 	var pid int | ||||
| 	err = txn.QueryRow("SELECT pg_backend_pid()").Scan(&pid) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	_, err = txn.Exec("CREATE TEMP TABLE temp (a int)") | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	stmt, err := txn.Prepare(CopyIn("temp", "a")) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	defer stmt.Close() | ||||
|  | ||||
| 	_, 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 { | ||||
| 		if err == driver.ErrBadConn { | ||||
| 			// likely an EPIPE | ||||
| 		} else { | ||||
| 			t.Fatalf("expected *pq.Error or driver.ErrBadConn, got %+#v", err) | ||||
| 		} | ||||
| 	} else if pge.Code.Name() != "admin_shutdown" { | ||||
| 		t.Fatalf("expected admin_shutdown, got %s", pge.Code.Name()) | ||||
| 	} | ||||
|  | ||||
| 	_ = stmt.Close() | ||||
| } | ||||
|  | ||||
| func BenchmarkCopyIn(b *testing.B) { | ||||
| 	db := openTestConn(b) | ||||
| 	defer db.Close() | ||||
|  | ||||
| 	txn, err := db.Begin() | ||||
| 	if err != nil { | ||||
| 		b.Fatal(err) | ||||
| 	} | ||||
| 	defer txn.Rollback() | ||||
|  | ||||
| 	_, err = txn.Exec("CREATE TEMP TABLE temp (a int, b varchar)") | ||||
| 	if err != nil { | ||||
| 		b.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	stmt, err := txn.Prepare(CopyIn("temp", "a", "b")) | ||||
| 	if err != nil { | ||||
| 		b.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	for i := 0; i < b.N; i++ { | ||||
| 		_, err = stmt.Exec(int64(i), "hello world!") | ||||
| 		if err != nil { | ||||
| 			b.Fatal(err) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	_, err = stmt.Exec() | ||||
| 	if err != nil { | ||||
| 		b.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	err = stmt.Close() | ||||
| 	if err != nil { | ||||
| 		b.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	var num int | ||||
| 	err = txn.QueryRow("SELECT COUNT(*) FROM temp").Scan(&num) | ||||
| 	if err != nil { | ||||
| 		b.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	if num != b.N { | ||||
| 		b.Fatalf("expected %d items, not %d", b.N, num) | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										738
									
								
								vendor/github.com/lib/pq/encode_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										738
									
								
								vendor/github.com/lib/pq/encode_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,738 +0,0 @@ | ||||
| package pq | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"database/sql" | ||||
| 	"fmt" | ||||
| 	"strings" | ||||
| 	"testing" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/lib/pq/oid" | ||||
| ) | ||||
|  | ||||
| func TestScanTimestamp(t *testing.T) { | ||||
| 	var nt NullTime | ||||
| 	tn := time.Now() | ||||
| 	nt.Scan(tn) | ||||
| 	if !nt.Valid { | ||||
| 		t.Errorf("Expected Valid=false") | ||||
| 	} | ||||
| 	if nt.Time != tn { | ||||
| 		t.Errorf("Time value mismatch") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestScanNilTimestamp(t *testing.T) { | ||||
| 	var nt NullTime | ||||
| 	nt.Scan(nil) | ||||
| 	if nt.Valid { | ||||
| 		t.Errorf("Expected Valid=false") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| var timeTests = []struct { | ||||
| 	str     string | ||||
| 	timeval time.Time | ||||
| }{ | ||||
| 	{"22001-02-03", time.Date(22001, time.February, 3, 0, 0, 0, 0, time.FixedZone("", 0))}, | ||||
| 	{"2001-02-03", time.Date(2001, time.February, 3, 0, 0, 0, 0, time.FixedZone("", 0))}, | ||||
| 	{"2001-02-03 04:05:06", time.Date(2001, time.February, 3, 4, 5, 6, 0, time.FixedZone("", 0))}, | ||||
| 	{"2001-02-03 04:05:06.000001", time.Date(2001, time.February, 3, 4, 5, 6, 1000, time.FixedZone("", 0))}, | ||||
| 	{"2001-02-03 04:05:06.00001", time.Date(2001, time.February, 3, 4, 5, 6, 10000, time.FixedZone("", 0))}, | ||||
| 	{"2001-02-03 04:05:06.0001", time.Date(2001, time.February, 3, 4, 5, 6, 100000, time.FixedZone("", 0))}, | ||||
| 	{"2001-02-03 04:05:06.001", time.Date(2001, time.February, 3, 4, 5, 6, 1000000, time.FixedZone("", 0))}, | ||||
| 	{"2001-02-03 04:05:06.01", time.Date(2001, time.February, 3, 4, 5, 6, 10000000, time.FixedZone("", 0))}, | ||||
| 	{"2001-02-03 04:05:06.1", time.Date(2001, time.February, 3, 4, 5, 6, 100000000, time.FixedZone("", 0))}, | ||||
| 	{"2001-02-03 04:05:06.12", time.Date(2001, time.February, 3, 4, 5, 6, 120000000, time.FixedZone("", 0))}, | ||||
| 	{"2001-02-03 04:05:06.123", time.Date(2001, time.February, 3, 4, 5, 6, 123000000, time.FixedZone("", 0))}, | ||||
| 	{"2001-02-03 04:05:06.1234", time.Date(2001, time.February, 3, 4, 5, 6, 123400000, time.FixedZone("", 0))}, | ||||
| 	{"2001-02-03 04:05:06.12345", time.Date(2001, time.February, 3, 4, 5, 6, 123450000, time.FixedZone("", 0))}, | ||||
| 	{"2001-02-03 04:05:06.123456", time.Date(2001, time.February, 3, 4, 5, 6, 123456000, time.FixedZone("", 0))}, | ||||
| 	{"2001-02-03 04:05:06.123-07", time.Date(2001, time.February, 3, 4, 5, 6, 123000000, | ||||
| 		time.FixedZone("", -7*60*60))}, | ||||
| 	{"2001-02-03 04:05:06-07", time.Date(2001, time.February, 3, 4, 5, 6, 0, | ||||
| 		time.FixedZone("", -7*60*60))}, | ||||
| 	{"2001-02-03 04:05:06-07:42", time.Date(2001, time.February, 3, 4, 5, 6, 0, | ||||
| 		time.FixedZone("", -(7*60*60+42*60)))}, | ||||
| 	{"2001-02-03 04:05:06-07:30:09", time.Date(2001, time.February, 3, 4, 5, 6, 0, | ||||
| 		time.FixedZone("", -(7*60*60+30*60+9)))}, | ||||
| 	{"2001-02-03 04:05:06+07", time.Date(2001, time.February, 3, 4, 5, 6, 0, | ||||
| 		time.FixedZone("", 7*60*60))}, | ||||
| 	{"0011-02-03 04:05:06 BC", time.Date(-10, time.February, 3, 4, 5, 6, 0, time.FixedZone("", 0))}, | ||||
| 	{"0011-02-03 04:05:06.123 BC", time.Date(-10, time.February, 3, 4, 5, 6, 123000000, time.FixedZone("", 0))}, | ||||
| 	{"0011-02-03 04:05:06.123-07 BC", time.Date(-10, time.February, 3, 4, 5, 6, 123000000, | ||||
| 		time.FixedZone("", -7*60*60))}, | ||||
| 	{"0001-02-03 04:05:06.123", time.Date(1, time.February, 3, 4, 5, 6, 123000000, time.FixedZone("", 0))}, | ||||
| 	{"0001-02-03 04:05:06.123 BC", time.Date(1, time.February, 3, 4, 5, 6, 123000000, time.FixedZone("", 0)).AddDate(-1, 0, 0)}, | ||||
| 	{"0001-02-03 04:05:06.123 BC", time.Date(0, time.February, 3, 4, 5, 6, 123000000, time.FixedZone("", 0))}, | ||||
| 	{"0002-02-03 04:05:06.123 BC", time.Date(0, time.February, 3, 4, 5, 6, 123000000, time.FixedZone("", 0)).AddDate(-1, 0, 0)}, | ||||
| 	{"0002-02-03 04:05:06.123 BC", time.Date(-1, time.February, 3, 4, 5, 6, 123000000, time.FixedZone("", 0))}, | ||||
| 	{"12345-02-03 04:05:06.1", time.Date(12345, time.February, 3, 4, 5, 6, 100000000, time.FixedZone("", 0))}, | ||||
| 	{"123456-02-03 04:05:06.1", time.Date(123456, time.February, 3, 4, 5, 6, 100000000, time.FixedZone("", 0))}, | ||||
| } | ||||
|  | ||||
| // Test that parsing the string results in the expected value. | ||||
| func TestParseTs(t *testing.T) { | ||||
| 	for i, tt := range timeTests { | ||||
| 		val, err := ParseTimestamp(nil, tt.str) | ||||
| 		if err != nil { | ||||
| 			t.Errorf("%d: got error: %v", i, err) | ||||
| 		} else if val.String() != tt.timeval.String() { | ||||
| 			t.Errorf("%d: expected to parse %q into %q; got %q", | ||||
| 				i, tt.str, tt.timeval, val) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| var timeErrorTests = []string{ | ||||
| 	"2001", | ||||
| 	"2001-2-03", | ||||
| 	"2001-02-3", | ||||
| 	"2001-02-03 ", | ||||
| 	"2001-02-03 04", | ||||
| 	"2001-02-03 04:", | ||||
| 	"2001-02-03 04:05", | ||||
| 	"2001-02-03 04:05:", | ||||
| 	"2001-02-03 04:05:6", | ||||
| 	"2001-02-03 04:05:06.123 B", | ||||
| } | ||||
|  | ||||
| // Test that parsing the string results in an error. | ||||
| func TestParseTsErrors(t *testing.T) { | ||||
| 	for i, tt := range timeErrorTests { | ||||
| 		_, err := ParseTimestamp(nil, tt) | ||||
| 		if err == nil { | ||||
| 			t.Errorf("%d: expected an error from parsing: %v", i, tt) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // 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 := ParseTimestamp(nil, dbstr) | ||||
| 		if err != nil { | ||||
| 			t.Errorf("%d: could not parse value %q: %s", i, dbstr, err) | ||||
| 			continue | ||||
| 		} | ||||
| 		val = val.In(tt.timeval.Location()) | ||||
| 		if val.String() != tt.timeval.String() { | ||||
| 			t.Errorf("%d: expected to parse %q into %q; got %q", i, dbstr, tt.timeval, val) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| var formatTimeTests = []struct { | ||||
| 	time     time.Time | ||||
| 	expected string | ||||
| }{ | ||||
| 	{time.Time{}, "0001-01-01T00:00:00Z"}, | ||||
| 	{time.Date(2001, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", 0)), "2001-02-03T04:05:06.123456789Z"}, | ||||
| 	{time.Date(2001, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", 2*60*60)), "2001-02-03T04:05:06.123456789+02:00"}, | ||||
| 	{time.Date(2001, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", -6*60*60)), "2001-02-03T04:05:06.123456789-06:00"}, | ||||
| 	{time.Date(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) { | ||||
| 	for i, tt := range formatTimeTests { | ||||
| 		val := string(formatTs(tt.time)) | ||||
| 		if val != tt.expected { | ||||
| 			t.Errorf("%d: incorrect time format %q, want %q", i, val, tt.expected) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestTimestampWithTimeZone(t *testing.T) { | ||||
| 	db := openTestConn(t) | ||||
| 	defer db.Close() | ||||
|  | ||||
| 	tx, err := db.Begin() | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	defer tx.Rollback() | ||||
|  | ||||
| 	// try several different locations, all included in Go's zoneinfo.zip | ||||
| 	for _, locName := range []string{ | ||||
| 		"UTC", | ||||
| 		"America/Chicago", | ||||
| 		"America/New_York", | ||||
| 		"Australia/Darwin", | ||||
| 		"Australia/Perth", | ||||
| 	} { | ||||
| 		loc, err := time.LoadLocation(locName) | ||||
| 		if err != nil { | ||||
| 			t.Logf("Could not load time zone %s - skipping", locName) | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		// Postgres timestamps have a resolution of 1 microsecond, so don't | ||||
| 		// use the full range of the Nanosecond argument | ||||
| 		refTime := time.Date(2012, 11, 6, 10, 23, 42, 123456000, loc) | ||||
|  | ||||
| 		for _, pgTimeZone := range []string{"US/Eastern", "Australia/Darwin"} { | ||||
| 			// Switch Postgres's timezone to test different output timestamp formats | ||||
| 			_, err = tx.Exec(fmt.Sprintf("set time zone '%s'", pgTimeZone)) | ||||
| 			if err != nil { | ||||
| 				t.Fatal(err) | ||||
| 			} | ||||
|  | ||||
| 			var gotTime time.Time | ||||
| 			row := tx.QueryRow("select $1::timestamp with time zone", refTime) | ||||
| 			err = row.Scan(&gotTime) | ||||
| 			if err != nil { | ||||
| 				t.Fatal(err) | ||||
| 			} | ||||
|  | ||||
| 			if !refTime.Equal(gotTime) { | ||||
| 				t.Errorf("timestamps not equal: %s != %s", refTime, gotTime) | ||||
| 			} | ||||
|  | ||||
| 			// check that the time zone is set correctly based on TimeZone | ||||
| 			pgLoc, err := time.LoadLocation(pgTimeZone) | ||||
| 			if err != nil { | ||||
| 				t.Logf("Could not load time zone %s - skipping", pgLoc) | ||||
| 				continue | ||||
| 			} | ||||
| 			translated := refTime.In(pgLoc) | ||||
| 			if translated.String() != gotTime.String() { | ||||
| 				t.Errorf("timestamps not equal: %s != %s", translated, gotTime) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestTimestampWithOutTimezone(t *testing.T) { | ||||
| 	db := openTestConn(t) | ||||
| 	defer db.Close() | ||||
|  | ||||
| 	test := func(ts, pgts string) { | ||||
| 		r, err := db.Query("SELECT $1::timestamp", pgts) | ||||
| 		if err != nil { | ||||
| 			t.Fatalf("Could not run query: %v", err) | ||||
| 		} | ||||
|  | ||||
| 		n := r.Next() | ||||
|  | ||||
| 		if n != true { | ||||
| 			t.Fatal("Expected at least one row") | ||||
| 		} | ||||
|  | ||||
| 		var result time.Time | ||||
| 		err = r.Scan(&result) | ||||
| 		if err != nil { | ||||
| 			t.Fatalf("Did not expect error scanning row: %v", err) | ||||
| 		} | ||||
|  | ||||
| 		expected, err := time.Parse(time.RFC3339, ts) | ||||
| 		if err != nil { | ||||
| 			t.Fatalf("Could not parse test time literal: %v", err) | ||||
| 		} | ||||
|  | ||||
| 		if !result.Equal(expected) { | ||||
| 			t.Fatalf("Expected time to match %v: got mismatch %v", | ||||
| 				expected, result) | ||||
| 		} | ||||
|  | ||||
| 		n = r.Next() | ||||
| 		if n != false { | ||||
| 			t.Fatal("Expected only one row") | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	test("2000-01-01T00:00:00Z", "2000-01-01T00:00:00") | ||||
|  | ||||
| 	// Test higher precision time | ||||
| 	test("2013-01-04T20:14:58.80033Z", "2013-01-04 20:14:58.80033") | ||||
| } | ||||
|  | ||||
| func TestInfinityTimestamp(t *testing.T) { | ||||
| 	db := openTestConn(t) | ||||
| 	defer db.Close() | ||||
| 	var err error | ||||
| 	var resultT time.Time | ||||
|  | ||||
| 	expectedErrorStrPrefix := `sql: Scan error on column index 0: unsupported` | ||||
| 	type testCases []struct { | ||||
| 		Query                string | ||||
| 		Param                string | ||||
| 		ExpectedErrStrPrefix string | ||||
| 		ExpectedVal          interface{} | ||||
| 	} | ||||
| 	tc := testCases{ | ||||
| 		{"SELECT $1::timestamp", "-infinity", expectedErrorStrPrefix, "-infinity"}, | ||||
| 		{"SELECT $1::timestamptz", "-infinity", expectedErrorStrPrefix, "-infinity"}, | ||||
| 		{"SELECT $1::timestamp", "infinity", expectedErrorStrPrefix, "infinity"}, | ||||
| 		{"SELECT $1::timestamptz", "infinity", expectedErrorStrPrefix, "infinity"}, | ||||
| 	} | ||||
| 	// try to assert []byte to time.Time | ||||
| 	for _, q := range tc { | ||||
| 		err = db.QueryRow(q.Query, q.Param).Scan(&resultT) | ||||
| 		if !strings.HasPrefix(err.Error(), q.ExpectedErrStrPrefix) { | ||||
| 			t.Errorf("Scanning -/+infinity, expected error to have prefix %q, got %q", q.ExpectedErrStrPrefix, 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) { | ||||
| 	db := openTestConn(t) | ||||
| 	defer db.Close() | ||||
|  | ||||
| 	hello0world := string("hello\x00world") | ||||
| 	_, err := db.Query("SELECT $1::text", &hello0world) | ||||
| 	if err == nil { | ||||
| 		t.Fatal("Postgres accepts a string with nul in it; " + | ||||
| 			"injection attacks may be plausible") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestByteSliceToText(t *testing.T) { | ||||
| 	db := openTestConn(t) | ||||
| 	defer db.Close() | ||||
|  | ||||
| 	b := []byte("hello world") | ||||
| 	row := db.QueryRow("SELECT $1::text", b) | ||||
|  | ||||
| 	var result []byte | ||||
| 	err := row.Scan(&result) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	if string(result) != string(b) { | ||||
| 		t.Fatalf("expected %v but got %v", b, result) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestStringToBytea(t *testing.T) { | ||||
| 	db := openTestConn(t) | ||||
| 	defer db.Close() | ||||
|  | ||||
| 	b := "hello world" | ||||
| 	row := db.QueryRow("SELECT $1::bytea", b) | ||||
|  | ||||
| 	var result []byte | ||||
| 	err := row.Scan(&result) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	if !bytes.Equal(result, []byte(b)) { | ||||
| 		t.Fatalf("expected %v but got %v", b, result) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func 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 TestTextDecodeIntoString(t *testing.T) { | ||||
| 	input := []byte("hello world") | ||||
| 	want := string(input) | ||||
| 	for _, typ := range []oid.Oid{oid.T_char, oid.T_varchar, oid.T_text} { | ||||
| 		got := decode(¶meterStatus{}, input, typ, formatText) | ||||
| 		if got != want { | ||||
| 			t.Errorf("invalid string decoding output for %T(%+v), got %v but expected %v", typ, typ, got, want) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestByteaOutputFormatEncoding(t *testing.T) { | ||||
| 	input := []byte("\\x\x00\x01\x02\xFF\xFEabcdefg0123") | ||||
| 	want := []byte("\\x5c78000102fffe6162636465666730313233") | ||||
| 	got := encode(¶meterStatus{serverVersion: 90000}, input, oid.T_bytea) | ||||
| 	if !bytes.Equal(want, got) { | ||||
| 		t.Errorf("invalid hex bytea output, got %v but expected %v", got, want) | ||||
| 	} | ||||
|  | ||||
| 	want = []byte("\\\\x\\000\\001\\002\\377\\376abcdefg0123") | ||||
| 	got = encode(¶meterStatus{serverVersion: 84000}, input, oid.T_bytea) | ||||
| 	if !bytes.Equal(want, got) { | ||||
| 		t.Errorf("invalid escape bytea output, got %v but expected %v", got, want) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestByteaOutputFormats(t *testing.T) { | ||||
| 	db := openTestConn(t) | ||||
| 	defer db.Close() | ||||
|  | ||||
| 	if getServerVersion(t, db) < 90000 { | ||||
| 		// skip | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	testByteaOutputFormat := func(f string, usePrepared bool) { | ||||
| 		expectedData := []byte("\x5c\x78\x00\xff\x61\x62\x63\x01\x08") | ||||
| 		sqlQuery := "SELECT decode('5c7800ff6162630108', 'hex')" | ||||
|  | ||||
| 		var data []byte | ||||
|  | ||||
| 		// use a txn to avoid relying on getting the same connection | ||||
| 		txn, err := db.Begin() | ||||
| 		if err != nil { | ||||
| 			t.Fatal(err) | ||||
| 		} | ||||
| 		defer txn.Rollback() | ||||
|  | ||||
| 		_, err = txn.Exec("SET LOCAL bytea_output TO " + f) | ||||
| 		if err != nil { | ||||
| 			t.Fatal(err) | ||||
| 		} | ||||
| 		var rows *sql.Rows | ||||
| 		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 { | ||||
| 			t.Fatal(err) | ||||
| 		} | ||||
| 		if !rows.Next() { | ||||
| 			if rows.Err() != nil { | ||||
| 				t.Fatal(rows.Err()) | ||||
| 			} | ||||
| 			t.Fatal("shouldn't happen") | ||||
| 		} | ||||
| 		err = rows.Scan(&data) | ||||
| 		if err != nil { | ||||
| 			t.Fatal(err) | ||||
| 		} | ||||
| 		err = rows.Close() | ||||
| 		if err != nil { | ||||
| 			t.Fatal(err) | ||||
| 		} | ||||
| 		if stmt != nil { | ||||
| 			err = stmt.Close() | ||||
| 			if err != nil { | ||||
| 				t.Fatal(err) | ||||
| 			} | ||||
| 		} | ||||
| 		if !bytes.Equal(data, expectedData) { | ||||
| 			t.Errorf("unexpected bytea value %v for format %s; expected %v", data, f, expectedData) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	testByteaOutputFormat("hex", false) | ||||
| 	testByteaOutputFormat("escape", false) | ||||
| 	testByteaOutputFormat("hex", true) | ||||
| 	testByteaOutputFormat("escape", true) | ||||
| } | ||||
|  | ||||
| func TestAppendEncodedText(t *testing.T) { | ||||
| 	var buf []byte | ||||
|  | ||||
| 	buf = appendEncodedText(¶meterStatus{serverVersion: 90000}, buf, int64(10)) | ||||
| 	buf = append(buf, '\t') | ||||
| 	buf = appendEncodedText(¶meterStatus{serverVersion: 90000}, buf, 42.0000000001) | ||||
| 	buf = append(buf, '\t') | ||||
| 	buf = appendEncodedText(¶meterStatus{serverVersion: 90000}, buf, "hello\tworld") | ||||
| 	buf = append(buf, '\t') | ||||
| 	buf = appendEncodedText(¶meterStatus{serverVersion: 90000}, buf, []byte{0, 128, 255}) | ||||
|  | ||||
| 	if string(buf) != "10\t42.0000000001\thello\\tworld\t\\\\x0080ff" { | ||||
| 		t.Fatal(string(buf)) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestAppendEscapedText(t *testing.T) { | ||||
| 	if esc := appendEscapedText(nil, "hallo\tescape"); string(esc) != "hallo\\tescape" { | ||||
| 		t.Fatal(string(esc)) | ||||
| 	} | ||||
| 	if esc := appendEscapedText(nil, "hallo\\tescape\n"); string(esc) != "hallo\\\\tescape\\n" { | ||||
| 		t.Fatal(string(esc)) | ||||
| 	} | ||||
| 	if esc := appendEscapedText(nil, "\n\r\t\f"); string(esc) != "\\n\\r\\t\f" { | ||||
| 		t.Fatal(string(esc)) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestAppendEscapedTextExistingBuffer(t *testing.T) { | ||||
| 	var buf []byte | ||||
| 	buf = []byte("123\t") | ||||
| 	if esc := appendEscapedText(buf, "hallo\tescape"); string(esc) != "123\thallo\\tescape" { | ||||
| 		t.Fatal(string(esc)) | ||||
| 	} | ||||
| 	buf = []byte("123\t") | ||||
| 	if esc := appendEscapedText(buf, "hallo\\tescape\n"); string(esc) != "123\thallo\\\\tescape\\n" { | ||||
| 		t.Fatal(string(esc)) | ||||
| 	} | ||||
| 	buf = []byte("123\t") | ||||
| 	if esc := appendEscapedText(buf, "\n\r\t\f"); string(esc) != "123\t\\n\\r\\t\f" { | ||||
| 		t.Fatal(string(esc)) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func BenchmarkAppendEscapedText(b *testing.B) { | ||||
| 	longString := "" | ||||
| 	for i := 0; i < 100; i++ { | ||||
| 		longString += "123456789\n" | ||||
| 	} | ||||
| 	for i := 0; i < b.N; i++ { | ||||
| 		appendEscapedText(nil, longString) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func BenchmarkAppendEscapedTextNoEscape(b *testing.B) { | ||||
| 	longString := "" | ||||
| 	for i := 0; i < 100; i++ { | ||||
| 		longString += "1234567890" | ||||
| 	} | ||||
| 	for i := 0; i < b.N; i++ { | ||||
| 		appendEscapedText(nil, longString) | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										574
									
								
								vendor/github.com/lib/pq/notify_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										574
									
								
								vendor/github.com/lib/pq/notify_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,574 +0,0 @@ | ||||
| package pq | ||||
|  | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"os" | ||||
| 	"runtime" | ||||
| 	"sync" | ||||
| 	"sync/atomic" | ||||
| 	"testing" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| var errNilNotification = errors.New("nil notification") | ||||
|  | ||||
| func expectNotification(t *testing.T, ch <-chan *Notification, relname string, extra string) error { | ||||
| 	select { | ||||
| 	case n := <-ch: | ||||
| 		if n == nil { | ||||
| 			return errNilNotification | ||||
| 		} | ||||
| 		if n.Channel != relname || n.Extra != extra { | ||||
| 			return fmt.Errorf("unexpected notification %v", n) | ||||
| 		} | ||||
| 		return nil | ||||
| 	case <-time.After(1500 * time.Millisecond): | ||||
| 		return fmt.Errorf("timeout") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func expectNoNotification(t *testing.T, ch <-chan *Notification) error { | ||||
| 	select { | ||||
| 	case n := <-ch: | ||||
| 		return fmt.Errorf("unexpected notification %v", n) | ||||
| 	case <-time.After(100 * time.Millisecond): | ||||
| 		return nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func expectEvent(t *testing.T, eventch <-chan ListenerEventType, et ListenerEventType) error { | ||||
| 	select { | ||||
| 	case e := <-eventch: | ||||
| 		if e != et { | ||||
| 			return fmt.Errorf("unexpected event %v", e) | ||||
| 		} | ||||
| 		return nil | ||||
| 	case <-time.After(1500 * time.Millisecond): | ||||
| 		panic("expectEvent timeout") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func expectNoEvent(t *testing.T, eventch <-chan ListenerEventType) error { | ||||
| 	select { | ||||
| 	case e := <-eventch: | ||||
| 		return fmt.Errorf("unexpected event %v", e) | ||||
| 	case <-time.After(100 * time.Millisecond): | ||||
| 		return nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func newTestListenerConn(t *testing.T) (*ListenerConn, <-chan *Notification) { | ||||
| 	datname := os.Getenv("PGDATABASE") | ||||
| 	sslmode := os.Getenv("PGSSLMODE") | ||||
|  | ||||
| 	if datname == "" { | ||||
| 		os.Setenv("PGDATABASE", "pqgotest") | ||||
| 	} | ||||
|  | ||||
| 	if sslmode == "" { | ||||
| 		os.Setenv("PGSSLMODE", "disable") | ||||
| 	} | ||||
|  | ||||
| 	notificationChan := make(chan *Notification) | ||||
| 	l, err := NewListenerConn("", notificationChan) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	return l, notificationChan | ||||
| } | ||||
|  | ||||
| func TestNewListenerConn(t *testing.T) { | ||||
| 	l, _ := newTestListenerConn(t) | ||||
|  | ||||
| 	defer l.Close() | ||||
| } | ||||
|  | ||||
| func TestConnListen(t *testing.T) { | ||||
| 	l, channel := newTestListenerConn(t) | ||||
|  | ||||
| 	defer l.Close() | ||||
|  | ||||
| 	db := openTestConn(t) | ||||
| 	defer db.Close() | ||||
|  | ||||
| 	ok, err := l.Listen("notify_test") | ||||
| 	if !ok || err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	_, err = db.Exec("NOTIFY notify_test") | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	err = expectNotification(t, channel, "notify_test", "") | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestConnUnlisten(t *testing.T) { | ||||
| 	l, channel := newTestListenerConn(t) | ||||
|  | ||||
| 	defer l.Close() | ||||
|  | ||||
| 	db := openTestConn(t) | ||||
| 	defer db.Close() | ||||
|  | ||||
| 	ok, err := l.Listen("notify_test") | ||||
| 	if !ok || err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	_, err = db.Exec("NOTIFY notify_test") | ||||
|  | ||||
| 	err = expectNotification(t, channel, "notify_test", "") | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	ok, err = l.Unlisten("notify_test") | ||||
| 	if !ok || err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	_, err = db.Exec("NOTIFY notify_test") | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	err = expectNoNotification(t, channel) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestConnUnlistenAll(t *testing.T) { | ||||
| 	l, channel := newTestListenerConn(t) | ||||
|  | ||||
| 	defer l.Close() | ||||
|  | ||||
| 	db := openTestConn(t) | ||||
| 	defer db.Close() | ||||
|  | ||||
| 	ok, err := l.Listen("notify_test") | ||||
| 	if !ok || err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	_, err = db.Exec("NOTIFY notify_test") | ||||
|  | ||||
| 	err = expectNotification(t, channel, "notify_test", "") | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	ok, err = l.UnlistenAll() | ||||
| 	if !ok || err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	_, err = db.Exec("NOTIFY notify_test") | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	err = expectNoNotification(t, channel) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestConnClose(t *testing.T) { | ||||
| 	l, _ := newTestListenerConn(t) | ||||
| 	defer l.Close() | ||||
|  | ||||
| 	err := l.Close() | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	err = l.Close() | ||||
| 	if err != errListenerConnClosed { | ||||
| 		t.Fatalf("expected errListenerConnClosed; got %v", err) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestConnPing(t *testing.T) { | ||||
| 	l, _ := newTestListenerConn(t) | ||||
| 	defer l.Close() | ||||
| 	err := l.Ping() | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	err = l.Close() | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	err = l.Ping() | ||||
| 	if err != errListenerConnClosed { | ||||
| 		t.Fatalf("expected errListenerConnClosed; got %v", err) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // 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) { | ||||
| 	db := openTestConn(t) | ||||
| 	defer db.Close() | ||||
|  | ||||
| 	if getServerVersion(t, db) < 90000 { | ||||
| 		t.Skip("skipping NOTIFY payload test since the server does not appear to support it") | ||||
| 	} | ||||
|  | ||||
| 	l, channel := newTestListenerConn(t) | ||||
| 	defer l.Close() | ||||
|  | ||||
| 	ok, err := l.Listen("notify_test") | ||||
| 	if !ok || err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	_, err = db.Exec("NOTIFY notify_test, 'something'") | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	err = expectNotification(t, channel, "notify_test", "something") | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // create a new test listener and also set the timeouts | ||||
| func newTestListenerTimeout(t *testing.T, min time.Duration, max time.Duration) (*Listener, <-chan ListenerEventType) { | ||||
| 	datname := os.Getenv("PGDATABASE") | ||||
| 	sslmode := os.Getenv("PGSSLMODE") | ||||
|  | ||||
| 	if datname == "" { | ||||
| 		os.Setenv("PGDATABASE", "pqgotest") | ||||
| 	} | ||||
|  | ||||
| 	if sslmode == "" { | ||||
| 		os.Setenv("PGSSLMODE", "disable") | ||||
| 	} | ||||
|  | ||||
| 	eventch := make(chan ListenerEventType, 16) | ||||
| 	l := NewListener("", min, max, func(t ListenerEventType, err error) { eventch <- t }) | ||||
| 	err := expectEvent(t, eventch, ListenerEventConnected) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	return l, eventch | ||||
| } | ||||
|  | ||||
| func newTestListener(t *testing.T) (*Listener, <-chan ListenerEventType) { | ||||
| 	return newTestListenerTimeout(t, time.Hour, time.Hour) | ||||
| } | ||||
|  | ||||
| func TestListenerListen(t *testing.T) { | ||||
| 	l, _ := newTestListener(t) | ||||
| 	defer l.Close() | ||||
|  | ||||
| 	db := openTestConn(t) | ||||
| 	defer db.Close() | ||||
|  | ||||
| 	err := l.Listen("notify_listen_test") | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	_, err = db.Exec("NOTIFY notify_listen_test") | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	err = expectNotification(t, l.Notify, "notify_listen_test", "") | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestListenerUnlisten(t *testing.T) { | ||||
| 	l, _ := newTestListener(t) | ||||
| 	defer l.Close() | ||||
|  | ||||
| 	db := openTestConn(t) | ||||
| 	defer db.Close() | ||||
|  | ||||
| 	err := l.Listen("notify_listen_test") | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	_, err = db.Exec("NOTIFY notify_listen_test") | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	err = l.Unlisten("notify_listen_test") | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	err = expectNotification(t, l.Notify, "notify_listen_test", "") | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	_, err = db.Exec("NOTIFY notify_listen_test") | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	err = expectNoNotification(t, l.Notify) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestListenerUnlistenAll(t *testing.T) { | ||||
| 	l, _ := newTestListener(t) | ||||
| 	defer l.Close() | ||||
|  | ||||
| 	db := openTestConn(t) | ||||
| 	defer db.Close() | ||||
|  | ||||
| 	err := l.Listen("notify_listen_test") | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	_, err = db.Exec("NOTIFY notify_listen_test") | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	err = l.UnlistenAll() | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	err = expectNotification(t, l.Notify, "notify_listen_test", "") | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	_, err = db.Exec("NOTIFY notify_listen_test") | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	err = expectNoNotification(t, l.Notify) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestListenerFailedQuery(t *testing.T) { | ||||
| 	l, eventch := newTestListener(t) | ||||
| 	defer l.Close() | ||||
|  | ||||
| 	db := openTestConn(t) | ||||
| 	defer db.Close() | ||||
|  | ||||
| 	err := l.Listen("notify_listen_test") | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	_, err = db.Exec("NOTIFY notify_listen_test") | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	err = expectNotification(t, l.Notify, "notify_listen_test", "") | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	// shouldn't cause a disconnect | ||||
| 	ok, err := l.cn.ExecSimpleQuery("SELECT error") | ||||
| 	if !ok { | ||||
| 		t.Fatalf("could not send query to server: %v", err) | ||||
| 	} | ||||
| 	_, ok = err.(PGError) | ||||
| 	if !ok { | ||||
| 		t.Fatalf("unexpected error %v", err) | ||||
| 	} | ||||
| 	err = expectNoEvent(t, eventch) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	// should still work | ||||
| 	_, err = db.Exec("NOTIFY notify_listen_test") | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	err = expectNotification(t, l.Notify, "notify_listen_test", "") | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestListenerReconnect(t *testing.T) { | ||||
| 	l, eventch := newTestListenerTimeout(t, 20*time.Millisecond, time.Hour) | ||||
| 	defer l.Close() | ||||
|  | ||||
| 	db := openTestConn(t) | ||||
| 	defer db.Close() | ||||
|  | ||||
| 	err := l.Listen("notify_listen_test") | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	_, err = db.Exec("NOTIFY notify_listen_test") | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	err = expectNotification(t, l.Notify, "notify_listen_test", "") | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	// kill the connection and make sure it comes back up | ||||
| 	ok, err := l.cn.ExecSimpleQuery("SELECT pg_terminate_backend(pg_backend_pid())") | ||||
| 	if ok { | ||||
| 		t.Fatalf("could not kill the connection: %v", err) | ||||
| 	} | ||||
| 	if err != io.EOF { | ||||
| 		t.Fatalf("unexpected error %v", err) | ||||
| 	} | ||||
| 	err = expectEvent(t, eventch, ListenerEventDisconnected) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	err = expectEvent(t, eventch, ListenerEventReconnected) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	// should still work | ||||
| 	_, err = db.Exec("NOTIFY notify_listen_test") | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	// should get nil after Reconnected | ||||
| 	err = expectNotification(t, l.Notify, "", "") | ||||
| 	if err != errNilNotification { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	err = expectNotification(t, l.Notify, "notify_listen_test", "") | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestListenerClose(t *testing.T) { | ||||
| 	l, _ := newTestListenerTimeout(t, 20*time.Millisecond, time.Hour) | ||||
| 	defer l.Close() | ||||
|  | ||||
| 	err := l.Close() | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	err = l.Close() | ||||
| 	if err != errListenerClosed { | ||||
| 		t.Fatalf("expected errListenerClosed; got %v", err) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestListenerPing(t *testing.T) { | ||||
| 	l, _ := newTestListenerTimeout(t, 20*time.Millisecond, time.Hour) | ||||
| 	defer l.Close() | ||||
|  | ||||
| 	err := l.Ping() | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	err = l.Close() | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	err = l.Ping() | ||||
| 	if err != errListenerClosed { | ||||
| 		t.Fatalf("expected errListenerClosed; got %v", err) | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										269
									
								
								vendor/github.com/lib/pq/ssl_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										269
									
								
								vendor/github.com/lib/pq/ssl_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,269 +0,0 @@ | ||||
| package pq | ||||
|  | ||||
| // This file contains SSL tests | ||||
|  | ||||
| import ( | ||||
| 	_ "crypto/sha256" | ||||
| 	"crypto/x509" | ||||
| 	"database/sql" | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| func maybeSkipSSLTests(t *testing.T) { | ||||
| 	// Require some special variables for testing certificates | ||||
| 	if os.Getenv("PQSSLCERTTEST_PATH") == "" { | ||||
| 		t.Skip("PQSSLCERTTEST_PATH not set, skipping SSL tests") | ||||
| 	} | ||||
|  | ||||
| 	value := os.Getenv("PQGOSSLTESTS") | ||||
| 	if value == "" || value == "0" { | ||||
| 		t.Skip("PQGOSSLTESTS not enabled, skipping SSL tests") | ||||
| 	} else if value != "1" { | ||||
| 		t.Fatalf("unexpected value %q for PQGOSSLTESTS", value) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func openSSLConn(t *testing.T, conninfo string) (*sql.DB, error) { | ||||
| 	db, err := openTestConnConninfo(conninfo) | ||||
| 	if err != nil { | ||||
| 		// should never fail | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	// Do something with the connection to see whether it's working or not. | ||||
| 	tx, err := db.Begin() | ||||
| 	if err == nil { | ||||
| 		return db, tx.Rollback() | ||||
| 	} | ||||
| 	_ = db.Close() | ||||
| 	return nil, err | ||||
| } | ||||
|  | ||||
| func checkSSLSetup(t *testing.T, conninfo string) { | ||||
| 	db, err := openSSLConn(t, conninfo) | ||||
| 	if err == nil { | ||||
| 		db.Close() | ||||
| 		t.Fatalf("expected error with conninfo=%q", conninfo) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Connect over SSL and run a simple query to test the basics | ||||
| func TestSSLConnection(t *testing.T) { | ||||
| 	maybeSkipSSLTests(t) | ||||
| 	// Environment sanity check: should fail without SSL | ||||
| 	checkSSLSetup(t, "sslmode=disable user=pqgossltest") | ||||
|  | ||||
| 	db, err := openSSLConn(t, "sslmode=require user=pqgossltest") | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	rows, err := db.Query("SELECT 1") | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	rows.Close() | ||||
| } | ||||
|  | ||||
| // Test sslmode=verify-full | ||||
| func TestSSLVerifyFull(t *testing.T) { | ||||
| 	maybeSkipSSLTests(t) | ||||
| 	// Environment sanity check: should fail without SSL | ||||
| 	checkSSLSetup(t, "sslmode=disable user=pqgossltest") | ||||
|  | ||||
| 	// Not OK according to the system CA | ||||
| 	_, err := openSSLConn(t, "host=postgres sslmode=verify-full user=pqgossltest") | ||||
| 	if err == nil { | ||||
| 		t.Fatal("expected error") | ||||
| 	} | ||||
| 	_, ok := err.(x509.UnknownAuthorityError) | ||||
| 	if !ok { | ||||
| 		t.Fatalf("expected x509.UnknownAuthorityError, got %#+v", err) | ||||
| 	} | ||||
|  | ||||
| 	rootCertPath := filepath.Join(os.Getenv("PQSSLCERTTEST_PATH"), "root.crt") | ||||
| 	rootCert := "sslrootcert=" + rootCertPath + " " | ||||
| 	// No match on Common Name | ||||
| 	_, err = openSSLConn(t, rootCert+"host=127.0.0.1 sslmode=verify-full user=pqgossltest") | ||||
| 	if err == nil { | ||||
| 		t.Fatal("expected error") | ||||
| 	} | ||||
| 	_, ok = err.(x509.HostnameError) | ||||
| 	if !ok { | ||||
| 		t.Fatalf("expected x509.HostnameError, got %#+v", err) | ||||
| 	} | ||||
| 	// OK | ||||
| 	_, err = openSSLConn(t, rootCert+"host=postgres sslmode=verify-full user=pqgossltest") | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Test sslmode=require sslrootcert=rootCertPath | ||||
| func TestSSLRequireWithRootCert(t *testing.T) { | ||||
| 	maybeSkipSSLTests(t) | ||||
| 	// Environment sanity check: should fail without SSL | ||||
| 	checkSSLSetup(t, "sslmode=disable user=pqgossltest") | ||||
|  | ||||
| 	bogusRootCertPath := filepath.Join(os.Getenv("PQSSLCERTTEST_PATH"), "bogus_root.crt") | ||||
| 	bogusRootCert := "sslrootcert=" + bogusRootCertPath + " " | ||||
|  | ||||
| 	// Not OK according to the bogus CA | ||||
| 	_, err := openSSLConn(t, bogusRootCert+"host=postgres sslmode=require user=pqgossltest") | ||||
| 	if err == nil { | ||||
| 		t.Fatal("expected error") | ||||
| 	} | ||||
| 	_, ok := err.(x509.UnknownAuthorityError) | ||||
| 	if !ok { | ||||
| 		t.Fatalf("expected x509.UnknownAuthorityError, got %s, %#+v", err, err) | ||||
| 	} | ||||
|  | ||||
| 	nonExistentCertPath := filepath.Join(os.Getenv("PQSSLCERTTEST_PATH"), "non_existent.crt") | ||||
| 	nonExistentCert := "sslrootcert=" + nonExistentCertPath + " " | ||||
|  | ||||
| 	// No match on Common Name, but that's OK because we're not validating anything. | ||||
| 	_, err = openSSLConn(t, nonExistentCert+"host=127.0.0.1 sslmode=require user=pqgossltest") | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	rootCertPath := filepath.Join(os.Getenv("PQSSLCERTTEST_PATH"), "root.crt") | ||||
| 	rootCert := "sslrootcert=" + rootCertPath + " " | ||||
|  | ||||
| 	// No match on Common Name, but that's OK because we're not validating the CN. | ||||
| 	_, err = openSSLConn(t, rootCert+"host=127.0.0.1 sslmode=require user=pqgossltest") | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	// Everything OK | ||||
| 	_, err = openSSLConn(t, rootCert+"host=postgres sslmode=require 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) | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										66
									
								
								vendor/github.com/lib/pq/url_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										66
									
								
								vendor/github.com/lib/pq/url_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,66 +0,0 @@ | ||||
| package pq | ||||
|  | ||||
| import ( | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| func TestSimpleParseURL(t *testing.T) { | ||||
| 	expected := "host=hostname.remote" | ||||
| 	str, err := ParseURL("postgres://hostname.remote") | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	if str != expected { | ||||
| 		t.Fatalf("unexpected result from ParseURL:\n+ %v\n- %v", str, expected) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestIPv6LoopbackParseURL(t *testing.T) { | ||||
| 	expected := "host=::1 port=1234" | ||||
| 	str, err := ParseURL("postgres://[::1]:1234") | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	if str != expected { | ||||
| 		t.Fatalf("unexpected result from ParseURL:\n+ %v\n- %v", str, expected) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestFullParseURL(t *testing.T) { | ||||
| 	expected := `dbname=database host=hostname.remote password=top\ secret port=1234 user=username` | ||||
| 	str, err := ParseURL("postgres://username:top%20secret@hostname.remote:1234/database") | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	if str != expected { | ||||
| 		t.Fatalf("unexpected result from ParseURL:\n+ %s\n- %s", str, expected) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestInvalidProtocolParseURL(t *testing.T) { | ||||
| 	_, err := ParseURL("http://hostname.remote") | ||||
| 	switch err { | ||||
| 	case nil: | ||||
| 		t.Fatal("Expected an error from parsing invalid protocol") | ||||
| 	default: | ||||
| 		msg := "invalid connection protocol: http" | ||||
| 		if err.Error() != msg { | ||||
| 			t.Fatalf("Unexpected error message:\n+ %s\n- %s", | ||||
| 				err.Error(), msg) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestMinimalURL(t *testing.T) { | ||||
| 	cs, err := ParseURL("postgres://") | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	if cs != "" { | ||||
| 		t.Fatalf("expected blank connection string, got: %q", cs) | ||||
| 	} | ||||
| } | ||||
		Reference in New Issue
	
	Block a user