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.
- checksums.yaml +4 -4
- data/README.md +9 -0
- data/build.gradle +1 -2
- data/classpath/embulk-input-jdbc-0.8.1.jar +0 -0
- data/classpath/embulk-input-mysql-0.8.1.jar +0 -0
- data/src/main/java/org/embulk/input/MySQLInputPlugin.java +54 -0
- data/src/main/java/org/embulk/input/mysql/MySQLInputConnection.java +14 -0
- data/src/main/java/org/embulk/input/mysql/getter/AbstractMySQLTimestampIncrementalHandler.java +75 -0
- data/src/main/java/org/embulk/input/mysql/getter/MySQLColumnGetterFactory.java +61 -0
- data/src/main/java/org/embulk/input/mysql/getter/MySQLDateTimeTimestampIncrementalHandler.java +45 -0
- data/src/main/java/org/embulk/input/mysql/getter/MySQLTimestampTimestampIncrementalHandler.java +42 -0
- data/src/test/java/org/embulk/input/mysql/BasicTest.java +137 -0
- data/src/test/java/org/embulk/input/mysql/IncrementalTest.java +107 -0
- data/src/test/java/org/embulk/input/mysql/MySQLTests.java +55 -0
- data/src/test/resources/org/embulk/input/mysql/test/expect/basic/setup.sql +65 -0
- data/src/test/resources/org/embulk/input/mysql/test/expect/basic/test_boolean_config.yml +13 -0
- data/src/test/resources/org/embulk/input/mysql/test/expect/basic/test_boolean_expected.csv +2 -0
- data/src/test/resources/org/embulk/input/mysql/test/expect/basic/test_boolean_expected.diff +2 -0
- data/src/test/resources/org/embulk/input/mysql/test/expect/basic/test_config.yml +2 -0
- data/src/test/resources/org/embulk/input/mysql/test/expect/basic/test_double_config.yml +13 -0
- data/src/test/resources/org/embulk/input/mysql/test/expect/basic/test_double_expected.csv +2 -0
- data/src/test/resources/org/embulk/input/mysql/test/expect/basic/test_double_expected.diff +2 -0
- data/src/test/resources/org/embulk/input/mysql/test/expect/basic/test_expected.csv +2 -0
- data/src/test/resources/org/embulk/input/mysql/test/expect/basic/test_expected.diff +2 -0
- data/src/test/resources/org/embulk/input/mysql/test/expect/basic/test_long_config.yml +13 -0
- data/src/test/resources/org/embulk/input/mysql/test/expect/basic/test_long_expected.csv +2 -0
- data/src/test/resources/org/embulk/input/mysql/test/expect/basic/test_long_expected.diff +2 -0
- data/src/test/resources/org/embulk/input/mysql/test/expect/basic/test_string_config.yml +13 -0
- data/src/test/resources/org/embulk/input/mysql/test/expect/basic/test_string_expected.csv +2 -0
- data/src/test/resources/org/embulk/input/mysql/test/expect/basic/test_string_expected.diff +2 -0
- data/src/test/resources/org/embulk/input/mysql/test/expect/basic/test_timestamp1_config.yml +13 -0
- data/src/test/resources/org/embulk/input/mysql/test/expect/basic/test_timestamp1_expected.csv +2 -0
- data/src/test/resources/org/embulk/input/mysql/test/expect/basic/test_timestamp1_expected.diff +2 -0
- data/src/test/resources/org/embulk/input/mysql/test/expect/basic/test_timestamp2_config.yml +8 -0
- data/src/test/resources/org/embulk/input/mysql/test/expect/basic/test_timestamp2_expected.csv +2 -0
- data/src/test/resources/org/embulk/input/mysql/test/expect/basic/test_timestamp2_expected.diff +2 -0
- data/src/test/resources/org/embulk/input/mysql/test/expect/basic/test_timestamp3_config.yml +9 -0
- data/src/test/resources/org/embulk/input/mysql/test/expect/basic/test_timestamp3_expected.csv +2 -0
- data/src/test/resources/org/embulk/input/mysql/test/expect/basic/test_timestamp3_expected.diff +2 -0
- data/src/test/resources/org/embulk/input/mysql/test/expect/basic/test_valuetype_decimal_config.yml +3 -0
- data/src/test/resources/org/embulk/input/mysql/test/expect/basic/test_valuetype_decimal_expected.csv +2 -0
- data/src/test/resources/org/embulk/input/mysql/test/expect/basic/test_valuetype_decimal_expected.diff +2 -0
- data/src/test/resources/org/embulk/input/mysql/test/expect/basic/test_valuetype_string_config.yml +3 -0
- data/src/test/resources/org/embulk/input/mysql/test/expect/basic/test_valuetype_string_expected.csv +2 -0
- data/src/test/resources/org/embulk/input/mysql/test/expect/basic/test_valuetype_string_expected.diff +2 -0
- data/src/test/resources/org/embulk/input/mysql/test/expect/incremental/dt/config_1.yml +5 -0
- data/src/test/resources/org/embulk/input/mysql/test/expect/incremental/dt/config_2.yml +5 -0
- data/src/test/resources/org/embulk/input/mysql/test/expect/incremental/dt/expected_1.csv +7 -0
- data/src/test/resources/org/embulk/input/mysql/test/expect/incremental/dt/expected_1.diff +3 -0
- data/src/test/resources/org/embulk/input/mysql/test/expect/incremental/dt/expected_2.csv +3 -0
- data/src/test/resources/org/embulk/input/mysql/test/expect/incremental/dt/expected_2.diff +3 -0
- data/src/test/resources/org/embulk/input/mysql/test/expect/incremental/dt/insert_more.sql +9 -0
- data/src/test/resources/org/embulk/input/mysql/test/expect/incremental/dt/setup.sql +16 -0
- data/src/test/resources/org/embulk/input/mysql/test/expect/incremental/int/config_1.yml +3 -0
- data/src/test/resources/org/embulk/input/mysql/test/expect/incremental/int/config_2.yml +4 -0
- data/src/test/resources/org/embulk/input/mysql/test/expect/incremental/int/expected_1.csv +4 -0
- data/src/test/resources/org/embulk/input/mysql/test/expect/incremental/int/expected_1.diff +3 -0
- data/src/test/resources/org/embulk/input/mysql/test/expect/incremental/int/expected_2.csv +2 -0
- data/src/test/resources/org/embulk/input/mysql/test/expect/incremental/int/expected_2.diff +3 -0
- data/src/test/resources/org/embulk/input/mysql/test/expect/incremental/int/insert_more.sql +7 -0
- data/src/test/resources/org/embulk/input/mysql/test/expect/incremental/int/setup.sql +13 -0
- data/src/test/resources/org/embulk/input/mysql/test/expect/incremental/ts/config_1.yml +5 -0
- data/src/test/resources/org/embulk/input/mysql/test/expect/incremental/ts/config_2.yml +5 -0
- data/src/test/resources/org/embulk/input/mysql/test/expect/incremental/ts/expected_1.csv +7 -0
- data/src/test/resources/org/embulk/input/mysql/test/expect/incremental/ts/expected_1.diff +3 -0
- data/src/test/resources/org/embulk/input/mysql/test/expect/incremental/ts/expected_2.csv +3 -0
- data/src/test/resources/org/embulk/input/mysql/test/expect/incremental/ts/expected_2.diff +3 -0
- data/src/test/resources/org/embulk/input/mysql/test/expect/incremental/ts/insert_more.sql +10 -0
- data/src/test/resources/org/embulk/input/mysql/test/expect/incremental/ts/setup.sql +18 -0
- metadata +66 -15
- data/classpath/embulk-input-jdbc-0.8.0.jar +0 -0
- data/classpath/embulk-input-mysql-0.8.0.jar +0 -0
- data/src/test/java/org/embulk/input/mysql/MySQLInputPluginTest.java +0 -242
- data/src/test/resources/mysql/yml/input-boolean.yml +0 -33
- data/src/test/resources/mysql/yml/input-double.yml +0 -33
- data/src/test/resources/mysql/yml/input-long.yml +0 -33
- data/src/test/resources/mysql/yml/input-string.yml +0 -33
- data/src/test/resources/mysql/yml/input-timestamp1.yml +0 -33
- data/src/test/resources/mysql/yml/input-timestamp2.yml +0 -22
- data/src/test/resources/mysql/yml/input-timestamp3.yml +0 -23
- data/src/test/resources/mysql/yml/input-valuetype-decimal.yml +0 -17
- data/src/test/resources/mysql/yml/input-valuetype-string.yml +0 -17
- 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:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4797ea2ce2deddb157e0d4804267a776bd163420
|
|
4
|
+
data.tar.gz: 13494a5d27aabf8cbea454ed97c0b25e4ce46077
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
|
Binary file
|
|
Binary file
|
|
@@ -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
|
}
|
data/src/main/java/org/embulk/input/mysql/getter/AbstractMySQLTimestampIncrementalHandler.java
ADDED
|
@@ -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
|
+
}
|
data/src/main/java/org/embulk/input/mysql/getter/MySQLDateTimeTimestampIncrementalHandler.java
ADDED
|
@@ -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
|
+
}
|
data/src/main/java/org/embulk/input/mysql/getter/MySQLTimestampTimestampIncrementalHandler.java
ADDED
|
@@ -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
|
+
}
|