Commit f8698dc4 by Sven Klemm Committed by Daniel Lee

update lib/pq (#9788)

parent b65ea57f
# pq - A pure Go postgres driver for Go's database/sql package # 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) [![Build Status](https://travis-ci.org/lib/pq.svg?branch=master)](https://travis-ci.org/lib/pq)
## Install ## Install
......
...@@ -35,8 +35,12 @@ var ( ...@@ -35,8 +35,12 @@ var (
errNoLastInsertID = errors.New("no LastInsertId available after the empty statement") errNoLastInsertID = errors.New("no LastInsertId available after the empty statement")
) )
// Driver is the Postgres database driver.
type Driver struct{} type Driver struct{}
// Open opens a new connection to the database. name is a connection string.
// Most users should only use it through database/sql package from the standard
// library.
func (d *Driver) Open(name string) (driver.Conn, error) { func (d *Driver) Open(name string) (driver.Conn, error) {
return Open(name) return Open(name)
} }
...@@ -78,6 +82,8 @@ func (s transactionStatus) String() string { ...@@ -78,6 +82,8 @@ func (s transactionStatus) String() string {
panic("not reached") panic("not reached")
} }
// Dialer is the dialer interface. It can be used to obtain more control over
// how pq creates network connections.
type Dialer interface { type Dialer interface {
Dial(network, address string) (net.Conn, error) Dial(network, address string) (net.Conn, error)
DialTimeout(network, address string, timeout time.Duration) (net.Conn, error) DialTimeout(network, address string, timeout time.Duration) (net.Conn, error)
...@@ -149,11 +155,7 @@ func (cn *conn) handleDriverSettings(o values) (err error) { ...@@ -149,11 +155,7 @@ func (cn *conn) handleDriverSettings(o values) (err error) {
if err != nil { if err != nil {
return err return err
} }
err = boolSetting("binary_parameters", &cn.binaryParameters) return boolSetting("binary_parameters", &cn.binaryParameters)
if err != nil {
return err
}
return nil
} }
func (cn *conn) handlePgpass(o values) { func (cn *conn) handlePgpass(o values) {
...@@ -165,11 +167,16 @@ func (cn *conn) handlePgpass(o values) { ...@@ -165,11 +167,16 @@ func (cn *conn) handlePgpass(o values) {
if filename == "" { if filename == "" {
// XXX this code doesn't work on Windows where the default filename is // XXX this code doesn't work on Windows where the default filename is
// XXX %APPDATA%\postgresql\pgpass.conf // XXX %APPDATA%\postgresql\pgpass.conf
// Prefer $HOME over user.Current due to glibc bug: golang.org/issue/13470
userHome := os.Getenv("HOME")
if userHome == "" {
user, err := user.Current() user, err := user.Current()
if err != nil { if err != nil {
return return
} }
filename = filepath.Join(user.HomeDir, ".pgpass") userHome = user.HomeDir
}
filename = filepath.Join(userHome, ".pgpass")
} }
fileinfo, err := os.Stat(filename) fileinfo, err := os.Stat(filename)
if err != nil { if err != nil {
...@@ -237,10 +244,14 @@ func (cn *conn) writeBuf(b byte) *writeBuf { ...@@ -237,10 +244,14 @@ func (cn *conn) writeBuf(b byte) *writeBuf {
} }
} }
// Open opens a new connection to the database. name is a connection string.
// Most users should only use it through database/sql package from the standard
// library.
func Open(name string) (_ driver.Conn, err error) { func Open(name string) (_ driver.Conn, err error) {
return DialOpen(defaultDialer{}, name) return DialOpen(defaultDialer{}, name)
} }
// DialOpen opens a new connection to the database using a dialer.
func DialOpen(d Dialer, name string) (_ driver.Conn, err error) { func DialOpen(d Dialer, name string) (_ driver.Conn, err error) {
// Handle any panics during connection initialization. Note that we // Handle any panics during connection initialization. Note that we
// specifically do *not* want to use errRecover(), as that would turn any // specifically do *not* want to use errRecover(), as that would turn any
...@@ -1431,7 +1442,8 @@ func (rs *rows) NextResultSet() error { ...@@ -1431,7 +1442,8 @@ func (rs *rows) NextResultSet() error {
// //
// tblname := "my_table" // tblname := "my_table"
// data := "my_data" // data := "my_data"
// err = db.Exec(fmt.Sprintf("INSERT INTO %s VALUES ($1)", pq.QuoteIdentifier(tblname)), data) // quoted := pq.QuoteIdentifier(tblname)
// err := db.Exec(fmt.Sprintf("INSERT INTO %s VALUES ($1)", quoted), data)
// //
// Any double quotes in name will be escaped. The quoted identifier will be // Any double quotes in name will be escaped. The quoted identifier will be
// case sensitive when used in a query. If the input string contains a zero // case sensitive when used in a query. If the input string contains a zero
......
...@@ -11,7 +11,8 @@ using this package directly. For example: ...@@ -11,7 +11,8 @@ using this package directly. For example:
) )
func main() { func main() {
db, err := sql.Open("postgres", "user=pqgotest dbname=pqgotest sslmode=verify-full") connStr := "user=pqgotest dbname=pqgotest sslmode=verify-full"
db, err := sql.Open("postgres", connStr)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
...@@ -23,7 +24,8 @@ using this package directly. For example: ...@@ -23,7 +24,8 @@ using this package directly. For example:
You can also connect to a database using a URL. For example: You can also connect to a database using a URL. For example:
db, err := sql.Open("postgres", "postgres://pqgotest:password@localhost/pqgotest?sslmode=verify-full") connStr := "postgres://pqgotest:password@localhost/pqgotest?sslmode=verify-full"
db, err := sql.Open("postgres", connStr)
Connection String Parameters Connection String Parameters
...@@ -43,21 +45,28 @@ supported: ...@@ -43,21 +45,28 @@ supported:
* dbname - The name of the database to connect to * dbname - The name of the database to connect to
* user - The user to sign in as * user - The user to sign in as
* password - The user's password * password - The user's password
* host - The host to connect to. Values that start with / are for unix domain sockets. (default is localhost) * host - The host to connect to. Values that start with / are for unix
domain sockets. (default is localhost)
* port - The port to bind to. (default is 5432) * port - The port to bind to. (default is 5432)
* sslmode - Whether or not to use SSL (default is require, this is not the default for libpq) * sslmode - Whether or not to use SSL (default is require, this is not
the default for libpq)
* fallback_application_name - An application_name to fall back to if one isn't provided. * fallback_application_name - An application_name to fall back to if one isn't provided.
* connect_timeout - Maximum wait for connection, in seconds. Zero or not specified means wait indefinitely. * connect_timeout - Maximum wait for connection, in seconds. Zero or
not specified means wait indefinitely.
* sslcert - Cert file location. The file must contain PEM encoded data. * sslcert - Cert file location. The file must contain PEM encoded data.
* sslkey - Key file location. The file must contain PEM encoded data. * sslkey - Key file location. The file must contain PEM encoded data.
* sslrootcert - The location of the root certificate file. The file must contain PEM encoded data. * sslrootcert - The location of the root certificate file. The file
must contain PEM encoded data.
Valid values for sslmode are: Valid values for sslmode are:
* disable - No SSL * disable - No SSL
* require - Always SSL (skip verification) * require - Always SSL (skip verification)
* verify-ca - Always SSL (verify that the certificate presented by the server was signed by a trusted CA) * verify-ca - Always SSL (verify that the certificate presented by the
* verify-full - Always SSL (verify that the certification presented by the server was signed by a trusted CA and the server host name matches the one in the certificate) server was signed by a trusted CA)
* verify-full - Always SSL (verify that the certification presented by
the server was signed by a trusted CA and the server host name
matches the one in the certificate)
See http://www.postgresql.org/docs/current/static/libpq-connect.html#LIBPQ-CONNSTRING See http://www.postgresql.org/docs/current/static/libpq-connect.html#LIBPQ-CONNSTRING
for more information about connection string parameters. for more information about connection string parameters.
...@@ -68,7 +77,7 @@ Use single quotes for values that contain whitespace: ...@@ -68,7 +77,7 @@ Use single quotes for values that contain whitespace:
A backslash will escape the next character in values: A backslash will escape the next character in values:
"user=space\ man password='it\'s valid' "user=space\ man password='it\'s valid'"
Note that the connection parameter client_encoding (which sets the Note that the connection parameter client_encoding (which sets the
text encoding for the connection) may be set but must be "UTF8", text encoding for the connection) may be set but must be "UTF8",
...@@ -129,7 +138,8 @@ This package returns the following types for values from the PostgreSQL backend: ...@@ -129,7 +138,8 @@ This package returns the following types for values from the PostgreSQL backend:
- integer types smallint, integer, and bigint are returned as int64 - integer types smallint, integer, and bigint are returned as int64
- floating-point types real and double precision are returned as float64 - floating-point types real and double precision are returned as float64
- character types char, varchar, and text are returned as string - character types char, varchar, and text are returned as string
- temporal types date, time, timetz, timestamp, and timestamptz are returned as time.Time - temporal types date, time, timetz, timestamp, and timestamptz are
returned as time.Time
- the boolean type is returned as bool - the boolean type is returned as bool
- the bytea type is returned as []byte - the bytea type is returned as []byte
...@@ -229,7 +239,7 @@ for more information). Note that the channel name will be truncated to 63 ...@@ -229,7 +239,7 @@ for more information). Note that the channel name will be truncated to 63
bytes by the PostgreSQL server. bytes by the PostgreSQL server.
You can find a complete, working example of Listener usage at You can find a complete, working example of Listener usage at
http://godoc.org/github.com/lib/pq/listen_example. http://godoc.org/github.com/lib/pq/examples/listen.
*/ */
package pq package pq
...@@ -367,8 +367,15 @@ func ParseTimestamp(currentLocation *time.Location, str string) (time.Time, erro ...@@ -367,8 +367,15 @@ func ParseTimestamp(currentLocation *time.Location, str string) (time.Time, erro
timeSep := daySep + 3 timeSep := daySep + 3
day := p.mustAtoi(str, daySep+1, timeSep) day := p.mustAtoi(str, daySep+1, timeSep)
minLen := monSep + len("01-01") + 1
isBC := strings.HasSuffix(str, " BC")
if isBC {
minLen += 3
}
var hour, minute, second int var hour, minute, second int
if len(str) > monSep+len("01-01")+1 { if len(str) > minLen {
p.expect(str, ' ', timeSep) p.expect(str, ' ', timeSep)
minSep := timeSep + 3 minSep := timeSep + 3
p.expect(str, ':', minSep) p.expect(str, ':', minSep)
...@@ -424,7 +431,8 @@ func ParseTimestamp(currentLocation *time.Location, str string) (time.Time, erro ...@@ -424,7 +431,8 @@ func ParseTimestamp(currentLocation *time.Location, str string) (time.Time, erro
tzOff = tzSign * ((tzHours * 60 * 60) + (tzMin * 60) + tzSec) tzOff = tzSign * ((tzHours * 60 * 60) + (tzMin * 60) + tzSec)
} }
var isoYear int var isoYear int
if remainderIdx+3 <= len(str) && str[remainderIdx:remainderIdx+3] == " BC" {
if isBC {
isoYear = 1 - year isoYear = 1 - year
remainderIdx += 3 remainderIdx += 3
} else { } else {
......
...@@ -60,7 +60,7 @@ type ListenerConn struct { ...@@ -60,7 +60,7 @@ type ListenerConn struct {
replyChan chan message replyChan chan message
} }
// Creates a new ListenerConn. Use NewListener instead. // NewListenerConn creates a new ListenerConn. Use NewListener instead.
func NewListenerConn(name string, notificationChan chan<- *Notification) (*ListenerConn, error) { func NewListenerConn(name string, notificationChan chan<- *Notification) (*ListenerConn, error) {
return newDialListenerConn(defaultDialer{}, name, notificationChan) return newDialListenerConn(defaultDialer{}, name, notificationChan)
} }
...@@ -214,17 +214,17 @@ func (l *ListenerConn) listenerConnMain() { ...@@ -214,17 +214,17 @@ func (l *ListenerConn) listenerConnMain() {
// this ListenerConn is done // this ListenerConn is done
} }
// Send a LISTEN query to the server. See ExecSimpleQuery. // Listen sends a LISTEN query to the server. See ExecSimpleQuery.
func (l *ListenerConn) Listen(channel string) (bool, error) { func (l *ListenerConn) Listen(channel string) (bool, error) {
return l.ExecSimpleQuery("LISTEN " + QuoteIdentifier(channel)) return l.ExecSimpleQuery("LISTEN " + QuoteIdentifier(channel))
} }
// Send an UNLISTEN query to the server. See ExecSimpleQuery. // Unlisten sends an UNLISTEN query to the server. See ExecSimpleQuery.
func (l *ListenerConn) Unlisten(channel string) (bool, error) { func (l *ListenerConn) Unlisten(channel string) (bool, error) {
return l.ExecSimpleQuery("UNLISTEN " + QuoteIdentifier(channel)) return l.ExecSimpleQuery("UNLISTEN " + QuoteIdentifier(channel))
} }
// Send `UNLISTEN *` to the server. See ExecSimpleQuery. // UnlistenAll sends an `UNLISTEN *` query to the server. See ExecSimpleQuery.
func (l *ListenerConn) UnlistenAll() (bool, error) { func (l *ListenerConn) UnlistenAll() (bool, error) {
return l.ExecSimpleQuery("UNLISTEN *") return l.ExecSimpleQuery("UNLISTEN *")
} }
...@@ -267,8 +267,8 @@ func (l *ListenerConn) sendSimpleQuery(q string) (err error) { ...@@ -267,8 +267,8 @@ func (l *ListenerConn) sendSimpleQuery(q string) (err error) {
return nil return nil
} }
// Execute a "simple query" (i.e. one with no bindable parameters) on the // ExecSimpleQuery executes a "simple query" (i.e. one with no bindable
// connection. The possible return values are: // parameters) on the connection. The possible return values are:
// 1) "executed" is true; the query was executed to completion on the // 1) "executed" is true; the query was executed to completion on the
// database server. If the query failed, err will be set to the error // database server. If the query failed, err will be set to the error
// returned by the database, otherwise err will be nil. // returned by the database, otherwise err will be nil.
...@@ -333,6 +333,7 @@ func (l *ListenerConn) ExecSimpleQuery(q string) (executed bool, err error) { ...@@ -333,6 +333,7 @@ func (l *ListenerConn) ExecSimpleQuery(q string) (executed bool, err error) {
} }
} }
// Close closes the connection.
func (l *ListenerConn) Close() error { func (l *ListenerConn) Close() error {
l.connectionLock.Lock() l.connectionLock.Lock()
if l.err != nil { if l.err != nil {
...@@ -346,7 +347,7 @@ func (l *ListenerConn) Close() error { ...@@ -346,7 +347,7 @@ func (l *ListenerConn) Close() error {
return l.cn.c.Close() return l.cn.c.Close()
} }
// Err() returns the reason the connection was closed. It is not safe to call // Err returns the reason the connection was closed. It is not safe to call
// this function until l.Notify has been closed. // this function until l.Notify has been closed.
func (l *ListenerConn) Err() error { func (l *ListenerConn) Err() error {
return l.err return l.err
...@@ -354,32 +355,43 @@ func (l *ListenerConn) Err() error { ...@@ -354,32 +355,43 @@ func (l *ListenerConn) Err() error {
var errListenerClosed = errors.New("pq: Listener has been closed") var errListenerClosed = errors.New("pq: Listener has been closed")
// ErrChannelAlreadyOpen is returned from Listen when a channel is already
// open.
var ErrChannelAlreadyOpen = errors.New("pq: channel is already open") var ErrChannelAlreadyOpen = errors.New("pq: channel is already open")
// ErrChannelNotOpen is returned from Unlisten when a channel is not open.
var ErrChannelNotOpen = errors.New("pq: channel is not open") var ErrChannelNotOpen = errors.New("pq: channel is not open")
// ListenerEventType is an enumeration of listener event types.
type ListenerEventType int type ListenerEventType int
const ( const (
// Emitted only when the database connection has been initially // ListenerEventConnected is emitted only when the database connection
// initialized. err will always be nil. // has been initially initialized. The err argument of the callback
// will always be nil.
ListenerEventConnected ListenerEventType = iota ListenerEventConnected ListenerEventType = iota
// Emitted after a database connection has been lost, either because of an // ListenerEventDisconnected is emitted after a database connection has
// error or because Close has been called. err will be set to the reason // been lost, either because of an error or because Close has been
// the database connection was lost. // called. The err argument will be set to the reason the database
// connection was lost.
ListenerEventDisconnected ListenerEventDisconnected
// Emitted after a database connection has been re-established after // ListenerEventReconnected is emitted after a database connection has
// connection loss. err will always be nil. After this event has been // been re-established after connection loss. The err argument of the
// emitted, a nil pq.Notification is sent on the Listener.Notify channel. // callback will always be nil. After this event has been emitted, a
// nil pq.Notification is sent on the Listener.Notify channel.
ListenerEventReconnected ListenerEventReconnected
// Emitted after a connection to the database was attempted, but failed. // ListenerEventConnectionAttemptFailed is emitted after a connection
// err will be set to an error describing why the connection attempt did // to the database was attempted, but failed. The err argument will be
// not succeed. // set to an error describing why the connection attempt did not
// succeed.
ListenerEventConnectionAttemptFailed ListenerEventConnectionAttemptFailed
) )
// EventCallbackType is the event callback type. See also ListenerEventType
// constants' documentation.
type EventCallbackType func(event ListenerEventType, err error) type EventCallbackType func(event ListenerEventType, err error)
// Listener provides an interface for listening to notifications from a // Listener provides an interface for listening to notifications from a
...@@ -454,9 +466,9 @@ func NewDialListener(d Dialer, ...@@ -454,9 +466,9 @@ func NewDialListener(d Dialer,
return l return l
} }
// Returns the notification channel for this listener. This is the same // NotificationChannel returns the notification channel for this listener.
// channel as Notify, and will not be recreated during the life time of the // This is the same channel as Notify, and will not be recreated during the
// Listener. // life time of the Listener.
func (l *Listener) NotificationChannel() <-chan *Notification { func (l *Listener) NotificationChannel() <-chan *Notification {
return l.Notify return l.Notify
} }
...@@ -639,7 +651,7 @@ func (l *Listener) resync(cn *ListenerConn, notificationChan <-chan *Notificatio ...@@ -639,7 +651,7 @@ func (l *Listener) resync(cn *ListenerConn, notificationChan <-chan *Notificatio
// close and then return the error message from the connection, as // close and then return the error message from the connection, as
// per ListenerConn's interface. // per ListenerConn's interface.
if err != nil { if err != nil {
for _ = range notificationChan { for range notificationChan {
} }
doneChan <- cn.Err() doneChan <- cn.Err()
return return
......
...@@ -461,10 +461,10 @@ ...@@ -461,10 +461,10 @@
"revisionTime": "2017-02-10T14:05:23Z" "revisionTime": "2017-02-10T14:05:23Z"
}, },
{ {
"checksumSHA1": "RYMOEINLFNWIJk8aKNifSlPhg9U=", "checksumSHA1": "3HVfwgLpCDH8JX211UWdrSi/GU4=",
"path": "github.com/lib/pq", "path": "github.com/lib/pq",
"revision": "23da1db4f16d9658a86ae9b717c245fc078f10f1", "revision": "b609790bd85edf8e9ab7e0f8912750a786177bcf",
"revisionTime": "2017-09-18T17:50:43Z" "revisionTime": "2017-10-22T19:20:43Z"
}, },
{ {
"checksumSHA1": "jaCQF1par6Jl8g+V2Cgp0n/0wSc=", "checksumSHA1": "jaCQF1par6Jl8g+V2Cgp0n/0wSc=",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment