Skip to content

Commit 8f587cf

Browse files
authored
chore: store query timeout as a java.time.Duration (googleapis#1865)
Store the query timeout internally as a java.time.Duration, so we can use a smaller unit for testing. This again allows us to enable the timeout tests by default.
1 parent dee17e2 commit 8f587cf

File tree

3 files changed

+41
-15
lines changed

3 files changed

+41
-15
lines changed

pom.xml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,6 @@
241241
<configuration>
242242
<excludes>
243243
<exclude>com.google.cloud.spanner.jdbc.it.**</exclude>
244-
<exclude>com.google.cloud.spanner.jdbc.JdbcStatementTimeoutTest</exclude>
245244
</excludes>
246245
<reportNameSuffix>sponge_log</reportNameSuffix>
247246
<systemPropertyVariables>

src/main/java/com/google/cloud/spanner/jdbc/AbstractJdbcStatement.java

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import com.google.cloud.spanner.connection.Connection;
2525
import com.google.cloud.spanner.connection.StatementResult;
2626
import com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType;
27+
import com.google.common.annotations.VisibleForTesting;
2728
import com.google.common.base.Stopwatch;
2829
import com.google.rpc.Code;
2930
import java.sql.ResultSet;
@@ -35,6 +36,7 @@
3536
import java.util.concurrent.TimeUnit;
3637
import java.util.function.Function;
3738
import java.util.function.Supplier;
39+
import javax.annotation.Nonnull;
3840

3941
/** Base class for Cloud Spanner JDBC {@link Statement}s */
4042
abstract class AbstractJdbcStatement extends AbstractJdbcWrapper implements Statement {
@@ -45,7 +47,7 @@ abstract class AbstractJdbcStatement extends AbstractJdbcWrapper implements Stat
4547
private boolean closeOnCompletion;
4648
private boolean poolable;
4749
private final JdbcConnection connection;
48-
private int queryTimeout;
50+
private Duration queryTimeout = Duration.ZERO;
4951

5052
AbstractJdbcStatement(JdbcConnection connection) throws SQLException {
5153
this.connection = connection;
@@ -148,13 +150,22 @@ protected <T> T runWithStatementTimeout(JdbcFunction<Connection, T> function)
148150
*/
149151
StatementTimeout setTemporaryStatementTimeout() throws SQLException {
150152
StatementTimeout originalTimeout = null;
151-
if (getQueryTimeout() > 0) {
153+
if (!getQueryTimeoutDuration().isZero()) {
152154
if (connection.getSpannerConnection().hasStatementTimeout()) {
153155
TimeUnit unit = getAppropriateTimeUnit();
154156
originalTimeout =
155157
StatementTimeout.of(connection.getSpannerConnection().getStatementTimeout(unit), unit);
156158
}
157-
connection.getSpannerConnection().setStatementTimeout(getQueryTimeout(), TimeUnit.SECONDS);
159+
Duration queryTimeout = getQueryTimeoutDuration();
160+
if (queryTimeout.getNano() > 0) {
161+
connection
162+
.getSpannerConnection()
163+
.setStatementTimeout(queryTimeout.toMillis(), TimeUnit.MILLISECONDS);
164+
} else {
165+
connection
166+
.getSpannerConnection()
167+
.setStatementTimeout(queryTimeout.getSeconds(), TimeUnit.SECONDS);
168+
}
158169
}
159170
return originalTimeout;
160171
}
@@ -164,7 +175,7 @@ StatementTimeout setTemporaryStatementTimeout() throws SQLException {
164175
* has been executed.
165176
*/
166177
void resetStatementTimeout(StatementTimeout originalTimeout) throws SQLException {
167-
if (getQueryTimeout() > 0) {
178+
if (!getQueryTimeoutDuration().isZero()) {
168179
if (originalTimeout == null) {
169180
connection.getSpannerConnection().clearStatementTimeout();
170181
} else {
@@ -317,14 +328,26 @@ private StatementResult rerunShowStatementTimeout(com.google.cloud.spanner.State
317328

318329
@Override
319330
public int getQueryTimeout() throws SQLException {
331+
return (int) getQueryTimeoutDuration().getSeconds();
332+
}
333+
334+
@VisibleForTesting
335+
@Nonnull
336+
Duration getQueryTimeoutDuration() throws SQLException {
320337
checkClosed();
321-
return queryTimeout;
338+
return this.queryTimeout;
322339
}
323340

324341
@Override
325342
public void setQueryTimeout(int seconds) throws SQLException {
343+
setQueryTimeout(Duration.ofSeconds(seconds));
344+
}
345+
346+
@VisibleForTesting
347+
void setQueryTimeout(@Nonnull Duration duration) throws SQLException {
348+
JdbcPreconditions.checkArgument(!duration.isNegative(), "Timeout must be >= 0");
326349
checkClosed();
327-
this.queryTimeout = seconds;
350+
this.queryTimeout = duration;
328351
}
329352

330353
@Override

src/test/java/com/google/cloud/spanner/jdbc/JdbcStatementTimeoutTest.java

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,21 @@
2727
import java.sql.ResultSet;
2828
import java.sql.SQLException;
2929
import java.sql.Statement;
30+
import java.time.Duration;
31+
import org.junit.After;
3032
import org.junit.Test;
3133
import org.junit.runner.RunWith;
3234
import org.junit.runners.JUnit4;
3335

34-
/**
35-
* Tests setting a statement timeout. This test is by default not included in unit test runs, as the
36-
* minimum timeout value in JDBC is 1 second, which again makes this test relatively slow.
37-
*/
36+
/** Tests setting a statement timeout. */
3837
@RunWith(JUnit4.class)
3938
public class JdbcStatementTimeoutTest extends AbstractMockServerTest {
4039

40+
@After
41+
public void resetExecutionTimes() {
42+
mockSpanner.removeAllExecutionTimes();
43+
}
44+
4145
@Test
4246
public void testExecuteTimeout() throws SQLException {
4347
try (java.sql.Connection connection = createJdbcConnection()) {
@@ -50,7 +54,7 @@ public void testExecuteTimeout() throws SQLException {
5054
// Simulate that executeSql takes 2 seconds and set a statement timeout of 1 second.
5155
mockSpanner.setExecuteSqlExecutionTime(
5256
SimulatedExecutionTime.ofMinimumAndRandomTime(2000, 0));
53-
statement.setQueryTimeout(1);
57+
((JdbcStatement) statement).setQueryTimeout(Duration.ofMillis(5L));
5458
assertThrows(
5559
JdbcSqlTimeoutException.class, () -> statement.execute(INSERT_STATEMENT.getSql()));
5660
}
@@ -74,7 +78,7 @@ public void testExecuteQueryTimeout() throws SQLException {
7478
// second.
7579
mockSpanner.setExecuteStreamingSqlExecutionTime(
7680
SimulatedExecutionTime.ofMinimumAndRandomTime(2000, 0));
77-
statement.setQueryTimeout(1);
81+
((JdbcStatement) statement).setQueryTimeout(Duration.ofMillis(5L));
7882
assertThrows(
7983
JdbcSqlTimeoutException.class,
8084
() -> statement.executeQuery(SELECT_RANDOM_STATEMENT.getSql()));
@@ -92,7 +96,7 @@ public void testExecuteUpdateTimeout() throws SQLException {
9296
// Simulate that executeSql takes 2 seconds and set a statement timeout of 1 second.
9397
mockSpanner.setExecuteSqlExecutionTime(
9498
SimulatedExecutionTime.ofMinimumAndRandomTime(2000, 0));
95-
statement.setQueryTimeout(1);
99+
((JdbcStatement) statement).setQueryTimeout(Duration.ofMillis(5L));
96100
assertThrows(
97101
JdbcSqlTimeoutException.class,
98102
() -> statement.executeUpdate(INSERT_STATEMENT.getSql()));
@@ -112,7 +116,7 @@ public void testExecuteBatchTimeout() throws SQLException {
112116
// Simulate that executeBatchDml takes 2 seconds and set a statement timeout of 1 second.
113117
mockSpanner.setExecuteBatchDmlExecutionTime(
114118
SimulatedExecutionTime.ofMinimumAndRandomTime(2000, 0));
115-
statement.setQueryTimeout(1);
119+
((JdbcStatement) statement).setQueryTimeout(Duration.ofMillis(5L));
116120
statement.addBatch(INSERT_STATEMENT.getSql());
117121
assertThrows(JdbcSqlTimeoutException.class, statement::executeBatch);
118122
}

0 commit comments

Comments
 (0)