embulk-input-mysql 0.8.0 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +9 -0
  3. data/build.gradle +1 -2
  4. data/classpath/embulk-input-jdbc-0.8.1.jar +0 -0
  5. data/classpath/embulk-input-mysql-0.8.1.jar +0 -0
  6. data/src/main/java/org/embulk/input/MySQLInputPlugin.java +54 -0
  7. data/src/main/java/org/embulk/input/mysql/MySQLInputConnection.java +14 -0
  8. data/src/main/java/org/embulk/input/mysql/getter/AbstractMySQLTimestampIncrementalHandler.java +75 -0
  9. data/src/main/java/org/embulk/input/mysql/getter/MySQLColumnGetterFactory.java +61 -0
  10. data/src/main/java/org/embulk/input/mysql/getter/MySQLDateTimeTimestampIncrementalHandler.java +45 -0
  11. data/src/main/java/org/embulk/input/mysql/getter/MySQLTimestampTimestampIncrementalHandler.java +42 -0
  12. data/src/test/java/org/embulk/input/mysql/BasicTest.java +137 -0
  13. data/src/test/java/org/embulk/input/mysql/IncrementalTest.java +107 -0
  14. data/src/test/java/org/embulk/input/mysql/MySQLTests.java +55 -0
  15. data/src/test/resources/org/embulk/input/mysql/test/expect/basic/setup.sql +65 -0
  16. data/src/test/resources/org/embulk/input/mysql/test/expect/basic/test_boolean_config.yml +13 -0
  17. data/src/test/resources/org/embulk/input/mysql/test/expect/basic/test_boolean_expected.csv +2 -0
  18. data/src/test/resources/org/embulk/input/mysql/test/expect/basic/test_boolean_expected.diff +2 -0
  19. data/src/test/resources/org/embulk/input/mysql/test/expect/basic/test_config.yml +2 -0
  20. data/src/test/resources/org/embulk/input/mysql/test/expect/basic/test_double_config.yml +13 -0
  21. data/src/test/resources/org/embulk/input/mysql/test/expect/basic/test_double_expected.csv +2 -0
  22. data/src/test/resources/org/embulk/input/mysql/test/expect/basic/test_double_expected.diff +2 -0
  23. data/src/test/resources/org/embulk/input/mysql/test/expect/basic/test_expected.csv +2 -0
  24. data/src/test/resources/org/embulk/input/mysql/test/expect/basic/test_expected.diff +2 -0
  25. data/src/test/resources/org/embulk/input/mysql/test/expect/basic/test_long_config.yml +13 -0
  26. data/src/test/resources/org/embulk/input/mysql/test/expect/basic/test_long_expected.csv +2 -0
  27. data/src/test/resources/org/embulk/input/mysql/test/expect/basic/test_long_expected.diff +2 -0
  28. data/src/test/resources/org/embulk/input/mysql/test/expect/basic/test_string_config.yml +13 -0
  29. data/src/test/resources/org/embulk/input/mysql/test/expect/basic/test_string_expected.csv +2 -0
  30. data/src/test/resources/org/embulk/input/mysql/test/expect/basic/test_string_expected.diff +2 -0
  31. data/src/test/resources/org/embulk/input/mysql/test/expect/basic/test_timestamp1_config.yml +13 -0
  32. data/src/test/resources/org/embulk/input/mysql/test/expect/basic/test_timestamp1_expected.csv +2 -0
  33. data/src/test/resources/org/embulk/input/mysql/test/expect/basic/test_timestamp1_expected.diff +2 -0
  34. data/src/test/resources/org/embulk/input/mysql/test/expect/basic/test_timestamp2_config.yml +8 -0
  35. data/src/test/resources/org/embulk/input/mysql/test/expect/basic/test_timestamp2_expected.csv +2 -0
  36. data/src/test/resources/org/embulk/input/mysql/test/expect/basic/test_timestamp2_expected.diff +2 -0
  37. data/src/test/resources/org/embulk/input/mysql/test/expect/basic/test_timestamp3_config.yml +9 -0
  38. data/src/test/resources/org/embulk/input/mysql/test/expect/basic/test_timestamp3_expected.csv +2 -0
  39. data/src/test/resources/org/embulk/input/mysql/test/expect/basic/test_timestamp3_expected.diff +2 -0
  40. data/src/test/resources/org/embulk/input/mysql/test/expect/basic/test_valuetype_decimal_config.yml +3 -0
  41. data/src/test/resources/org/embulk/input/mysql/test/expect/basic/test_valuetype_decimal_expected.csv +2 -0
  42. data/src/test/resources/org/embulk/input/mysql/test/expect/basic/test_valuetype_decimal_expected.diff +2 -0
  43. data/src/test/resources/org/embulk/input/mysql/test/expect/basic/test_valuetype_string_config.yml +3 -0
  44. data/src/test/resources/org/embulk/input/mysql/test/expect/basic/test_valuetype_string_expected.csv +2 -0
  45. data/src/test/resources/org/embulk/input/mysql/test/expect/basic/test_valuetype_string_expected.diff +2 -0
  46. data/src/test/resources/org/embulk/input/mysql/test/expect/incremental/dt/config_1.yml +5 -0
  47. data/src/test/resources/org/embulk/input/mysql/test/expect/incremental/dt/config_2.yml +5 -0
  48. data/src/test/resources/org/embulk/input/mysql/test/expect/incremental/dt/expected_1.csv +7 -0
  49. data/src/test/resources/org/embulk/input/mysql/test/expect/incremental/dt/expected_1.diff +3 -0
  50. data/src/test/resources/org/embulk/input/mysql/test/expect/incremental/dt/expected_2.csv +3 -0
  51. data/src/test/resources/org/embulk/input/mysql/test/expect/incremental/dt/expected_2.diff +3 -0
  52. data/src/test/resources/org/embulk/input/mysql/test/expect/incremental/dt/insert_more.sql +9 -0
  53. data/src/test/resources/org/embulk/input/mysql/test/expect/incremental/dt/setup.sql +16 -0
  54. data/src/test/resources/org/embulk/input/mysql/test/expect/incremental/int/config_1.yml +3 -0
  55. data/src/test/resources/org/embulk/input/mysql/test/expect/incremental/int/config_2.yml +4 -0
  56. data/src/test/resources/org/embulk/input/mysql/test/expect/incremental/int/expected_1.csv +4 -0
  57. data/src/test/resources/org/embulk/input/mysql/test/expect/incremental/int/expected_1.diff +3 -0
  58. data/src/test/resources/org/embulk/input/mysql/test/expect/incremental/int/expected_2.csv +2 -0
  59. data/src/test/resources/org/embulk/input/mysql/test/expect/incremental/int/expected_2.diff +3 -0
  60. data/src/test/resources/org/embulk/input/mysql/test/expect/incremental/int/insert_more.sql +7 -0
  61. data/src/test/resources/org/embulk/input/mysql/test/expect/incremental/int/setup.sql +13 -0
  62. data/src/test/resources/org/embulk/input/mysql/test/expect/incremental/ts/config_1.yml +5 -0
  63. data/src/test/resources/org/embulk/input/mysql/test/expect/incremental/ts/config_2.yml +5 -0
  64. data/src/test/resources/org/embulk/input/mysql/test/expect/incremental/ts/expected_1.csv +7 -0
  65. data/src/test/resources/org/embulk/input/mysql/test/expect/incremental/ts/expected_1.diff +3 -0
  66. data/src/test/resources/org/embulk/input/mysql/test/expect/incremental/ts/expected_2.csv +3 -0
  67. data/src/test/resources/org/embulk/input/mysql/test/expect/incremental/ts/expected_2.diff +3 -0
  68. data/src/test/resources/org/embulk/input/mysql/test/expect/incremental/ts/insert_more.sql +10 -0
  69. data/src/test/resources/org/embulk/input/mysql/test/expect/incremental/ts/setup.sql +18 -0
  70. metadata +66 -15
  71. data/classpath/embulk-input-jdbc-0.8.0.jar +0 -0
  72. data/classpath/embulk-input-mysql-0.8.0.jar +0 -0
  73. data/src/test/java/org/embulk/input/mysql/MySQLInputPluginTest.java +0 -242
  74. data/src/test/resources/mysql/yml/input-boolean.yml +0 -33
  75. data/src/test/resources/mysql/yml/input-double.yml +0 -33
  76. data/src/test/resources/mysql/yml/input-long.yml +0 -33
  77. data/src/test/resources/mysql/yml/input-string.yml +0 -33
  78. data/src/test/resources/mysql/yml/input-timestamp1.yml +0 -33
  79. data/src/test/resources/mysql/yml/input-timestamp2.yml +0 -22
  80. data/src/test/resources/mysql/yml/input-timestamp3.yml +0 -23
  81. data/src/test/resources/mysql/yml/input-valuetype-decimal.yml +0 -17
  82. data/src/test/resources/mysql/yml/input-valuetype-string.yml +0 -17
  83. data/src/test/resources/mysql/yml/input.yml +0 -22
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2144fd45cabb9eb049b87ef7307119912982544d
4
- data.tar.gz: 18b30e932ba4ae4db386f1ead1d6b93780c94830
3
+ metadata.gz: 4797ea2ce2deddb157e0d4804267a776bd163420
4
+ data.tar.gz: 13494a5d27aabf8cbea454ed97c0b25e4ce46077
5
5
  SHA512:
6
- metadata.gz: 82f1d70e1d75acfd47b71e1e679a4eb085dd4fbc22ef562807a1045b697f77f2980e64663807503a4b2fb55d93365b594ecd0b1f7492e597c5262bb3edce47b2
7
- data.tar.gz: 3ee4d8e3dd1570c230fdcd0ac684122998d728df75c143b7ac2b70355b2d91268424d675dcde52dfc46baa358e1f4d3a3ecb68959dd1e3561f642b776551d909
6
+ metadata.gz: dc654e504b7bceee5836fef9f3d57ec73a9b47ae39fc8f332a63866c6be097babb2f953f6a067a54055c90af4b6bc09bd9c2a7ea8e69d7b05504cb4047fb8739
7
+ data.tar.gz: aaa3cefa4f48abaa0e7bafe1bae8db92c29d8787c8a561ce65b13c70d2bced39a8ce135a389b48d85c9332c9c75ed459cc3aa47f4a85aa21b6bfbc3dd4df5215
data/README.md CHANGED
@@ -150,3 +150,12 @@ in:
150
150
  ```
151
151
  $ ./gradlew gem
152
152
  ```
153
+
154
+ Running tests:
155
+
156
+ ```
157
+ $ cp ci/travis_mysql.yml ci/mysql.yml # edit this file if necessary
158
+ $ EMBULK_INPUT_MYSQL_TEST_CONFIG=`pwd`/ci/mysql.yml ./gradlew :embulk-input-mysql:check --info
159
+ ```
160
+
161
+ This test data are expected by using 'UTC' as MySQL server's timezone. On the other hand, unit tests use 'Europe/Helsinki' as jdbc driver's session timezone.
data/build.gradle CHANGED
@@ -3,6 +3,5 @@ dependencies {
3
3
 
4
4
  compile 'mysql:mysql-connector-java:5.1.34'
5
5
 
6
- testCompile 'org.embulk:embulk-standards:0.8.8'
7
- testCompile project(':embulk-input-jdbc').sourceSets.test.output
6
+ testCompile 'org.embulk:embulk-standards:0.8.15'
8
7
  }
