embulk-output-mysql 0.7.7 → 0.8.0

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 (60) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +21 -0
  3. data/build.gradle +3 -3
  4. data/classpath/embulk-output-jdbc-0.8.0.jar +0 -0
  5. data/classpath/embulk-output-mysql-0.8.0.jar +0 -0
  6. data/default_jdbc_driver/mysql-connector-java-5.1.44.jar +0 -0
  7. data/src/main/java/org/embulk/output/MySQLOutputPlugin.java +56 -16
  8. data/src/main/java/org/embulk/output/MySQLTimeZoneComparison.java +107 -0
  9. data/src/main/java/org/embulk/output/mysql/MySQLOutputConnection.java +14 -5
  10. data/src/main/java/org/embulk/output/mysql/MySQLOutputConnector.java +3 -8
  11. data/src/test/java/org/embulk/output/mysql/AfterLoadTest.java +136 -0
  12. data/src/test/java/org/embulk/output/mysql/BeforeLoadTest.java +124 -0
  13. data/src/test/java/org/embulk/output/mysql/CreateTableTest.java +79 -0
  14. data/src/test/java/org/embulk/output/mysql/MySQLTests.java +69 -0
  15. data/src/test/resources/org/embulk/output/mysql/test/expect/after_load/setup.sql +8 -0
  16. data/src/test/resources/org/embulk/output/mysql/test/expect/after_load/test1.csv +4 -0
  17. data/src/test/resources/org/embulk/output/mysql/test/expect/after_load/test_expected.diff +2 -0
  18. data/src/test/resources/org/embulk/output/mysql/test/expect/after_load/test_insert_after_load.yml +3 -0
  19. data/src/test/resources/org/embulk/output/mysql/test/expect/after_load/test_insert_after_load_expected.csv +5 -0
  20. data/src/test/resources/org/embulk/output/mysql/test/expect/after_load/test_insert_direct_after_load.yml +3 -0
  21. data/src/test/resources/org/embulk/output/mysql/test/expect/after_load/test_merge_after_load.yml +3 -0
  22. data/src/test/resources/org/embulk/output/mysql/test/expect/after_load/test_merge_after_load_expected.csv +5 -0
  23. data/src/test/resources/org/embulk/output/mysql/test/expect/after_load/test_merge_direct_after_load.yml +3 -0
  24. data/src/test/resources/org/embulk/output/mysql/test/expect/after_load/test_replace_after_load.yml +3 -0
  25. data/src/test/resources/org/embulk/output/mysql/test/expect/after_load/test_replace_after_load_expected.csv +3 -0
  26. data/src/test/resources/org/embulk/output/mysql/test/expect/after_load/test_truncate_insert_after_load.yml +3 -0
  27. data/src/test/resources/org/embulk/output/mysql/test/expect/after_load/test_truncate_insert_after_load_expected.csv +3 -0
  28. data/src/test/resources/org/embulk/output/mysql/test/expect/before_load/setup.sql +8 -0
  29. data/src/test/resources/org/embulk/output/mysql/test/expect/before_load/test1.csv +4 -0
  30. data/src/test/resources/org/embulk/output/mysql/test/expect/before_load/test_expected.diff +2 -0
  31. data/src/test/resources/org/embulk/output/mysql/test/expect/before_load/test_insert_before_load.yml +3 -0
  32. data/src/test/resources/{mysql/data/test1.csv → org/embulk/output/mysql/test/expect/before_load/test_insert_before_load_expected.csv} +1 -0
  33. data/src/test/resources/org/embulk/output/mysql/test/expect/before_load/test_insert_direct_before_load.yml +3 -0
  34. data/src/test/resources/org/embulk/output/mysql/test/expect/before_load/test_merge_before_load.yml +3 -0
  35. data/src/test/resources/org/embulk/output/mysql/test/expect/before_load/test_merge_before_load_expected.csv +4 -0
  36. data/src/test/resources/org/embulk/output/mysql/test/expect/before_load/test_merge_direct_before_load.yml +3 -0
  37. data/src/test/resources/org/embulk/output/mysql/test/expect/before_load/test_truncate_insert_before_load.yml +3 -0
  38. data/src/test/resources/org/embulk/output/mysql/test/expect/before_load/test_truncate_insert_before_load_expected.csv +4 -0
  39. data/src/test/resources/org/embulk/output/mysql/test/expect/create_table/setup.sql +1 -0
  40. data/src/test/resources/org/embulk/output/mysql/test/expect/create_table/test1.csv +4 -0
  41. data/src/test/resources/org/embulk/output/mysql/test/expect/create_table/test_table_constraint.yml +5 -0
  42. data/src/test/resources/org/embulk/output/mysql/test/expect/create_table/test_table_constraint_expected.csv +3 -0
  43. data/src/test/resources/org/embulk/output/mysql/test/expect/create_table/test_table_option.yml +5 -0
  44. data/src/test/resources/org/embulk/output/mysql/test/expect/create_table/test_table_option_expected.csv +3 -0
  45. metadata +40 -18
  46. data/classpath/embulk-output-jdbc-0.7.7.jar +0 -0
  47. data/classpath/embulk-output-mysql-0.7.7.jar +0 -0
  48. data/classpath/mysql-connector-java-5.1.34.jar +0 -0
  49. data/src/test/java/org/embulk/output/mysql/MySQLOutputPluginTest.java +0 -569
  50. data/src/test/resources/mysql/yml/test-insert-after-load.yml +0 -22
  51. data/src/test/resources/mysql/yml/test-insert-before-load.yml +0 -22
  52. data/src/test/resources/mysql/yml/test-insert-direct-after-load.yml +0 -22
  53. data/src/test/resources/mysql/yml/test-insert-direct-before-load.yml +0 -22
  54. data/src/test/resources/mysql/yml/test-merge-after-load.yml +0 -22
  55. data/src/test/resources/mysql/yml/test-merge-before-load.yml +0 -22
  56. data/src/test/resources/mysql/yml/test-merge-direct-after-load.yml +0 -22
  57. data/src/test/resources/mysql/yml/test-merge-direct-before-load.yml +0 -22
  58. data/src/test/resources/mysql/yml/test-replace-after-load.yml +0 -22
  59. data/src/test/resources/mysql/yml/test-truncate-insert-after-load.yml +0 -22
  60. data/src/test/resources/mysql/yml/test-truncate-insert-before-load.yml +0 -22
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: bf58d4882f474c11125f531945a5048f350c0f39
4
- data.tar.gz: 2f28afb1f6bf1bcfdc700595f59eaaf0143984c7
3
+ metadata.gz: 6da5ba42634421a68e79de5f9c753a76d8406786
4
+ data.tar.gz: 7f80247c0f4c5fa8b973d9dca3914151f90815e5
5
5
  SHA512:
