From 6067cfab4f674940e745d14579632430c2c33b32 Mon Sep 17 00:00:00 2001 From: Jack Christensen Date: Mon, 28 Jan 2019 22:45:44 -0600 Subject: [PATCH] All Write errors are fatal With TLS connections a Write timeout caused by a SetDeadline permanently breaks the connection. However, the errors are reported as temporary. So there is no way to determine if it really is recoverable. As these were the only kind of Write error that was recovered all Write errors are now fatal to the connection. https://github.com/jackc/pgx/issues/494 https://github.com/jackc/pgx/issues/506 https://github.com/golang/go/issues/29971 --- batch.go | 6 ++---- conn.go | 27 ++++++--------------------- query.go | 4 ++-- 3 files changed, 10 insertions(+), 27 deletions(-) diff --git a/batch.go b/batch.go index 0d7f14cc..4b624387 100644 --- a/batch.go +++ b/batch.go @@ -133,11 +133,9 @@ func (b *Batch) Send(ctx context.Context, txOptions *TxOptions) error { b.conn.pendingReadyForQueryCount++ } - n, err := b.conn.conn.Write(buf) + _, err = b.conn.conn.Write(buf) if err != nil { - if fatalWriteErr(n, err) { - b.conn.die(err) - } + b.conn.die(err) return err } diff --git a/conn.go b/conn.go index 7b3db53d..f8016220 100644 --- a/conn.go +++ b/conn.go @@ -1096,11 +1096,9 @@ func (c *Conn) prepareEx(name, sql string, opts *PrepareExOptions) (ps *Prepared buf = appendDescribe(buf, 'S', name) buf = appendSync(buf) - n, err := c.conn.Write(buf) + _, err = c.conn.Write(buf) if err != nil { - if fatalWriteErr(n, err) { - c.die(err) - } + c.die(err) return nil, err } c.pendingReadyForQueryCount++ @@ -1360,11 +1358,9 @@ func (c *Conn) sendPreparedQuery(ps *PreparedStatement, arguments ...interface{} buf = appendExecute(buf, "", 0) buf = appendSync(buf) - n, err := c.conn.Write(buf) + _, err = c.conn.Write(buf) if err != nil { - if fatalWriteErr(n, err) { - c.die(err) - } + c.die(err) return err } c.pendingReadyForQueryCount++ @@ -1372,17 +1368,6 @@ func (c *Conn) sendPreparedQuery(ps *PreparedStatement, arguments ...interface{} return nil } -// fatalWriteError takes the response of a net.Conn.Write and determines if it is fatal -func fatalWriteErr(bytesWritten int, err error) bool { - // Partial writes break the connection - if bytesWritten > 0 { - return true - } - - netErr, is := err.(net.Error) - return !(is && netErr.Timeout()) -} - // Exec executes sql. sql can be either a prepared statement name or an SQL string. // arguments should be referenced positionally from the sql string as $1, $2, etc. func (c *Conn) Exec(sql string, arguments ...interface{}) (commandTag CommandTag, err error) { @@ -1791,8 +1776,8 @@ func (c *Conn) execEx(ctx context.Context, sql string, options *QueryExOptions, buf = appendSync(buf) c.lastStmtSent = true - n, err := c.conn.Write(buf) - if err != nil && fatalWriteErr(n, err) { + _, err = c.conn.Write(buf) + if err != nil { c.die(err) return "", err } diff --git a/query.go b/query.go index d85ee771..27969be9 100644 --- a/query.go +++ b/query.go @@ -418,8 +418,8 @@ func (c *Conn) QueryEx(ctx context.Context, sql string, options *QueryExOptions, buf = appendSync(buf) c.lastStmtSent = true - n, err := c.conn.Write(buf) - if err != nil && fatalWriteErr(n, err) { + _, err = c.conn.Write(buf) + if err != nil { rows.fatal(err) c.die(err) return rows, err