@@ -61,7 +61,7 @@ require ( | |||
github.com/keybase/go-crypto v0.0.0-20200123153347-de78d2cb44f4 | |||
github.com/klauspost/compress v1.10.2 | |||
github.com/lafriks/xormstore v1.3.2 | |||
github.com/lib/pq v1.2.0 | |||
github.com/lib/pq v1.7.0 | |||
github.com/lunny/dingtalk_webhook v0.0.0-20171025031554-e3534c89ef96 | |||
github.com/mailru/easyjson v0.7.0 // indirect | |||
github.com/markbates/goth v1.61.2 |
@@ -437,6 +437,8 @@ github.com/lestrrat-go/jwx v0.9.0/go.mod h1:iEoxlYfZjvoGpuWwxUz+eR5e6KTJGsaRcy/Y | |||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= | |||
github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0= | |||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= | |||
github.com/lib/pq v1.7.0 h1:h93mCPfUSkaul3Ka/VG8uZdmW1uMHDGxzu0NWHuJmHY= | |||
github.com/lib/pq v1.7.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= | |||
github.com/lunny/dingtalk_webhook v0.0.0-20171025031554-e3534c89ef96 h1:uNwtsDp7ci48vBTTxDuwcoTXz4lwtDTe7TjCQ0noaWY= | |||
github.com/lunny/dingtalk_webhook v0.0.0-20171025031554-e3534c89ef96/go.mod h1:mmIfjCSQlGYXmJ95jFN84AkQFnVABtKuJL8IrzwvUKQ= | |||
github.com/lunny/log v0.0.0-20160921050905-7887c61bf0de h1:nyxwRdWHAVxpFcDThedEgQ07DbcRc5xgNObtbTp76fk= |
@@ -1,8 +1,8 @@ | |||
language: go | |||
go: | |||
- 1.11.x | |||
- 1.12.x | |||
- 1.13.x | |||
- 1.14.x | |||
- master | |||
sudo: true | |||
@@ -27,7 +27,7 @@ before_install: | |||
- ./.travis.sh client_configure | |||
- go get golang.org/x/tools/cmd/goimports | |||
- go get golang.org/x/lint/golint | |||
- GO111MODULE=on go get honnef.co/go/tools/cmd/staticcheck@2019.2.1 | |||
- GO111MODULE=on go get honnef.co/go/tools/cmd/staticcheck@2020.1.3 | |||
before_script: | |||
- createdb pqgotest | |||
@@ -38,7 +38,7 @@ script: | |||
- > | |||
goimports -d -e $(find -name '*.go') | awk '{ print } END { exit NR == 0 ? 0 : 1 }' | |||
- go vet ./... | |||
- staticcheck -go 1.11 ./... | |||
- staticcheck -go 1.13 ./... | |||
- golint ./... | |||
- PQTEST_BINARY_PARAMETERS=no go test -race -v ./... | |||
- PQTEST_BINARY_PARAMETERS=yes go test -race -v ./... |
@@ -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. |
@@ -1,21 +1,11 @@ | |||
# pq - A pure Go postgres driver for Go's database/sql package | |||
[![GoDoc](https://godoc.org/github.com/lib/pq?status.svg)](https://godoc.org/github.com/lib/pq) | |||
[![Build Status](https://travis-ci.org/lib/pq.svg?branch=master)](https://travis-ci.org/lib/pq) | |||
[![GoDoc](https://godoc.org/github.com/lib/pq?status.svg)](https://pkg.go.dev/github.com/lib/pq?tab=doc) | |||
## Install | |||
go get github.com/lib/pq | |||
## Docs | |||
For detailed documentation and basic usage examples, please see the package | |||
documentation at <https://godoc.org/github.com/lib/pq>. | |||
## Tests | |||
`go test` is used for testing. See [TESTS.md](TESTS.md) for more details. | |||
## Features | |||
* SSL | |||
@@ -30,66 +20,14 @@ documentation at <https://godoc.org/github.com/lib/pq>. | |||
* Notifications: `LISTEN`/`NOTIFY` | |||
* pgpass support | |||
## Future / Things you can help with | |||
## Optional Features | |||
* GSS (Kerberos) auth (to use, see GoDoc) | |||
* Better COPY FROM / COPY TO (see discussion in #181) | |||
## Tests | |||
## Thank you (alphabetical) | |||
`go test` is used for testing. See [TESTS.md](TESTS.md) for more details. | |||
Some of these contributors are from the original library `bmizerany/pq.go` whose | |||
code still exists in here. | |||
## Status | |||
* 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) | |||
This package is effectively in maintenance mode and is not actively developed. Small patches and features are only rarely reviewed and merged. We recommend using [pgx](https://github.com/jackc/pgx) which is actively maintained. |
@@ -149,6 +149,15 @@ type conn struct { | |||
// If true this connection is in the middle of a COPY | |||
inCopy bool | |||
// If not nil, notices will be synchronously sent here | |||
noticeHandler func(*Error) | |||
// If not nil, notifications will be synchronously sent here | |||
notificationHandler func(*Notification) | |||
// GSSAPI context | |||
gss GSS | |||
} | |||
// Handle driver-side settings in parsed connection string. | |||
@@ -329,10 +338,6 @@ func (c *Connector) open(ctx context.Context) (cn *conn, err error) { | |||
func dial(ctx context.Context, d Dialer, o values) (net.Conn, error) { | |||
network, address := network(o) | |||
// SSL is not necessary or supported over UNIX domain sockets | |||
if network == "unix" { | |||
o["sslmode"] = "disable" | |||
} | |||
// Zero or not specified means wait indefinitely. | |||
if timeout, ok := o["connect_timeout"]; ok && timeout != "0" { | |||
@@ -971,7 +976,13 @@ func (cn *conn) recv() (t byte, r *readBuf) { | |||
case 'E': | |||
panic(parseError(r)) | |||
case 'N': | |||
// ignore | |||
if n := cn.noticeHandler; n != nil { | |||
n(parseError(r)) | |||
} | |||
case 'A': | |||
if n := cn.notificationHandler; n != nil { | |||
n(recvNotification(r)) | |||
} | |||
default: | |||
return | |||
} | |||
@@ -988,8 +999,14 @@ func (cn *conn) recv1Buf(r *readBuf) byte { | |||
} | |||
switch t { | |||
case 'A', 'N': | |||
// ignore | |||
case 'A': | |||
if n := cn.notificationHandler; n != nil { | |||
n(recvNotification(r)) | |||
} | |||
case 'N': | |||
if n := cn.noticeHandler; n != nil { | |||
n(parseError(r)) | |||
} | |||
case 'S': | |||
cn.processParameterStatus(r) | |||
default: | |||
@@ -1057,7 +1074,10 @@ func isDriverSetting(key string) bool { | |||
return true | |||
case "binary_parameters": | |||
return true | |||
case "service": | |||
return true | |||
case "spn": | |||
return true | |||
default: | |||
return false | |||
} | |||
@@ -1137,6 +1157,59 @@ func (cn *conn) auth(r *readBuf, o values) { | |||
if r.int32() != 0 { | |||
errorf("unexpected authentication response: %q", t) | |||
} | |||
case 7: // GSSAPI, startup | |||
if newGss == nil { | |||
errorf("kerberos error: no GSSAPI provider registered (import github.com/lib/pq/auth/kerberos if you need Kerberos support)") | |||
} | |||
cli, err := newGss() | |||
if err != nil { | |||
errorf("kerberos error: %s", err.Error()) | |||
} | |||
var token []byte | |||
if spn, ok := o["spn"]; ok { | |||
// Use the supplied SPN if provided.. | |||
token, err = cli.GetInitTokenFromSpn(spn) | |||
} else { | |||
// Allow the kerberos service name to be overridden | |||
service := "postgres" | |||
if val, ok := o["service"]; ok { | |||
service = val | |||
} | |||
token, err = cli.GetInitToken(o["host"], service) | |||
} | |||
if err != nil { | |||
errorf("failed to get Kerberos ticket: %q", err) | |||
} | |||
w := cn.writeBuf('p') | |||
w.bytes(token) | |||
cn.send(w) | |||
// Store for GSSAPI continue message | |||
cn.gss = cli | |||
case 8: // GSSAPI continue | |||
if cn.gss == nil { | |||
errorf("GSSAPI protocol error") | |||
} | |||
b := []byte(*r) | |||
done, tokOut, err := cn.gss.Continue(b) | |||
if err == nil && !done { | |||
w := cn.writeBuf('p') | |||
w.bytes(tokOut) | |||
cn.send(w) | |||
} | |||
// Errors fall through and read the more detailed message | |||
// from the server.. | |||
case 10: | |||
sc := scram.NewClient(sha256.New, o["user"], o["password"]) | |||
sc.Step(nil) |
@@ -79,7 +79,7 @@ func (cn *conn) Ping(ctx context.Context) error { | |||
if finish := cn.watchCancel(ctx); finish != nil { | |||
defer finish() | |||
} | |||
rows, err := cn.simpleQuery("SELECT 'lib/pq ping test';") | |||
rows, err := cn.simpleQuery(";") | |||
if err != nil { | |||
return driver.ErrBadConn // https://golang.org/pkg/database/sql/driver/#Pinger | |||
} |
@@ -106,5 +106,10 @@ func NewConnector(dsn string) (*Connector, error) { | |||
o["user"] = u | |||
} | |||
// SSL is not necessary or supported over UNIX domain sockets | |||
if network, _ := network(o); network == "unix" { | |||
o["sslmode"] = "disable" | |||
} | |||
return &Connector{opts: o, dialer: defaultDialer{}}, nil | |||
} |
@@ -152,7 +152,9 @@ func (ci *copyin) resploop() { | |||
case 'C': | |||
// complete | |||
case 'N': | |||
// NoticeResponse | |||
if n := ci.cn.noticeHandler; n != nil { | |||
n(parseError(&r)) | |||
} | |||
case 'Z': | |||
ci.cn.processReadyForQuery(&r) | |||
ci.done <- true | |||
@@ -229,7 +231,7 @@ func (ci *copyin) Exec(v []driver.Value) (r driver.Result, err error) { | |||
} | |||
if len(v) == 0 { | |||
return nil, ci.Close() | |||
return driver.RowsAffected(0), ci.Close() | |||
} | |||
numValues := len(v) |
@@ -57,6 +57,8 @@ supported: | |||
* sslkey - Key file location. The file must contain PEM encoded data. | |||
* sslrootcert - The location of the root certificate file. The file | |||
must contain PEM encoded data. | |||
* spn - Configures GSS (Kerberos) SPN. | |||
* service - GSS (Kerberos) service name to use when constructing the SPN (default is `postgres`). | |||
Valid values for sslmode are: | |||
@@ -241,5 +243,21 @@ bytes by the PostgreSQL server. | |||
You can find a complete, working example of Listener usage at | |||
https://godoc.org/github.com/lib/pq/example/listen. | |||
Kerberos Support | |||
If you need support for Kerberos authentication, add the following to your main | |||
package: | |||
import "github.com/lib/pq/auth/kerberos" | |||
func init() { | |||
pq.RegisterGSSProvider(func() (pq.Gss, error) { return kerberos.NewGSS() }) | |||
} | |||
This package is in a separate module so that users who don't need Kerberos | |||
don't have to download unnecessary dependencies. | |||
*/ | |||
package pq |
@@ -8,6 +8,7 @@ import ( | |||
"errors" | |||
"fmt" | |||
"math" | |||
"regexp" | |||
"strconv" | |||
"strings" | |||
"sync" | |||
@@ -16,6 +17,8 @@ import ( | |||
"github.com/lib/pq/oid" | |||
) | |||
var time2400Regex = regexp.MustCompile(`^(24:00(?::00(?:\.0+)?)?)(?:[Z+-].*)?$`) | |||
func binaryEncode(parameterStatus *parameterStatus, x interface{}) []byte { | |||
switch v := x.(type) { | |||
case []byte: | |||
@@ -202,10 +205,27 @@ func mustParse(f string, typ oid.Oid, s []byte) time.Time { | |||
str[len(str)-3] == ':' { | |||
f += ":00" | |||
} | |||
// Special case for 24:00 time. | |||
// Unfortunately, golang does not parse 24:00 as a proper time. | |||
// In this case, we want to try "round to the next day", to differentiate. | |||
// As such, we find if the 24:00 time matches at the beginning; if so, | |||
// we default it back to 00:00 but add a day later. | |||
var is2400Time bool | |||
switch typ { | |||
case oid.T_timetz, oid.T_time: | |||
if matches := time2400Regex.FindStringSubmatch(str); matches != nil { | |||
// Concatenate timezone information at the back. | |||
str = "00:00:00" + str[len(matches[1]):] | |||
is2400Time = true | |||
} | |||
} | |||
t, err := time.Parse(f, str) | |||
if err != nil { | |||
errorf("decode: %s", err) | |||
} | |||
if is2400Time { | |||
t = t.Add(24 * time.Hour) | |||
} | |||
return t | |||
} | |||
@@ -487,7 +507,7 @@ func FormatTimestamp(t time.Time) []byte { | |||
b := []byte(t.Format("2006-01-02 15:04:05.999999999Z07:00")) | |||
_, offset := t.Zone() | |||
offset = offset % 60 | |||
offset %= 60 | |||
if offset != 0 { | |||
// RFC3339Nano already printed the minus sign | |||
if offset < 0 { |
@@ -1 +1,3 @@ | |||
module github.com/lib/pq | |||
go 1.13 |
@@ -0,0 +1,27 @@ | |||
package pq | |||
// NewGSSFunc creates a GSS authentication provider, for use with | |||
// RegisterGSSProvider. | |||
type NewGSSFunc func() (GSS, error) | |||
var newGss NewGSSFunc | |||
// RegisterGSSProvider registers a GSS authentication provider. For example, if | |||
// you need to use Kerberos to authenticate with your server, add this to your | |||
// main package: | |||
// | |||
// import "github.com/lib/pq/auth/kerberos" | |||
// | |||
// func init() { | |||
// pq.RegisterGSSProvider(func() (pq.GSS, error) { return kerberos.NewGSS() }) | |||
// } | |||
func RegisterGSSProvider(newGssArg NewGSSFunc) { | |||
newGss = newGssArg | |||
} | |||
// GSS provides GSSAPI authentication (e.g., Kerberos). | |||
type GSS interface { | |||
GetInitToken(host string, service string) ([]byte, error) | |||
GetInitTokenFromSpn(spn string) ([]byte, error) | |||
Continue(inToken []byte) (done bool, outToken []byte, err error) | |||
} |
@@ -0,0 +1,71 @@ | |||
// +build go1.10 | |||
package pq | |||
import ( | |||
"context" | |||
"database/sql/driver" | |||
) | |||
// NoticeHandler returns the notice handler on the given connection, if any. A | |||
// runtime panic occurs if c is not a pq connection. This is rarely used | |||
// directly, use ConnectorNoticeHandler and ConnectorWithNoticeHandler instead. | |||
func NoticeHandler(c driver.Conn) func(*Error) { | |||
return c.(*conn).noticeHandler | |||
} | |||
// SetNoticeHandler sets the given notice handler on the given connection. A | |||
// runtime panic occurs if c is not a pq connection. A nil handler may be used | |||
// to unset it. This is rarely used directly, use ConnectorNoticeHandler and | |||
// ConnectorWithNoticeHandler instead. | |||
// | |||
// Note: Notice handlers are executed synchronously by pq meaning commands | |||
// won't continue to be processed until the handler returns. | |||
func SetNoticeHandler(c driver.Conn, handler func(*Error)) { | |||
c.(*conn).noticeHandler = handler | |||
} | |||
// NoticeHandlerConnector wraps a regular connector and sets a notice handler | |||
// on it. | |||
type NoticeHandlerConnector struct { | |||
driver.Connector | |||
noticeHandler func(*Error) | |||
} | |||
// Connect calls the underlying connector's connect method and then sets the | |||
// notice handler. | |||
func (n *NoticeHandlerConnector) Connect(ctx context.Context) (driver.Conn, error) { | |||
c, err := n.Connector.Connect(ctx) | |||
if err == nil { | |||
SetNoticeHandler(c, n.noticeHandler) | |||
} | |||
return c, err | |||
} | |||
// ConnectorNoticeHandler returns the currently set notice handler, if any. If | |||
// the given connector is not a result of ConnectorWithNoticeHandler, nil is | |||
// returned. | |||
func ConnectorNoticeHandler(c driver.Connector) func(*Error) { | |||
if c, ok := c.(*NoticeHandlerConnector); ok { | |||
return c.noticeHandler | |||
} | |||
return nil | |||
} | |||
// ConnectorWithNoticeHandler creates or sets the given handler for the given | |||
// connector. If the given connector is a result of calling this function | |||
// previously, it is simply set on the given connector and returned. Otherwise, | |||
// this returns a new connector wrapping the given one and setting the notice | |||
// handler. A nil notice handler may be used to unset it. | |||
// | |||
// The returned connector is intended to be used with database/sql.OpenDB. | |||
// | |||
// Note: Notice handlers are executed synchronously by pq meaning commands | |||
// won't continue to be processed until the handler returns. | |||
func ConnectorWithNoticeHandler(c driver.Connector, handler func(*Error)) *NoticeHandlerConnector { | |||
if c, ok := c.(*NoticeHandlerConnector); ok { | |||
c.noticeHandler = handler | |||
return c | |||
} | |||
return &NoticeHandlerConnector{Connector: c, noticeHandler: handler} | |||
} |
@@ -4,6 +4,8 @@ package pq | |||
// This module contains support for Postgres LISTEN/NOTIFY. | |||
import ( | |||
"context" | |||
"database/sql/driver" | |||
"errors" | |||
"fmt" | |||
"sync" | |||
@@ -29,6 +31,61 @@ func recvNotification(r *readBuf) *Notification { | |||
return &Notification{bePid, channel, extra} | |||
} | |||
// SetNotificationHandler sets the given notification handler on the given | |||
// connection. A runtime panic occurs if c is not a pq connection. A nil handler | |||
// may be used to unset it. | |||
// | |||
// Note: Notification handlers are executed synchronously by pq meaning commands | |||
// won't continue to be processed until the handler returns. | |||
func SetNotificationHandler(c driver.Conn, handler func(*Notification)) { | |||
c.(*conn).notificationHandler = handler | |||
} | |||
// NotificationHandlerConnector wraps a regular connector and sets a notification handler | |||
// on it. | |||
type NotificationHandlerConnector struct { | |||
driver.Connector | |||
notificationHandler func(*Notification) | |||
} | |||
// Connect calls the underlying connector's connect method and then sets the | |||
// notification handler. | |||
func (n *NotificationHandlerConnector) Connect(ctx context.Context) (driver.Conn, error) { | |||
c, err := n.Connector.Connect(ctx) | |||
if err == nil { | |||
SetNotificationHandler(c, n.notificationHandler) | |||
} | |||
return c, err | |||
} | |||
// ConnectorNotificationHandler returns the currently set notification handler, if any. If | |||
// the given connector is not a result of ConnectorWithNotificationHandler, nil is | |||
// returned. | |||
func ConnectorNotificationHandler(c driver.Connector) func(*Notification) { | |||
if c, ok := c.(*NotificationHandlerConnector); ok { | |||
return c.notificationHandler | |||
} | |||
return nil | |||
} | |||
// ConnectorWithNotificationHandler creates or sets the given handler for the given | |||
// connector. If the given connector is a result of calling this function | |||
// previously, it is simply set on the given connector and returned. Otherwise, | |||
// this returns a new connector wrapping the given one and setting the notification | |||
// handler. A nil notification handler may be used to unset it. | |||
// | |||
// The returned connector is intended to be used with database/sql.OpenDB. | |||
// | |||
// Note: Notification handlers are executed synchronously by pq meaning commands | |||
// won't continue to be processed until the handler returns. | |||
func ConnectorWithNotificationHandler(c driver.Connector, handler func(*Notification)) *NotificationHandlerConnector { | |||
if c, ok := c.(*NotificationHandlerConnector); ok { | |||
c.notificationHandler = handler | |||
return c | |||
} | |||
return &NotificationHandlerConnector{Connector: c, notificationHandler: handler} | |||
} | |||
const ( | |||
connStateIdle int32 = iota | |||
connStateExpectResponse | |||
@@ -174,8 +231,12 @@ func (l *ListenerConn) listenerConnLoop() (err error) { | |||
} | |||
l.replyChan <- message{t, nil} | |||
case 'N', 'S': | |||
case 'S': | |||
// ignore | |||
case 'N': | |||
if n := l.cn.noticeHandler; n != nil { | |||
n(parseError(r)) | |||
} | |||
default: | |||
return fmt.Errorf("unexpected message %q from server in listenerConnLoop", t) | |||
} |
@@ -94,7 +94,7 @@ func (c *Client) Out() []byte { | |||
return c.out.Bytes() | |||
} | |||
// Err returns the error that ocurred, or nil if there were no errors. | |||
// Err returns the error that occurred, or nil if there were no errors. | |||
func (c *Client) Err() error { | |||
return c.err | |||
} |
@@ -1,6 +1,6 @@ | |||
// Package pq is a pure Go Postgres driver for the database/sql package. | |||
// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris rumprun | |||
// +build aix darwin dragonfly freebsd linux nacl netbsd openbsd plan9 solaris rumprun | |||
package pq | |||
@@ -451,7 +451,7 @@ github.com/kr/text | |||
## explicit | |||
github.com/lafriks/xormstore | |||
github.com/lafriks/xormstore/util | |||
# github.com/lib/pq v1.2.0 | |||
# github.com/lib/pq v1.7.0 | |||
## explicit | |||
github.com/lib/pq | |||
github.com/lib/pq/oid |