6
- metadata.gz: 227b8b0b5a95eb0c464a98a67a2824fb79d93c0491b97bcb729c0b15f624307d86095cdd5c1ed74afc2a424215ca87df070046fdcb2990f83b9398ac72e4e671
7
- data.tar.gz: 9536f2f57ae9a11a48a0b594b4f67157a8ff35bb83ba3528db9cf05544fec85c60c4ae8a0fd17b979d92e35c5b413e058c41236e0751ad6786fda2e821519fcd
6
+ metadata.gz: be36e44971e9d805842958a0acd90f69cbde13c141df4e727aff2fcd05158452d463ebfe7d36ff476643e76a71f0793494dc694e1687083ea46892ef5e59955f
7
+ data.tar.gz: 2bbf372969dd29e6368d32da9c29db14322f9035c4291696853d7c8d6f7a75261dae5086b063a09efe5435fa53a57359eb00d8f22b127ec9d493affd86600d46
data/README.md CHANGED
@@ -10,12 +10,17 @@ MySQL output plugin for Embulk loads records to MySQL.
10
10
 
11
11
  ## Configuration
12
12
 
13
+ - **driver_path**: path to the jar file of the MySQL JDBC driver. If not set, the bundled JDBC driver (MySQL Connector/J 5.1.44) will be used (string). NOTE: the bundled JDBC driver version was upgrade from 5.1.34 to 5.1.44 at embulk-output-mysql 0.8.0 . Please check release notes for MySQL Connector/J (https://dev.mysql.com/doc/relnotes/connector-j/5.1/en/news-5-1.html) .
13
14
  - **host**: database host name (string, required)
14
15
  - **port**: database port number (integer, default: 3306)
15
16
  - **user**: database login user name (string, required)
16
17
  - **password**: database login password (string, default: "")
18
+ - **ssl**: use SSL to connect to the database (string, default: `disable`. `enable` uses SSL without server-side validation and `verify` checks the certificate. For compatibility reasons, `true` behaves as `enable` and `false` behaves as `disable`.)
17
19
  - **database**: destination database name (string, required)
20
+ - **temp_database**: database name for intermediate tables. by default, intermediate tables will be created in the database specified by `database`. (string, optional)
18
21
  - **table**: destination table name (string, required)
22
+ - **create_table_constraint** table constraint added to `CREATE TABLE` statement, like `CREATE TABLE <table_name> (<column1> <type1>, <column2> <type2>, ..., <create_table_constraint>) <create_table_option>`.
23
+ - **create_table_option** table option added to `CREATE TABLE` statement, like `CREATE TABLE <table_name> (<column1> <type1>, <column2> <type2>, ..., <create_table_constraint>) <create_table_option>`.
19
24
  - **options**: extra connection properties (hash, default: {})
20
25
  - **retry_limit** max retry count for database operations (integer, default: 12)
21
26
  - **retry_wait** initial retry wait time in milliseconds (integer, default: 1000 (1 second))
@@ -118,3 +123,19 @@ out:
118
123
  ```
119
124
  $ ./gradlew gem
120
125
  ```
126
+
127
+ Running tests:
128
+
129
+ You need to create 'mysql.yml' as follows.
130
+ ```
131
+ type: mysql
132
+ host: localhost
133
+ port: 3306
134
+ database: database
135
+ user: user
136
+ password: pass
137
+ ```
138
+
139
+ ```
140
+ $ EMBULK_OUTPUT_MYSQL_TEST_CONFIG=mysql.yml ./gradlew :embulk-output-mysql:check --info
141
+ ```
data/build.gradle CHANGED
@@ -1,7 +1,7 @@
1
1
  dependencies {
2
2
  compile project(':embulk-output-jdbc')
3
- compile 'mysql:mysql-connector-java:5.1.34'
3
+ compile 'mysql:mysql-connector-java:5.1.44'
4
+ defaultJdbcDriver 'mysql:mysql-connector-java:5.1.44'
4
5
 
5
- testCompile 'org.embulk:embulk-standards:0.8.8'
6
- testCompile project(':embulk-output-jdbc').sourceSets.test.output
6
+ testCompile 'org.embulk:embulk-standards:0.8.22'
7
7
  }
@@ -3,14 +3,21 @@ package org.embulk.output;
3
3
  import java.util.Properties;
4
4
  import java.io.IOException;
5
5
  import java.sql.SQLException;
6
+
6
7
  import com.google.common.base.Optional;
8
+
7
9
  import org.embulk.config.Config;
8
10
  import org.embulk.config.ConfigDefault;
9
11
  import org.embulk.output.jdbc.AbstractJdbcOutputPlugin;
12
+ import org.embulk.output.jdbc.Ssl;
10
13
  import org.embulk.output.jdbc.BatchInsert;
14
+ import org.embulk.output.jdbc.JdbcOutputConnection;
11
15
  import org.embulk.output.jdbc.MergeConfig;
16
+ import org.embulk.output.jdbc.TableIdentifier;
17
+ import org.embulk.output.mysql.MySQLOutputConnection;
12
18
  import org.embulk.output.mysql.MySQLOutputConnector;
13
19
  import org.embulk.output.mysql.MySQLBatchInsert;
20
+ import org.embulk.spi.Schema;
14
21
 
15
22
  public class MySQLOutputPlugin
16
23
  extends AbstractJdbcOutputPlugin
@@ -18,6 +25,10 @@ public class MySQLOutputPlugin
18
25
  public interface MySQLPluginTask
19
26
  extends PluginTask
20
27
  {
28
+ @Config("driver_path")
29
+ @ConfigDefault("null")
30
+ public Optional<String> getDriverPath();
31
+
21
32
  @Config("host")
22
33
  public String getHost();
23
34
 
@@ -34,6 +45,15 @@ public class MySQLOutputPlugin
34
45
 
35
46
  @Config("database")
36
47
  public String getDatabase();
48
+
49
+ @Config("temp_database")
50
+ @ConfigDefault("null")
51
+ public Optional<String> getTempDatabase();
52
+
53
+ @Config("ssl")
54
+ @ConfigDefault("\"disable\"") // backward compatibility
55
+ public Ssl getSsl();
56
+
37
57
  }
38
58
 
39
59
  @Override
@@ -55,6 +75,8 @@ public class MySQLOutputPlugin
55
75
  {
56
76
  MySQLPluginTask t = (MySQLPluginTask) task;
57
77
 
78
+ loadDriver("com.mysql.jdbc.Driver", t.getDriverPath());
79
+
58
80
  String url = String.format("jdbc:mysql://%s:%d/%s",
59
81
  t.getHost(), t.getPort(), t.getDatabase());
60
82
 
@@ -70,21 +92,21 @@ public class MySQLOutputPlugin
70
92
  // Socket options TCP_KEEPCNT, TCP_KEEPIDLE, and TCP_KEEPINTVL are not configurable.
71
93
  props.setProperty("tcpKeepAlive", "true");
72
94
 
73
- // TODO
74
- //switch t.getSssl() {
75
- //when "disable":
76
- // break;
77
- //when "enable":
78
- // props.setProperty("useSSL", "true");
79
- // props.setProperty("requireSSL", "false");
80
- // props.setProperty("verifyServerCertificate", "false");
81
- // break;
82
- //when "verify":
83
- // props.setProperty("useSSL", "true");
84
- // props.setProperty("requireSSL", "true");
85
- // props.setProperty("verifyServerCertificate", "true");
86
- // break;
87
- //}
95
+ switch (t.getSsl()) {
96
+ case DISABLE:
97
+ props.setProperty("useSSL", "false");
98
+ break;
99
+ case ENABLE:
100
+ props.setProperty("useSSL", "true");
101
+ props.setProperty("requireSSL", "true");
102
+ props.setProperty("verifyServerCertificate", "false");
103
+ break;
104
+ case VERIFY:
105
+ props.setProperty("useSSL", "true");
106
+ props.setProperty("requireSSL", "true");
107
+ props.setProperty("verifyServerCertificate", "true");
108
+ break;
109
+ }
88
110
 
89
111
  if (!retryableMetadataOperation) {
90
112
  // non-retryable batch operation uses longer timeout
@@ -97,12 +119,21 @@ public class MySQLOutputPlugin
97
119
  // TODO validate task.getMergeKeys is null
98
120
 
99
121
  props.setProperty("user", t.getUser());
100
- logger.info("Connecting to {} options {}", url, props);
101
122
  props.setProperty("password", t.getPassword());
123
+ logConnectionProperties(url, props);
102
124
 
103
125
  return new MySQLOutputConnector(url, props);
104
126
  }
105
127
 
128
+ @Override
129
+ protected TableIdentifier buildIntermediateTableId(JdbcOutputConnection con, PluginTask task, String tableName) {
130
+ MySQLPluginTask t = (MySQLPluginTask) task;
131
+ if (t.getTempDatabase().isPresent()) {
132
+ return new TableIdentifier(t.getTempDatabase().get(), null, tableName);
133
+ }
134
+ return super.buildIntermediateTableId(con, task, tableName);
135
+ }
136
+
106
137
  @Override
107
138
  protected BatchInsert newBatchInsert(PluginTask task, Optional<MergeConfig> mergeConfig) throws IOException, SQLException
108
139
  {
@@ -122,4 +153,13 @@ public class MySQLOutputPlugin
122
153
  return false;
123
154
  }
124
155
  }
156
+
157
+ @Override
158
+ protected void doBegin(JdbcOutputConnection con,
159
+ PluginTask task, final Schema schema, int taskCount) throws SQLException
160
+ {
161
+ MySQLOutputConnection mySQLCon = (MySQLOutputConnection)con;
162
+ mySQLCon.compareTimeZone();
163
+ super.doBegin(con,task,schema,taskCount);
164
+ }
125
165
  }
