Skip to content

Commit ced0816

Browse files
authored
Merge pull request #106 from hiroyuki-sato/mysql_timezone_check
The MySQL plugin compare server and client timezone
2 parents 4c8d92f + dd2c693 commit ced0816

File tree

4 files changed

+124
-1
lines changed

4 files changed

+124
-1
lines changed

embulk-input-jdbc/src/main/java/org/embulk/input/jdbc/AbstractJdbcInputPlugin.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ public ConfigDiff transaction(ConfigSource config,
193193
return buildNextConfigDiff(task, control.run(task.dump(), schema, 1));
194194
}
195195

196-
private Schema setupTask(JdbcInputConnection con, PluginTask task) throws SQLException
196+
protected Schema setupTask(JdbcInputConnection con, PluginTask task) throws SQLException
197197
{
198198
if (task.getTable().isPresent()) {
199199
String actualTableName = normalizeTableNameCase(con, task.getTable().get());

embulk-input-mysql/src/main/java/org/embulk/input/MySQLInputPlugin.java

+11
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,12 @@
1212
import org.embulk.config.Config;
1313
import org.embulk.config.ConfigDefault;
1414
import org.embulk.input.jdbc.AbstractJdbcInputPlugin;
15+
import org.embulk.input.jdbc.JdbcInputConnection;
1516
import org.embulk.input.jdbc.getter.ColumnGetterFactory;
1617
import org.embulk.input.mysql.MySQLInputConnection;
1718
import org.embulk.input.mysql.getter.MySQLColumnGetterFactory;
1819
import org.embulk.spi.PageBuilder;
20+
import org.embulk.spi.Schema;
1921
import org.joda.time.DateTimeZone;
2022

2123
public class MySQLInputPlugin
@@ -163,4 +165,13 @@ private void loadTimeZoneMappings()
163165
}
164166
}
165167
}
168+
169+
@Override
170+
protected Schema setupTask(JdbcInputConnection con, PluginTask task) throws SQLException
171+
{
172+
MySQLInputConnection mySQLCon = (MySQLInputConnection)con;
173+
mySQLCon.compareTimeZone();
174+
return super.setupTask(con,task);
175+
}
176+
166177
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
package org.embulk.input;
2+
3+
import org.embulk.spi.Exec;
4+
import org.slf4j.Logger;
5+
6+
import java.sql.Connection;
7+
import java.sql.ResultSet;
8+
import java.sql.SQLException;
9+
import java.sql.Statement;
10+
import java.util.Date;
11+
import java.util.Locale;
12+
import java.util.TimeZone;
13+
14+
public class MySQLTimeZoneComparison
15+
{
16+
private static final int ONE_HOUR_SEC = 3600;
17+
private static final int ONE_MIN_SEC = 60;
18+
19+
private Connection connection;
20+
21+
private final Logger logger = Exec.getLogger(getClass());
22+
23+
public MySQLTimeZoneComparison(Connection connection)
24+
{
25+
this.connection = connection;
26+
}
27+
28+
public void compareTimeZone()
29+
throws SQLException
30+
{
31+
TimeZone serverTimeZone = null;
32+
try {
33+
serverTimeZone = getServerTimeZone();
34+
}
35+
catch (SQLException ex) {
36+
logger.warn("Can't get server TimeZone.");
37+
logger.warn(String.format(Locale.ENGLISH, "SQLException raised %s", ex.toString()));
38+
}
39+
40+
TimeZone clientTimeZone = TimeZone.getDefault();
41+
Date today = new Date();
42+
int clientOffset = clientTimeZone.getRawOffset();
43+
44+
if (clientTimeZone.inDaylightTime(today)) {
45+
clientOffset += clientTimeZone.getDSTSavings();
46+
}
47+
48+
//
49+
// Compare offset only. Although I expect to return true, the following code return false,
50+
//
51+
// TimeZone tz_jst = TimeZone.getTimeZone("JST");
52+
// TimeZone tz_gmt9 = TimeZone.getTimeZone("GMT+9");
53+
// tz_jst.hasSameRules(tz_gmt9) // return false.
54+
//
55+
if (clientOffset != serverTimeZone.getRawOffset()) {
56+
logger.warn(String.format(Locale.ENGLISH,
57+
"The client timezone(%s) is different from the server timezone(%s). The plugin will fetch wrong datetime values.",
58+
clientTimeZone.getID(), serverTimeZone.getID()));
59+
logger.warn(String.format(Locale.ENGLISH,
60+
"You may need to set options `useLegacyDatetimeCode` and `serverTimezone`"));
61+
logger.warn(String.format(Locale.ENGLISH,
62+
"Example. `options: { useLegacyDatetimeCode: false, serverTimezone: UTC }`"));
63+
}
64+
logger.warn(String.format(Locale.ENGLISH, "The plugin will set `useLegacyDatetimeCode=false` by default in future."));
65+
}
66+
67+
private TimeZone getServerTimeZone()
68+
throws SQLException
69+
{
70+
//
71+
// First, I used `@@system_time_zone`. but It return non Time Zone Abbreviations name on a specific platform.
72+
// So, This method calculate GMT offset with query.
73+
//
74+
String query = "select TIME_TO_SEC(timediff(now(),utc_timestamp()));";
75+
Statement stmt = connection.createStatement();
76+
77+
try {
78+
ResultSet rs = stmt.executeQuery(query);
79+
if (rs.next()) {
80+
int offsetSeconds = rs.getInt(1);
81+
return fromGMTOffsetSeconds(offsetSeconds);
82+
}
83+
throw new SQLException(String.format(Locale.ENGLISH,
84+
"The timezone comparison query(%s) doesn't return the result.",query));
85+
}
86+
finally {
87+
stmt.close();
88+
}
89+
}
90+
91+
private TimeZone fromGMTOffsetSeconds(int offsetSeconds)
92+
{
93+
if (offsetSeconds == 0) {
94+
return TimeZone.getTimeZone("UTC");
95+
}
96+
97+
String sign = offsetSeconds > 0 ? "+" : "-";
98+
int absOffsetSec = Math.abs(offsetSeconds);
99+
int tzHour = absOffsetSec / ONE_HOUR_SEC;
100+
int tzMin = absOffsetSec % ONE_HOUR_SEC / ONE_MIN_SEC;
101+
String tzName = String.format(Locale.ENGLISH, "GMT%s%02d:%02d", sign, tzHour, tzMin);
102+
return TimeZone.getTimeZone(tzName);
103+
}
104+
}

embulk-input-mysql/src/main/java/org/embulk/input/mysql/MySQLInputConnection.java

+8
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
import com.mysql.jdbc.ConnectionImpl;
1111
import com.mysql.jdbc.ConnectionProperties;
12+
import org.embulk.input.MySQLTimeZoneComparison;
1213
import org.embulk.input.jdbc.JdbcInputConnection;
1314
import org.embulk.input.jdbc.JdbcLiteral;
1415
import org.embulk.input.jdbc.getter.ColumnGetter;
@@ -59,4 +60,11 @@ public TimeZone getServerTimezoneTZ()
5960
{
6061
return ((ConnectionImpl) connection).getServerTimezoneTZ();
6162
}
63+
64+
public void compareTimeZone() throws SQLException
65+
{
66+
MySQLTimeZoneComparison timeZoneComparison = new MySQLTimeZoneComparison(connection);
67+
timeZoneComparison.compareTimeZone();
68+
}
69+
6270
}

0 commit comments

Comments
 (0)