diff --git a/go.mod b/go.mod index 7e5600ff..bc990721 100644 --- a/go.mod +++ b/go.mod @@ -4,8 +4,7 @@ go 1.13 require ( github.com/go-kit/kit v0.9.0 - github.com/jackc/pgtype v1.0.3 // indirect - github.com/jackc/pgx/v4 v4.1.2 + github.com/jackc/pgx/v4 v4.2.1 github.com/lib/pq v1.3.0 // indirect github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.3.0 diff --git a/go.sum b/go.sum index 2570b080..a9f8106c 100644 --- a/go.sum +++ b/go.sum @@ -49,8 +49,8 @@ github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgO github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA= github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE= github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s= -github.com/jackc/pgconn v1.1.0 h1:10i6DMVJOSko/sD3FLpFKBHONzDGKkX8pbLyHC8B92o= -github.com/jackc/pgconn v1.1.0/go.mod h1:GgY/Lbj1VonNaVdNUHs9AwWom3yP2eymFQ1C8z9r/Lk= +github.com/jackc/pgconn v1.2.1 h1:+73KD6pbtv6Dbs6/rqlSRUa8XffPlW6YBd1hyFLpwuA= +github.com/jackc/pgconn v1.2.1/go.mod h1:GgY/Lbj1VonNaVdNUHs9AwWom3yP2eymFQ1C8z9r/Lk= github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2 h1:JVX6jT/XfzNqIjye4717ITLaNwV9mWbJx0dLCpcRzdA= @@ -68,15 +68,13 @@ github.com/jackc/pgproto3/v2 v2.0.0/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT9 github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= -github.com/jackc/pgtype v1.0.2 h1:TVyes5WLzcWjLUQ5C7WUQOZ/+yd+v7bCfKRd7XMP6Mk= -github.com/jackc/pgtype v1.0.2/go.mod h1:5m2OfMh1wTK7x+Fk952IDmI4nw3nPrvtQdM0ZT4WpC0= -github.com/jackc/pgtype v1.0.3 h1:sFfpUKhD2njyIFVEgNaZSKwMtPxYJi2spVP9iFY8E6w= -github.com/jackc/pgtype v1.0.3/go.mod h1:5m2OfMh1wTK7x+Fk952IDmI4nw3nPrvtQdM0ZT4WpC0= +github.com/jackc/pgtype v1.1.0 h1:aZwrtaSe314VgSGmKvggULa2TavoD1jWVsxj9Zdltek= +github.com/jackc/pgtype v1.1.0/go.mod h1:5m2OfMh1wTK7x+Fk952IDmI4nw3nPrvtQdM0ZT4WpC0= github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= -github.com/jackc/pgx/v4 v4.1.2 h1:xZwqiD9cP6zF7oJ1NO2j9txtjpA7I+MdfP3h/TAT1Q8= -github.com/jackc/pgx/v4 v4.1.2/go.mod h1:0cQ5ee0A6fEsg29vZekucSFk5OcWy8sT4qkhuPXHuIE= +github.com/jackc/pgx/v4 v4.2.1 h1:ax8CUJktiYKcxp+QUVg+RzsrIEhOaUrpDhggVpTMm2g= +github.com/jackc/pgx/v4 v4.2.1/go.mod h1:dEKjU2/cUpThaZpBvDrThcA0a3uqYS9uj53jcGa5j0U= github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.0.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= diff --git a/vendor/github.com/jackc/pgconn/.gitignore b/vendor/github.com/jackc/pgconn/.gitignore index 6eb9d442..e980f555 100644 --- a/vendor/github.com/jackc/pgconn/.gitignore +++ b/vendor/github.com/jackc/pgconn/.gitignore @@ -1,2 +1,3 @@ .envrc -vendor/ \ No newline at end of file +vendor/ +.vscode diff --git a/vendor/github.com/jackc/pgconn/.travis.yml b/vendor/github.com/jackc/pgconn/.travis.yml index abff8515..87a0c058 100644 --- a/vendor/github.com/jackc/pgconn/.travis.yml +++ b/vendor/github.com/jackc/pgconn/.travis.yml @@ -24,11 +24,12 @@ env: - PGX_TEST_PLAIN_PASSWORD_CONN_STRING=postgres://pgx_pw:secret@127.0.0.1/pgx_test matrix: - CRATEVERSION=2.1 PGX_TEST_CRATEDB_CONN_STRING="host=127.0.0.1 port=6543 user=pgx dbname=pgx_test" - - PGVERSION=10 PGX_TEST_REPLICATION_CONN_STRING="host=127.0.0.1 port=6543 user=pgx_replication password=secret dbname=pgx_test" - - PGVERSION=9.6 PGX_TEST_REPLICATION_CONN_STRING="host=127.0.0.1 port=6543 user=pgx_replication password=secret dbname=pgx_test" + - PGVERSION=12 + - PGVERSION=11 + - PGVERSION=10 + - PGVERSION=9.6 - PGVERSION=9.5 - PGVERSION=9.4 - - PGVERSION=9.3 cache: directories: diff --git a/vendor/github.com/jackc/pgconn/CHANGELOG.md b/vendor/github.com/jackc/pgconn/CHANGELOG.md index 92497f47..c79d4f0b 100644 --- a/vendor/github.com/jackc/pgconn/CHANGELOG.md +++ b/vendor/github.com/jackc/pgconn/CHANGELOG.md @@ -1,7 +1,29 @@ +# 1.2.1 (January 13, 2020) + +* Fix data race in context cancellation introduced in v1.2.0. + +# 1.2.0 (January 11, 2020) + +## Features + +* Add Insert(), Update(), Delete(), and Select() statement type query methods to CommandTag. +* Add PgError.SQLState method. This could be used for compatibility with other drivers and databases. + +## Performance + +* Improve performance when context.Background() is used. (bakape) +* CommandTag.RowsAffected is faster and does not allocate. + +## Fixes + +* Try to cancel any in-progress query when a conn is closed by ctx cancel. +* Handle NoticeResponse during CopyFrom. +* Ignore errors sending Terminate message while closing connection. This mimics the behavior of libpq PGfinish. + # 1.1.0 (October 12, 2019) -* Add PgConn.IsBusy() method +* Add PgConn.IsBusy() method. # 1.0.1 (September 19, 2019) -* Fix statement cache not properly cleaning discarded statements +* Fix statement cache not properly cleaning discarded statements. diff --git a/vendor/github.com/jackc/pgconn/config.go b/vendor/github.com/jackc/pgconn/config.go index f41c38b9..628deed8 100644 --- a/vendor/github.com/jackc/pgconn/config.go +++ b/vendor/github.com/jackc/pgconn/config.go @@ -43,9 +43,8 @@ type Config struct { Fallbacks []*FallbackConfig // ValidateConnect is called during a connection attempt after a successful authentication with the PostgreSQL server. - // It can be used validate that server is acceptable. If this returns an error the connection is closed and the next - // fallback config is tried. This allows implementing high availability behavior such as libpq does with - // target_session_attrs. + // It can be used to validate that the server is acceptable. If this returns an error the connection is closed and the next + // fallback config is tried. This allows implementing high availability behavior such as libpq does with target_session_attrs. ValidateConnect ValidateConnectFunc // AfterConnect is called after ValidateConnect. It can be used to set up the connection (e.g. Set session variables diff --git a/vendor/github.com/jackc/pgconn/errors.go b/vendor/github.com/jackc/pgconn/errors.go index a088dcdd..7a21af98 100644 --- a/vendor/github.com/jackc/pgconn/errors.go +++ b/vendor/github.com/jackc/pgconn/errors.go @@ -55,6 +55,11 @@ func (pe *PgError) Error() string { return pe.Severity + ": " + pe.Message + " (SQLSTATE " + pe.Code + ")" } +// SQLState returns the SQLState of the error. +func (pe *PgError) SQLState() string { + return pe.Code +} + type connectError struct { config *Config msg string diff --git a/vendor/github.com/jackc/pgconn/pgconn.go b/vendor/github.com/jackc/pgconn/pgconn.go index e3f3aaff..89d7bb45 100644 --- a/vendor/github.com/jackc/pgconn/pgconn.go +++ b/vendor/github.com/jackc/pgconn/pgconn.go @@ -1,7 +1,6 @@ package pgconn import ( - "bytes" "context" "crypto/md5" "crypto/tls" @@ -10,7 +9,6 @@ import ( "io" "math" "net" - "strconv" "strings" "sync" "time" @@ -362,17 +360,19 @@ func (pgConn *PgConn) SendBytes(ctx context.Context, buf []byte) error { } defer pgConn.unlock() - select { - case <-ctx.Done(): - return &contextAlreadyDoneError{err: ctx.Err()} - default: + if ctx != context.Background() { + select { + case <-ctx.Done(): + return &contextAlreadyDoneError{err: ctx.Err()} + default: + } + pgConn.contextWatcher.Watch(ctx) + defer pgConn.contextWatcher.Unwatch() } - pgConn.contextWatcher.Watch(ctx) - defer pgConn.contextWatcher.Unwatch() n, err := pgConn.conn.Write(buf) if err != nil { - pgConn.hardClose() + pgConn.asyncClose() return &writeError{err: err, safeToRetry: n == 0} } @@ -392,13 +392,15 @@ func (pgConn *PgConn) ReceiveMessage(ctx context.Context) (pgproto3.BackendMessa } defer pgConn.unlock() - select { - case <-ctx.Done(): - return nil, &contextAlreadyDoneError{err: ctx.Err()} - default: + if ctx != context.Background() { + select { + case <-ctx.Done(): + return nil, &contextAlreadyDoneError{err: ctx.Err()} + default: + } + pgConn.contextWatcher.Watch(ctx) + defer pgConn.contextWatcher.Unwatch() } - pgConn.contextWatcher.Watch(ctx) - defer pgConn.contextWatcher.Unwatch() msg, err := pgConn.receiveMessage() if err != nil { @@ -429,7 +431,7 @@ func (pgConn *PgConn) receiveMessage() (pgproto3.BackendMessage, error) { if err != nil { // Close on anything other than timeout error - everything else is fatal if err, ok := err.(net.Error); !(ok && err.Timeout()) { - pgConn.hardClose() + pgConn.asyncClose() } return nil, err @@ -442,7 +444,7 @@ func (pgConn *PgConn) receiveMessage() (pgproto3.BackendMessage, error) { pgConn.parameterStatuses[msg.Name] = msg.Value case *pgproto3.ErrorResponse: if msg.Severity == "FATAL" { - pgConn.hardClose() + pgConn.asyncClose() return nil, ErrorResponseToPgError(msg) } case *pgproto3.NoticeResponse: @@ -489,30 +491,45 @@ func (pgConn *PgConn) Close(ctx context.Context) error { defer pgConn.conn.Close() - pgConn.contextWatcher.Watch(ctx) - defer pgConn.contextWatcher.Unwatch() - - _, err := pgConn.conn.Write([]byte{'X', 0, 0, 0, 4}) - if err != nil { - return err + if ctx != context.Background() { + pgConn.contextWatcher.Watch(ctx) + defer pgConn.contextWatcher.Unwatch() } - _, err = pgConn.conn.Read(make([]byte, 1)) - if err != io.EOF { - return err - } + // Ignore any errors sending Terminate message and waiting for server to close connection. + // This mimics the behavior of libpq PQfinish. It calls closePGconn which calls sendTerminateConn which purposefully + // ignores errors. + // + // See https://github.com/jackc/pgx/issues/637 + pgConn.conn.Write([]byte{'X', 0, 0, 0, 4}) + pgConn.conn.Read(make([]byte, 1)) return pgConn.conn.Close() } -// hardClose closes the underlying connection without sending the exit message. -func (pgConn *PgConn) hardClose() error { +// asyncClose marks the connection as closed and asynchronously sends a cancel query message and closes the underlying +// connection. +func (pgConn *PgConn) asyncClose() { if pgConn.status == connStatusClosed { - return nil + return } pgConn.status = connStatusClosed - return pgConn.conn.Close() + go func() { + defer pgConn.conn.Close() + + deadline := time.Now().Add(time.Second * 15) + + ctx, cancel := context.WithDeadline(context.Background(), deadline) + defer cancel() + + pgConn.CancelRequest(ctx) + + pgConn.conn.SetDeadline(deadline) + + pgConn.conn.Write([]byte{'X', 0, 0, 0, 4}) + pgConn.conn.Read(make([]byte, 1)) + }() } // IsClosed reports if the connection has been closed. @@ -561,11 +578,25 @@ type CommandTag []byte // RowsAffected returns the number of rows affected. If the CommandTag was not // for a row affecting command (e.g. "CREATE TABLE") then it returns 0. func (ct CommandTag) RowsAffected() int64 { - idx := bytes.LastIndexByte([]byte(ct), ' ') + // Find last non-digit + idx := -1 + for i := len(ct) - 1; i >= 0; i-- { + if ct[i] >= '0' && ct[i] <= '9' { + idx = i + } else { + break + } + } + if idx == -1 { return 0 } - n, _ := strconv.ParseInt(string([]byte(ct)[idx+1:]), 10, 64) + + var n int64 + for _, b := range ct[idx:] { + n = n*10 + int64(b-'0') + } + return n } @@ -573,6 +604,50 @@ func (ct CommandTag) String() string { return string(ct) } +// Insert is true if the command tag starts with "INSERT". +func (ct CommandTag) Insert() bool { + return len(ct) >= 6 && + ct[0] == 'I' && + ct[1] == 'N' && + ct[2] == 'S' && + ct[3] == 'E' && + ct[4] == 'R' && + ct[5] == 'T' +} + +// Update is true if the command tag starts with "UPDATE". +func (ct CommandTag) Update() bool { + return len(ct) >= 6 && + ct[0] == 'U' && + ct[1] == 'P' && + ct[2] == 'D' && + ct[3] == 'A' && + ct[4] == 'T' && + ct[5] == 'E' +} + +// Delete is true if the command tag starts with "DELETE". +func (ct CommandTag) Delete() bool { + return len(ct) >= 6 && + ct[0] == 'D' && + ct[1] == 'E' && + ct[2] == 'L' && + ct[3] == 'E' && + ct[4] == 'T' && + ct[5] == 'E' +} + +// Select is true if the command tag starts with "SELECT". +func (ct CommandTag) Select() bool { + return len(ct) >= 6 && + ct[0] == 'S' && + ct[1] == 'E' && + ct[2] == 'L' && + ct[3] == 'E' && + ct[4] == 'C' && + ct[5] == 'T' +} + type StatementDescription struct { Name string SQL string @@ -588,13 +663,15 @@ func (pgConn *PgConn) Prepare(ctx context.Context, name, sql string, paramOIDs [ } defer pgConn.unlock() - select { - case <-ctx.Done(): - return nil, &contextAlreadyDoneError{err: ctx.Err()} - default: + if ctx != context.Background() { + select { + case <-ctx.Done(): + return nil, &contextAlreadyDoneError{err: ctx.Err()} + default: + } + pgConn.contextWatcher.Watch(ctx) + defer pgConn.contextWatcher.Unwatch() } - pgConn.contextWatcher.Watch(ctx) - defer pgConn.contextWatcher.Unwatch() buf := pgConn.wbuf buf = (&pgproto3.Parse{Name: name, Query: sql, ParameterOIDs: paramOIDs}).Encode(buf) @@ -603,7 +680,7 @@ func (pgConn *PgConn) Prepare(ctx context.Context, name, sql string, paramOIDs [ n, err := pgConn.conn.Write(buf) if err != nil { - pgConn.hardClose() + pgConn.asyncClose() return nil, &pgconnError{msg: "write failed", err: err, safeToRetry: n == 0} } @@ -615,7 +692,7 @@ readloop: for { msg, err := pgConn.receiveMessage() if err != nil { - pgConn.hardClose() + pgConn.asyncClose() return nil, err } @@ -681,12 +758,14 @@ func (pgConn *PgConn) CancelRequest(ctx context.Context) error { } defer cancelConn.Close() - contextWatcher := ctxwatch.NewContextWatcher( - func() { cancelConn.SetDeadline(time.Date(1, 1, 1, 1, 1, 1, 1, time.UTC)) }, - func() { cancelConn.SetDeadline(time.Time{}) }, - ) - contextWatcher.Watch(ctx) - defer contextWatcher.Unwatch() + if ctx != context.Background() { + contextWatcher := ctxwatch.NewContextWatcher( + func() { cancelConn.SetDeadline(time.Date(1, 1, 1, 1, 1, 1, 1, time.UTC)) }, + func() { cancelConn.SetDeadline(time.Time{}) }, + ) + contextWatcher.Watch(ctx) + defer contextWatcher.Unwatch() + } buf := make([]byte, 16) binary.BigEndian.PutUint32(buf[0:4], 16) @@ -714,14 +793,16 @@ func (pgConn *PgConn) WaitForNotification(ctx context.Context) error { } defer pgConn.unlock() - select { - case <-ctx.Done(): - return ctx.Err() - default: - } + if ctx != context.Background() { + select { + case <-ctx.Done(): + return ctx.Err() + default: + } - pgConn.contextWatcher.Watch(ctx) - defer pgConn.contextWatcher.Unwatch() + pgConn.contextWatcher.Watch(ctx) + defer pgConn.contextWatcher.Unwatch() + } for { msg, err := pgConn.receiveMessage() @@ -754,23 +835,24 @@ func (pgConn *PgConn) Exec(ctx context.Context, sql string) *MultiResultReader { ctx: ctx, } multiResult := &pgConn.multiResultReader - - select { - case <-ctx.Done(): - multiResult.closed = true - multiResult.err = &contextAlreadyDoneError{err: ctx.Err()} - pgConn.unlock() - return multiResult - default: + if ctx != context.Background() { + select { + case <-ctx.Done(): + multiResult.closed = true + multiResult.err = &contextAlreadyDoneError{err: ctx.Err()} + pgConn.unlock() + return multiResult + default: + } + pgConn.contextWatcher.Watch(ctx) } - pgConn.contextWatcher.Watch(ctx) buf := pgConn.wbuf buf = (&pgproto3.Query{String: sql}).Encode(buf) n, err := pgConn.conn.Write(buf) if err != nil { - pgConn.hardClose() + pgConn.asyncClose() pgConn.contextWatcher.Unwatch() multiResult.closed = true multiResult.err = &writeError{err: err, safeToRetry: n == 0} @@ -810,7 +892,7 @@ func (pgConn *PgConn) ExecParams(ctx context.Context, sql string, paramValues [] buf = (&pgproto3.Parse{Query: sql, ParameterOIDs: paramOIDs}).Encode(buf) buf = (&pgproto3.Bind{ParameterFormatCodes: paramFormats, Parameters: paramValues, ResultFormatCodes: resultFormats}).Encode(buf) - pgConn.execExtendedSuffix(ctx, buf, result) + pgConn.execExtendedSuffix(buf, result) return result } @@ -836,7 +918,7 @@ func (pgConn *PgConn) ExecPrepared(ctx context.Context, stmtName string, paramVa buf := pgConn.wbuf buf = (&pgproto3.Bind{PreparedStatement: stmtName, ParameterFormatCodes: paramFormats, Parameters: paramValues, ResultFormatCodes: resultFormats}).Encode(buf) - pgConn.execExtendedSuffix(ctx, buf, result) + pgConn.execExtendedSuffix(buf, result) return result } @@ -861,27 +943,29 @@ func (pgConn *PgConn) execExtendedPrefix(ctx context.Context, paramValues [][]by return result } - select { - case <-ctx.Done(): - result.concludeCommand(nil, &contextAlreadyDoneError{err: ctx.Err()}) - result.closed = true - pgConn.unlock() - return result - default: + if ctx != context.Background() { + select { + case <-ctx.Done(): + result.concludeCommand(nil, &contextAlreadyDoneError{err: ctx.Err()}) + result.closed = true + pgConn.unlock() + return result + default: + } + pgConn.contextWatcher.Watch(ctx) } - pgConn.contextWatcher.Watch(ctx) return result } -func (pgConn *PgConn) execExtendedSuffix(ctx context.Context, buf []byte, result *ResultReader) { +func (pgConn *PgConn) execExtendedSuffix(buf []byte, result *ResultReader) { buf = (&pgproto3.Describe{ObjectType: 'P'}).Encode(buf) buf = (&pgproto3.Execute{}).Encode(buf) buf = (&pgproto3.Sync{}).Encode(buf) n, err := pgConn.conn.Write(buf) if err != nil { - pgConn.hardClose() + pgConn.asyncClose() result.concludeCommand(nil, &writeError{err: err, safeToRetry: n == 0}) pgConn.contextWatcher.Unwatch() result.closed = true @@ -895,14 +979,16 @@ func (pgConn *PgConn) CopyTo(ctx context.Context, w io.Writer, sql string) (Comm return nil, err } - select { - case <-ctx.Done(): - pgConn.unlock() - return nil, &contextAlreadyDoneError{err: ctx.Err()} - default: + if ctx != context.Background() { + select { + case <-ctx.Done(): + pgConn.unlock() + return nil, &contextAlreadyDoneError{err: ctx.Err()} + default: + } + pgConn.contextWatcher.Watch(ctx) + defer pgConn.contextWatcher.Unwatch() } - pgConn.contextWatcher.Watch(ctx) - defer pgConn.contextWatcher.Unwatch() // Send copy to command buf := pgConn.wbuf @@ -910,7 +996,7 @@ func (pgConn *PgConn) CopyTo(ctx context.Context, w io.Writer, sql string) (Comm n, err := pgConn.conn.Write(buf) if err != nil { - pgConn.hardClose() + pgConn.asyncClose() pgConn.unlock() return nil, &writeError{err: err, safeToRetry: n == 0} } @@ -921,7 +1007,7 @@ func (pgConn *PgConn) CopyTo(ctx context.Context, w io.Writer, sql string) (Comm for { msg, err := pgConn.receiveMessage() if err != nil { - pgConn.hardClose() + pgConn.asyncClose() return nil, err } @@ -930,7 +1016,7 @@ func (pgConn *PgConn) CopyTo(ctx context.Context, w io.Writer, sql string) (Comm case *pgproto3.CopyData: _, err := w.Write(msg.Data) if err != nil { - pgConn.hardClose() + pgConn.asyncClose() return nil, err } case *pgproto3.ReadyForQuery: @@ -954,13 +1040,15 @@ func (pgConn *PgConn) CopyFrom(ctx context.Context, r io.Reader, sql string) (Co } defer pgConn.unlock() - select { - case <-ctx.Done(): - return nil, &contextAlreadyDoneError{err: ctx.Err()} - default: + if ctx != context.Background() { + select { + case <-ctx.Done(): + return nil, &contextAlreadyDoneError{err: ctx.Err()} + default: + } + pgConn.contextWatcher.Watch(ctx) + defer pgConn.contextWatcher.Unwatch() } - pgConn.contextWatcher.Watch(ctx) - defer pgConn.contextWatcher.Unwatch() // Send copy to command buf := pgConn.wbuf @@ -968,7 +1056,7 @@ func (pgConn *PgConn) CopyFrom(ctx context.Context, r io.Reader, sql string) (Co n, err := pgConn.conn.Write(buf) if err != nil { - pgConn.hardClose() + pgConn.asyncClose() return nil, &writeError{err: err, safeToRetry: n == 0} } @@ -979,7 +1067,7 @@ func (pgConn *PgConn) CopyFrom(ctx context.Context, r io.Reader, sql string) (Co for pendingCopyInResponse { msg, err := pgConn.receiveMessage() if err != nil { - pgConn.hardClose() + pgConn.asyncClose() return nil, err } @@ -1008,7 +1096,7 @@ func (pgConn *PgConn) CopyFrom(ctx context.Context, r io.Reader, sql string) (Co _, err = pgConn.conn.Write(buf) if err != nil { - pgConn.hardClose() + pgConn.asyncClose() return nil, err } } @@ -1017,13 +1105,15 @@ func (pgConn *PgConn) CopyFrom(ctx context.Context, r io.Reader, sql string) (Co case <-signalMessageChan: msg, err := pgConn.receiveMessage() if err != nil { - pgConn.hardClose() + pgConn.asyncClose() return nil, err } switch msg := msg.(type) { case *pgproto3.ErrorResponse: pgErr = ErrorResponseToPgError(msg) + default: + signalMessageChan = pgConn.signalMessage() } default: } @@ -1039,7 +1129,7 @@ func (pgConn *PgConn) CopyFrom(ctx context.Context, r io.Reader, sql string) (Co } _, err = pgConn.conn.Write(buf) if err != nil { - pgConn.hardClose() + pgConn.asyncClose() return nil, err } @@ -1047,7 +1137,7 @@ func (pgConn *PgConn) CopyFrom(ctx context.Context, r io.Reader, sql string) (Co for { msg, err := pgConn.receiveMessage() if err != nil { - pgConn.hardClose() + pgConn.asyncClose() return nil, err } @@ -1092,7 +1182,7 @@ func (mrr *MultiResultReader) receiveMessage() (pgproto3.BackendMessage, error) mrr.pgConn.contextWatcher.Unwatch() mrr.err = err mrr.closed = true - mrr.pgConn.hardClose() + mrr.pgConn.asyncClose() return nil, mrr.err } @@ -1281,7 +1371,7 @@ func (rr *ResultReader) receiveMessage() (msg pgproto3.BackendMessage, err error rr.pgConn.contextWatcher.Unwatch() rr.closed = true if rr.multiResultReader == nil { - rr.pgConn.hardClose() + rr.pgConn.asyncClose() } return nil, rr.err @@ -1345,15 +1435,17 @@ func (pgConn *PgConn) ExecBatch(ctx context.Context, batch *Batch) *MultiResultR } multiResult := &pgConn.multiResultReader - select { - case <-ctx.Done(): - multiResult.closed = true - multiResult.err = &contextAlreadyDoneError{err: ctx.Err()} - pgConn.unlock() - return multiResult - default: + if ctx != context.Background() { + select { + case <-ctx.Done(): + multiResult.closed = true + multiResult.err = &contextAlreadyDoneError{err: ctx.Err()} + pgConn.unlock() + return multiResult + default: + } + pgConn.contextWatcher.Watch(ctx) } - pgConn.contextWatcher.Watch(ctx) batch.buf = (&pgproto3.Sync{}).Encode(batch.buf) diff --git a/vendor/github.com/jackc/pgtype/CHANGELOG.md b/vendor/github.com/jackc/pgtype/CHANGELOG.md index 7db5c1a2..8c76d496 100644 --- a/vendor/github.com/jackc/pgtype/CHANGELOG.md +++ b/vendor/github.com/jackc/pgtype/CHANGELOG.md @@ -1,3 +1,8 @@ +# 1.1.0 (January 11, 2020) + +* Add PostgreSQL time type support +* Add more automatic conversions of integer arrays of different types (Jean-Philippe Quéméner) + # 1.0.3 (November 16, 2019) * Support initializing Array types from a slice of the value (Alex Gaynor) diff --git a/vendor/github.com/jackc/pgtype/int2_array.go b/vendor/github.com/jackc/pgtype/int2_array.go index 27892b15..3f6bdb87 100644 --- a/vendor/github.com/jackc/pgtype/int2_array.go +++ b/vendor/github.com/jackc/pgtype/int2_array.go @@ -61,6 +61,120 @@ func (dst *Int2Array) Set(src interface{}) error { } } + case []int32: + if value == nil { + *dst = Int2Array{Status: Null} + } else if len(value) == 0 { + *dst = Int2Array{Status: Present} + } else { + elements := make([]Int2, len(value)) + for i := range value { + if err := elements[i].Set(value[i]); err != nil { + return err + } + } + *dst = Int2Array{ + Elements: elements, + Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}}, + Status: Present, + } + } + + case []uint32: + if value == nil { + *dst = Int2Array{Status: Null} + } else if len(value) == 0 { + *dst = Int2Array{Status: Present} + } else { + elements := make([]Int2, len(value)) + for i := range value { + if err := elements[i].Set(value[i]); err != nil { + return err + } + } + *dst = Int2Array{ + Elements: elements, + Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}}, + Status: Present, + } + } + + case []int64: + if value == nil { + *dst = Int2Array{Status: Null} + } else if len(value) == 0 { + *dst = Int2Array{Status: Present} + } else { + elements := make([]Int2, len(value)) + for i := range value { + if err := elements[i].Set(value[i]); err != nil { + return err + } + } + *dst = Int2Array{ + Elements: elements, + Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}}, + Status: Present, + } + } + + case []uint64: + if value == nil { + *dst = Int2Array{Status: Null} + } else if len(value) == 0 { + *dst = Int2Array{Status: Present} + } else { + elements := make([]Int2, len(value)) + for i := range value { + if err := elements[i].Set(value[i]); err != nil { + return err + } + } + *dst = Int2Array{ + Elements: elements, + Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}}, + Status: Present, + } + } + + case []int: + if value == nil { + *dst = Int2Array{Status: Null} + } else if len(value) == 0 { + *dst = Int2Array{Status: Present} + } else { + elements := make([]Int2, len(value)) + for i := range value { + if err := elements[i].Set(value[i]); err != nil { + return err + } + } + *dst = Int2Array{ + Elements: elements, + Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}}, + Status: Present, + } + } + + case []uint: + if value == nil { + *dst = Int2Array{Status: Null} + } else if len(value) == 0 { + *dst = Int2Array{Status: Present} + } else { + elements := make([]Int2, len(value)) + for i := range value { + if err := elements[i].Set(value[i]); err != nil { + return err + } + } + *dst = Int2Array{ + Elements: elements, + Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}}, + Status: Present, + } + } + case []Int2: if value == nil { *dst = Int2Array{Status: Null} @@ -117,6 +231,60 @@ func (src *Int2Array) AssignTo(dst interface{}) error { } return nil + case *[]int32: + *v = make([]int32, len(src.Elements)) + for i := range src.Elements { + if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil { + return err + } + } + return nil + + case *[]uint32: + *v = make([]uint32, len(src.Elements)) + for i := range src.Elements { + if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil { + return err + } + } + return nil + + case *[]int64: + *v = make([]int64, len(src.Elements)) + for i := range src.Elements { + if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil { + return err + } + } + return nil + + case *[]uint64: + *v = make([]uint64, len(src.Elements)) + for i := range src.Elements { + if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil { + return err + } + } + return nil + + case *[]int: + *v = make([]int, len(src.Elements)) + for i := range src.Elements { + if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil { + return err + } + } + return nil + + case *[]uint: + *v = make([]uint, len(src.Elements)) + for i := range src.Elements { + if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil { + return err + } + } + return nil + default: if nextDst, retry := GetAssignToDstType(dst); retry { return src.AssignTo(nextDst) diff --git a/vendor/github.com/jackc/pgtype/int4_array.go b/vendor/github.com/jackc/pgtype/int4_array.go index e3819562..f3e87b00 100644 --- a/vendor/github.com/jackc/pgtype/int4_array.go +++ b/vendor/github.com/jackc/pgtype/int4_array.go @@ -23,6 +23,44 @@ func (dst *Int4Array) Set(src interface{}) error { switch value := src.(type) { + case []int16: + if value == nil { + *dst = Int4Array{Status: Null} + } else if len(value) == 0 { + *dst = Int4Array{Status: Present} + } else { + elements := make([]Int4, len(value)) + for i := range value { + if err := elements[i].Set(value[i]); err != nil { + return err + } + } + *dst = Int4Array{ + Elements: elements, + Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}}, + Status: Present, + } + } + + case []uint16: + if value == nil { + *dst = Int4Array{Status: Null} + } else if len(value) == 0 { + *dst = Int4Array{Status: Present} + } else { + elements := make([]Int4, len(value)) + for i := range value { + if err := elements[i].Set(value[i]); err != nil { + return err + } + } + *dst = Int4Array{ + Elements: elements, + Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}}, + Status: Present, + } + } + case []int32: if value == nil { *dst = Int4Array{Status: Null} @@ -61,6 +99,44 @@ func (dst *Int4Array) Set(src interface{}) error { } } + case []int64: + if value == nil { + *dst = Int4Array{Status: Null} + } else if len(value) == 0 { + *dst = Int4Array{Status: Present} + } else { + elements := make([]Int4, len(value)) + for i := range value { + if err := elements[i].Set(value[i]); err != nil { + return err + } + } + *dst = Int4Array{ + Elements: elements, + Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}}, + Status: Present, + } + } + + case []uint64: + if value == nil { + *dst = Int4Array{Status: Null} + } else if len(value) == 0 { + *dst = Int4Array{Status: Present} + } else { + elements := make([]Int4, len(value)) + for i := range value { + if err := elements[i].Set(value[i]); err != nil { + return err + } + } + *dst = Int4Array{ + Elements: elements, + Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}}, + Status: Present, + } + } + case []int: if value == nil { *dst = Int4Array{Status: Null} @@ -80,6 +156,25 @@ func (dst *Int4Array) Set(src interface{}) error { } } + case []uint: + if value == nil { + *dst = Int4Array{Status: Null} + } else if len(value) == 0 { + *dst = Int4Array{Status: Present} + } else { + elements := make([]Int4, len(value)) + for i := range value { + if err := elements[i].Set(value[i]); err != nil { + return err + } + } + *dst = Int4Array{ + Elements: elements, + Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}}, + Status: Present, + } + } + case []Int4: if value == nil { *dst = Int4Array{Status: Null} @@ -118,6 +213,24 @@ func (src *Int4Array) AssignTo(dst interface{}) error { case Present: switch v := dst.(type) { + case *[]int16: + *v = make([]int16, len(src.Elements)) + for i := range src.Elements { + if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil { + return err + } + } + return nil + + case *[]uint16: + *v = make([]uint16, len(src.Elements)) + for i := range src.Elements { + if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil { + return err + } + } + return nil + case *[]int32: *v = make([]int32, len(src.Elements)) for i := range src.Elements { @@ -136,6 +249,24 @@ func (src *Int4Array) AssignTo(dst interface{}) error { } return nil + case *[]int64: + *v = make([]int64, len(src.Elements)) + for i := range src.Elements { + if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil { + return err + } + } + return nil + + case *[]uint64: + *v = make([]uint64, len(src.Elements)) + for i := range src.Elements { + if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil { + return err + } + } + return nil + case *[]int: *v = make([]int, len(src.Elements)) for i := range src.Elements { @@ -145,6 +276,15 @@ func (src *Int4Array) AssignTo(dst interface{}) error { } return nil + case *[]uint: + *v = make([]uint, len(src.Elements)) + for i := range src.Elements { + if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil { + return err + } + } + return nil + default: if nextDst, retry := GetAssignToDstType(dst); retry { return src.AssignTo(nextDst) diff --git a/vendor/github.com/jackc/pgtype/int8_array.go b/vendor/github.com/jackc/pgtype/int8_array.go index a31a474a..a6798173 100644 --- a/vendor/github.com/jackc/pgtype/int8_array.go +++ b/vendor/github.com/jackc/pgtype/int8_array.go @@ -23,6 +23,82 @@ func (dst *Int8Array) Set(src interface{}) error { switch value := src.(type) { + case []int16: + if value == nil { + *dst = Int8Array{Status: Null} + } else if len(value) == 0 { + *dst = Int8Array{Status: Present} + } else { + elements := make([]Int8, len(value)) + for i := range value { + if err := elements[i].Set(value[i]); err != nil { + return err + } + } + *dst = Int8Array{ + Elements: elements, + Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}}, + Status: Present, + } + } + + case []uint16: + if value == nil { + *dst = Int8Array{Status: Null} + } else if len(value) == 0 { + *dst = Int8Array{Status: Present} + } else { + elements := make([]Int8, len(value)) + for i := range value { + if err := elements[i].Set(value[i]); err != nil { + return err + } + } + *dst = Int8Array{ + Elements: elements, + Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}}, + Status: Present, + } + } + + case []int32: + if value == nil { + *dst = Int8Array{Status: Null} + } else if len(value) == 0 { + *dst = Int8Array{Status: Present} + } else { + elements := make([]Int8, len(value)) + for i := range value { + if err := elements[i].Set(value[i]); err != nil { + return err + } + } + *dst = Int8Array{ + Elements: elements, + Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}}, + Status: Present, + } + } + + case []uint32: + if value == nil { + *dst = Int8Array{Status: Null} + } else if len(value) == 0 { + *dst = Int8Array{Status: Present} + } else { + elements := make([]Int8, len(value)) + for i := range value { + if err := elements[i].Set(value[i]); err != nil { + return err + } + } + *dst = Int8Array{ + Elements: elements, + Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}}, + Status: Present, + } + } + case []int64: if value == nil { *dst = Int8Array{Status: Null} @@ -61,6 +137,44 @@ func (dst *Int8Array) Set(src interface{}) error { } } + case []int: + if value == nil { + *dst = Int8Array{Status: Null} + } else if len(value) == 0 { + *dst = Int8Array{Status: Present} + } else { + elements := make([]Int8, len(value)) + for i := range value { + if err := elements[i].Set(value[i]); err != nil { + return err + } + } + *dst = Int8Array{ + Elements: elements, + Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}}, + Status: Present, + } + } + + case []uint: + if value == nil { + *dst = Int8Array{Status: Null} + } else if len(value) == 0 { + *dst = Int8Array{Status: Present} + } else { + elements := make([]Int8, len(value)) + for i := range value { + if err := elements[i].Set(value[i]); err != nil { + return err + } + } + *dst = Int8Array{ + Elements: elements, + Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}}, + Status: Present, + } + } + case []Int8: if value == nil { *dst = Int8Array{Status: Null} @@ -99,6 +213,42 @@ func (src *Int8Array) AssignTo(dst interface{}) error { case Present: switch v := dst.(type) { + case *[]int16: + *v = make([]int16, len(src.Elements)) + for i := range src.Elements { + if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil { + return err + } + } + return nil + + case *[]uint16: + *v = make([]uint16, len(src.Elements)) + for i := range src.Elements { + if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil { + return err + } + } + return nil + + case *[]int32: + *v = make([]int32, len(src.Elements)) + for i := range src.Elements { + if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil { + return err + } + } + return nil + + case *[]uint32: + *v = make([]uint32, len(src.Elements)) + for i := range src.Elements { + if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil { + return err + } + } + return nil + case *[]int64: *v = make([]int64, len(src.Elements)) for i := range src.Elements { @@ -117,6 +267,24 @@ func (src *Int8Array) AssignTo(dst interface{}) error { } return nil + case *[]int: + *v = make([]int, len(src.Elements)) + for i := range src.Elements { + if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil { + return err + } + } + return nil + + case *[]uint: + *v = make([]uint, len(src.Elements)) + for i := range src.Elements { + if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil { + return err + } + } + return nil + default: if nextDst, retry := GetAssignToDstType(dst); retry { return src.AssignTo(nextDst) diff --git a/vendor/github.com/jackc/pgtype/pgtype.go b/vendor/github.com/jackc/pgtype/pgtype.go index 058aa5c6..1109d0d8 100644 --- a/vendor/github.com/jackc/pgtype/pgtype.go +++ b/vendor/github.com/jackc/pgtype/pgtype.go @@ -52,6 +52,7 @@ const ( BPCharOID = 1042 VarcharOID = 1043 DateOID = 1082 + TimeOID = 1083 TimestampOID = 1114 TimestampArrayOID = 1115 DateArrayOID = 1182 @@ -237,6 +238,7 @@ func NewConnInfo() *ConnInfo { ci.RegisterDataType(DataType{Value: &Record{}, Name: "record", OID: RecordOID}) ci.RegisterDataType(DataType{Value: &Text{}, Name: "text", OID: TextOID}) ci.RegisterDataType(DataType{Value: &TID{}, Name: "tid", OID: TIDOID}) + ci.RegisterDataType(DataType{Value: &Time{}, Name: "time", OID: TimeOID}) ci.RegisterDataType(DataType{Value: &Timestamp{}, Name: "timestamp", OID: TimestampOID}) ci.RegisterDataType(DataType{Value: &Timestamptz{}, Name: "timestamptz", OID: TimestamptzOID}) ci.RegisterDataType(DataType{Value: &Tsrange{}, Name: "tsrange", OID: TsrangeOID}) diff --git a/vendor/github.com/jackc/pgtype/time.go b/vendor/github.com/jackc/pgtype/time.go new file mode 100644 index 00000000..3bf91b10 --- /dev/null +++ b/vendor/github.com/jackc/pgtype/time.go @@ -0,0 +1,219 @@ +package pgtype + +import ( + "database/sql/driver" + "encoding/binary" + "fmt" + "strconv" + "time" + + "github.com/jackc/pgio" + errors "golang.org/x/xerrors" +) + +// Time represents the PostgreSQL time type. The PostgreSQL time is a time of day without time zone. +// +// Time is represented as the number of microseconds since midnight in the same way that PostgreSQL does. Other time +// and date types in pgtype can use time.Time as the underlying representation. However, pgtype.Time type cannot due +// to needing to handle 24:00:00. time.Time converts that to 00:00:00 on the following day. +type Time struct { + Microseconds int64 // Number of microseconds since midnight + Status Status +} + +// Set converts src into a Time and stores in dst. +func (dst *Time) Set(src interface{}) error { + if src == nil { + *dst = Time{Status: Null} + return nil + } + + switch value := src.(type) { + case time.Time: + usec := int64(value.Hour())*microsecondsPerHour + + int64(value.Minute())*microsecondsPerMinute + + int64(value.Second())*microsecondsPerSecond + + int64(value.Nanosecond())/1000 + *dst = Time{Microseconds: usec, Status: Present} + default: + if originalSrc, ok := underlyingTimeType(src); ok { + return dst.Set(originalSrc) + } + return errors.Errorf("cannot convert %v to Time", value) + } + + return nil +} + +func (dst *Time) Get() interface{} { + switch dst.Status { + case Present: + return dst.Microseconds + case Null: + return nil + default: + return dst.Status + } +} + +func (src *Time) AssignTo(dst interface{}) error { + switch src.Status { + case Present: + switch v := dst.(type) { + case *time.Time: + // 24:00:00 is max allowed time in PostgreSQL, but time.Time will normalize that to 00:00:00 the next day. + var maxRepresentableByTime int64 = 24*60*60*1000000 - 1 + if src.Microseconds > maxRepresentableByTime { + return errors.Errorf("%d microseconds cannot be represented as time.Time", src.Microseconds) + } + + usec := src.Microseconds + hours := usec / microsecondsPerHour + usec -= hours * microsecondsPerHour + minutes := usec / microsecondsPerMinute + usec -= minutes * microsecondsPerMinute + seconds := usec / microsecondsPerSecond + usec -= seconds * microsecondsPerSecond + ns := usec * 1000 + *v = time.Date(2000, 1, 1, int(hours), int(minutes), int(seconds), int(ns), time.UTC) + return nil + default: + if nextDst, retry := GetAssignToDstType(dst); retry { + return src.AssignTo(nextDst) + } + return errors.Errorf("unable to assign to %T", dst) + } + case Null: + return NullAssignTo(dst) + } + + return errors.Errorf("cannot decode %#v into %T", src, dst) +} + +// DecodeText decodes from src into dst. +func (dst *Time) DecodeText(ci *ConnInfo, src []byte) error { + if src == nil { + *dst = Time{Status: Null} + return nil + } + + s := string(src) + + if len(s) < 8 { + return errors.Errorf("cannot decode %v into Time", s) + } + + hours, err := strconv.ParseInt(s[0:2], 10, 64) + if err != nil { + return errors.Errorf("cannot decode %v into Time", s) + } + usec := hours * microsecondsPerHour + + minutes, err := strconv.ParseInt(s[3:5], 10, 64) + if err != nil { + return errors.Errorf("cannot decode %v into Time", s) + } + usec += minutes * microsecondsPerMinute + + seconds, err := strconv.ParseInt(s[6:8], 10, 64) + if err != nil { + return errors.Errorf("cannot decode %v into Time", s) + } + usec += seconds * microsecondsPerSecond + + if len(s) > 9 { + fraction := s[9:] + n, err := strconv.ParseInt(fraction, 10, 64) + if err != nil { + return errors.Errorf("cannot decode %v into Time", s) + } + + for i := len(fraction); i < 6; i++ { + n *= 10 + } + + usec += n + } + + *dst = Time{Microseconds: usec, Status: Present} + + return nil +} + +// DecodeBinary decodes from src into dst. +func (dst *Time) DecodeBinary(ci *ConnInfo, src []byte) error { + if src == nil { + *dst = Time{Status: Null} + return nil + } + + if len(src) != 8 { + return errors.Errorf("invalid length for time: %v", len(src)) + } + + usec := int64(binary.BigEndian.Uint64(src)) + *dst = Time{Microseconds: usec, Status: Present} + + return nil +} + +// EncodeText writes the text encoding of src into w. +func (src Time) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) { + switch src.Status { + case Null: + return nil, nil + case Undefined: + return nil, errUndefined + } + + usec := src.Microseconds + hours := usec / microsecondsPerHour + usec -= hours * microsecondsPerHour + minutes := usec / microsecondsPerMinute + usec -= minutes * microsecondsPerMinute + seconds := usec / microsecondsPerSecond + usec -= seconds * microsecondsPerSecond + + s := fmt.Sprintf("%02d:%02d:%02d.%06d", hours, minutes, seconds, usec) + + return append(buf, s...), nil +} + +// EncodeBinary writes the binary encoding of src into w. If src.Time is not in +// the UTC time zone it returns an error. +func (src Time) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) { + switch src.Status { + case Null: + return nil, nil + case Undefined: + return nil, errUndefined + } + + return pgio.AppendInt64(buf, src.Microseconds), nil +} + +// Scan implements the database/sql Scanner interface. +func (dst *Time) Scan(src interface{}) error { + if src == nil { + *dst = Time{Status: Null} + return nil + } + + switch src := src.(type) { + case string: + return dst.DecodeText(nil, []byte(src)) + case []byte: + srcCopy := make([]byte, len(src)) + copy(srcCopy, src) + return dst.DecodeText(nil, srcCopy) + case time.Time: + return dst.Set(src) + } + + return errors.Errorf("cannot scan %T", src) +} + +// Value implements the database/sql/driver Valuer interface. +func (src Time) Value() (driver.Value, error) { + return EncodeValueText(src) +} diff --git a/vendor/github.com/jackc/pgtype/typed_array_gen.sh b/vendor/github.com/jackc/pgtype/typed_array_gen.sh index 6eca219d..6fd49264 100644 --- a/vendor/github.com/jackc/pgtype/typed_array_gen.sh +++ b/vendor/github.com/jackc/pgtype/typed_array_gen.sh @@ -1,6 +1,6 @@ -erb pgtype_array_type=Int2Array pgtype_element_type=Int2 go_array_types=[]int16,[]uint16 element_type_name=int2 text_null=NULL binary_format=true typed_array.go.erb > int2_array.go -erb pgtype_array_type=Int4Array pgtype_element_type=Int4 go_array_types=[]int32,[]uint32,[]int element_type_name=int4 text_null=NULL binary_format=true typed_array.go.erb > int4_array.go -erb pgtype_array_type=Int8Array pgtype_element_type=Int8 go_array_types=[]int64,[]uint64 element_type_name=int8 text_null=NULL binary_format=true typed_array.go.erb > int8_array.go +erb pgtype_array_type=Int2Array pgtype_element_type=Int2 go_array_types=[]int16,[]uint16,[]int32,[]uint32,[]int64,[]uint64,[]int,[]uint element_type_name=int2 text_null=NULL binary_format=true typed_array.go.erb > int2_array.go +erb pgtype_array_type=Int4Array pgtype_element_type=Int4 go_array_types=[]int16,[]uint16,[]int32,[]uint32,[]int64,[]uint64,[]int,[]uint element_type_name=int4 text_null=NULL binary_format=true typed_array.go.erb > int4_array.go +erb pgtype_array_type=Int8Array pgtype_element_type=Int8 go_array_types=[]int16,[]uint16,[]int32,[]uint32,[]int64,[]uint64,[]int,[]uint element_type_name=int8 text_null=NULL binary_format=true typed_array.go.erb > int8_array.go erb pgtype_array_type=BoolArray pgtype_element_type=Bool go_array_types=[]bool element_type_name=bool text_null=NULL binary_format=true typed_array.go.erb > bool_array.go erb pgtype_array_type=DateArray pgtype_element_type=Date go_array_types=[]time.Time element_type_name=date text_null=NULL binary_format=true typed_array.go.erb > date_array.go erb pgtype_array_type=TimestamptzArray pgtype_element_type=Timestamptz go_array_types=[]time.Time element_type_name=timestamptz text_null=NULL binary_format=true typed_array.go.erb > timestamptz_array.go diff --git a/vendor/github.com/jackc/pgx/v4/.travis.yml b/vendor/github.com/jackc/pgx/v4/.travis.yml index 01b3febf..1bc5a8ae 100644 --- a/vendor/github.com/jackc/pgx/v4/.travis.yml +++ b/vendor/github.com/jackc/pgx/v4/.travis.yml @@ -15,6 +15,7 @@ env: matrix: - CRATEVERSION=2.1 PGX_TEST_CRATEDB_CONN_STRING="host=127.0.0.1 port=6543 user=pgx database=pgx_test" + - PGVERSION=12 - PGVERSION=11 - PGVERSION=10 - PGVERSION=9.6 diff --git a/vendor/github.com/jackc/pgx/v4/CHANGELOG.md b/vendor/github.com/jackc/pgx/v4/CHANGELOG.md index f7601464..2a2baf90 100644 --- a/vendor/github.com/jackc/pgx/v4/CHANGELOG.md +++ b/vendor/github.com/jackc/pgx/v4/CHANGELOG.md @@ -1,3 +1,16 @@ +# 4.2.1 (January 13, 2020) + +* Update pgconn to v1.2.1 (fixes context cancellation data race introduced in v1.2.0)) + +# 4.2.0 (January 11, 2020) + +* Update pgconn to v1.2.0. +* Update pgtype to v1.1.0. +* Return error instead of panic when wrong number of arguments passed to Exec. (malstoun) +* Fix large objects functionality when PreferSimpleProtocol = true. +* Restore GetDefaultDriver which existed in v3. (Johan Brandhorst) +* Add RegisterConnConfig to stdlib which replaces the removed RegisterDriverConfig from v3. + # 4.1.2 (October 22, 2019) * Fix dbSavepoint.Begin recursive self call diff --git a/vendor/github.com/jackc/pgx/v4/conn.go b/vendor/github.com/jackc/pgx/v4/conn.go index 58195f1f..014e1e2d 100644 --- a/vendor/github.com/jackc/pgx/v4/conn.go +++ b/vendor/github.com/jackc/pgx/v4/conn.go @@ -501,6 +501,10 @@ func (c *Conn) execSimpleProtocol(ctx context.Context, sql string, arguments []i } func (c *Conn) execParamsAndPreparedPrefix(sd *pgconn.StatementDescription, arguments []interface{}) error { + if len(sd.ParamOIDs) != len(arguments) { + return errors.Errorf("expected %d arguments, got %d", len(sd.ParamOIDs), len(arguments)) + } + c.eqb.Reset() args, err := convertDriverValuers(arguments) diff --git a/vendor/github.com/jackc/pgx/v4/go.mod b/vendor/github.com/jackc/pgx/v4/go.mod index 52589f51..e1d69900 100644 --- a/vendor/github.com/jackc/pgx/v4/go.mod +++ b/vendor/github.com/jackc/pgx/v4/go.mod @@ -5,10 +5,10 @@ go 1.12 require ( github.com/cockroachdb/apd v1.1.0 github.com/gofrs/uuid v3.2.0+incompatible - github.com/jackc/pgconn v1.1.0 + github.com/jackc/pgconn v1.2.1 github.com/jackc/pgio v1.0.0 github.com/jackc/pgproto3/v2 v2.0.0 - github.com/jackc/pgtype v1.0.2 + github.com/jackc/pgtype v1.1.0 github.com/jackc/puddle v1.0.0 github.com/mattn/go-colorable v0.1.2 // indirect github.com/mattn/go-isatty v0.0.9 // indirect diff --git a/vendor/github.com/jackc/pgx/v4/go.sum b/vendor/github.com/jackc/pgx/v4/go.sum index 78e05b0f..573e07d8 100644 --- a/vendor/github.com/jackc/pgx/v4/go.sum +++ b/vendor/github.com/jackc/pgx/v4/go.sum @@ -30,6 +30,10 @@ github.com/jackc/pgconn v1.0.1 h1:ZANo4pIkeHKIVD1cQMcxu8fwrwIICLblzi9HCjooZeQ= github.com/jackc/pgconn v1.0.1/go.mod h1:GgY/Lbj1VonNaVdNUHs9AwWom3yP2eymFQ1C8z9r/Lk= github.com/jackc/pgconn v1.1.0 h1:10i6DMVJOSko/sD3FLpFKBHONzDGKkX8pbLyHC8B92o= github.com/jackc/pgconn v1.1.0/go.mod h1:GgY/Lbj1VonNaVdNUHs9AwWom3yP2eymFQ1C8z9r/Lk= +github.com/jackc/pgconn v1.2.0 h1:6Q01OMLPPkmcCZVB9oRT6ACgo6nTEaNFQ97O79A8NuA= +github.com/jackc/pgconn v1.2.0/go.mod h1:GgY/Lbj1VonNaVdNUHs9AwWom3yP2eymFQ1C8z9r/Lk= +github.com/jackc/pgconn v1.2.1 h1:+73KD6pbtv6Dbs6/rqlSRUa8XffPlW6YBd1hyFLpwuA= +github.com/jackc/pgconn v1.2.1/go.mod h1:GgY/Lbj1VonNaVdNUHs9AwWom3yP2eymFQ1C8z9r/Lk= github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= @@ -60,6 +64,10 @@ github.com/jackc/pgtype v1.0.1 h1:7GWB9n3DdnO3TIbj59wMAE9QcHPL4cy/Bbtk5P1Noow= github.com/jackc/pgtype v1.0.1/go.mod h1:5m2OfMh1wTK7x+Fk952IDmI4nw3nPrvtQdM0ZT4WpC0= github.com/jackc/pgtype v1.0.2 h1:TVyes5WLzcWjLUQ5C7WUQOZ/+yd+v7bCfKRd7XMP6Mk= github.com/jackc/pgtype v1.0.2/go.mod h1:5m2OfMh1wTK7x+Fk952IDmI4nw3nPrvtQdM0ZT4WpC0= +github.com/jackc/pgtype v1.0.3 h1:sFfpUKhD2njyIFVEgNaZSKwMtPxYJi2spVP9iFY8E6w= +github.com/jackc/pgtype v1.0.3/go.mod h1:5m2OfMh1wTK7x+Fk952IDmI4nw3nPrvtQdM0ZT4WpC0= +github.com/jackc/pgtype v1.1.0 h1:aZwrtaSe314VgSGmKvggULa2TavoD1jWVsxj9Zdltek= +github.com/jackc/pgtype v1.1.0/go.mod h1:5m2OfMh1wTK7x+Fk952IDmI4nw3nPrvtQdM0ZT4WpC0= github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= diff --git a/vendor/github.com/jackc/pgx/v4/large_objects.go b/vendor/github.com/jackc/pgx/v4/large_objects.go index 768c782c..4fed7901 100644 --- a/vendor/github.com/jackc/pgx/v4/large_objects.go +++ b/vendor/github.com/jackc/pgx/v4/large_objects.go @@ -24,25 +24,15 @@ const ( // Create creates a new large object. If oid is zero, the server assigns an unused OID. func (o *LargeObjects) Create(ctx context.Context, oid uint32) (uint32, error) { - _, err := o.tx.Prepare(ctx, "lo_create", "select lo_create($1)") - if err != nil { - return 0, err - } - - err = o.tx.QueryRow(ctx, "lo_create", oid).Scan(&oid) + err := o.tx.QueryRow(ctx, "select lo_create($1)", oid).Scan(&oid) return oid, err } // Open opens an existing large object with the given mode. ctx will also be used for all operations on the opened large // object. func (o *LargeObjects) Open(ctx context.Context, oid uint32, mode LargeObjectMode) (*LargeObject, error) { - _, err := o.tx.Prepare(ctx, "lo_open", "select lo_open($1, $2)") - if err != nil { - return nil, err - } - var fd int32 - err = o.tx.QueryRow(ctx, "lo_open", oid, mode).Scan(&fd) + err := o.tx.QueryRow(ctx, "select lo_open($1, $2)", oid, mode).Scan(&fd) if err != nil { return nil, err } @@ -51,13 +41,8 @@ func (o *LargeObjects) Open(ctx context.Context, oid uint32, mode LargeObjectMod // Unlink removes a large object from the database. func (o *LargeObjects) Unlink(ctx context.Context, oid uint32) error { - _, err := o.tx.Prepare(ctx, "lo_unlink", "select lo_unlink($1)") - if err != nil { - return err - } - var result int32 - err = o.tx.QueryRow(ctx, "lo_unlink", oid).Scan(&result) + err := o.tx.QueryRow(ctx, "select lo_unlink($1)", oid).Scan(&result) if err != nil { return err } @@ -84,13 +69,8 @@ type LargeObject struct { // Write writes p to the large object and returns the number of bytes written and an error if not all of p was written. func (o *LargeObject) Write(p []byte) (int, error) { - _, err := o.tx.Prepare(o.ctx, "lowrite", "select lowrite($1, $2)") - if err != nil { - return 0, err - } - var n int - err = o.tx.QueryRow(o.ctx, "lowrite", o.fd, p).Scan(&n) + err := o.tx.QueryRow(o.ctx, "select lowrite($1, $2)", o.fd, p).Scan(&n) if err != nil { return n, err } @@ -104,13 +84,8 @@ func (o *LargeObject) Write(p []byte) (int, error) { // Read reads up to len(p) bytes into p returning the number of bytes read. func (o *LargeObject) Read(p []byte) (int, error) { - _, err := o.tx.Prepare(o.ctx, "loread", "select loread($1, $2)") - if err != nil { - return 0, err - } - var res []byte - err = o.tx.QueryRow(o.ctx, "loread", o.fd, len(p)).Scan(&res) + err := o.tx.QueryRow(o.ctx, "select loread($1, $2)", o.fd, len(p)).Scan(&res) copy(p, res) if err != nil { return len(res), err @@ -124,44 +99,24 @@ func (o *LargeObject) Read(p []byte) (int, error) { // Seek moves the current location pointer to the new location specified by offset. func (o *LargeObject) Seek(offset int64, whence int) (n int64, err error) { - _, err = o.tx.Prepare(o.ctx, "lo_lseek64", "select lo_lseek64($1, $2, $3)") - if err != nil { - return 0, err - } - - err = o.tx.QueryRow(o.ctx, "lo_lseek64", o.fd, offset, whence).Scan(&n) + err = o.tx.QueryRow(o.ctx, "select lo_lseek64($1, $2, $3)", o.fd, offset, whence).Scan(&n) return n, err } // Tell returns the current read or write location of the large object descriptor. func (o *LargeObject) Tell() (n int64, err error) { - _, err = o.tx.Prepare(o.ctx, "lo_tell64", "select lo_tell64($1)") - if err != nil { - return 0, err - } - - err = o.tx.QueryRow(o.ctx, "lo_tell64", o.fd).Scan(&n) + err = o.tx.QueryRow(o.ctx, "select lo_tell64($1)", o.fd).Scan(&n) return n, err } // Trunctes the large object to size. func (o *LargeObject) Truncate(size int64) (err error) { - _, err = o.tx.Prepare(o.ctx, "lo_truncate64", "select lo_truncate64($1, $2)") - if err != nil { - return err - } - - _, err = o.tx.Exec(o.ctx, "lo_truncate64", o.fd, size) + _, err = o.tx.Exec(o.ctx, "select lo_truncate64($1, $2)", o.fd, size) return err } // Close closees the large object descriptor. func (o *LargeObject) Close() error { - _, err := o.tx.Prepare(o.ctx, "lo_close", "select lo_close($1)") - if err != nil { - return err - } - - _, err = o.tx.Exec(o.ctx, "lo_close", o.fd) + _, err := o.tx.Exec(o.ctx, "select lo_close($1)", o.fd) return err } diff --git a/vendor/modules.txt b/vendor/modules.txt index be808a51..db95f8bb 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -20,7 +20,7 @@ github.com/golang/protobuf/ptypes/duration github.com/golang/protobuf/ptypes/timestamp # github.com/jackc/chunkreader/v2 v2.0.0 github.com/jackc/chunkreader/v2 -# github.com/jackc/pgconn v1.1.0 +# github.com/jackc/pgconn v1.2.1 github.com/jackc/pgconn github.com/jackc/pgconn/internal/ctxwatch github.com/jackc/pgconn/stmtcache @@ -30,9 +30,9 @@ github.com/jackc/pgio github.com/jackc/pgpassfile # github.com/jackc/pgproto3/v2 v2.0.0 github.com/jackc/pgproto3/v2 -# github.com/jackc/pgtype v1.0.3 +# github.com/jackc/pgtype v1.1.0 github.com/jackc/pgtype -# github.com/jackc/pgx/v4 v4.1.2 +# github.com/jackc/pgx/v4 v4.2.1 github.com/jackc/pgx/v4 github.com/jackc/pgx/v4/internal/sanitize # github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515