Skip to content

Commit 9bc373c

Browse files
committed
misc - timezone handling
When setting timezone, an initial verification check that this doesn't correspond to server, in order to avoid any unneeded timezone conversion. Implementation correction in order to avoid throwing error if server timezone is not recognized.
1 parent e33127f commit 9bc373c

File tree

5 files changed

+109
-86
lines changed

5 files changed

+109
-86
lines changed

src/main/java/org/mariadb/jdbc/client/ClientImpl.java

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import java.time.Instant;
1818
import java.time.ZoneId;
1919
import java.time.ZoneOffset;
20+
import java.time.zone.ZoneRulesException;
2021
import java.util.*;
2122
import java.util.concurrent.Executor;
2223
import java.util.concurrent.locks.ReentrantLock;
@@ -359,18 +360,25 @@ public String createSessionVariableQuery(String serverTz) {
359360

360361
// force client timezone to connection to ensure result of now(), ...
361362
if (conf.timezone() != null && !"disable".equalsIgnoreCase(conf.timezone())) {
362-
ZoneId serverZoneId = ZoneId.of(serverTz).normalized();
363+
boolean mustSetTimezone = true;
363364
ZoneId clientZoneId = ZoneId.of(conf.timezone()).normalized();
364-
if (!serverZoneId.equals(clientZoneId)) {
365-
serverZoneId = ZoneId.of(serverTz, ZoneId.SHORT_IDS);
366-
if (!serverZoneId.equals(clientZoneId)) {
367-
// to ensure system not having saving time set, prefer fixed offset if possible
368-
if (clientZoneId.getRules().isFixedOffset()) {
369-
ZoneOffset zoneOffset = clientZoneId.getRules().getOffset(Instant.now());
370-
sb.append(",time_zone='").append(zoneOffset.getId()).append("'");
371-
} else {
372-
sb.append(",time_zone='").append(conf.timezone()).append("'");
373-
}
365+
366+
// try to avoid timezone consideration if server use the same one
367+
try {
368+
if (ZoneId.of(serverTz).normalized().equals(clientZoneId)
369+
|| ZoneId.of(serverTz, ZoneId.SHORT_IDS).equals(clientZoneId)) {
370+
mustSetTimezone = false;
371+
}
372+
} catch (ZoneRulesException e) {
373+
// eat
374+
}
375+
376+
if (mustSetTimezone) {
377+
if (clientZoneId.getRules().isFixedOffset()) {
378+
ZoneOffset zoneOffset = clientZoneId.getRules().getOffset(Instant.now());
379+
sb.append(",time_zone='").append(zoneOffset.getId()).append("'");
380+
} else {
381+
sb.append(",time_zone='").append(conf.timezone()).append("'");
374382
}
375383
}
376384
}

src/test/java/org/mariadb/jdbc/Common.java

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,7 @@ public class Common {
5454
mDefUrl =
5555
String.format(
5656
"jdbc:mariadb://%s:%s/%s?user=%s&password=%s&restrictedAuth=false&%s",
57-
hostname,
58-
port,
59-
get("DB_DATABASE", prop),
60-
user,
61-
password,
62-
defaultOther);
57+
hostname, port, get("DB_DATABASE", prop), user, password, defaultOther);
6358

6459
} catch (IOException io) {
6560
io.printStackTrace();

src/test/java/org/mariadb/jdbc/integration/LocalInfileTest.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,11 +73,12 @@ public void wrongFile() throws Exception {
7373
try (Connection con = createCon("allowLocalInfile")) {
7474
Statement stmt = con.createStatement();
7575
assertThrowsContains(
76-
SQLTransientConnectionException.class,
76+
SQLException.class,
7777
() ->
7878
stmt.execute(
7979
"LOAD DATA LOCAL INFILE 'someFile' INTO TABLE LocalInfileInputStreamTest2 (id, test)"),
8080
"Could not send file : someFile");
81+
assertTrue(con.isValid(1));
8182
}
8283
}
8384

@@ -95,13 +96,14 @@ public void unReadableFile() throws Exception {
9596
tempFile.setReadable(false);
9697
Statement stmt = con.createStatement();
9798
assertThrowsContains(
98-
SQLTransientConnectionException.class,
99+
SQLException.class,
99100
() ->
100101
stmt.execute(
101102
"LOAD DATA LOCAL INFILE '"
102103
+ tempFile.getCanonicalPath().replace("\\", "/")
103104
+ "' INTO TABLE LocalInfileInputStreamTest2 (id, test)"),
104105
"Could not send file");
106+
assertTrue(con.isValid(1));
105107
}
106108
}
107109

src/test/java/org/mariadb/jdbc/integration/MultiHostTest.java

Lines changed: 83 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88

99
import java.io.IOException;
1010
import java.sql.*;
11-
1211
import org.junit.jupiter.api.Assumptions;
1312
import org.junit.jupiter.api.Test;
1413
import org.mariadb.jdbc.*;
@@ -106,7 +105,7 @@ public void replicaNotSet() throws Exception {
106105
@Test
107106
public void masterFailover() throws Exception {
108107
Assumptions.assumeTrue(
109-
!"skysql".equals(System.getenv("srv")) && !"skysql-ha".equals(System.getenv("srv")));
108+
!"skysql".equals(System.getenv("srv")) && !"skysql-ha".equals(System.getenv("srv")));
110109

111110
Configuration conf = Configuration.parse(mDefUrl);
112111
HostAddress hostAddress = conf.addresses().get(0);
@@ -117,21 +116,21 @@ public void masterFailover() throws Exception {
117116
}
118117

119118
String url =
120-
mDefUrl.replaceAll(
121-
"//([^/]*)/",
122-
String.format(
123-
"//address=(host=localhost)(port=9999)(type=master),address=(host=localhost)(port=%s)(type=master),address=(host=%s)(port=%s)(type=master)/",
124-
proxy.getLocalPort(), hostAddress.host, hostAddress.port));
119+
mDefUrl.replaceAll(
120+
"//([^/]*)/",
121+
String.format(
122+
"//address=(host=localhost)(port=9999)(type=master),address=(host=localhost)(port=%s)(type=master),address=(host=%s)(port=%s)(type=master)/",
123+
proxy.getLocalPort(), hostAddress.host, hostAddress.port));
125124
url = url.replaceAll("jdbc:mariadb:", "jdbc:mariadb:sequential:");
126125
if (conf.sslMode() == SslMode.VERIFY_FULL) {
127126
url = url.replaceAll("sslMode=verify-full", "sslMode=verify-ca");
128127
}
129128

130129
try (Connection con =
131-
(Connection)
132-
DriverManager.getConnection(
133-
url
134-
+ "waitReconnectTimeout=300&deniedListTimeout=300&retriesAllDown=4&connectTimeout=500")) {
130+
(Connection)
131+
DriverManager.getConnection(
132+
url
133+
+ "waitReconnectTimeout=300&deniedListTimeout=300&retriesAllDown=4&connectTimeout=500")) {
135134
Statement stmt = con.createStatement();
136135
stmt.execute("SET @con=1");
137136
proxy.restart(50);
@@ -144,10 +143,10 @@ public void masterFailover() throws Exception {
144143

145144
// with transaction replay
146145
try (Connection con =
147-
(Connection)
148-
DriverManager.getConnection(
149-
url
150-
+ "transactionReplay=true&waitReconnectTimeout=300&deniedListTimeout=300&retriesAllDown=4&connectTimeout=500")) {
146+
(Connection)
147+
DriverManager.getConnection(
148+
url
149+
+ "transactionReplay=true&waitReconnectTimeout=300&deniedListTimeout=300&retriesAllDown=4&connectTimeout=500")) {
151150
Statement stmt = con.createStatement();
152151
stmt.execute("DROP TABLE IF EXISTS testReplay");
153152
stmt.execute("CREATE TABLE testReplay(id INT)");
@@ -186,8 +185,9 @@ public void masterFailover() throws Exception {
186185
@Test
187186
public void masterStreamingFailover() throws Exception {
188187
Assumptions.assumeTrue(
189-
isMariaDBServer() &&
190-
!"skysql".equals(System.getenv("srv")) && !"skysql-ha".equals(System.getenv("srv")));
188+
isMariaDBServer()
189+
&& !"skysql".equals(System.getenv("srv"))
190+
&& !"skysql-ha".equals(System.getenv("srv")));
191191

192192
Configuration conf = Configuration.parse(mDefUrl);
193193
HostAddress hostAddress = conf.addresses().get(0);
@@ -198,47 +198,56 @@ public void masterStreamingFailover() throws Exception {
198198
}
199199

200200
String url =
201-
mDefUrl.replaceAll(
202-
"//([^/]*)/",
203-
String.format(
204-
"//address=(host=localhost)(port=%s)(type=master)/",
205-
proxy.getLocalPort(), hostAddress.host, hostAddress.port));
201+
mDefUrl.replaceAll(
202+
"//([^/]*)/",
203+
String.format(
204+
"//address=(host=localhost)(port=%s)(type=master)/",
205+
proxy.getLocalPort(), hostAddress.host, hostAddress.port));
206206
url = url.replaceAll("jdbc:mariadb:", "jdbc:mariadb:sequential:");
207207
if (conf.sslMode() == SslMode.VERIFY_FULL) {
208208
url = url.replaceAll("sslMode=verify-full", "sslMode=verify-ca");
209209
}
210210

211211
Connection con =
212-
(Connection)
213-
DriverManager.getConnection(
214-
url
215-
+ "allowMultiQueries&transactionReplay=true&waitReconnectTimeout=300&deniedListTimeout=300&retriesAllDown=40&connectTimeout=500&useReadAheadInput=false");
216-
long threadId = con.getThreadId();
217-
Statement stmt = con.createStatement();
218-
stmt.setFetchSize(2);
219-
ResultSet rs = stmt.executeQuery("SELECT * FROM seq_1_to_50; SELECT * FROM seq_1_to_50000");
220-
rs.next();
221-
assertEquals(1, rs.getInt(1));
222-
proxy.restart(50);
223-
Statement stmt2 = con.createStatement();
224-
assertThrowsContains(SQLException.class, () -> stmt2.executeQuery("SELECT * from mysql.user"), "Socket error during result streaming");
225-
assertNotEquals(threadId, con.getThreadId());
212+
(Connection)
213+
DriverManager.getConnection(
214+
url
215+
+ "allowMultiQueries&transactionReplay=true&waitReconnectTimeout=300&deniedListTimeout=300&retriesAllDown=40&connectTimeout=500&useReadAheadInput=false");
216+
long threadId = con.getThreadId();
217+
Statement stmt = con.createStatement();
218+
stmt.setFetchSize(2);
219+
ResultSet rs = stmt.executeQuery("SELECT * FROM seq_1_to_50; SELECT * FROM seq_1_to_50000");
220+
rs.next();
221+
assertEquals(1, rs.getInt(1));
222+
proxy.restart(50);
223+
Statement stmt2 = con.createStatement();
224+
assertThrowsContains(
225+
SQLException.class,
226+
() -> stmt2.executeQuery("SELECT * from mysql.user"),
227+
"Socket error during result streaming");
228+
assertNotEquals(threadId, con.getThreadId());
226229

227-
// additional small test
230+
// additional small test
228231
assertEquals(0, con.getNetworkTimeout());
229-
con.setNetworkTimeout(Runnable::run,10);
232+
con.setNetworkTimeout(Runnable::run, 10);
230233
assertEquals(10, con.getNetworkTimeout());
231234

232235
con.setReadOnly(true);
233-
con.close();
234-
assertThrowsContains(SQLNonTransientConnectionException.class, () -> con.setReadOnly(false), "Connection is closed");
235-
assertThrowsContains(SQLNonTransientConnectionException.class, () -> con.abort(Runnable::run), "Connection is closed");
236+
con.close();
237+
assertThrowsContains(
238+
SQLNonTransientConnectionException.class,
239+
() -> con.setReadOnly(false),
240+
"Connection is closed");
241+
assertThrowsContains(
242+
SQLNonTransientConnectionException.class,
243+
() -> con.abort(Runnable::run),
244+
"Connection is closed");
236245

237246
Connection con2 =
238-
(Connection)
239-
DriverManager.getConnection(
240-
url
241-
+ "allowMultiQueries&transactionReplay=true&waitReconnectTimeout=300&deniedListTimeout=300&retriesAllDown=40&connectTimeout=500&useReadAheadInput=false");
247+
(Connection)
248+
DriverManager.getConnection(
249+
url
250+
+ "allowMultiQueries&transactionReplay=true&waitReconnectTimeout=300&deniedListTimeout=300&retriesAllDown=40&connectTimeout=500&useReadAheadInput=false");
242251
con2.abort(Runnable::run);
243252
}
244253

@@ -301,12 +310,12 @@ public void masterReplicationFailover() throws Exception {
301310
}
302311
}
303312

304-
305313
@Test
306314
public void masterReplicationStreamingFailover() throws Exception {
307315
Assumptions.assumeTrue(
308-
isMariaDBServer() &&
309-
!"skysql".equals(System.getenv("srv")) && !"skysql-ha".equals(System.getenv("srv")));
316+
isMariaDBServer()
317+
&& !"skysql".equals(System.getenv("srv"))
318+
&& !"skysql-ha".equals(System.getenv("srv")));
310319

311320
Configuration conf = Configuration.parse(mDefUrl);
312321
HostAddress hostAddress = conf.addresses().get(0);
@@ -317,21 +326,21 @@ public void masterReplicationStreamingFailover() throws Exception {
317326
}
318327

319328
String url =
320-
mDefUrl.replaceAll(
321-
"//([^/]*)/",
322-
String.format(
323-
"//address=(host=localhost)(port=%s)(type=primary),address=(host=%s)(port=%s)(type=replica)/",
324-
proxy.getLocalPort(), hostAddress.host, hostAddress.port, hostname, port));
329+
mDefUrl.replaceAll(
330+
"//([^/]*)/",
331+
String.format(
332+
"//address=(host=localhost)(port=%s)(type=primary),address=(host=%s)(port=%s)(type=replica)/",
333+
proxy.getLocalPort(), hostAddress.host, hostAddress.port, hostname, port));
325334
url = url.replaceAll("jdbc:mariadb:", "jdbc:mariadb:replication:");
326335
if (conf.sslMode() == SslMode.VERIFY_FULL) {
327336
url = url.replaceAll("sslMode=verify-full", "sslMode=verify-ca");
328337
}
329338

330339
Connection con =
331-
(Connection)
332-
DriverManager.getConnection(
333-
url
334-
+ "allowMultiQueries&transactionReplay=true&waitReconnectTimeout=300&deniedListTimeout=300&retriesAllDown=40&connectTimeout=500&useReadAheadInput=false");
340+
(Connection)
341+
DriverManager.getConnection(
342+
url
343+
+ "allowMultiQueries&transactionReplay=true&waitReconnectTimeout=300&deniedListTimeout=300&retriesAllDown=40&connectTimeout=500&useReadAheadInput=false");
335344
long threadId = con.getThreadId();
336345
Statement stmt = con.createStatement();
337346
stmt.setFetchSize(2);
@@ -340,28 +349,36 @@ public void masterReplicationStreamingFailover() throws Exception {
340349
assertEquals(1, rs.getInt(1));
341350
proxy.restart(50);
342351
Statement stmt2 = con.createStatement();
343-
assertThrowsContains(SQLException.class, () -> stmt2.executeQuery("SELECT * from mysql.user"), "Socket error during result streaming");
352+
assertThrowsContains(
353+
SQLException.class,
354+
() -> stmt2.executeQuery("SELECT * from mysql.user"),
355+
"Socket error during result streaming");
344356
assertNotEquals(threadId, con.getThreadId());
345357

346358
// additional small test
347359
assertEquals(0, con.getNetworkTimeout());
348-
con.setNetworkTimeout(Runnable::run,10);
360+
con.setNetworkTimeout(Runnable::run, 10);
349361
assertEquals(10, con.getNetworkTimeout());
350362

351363
con.setReadOnly(true);
352364
con.close();
353-
assertThrowsContains(SQLNonTransientConnectionException.class, () -> con.setReadOnly(false), "Connection is closed");
354-
assertThrowsContains(SQLNonTransientConnectionException.class, () -> con.abort(Runnable::run), "Connection is closed");
365+
assertThrowsContains(
366+
SQLNonTransientConnectionException.class,
367+
() -> con.setReadOnly(false),
368+
"Connection is closed");
369+
assertThrowsContains(
370+
SQLNonTransientConnectionException.class,
371+
() -> con.abort(Runnable::run),
372+
"Connection is closed");
355373

356374
Connection con2 =
357-
(Connection)
358-
DriverManager.getConnection(
359-
url
360-
+ "allowMultiQueries&transactionReplay=true&waitReconnectTimeout=300&deniedListTimeout=300&retriesAllDown=40&connectTimeout=500&useReadAheadInput=false");
375+
(Connection)
376+
DriverManager.getConnection(
377+
url
378+
+ "allowMultiQueries&transactionReplay=true&waitReconnectTimeout=300&deniedListTimeout=300&retriesAllDown=40&connectTimeout=500&useReadAheadInput=false");
361379
con2.abort(Runnable::run);
362380
}
363381

364-
365382
public Connection createProxyConKeep(String opts) throws SQLException {
366383
Configuration conf = Configuration.parse(mDefUrl);
367384
HostAddress hostAddress = conf.addresses().get(0);

src/test/java/org/mariadb/jdbc/integration/PreparedStatementTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1017,10 +1017,11 @@ public void more2BytesParameters() throws Throwable {
10171017
st.setInt(i, rnds[i - 1]);
10181018
}
10191019
assertThrowsContains(
1020-
SQLTransientConnectionException.class,
1020+
SQLException.class,
10211021
() -> st.executeQuery(),
10221022
"Prepared statement contains too many placeholders");
10231023
}
1024+
assertTrue(sharedConnBinary.isValid(1));
10241025
}
10251026

10261027
private String generateLongText(int len) {

0 commit comments

Comments
 (0)