@@ -132,6 +132,12 @@ type conn struct {
132132 // round-trip mode for non-prepared Query calls.
133133 binaryParameters bool
134134
135+ // Timeouts for read and write operations against the database server.
136+ // A duration of 0 indicates no timeout.
137+ // specified in milliseconds
138+ readTimeout time.Duration
139+ writeTimeout time.Duration
140+
135141 // If true this connection is in the middle of a COPY
136142 inCopy bool
137143}
@@ -151,6 +157,28 @@ func (cn *conn) handleDriverSettings(o values) (err error) {
151157 return nil
152158 }
153159
160+ timeSetting := func (key string , val * time.Duration ) error {
161+ if value := o [key ]; value != "" {
162+ timeout , err := strconv .Atoi (value )
163+ if err != nil {
164+ return err
165+ }
166+ // timeout is specified in milliseconds.
167+ * val = time .Duration (timeout ) * time .Millisecond
168+ } else {
169+ * val = time .Duration (0 ) * time .Millisecond
170+ }
171+ return nil
172+ }
173+
174+ err = timeSetting ("read_timeout" , & cn .readTimeout )
175+ if err != nil {
176+ return err
177+ }
178+ err = timeSetting ("write_timeout" , & cn .writeTimeout )
179+ if err != nil {
180+ return err
181+ }
154182 err = boolSetting ("disable_prepared_binary_result" , & cn .disablePreparedBinaryResult )
155183 if err != nil {
156184 return err
@@ -911,23 +939,57 @@ func (cn *conn) Exec(query string, args []driver.Value) (res driver.Result, err
911939 return r , err
912940}
913941
942+ func (cn * conn ) setWriteTimeout () {
943+ // Set the write deadline if we have a write timeout set.
944+ if cn .writeTimeout != 0 {
945+ cn .c .SetWriteDeadline (time .Now ().Add (cn .writeTimeout ))
946+ }
947+ }
948+
949+ func (cn * conn ) cleanWriteTimeout () {
950+ if cn .writeTimeout != 0 {
951+ // Clear the write deadline if we set one.
952+ cn .c .SetWriteDeadline (time.Time {})
953+ }
954+ }
955+
956+ func (cn * conn ) setReadTimeout () {
957+ // Set the read deadline if we have a read timeout set.
958+ if cn .readTimeout != 0 {
959+ cn .c .SetReadDeadline (time .Now ().Add (cn .readTimeout ))
960+ }
961+ }
962+
963+ func (cn * conn ) cleanReadTimeout () {
964+ if cn .readTimeout != 0 {
965+ // Clear the read deadline if we set one.
966+ cn .c .SetReadDeadline (time.Time {})
967+ }
968+ }
969+
914970func (cn * conn ) send (m * writeBuf ) {
971+ cn .setWriteTimeout ()
915972 _ , err := cn .c .Write (m .wrap ())
916973 if err != nil {
917974 panic (err )
918975 }
976+ cn .cleanWriteTimeout ()
919977}
920978
921979func (cn * conn ) sendStartupPacket (m * writeBuf ) error {
980+ cn .setWriteTimeout ()
922981 _ , err := cn .c .Write ((m .wrap ())[1 :])
982+ cn .cleanWriteTimeout ()
923983 return err
924984}
925985
926986// Send a message of type typ to the server on the other end of cn. The
927987// message should have no payload. This method does not use the scratch
928988// buffer.
929989func (cn * conn ) sendSimpleMessage (typ byte ) (err error ) {
990+ cn .setWriteTimeout ()
930991 _ , err = cn .c .Write ([]byte {typ , '\x00' , '\x00' , '\x00' , '\x04' })
992+ cn .cleanWriteTimeout ()
931993 return err
932994}
933995
@@ -957,9 +1019,11 @@ func (cn *conn) recvMessage(r *readBuf) (byte, error) {
9571019 return t , nil
9581020 }
9591021
1022+ cn .setReadTimeout ()
9601023 x := cn .scratch [:5 ]
9611024 _ , err := io .ReadFull (cn .buf , x )
9621025 if err != nil {
1026+ cn .cleanReadTimeout ()
9631027 return 0 , err
9641028 }
9651029
@@ -972,11 +1036,14 @@ func (cn *conn) recvMessage(r *readBuf) (byte, error) {
9721036 } else {
9731037 y = make ([]byte , n )
9741038 }
1039+ cn .setReadTimeout ()
9751040 _ , err = io .ReadFull (cn .buf , y )
9761041 if err != nil {
1042+ cn .cleanReadTimeout ()
9771043 return 0 , err
9781044 }
9791045 * r = y
1046+ cn .cleanReadTimeout ()
9801047 return t , nil
9811048}
9821049
@@ -1083,6 +1150,10 @@ func isDriverSetting(key string) bool {
10831150 return true
10841151 case "binary_parameters" :
10851152 return true
1153+ case "read_timeout" :
1154+ return true
1155+ case "write_timeout" :
1156+ return true
10861157
10871158 default :
10881159 return false
0 commit comments