2424import com .google .cloud .spanner .connection .Connection ;
2525import com .google .cloud .spanner .connection .StatementResult ;
2626import com .google .cloud .spanner .connection .StatementResult .ClientSideStatementType ;
27+ import com .google .common .annotations .VisibleForTesting ;
2728import com .google .common .base .Stopwatch ;
2829import com .google .rpc .Code ;
2930import java .sql .ResultSet ;
3738import java .util .concurrent .locks .ReentrantLock ;
3839import java .util .function .Function ;
3940import java .util .function .Supplier ;
41+ import javax .annotation .Nonnull ;
4042
4143/** Base class for Cloud Spanner JDBC {@link Statement}s */
4244abstract class AbstractJdbcStatement extends AbstractJdbcWrapper implements Statement {
@@ -49,7 +51,7 @@ abstract class AbstractJdbcStatement extends AbstractJdbcWrapper implements Stat
4951 private boolean closeOnCompletion ;
5052 private boolean poolable ;
5153 private final JdbcConnection connection ;
52- private int queryTimeout ;
54+ private Duration queryTimeout = Duration . ZERO ;
5355
5456 AbstractJdbcStatement (JdbcConnection connection ) throws SQLException {
5557 this .connection = connection ;
@@ -157,13 +159,22 @@ protected <T> T runWithStatementTimeout(JdbcFunction<Connection, T> function)
157159 */
158160 StatementTimeout setTemporaryStatementTimeout () throws SQLException {
159161 StatementTimeout originalTimeout = null ;
160- if (getQueryTimeout () > 0 ) {
162+ if (! getQueryTimeoutDuration (). isZero () ) {
161163 if (connection .getSpannerConnection ().hasStatementTimeout ()) {
162164 TimeUnit unit = getAppropriateTimeUnit ();
163165 originalTimeout =
164166 StatementTimeout .of (connection .getSpannerConnection ().getStatementTimeout (unit ), unit );
165167 }
166- connection .getSpannerConnection ().setStatementTimeout (getQueryTimeout (), TimeUnit .SECONDS );
168+ Duration queryTimeout = getQueryTimeoutDuration ();
169+ if (queryTimeout .getNano () > 0 ) {
170+ connection
171+ .getSpannerConnection ()
172+ .setStatementTimeout (queryTimeout .toMillis (), TimeUnit .MILLISECONDS );
173+ } else {
174+ connection
175+ .getSpannerConnection ()
176+ .setStatementTimeout (queryTimeout .getSeconds (), TimeUnit .SECONDS );
177+ }
167178 }
168179 return originalTimeout ;
169180 }
@@ -173,7 +184,7 @@ StatementTimeout setTemporaryStatementTimeout() throws SQLException {
173184 * has been executed.
174185 */
175186 void resetStatementTimeout (StatementTimeout originalTimeout ) throws SQLException {
176- if (getQueryTimeout () > 0 ) {
187+ if (! getQueryTimeoutDuration (). isZero () ) {
177188 if (originalTimeout == null ) {
178189 connection .getSpannerConnection ().clearStatementTimeout ();
179190 } else {
@@ -334,14 +345,26 @@ private StatementResult rerunShowStatementTimeout(com.google.cloud.spanner.State
334345
335346 @ Override
336347 public int getQueryTimeout () throws SQLException {
348+ return (int ) getQueryTimeoutDuration ().getSeconds ();
349+ }
350+
351+ @ VisibleForTesting
352+ @ Nonnull
353+ Duration getQueryTimeoutDuration () throws SQLException {
337354 checkClosed ();
338- return queryTimeout ;
355+ return this . queryTimeout ;
339356 }
340357
341358 @ Override
342359 public void setQueryTimeout (int seconds ) throws SQLException {
360+ setQueryTimeout (Duration .ofSeconds (seconds ));
361+ }
362+
363+ @ VisibleForTesting
364+ void setQueryTimeout (@ Nonnull Duration duration ) throws SQLException {
365+ JdbcPreconditions .checkArgument (!duration .isNegative (), "Timeout must be >= 0" );
343366 checkClosed ();
344- this .queryTimeout = seconds ;
367+ this .queryTimeout = duration ;
345368 }
346369
347370 @ Override
0 commit comments