@@ -1,13 +1,22 @@
1
1
  package org.embulk.input;
2
2
 
3
+ import java.io.IOException;
4
+ import java.lang.reflect.Field;
3
5
  import java.util.Properties;
4
6
  import java.sql.Connection;
5
7
  import java.sql.Driver;
6
8
  import java.sql.SQLException;
9
+
10
+ import com.google.common.base.Throwables;
11
+ import com.mysql.jdbc.TimeUtil;
7
12
  import org.embulk.config.Config;
8
13
  import org.embulk.config.ConfigDefault;
9
14
  import org.embulk.input.jdbc.AbstractJdbcInputPlugin;
15
+ import org.embulk.input.jdbc.getter.ColumnGetterFactory;
10
16
  import org.embulk.input.mysql.MySQLInputConnection;
17
+ import org.embulk.input.mysql.getter.MySQLColumnGetterFactory;
18
+ import org.embulk.spi.PageBuilder;
19
+ import org.joda.time.DateTimeZone;
11
20
 
12
21
  public class MySQLInputPlugin
13
22
  extends AbstractJdbcInputPlugin
@@ -91,6 +100,9 @@ public class MySQLInputPlugin
91
100
 
92
101
  props.putAll(t.getOptions());
93
102
 
103
+ // load timezone mappings
104
+ loadTimeZoneMappings();
105
+
94
106
  Driver driver;
95
107
  try {
96
108
  driver = new com.mysql.jdbc.Driver(); // new com.mysql.jdbc.Driver throws SQLException
@@ -109,4 +121,46 @@ public class MySQLInputPlugin
109
121
  }