@@ -0,0 +1,107 @@
1
+ package org.embulk.output;
2
+
3
+ import org.embulk.spi.Exec;
4
+ import org.slf4j.Logger;
5
+
6
+
7
+ import java.sql.Connection;
8
+ import java.sql.ResultSet;
9
+ import java.sql.SQLException;
10
+ import java.sql.Statement;
11
+ import java.util.Date;
12
+ import java.util.Locale;
13
+ import java.util.TimeZone;
14
+
15
+ public class MySQLTimeZoneComparison {
16
+
17
+ private static final int ONE_HOUR_SEC = 3600;
18
+ private static final int ONE_MIN_SEC = 60;
19
+
20
+ private Connection connection;
21
+
22
+ private final Logger logger = Exec.getLogger(getClass());
23
+
24
+ public MySQLTimeZoneComparison(Connection connection)
25
+ {
26
+ this.connection = connection;
27
+ }
28
+
29
+ public void compareTimeZone()
30
+ throws SQLException
31
+ {
32
+ TimeZone serverTimeZone = null;
33
+ try {
34
+ serverTimeZone = getServerTimeZone();
35
+ }
36
+ catch (SQLException ex) {
37
+ logger.warn("Can't get server TimeZone.");
38
+ logger.warn(String.format(Locale.ENGLISH, "SQLException raised %s", ex.toString()));
39
+ }
40
+
41
+ TimeZone clientTimeZone = TimeZone.getDefault();
42
+ Date today = new Date();
43
+ int clientOffset = clientTimeZone.getRawOffset();
44
+
45
+ if (clientTimeZone.inDaylightTime(today)) {
46
+ clientOffset += clientTimeZone.getDSTSavings();
47
+ }
48
+
49
+ //
50
+ // Compare offset only. Although I expect to return true, the following code return false,
51
+ //
52
+ // TimeZone tz_jst = TimeZone.getTimeZone("JST");
53
+ // TimeZone tz_gmt9 = TimeZone.getTimeZone("GMT+9");
54
+ // tz_jst.hasSameRules(tz_gmt9) // return false.
55
+ //
56
+ if (clientOffset != serverTimeZone.getRawOffset()) {
57
+ logger.warn(String.format(Locale.ENGLISH,
58
+ "The client timezone(%s) is different from the server timezone(%s). The plugin will store wrong datetime values.",
59
+ clientTimeZone.getID(), serverTimeZone.getID()));
60
+ logger.warn(String.format(Locale.ENGLISH,
61
+ "You may need to set options `useLegacyDatetimeCode` and `serverTimezone`"));
62
+ logger.warn(String.format(Locale.ENGLISH,
63
+ "Example. `options: { useLegacyDatetimeCode: false, serverTimezone: UTC }`"));
64
+ }
65
+ logger.warn(String.format(Locale.ENGLISH, "The plugin will set `useLegacyDatetimeCode=false` by default in future."));
66
+ }
67
+
68
+ private TimeZone getServerTimeZone()
69
+ throws SQLException
70
+ {
71
+ //
72
+ // First, I used `@@system_time_zone`. but It return non Time Zone Abbreviations name on a specific platform.
73
+ // So, This method calculate GMT offset with query.
74
+ //
75
+ String query = "select TIME_TO_SEC(timediff(now(),utc_timestamp()));";
76
+ Statement stmt = connection.createStatement();
77
+
78
+ try {
79
+ ResultSet rs = stmt.executeQuery(query);
80
+ if (rs.next()) {
81
+ int offsetSeconds = rs.getInt(1);
82
+ return fromGMTOffsetSeconds(offsetSeconds);
83
+ }
84
+ throw new SQLException(String.format(Locale.ENGLISH,
85
+ "The timezone comparison query(%s) doesn't return the result.",query));
86
+ }
87
+ finally {
88
+ stmt.close();
89
+ }
90
+ }
91
+
92
+ private TimeZone fromGMTOffsetSeconds(int offsetSeconds)
93
+ {
94
+ if (offsetSeconds == 0) {
95
+ return TimeZone.getTimeZone("UTC");
96
+ }
97
+
98
+ String sign = offsetSeconds > 0 ? "+" : "-";
99
+ int absOffsetSec = Math.abs(offsetSeconds);
100
+ int tzHour = absOffsetSec / ONE_HOUR_SEC;
101
+ int tzMin = absOffsetSec % ONE_HOUR_SEC / ONE_MIN_SEC;
102
+ String tzName = String.format(Locale.ENGLISH, "GMT%s%02d:%02d", sign, tzHour, tzMin);
103
+ return TimeZone.getTimeZone(tzName);
104
+ }
105
+
106
+
107
+ }
@@ -4,10 +4,12 @@ import java.util.List;
4
4
  import java.sql.Connection;
