embulk-output-teradata 0.1.2 → 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.DS_Store +0 -0
- data/README.md +0 -8
- data/build.gradle +5 -2
- data/embulk-output-teradata.iml +12 -0
- data/gradle/wrapper/gradle-wrapper.properties +2 -2
- data/gradlew +0 -0
- data/lib/embulk-output-jdbc-0.7.11.jar +0 -0
- data/src/main/java/org/embulk/output/teradata/TeradataOutputPlugin.java +13 -52
- data/src/main/java/org/embulk/output/teradata/jdbc/TeradataBatchInsert.java +37 -0
- data/src/main/java/org/embulk/output/teradata/jdbc/TeradataOutputConnection.java +307 -0
- data/src/main/java/org/embulk/output/teradata/jdbc/TeradataOutputConnector.java +46 -0
- metadata +10 -40
- data/src/main/java/org/embulk/output/teradata/JdbcOutputPlugin.java +0 -134
- data/src/main/java/org/embulk/output/teradata/TeradataOutputConnection.java +0 -19
- data/src/main/java/org/embulk/output/teradata/jdbc/AbstractJdbcOutputPlugin.java +0 -1144
- data/src/main/java/org/embulk/output/teradata/jdbc/BatchInsert.java +0 -52
- data/src/main/java/org/embulk/output/teradata/jdbc/JdbcColumn.java +0 -134
- data/src/main/java/org/embulk/output/teradata/jdbc/JdbcColumnOption.java +0 -34
- data/src/main/java/org/embulk/output/teradata/jdbc/JdbcOutputConnection.java +0 -549
- data/src/main/java/org/embulk/output/teradata/jdbc/JdbcOutputConnector.java +0 -8
- data/src/main/java/org/embulk/output/teradata/jdbc/JdbcSchema.java +0 -79
- data/src/main/java/org/embulk/output/teradata/jdbc/JdbcUtils.java +0 -153
- data/src/main/java/org/embulk/output/teradata/jdbc/MergeConfig.java +0 -23
- data/src/main/java/org/embulk/output/teradata/jdbc/StandardBatchInsert.java +0 -201
- data/src/main/java/org/embulk/output/teradata/jdbc/TimestampFormat.java +0 -37
- data/src/main/java/org/embulk/output/teradata/jdbc/ToString.java +0 -54
- data/src/main/java/org/embulk/output/teradata/jdbc/ToStringMap.java +0 -34
- data/src/main/java/org/embulk/output/teradata/jdbc/setter/BigDecimalColumnSetter.java +0 -76
- data/src/main/java/org/embulk/output/teradata/jdbc/setter/BooleanColumnSetter.java +0 -61
- data/src/main/java/org/embulk/output/teradata/jdbc/setter/ByteColumnSetter.java +0 -84
- data/src/main/java/org/embulk/output/teradata/jdbc/setter/ColumnSetter.java +0 -48
- data/src/main/java/org/embulk/output/teradata/jdbc/setter/ColumnSetterFactory.java +0 -199
- data/src/main/java/org/embulk/output/teradata/jdbc/setter/ColumnSetterVisitor.java +0 -110
- data/src/main/java/org/embulk/output/teradata/jdbc/setter/DefaultValueSetter.java +0 -50
- data/src/main/java/org/embulk/output/teradata/jdbc/setter/DoubleColumnSetter.java +0 -68
- data/src/main/java/org/embulk/output/teradata/jdbc/setter/FloatColumnSetter.java +0 -68
- data/src/main/java/org/embulk/output/teradata/jdbc/setter/IntColumnSetter.java +0 -84
- data/src/main/java/org/embulk/output/teradata/jdbc/setter/JsonColumnSetter.java +0 -61
- data/src/main/java/org/embulk/output/teradata/jdbc/setter/LongColumnSetter.java +0 -80
- data/src/main/java/org/embulk/output/teradata/jdbc/setter/NStringColumnSetter.java +0 -66
- data/src/main/java/org/embulk/output/teradata/jdbc/setter/NullColumnSetter.java +0 -61
- data/src/main/java/org/embulk/output/teradata/jdbc/setter/NullDefaultValueSetter.java +0 -111
- data/src/main/java/org/embulk/output/teradata/jdbc/setter/PassThroughColumnSetter.java +0 -66
- data/src/main/java/org/embulk/output/teradata/jdbc/setter/ShortColumnSetter.java +0 -84
- data/src/main/java/org/embulk/output/teradata/jdbc/setter/SkipColumnSetter.java +0 -49
- data/src/main/java/org/embulk/output/teradata/jdbc/setter/SqlDateColumnSetter.java +0 -66
- data/src/main/java/org/embulk/output/teradata/jdbc/setter/SqlTimeColumnSetter.java +0 -66
- data/src/main/java/org/embulk/output/teradata/jdbc/setter/SqlTimestampColumnSetter.java +0 -66
- data/src/main/java/org/embulk/output/teradata/jdbc/setter/StringColumnSetter.java +0 -66
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1576a329c01404b00bfd22be516a1cdf3a1a06eb
|
4
|
+
data.tar.gz: cdf50889dd17602ffd2e1bed867277c0fdfbe9f1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 12bc72528547067922f58487932e1a282ccf9f676fe0268519bec8450993ae242ae4c2781ff4ab84127b494117dcfe82365454e10a9b161040a68cd94aa9c3bd
|
7
|
+
data.tar.gz: 2a64ff07020a0c7a0338d8f59ea6b67633712dff22cb5243829605409cdc8d5e8beeb65abfd4eda67f4be70064a95ba96cbb260ee3775848175e289e82e55212
|
data/.DS_Store
ADDED
Binary file
|
data/README.md
CHANGED
@@ -48,14 +48,6 @@ Teradata output plugin for Embulk loads records to a database using a Teradata J
|
|
48
48
|
* 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.
|
49
49
|
* Transactional: No. If fails, the target table could be dropped.
|
50
50
|
* Resumable: No.
|
51
|
-
* **merge**:
|
52
|
-
* Behavior: This mode writes rows to some intermediate tables first. If all those tasks run correctly, merges the intermediate tables into the target table. Namely, if primary 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.
|
53
|
-
* Transactional: Yes.
|
54
|
-
* Resumable: Yes.
|
55
|
-
* **merge_direct**:
|
56
|
-
* Behavior: This mode merges rows to the target table directly. Namely, if primary keys of an input record already exist in the target table, the target record is updated by the input record, otherwise the input record is inserted. If the target table doesn't exist, it is created automatically.
|
57
|
-
* Transactional: No.
|
58
|
-
* Resumable: No.
|
59
51
|
|
60
52
|
## Example
|
61
53
|
|
data/build.gradle
CHANGED
@@ -6,14 +6,16 @@ plugins {
|
|
6
6
|
}
|
7
7
|
import com.github.jrubygradle.JRubyExec
|
8
8
|
repositories {
|
9
|
-
|
9
|
+
maven {
|
10
|
+
url("https://plugins.gradle.org/m2/")
|
11
|
+
}
|
10
12
|
jcenter()
|
11
13
|
}
|
12
14
|
configurations {
|
13
15
|
provided
|
14
16
|
}
|
15
17
|
|
16
|
-
version = "0.1.
|
18
|
+
version = "0.1.3"
|
17
19
|
|
18
20
|
sourceCompatibility = 1.7
|
19
21
|
targetCompatibility = 1.7
|
@@ -21,6 +23,7 @@ targetCompatibility = 1.7
|
|
21
23
|
dependencies {
|
22
24
|
compile "org.embulk:embulk-core:0.8.2"
|
23
25
|
provided "org.embulk:embulk-core:0.8.2"
|
26
|
+
compile files('lib/embulk-output-jdbc-0.7.11.jar')
|
24
27
|
compile files('lib/tdgssconfig.jar')
|
25
28
|
compile files('lib/terajdbc4.jar')
|
26
29
|
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<module external.linked.project.id="embulk-output-teradata" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" external.system.module.group="" external.system.module.version="0.1.2" type="JAVA_MODULE" version="4">
|
3
|
+
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
4
|
+
<exclude-output />
|
5
|
+
<content url="file://$MODULE_DIR$">
|
6
|
+
<excludeFolder url="file://$MODULE_DIR$/.gradle" />
|
7
|
+
<excludeFolder url="file://$MODULE_DIR$/build" />
|
8
|
+
</content>
|
9
|
+
<orderEntry type="inheritedJdk" />
|
10
|
+
<orderEntry type="sourceFolder" forTests="false" />
|
11
|
+
</component>
|
12
|
+
</module>
|
@@ -1,6 +1,6 @@
|
|
1
|
-
#
|
1
|
+
#Tue Aug 29 21:53:01 JST 2017
|
2
2
|
distributionBase=GRADLE_USER_HOME
|
3
3
|
distributionPath=wrapper/dists
|
4
4
|
zipStoreBase=GRADLE_USER_HOME
|
5
5
|
zipStorePath=wrapper/dists
|
6
|
-
distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-
|
6
|
+
distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip
|
data/gradlew
CHANGED
File without changes
|
Binary file
|
@@ -1,25 +1,26 @@
|
|
1
1
|
package org.embulk.output.teradata;
|
2
2
|
|
3
3
|
import java.util.Properties;
|
4
|
-
import java.sql.Driver;
|
5
4
|
import java.io.IOException;
|
6
|
-
import java.sql.Connection;
|
7
5
|
import java.sql.SQLException;
|
8
6
|
|
9
7
|
import com.google.common.base.Optional;
|
10
|
-
import com.google.common.base.Throwables;
|
11
8
|
import com.google.common.collect.ImmutableSet;
|
12
9
|
|
13
10
|
import org.embulk.config.Config;
|
14
11
|
import org.embulk.config.ConfigDefault;
|
15
|
-
import org.embulk.output.jdbc
|
16
|
-
import org.embulk.output.
|
12
|
+
import org.embulk.output.jdbc.AbstractJdbcOutputPlugin;
|
13
|
+
import org.embulk.output.jdbc.BatchInsert;
|
14
|
+
import org.embulk.output.jdbc.MergeConfig;
|
15
|
+
import org.embulk.output.teradata.jdbc.TeradataBatchInsert;
|
16
|
+
import org.embulk.output.teradata.jdbc.TeradataOutputConnector;
|
17
17
|
|
18
18
|
public class TeradataOutputPlugin
|
19
19
|
extends AbstractJdbcOutputPlugin
|
20
20
|
{
|
21
21
|
|
22
|
-
public interface
|
22
|
+
public interface TeradataPluginTask
|
23
|
+
extends PluginTask
|
23
24
|
{
|
24
25
|
@Config("url")
|
25
26
|
public String getUrl();
|
@@ -44,22 +45,22 @@ public class TeradataOutputPlugin
|
|
44
45
|
@Override
|
45
46
|
protected Class<? extends PluginTask> getTaskClass()
|
46
47
|
{
|
47
|
-
return
|
48
|
+
return TeradataPluginTask.class;
|
48
49
|
}
|
49
50
|
|
50
51
|
@Override
|
51
52
|
protected Features getFeatures(PluginTask task)
|
52
53
|
{
|
53
|
-
|
54
|
+
TeradataPluginTask t = (TeradataPluginTask) task;
|
54
55
|
return new Features()
|
55
56
|
.setMaxTableNameLength(t.getMaxTableNameLength())
|
56
57
|
.setSupportedModes(ImmutableSet.of(Mode.INSERT, Mode.INSERT_DIRECT, Mode.TRUNCATE_INSERT, Mode.REPLACE));
|
57
58
|
}
|
58
59
|
|
59
60
|
@Override
|
60
|
-
protected
|
61
|
+
protected TeradataOutputConnector getConnector(PluginTask task, boolean retryableMetadataOperation)
|
61
62
|
{
|
62
|
-
|
63
|
+
TeradataPluginTask t = (TeradataPluginTask) task;
|
63
64
|
|
64
65
|
Properties props = new Properties();
|
65
66
|
|
@@ -73,52 +74,12 @@ public class TeradataOutputPlugin
|
|
73
74
|
props.setProperty("password", t.getPassword().get());
|
74
75
|
}
|
75
76
|
|
76
|
-
return new
|
77
|
-
}
|
78
|
-
|
79
|
-
private static class GenericOutputConnector
|
80
|
-
implements JdbcOutputConnector
|
81
|
-
{
|
82
|
-
private final Driver driver;
|
83
|
-
private final String url;
|
84
|
-
private final Properties properties;
|
85
|
-
private final String schemaName;
|
86
|
-
|
87
|
-
public GenericOutputConnector(String url, Properties properties, String driverClass,
|
88
|
-
String schemaName)
|
89
|
-
{
|
90
|
-
try {
|
91
|
-
// TODO check Class.forName(driverClass) is a Driver before newInstance
|
92
|
-
// for security
|
93
|
-
this.driver = new com.teradata.jdbc.TeraDriver();
|
94
|
-
} catch (Exception ex) {
|
95
|
-
throw Throwables.propagate(ex);
|
96
|
-
}
|
97
|
-
this.url = url;
|
98
|
-
this.properties = properties;
|
99
|
-
this.schemaName = schemaName;
|
100
|
-
}
|
101
|
-
|
102
|
-
@Override
|
103
|
-
public JdbcOutputConnection connect(boolean autoCommit) throws SQLException
|
104
|
-
{
|
105
|
-
Connection c = driver.connect(url, properties);
|
106
|
-
try {
|
107
|
-
c.setAutoCommit(autoCommit);
|
108
|
-
JdbcOutputConnection con = new JdbcOutputConnection(c, schemaName);
|
109
|
-
c = null;
|
110
|
-
return con;
|
111
|
-
} finally {
|
112
|
-
if (c != null) {
|
113
|
-
c.close();
|
114
|
-
}
|
115
|
-
}
|
116
|
-
}
|
77
|
+
return new TeradataOutputConnector(t.getUrl(), props);
|
117
78
|
}
|
118
79
|
|
119
80
|
@Override
|
120
81
|
protected BatchInsert newBatchInsert(PluginTask task, Optional<MergeConfig> mergeConfig) throws IOException, SQLException
|
121
82
|
{
|
122
|
-
return new
|
83
|
+
return new TeradataBatchInsert(getConnector(task, true), mergeConfig);
|
123
84
|
}
|
124
85
|
}
|
@@ -0,0 +1,37 @@
|
|
1
|
+
package org.embulk.output.teradata.jdbc;
|
2
|
+
|
3
|
+
import java.io.IOException;
|
4
|
+
import java.sql.Types;
|
5
|
+
import java.sql.SQLException;
|
6
|
+
import com.google.common.base.Optional;
|
7
|
+
import org.embulk.output.jdbc.MergeConfig;
|
8
|
+
import org.embulk.output.jdbc.StandardBatchInsert;
|
9
|
+
|
10
|
+
public class TeradataBatchInsert
|
11
|
+
extends StandardBatchInsert
|
12
|
+
{
|
13
|
+
public TeradataBatchInsert(TeradataOutputConnector connector, Optional<MergeConfig> mergeConfig) throws IOException, SQLException
|
14
|
+
{
|
15
|
+
super(connector, mergeConfig);
|
16
|
+
}
|
17
|
+
|
18
|
+
@Override
|
19
|
+
public void setFloat(float v) throws IOException, SQLException
|
20
|
+
{
|
21
|
+
if (Float.isNaN(v) || Float.isInfinite(v)) {
|
22
|
+
setNull(Types.REAL); // TODO get through argument
|
23
|
+
} else {
|
24
|
+
super.setFloat(v);
|
25
|
+
}
|
26
|
+
}
|
27
|
+
|
28
|
+
@Override
|
29
|
+
public void setDouble(double v) throws IOException, SQLException
|
30
|
+
{
|
31
|
+
if (Double.isNaN(v) || Double.isInfinite(v)) {
|
32
|
+
setNull(Types.DOUBLE); // TODO get through argument
|
33
|
+
} else {
|
34
|
+
super.setDouble(v);
|
35
|
+
}
|
36
|
+
}
|
37
|
+
}
|
@@ -0,0 +1,307 @@
|
|
1
|
+
package org.embulk.output.teradata.jdbc;
|
2
|
+
|
3
|
+
import java.nio.charset.Charset;
|
4
|
+
import java.nio.charset.StandardCharsets;
|
5
|
+
import java.sql.Connection;
|
6
|
+
import java.sql.DatabaseMetaData;
|
7
|
+
import java.sql.SQLException;
|
8
|
+
import java.sql.Statement;
|
9
|
+
|
10
|
+
import org.embulk.output.jdbc.JdbcColumn;
|
11
|
+
import org.embulk.output.jdbc.JdbcOutputConnection;
|
12
|
+
import org.embulk.output.jdbc.JdbcSchema;
|
13
|
+
import org.embulk.output.jdbc.TableIdentifier;
|
14
|
+
import org.slf4j.Logger;
|
15
|
+
import org.embulk.spi.Exec;
|
16
|
+
|
17
|
+
import static java.lang.String.format;
|
18
|
+
|
19
|
+
public class TeradataOutputConnection
|
20
|
+
extends JdbcOutputConnection
|
21
|
+
{
|
22
|
+
private final Logger logger = Exec.getLogger(TeradataOutputConnection.class);
|
23
|
+
protected final Connection connection;
|
24
|
+
protected final DatabaseMetaData databaseMetaData;
|
25
|
+
protected String identifierQuoteString;
|
26
|
+
|
27
|
+
public TeradataOutputConnection(Connection connection, boolean autoCommit)
|
28
|
+
throws SQLException
|
29
|
+
{
|
30
|
+
super(connection, null);
|
31
|
+
this.connection = connection;
|
32
|
+
this.databaseMetaData = connection.getMetaData();
|
33
|
+
this.identifierQuoteString = databaseMetaData.getIdentifierQuoteString();
|
34
|
+
if (schemaName != null) {
|
35
|
+
setSearchPath(schemaName);
|
36
|
+
}
|
37
|
+
}
|
38
|
+
|
39
|
+
@Override
|
40
|
+
public void close() throws SQLException
|
41
|
+
{
|
42
|
+
if (!connection.isClosed()) {
|
43
|
+
connection.close();
|
44
|
+
}
|
45
|
+
}
|
46
|
+
|
47
|
+
public String getSchemaName()
|
48
|
+
{
|
49
|
+
return schemaName;
|
50
|
+
}
|
51
|
+
|
52
|
+
public DatabaseMetaData getMetaData() throws SQLException
|
53
|
+
{
|
54
|
+
return databaseMetaData;
|
55
|
+
}
|
56
|
+
|
57
|
+
public Charset getTableNameCharset() throws SQLException
|
58
|
+
{
|
59
|
+
return StandardCharsets.UTF_8;
|
60
|
+
}
|
61
|
+
|
62
|
+
protected void setSearchPath(String schema) throws SQLException
|
63
|
+
{
|
64
|
+
Statement stmt = connection.createStatement();
|
65
|
+
try {
|
66
|
+
String sql = "DATABASE " + quoteIdentifierString(schema);
|
67
|
+
executeUpdate(stmt, sql);
|
68
|
+
commitIfNecessary(connection);
|
69
|
+
} finally {
|
70
|
+
stmt.close();
|
71
|
+
}
|
72
|
+
}
|
73
|
+
|
74
|
+
// Teradata doesn't support CREATE TABLE IF NOT EXIST
|
75
|
+
@Override
|
76
|
+
protected String buildCreateTableIfNotExistsSql(TableIdentifier table, JdbcSchema schema) {
|
77
|
+
StringBuilder sb = new StringBuilder();
|
78
|
+
sb.append("CREATE TABLE ");
|
79
|
+
this.quoteTableIdentifier(sb, table);
|
80
|
+
sb.append(this.buildCreateTableSchemaSql(schema));
|
81
|
+
return sb.toString();
|
82
|
+
}
|
83
|
+
|
84
|
+
@Override
|
85
|
+
protected void dropTableIfExists(Statement stmt, TableIdentifier table) throws SQLException
|
86
|
+
{
|
87
|
+
if (existTable(table.getTableName()))
|
88
|
+
{
|
89
|
+
String sql = format("DROP TABLE %s", this.quoteTableIdentifier(table));
|
90
|
+
this.executeUpdate(stmt, sql);
|
91
|
+
}
|
92
|
+
else
|
93
|
+
{
|
94
|
+
logger.info(format("Skip dropping the table: %s", quoteIdentifierString(table.getTableName())));
|
95
|
+
}
|
96
|
+
}
|
97
|
+
|
98
|
+
// Teradata doesn't support IF EXISTS
|
99
|
+
public boolean existTable(String tableName)
|
100
|
+
{
|
101
|
+
try{
|
102
|
+
String sql = format("SELECT COUNT(1) FROM %s", quoteIdentifierString(tableName));
|
103
|
+
executeSql(sql);
|
104
|
+
} catch (SQLException se){
|
105
|
+
return false;
|
106
|
+
}
|
107
|
+
return true;
|
108
|
+
}
|
109
|
+
|
110
|
+
protected String buildCreateTableSchemaSql(JdbcSchema schema)
|
111
|
+
{
|
112
|
+
StringBuilder sb = new StringBuilder();
|
113
|
+
|
114
|
+
sb.append(" (");
|
115
|
+
for (int i=0; i < schema.getCount(); i++) {
|
116
|
+
if (i != 0) { sb.append(", "); }
|
117
|
+
quoteIdentifierString(sb, schema.getColumnName(i));
|
118
|
+
sb.append(" ");
|
119
|
+
String typeName = getCreateTableTypeName(schema.getColumn(i));
|
120
|
+
sb.append(typeName);
|
121
|
+
}
|
122
|
+
sb.append(")");
|
123
|
+
|
124
|
+
return sb.toString();
|
125
|
+
}
|
126
|
+
|
127
|
+
protected String getCreateTableTypeName(JdbcColumn c)
|
128
|
+
{
|
129
|
+
if (c.getDeclaredType().isPresent()) {
|
130
|
+
return c.getDeclaredType().get();
|
131
|
+
} else {
|
132
|
+
return buildColumnTypeName(c);
|
133
|
+
}
|
134
|
+
}
|
135
|
+
|
136
|
+
protected String buildColumnTypeName(JdbcColumn c)
|
137
|
+
{
|
138
|
+
String simpleTypeName = c.getSimpleTypeName();
|
139
|
+
switch (getColumnDeclareType(simpleTypeName, c)) {
|
140
|
+
case SIZE:
|
141
|
+
return format("%s(%d)", simpleTypeName, c.getSizeTypeParameter());
|
142
|
+
case SIZE_AND_SCALE:
|
143
|
+
if (c.getScaleTypeParameter() < 0) {
|
144
|
+
return format("%s(%d,0)", simpleTypeName, c.getSizeTypeParameter());
|
145
|
+
} else {
|
146
|
+
return format("%s(%d,%d)", simpleTypeName, c.getSizeTypeParameter(), c.getScaleTypeParameter());
|
147
|
+
}
|
148
|
+
case SIZE_AND_OPTIONAL_SCALE:
|
149
|
+
if (c.getScaleTypeParameter() < 0) {
|
150
|
+
return format("%s(%d)", simpleTypeName, c.getSizeTypeParameter());
|
151
|
+
} else {
|
152
|
+
return format("%s(%d,%d)", simpleTypeName, c.getSizeTypeParameter(), c.getScaleTypeParameter());
|
153
|
+
}
|
154
|
+
default: // SIMPLE
|
155
|
+
if (simpleTypeName.equals("CLOB"))
|
156
|
+
{
|
157
|
+
return "VARCHAR(1024)";
|
158
|
+
}
|
159
|
+
return simpleTypeName;
|
160
|
+
}
|
161
|
+
}
|
162
|
+
|
163
|
+
protected void executeSql(String sql) throws SQLException
|
164
|
+
{
|
165
|
+
Statement stmt = connection.createStatement();
|
166
|
+
try {
|
167
|
+
executeUpdate(stmt, sql);
|
168
|
+
commitIfNecessary(connection);
|
169
|
+
} catch (SQLException ex) {
|
170
|
+
throw safeRollback(connection, ex);
|
171
|
+
} finally {
|
172
|
+
stmt.close();
|
173
|
+
}
|
174
|
+
}
|
175
|
+
|
176
|
+
@Override
|
177
|
+
protected String buildRenameTableSql(TableIdentifier fromTable, TableIdentifier toTable) {
|
178
|
+
StringBuilder sb = new StringBuilder();
|
179
|
+
sb.append("RENAME TABLE ");
|
180
|
+
this.quoteTableIdentifier(sb, fromTable);
|
181
|
+
sb.append(" TO ");
|
182
|
+
this.quoteTableIdentifier(sb, toTable);
|
183
|
+
return sb.toString();
|
184
|
+
}
|
185
|
+
|
186
|
+
|
187
|
+
protected void quoteIdentifierString(StringBuilder sb, String str)
|
188
|
+
{
|
189
|
+
sb.append(quoteIdentifierString(str, identifierQuoteString));
|
190
|
+
}
|
191
|
+
|
192
|
+
protected String quoteIdentifierString(String str)
|
193
|
+
{
|
194
|
+
return quoteIdentifierString(str, identifierQuoteString);
|
195
|
+
}
|
196
|
+
|
197
|
+
protected String quoteIdentifierString(String str, String quoteString)
|
198
|
+
{
|
199
|
+
// TODO if identifierQuoteString.equals(" ") && str.contains([^a-zA-Z0-9_connection.getMetaData().getExtraNameCharacters()])
|
200
|
+
// TODO if str.contains(identifierQuoteString);
|
201
|
+
return quoteString + str + quoteString;
|
202
|
+
}
|
203
|
+
|
204
|
+
public boolean isValidConnection(int timeout) throws SQLException
|
205
|
+
{
|
206
|
+
Statement stmt = connection.createStatement();
|
207
|
+
try {
|
208
|
+
stmt.executeQuery("SELECT 1").close();
|
209
|
+
return true;
|
210
|
+
} catch (SQLException ex) {
|
211
|
+
return false;
|
212
|
+
} finally {
|
213
|
+
stmt.close();
|
214
|
+
}
|
215
|
+
}
|
216
|
+
|
217
|
+
protected String[] getDeterministicSqlStates()
|
218
|
+
{
|
219
|
+
return new String[0];
|
220
|
+
}
|
221
|
+
|
222
|
+
protected int[] getDeterministicErrorCodes()
|
223
|
+
{
|
224
|
+
return new int[0];
|
225
|
+
}
|
226
|
+
|
227
|
+
protected Class[] getDeterministicRootCauses()
|
228
|
+
{
|
229
|
+
return new Class[] {
|
230
|
+
// Don't retry on UnknownHostException.
|
231
|
+
java.net.UnknownHostException.class,
|
232
|
+
|
233
|
+
//// we should not retry on connect() error?
|
234
|
+
//java.net.ConnectException.class,
|
235
|
+
};
|
236
|
+
}
|
237
|
+
|
238
|
+
public boolean isRetryableException(SQLException exception)
|
239
|
+
{
|
240
|
+
String sqlState = exception.getSQLState();
|
241
|
+
for (String deterministic : getDeterministicSqlStates()) {
|
242
|
+
if (sqlState.equals(deterministic)) {
|
243
|
+
return false;
|
244
|
+
}
|
245
|
+
}
|
246
|
+
|
247
|
+
int errorCode = exception.getErrorCode();
|
248
|
+
for (int deterministic : getDeterministicErrorCodes()) {
|
249
|
+
if (errorCode == deterministic) {
|
250
|
+
return false;
|
251
|
+
}
|
252
|
+
}
|
253
|
+
|
254
|
+
Throwable rootCause = getRootCause(exception);
|
255
|
+
for (Class deterministic : getDeterministicRootCauses()) {
|
256
|
+
if (deterministic.equals(rootCause.getClass())) {
|
257
|
+
return false;
|
258
|
+
}
|
259
|
+
}
|
260
|
+
|
261
|
+
return true;
|
262
|
+
}
|
263
|
+
|
264
|
+
private Throwable getRootCause(Throwable e) {
|
265
|
+
while (e.getCause() != null) {
|
266
|
+
e = e.getCause();
|
267
|
+
}
|
268
|
+
return e;
|
269
|
+
}
|
270
|
+
|
271
|
+
protected int executeUpdate(Statement stmt, String sql) throws SQLException
|
272
|
+
{
|
273
|
+
logger.info("SQL: " + sql);
|
274
|
+
long startTime = System.currentTimeMillis();
|
275
|
+
int count = stmt.executeUpdate(sql);
|
276
|
+
double seconds = (System.currentTimeMillis() - startTime) / 1000.0;
|
277
|
+
if (count == 0) {
|
278
|
+
logger.info(format("> %.2f seconds", seconds));
|
279
|
+
} else {
|
280
|
+
logger.info(format("> %.2f seconds (%,d rows)", seconds, count));
|
281
|
+
}
|
282
|
+
return count;
|
283
|
+
}
|
284
|
+
|
285
|
+
protected void commitIfNecessary(Connection con) throws SQLException
|
286
|
+
{
|
287
|
+
if (!con.getAutoCommit()) {
|
288
|
+
con.commit();
|
289
|
+
}
|
290
|
+
}
|
291
|
+
|
292
|
+
protected SQLException safeRollback(Connection con, SQLException cause)
|
293
|
+
{
|
294
|
+
try {
|
295
|
+
if (!con.getAutoCommit()) {
|
296
|
+
con.rollback();
|
297
|
+
}
|
298
|
+
return cause;
|
299
|
+
} catch (SQLException ex) {
|
300
|
+
if (cause != null) {
|
301
|
+
cause.addSuppressed(ex);
|
302
|
+
return cause;
|
303
|
+
}
|
304
|
+
return ex;
|
305
|
+
}
|
306
|
+
}
|
307
|
+
}
|