110
122
  }
111
123
  }
124
+
125
+ @Override
126
+ protected ColumnGetterFactory newColumnGetterFactory(PageBuilder pageBuilder, DateTimeZone dateTimeZone)
127
+ {
128
+ return new MySQLColumnGetterFactory(pageBuilder, dateTimeZone);
129
+ }
130
+
131
+ private void loadTimeZoneMappings()
132
+ {
133
+ // Here initializes com.mysql.jdbc.TimeUtil.timeZoneMappings static field by calling
134
+ // static timeZoneMappings method using reflection.
135
+ // The field is usually initialized when Driver#connect method is called. But the field
136
+ // initialization fails when a) useLegacyDatetimeCode=false is set AND b) mysql server's
137
+ // default_time_zone is not SYSTEM (default). According to the stacktrace, that's because
138
+ // the com.mysql.jdbc.TimeUtil.loadTimeZoneMappings can't find TimeZoneMapping.properties
139
+ // from the classloader. It seems like a bug of JDBC Driver where it should use the class loader
140
+ // that loaded com.mysql.jdbc.TimeUtil class rather than system class loader to read the
141
+ // property file because the file should be in the same classpath with the class.
142
+ // Here implements a workaround as as workaround.
143
+ Field f = null;
144
+ try {
145
+ f = TimeUtil.class.getDeclaredField("timeZoneMappings");
146
+ f.setAccessible(true);
147
+
148
+ Properties timeZoneMappings = (Properties) f.get(null);
149
+ if (timeZoneMappings == null) {
150
+ timeZoneMappings = new Properties();
151
+ synchronized (TimeUtil.class) {
152
+ timeZoneMappings.load(this.getClass().getResourceAsStream("/com/mysql/jdbc/TimeZoneMapping.properties"));
153
+ }
154
+ f.set(null, timeZoneMappings);
155
+ }
156
+ }
157
+ catch (IllegalAccessException | NoSuchFieldException | IOException e) {
158
+ throw Throwables.propagate(e);
159
+ }
160
+ finally {
161
+ if (f != null) {
162
+ f.setAccessible(false);
163
+ }
164
+ }
165
+ }
112
166
  }
@@ -5,6 +5,10 @@ import java.sql.Connection;
5
5
  import java.sql.PreparedStatement;
6
6
  import java.sql.SQLException;
7
7
  import java.sql.ResultSet;
8
+ import java.util.TimeZone;
9
+
10
+ import com.mysql.jdbc.ConnectionImpl;
11
+ import com.mysql.jdbc.ConnectionProperties;
8
12
  import org.embulk.input.jdbc.JdbcInputConnection;
9
13
  import org.embulk.input.jdbc.JdbcLiteral;
10
14
  import org.embulk.input.jdbc.getter.ColumnGetter;
@@ -45,4 +49,14 @@ public class MySQLInputConnection
45
49
  // Because socketTimeout is set in Connection, don't need to set quertyTimeout.
46
50
  return new SingleSelect(stmt);
47
51
  }
52
+
53
+ public boolean getUseLegacyDatetimeCode()
54
+ {
55
+ return ((ConnectionProperties) connection).getUseLegacyDatetimeCode();
56
+ }
57
+
58
+ public TimeZone getServerTimezoneTZ()
59
+ {
60
+ return ((ConnectionImpl) connection).getServerTimezoneTZ();
61
+ }
48
62
  }