5
5
  import java.sql.SQLException;
6
6
 
7
+ import org.embulk.output.MySQLTimeZoneComparison;
7
8
  import org.embulk.output.jdbc.JdbcColumn;
8
9
  import org.embulk.output.jdbc.JdbcSchema;
9
10
  import org.embulk.output.jdbc.JdbcOutputConnection;
10
11
  import org.embulk.output.jdbc.MergeConfig;
12
+ import org.embulk.output.jdbc.TableIdentifier;
11
13
 
12
14
  public class MySQLOutputConnection
13
15
  extends JdbcOutputConnection
@@ -20,12 +22,12 @@ public class MySQLOutputConnection
20
22
  }
21
23
 
22
24
  @Override
23
- protected String buildPreparedMergeSql(String toTable, JdbcSchema toTableSchema, MergeConfig mergeConfig) throws SQLException
25
+ protected String buildPreparedMergeSql(TableIdentifier toTable, JdbcSchema toTableSchema, MergeConfig mergeConfig) throws SQLException
24
26
  {
25
27
  StringBuilder sb = new StringBuilder();
26
28
 
27
29
  sb.append("INSERT INTO ");
28
- quoteIdentifierString(sb, toTable);
30
+ quoteTableIdentifier(sb, toTable);
29
31
  sb.append(" (");
30
32
  for (int i = 0; i < toTableSchema.getCount(); i++) {
31
33
  if(i != 0) { sb.append(", "); }
@@ -58,12 +60,12 @@ public class MySQLOutputConnection
58
60
  }
59
61
 
60
62
  @Override
61
- protected String buildCollectMergeSql(List<String> fromTables, JdbcSchema schema, String toTable, MergeConfig mergeConfig) throws SQLException
63
+ protected String buildCollectMergeSql(List<TableIdentifier> fromTables, JdbcSchema schema, TableIdentifier toTable, MergeConfig mergeConfig) throws SQLException
62
64
  {
63
65
  StringBuilder sb = new StringBuilder();
64
66
 
65
67
  sb.append("INSERT INTO ");
66
- quoteIdentifierString(sb, toTable);
68
+ quoteTableIdentifier(sb, toTable);
67
69
  sb.append(" (");
68
70
  for (int i = 0; i < schema.getCount(); i++) {
69
71
  if (i != 0) { sb.append(", "); }
@@ -78,7 +80,7 @@ public class MySQLOutputConnection
78
80
  quoteIdentifierString(sb, schema.getColumnName(j));
79
81
  }
80
82
  sb.append(" FROM ");
81
- quoteIdentifierString(sb, fromTables.get(i));
83
+ quoteTableIdentifier(sb, fromTables.get(i));
82
84
  }
83
85
  sb.append(" ON DUPLICATE KEY UPDATE ");
84
86
  if (mergeConfig.getMergeRule().isPresent()) {
@@ -110,4 +112,11 @@ public class MySQLOutputConnection
110
112
  return super.buildColumnTypeName(c);
111
113
  }
112
114
  }
