embulk-output-sqlserver 0.7.1 → 0.7.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +7 -1
- data/classpath/{embulk-output-jdbc-0.7.1.jar → embulk-output-jdbc-0.7.2.jar} +0 -0
- data/classpath/{embulk-output-sqlserver-0.7.1.jar → embulk-output-sqlserver-0.7.2.jar} +0 -0
- data/src/main/java/org/embulk/output/SQLServerOutputPlugin.java +2 -1
- data/src/main/java/org/embulk/output/sqlserver/SQLServerOutputConnection.java +61 -4
- data/src/test/java/org/embulk/output/sqlserver/SQLServerOutputPluginTest.java +140 -1
- data/src/test/resources/sqlserver/data/test6/test6.csv +4 -0
- data/src/test/resources/sqlserver/yml/test-merge-keys.yml +23 -0
- data/src/test/resources/sqlserver/yml/test-merge-rule.yml +22 -0
- data/src/test/resources/sqlserver/yml/test-merge.yml +21 -0
- metadata +8 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 83928aeb58e8e44cd1e3ddd359a5f0bc91a8b480
|
4
|
+
data.tar.gz: ebcde6ea3c960f1a962750e41e43732fe9bcff60
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0321e417ca209e078b1c9f183f3332f23068f7b6ae0abfd2115f2c15ebbd3c6aa9b6a0b97c2f6e45a44114fd462234e6765e3c882929fa76d91fd2cc651141e6
|
7
|
+
data.tar.gz: 8a939954de682d79658f854fd62ccbd42857be89c579c7ed22b1d44993c2ed0653910d6e4529bd82403558ca05b92c7be1999257d369908f665b965fe0fb6937
|
data/README.md
CHANGED
@@ -28,7 +28,9 @@ embulk "-J-Djava.library.path=C:\drivers" run input-sqlserver.yml
|
|
28
28
|
- **retry_limit** max retry count for database operations (integer, default: 12)
|
29
29
|
- **retry_wait** initial retry wait time in milliseconds (integer, default: 1000 (1 second))
|
30
30
|
- **max_retry_wait** upper limit of retry wait, which will be doubled at every retry (integer, default: 1800000 (30 minutes))
|
31
|
-
- **mode**: "insert", "insert_direct", "truncate_insert"
|
31
|
+
- **mode**: "insert", "insert_direct", "truncate_insert" , "replace" or "merge". See below. (string, required)
|
32
|
+
- **merge_keys**: key column names for merging records in merge mode (string array, required in merge mode if table doesn't have primary key)
|
33
|
+
- **merge_rule**: list of column assignments for updating existing records used in merge mode, for example `foo = T.foo + S.foo` (`T` means target table and `S` means source table). (string array, default: always overwrites with new values)
|
32
34
|
- **insert_method**: see below
|
33
35
|
- **batch_size**: size of a single batch insert (integer, default: 16777216)
|
34
36
|
- **default_timezone**: If input column type (embulk type) is timestamp, this plugin needs to format the timestamp into a SQL string. This default_timezone option is used to control the timezone. You can overwrite timezone for each columns using column_options option. (string, default: `UTC`)
|
@@ -57,6 +59,10 @@ embulk "-J-Djava.library.path=C:\drivers" run input-sqlserver.yml
|
|
57
59
|
* Behavior: This mode writes rows to an intermediate table first. If all those tasks run correctly, drops the target table and alters the name of the intermediate table into the target table name.
|
58
60
|
* Transactional: No. If fails, the target table could be dropped (because SQL Server can't rollback DDL).
|
59
61
|
* Resumable: No.
|
62
|
+
* **merge**:
|
63
|
+
* Behavior: This mode writes rows to some intermediate tables first. If all those tasks run correctly, runs `MERGE INTO ... WHEN MATCHED THEN UPDATE ... WHEN NOT MATCHED THEN INSERT ...` query. Namely, if merge keys of a record in the intermediate tables already exist in the target table, the target record is updated by the intermediate record, otherwise the intermediate record is inserted. If the target table doesn't exist, it is created automatically.
|
64
|
+
* Transactional: Yes.
|
65
|
+
* Resumable: Yes.
|
60
66
|
|
61
67
|
### Insert methods
|
62
68
|
|
Binary file
|
Binary file
|
@@ -2,6 +2,7 @@ package org.embulk.output;
|
|
2
2
|
|
3
3
|
import com.google.common.base.Optional;
|
4
4
|
import com.google.common.collect.ImmutableSet;
|
5
|
+
|
5
6
|
import org.embulk.config.Config;
|
6
7
|
import org.embulk.config.ConfigDefault;
|
7
8
|
import org.embulk.config.ConfigException;
|
@@ -103,7 +104,7 @@ public class SQLServerOutputPlugin
|
|
103
104
|
{
|
104
105
|
return new Features()
|
105
106
|
.setMaxTableNameLength(128)
|
106
|
-
.setSupportedModes(ImmutableSet.of(Mode.INSERT, Mode.INSERT_DIRECT, Mode.TRUNCATE_INSERT, Mode.REPLACE))
|
107
|
+
.setSupportedModes(ImmutableSet.of(Mode.INSERT, Mode.INSERT_DIRECT, Mode.MERGE, Mode.TRUNCATE_INSERT, Mode.REPLACE))
|
107
108
|
.setIgnoreMergeKeys(false);
|
108
109
|
}
|
109
110
|
|
@@ -4,10 +4,12 @@ import java.sql.Connection;
|
|
4
4
|
import java.sql.SQLException;
|
5
5
|
import java.sql.Statement;
|
6
6
|
import java.util.Arrays;
|
7
|
+
import java.util.List;
|
7
8
|
|
8
9
|
import org.embulk.output.jdbc.JdbcColumn;
|
9
10
|
import org.embulk.output.jdbc.JdbcOutputConnection;
|
10
11
|
import org.embulk.output.jdbc.JdbcSchema;
|
12
|
+
import org.embulk.output.jdbc.MergeConfig;
|
11
13
|
|
12
14
|
public class SQLServerOutputConnection
|
13
15
|
extends JdbcOutputConnection
|
@@ -113,12 +115,67 @@ public class SQLServerOutputConnection
|
|
113
115
|
return super.getColumnDeclareType(convertedTypeName, col);
|
114
116
|
}
|
115
117
|
|
116
|
-
/*
|
117
118
|
@Override
|
118
|
-
|
119
|
+
protected String buildCollectMergeSql(List<String> fromTables, JdbcSchema schema, String toTable, MergeConfig mergeConfig) throws SQLException
|
119
120
|
{
|
120
|
-
|
121
|
+
StringBuilder sb = new StringBuilder();
|
122
|
+
|
123
|
+
sb.append("MERGE INTO ");
|
124
|
+
sb.append(quoteIdentifierString(toTable));
|
125
|
+
sb.append(" AS T");
|
126
|
+
sb.append(" USING (");
|
127
|
+
for (int i = 0; i < fromTables.size(); i++) {
|
128
|
+
if (i != 0) { sb.append(" UNION ALL "); }
|
129
|
+
sb.append(" SELECT ");
|
130
|
+
sb.append(buildColumns(schema, ""));
|
131
|
+
sb.append(" FROM ");
|
132
|
+
sb.append(quoteIdentifierString(fromTables.get(i)));
|
133
|
+
}
|
134
|
+
sb.append(") AS S");
|
135
|
+
sb.append(" ON (");
|
136
|
+
for (int i = 0; i < mergeConfig.getMergeKeys().size(); i++) {
|
137
|
+
if (i != 0) { sb.append(" AND "); }
|
138
|
+
String mergeKey = quoteIdentifierString(mergeConfig.getMergeKeys().get(i));
|
139
|
+
sb.append("T.");
|
140
|
+
sb.append(mergeKey);
|
141
|
+
sb.append(" = S.");
|
142
|
+
sb.append(mergeKey);
|
143
|
+
}
|
144
|
+
sb.append(")");
|
145
|
+
sb.append(" WHEN MATCHED THEN");
|
146
|
+
sb.append(" UPDATE SET ");
|
147
|
+
if (mergeConfig.getMergeRule().isPresent()) {
|
148
|
+
for (int i = 0; i < mergeConfig.getMergeRule().get().size(); i++) {
|
149
|
+
if (i != 0) { sb.append(", "); }
|
150
|
+
sb.append(mergeConfig.getMergeRule().get().get(i));
|
151
|
+
}
|
152
|
+
} else {
|
153
|
+
for (int i = 0; i < schema.getCount(); i++) {
|
154
|
+
if (i != 0) { sb.append(", "); }
|
155
|
+
String column = quoteIdentifierString(schema.getColumnName(i));
|
156
|
+
sb.append(column);
|
157
|
+
sb.append(" = S.");
|
158
|
+
sb.append(column);
|
159
|
+
}
|
160
|
+
}
|
161
|
+
sb.append(" WHEN NOT MATCHED THEN");
|
162
|
+
sb.append(" INSERT (");
|
163
|
+
sb.append(buildColumns(schema, ""));
|
164
|
+
sb.append(") VALUES (");
|
165
|
+
sb.append(buildColumns(schema, "S."));
|
166
|
+
sb.append(");");
|
167
|
+
|
168
|
+
return sb.toString();
|
121
169
|
}
|
122
170
|
|
123
|
-
|
171
|
+
private String buildColumns(JdbcSchema schema, String prefix)
|
172
|
+
{
|
173
|
+
StringBuilder sb = new StringBuilder();
|
174
|
+
for (int i = 0; i < schema.getCount(); i++) {
|
175
|
+
if (i != 0) { sb.append(", "); }
|
176
|
+
sb.append(prefix);
|
177
|
+
sb.append(quoteIdentifierString(schema.getColumnName(i)));
|
178
|
+
}
|
179
|
+
return sb.toString();
|
180
|
+
}
|
124
181
|
}
|
@@ -34,7 +34,7 @@ public class SQLServerOutputPluginTest extends AbstractJdbcOutputPluginTest
|
|
34
34
|
try {
|
35
35
|
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
|
36
36
|
} catch (ClassNotFoundException e) {
|
37
|
-
System.err.println("Warning: you should put 'sqljdbc41.jar' in 'embulk-
|
37
|
+
System.err.println("Warning: you should put 'sqljdbc41.jar' in 'embulk-output-sqlserver/driver' directory in order to test.");
|
38
38
|
return;
|
39
39
|
}
|
40
40
|
|
@@ -358,6 +358,145 @@ public class SQLServerOutputPluginTest extends AbstractJdbcOutputPluginTest
|
|
358
358
|
}
|
359
359
|
}
|
360
360
|
|
361
|
+
@Test
|
362
|
+
public void testMerge() throws Exception
|
363
|
+
{
|
364
|
+
if (!enabled) {
|
365
|
+
return;
|
366
|
+
}
|
367
|
+
|
368
|
+
String table = "TEST6";
|
369
|
+
|
370
|
+
dropTable(table);
|
371
|
+
executeSQL(String.format("CREATE TABLE %S (ITEM1 INT, ITEM2 INT, ITEM3 VARCHAR(4), PRIMARY KEY(ITEM1, ITEM2))", table));
|
372
|
+
executeSQL(String.format("INSERT INTO %S VALUES(10, 20, 'A')", table));
|
373
|
+
executeSQL(String.format("INSERT INTO %S VALUES(10, 21, 'B')", table));
|
374
|
+
executeSQL(String.format("INSERT INTO %S VALUES(11, 20, 'C')", table));
|
375
|
+
|
376
|
+
test("/sqlserver/yml/test-merge.yml");
|
377
|
+
|
378
|
+
assertMergedTable(table);
|
379
|
+
}
|
380
|
+
|
381
|
+
@Test
|
382
|
+
public void testMergeWithKeys() throws Exception
|
383
|
+
{
|
384
|
+
if (!enabled) {
|
385
|
+
return;
|
386
|
+
}
|
387
|
+
|
388
|
+
String table = "TEST6b";
|
389
|
+
|
390
|
+
dropTable(table);
|
391
|
+
executeSQL(String.format("CREATE TABLE %S (ITEM1 INT, ITEM2 INT, ITEM3 VARCHAR(4))", table));
|
392
|
+
executeSQL(String.format("INSERT INTO %S VALUES(10, 20, 'A')", table));
|
393
|
+
executeSQL(String.format("INSERT INTO %S VALUES(10, 21, 'B')", table));
|
394
|
+
executeSQL(String.format("INSERT INTO %S VALUES(11, 20, 'C')", table));
|
395
|
+
|
396
|
+
test("/sqlserver/yml/test-merge-keys.yml");
|
397
|
+
|
398
|
+
assertMergedTable(table);
|
399
|
+
}
|
400
|
+
|
401
|
+
@Test
|
402
|
+
public void testMergeWithRule() throws Exception
|
403
|
+
{
|
404
|
+
if (!enabled) {
|
405
|
+
return;
|
406
|
+
}
|
407
|
+
|
408
|
+
String table = "TEST6";
|
409
|
+
|
410
|
+
dropTable(table);
|
411
|
+
executeSQL(String.format("CREATE TABLE %S (ITEM1 INT, ITEM2 INT, ITEM3 VARCHAR(4), PRIMARY KEY(ITEM1, ITEM2))", table));
|
412
|
+
executeSQL(String.format("INSERT INTO %S VALUES(10, 20, 'A')", table));
|
413
|
+
executeSQL(String.format("INSERT INTO %S VALUES(10, 21, 'B')", table));
|
414
|
+
executeSQL(String.format("INSERT INTO %S VALUES(11, 20, 'C')", table));
|
415
|
+
|
416
|
+
test("/sqlserver/yml/test-merge-rule.yml");
|
417
|
+
|
418
|
+
List<List<Object>> rows = select(table);
|
419
|
+
assertEquals(6, rows.size());
|
420
|
+
{
|
421
|
+
List<Object> row = rows.get(0);
|
422
|
+
assertEquals(Integer.valueOf(10), row.get(0));
|
423
|
+
assertEquals(Integer.valueOf(20), row.get(1));
|
424
|
+
assertEquals("A", row.get(2));
|
425
|
+
}
|
426
|
+
{
|
427
|
+
List<Object> row = rows.get(1);
|
428
|
+
assertEquals(Integer.valueOf(10), row.get(0));
|
429
|
+
assertEquals(Integer.valueOf(21), row.get(1));
|
430
|
+
assertEquals("Baa", row.get(2));
|
431
|
+
}
|
432
|
+
{
|
433
|
+
List<Object> row = rows.get(2);
|
434
|
+
assertEquals(Integer.valueOf(10), row.get(0));
|
435
|
+
assertEquals(Integer.valueOf(22), row.get(1));
|
436
|
+
assertEquals("dd", row.get(2));
|
437
|
+
}
|
438
|
+
{
|
439
|
+
List<Object> row = rows.get(3);
|
440
|
+
assertEquals(Integer.valueOf(11), row.get(0));
|
441
|
+
assertEquals(Integer.valueOf(10), row.get(1));
|
442
|
+
assertEquals("bb", row.get(2));
|
443
|
+
}
|
444
|
+
{
|
445
|
+
List<Object> row = rows.get(4);
|
446
|
+
assertEquals(Integer.valueOf(11), row.get(0));
|
447
|
+
assertEquals(Integer.valueOf(20), row.get(1));
|
448
|
+
assertEquals("C", row.get(2));
|
449
|
+
}
|
450
|
+
{
|
451
|
+
List<Object> row = rows.get(5);
|
452
|
+
assertEquals(Integer.valueOf(12), row.get(0));
|
453
|
+
assertEquals(Integer.valueOf(20), row.get(1));
|
454
|
+
assertEquals("cc", row.get(2));
|
455
|
+
}
|
456
|
+
}
|
457
|
+
|
458
|
+
private void assertMergedTable(String table) throws Exception
|
459
|
+
{
|
460
|
+
List<List<Object>> rows = select(table);
|
461
|
+
assertEquals(6, rows.size());
|
462
|
+
{
|
463
|
+
List<Object> row = rows.get(0);
|
464
|
+
assertEquals(Integer.valueOf(10), row.get(0));
|
465
|
+
assertEquals(Integer.valueOf(20), row.get(1));
|
466
|
+
assertEquals("A", row.get(2));
|
467
|
+
}
|
468
|
+
{
|
469
|
+
List<Object> row = rows.get(1);
|
470
|
+
assertEquals(Integer.valueOf(10), row.get(0));
|
471
|
+
assertEquals(Integer.valueOf(21), row.get(1));
|
472
|
+
assertEquals("aa", row.get(2));
|
473
|
+
}
|
474
|
+
{
|
475
|
+
List<Object> row = rows.get(2);
|
476
|
+
assertEquals(Integer.valueOf(10), row.get(0));
|
477
|
+
assertEquals(Integer.valueOf(22), row.get(1));
|
478
|
+
assertEquals("dd", row.get(2));
|
479
|
+
}
|
480
|
+
{
|
481
|
+
List<Object> row = rows.get(3);
|
482
|
+
assertEquals(Integer.valueOf(11), row.get(0));
|
483
|
+
assertEquals(Integer.valueOf(10), row.get(1));
|
484
|
+
assertEquals("bb", row.get(2));
|
485
|
+
}
|
486
|
+
{
|
487
|
+
List<Object> row = rows.get(4);
|
488
|
+
assertEquals(Integer.valueOf(11), row.get(0));
|
489
|
+
assertEquals(Integer.valueOf(20), row.get(1));
|
490
|
+
assertEquals("C", row.get(2));
|
491
|
+
}
|
492
|
+
{
|
493
|
+
List<Object> row = rows.get(5);
|
494
|
+
assertEquals(Integer.valueOf(12), row.get(0));
|
495
|
+
assertEquals(Integer.valueOf(20), row.get(1));
|
496
|
+
assertEquals("cc", row.get(2));
|
497
|
+
}
|
498
|
+
}
|
499
|
+
|
361
500
|
|
362
501
|
private void assertTable(int skip, String table) throws Exception
|
363
502
|
{
|
@@ -0,0 +1,23 @@
|
|
1
|
+
in:
|
2
|
+
type: file
|
3
|
+
path_prefix: '/sqlserver/data/test6/test6.csv'
|
4
|
+
parser:
|
5
|
+
charset: UTF-8
|
6
|
+
newline: CRLF
|
7
|
+
type: csv
|
8
|
+
delimiter: ','
|
9
|
+
quote: ''
|
10
|
+
columns:
|
11
|
+
- {name: ITEM1, type: long}
|
12
|
+
- {name: ITEM2, type: long}
|
13
|
+
- {name: ITEM3, type: string}
|
14
|
+
out:
|
15
|
+
type: sqlserver
|
16
|
+
host: #host#
|
17
|
+
database: #database#
|
18
|
+
user: #user#
|
19
|
+
password: #password#
|
20
|
+
table: TEST6B
|
21
|
+
mode: merge
|
22
|
+
merge_keys: [ITEM1,ITEM2]
|
23
|
+
|
@@ -0,0 +1,22 @@
|
|
1
|
+
in:
|
2
|
+
type: file
|
3
|
+
path_prefix: '/sqlserver/data/test6/test6.csv'
|
4
|
+
parser:
|
5
|
+
charset: UTF-8
|
6
|
+
newline: CRLF
|
7
|
+
type: csv
|
8
|
+
delimiter: ','
|
9
|
+
quote: ''
|
10
|
+
columns:
|
11
|
+
- {name: ITEM1, type: long}
|
12
|
+
- {name: ITEM2, type: long}
|
13
|
+
- {name: ITEM3, type: string}
|
14
|
+
out:
|
15
|
+
type: sqlserver
|
16
|
+
host: #host#
|
17
|
+
database: #database#
|
18
|
+
user: #user#
|
19
|
+
password: #password#
|
20
|
+
table: TEST6
|
21
|
+
mode: merge
|
22
|
+
merge_rule: ["ITEM3 = T.ITEM3 + S.ITEM3"]
|
@@ -0,0 +1,21 @@
|
|
1
|
+
in:
|
2
|
+
type: file
|
3
|
+
path_prefix: '/sqlserver/data/test6/test6.csv'
|
4
|
+
parser:
|
5
|
+
charset: UTF-8
|
6
|
+
newline: CRLF
|
7
|
+
type: csv
|
8
|
+
delimiter: ','
|
9
|
+
quote: ''
|
10
|
+
columns:
|
11
|
+
- {name: ITEM1, type: long}
|
12
|
+
- {name: ITEM2, type: long}
|
13
|
+
- {name: ITEM3, type: string}
|
14
|
+
out:
|
15
|
+
type: sqlserver
|
16
|
+
host: #host#
|
17
|
+
database: #database#
|
18
|
+
user: #user#
|
19
|
+
password: #password#
|
20
|
+
table: TEST6
|
21
|
+
mode: merge
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: embulk-output-sqlserver
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.7.
|
4
|
+
version: 0.7.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sadayuki Furuhashi
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-12-19 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Inserts or updates records to a table.
|
14
14
|
email:
|
@@ -19,8 +19,8 @@ extra_rdoc_files: []
|
|
19
19
|
files:
|
20
20
|
- README.md
|
21
21
|
- build.gradle
|
22
|
-
- classpath/embulk-output-jdbc-0.7.
|
23
|
-
- classpath/embulk-output-sqlserver-0.7.
|
22
|
+
- classpath/embulk-output-jdbc-0.7.2.jar
|
23
|
+
- classpath/embulk-output-sqlserver-0.7.2.jar
|
24
24
|
- classpath/jtds-1.3.1.jar
|
25
25
|
- lib/embulk/output/sqlserver.rb
|
26
26
|
- src/main/java/org/embulk/output/SQLServerOutputPlugin.java
|
@@ -42,9 +42,13 @@ files:
|
|
42
42
|
- src/test/resources/sqlserver/data/test3/test3.csv
|
43
43
|
- src/test/resources/sqlserver/data/test4/test4.csv
|
44
44
|
- src/test/resources/sqlserver/data/test5/test5.csv
|
45
|
+
- src/test/resources/sqlserver/data/test6/test6.csv
|
45
46
|
- src/test/resources/sqlserver/yml/test-insert-direct.yml
|
46
47
|
- src/test/resources/sqlserver/yml/test-insert.yml
|
47
48
|
- src/test/resources/sqlserver/yml/test-jtds.yml
|
49
|
+
- src/test/resources/sqlserver/yml/test-merge-keys.yml
|
50
|
+
- src/test/resources/sqlserver/yml/test-merge-rule.yml
|
51
|
+
- src/test/resources/sqlserver/yml/test-merge.yml
|
48
52
|
- src/test/resources/sqlserver/yml/test-native-date.yml
|
49
53
|
- src/test/resources/sqlserver/yml/test-native-decimal.yml
|
50
54
|
- src/test/resources/sqlserver/yml/test-native-integer.yml
|