@@ -0,0 +1,75 @@
1
+ package org.embulk.input.mysql.getter;
2
+
3
+ import com.fasterxml.jackson.databind.JsonNode;
4
+ import org.embulk.input.jdbc.getter.AbstractIncrementalHandler;
5
+ import org.embulk.input.jdbc.getter.ColumnGetter;
6
+ import org.embulk.spi.Column;
7
+ import org.embulk.spi.Exec;
8
+ import org.embulk.spi.time.TimestampFormatter;
9
+ import org.embulk.spi.time.TimestampFormatter.FormatterTask;
10
+ import org.embulk.spi.time.TimestampParser;
11
+ import org.embulk.spi.time.TimestampParser.ParserTask;
12
+ import org.joda.time.DateTimeZone;
13
+
14
+ import java.sql.PreparedStatement;
15
+ import java.sql.ResultSet;
16
+ import java.sql.SQLException;
17
+ import java.sql.Timestamp;
18
+
19
+ public abstract class AbstractMySQLTimestampIncrementalHandler
20
+ extends AbstractIncrementalHandler
21
+ {
22
+ protected final DateTimeZone sessionTimeZone;
23
+ protected long epochSecond;
24
+ protected int nano;
25
+
26
+ public AbstractMySQLTimestampIncrementalHandler(DateTimeZone sessionTimeZone, ColumnGetter next)
27
+ {
28
+ super(next);
29
+ this.sessionTimeZone = sessionTimeZone;
30
+ }
31
+
32
+ @Override
33
+ public void getAndSet(ResultSet from, int fromIndex, Column toColumn)
34
+ throws SQLException
35
+ {
36
+ Timestamp timestamp = from.getTimestamp(fromIndex);
37
+ if (timestamp != null) {
38
+ epochSecond = timestamp.getTime() / 1000;
39
+ nano = timestamp.getNanos();
40
+ }
41
+
42
+ super.getAndSet(from, fromIndex, toColumn);
43
+ }
44
+
45
+ @Override
46
+ public JsonNode encodeToJson()
47
+ {
48
+ FormatterTask task = Exec.newConfigSource()
49
+ .set("timezone", "UTC")
50
+ .loadConfig(FormatterTask.class);
51
+ TimestampFormatter formatter = new TimestampFormatter(getTimestampFormat(), task);
52
+ String text = formatter.format(utcTimestampFromSessionTime(epochSecond, nano));
53
+ return jsonNodeFactory.textNode(text);
54
+ }
55
+
56
+ protected abstract String getTimestampFormat();
57
+
58
+ protected abstract org.embulk.spi.time.Timestamp utcTimestampFromSessionTime(long epochSecond, int nano);
59
+
60
+ @Override
61
+ public void decodeFromJsonTo(PreparedStatement toStatement, int toIndex, JsonNode fromValue)
62
+ throws SQLException
63
+ {
64
+ ParserTask task = Exec.newConfigSource()
65
+ .set("default_timezone", "UTC")
66
+ .loadConfig(ParserTask.class);
67
+ TimestampParser parser = new TimestampParser(getTimestampPattern(), task);
68
+ org.embulk.spi.time.Timestamp epoch = parser.parse(fromValue.asText());
69
+ toStatement.setTimestamp(toIndex, utcTimestampToSessionTime(epoch));
70
+ }
71
+
72
+ protected abstract String getTimestampPattern();
73
+
74
+ protected abstract Timestamp utcTimestampToSessionTime(org.embulk.spi.time.Timestamp ts);
75
+ }
@@ -0,0 +1,61 @@
1
+ package org.embulk.input.mysql.getter;
2
+
3
+ import com.google.common.base.Optional;
4
+ import org.embulk.config.ConfigException;
5
+ import org.embulk.input.jdbc.AbstractJdbcInputPlugin.PluginTask;
6
+ import org.embulk.input.jdbc.JdbcColumn;
7
+ import org.embulk.input.jdbc.JdbcColumnOption;
8
+ import org.embulk.input.jdbc.JdbcInputConnection;
9
+ import org.embulk.input.jdbc.getter.ColumnGetter;
10
+ import org.embulk.input.jdbc.getter.ColumnGetterFactory;
11
+ import org.embulk.input.mysql.MySQLInputConnection;
12
+ import org.embulk.spi.PageBuilder;
13
+ import org.joda.time.DateTimeZone;
14
+
15
+ import java.util.TimeZone;
16
+
17
+ import static com.google.common.base.Preconditions.checkNotNull;
18
+
19
+ public class MySQLColumnGetterFactory
20
+ extends ColumnGetterFactory
21
+ {
22
+ public MySQLColumnGetterFactory(PageBuilder to, DateTimeZone defaultTimeZone)
23
+ {
24
+ super(to, defaultTimeZone);
25
+ }
26
+
27
+ @Override
28
+ public ColumnGetter newColumnGetter(JdbcInputConnection con, PluginTask task, JdbcColumn column, JdbcColumnOption option)
29
+ {
30
+ ColumnGetter getter = super.newColumnGetter(con, task, column, option);
31
+
32
+ switch (column.getTypeName()) {
33
+ case "DATETIME":
34
+ case "TIMESTAMP":
35
+ int index = task.getQuerySchema().findColumn(column.getName()).get();
36
+ if (!task.getIncremental() || !task.getIncrementalColumnIndexes().contains(index)) {
37
+ return getter;
38
+ }
39
+
40
+ // incremental loading
41
+ MySQLInputConnection mysqlInputConnection = (MySQLInputConnection) con;
42
+ // Users cannot use DATETIME or TIMESTAMP typed columns as incremental_columns: if 'useLegacyDatetimeCode=true'.
43
+ // That might be acceptable since mysql-connector-java v6.x will turn off, by default.
44
+ if (mysqlInputConnection.getUseLegacyDatetimeCode()) {
45
+ throw new ConfigException("Must use 'useLegacyDatetimeCode=false' if 'DATETIME' or 'TIMESTAMP' typed columns are used as incremental_columns:");
46
+ }
47
+
48
+ TimeZone timeZone = mysqlInputConnection.getServerTimezoneTZ();
49
+ // Joda-Time's timezone mapping is probably not compatible with java.util.TimeZone if null is returned.
50
+ DateTimeZone sessionTimeZone = checkNotNull(DateTimeZone.forTimeZone(timeZone));
51
+ if (column.getTypeName().equals("DATETIME")) {
52
+ return new MySQLDateTimeTimestampIncrementalHandler(sessionTimeZone, getter);
53
+ }
54
+ else { // TIMESTAMP
55
+ return new MySQLTimestampTimestampIncrementalHandler(sessionTimeZone, getter);
56
+ }
57
+ default:
58
+ return getter;
59
+ }
60
+ }
61
+ }
@@ -0,0 +1,45 @@
1
+ package org.embulk.input.mysql.getter;
2
+
3
+ import org.embulk.input.jdbc.getter.ColumnGetter;
4
+ import org.joda.time.DateTimeZone;
5
+
6
+ import java.sql.Timestamp;
7
+
8
+ public class MySQLDateTimeTimestampIncrementalHandler
9
+ extends AbstractMySQLTimestampIncrementalHandler
10
+ {
11
+ public MySQLDateTimeTimestampIncrementalHandler(DateTimeZone sessionTimeZone, ColumnGetter next)
12
+ {
13
+ super(sessionTimeZone, next);
14
+ }
15
+
16
+ @Override
17
+ public String getTimestampFormat()
18
+ {
19
+ return "%Y-%m-%dT%H:%M:%S.%6N";
20
+ }
21
+
22
+ @Override
23
+ public org.embulk.spi.time.Timestamp utcTimestampFromSessionTime(long epochSecond, int nano)
24
+ {
25
+ // this Timestamp value is already converted by session time_zone.
26
+ long reconverted = sessionTimeZone.convertUTCToLocal(epochSecond * 1000) / 1000; // reconvert from session time_zone to UTC
27
+ return org.embulk.spi.time.Timestamp.ofEpochSecond(reconverted, nano);
28
+ }
29
+
30
+ @Override
31
+ public String getTimestampPattern()
32
+ {
33
+ return "%Y-%m-%dT%H:%M:%S.%N";
34
+ }
35
+
36
+ @Override
37
+ public Timestamp utcTimestampToSessionTime(org.embulk.spi.time.Timestamp from)
38
+ {
39
+ // reconvert from UTC to session time_zone
40
+ long reconverted = sessionTimeZone.convertLocalToUTC(from.getEpochSecond() * 1000, false);
41
+ Timestamp sqlTimestamp = new Timestamp(reconverted);
42
+ sqlTimestamp.setNanos(from.getNano());
43
+ return sqlTimestamp;
44
+ }
45
+ }
@@ -0,0 +1,42 @@
1
+ package org.embulk.input.mysql.getter;
2
+
3
+ import org.embulk.input.jdbc.getter.ColumnGetter;
4
+ import org.joda.time.DateTimeZone;
5
+
6
+ import java.sql.Timestamp;
7
+
8
+ public class MySQLTimestampTimestampIncrementalHandler
9
+ extends AbstractMySQLTimestampIncrementalHandler
10
+ {
11
+ public MySQLTimestampTimestampIncrementalHandler(DateTimeZone sessionTimeZone, ColumnGetter next)
12
+ {
13
+ super(sessionTimeZone, next);
14
+ }
15
+
16
+ @Override
17
+ public String getTimestampFormat()
18
+ {
19
+ return "%Y-%m-%dT%H:%M:%S.%6NZ";
20
+ }
21
+
22
+ @Override
23
+ public org.embulk.spi.time.Timestamp utcTimestampFromSessionTime(long epochSecond, int nano)
24
+ {
25
+ long sec = sessionTimeZone.convertLocalToUTC(epochSecond * 1000, false) / 1000;
26
+ return org.embulk.spi.time.Timestamp.ofEpochSecond(sec, nano);
27
+ }
28
+
29
+ @Override
30
+ public String getTimestampPattern()
31
+ {
32
+ return "%Y-%m-%dT%H:%M:%S.%N%z";
33
+ }
34
+
35
+ @Override
36
+ public Timestamp utcTimestampToSessionTime(org.embulk.spi.time.Timestamp ts)
37
+ {
38
+ Timestamp sqlTimestamp = new Timestamp(ts.getEpochSecond() * 1000);
39
+ sqlTimestamp.setNanos(ts.getNano());
40
+ return sqlTimestamp;
41
+ }
42
+ }
@@ -0,0 +1,137 @@
1
+ package org.embulk.input.mysql;
2
+
3
+ import org.embulk.config.ConfigDiff;
4
+ import org.embulk.config.ConfigSource;
5
+ import org.embulk.input.MySQLInputPlugin;
6
+ import org.embulk.spi.InputPlugin;
7
+ import org.embulk.test.EmbulkTests;
8
+ import org.embulk.test.TestingEmbulk;
9
+ import org.junit.Before;
10
+ import org.junit.Rule;
11
+ import org.junit.Test;
12
+
13
+ import java.nio.file.Path;
14
+
15
+ import static org.embulk.input.mysql.MySQLTests.execute;
16
+ import static org.embulk.test.EmbulkTests.readSortedFile;
17
+ import static org.hamcrest.Matchers.is;
18
+ import static org.junit.Assert.assertThat;
19
+
20
+ public class BasicTest
21
+ {
22
+ private static final String BASIC_RESOURCE_PATH = "org/embulk/input/mysql/test/expect/basic/";
23
+
24
+ private static ConfigSource loadYamlResource(TestingEmbulk embulk, String fileName)
25
+ {
26
+ return embulk.loadYamlResource(BASIC_RESOURCE_PATH + fileName);
27
+ }
28
+
29
+ private static String readResource(String fileName)
30
+ {
31
+ return EmbulkTests.readResource(BASIC_RESOURCE_PATH + fileName);
32
+ }
33
+
34
+ @Rule
35
+ public TestingEmbulk embulk = TestingEmbulk.builder()
36
+ .registerPlugin(InputPlugin.class, "mysql", MySQLInputPlugin.class)
37
+ .build();
38
+
39
+ private ConfigSource baseConfig;
40
+
41
+ @Before
42
+ public void setup()
43
+ {
44
+ baseConfig = MySQLTests.baseConfig();
45
+ execute(readResource("setup.sql")); // setup rows
46
+ }
47
+
48
+ @Test
49
+ public void test() throws Exception
50
+ {
51
+ Path out1 = embulk.createTempFile("csv");
52
+ TestingEmbulk.RunResult result1 = embulk.runInput(baseConfig.merge(loadYamlResource(embulk, "test_config.yml")), out1);
53
+ assertThat(readSortedFile(out1), is(readResource("test_expected.csv")));
54
+ assertThat(result1.getConfigDiff(), is((ConfigDiff) loadYamlResource(embulk, "test_expected.diff")));
55
+ }
56
+
57
+ @Test
58
+ public void testString() throws Exception
59
+ {
60
+ Path out1 = embulk.createTempFile("csv");
61
+ TestingEmbulk.RunResult result1 = embulk.runInput(baseConfig.merge(loadYamlResource(embulk, "test_string_config.yml")), out1);
62
+ assertThat(readSortedFile(out1), is(readResource("test_string_expected.csv")));
63
+ assertThat(result1.getConfigDiff(), is((ConfigDiff) loadYamlResource(embulk, "test_string_expected.diff")));
64
+ }
65
+
66
+ @Test
67
+ public void testBoolean() throws Exception
68
+ {
69
+ Path out1 = embulk.createTempFile("csv");
70
+ TestingEmbulk.RunResult result1 = embulk.runInput(baseConfig.merge(loadYamlResource(embulk, "test_boolean_config.yml")), out1);
71
+ assertThat(readSortedFile(out1), is(readResource("test_boolean_expected.csv")));
72
+ assertThat(result1.getConfigDiff(), is((ConfigDiff) loadYamlResource(embulk, "test_boolean_expected.diff")));
73
+ }
74
+
75
+ @Test
76
+ public void testLong() throws Exception
77
+ {
78
+ Path out1 = embulk.createTempFile("csv");
79
+ TestingEmbulk.RunResult result1 = embulk.runInput(baseConfig.merge(loadYamlResource(embulk, "test_long_config.yml")), out1);
80
+ assertThat(readSortedFile(out1), is(readResource("test_long_expected.csv")));
81
+ assertThat(result1.getConfigDiff(), is((ConfigDiff) loadYamlResource(embulk, "test_long_expected.diff")));
82
+ }
83
+
84
+ @Test
85
+ public void testDouble() throws Exception
86
+ {
87
+ Path out1 = embulk.createTempFile("csv");
88
+ TestingEmbulk.RunResult result1 = embulk.runInput(baseConfig.merge(loadYamlResource(embulk, "test_double_config.yml")), out1);
89
+ assertThat(readSortedFile(out1), is(readResource("test_double_expected.csv")));
90
+ assertThat(result1.getConfigDiff(), is((ConfigDiff) loadYamlResource(embulk, "test_double_expected.diff")));
91
+ }
92
+
93
+ @Test
94
+ public void testTimestamp1() throws Exception
95
+ {
96
+ Path out1 = embulk.createTempFile("csv");
97
+ TestingEmbulk.RunResult result1 = embulk.runInput(baseConfig.merge(loadYamlResource(embulk, "test_timestamp1_config.yml")), out1);
98
+ assertThat(readSortedFile(out1), is(readResource("test_timestamp1_expected.csv")));
99
+ assertThat(result1.getConfigDiff(), is((ConfigDiff) loadYamlResource(embulk, "test_timestamp1_expected.diff")));
100
+ }
101
+
102
+ @Test
103
+ public void testTimestamp2() throws Exception
104
+ {
105
+ Path out1 = embulk.createTempFile("csv");
106
+ TestingEmbulk.RunResult result1 = embulk.runInput(baseConfig.merge(loadYamlResource(embulk, "test_timestamp2_config.yml")), out1);
107
+ assertThat(readSortedFile(out1), is(readResource("test_timestamp2_expected.csv")));
108
+ assertThat(result1.getConfigDiff(), is((ConfigDiff) loadYamlResource(embulk, "test_timestamp2_expected.diff")));
109
+ }
110
+
111
+ @Test
112
+ public void testTimestamp3() throws Exception
113
+ {
114
+ Path out1 = embulk.createTempFile("csv");
115
+ TestingEmbulk.RunResult result1 = embulk.runInput(baseConfig.merge(loadYamlResource(embulk, "test_timestamp3_config.yml")), out1);
116
+ assertThat(readSortedFile(out1), is(readResource("test_timestamp3_expected.csv")));
117
+ assertThat(result1.getConfigDiff(), is((ConfigDiff) loadYamlResource(embulk, "test_timestamp3_expected.diff")));
118
+ }
119
+
120
+ @Test
121
+ public void testValueTypeString() throws Exception
122
+ {
123
+ Path out1 = embulk.createTempFile("csv");
124
+ TestingEmbulk.RunResult result1 = embulk.runInput(baseConfig.merge(loadYamlResource(embulk, "test_valuetype_string_config.yml")), out1);
125
+ assertThat(readSortedFile(out1), is(readResource("test_valuetype_string_expected.csv")));
126
+ assertThat(result1.getConfigDiff(), is((ConfigDiff) loadYamlResource(embulk, "test_valuetype_string_expected.diff")));
127
+ }
128
+
129
+ @Test
130
+ public void testValueTypeDecimal() throws Exception
131
+ {
132
+ Path out1 = embulk.createTempFile("csv");
133
+ TestingEmbulk.RunResult result1 = embulk.runInput(baseConfig.merge(loadYamlResource(embulk, "test_valuetype_decimal_config.yml")), out1);
134
+ assertThat(readSortedFile(out1), is(readResource("test_valuetype_decimal_expected.csv")));
135
+ assertThat(result1.getConfigDiff(), is((ConfigDiff) loadYamlResource(embulk, "test_valuetype_decimal_expected.diff")));
136
+ }
137
+ }