115
+
116
+ public void compareTimeZone() throws SQLException
117
+ {
118
+ MySQLTimeZoneComparison timeZoneComparison = new MySQLTimeZoneComparison(connection);
119
+ timeZoneComparison.compareTimeZone();
120
+ }
121
+
113
122
  }
@@ -1,25 +1,20 @@
1
1
  package org.embulk.output.mysql;
2
2
 
3
3
  import java.util.Properties;
4
- import java.sql.Driver;
5
4
  import java.sql.Connection;
5
+ import java.sql.DriverManager;
6
6
  import java.sql.SQLException;
7
+
7
8
  import org.embulk.output.jdbc.JdbcOutputConnector;
8
9
 
9
10
  public class MySQLOutputConnector
10
11
  implements JdbcOutputConnector
11
12
  {
12
- private final Driver driver;
13
13
  private final String url;
14
14
  private final Properties properties;
15
15
 
16
16
  public MySQLOutputConnector(String url, Properties properties)
17
17
  {
18
- try {
19
- this.driver = new com.mysql.jdbc.Driver(); // new com.mysql.jdbc.Driver throws SQLException
20
- } catch (SQLException ex) {
21
- throw new RuntimeException(ex);
22
- }
23
18
  this.url = url;
24
19
  this.properties = properties;
25
20
  }
@@ -27,7 +22,7 @@ public class MySQLOutputConnector
27
22
  @Override
28
23
  public MySQLOutputConnection connect(boolean autoCommit) throws SQLException
29
24
  {
30
- Connection c = driver.connect(url, properties);
25
+ Connection c = DriverManager.getConnection(url, properties);
31
26
  try {
32
27
  MySQLOutputConnection con = new MySQLOutputConnection(c, autoCommit);
33
28
  c = null;
@@ -0,0 +1,136 @@
1
+ package org.embulk.output.mysql;
2
+
3
+ import static org.embulk.output.mysql.MySQLTests.execute;
4
+ import static org.embulk.output.mysql.MySQLTests.selectRecords;
5
+ import static org.hamcrest.Matchers.is;
6
+ import static org.junit.Assert.assertThat;
7
+
8
+ import java.io.File;
9
+ import java.net.URISyntaxException;
10
+ import java.net.URL;
11
+ import java.nio.file.FileSystems;
12
+ import java.nio.file.Path;
13
+
14
+ import org.embulk.config.ConfigDiff;
15
+ import org.embulk.config.ConfigSource;
16
+ import org.embulk.output.MySQLOutputPlugin;
17
+ import org.embulk.spi.OutputPlugin;
18
+ import org.embulk.test.EmbulkTests;
19
+ import org.embulk.test.TestingEmbulk;
20
+ import org.junit.Before;
21
+ import org.junit.Rule;
22
+ import org.junit.Test;
23
+
24
+ import com.google.common.io.Resources;
25
+
26
+ public class AfterLoadTest
27
+ {
28
+ private static final String BASIC_RESOURCE_PATH = "org/embulk/output/mysql/test/expect/after_load/";
29
+
30
+ private static ConfigSource loadYamlResource(TestingEmbulk embulk, String fileName)
31
+ {
32
+ return embulk.loadYamlResource(BASIC_RESOURCE_PATH + fileName);
33
+ }
34
+
35
+ private static String readResource(String fileName)
36
+ {
37
+ return EmbulkTests.readResource(BASIC_RESOURCE_PATH + fileName);
38
+ }
39
+
40
+ @Rule
41
+ public TestingEmbulk embulk = TestingEmbulk.builder()
42
+ .registerPlugin(OutputPlugin.class, "mysql", MySQLOutputPlugin.class)
43
+ .build();
44
+
45
+ private ConfigSource baseConfig;
46
+
47
+ @Before
48
+ public void setup()
49
+ {
50
+ baseConfig = MySQLTests.baseConfig();
51
+ execute(readResource("setup.sql")); // setup rows
52
+ }
53
+
54
+ @Test
55
+ public void testInsertAfterLoad() throws Exception
56
+ {
57
+ execute("insert into test1 values('B001', 0, 'z')");
58
+ execute("insert into test1 values('B002', 9, 'z')");
59
+
60
+ Path in1 = toPath("test1.csv");
61
+ TestingEmbulk.RunResult result1 = embulk.runOutput(baseConfig.merge(loadYamlResource(embulk, "test_insert_after_load.yml")), in1);
62
+ assertThat(selectRecords(embulk, "test1"), is(readResource("test_insert_after_load_expected.csv")));
63
+ //assertThat(result1.getConfigDiff(), is((ConfigDiff) loadYamlResource(embulk, "test_expected.diff")));
64
+ }
65
+
66
+ @Test
67
+ public void testInsertDirectAfterLoad() throws Exception
68
+ {
69
+ execute("insert into test1 values('B001', 0, 'z')");
70
+ execute("insert into test1 values('B002', 9, 'z')");
71
+
72
+ Path in1 = toPath("test1.csv");
73
+ TestingEmbulk.RunResult result1 = embulk.runOutput(baseConfig.merge(loadYamlResource(embulk, "test_insert_direct_after_load.yml")), in1);
74
+ assertThat(selectRecords(embulk, "test1"), is(readResource("test_insert_after_load_expected.csv")));
75
+ //assertThat(result1.getConfigDiff(), is((ConfigDiff) loadYamlResource(embulk, "test_expected.diff")));
76
+ }
77
+
78
+ @Test
79
+ public void testTruncateInsertAfterLoad() throws Exception
80
+ {
81
+ execute("insert into test1 values('B001', 0, 'z')");
82
+ execute("insert into test1 values('B002', 9, 'z')");
83
+
84
+ Path in1 = toPath("test1.csv");
85
+ TestingEmbulk.RunResult result1 = embulk.runOutput(baseConfig.merge(loadYamlResource(embulk, "test_replace_after_load.yml")), in1);
86
+ assertThat(selectRecords(embulk, "test1"), is(readResource("test_replace_after_load_expected.csv")));
87
+ //assertThat(result1.getConfigDiff(), is((ConfigDiff) loadYamlResource(embulk, "test_expected.diff")));
88
+ }
89
+
90
+ @Test
91
+ public void testReplaceAfterLoad() throws Exception
92
+ {
93
+ execute("insert into test1 values('B001', 0, 'z')");
94
+ execute("insert into test1 values('B002', 9, 'z')");
95
+
96
+ Path in1 = toPath("test1.csv");
97
+ TestingEmbulk.RunResult result1 = embulk.runOutput(baseConfig.merge(loadYamlResource(embulk, "test_truncate_insert_after_load.yml")), in1);
98
+ assertThat(selectRecords(embulk, "test1"), is(readResource("test_truncate_insert_after_load_expected.csv")));
99
+ //assertThat(result1.getConfigDiff(), is((ConfigDiff) loadYamlResource(embulk, "test_expected.diff")));
100
+ }
101
+
102
+ @Test
103
+ public void testMergeAfterLoad() throws Exception
104
+ {
105
+ execute("insert into test1 values('A002', 1, 'y')");
106
+ execute("insert into test1 values('A003', 1, 'y')");
107
+ execute("insert into test1 values('B001', 0, 'z')");
108
+ execute("insert into test1 values('B002', 9, 'z')");
109
+
110
+ Path in1 = toPath("test1.csv");
111
+ TestingEmbulk.RunResult result1 = embulk.runOutput(baseConfig.merge(loadYamlResource(embulk, "test_merge_after_load.yml")), in1);
112
+ assertThat(selectRecords(embulk, "test1"), is(readResource("test_merge_after_load_expected.csv")));
113
+ //assertThat(result1.getConfigDiff(), is((ConfigDiff) loadYamlResource(embulk, "test_expected.diff")));
114
+ }
115
+
116
+ @Test
117
+ public void testMergeDirectAfterLoad() throws Exception
118
+ {
119
+ execute("insert into test1 values('A002', 1, 'y')");
120
+ execute("insert into test1 values('A003', 1, 'y')");
121
+ execute("insert into test1 values('B001', 0, 'z')");
122
+ execute("insert into test1 values('B002', 9, 'z')");
123
+
124
+ Path in1 = toPath("test1.csv");
125
+ TestingEmbulk.RunResult result1 = embulk.runOutput(baseConfig.merge(loadYamlResource(embulk, "test_merge_direct_after_load.yml")), in1);
126
+ assertThat(selectRecords(embulk, "test1"), is(readResource("test_merge_after_load_expected.csv")));
127
+ //assertThat(result1.getConfigDiff(), is((ConfigDiff) loadYamlResource(embulk, "test_expected.diff")));
128
+ }
129
+
130
+ private Path toPath(String fileName) throws URISyntaxException
131
+ {
132
+ URL url = Resources.getResource(BASIC_RESOURCE_PATH + fileName);
133
+ return FileSystems.getDefault().getPath(new File(url.toURI()).getAbsolutePath());
134
+ }
135
+
136
+ }
@@ -0,0 +1,124 @@
1
+ package org.embulk.output.mysql;
2
+
3
+ import static org.embulk.output.mysql.MySQLTests.execute;
4
+ import static org.embulk.output.mysql.MySQLTests.selectRecords;
5
+ import static org.hamcrest.Matchers.is;
6
+ import static org.junit.Assert.assertThat;
7
+
8
+ import java.io.File;
9
+ import java.net.URISyntaxException;
10
+ import java.net.URL;
11
+ import java.nio.file.FileSystems;
12
+ import java.nio.file.Path;
13
+
14
+ import org.embulk.config.ConfigDiff;
15
+ import org.embulk.config.ConfigSource;
16
+ import org.embulk.output.MySQLOutputPlugin;
17
+ import org.embulk.spi.OutputPlugin;
18
+ import org.embulk.test.EmbulkTests;
19
+ import org.embulk.test.TestingEmbulk;
20
+ import org.junit.Before;
21
+ import org.junit.Rule;
22
+ import org.junit.Test;
23
+
24
+ import com.google.common.io.Resources;
25
+
26
+ public class BeforeLoadTest
27
+ {
28
+ private static final String BASIC_RESOURCE_PATH = "org/embulk/output/mysql/test/expect/before_load/";
29
+
30
+ private static ConfigSource loadYamlResource(TestingEmbulk embulk, String fileName)
31
+ {
32
+ return embulk.loadYamlResource(BASIC_RESOURCE_PATH + fileName);
33
+ }
34
+
35
+ private static String readResource(String fileName)
36
+ {
37
+ return EmbulkTests.readResource(BASIC_RESOURCE_PATH + fileName);
38
+ }
39
+
40
+ @Rule
41
+ public TestingEmbulk embulk = TestingEmbulk.builder()
42
+ .registerPlugin(OutputPlugin.class, "mysql", MySQLOutputPlugin.class)
43
+ .build();
44
+
45
+ private ConfigSource baseConfig;
46
+
47
+ @Before
48
+ public void setup()
49
+ {
50
+ baseConfig = MySQLTests.baseConfig();
51
+ execute(readResource("setup.sql")); // setup rows
52
+ }
53
+
54
+ @Test
55
+ public void testInsertBeforeLoad() throws Exception
56
+ {
57
+ execute("insert into test1 values('B001', 0, 'z')");
58
+ execute("insert into test1 values('B002', 9, 'z')");
59
+
60
+ Path in1 = toPath("test1.csv");
61
+ TestingEmbulk.RunResult result1 = embulk.runOutput(baseConfig.merge(loadYamlResource(embulk, "test_insert_before_load.yml")), in1);
62
+ assertThat(selectRecords(embulk, "test1"), is(readResource("test_insert_before_load_expected.csv")));
63
+ //assertThat(result1.getConfigDiff(), is((ConfigDiff) loadYamlResource(embulk, "test_expected.diff")));
64
+ }
65
+
66
+ @Test
67
+ public void testInsertDirectBeforeLoad() throws Exception
68
+ {
69
+ execute("insert into test1 values('B001', 0, 'z')");
70
+ execute("insert into test1 values('B002', 9, 'z')");
71
+
72
+ Path in1 = toPath("test1.csv");
73
+ TestingEmbulk.RunResult result1 = embulk.runOutput(baseConfig.merge(loadYamlResource(embulk, "test_insert_direct_before_load.yml")), in1);
74
+ assertThat(selectRecords(embulk, "test1"), is(readResource("test_insert_before_load_expected.csv")));
75
+ //assertThat(result1.getConfigDiff(), is((ConfigDiff) loadYamlResource(embulk, "test_expected.diff")));
76
+ }
77
+
78
+ @Test
79
+ public void testTruncateInsertBeforeLoad() throws Exception
80
+ {
81
+ execute("insert into test1 values('B001', 0, 'z')");
82
+ execute("insert into test1 values('B002', 9, 'z')");
83
+
84
+ Path in1 = toPath("test1.csv");
85
+ TestingEmbulk.RunResult result1 = embulk.runOutput(baseConfig.merge(loadYamlResource(embulk, "test_truncate_insert_before_load.yml")), in1);
86
+ assertThat(selectRecords(embulk, "test1"), is(readResource("test_truncate_insert_before_load_expected.csv")));
87
+ //assertThat(result1.getConfigDiff(), is((ConfigDiff) loadYamlResource(embulk, "test_expected.diff")));
88
+ }
89
+
90
+ @Test
91
+ public void testMergeBeforeLoad() throws Exception
92
+ {
93
+ execute("insert into test1 values('A002', 1, 'y')");
94
+ execute("insert into test1 values('A003', 1, 'y')");
95
+ execute("insert into test1 values('B001', 0, 'z')");
96
+ execute("insert into test1 values('B002', 9, 'z')");
97
+
98
+ Path in1 = toPath("test1.csv");
99
+ TestingEmbulk.RunResult result1 = embulk.runOutput(baseConfig.merge(loadYamlResource(embulk, "test_merge_before_load.yml")), in1);
100
+ assertThat(selectRecords(embulk, "test1"), is(readResource("test_merge_before_load_expected.csv")));
101
+ //assertThat(result1.getConfigDiff(), is((ConfigDiff) loadYamlResource(embulk, "test_expected.diff")));
102
+ }
103
+
104
+ @Test
105
+ public void testMergeDirectBeforeLoad() throws Exception
106
+ {
107
+ execute("insert into test1 values('A002', 1, 'y')");
108
+ execute("insert into test1 values('A003', 1, 'y')");
109
+ execute("insert into test1 values('B001', 0, 'z')");
110
+ execute("insert into test1 values('B002', 9, 'z')");
111
+
112
+ Path in1 = toPath("test1.csv");
113
+ TestingEmbulk.RunResult result1 = embulk.runOutput(baseConfig.merge(loadYamlResource(embulk, "test_merge_direct_before_load.yml")), in1);
114
+ assertThat(selectRecords(embulk, "test1"), is(readResource("test_merge_before_load_expected.csv")));
115
+ //assertThat(result1.getConfigDiff(), is((ConfigDiff) loadYamlResource(embulk, "test_expected.diff")));
116
+ }
117
+
118
+ private Path toPath(String fileName) throws URISyntaxException
119
+ {
120
+ URL url = Resources.getResource(BASIC_RESOURCE_PATH + fileName);
121
+ return FileSystems.getDefault().getPath(new File(url.toURI()).getAbsolutePath());
122
+ }
123
+
124
+ }