2
0

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
This commit is contained in:
Jack Christensen
2019-01-28 22:45:44 -06:00
parent 4d2c112042
commit 6067cfab4f
3 changed files with 10 additions and 27 deletions
+2 -4
View File
@@ -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
}
+6 -21
View File
@@ -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
}
+2 -2
View File
@@ -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