@@ -159,6 +159,12 @@ type conn struct {
159159 // round-trip mode for non-prepared Query calls.
160160 binaryParameters bool
161161
162+ // Timeouts for read and write operations against the database server.
163+ // A duration of 0 indicates no timeout.
164+ // specified in milliseconds
165+ readTimeout time.Duration
166+ writeTimeout time.Duration
167+
162168 // If true this connection is in the middle of a COPY
163169 inCopy bool
164170
@@ -220,7 +226,28 @@ func (cn *conn) handleDriverSettings(o values) (err error) {
220226 }
221227 return nil
222228 }
229+ timeSetting := func (key string , val * time.Duration ) error {
230+ if value := o [key ]; value != "" {
231+ timeout , err := strconv .Atoi (value )
232+ if err != nil {
233+ return err
234+ }
235+ // timeout is specified in milliseconds.
236+ * val = time .Duration (timeout ) * time .Millisecond
237+ } else {
238+ * val = time .Duration (0 ) * time .Millisecond
239+ }
240+ return nil
241+ }
223242
243+ err = timeSetting ("read_timeout" , & cn .readTimeout )
244+ if err != nil {
245+ return err
246+ }
247+ err = timeSetting ("write_timeout" , & cn .writeTimeout )
248+ if err != nil {
249+ return err
250+ }
224251 err = boolSetting ("disable_prepared_binary_result" , & cn .disablePreparedBinaryResult )
225252 if err != nil {
226253 return err
@@ -965,7 +992,37 @@ func (se *safeRetryError) Error() string {
965992 return se .Err .Error ()
966993}
967994
995+ // Set the write deadline if we have a write timeout set.
996+ func (cn * conn ) setWriteTimeout () {
997+ if cn .writeTimeout != 0 {
998+ cn .c .SetWriteDeadline (time .Now ().Add (cn .writeTimeout ))
999+ }
1000+ }
1001+
1002+ // Clear the write deadline if we set one.
1003+ func (cn * conn ) cleanWriteTimeout () {
1004+ if cn .writeTimeout != 0 {
1005+ cn .c .SetWriteDeadline (time.Time {})
1006+ }
1007+ }
1008+
1009+ // Set the read deadline if we have a read timeout set.
1010+ func (cn * conn ) setReadTimeout () {
1011+ if cn .readTimeout != 0 {
1012+ cn .c .SetReadDeadline (time .Now ().Add (cn .readTimeout ))
1013+ }
1014+ }
1015+
1016+ // Clear the read deadline if we set one.
1017+ func (cn * conn ) cleanReadTimeout () {
1018+ if cn .readTimeout != 0 {
1019+ cn .c .SetReadDeadline (time.Time {})
1020+ }
1021+ }
1022+
9681023func (cn * conn ) send (m * writeBuf ) {
1024+ cn .setWriteTimeout ()
1025+ defer cn .cleanWriteTimeout ()
9691026 n , err := cn .c .Write (m .wrap ())
9701027 if err != nil {
9711028 if n == 0 {
@@ -976,6 +1033,8 @@ func (cn *conn) send(m *writeBuf) {
9761033}
9771034
9781035func (cn * conn ) sendStartupPacket (m * writeBuf ) error {
1036+ cn .setWriteTimeout ()
1037+ defer cn .cleanWriteTimeout ()
9791038 _ , err := cn .c .Write ((m .wrap ())[1 :])
9801039 return err
9811040}
@@ -984,6 +1043,8 @@ func (cn *conn) sendStartupPacket(m *writeBuf) error {
9841043// message should have no payload. This method does not use the scratch
9851044// buffer.
9861045func (cn * conn ) sendSimpleMessage (typ byte ) (err error ) {
1046+ cn .setWriteTimeout ()
1047+ defer cn .cleanWriteTimeout ()
9871048 _ , err = cn .c .Write ([]byte {typ , '\x00' , '\x00' , '\x00' , '\x04' })
9881049 return err
9891050}
@@ -1014,6 +1075,9 @@ func (cn *conn) recvMessage(r *readBuf) (byte, error) {
10141075 return t , nil
10151076 }
10161077
1078+ cn .setReadTimeout ()
1079+ defer cn .cleanReadTimeout ()
1080+
10171081 x := cn .scratch [:5 ]
10181082 _ , err := io .ReadFull (cn .buf , x )
10191083 if err != nil {
@@ -1151,6 +1215,10 @@ func isDriverSetting(key string) bool {
11511215 return true
11521216 case "binary_parameters" :
11531217 return true
1218+ case "read_timeout" :
1219+ return true
1220+ case "write_timeout" :
1221+ return true
11541222 case "krbsrvname" :
11551223 return true
11561224 case "krbspn" :
0 commit comments