embulk-output-db2 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +118 -0
- data/build.gradle +9 -0
- data/classpath/embulk-output-db2-0.7.0.jar +0 -0
- data/classpath/embulk-output-jdbc-0.7.0.jar +0 -0
- data/lib/embulk/output/db2.rb +3 -0
- data/out/test/db2/data/test-char.csv +3 -0
- data/out/test/db2/data/test-datetime.csv +3 -0
- data/out/test/db2/data/test-number.csv +3 -0
- data/out/test/db2/yml/test-insert-direct-char.yml +27 -0
- data/out/test/db2/yml/test-insert-direct-datetime.yml +24 -0
- data/out/test/db2/yml/test-insert-direct-number.yml +27 -0
- data/src/main/java/org/embulk/output/DB2OutputPlugin.java +89 -0
- data/src/main/java/org/embulk/output/db2/DB2BatchInsert.java +33 -0
- data/src/main/java/org/embulk/output/db2/DB2OutputConnection.java +140 -0
- data/src/main/java/org/embulk/output/db2/DB2OutputConnector.java +49 -0
- data/src/test/java/org/embulk/output/db2/DB2OutputPluginTest.java +499 -0
- data/src/test/resources/db2/data/test-char.csv +3 -0
- data/src/test/resources/db2/data/test-datetime.csv +3 -0
- data/src/test/resources/db2/data/test-number.csv +3 -0
- data/src/test/resources/db2/yml/test-insert-char.yml +27 -0
- data/src/test/resources/db2/yml/test-insert-datetime.yml +24 -0
- data/src/test/resources/db2/yml/test-insert-direct-char.yml +27 -0
- data/src/test/resources/db2/yml/test-insert-direct-datetime.yml +24 -0
- data/src/test/resources/db2/yml/test-insert-direct-number.yml +27 -0
- data/src/test/resources/db2/yml/test-insert-number.yml +27 -0
- data/src/test/resources/db2/yml/test-replace-long-name.yml +27 -0
- data/src/test/resources/db2/yml/test-replace.yml +27 -0
- data/src/test/resources/db2/yml/test-truncate-insert.yml +27 -0
- metadata +72 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: b20a23693346957b15458772f8cc1559d4177160
|
4
|
+
data.tar.gz: 6476a9a55e25f30e72ce49a12d34aaa3286ce605
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: fbbd4afe3678831d8f7cd751c81894519a4d677af7e3e82a89f182533d22e7288aa6bec737e45e7637ef0612a85695a34329be15d3538e5312f95230cb208965
|
7
|
+
data.tar.gz: 8682f185c18d3a5a5e112c368c7883cfc5bf71d020bf4e781faf51451d2e3cb80ff4a40782403867f2c99fc6088b28bc1b7b44b549dc60d204d3e42f4ae6f9fa
|
data/README.md
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
# DB2 output plugins for Embulk
|
2
|
+
|
3
|
+
DB2 output plugins for Embulk loads records to DB2.
|
4
|
+
|
5
|
+
## Overview
|
6
|
+
|
7
|
+
* **Plugin type**: output
|
8
|
+
* **Load all or nothing**: depends on the mode. see below.
|
9
|
+
* **Resume supported**: depends on the mode. see below.
|
10
|
+
|
11
|
+
## Configuration
|
12
|
+
|
13
|
+
- **driver_path**: path to the jar file of the DB2 JDBC driver (string)
|
14
|
+
- **host**: database host name (string, required)
|
15
|
+
- **port**: database port number (integer, default: 50000)
|
16
|
+
- **user**: database login user name (string, required)
|
17
|
+
- **password**: database login password (string)
|
18
|
+
- **database**: destination database name (string, required)
|
19
|
+
- **schema**: destination schema name (string, default: use the default schema)
|
20
|
+
- **table**: destination table name (string, required)
|
21
|
+
- **options**: extra connection properties (hash, default: {})
|
22
|
+
- **retry_limit** max retry count for database operations (integer, default: 12)
|
23
|
+
- **retry_wait** initial retry wait time in milliseconds (integer, default: 1000 (1 second))
|
24
|
+
- **max_retry_wait** upper limit of retry wait, which will be doubled at every retry (integer, default: 1800000 (30 minutes))
|
25
|
+
- **mode**: "insert", "insert_direct", "truncate_insert" or "replace". See below. (string, required)
|
26
|
+
- **insert_method**: see below
|
27
|
+
- **batch_size**: size of a single batch insert (integer, default: 16777216)
|
28
|
+
- **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`)
|
29
|
+
- **column_options**: advanced: a key-value pairs where key is a column name and value is options for the column.
|
30
|
+
- **type**: type of a column when this plugin creates new tables (e.g. `VARCHAR(255)`, `INTEGER NOT NULL UNIQUE`). This used when this plugin creates intermediate tables (insert, insert_truncate and merge modes), when it creates the target table (insert_direct, merge_direct and replace modes), and when it creates nonexistent target table automatically. (string, default: depends on input column type. `BIGINT` if input column type is long, `SMALLINT` if boolean, `DOUBLE` if double, `CLOB` if string, `TIMESTAMP` if timestamp)
|
31
|
+
- **value_type**: This plugin converts input column type (embulk type) into a database type to build a INSERT statement. This value_type option controls the type of the value in a INSERT statement. (string, default: depends on the sql type of the column. Available values options are: `byte`, `short`, `int`, `long`, `double`, `float`, `boolean`, `string`, `nstring`, `date`, `time`, `timestamp`, `decimal`, `json`, `null`, `pass`)
|
32
|
+
- **timestamp_format**: If input column type (embulk type) is timestamp and value_type is `string` or `nstring`, this plugin needs to format the timestamp value into a string. This timestamp_format option is used to control the format of the timestamp. (string, default: `%Y-%m-%d %H:%M:%S.%6N`)
|
33
|
+
- **timezone**: If input column type (embulk type) is timestamp, this plugin needs to format the timestamp value into a SQL string. In this cases, this timezone option is used to control the timezone. (string, value of default_timezone option is used by default)
|
34
|
+
|
35
|
+
### Modes
|
36
|
+
|
37
|
+
* **insert**:
|
38
|
+
* Behavior: This mode writes rows to some intermediate tables first. If all those tasks run correctly, runs `INSERT INTO <target_table> SELECT * FROM <intermediate_table_1> UNION ALL SELECT * FROM <intermediate_table_2> UNION ALL ...` query. If the target table doesn't exist, it is created automatically.
|
39
|
+
* Transactional: Yes. This mode successfully writes all rows, or fails with writing zero rows.
|
40
|
+
* Resumable: Yes.
|
41
|
+
* **insert_direct**:
|
42
|
+
* Behavior: This mode inserts rows to the target table directly. If the target table doesn't exist, it is created automatically.
|
43
|
+
* Transactional: No. If fails, the target table could have some rows inserted.
|
44
|
+
* Resumable: No.
|
45
|
+
* **truncate_insert**:
|
46
|
+
* Behavior: Same with `insert` mode excepting that it truncates the target table right before the last `INSERT ...` query.
|
47
|
+
* Transactional: Yes.
|
48
|
+
* Resumable: Yes.
|
49
|
+
* **replace**:
|
50
|
+
* 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.
|
51
|
+
* Transactional: No. If fails, the target table could be dropped (because DB2 can't rollback DDL).
|
52
|
+
* Resumable: No.
|
53
|
+
|
54
|
+
### Supported types
|
55
|
+
|
56
|
+
|database type|default value_type|note|
|
57
|
+
|:--|:--|:--|
|
58
|
+
|SMALLINT|short||
|
59
|
+
|INTEGER|int||
|
60
|
+
|BITINT|long||
|
61
|
+
|DECIMAL|decimal||
|
62
|
+
|NUMERIC|decimal||
|
63
|
+
|REAL|float||
|
64
|
+
|DOUBLE|double||
|
65
|
+
|FLOAT|double||
|
66
|
+
|CHAR|string||
|
67
|
+
|VARCHAR|string||
|
68
|
+
|CLOB|string||
|
69
|
+
|GRAPHIC|string||
|
70
|
+
|VARGRAPHIC|string||
|
71
|
+
|NCHAR|string||
|
72
|
+
|NVARCHAR|string||
|
73
|
+
|NCLOB|string||
|
74
|
+
|DATE|date||
|
75
|
+
|TIME|time||
|
76
|
+
|TIMESTAMP|timestamp||
|
77
|
+
|
78
|
+
You can use other types by specifying `value_type` in `column_options`.
|
79
|
+
|
80
|
+
### Example
|
81
|
+
|
82
|
+
```yaml
|
83
|
+
out:
|
84
|
+
type: db2
|
85
|
+
driver_path: /opt/db2/db2jcc4.jar
|
86
|
+
host: localhost
|
87
|
+
user: myuser
|
88
|
+
password: ""
|
89
|
+
database: my_database
|
90
|
+
table: my_table
|
91
|
+
mode: insert
|
92
|
+
```
|
93
|
+
|
94
|
+
Advanced configuration:
|
95
|
+
|
96
|
+
```yaml
|
97
|
+
out:
|
98
|
+
type: db2
|
99
|
+
driver_path: /opt/db2/db2jcc4.jar
|
100
|
+
host: localhost
|
101
|
+
user: myuser
|
102
|
+
password: ""
|
103
|
+
database: my_database
|
104
|
+
table: my_table
|
105
|
+
mode: insert_direct
|
106
|
+
insert_method: native
|
107
|
+
column_options:
|
108
|
+
my_col_1: {type: 'TEXT'}
|
109
|
+
my_col_3: {type: 'INT NOT NULL'}
|
110
|
+
my_col_4: {value_type: string, timestamp_format: `%Y-%m-%d %H:%M:%S %z`, timezone: '-0700'}
|
111
|
+
my_col_5: {type: 'DECIMAL(18,9)', value_type: pass}
|
112
|
+
```
|
113
|
+
|
114
|
+
### Build
|
115
|
+
|
116
|
+
```
|
117
|
+
$ ./gradlew gem
|
118
|
+
```
|
data/build.gradle
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
[compileTestJava]*.options*.encoding = 'UTF-8'
|
2
|
+
|
3
|
+
dependencies {
|
4
|
+
compile project(':embulk-output-jdbc')
|
5
|
+
|
6
|
+
testCompile 'org.embulk:embulk-standards:0.8.8'
|
7
|
+
testCompile project(':embulk-output-jdbc').sourceSets.test.output
|
8
|
+
testCompile files('driver/db2jcc4.jar')
|
9
|
+
}
|
Binary file
|
Binary file
|
@@ -0,0 +1,27 @@
|
|
1
|
+
in:
|
2
|
+
type: file
|
3
|
+
path_prefix: '/db2/data/test-char.csv'
|
4
|
+
parser:
|
5
|
+
charset: UTF-8
|
6
|
+
newline: CRLF
|
7
|
+
type: csv
|
8
|
+
delimiter: ','
|
9
|
+
quote: ''
|
10
|
+
columns:
|
11
|
+
- {name: ID, type: string}
|
12
|
+
- {name: CHAR_ITEM, type: string}
|
13
|
+
- {name: VARCHAR_ITEM, type: string}
|
14
|
+
- {name: CLOB_ITEM, type: string}
|
15
|
+
- {name: GRAPHIC_ITEM, type: string}
|
16
|
+
- {name: VARGRAPHIC_ITEM, type: string}
|
17
|
+
- {name: NCHAR_ITEM, type: string}
|
18
|
+
- {name: NVARCHAR_ITEM, type: string}
|
19
|
+
- {name: NCLOB_ITEM, type: string}
|
20
|
+
out:
|
21
|
+
type: db2
|
22
|
+
host: #host#
|
23
|
+
database: #database#
|
24
|
+
user: #user#
|
25
|
+
password: #password#
|
26
|
+
table: TEST_CHAR
|
27
|
+
mode: insert_direct
|
@@ -0,0 +1,24 @@
|
|
1
|
+
in:
|
2
|
+
type: file
|
3
|
+
path_prefix: '/db2/data/test-datetime.csv'
|
4
|
+
parser:
|
5
|
+
charset: UTF-8
|
6
|
+
newline: CRLF
|
7
|
+
type: csv
|
8
|
+
delimiter: ','
|
9
|
+
quote: ''
|
10
|
+
columns:
|
11
|
+
- {name: ID, type: string}
|
12
|
+
- {name: DATE_ITEM, type: timestamp, format: '%Y/%m/%d'}
|
13
|
+
- {name: TIME_ITEM, type: timestamp, format: '%H:%M:%S'}
|
14
|
+
- {name: TIMESTAMP_ITEM, type: timestamp, format: '%Y/%m/%d %H:%M:%S.%N'}
|
15
|
+
- {name: TIMESTAMP0_ITEM, type: timestamp, format: '%Y/%m/%d %H:%M:%S'}
|
16
|
+
- {name: TIMESTAMP12_ITEM, type: timestamp, format: '%Y/%m/%d %H:%M:%S.%N'}
|
17
|
+
out:
|
18
|
+
type: db2
|
19
|
+
host: #host#
|
20
|
+
database: #database#
|
21
|
+
user: #user#
|
22
|
+
password: #password#
|
23
|
+
table: TEST_DATETIME
|
24
|
+
mode: insert_direct
|
@@ -0,0 +1,27 @@
|
|
1
|
+
in:
|
2
|
+
type: file
|
3
|
+
path_prefix: '/db2/data/test-number.csv'
|
4
|
+
parser:
|
5
|
+
charset: UTF-8
|
6
|
+
newline: CRLF
|
7
|
+
type: csv
|
8
|
+
delimiter: ','
|
9
|
+
quote: ''
|
10
|
+
columns:
|
11
|
+
- {name: ID, type: string}
|
12
|
+
- {name: SMALLINT_ITEM, type: long}
|
13
|
+
- {name: INTEGER_ITEM, type: long}
|
14
|
+
- {name: BIGINT_ITEM, type: long}
|
15
|
+
- {name: DECIMAL_ITEM, type: string}
|
16
|
+
- {name: NUMERIC_ITEM, type: string}
|
17
|
+
- {name: REAL_ITEM, type: double}
|
18
|
+
- {name: DOUBLE_ITEM, type: double}
|
19
|
+
- {name: FLOAT_ITEM, type: double}
|
20
|
+
out:
|
21
|
+
type: db2
|
22
|
+
host: #host#
|
23
|
+
database: #database#
|
24
|
+
user: #user#
|
25
|
+
password: #password#
|
26
|
+
table: TEST_NUMBER
|
27
|
+
mode: insert_direct
|
@@ -0,0 +1,89 @@
|
|
1
|
+
package org.embulk.output;
|
2
|
+
|
3
|
+
import java.io.IOException;
|
4
|
+
import java.sql.SQLException;
|
5
|
+
import java.util.Properties;
|
6
|
+
|
7
|
+
import org.embulk.config.Config;
|
8
|
+
import org.embulk.config.ConfigDefault;
|
9
|
+
import org.embulk.output.db2.DB2BatchInsert;
|
10
|
+
import org.embulk.output.db2.DB2OutputConnector;
|
11
|
+
import org.embulk.output.jdbc.AbstractJdbcOutputPlugin;
|
12
|
+
import org.embulk.output.jdbc.BatchInsert;
|
13
|
+
import org.embulk.output.jdbc.MergeConfig;
|
14
|
+
|
15
|
+
import com.google.common.base.Optional;
|
16
|
+
import com.google.common.collect.ImmutableSet;
|
17
|
+
import static java.util.Locale.ENGLISH;
|
18
|
+
|
19
|
+
public class DB2OutputPlugin
|
20
|
+
extends AbstractJdbcOutputPlugin
|
21
|
+
{
|
22
|
+
public interface DB2PluginTask
|
23
|
+
extends PluginTask
|
24
|
+
{
|
25
|
+
@Config("driver_path")
|
26
|
+
@ConfigDefault("null")
|
27
|
+
public Optional<String> getDriverPath();
|
28
|
+
|
29
|
+
@Config("host")
|
30
|
+
public String getHost();
|
31
|
+
|
32
|
+
@Config("port")
|
33
|
+
@ConfigDefault("50000")
|
34
|
+
public int getPort();
|
35
|
+
|
36
|
+
@Config("database")
|
37
|
+
public String getDatabase();
|
38
|
+
|
39
|
+
@Config("user")
|
40
|
+
public String getUser();
|
41
|
+
|
42
|
+
@Config("password")
|
43
|
+
@ConfigDefault("null")
|
44
|
+
public Optional<String> getPassword();
|
45
|
+
}
|
46
|
+
|
47
|
+
@Override
|
48
|
+
protected Class<? extends PluginTask> getTaskClass()
|
49
|
+
{
|
50
|
+
return DB2PluginTask.class;
|
51
|
+
}
|
52
|
+
|
53
|
+
@Override
|
54
|
+
protected Features getFeatures(PluginTask task)
|
55
|
+
{
|
56
|
+
return new Features()
|
57
|
+
.setMaxTableNameLength(128) // http://www.ibm.com/support/knowledgecenter/SSEPGG_11.1.0/com.ibm.db2.luw.sql.ref.doc/doc/r0001029.html
|
58
|
+
.setSupportedModes(ImmutableSet.of(Mode.INSERT, Mode.INSERT_DIRECT, Mode.TRUNCATE_INSERT, Mode.REPLACE))
|
59
|
+
.setIgnoreMergeKeys(false);
|
60
|
+
}
|
61
|
+
|
62
|
+
@Override
|
63
|
+
protected DB2OutputConnector getConnector(PluginTask task, boolean retryableMetadataOperation)
|
64
|
+
{
|
65
|
+
DB2PluginTask db2Task = (DB2PluginTask) task;
|
66
|
+
|
67
|
+
if (db2Task.getDriverPath().isPresent()) {
|
68
|
+
loadDriverJar(db2Task.getDriverPath().get());
|
69
|
+
}
|
70
|
+
|
71
|
+
String url = String.format(ENGLISH, "jdbc:db2://%s:%d/%s",
|
72
|
+
db2Task.getHost(), db2Task.getPort(), db2Task.getDatabase());
|
73
|
+
|
74
|
+
Properties props = new Properties();
|
75
|
+
props.putAll(db2Task.getOptions());
|
76
|
+
props.setProperty("user", db2Task.getUser());
|
77
|
+
if (db2Task.getPassword().isPresent()) {
|
78
|
+
props.setProperty("password", db2Task.getPassword().get());
|
79
|
+
}
|
80
|
+
|
81
|
+
return new DB2OutputConnector(url, props, null);
|
82
|
+
}
|
83
|
+
|
84
|
+
@Override
|
85
|
+
protected BatchInsert newBatchInsert(PluginTask task, Optional<MergeConfig> mergeConfig) throws IOException, SQLException
|
86
|
+
{
|
87
|
+
return new DB2BatchInsert(getConnector(task, true), mergeConfig);
|
88
|
+
}
|
89
|
+
}
|
@@ -0,0 +1,33 @@
|
|
1
|
+
package org.embulk.output.db2;
|
2
|
+
|
3
|
+
import java.io.IOException;
|
4
|
+
import java.sql.SQLException;
|
5
|
+
|
6
|
+
import org.embulk.output.jdbc.MergeConfig;
|
7
|
+
import org.embulk.output.jdbc.StandardBatchInsert;
|
8
|
+
|
9
|
+
import com.google.common.base.Optional;
|
10
|
+
|
11
|
+
public class DB2BatchInsert
|
12
|
+
extends StandardBatchInsert
|
13
|
+
{
|
14
|
+
public DB2BatchInsert(DB2OutputConnector connector, Optional<MergeConfig> mergeConfig) throws IOException, SQLException
|
15
|
+
{
|
16
|
+
super(connector, mergeConfig);
|
17
|
+
}
|
18
|
+
|
19
|
+
@Override
|
20
|
+
public void flush() throws IOException, SQLException
|
21
|
+
{
|
22
|
+
try {
|
23
|
+
super.flush();
|
24
|
+
|
25
|
+
} catch (SQLException e) {
|
26
|
+
if (e.getNextException() != null) {
|
27
|
+
// SQLException of DB2 doesn't contain details.
|
28
|
+
throw new SQLException(e.toString(), e.getNextException());
|
29
|
+
}
|
30
|
+
throw e;
|
31
|
+
}
|
32
|
+
}
|
33
|
+
}
|
@@ -0,0 +1,140 @@
|
|
1
|
+
package org.embulk.output.db2;
|
2
|
+
|
3
|
+
import java.sql.Connection;
|
4
|
+
import java.sql.SQLException;
|
5
|
+
import java.sql.Statement;
|
6
|
+
|
7
|
+
import org.embulk.output.jdbc.JdbcColumn;
|
8
|
+
import org.embulk.output.jdbc.JdbcOutputConnection;
|
9
|
+
import org.embulk.output.jdbc.JdbcSchema;
|
10
|
+
|
11
|
+
import static java.util.Locale.ENGLISH;
|
12
|
+
|
13
|
+
public class DB2OutputConnection
|
14
|
+
extends JdbcOutputConnection
|
15
|
+
{
|
16
|
+
public DB2OutputConnection(Connection connection, String schemaName, boolean autoCommit)
|
17
|
+
throws SQLException
|
18
|
+
{
|
19
|
+
super(connection, schemaName);
|
20
|
+
connection.setAutoCommit(autoCommit);
|
21
|
+
}
|
22
|
+
|
23
|
+
@Override
|
24
|
+
protected String buildRenameTableSql(String fromTable, String toTable)
|
25
|
+
{
|
26
|
+
StringBuilder sb = new StringBuilder();
|
27
|
+
sb.append("RENAME TABLE ");
|
28
|
+
sb.append(quoteIdentifierString(fromTable));
|
29
|
+
sb.append(" TO ");
|
30
|
+
sb.append(quoteIdentifierString(toTable));
|
31
|
+
return sb.toString();
|
32
|
+
}
|
33
|
+
|
34
|
+
@Override
|
35
|
+
protected void setSearchPath(String schema) throws SQLException
|
36
|
+
{
|
37
|
+
// NOP
|
38
|
+
}
|
39
|
+
|
40
|
+
@Override
|
41
|
+
public void dropTableIfExists(String tableName) throws SQLException
|
42
|
+
{
|
43
|
+
if (tableExists(tableName)) {
|
44
|
+
dropTable(tableName);
|
45
|
+
}
|
46
|
+
}
|
47
|
+
|
48
|
+
@Override
|
49
|
+
protected void dropTableIfExists(Statement stmt, String tableName) throws SQLException
|
50
|
+
{
|
51
|
+
if (tableExists(tableName)) {
|
52
|
+
dropTable(stmt, tableName);
|
53
|
+
}
|
54
|
+
}
|
55
|
+
|
56
|
+
@Override
|
57
|
+
public void createTableIfNotExists(String tableName, JdbcSchema schema) throws SQLException
|
58
|
+
{
|
59
|
+
if (!tableExists(tableName)) {
|
60
|
+
createTable(tableName, schema);
|
61
|
+
}
|
62
|
+
}
|
63
|
+
|
64
|
+
public void createTable(String tableName, JdbcSchema schema) throws SQLException
|
65
|
+
{
|
66
|
+
Statement stmt = connection.createStatement();
|
67
|
+
try {
|
68
|
+
String sql = buildCreateTableSql(tableName, schema);
|
69
|
+
executeUpdate(stmt, sql);
|
70
|
+
commitIfNecessary(connection);
|
71
|
+
} catch (SQLException ex) {
|
72
|
+
throw safeRollback(connection, ex);
|
73
|
+
} finally {
|
74
|
+
stmt.close();
|
75
|
+
}
|
76
|
+
}
|
77
|
+
|
78
|
+
protected String buildCreateTableSql(String name, JdbcSchema schema)
|
79
|
+
{
|
80
|
+
StringBuilder sb = new StringBuilder();
|
81
|
+
|
82
|
+
sb.append("CREATE TABLE ");
|
83
|
+
quoteIdentifierString(sb, name);
|
84
|
+
sb.append(buildCreateTableSchemaSql(schema));
|
85
|
+
return sb.toString();
|
86
|
+
}
|
87
|
+
|
88
|
+
@Override
|
89
|
+
protected String buildColumnTypeName(JdbcColumn c)
|
90
|
+
{
|
91
|
+
switch(c.getSimpleTypeName()) {
|
92
|
+
case "BOOLEAN":
|
93
|
+
return "SMALLINT";
|
94
|
+
|
95
|
+
// NCHAR/NVARCHAR/NCLOB are synonyms for CHAR/VARCHAR/CLOB/GRAPHIC/VARGRAPHIC
|
96
|
+
case "CHAR":
|
97
|
+
case "VARCHAR":
|
98
|
+
case "CLOB":
|
99
|
+
String charUnit;
|
100
|
+
if (c.getSizeTypeParameter() == c.getDataLength()) {
|
101
|
+
charUnit = "OCTETS";
|
102
|
+
} else if (c.getSizeTypeParameter() * 2 == c.getDataLength()) {
|
103
|
+
charUnit = "CODEUNITS16";
|
104
|
+
} else if (c.getSizeTypeParameter() * 4 == c.getDataLength()) {
|
105
|
+
charUnit = "CODEUNITS32";
|
106
|
+
} else {
|
107
|
+
throw new IllegalArgumentException(String.format(ENGLISH, "Column %s has unexpected size %d and length %d.",
|
108
|
+
c.getName(), c.getSizeTypeParameter(), c.getDataLength()));
|
109
|
+
}
|
110
|
+
return String.format(ENGLISH, "%s(%d %s)", c.getSimpleTypeName(), c.getSizeTypeParameter(), charUnit);
|
111
|
+
|
112
|
+
case "GRAPHIC":
|
113
|
+
case "VARGRAPHIC":
|
114
|
+
String graphicUnit;
|
115
|
+
if (c.getSizeTypeParameter() == c.getDataLength()) {
|
116
|
+
graphicUnit = "CODEUNITS16";
|
117
|
+
} else if (c.getSizeTypeParameter() * 2 == c.getDataLength()) {
|
118
|
+
graphicUnit = "CODEUNITS32";
|
119
|
+
} else {
|
120
|
+
throw new IllegalArgumentException(String.format(ENGLISH, "Column %s has unexpected size %d and length %d.",
|
121
|
+
c.getName(), c.getSizeTypeParameter(), c.getDataLength()));
|
122
|
+
}
|
123
|
+
return String.format(ENGLISH, "%s(%d %s)", c.getSimpleTypeName(), c.getSizeTypeParameter(), graphicUnit);
|
124
|
+
|
125
|
+
default:
|
126
|
+
return super.buildColumnTypeName(c);
|
127
|
+
}
|
128
|
+
}
|
129
|
+
|
130
|
+
@Override
|
131
|
+
public void close() throws SQLException
|
132
|
+
{
|
133
|
+
if (!connection.isClosed()) {
|
134
|
+
// DB2 JDBC Driver requires explicit commit/rollback before closing connection.
|
135
|
+
connection.rollback();
|
136
|
+
}
|
137
|
+
|
138
|
+
super.close();
|
139
|
+
}
|
140
|
+
}
|
@@ -0,0 +1,49 @@
|
|
1
|
+
package org.embulk.output.db2;
|
2
|
+
|
3
|
+
import java.sql.Connection;
|
4
|
+
import java.sql.DriverManager;
|
5
|
+
import java.sql.SQLException;
|
6
|
+
import java.util.Properties;
|
7
|
+
|
8
|
+
import org.embulk.output.jdbc.JdbcOutputConnector;
|
9
|
+
|
10
|
+
public class DB2OutputConnector
|
11
|
+
implements JdbcOutputConnector
|
12
|
+
{
|
13
|
+
private final String url;
|
14
|
+
private final Properties properties;
|
15
|
+
private final String schemaName;
|
16
|
+
|
17
|
+
public DB2OutputConnector(String url, Properties properties, String schemaName)
|
18
|
+
{
|
19
|
+
try {
|
20
|
+
Class.forName("com.ibm.db2.jcc.DB2Driver");
|
21
|
+
} catch (Exception ex) {
|
22
|
+
throw new RuntimeException(ex);
|
23
|
+
}
|
24
|
+
this.url = url;
|
25
|
+
this.properties = properties;
|
26
|
+
this.schemaName = schemaName;
|
27
|
+
}
|
28
|
+
|
29
|
+
@Override
|
30
|
+
public DB2OutputConnection connect(boolean autoCommit) throws SQLException
|
31
|
+
{
|
32
|
+
Connection c = DriverManager.getConnection(url, properties);
|
33
|
+
if (c == null) {
|
34
|
+
// driver.connect returns null when url is "jdbc:mysql://...".
|
35
|
+
throw new SQLException("Invalid url : " + url);
|
36
|
+
}
|
37
|
+
|
38
|
+
try {
|
39
|
+
DB2OutputConnection con = new DB2OutputConnection(c, schemaName, autoCommit);
|
40
|
+
c = null;
|
41
|
+
return con;
|
42
|
+
|
43
|
+
} finally {
|
44
|
+
if (c != null) {
|
45
|
+
c.close();
|
46
|
+
}
|
47
|
+
}
|
48
|
+
}
|
49
|
+
}
|