embulk-input-mysql 0.8.0 → 0.8.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
}
|