@@ -153,6 +153,12 @@ type conn struct {
153153 // round-trip mode for non-prepared Query calls.
154154 binaryParameters bool
155155
156+ // Timeouts for read and write operations against the database server.
157+ // A duration of 0 indicates no timeout.
158+ // specified in milliseconds
159+ readTimeout time.Duration
160+ writeTimeout time.Duration
161+
156162 // If true this connection is in the middle of a COPY
157163 inCopy bool
158164
@@ -180,7 +186,28 @@ func (cn *conn) handleDriverSettings(o values) (err error) {
180186 }
181187 return nil
182188 }
189+ timeSetting := func (key string , val * time.Duration ) error {
190+ if value := o [key ]; value != "" {
191+ timeout , err := strconv .Atoi (value )
192+ if err != nil {
193+ return err
194+ }
195+ // timeout is specified in milliseconds.
196+ * val = time .Duration (timeout ) * time .Millisecond
197+ } else {
198+ * val = time .Duration (0 ) * time .Millisecond
199+ }
200+ return nil
201+ }
183202
203+ err = timeSetting ("read_timeout" , & cn .readTimeout )
204+ if err != nil {
205+ return err
206+ }
207+ err = timeSetting ("write_timeout" , & cn .writeTimeout )
208+ if err != nil {
209+ return err
210+ }
184211 err = boolSetting ("disable_prepared_binary_result" , & cn .disablePreparedBinaryResult )
185212 if err != nil {
186213 return err
@@ -924,7 +951,37 @@ func (se *safeRetryError) Error() string {
924951 return se .Err .Error ()
925952}
926953
954+ // Set the write deadline if we have a write timeout set.
955+ func (cn * conn ) setWriteTimeout () {
956+ if cn .writeTimeout != 0 {
957+ cn .c .SetWriteDeadline (time .Now ().Add (cn .writeTimeout ))
958+ }
959+ }
960+
961+ // Clear the write deadline if we set one.
962+ func (cn * conn ) cleanWriteTimeout () {
963+ if cn .writeTimeout != 0 {
964+ cn .c .SetWriteDeadline (time.Time {})
965+ }
966+ }
967+
968+ // Set the read deadline if we have a read timeout set.
969+ func (cn * conn ) setReadTimeout () {
970+ if cn .readTimeout != 0 {
971+ cn .c .SetReadDeadline (time .Now ().Add (cn .readTimeout ))
972+ }
973+ }
974+
975+ // Clear the read deadline if we set one.
976+ func (cn * conn ) cleanReadTimeout () {
977+ if cn .readTimeout != 0 {
978+ cn .c .SetReadDeadline (time.Time {})
979+ }
980+ }
981+
927982func (cn * conn ) send (m * writeBuf ) {
983+ cn .setWriteTimeout ()
984+ defer cn .cleanWriteTimeout ()
928985 n , err := cn .c .Write (m .wrap ())
929986 if err != nil {
930987 if n == 0 {
@@ -935,6 +992,8 @@ func (cn *conn) send(m *writeBuf) {
935992}
936993
937994func (cn * conn ) sendStartupPacket (m * writeBuf ) error {
995+ cn .setWriteTimeout ()
996+ defer cn .cleanWriteTimeout ()
938997 _ , err := cn .c .Write ((m .wrap ())[1 :])
939998 return err
940999}
@@ -943,6 +1002,8 @@ func (cn *conn) sendStartupPacket(m *writeBuf) error {
9431002// message should have no payload. This method does not use the scratch
9441003// buffer.
9451004func (cn * conn ) sendSimpleMessage (typ byte ) (err error ) {
1005+ cn .setWriteTimeout ()
1006+ defer cn .cleanWriteTimeout ()
9461007 _ , err = cn .c .Write ([]byte {typ , '\x00' , '\x00' , '\x00' , '\x04' })
9471008 return err
9481009}
@@ -973,6 +1034,9 @@ func (cn *conn) recvMessage(r *readBuf) (byte, error) {
9731034 return t , nil
9741035 }
9751036
1037+ cn .setReadTimeout ()
1038+ defer cn .cleanReadTimeout ()
1039+
9761040 x := cn .scratch [:5 ]
9771041 _ , err := io .ReadFull (cn .buf , x )
9781042 if err != nil {
@@ -1110,6 +1174,10 @@ func isDriverSetting(key string) bool {
11101174 return true
11111175 case "binary_parameters" :
11121176 return true
1177+ case "read_timeout" :
1178+ return true
1179+ case "write_timeout" :
1180+ return true
11131181 case "krbsrvname" :
11141182 return true
11151183 case "krbspn" :
0 commit comments