diff --git a/embulk-output-mysql/src/main/java/org/embulk/output/MySQLOutputPlugin.java b/embulk-output-mysql/src/main/java/org/embulk/output/MySQLOutputPlugin.java index efe02ea4..364383fd 100644 --- a/embulk-output-mysql/src/main/java/org/embulk/output/MySQLOutputPlugin.java +++ b/embulk-output-mysql/src/main/java/org/embulk/output/MySQLOutputPlugin.java @@ -8,9 +8,12 @@ import org.embulk.config.ConfigDefault; import org.embulk.output.jdbc.AbstractJdbcOutputPlugin; import org.embulk.output.jdbc.BatchInsert; +import org.embulk.output.jdbc.JdbcOutputConnection; import org.embulk.output.jdbc.MergeConfig; +import org.embulk.output.mysql.MySQLOutputConnection; import org.embulk.output.mysql.MySQLOutputConnector; import org.embulk.output.mysql.MySQLBatchInsert; +import org.embulk.spi.Schema; public class MySQLOutputPlugin extends AbstractJdbcOutputPlugin @@ -122,4 +125,13 @@ protected boolean isRetryableException(String sqlState, int errorCode) return false; } } + + @Override + protected void doBegin(JdbcOutputConnection con, + PluginTask task, final Schema schema, int taskCount) throws SQLException + { + MySQLOutputConnection mySQLCon = (MySQLOutputConnection)con; + mySQLCon.compareTimeZone(); + super.doBegin(con,task,schema,taskCount); + } } diff --git a/embulk-output-mysql/src/main/java/org/embulk/output/MySQLTimeZoneComparison.java b/embulk-output-mysql/src/main/java/org/embulk/output/MySQLTimeZoneComparison.java new file mode 100644 index 00000000..780ef3f5 --- /dev/null +++ b/embulk-output-mysql/src/main/java/org/embulk/output/MySQLTimeZoneComparison.java @@ -0,0 +1,107 @@ +package org.embulk.output; + +import org.embulk.spi.Exec; +import org.slf4j.Logger; + + +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.Date; +import java.util.Locale; +import java.util.TimeZone; + +public class MySQLTimeZoneComparison { + + private static final int ONE_HOUR_SEC = 3600; + private static final int ONE_MIN_SEC = 60; + + private Connection connection; + + private final Logger logger = Exec.getLogger(getClass()); + + public MySQLTimeZoneComparison(Connection connection) + { + this.connection = connection; + } + + public void compareTimeZone() + throws SQLException + { + TimeZone serverTimeZone = null; + try { + serverTimeZone = getServerTimeZone(); + } + catch (SQLException ex) { + logger.warn("Can't get server TimeZone."); + logger.warn(String.format(Locale.ENGLISH, "SQLException raised %s", ex.toString())); + } + + TimeZone clientTimeZone = TimeZone.getDefault(); + Date today = new Date(); + int clientOffset = clientTimeZone.getRawOffset(); + + if (clientTimeZone.inDaylightTime(today)) { + clientOffset += clientTimeZone.getDSTSavings(); + } + + // + // Compare offset only. Although I expect to return true, the following code return false, + // + // TimeZone tz_jst = TimeZone.getTimeZone("JST"); + // TimeZone tz_gmt9 = TimeZone.getTimeZone("GMT+9"); + // tz_jst.hasSameRules(tz_gmt9) // return false. + // + if (clientOffset != serverTimeZone.getRawOffset()) { + logger.warn(String.format(Locale.ENGLISH, + "The client timezone(%s) is different from the server timezone(%s). The plugin will store wrong datetime values.", + clientTimeZone.getID(), serverTimeZone.getID())); + logger.warn(String.format(Locale.ENGLISH, + "You may need to set options `useLegacyDatetimeCode` and `serverTimezone`")); + logger.warn(String.format(Locale.ENGLISH, + "Example. `options: { useLegacyDatetimeCode: false, serverTimezone: UTC }`")); + } + logger.warn(String.format(Locale.ENGLISH, "The plugin will set `useLegacyDatetimeCode=false` by default in future.")); + } + + private TimeZone getServerTimeZone() + throws SQLException + { + // + // First, I used `@@system_time_zone`. but It return non Time Zone Abbreviations name on a specific platform. + // So, This method calculate GMT offset with query. + // + String query = "select TIME_TO_SEC(timediff(now(),utc_timestamp()));"; + Statement stmt = connection.createStatement(); + + try { + ResultSet rs = stmt.executeQuery(query); + if (rs.next()) { + int offsetSeconds = rs.getInt(1); + return fromGMTOffsetSeconds(offsetSeconds); + } + throw new SQLException(String.format(Locale.ENGLISH, + "The timezone comparison query(%s) doesn't return the result.",query)); + } + finally { + stmt.close(); + } + } + + private TimeZone fromGMTOffsetSeconds(int offsetSeconds) + { + if (offsetSeconds == 0) { + return TimeZone.getTimeZone("UTC"); + } + + String sign = offsetSeconds > 0 ? "+" : "-"; + int absOffsetSec = Math.abs(offsetSeconds); + int tzHour = absOffsetSec / ONE_HOUR_SEC; + int tzMin = absOffsetSec % ONE_HOUR_SEC / ONE_MIN_SEC; + String tzName = String.format(Locale.ENGLISH, "GMT%s%02d:%02d", sign, tzHour, tzMin); + return TimeZone.getTimeZone(tzName); + } + + +} diff --git a/embulk-output-mysql/src/main/java/org/embulk/output/mysql/MySQLOutputConnection.java b/embulk-output-mysql/src/main/java/org/embulk/output/mysql/MySQLOutputConnection.java index 3ae16b8a..3edc9632 100644 --- a/embulk-output-mysql/src/main/java/org/embulk/output/mysql/MySQLOutputConnection.java +++ b/embulk-output-mysql/src/main/java/org/embulk/output/mysql/MySQLOutputConnection.java @@ -4,6 +4,7 @@ import java.sql.Connection; import java.sql.SQLException; +import org.embulk.output.MySQLTimeZoneComparison; import org.embulk.output.jdbc.JdbcColumn; import org.embulk.output.jdbc.JdbcSchema; import org.embulk.output.jdbc.JdbcOutputConnection; @@ -110,4 +111,11 @@ protected String buildColumnTypeName(JdbcColumn c) return super.buildColumnTypeName(c); } } + + public void compareTimeZone() throws SQLException + { + MySQLTimeZoneComparison timeZoneComparison = new MySQLTimeZoneComparison(connection); + timeZoneComparison.compareTimeZone(); + } + }