2
0

Properly abort CopyFrom on reader error

This commit is contained in:
Jack Christensen
2019-01-26 10:21:16 -06:00
parent 3683e4a0a1
commit 01b54c7cb6
+24 -21
View File
@@ -876,34 +876,37 @@ func (pgConn *PgConn) CopyFrom(ctx context.Context, r io.Reader, sql string) (Co
buf = make([]byte, 0, 65536) buf = make([]byte, 0, 65536)
buf = append(buf, 'd') buf = append(buf, 'd')
sp := len(buf) sp := len(buf)
for { var readErr error
n, err := r.Read(buf[5:cap(buf)]) for readErr == nil {
if err == io.EOF && n == 0 { n, readErr = r.Read(buf[5:cap(buf)])
break if n > 0 {
} buf = buf[0 : n+5]
buf = buf[0 : n+5] pgio.SetInt32(buf[sp:], int32(n+4))
pgio.SetInt32(buf[sp:], int32(n+4))
_, err = pgConn.conn.Write(buf) _, err = pgConn.conn.Write(buf)
if err != nil { if err != nil {
// Partially sent messages are a fatal error for the connection. If nothing was sent it might be possible to // Partially sent messages are a fatal error for the connection. If nothing was sent it might be possible to
// recover the connection with a CopyFail, but that could be rather complicated and error prone. Simpler just to // recover the connection with a CopyFail, but that could be rather complicated and error prone. Simpler just to
// close the connection. // close the connection.
pgConn.conn.Close() pgConn.conn.Close()
pgConn.closed = true pgConn.closed = true
cleanupContextDeadline() cleanupContextDeadline()
<-pgConn.controller <-pgConn.controller
return "", preferContextOverNetTimeoutError(ctx, err) return "", preferContextOverNetTimeoutError(ctx, err)
}
} }
} }
// Send copy done
buf = buf[:0] buf = buf[:0]
copyDone := &pgproto3.CopyDone{} if readErr == io.EOF {
buf = copyDone.Encode(buf) copyDone := &pgproto3.CopyDone{}
buf = copyDone.Encode(buf)
} else {
copyFail := &pgproto3.CopyFail{Error: readErr.Error()}
buf = copyFail.Encode(buf)
}
_, err = pgConn.conn.Write(buf) _, err = pgConn.conn.Write(buf)
if err != nil { if err != nil {
pgConn.conn.Close() pgConn.conn.Close()