embulk-output-teradata 0.1.2 → 0.1.3

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 (50) hide show
  1. checksums.yaml +4 -4
  2. data/.DS_Store +0 -0
  3. data/README.md +0 -8
  4. data/build.gradle +5 -2
  5. data/embulk-output-teradata.iml +12 -0
  6. data/gradle/wrapper/gradle-wrapper.properties +2 -2
  7. data/gradlew +0 -0
  8. data/lib/embulk-output-jdbc-0.7.11.jar +0 -0
  9. data/src/main/java/org/embulk/output/teradata/TeradataOutputPlugin.java +13 -52
  10. data/src/main/java/org/embulk/output/teradata/jdbc/TeradataBatchInsert.java +37 -0
  11. data/src/main/java/org/embulk/output/teradata/jdbc/TeradataOutputConnection.java +307 -0
  12. data/src/main/java/org/embulk/output/teradata/jdbc/TeradataOutputConnector.java +46 -0
  13. metadata +10 -40
  14. data/src/main/java/org/embulk/output/teradata/JdbcOutputPlugin.java +0 -134
  15. data/src/main/java/org/embulk/output/teradata/TeradataOutputConnection.java +0 -19
  16. data/src/main/java/org/embulk/output/teradata/jdbc/AbstractJdbcOutputPlugin.java +0 -1144
  17. data/src/main/java/org/embulk/output/teradata/jdbc/BatchInsert.java +0 -52
  18. data/src/main/java/org/embulk/output/teradata/jdbc/JdbcColumn.java +0 -134
  19. data/src/main/java/org/embulk/output/teradata/jdbc/JdbcColumnOption.java +0 -34
  20. data/src/main/java/org/embulk/output/teradata/jdbc/JdbcOutputConnection.java +0 -549
  21. data/src/main/java/org/embulk/output/teradata/jdbc/JdbcOutputConnector.java +0 -8
  22. data/src/main/java/org/embulk/output/teradata/jdbc/JdbcSchema.java +0 -79
  23. data/src/main/java/org/embulk/output/teradata/jdbc/JdbcUtils.java +0 -153
  24. data/src/main/java/org/embulk/output/teradata/jdbc/MergeConfig.java +0 -23
  25. data/src/main/java/org/embulk/output/teradata/jdbc/StandardBatchInsert.java +0 -201
  26. data/src/main/java/org/embulk/output/teradata/jdbc/TimestampFormat.java +0 -37
  27. data/src/main/java/org/embulk/output/teradata/jdbc/ToString.java +0 -54
  28. data/src/main/java/org/embulk/output/teradata/jdbc/ToStringMap.java +0 -34
  29. data/src/main/java/org/embulk/output/teradata/jdbc/setter/BigDecimalColumnSetter.java +0 -76
  30. data/src/main/java/org/embulk/output/teradata/jdbc/setter/BooleanColumnSetter.java +0 -61
  31. data/src/main/java/org/embulk/output/teradata/jdbc/setter/ByteColumnSetter.java +0 -84
  32. data/src/main/java/org/embulk/output/teradata/jdbc/setter/ColumnSetter.java +0 -48
  33. data/src/main/java/org/embulk/output/teradata/jdbc/setter/ColumnSetterFactory.java +0 -199
  34. data/src/main/java/org/embulk/output/teradata/jdbc/setter/ColumnSetterVisitor.java +0 -110
  35. data/src/main/java/org/embulk/output/teradata/jdbc/setter/DefaultValueSetter.java +0 -50
  36. data/src/main/java/org/embulk/output/teradata/jdbc/setter/DoubleColumnSetter.java +0 -68
  37. data/src/main/java/org/embulk/output/teradata/jdbc/setter/FloatColumnSetter.java +0 -68
  38. data/src/main/java/org/embulk/output/teradata/jdbc/setter/IntColumnSetter.java +0 -84
  39. data/src/main/java/org/embulk/output/teradata/jdbc/setter/JsonColumnSetter.java +0 -61
  40. data/src/main/java/org/embulk/output/teradata/jdbc/setter/LongColumnSetter.java +0 -80
  41. data/src/main/java/org/embulk/output/teradata/jdbc/setter/NStringColumnSetter.java +0 -66
  42. data/src/main/java/org/embulk/output/teradata/jdbc/setter/NullColumnSetter.java +0 -61
  43. data/src/main/java/org/embulk/output/teradata/jdbc/setter/NullDefaultValueSetter.java +0 -111
  44. data/src/main/java/org/embulk/output/teradata/jdbc/setter/PassThroughColumnSetter.java +0 -66
  45. data/src/main/java/org/embulk/output/teradata/jdbc/setter/ShortColumnSetter.java +0 -84
  46. data/src/main/java/org/embulk/output/teradata/jdbc/setter/SkipColumnSetter.java +0 -49
  47. data/src/main/java/org/embulk/output/teradata/jdbc/setter/SqlDateColumnSetter.java +0 -66
  48. data/src/main/java/org/embulk/output/teradata/jdbc/setter/SqlTimeColumnSetter.java +0 -66
  49. data/src/main/java/org/embulk/output/teradata/jdbc/setter/SqlTimestampColumnSetter.java +0 -66
  50. data/src/main/java/org/embulk/output/teradata/jdbc/setter/StringColumnSetter.java +0 -66
@@ -1,52 +0,0 @@
1
- package org.embulk.output.jdbc;
2
-
3
- import java.math.BigDecimal;
4
- import java.util.Calendar;
5
- import java.io.IOException;
6
- import java.sql.SQLException;
7
- import org.embulk.spi.time.Timestamp;
8
-
9
- public interface BatchInsert
10
- {
11
- public void prepare(String loadTable, JdbcSchema insertSchema) throws SQLException;
12
-
13
- public int getBatchWeight();
14
-
15
- public void add() throws IOException, SQLException;
16
-
17
- public void close() throws IOException, SQLException;
18
-
19
- public void flush() throws IOException, SQLException;
20
-
21
- public void finish() throws IOException, SQLException;
22
-
23
- public void setNull(int sqlType) throws IOException, SQLException;
24
-
25
- public void setBoolean(boolean v) throws IOException, SQLException;
26
-
27
- public void setByte(byte v) throws IOException, SQLException;
28
-
29
- public void setShort(short v) throws IOException, SQLException;
30
-
31
- public void setInt(int v) throws IOException, SQLException;
32
-
33
- public void setLong(long v) throws IOException, SQLException;
34
-
35
- public void setFloat(float v) throws IOException, SQLException;
36
-
37
- public void setDouble(double v) throws IOException, SQLException;
38
-
39
- public void setBigDecimal(BigDecimal v) throws IOException, SQLException;
40
-
41
- public void setString(String v) throws IOException, SQLException;
42
-
43
- public void setNString(String v) throws IOException, SQLException;
44
-
45
- public void setBytes(byte[] v) throws IOException, SQLException;
46
-
47
- public void setSqlDate(Timestamp v, Calendar cal) throws IOException, SQLException;
48
-
49
- public void setSqlTime(Timestamp v, Calendar cal) throws IOException, SQLException;
50
-
51
- public void setSqlTimestamp(Timestamp v, Calendar cal) throws IOException, SQLException;
52
- }
@@ -1,134 +0,0 @@
1
- package org.embulk.output.jdbc;
2
-
3
- import com.google.common.base.Optional;
4
- import com.fasterxml.jackson.annotation.JsonCreator;
5
- import com.fasterxml.jackson.annotation.JsonProperty;
6
- import com.fasterxml.jackson.annotation.JsonIgnore;
7
-
8
- public class JdbcColumn
9
- {
10
- private final String name;
11
- private final String simpleTypeName;
12
- private final int sqlType;
13
- private final int sizeTypeParameter;
14
- private final int scaleTypeParameter;
15
- private final int dataLength;
16
- private final Optional<String> declaredType;
17
- private final boolean isNotNull;
18
- private final boolean isUniqueKey;
19
-
20
- @JsonCreator
21
- public JdbcColumn(
22
- @JsonProperty("name") String name,
23
- @JsonProperty("sqlType") int sqlType,
24
- @JsonProperty("simpleTypeName") String simpleTypeName,
25
- @JsonProperty("sizeTypeParameter") int sizeTypeParameter,
26
- @JsonProperty("scaleTypeParameter") int scaleTypeParameter,
27
- @JsonProperty("dataLength") int dataLength,
28
- @JsonProperty("declaredType") Optional<String> declaredType,
29
- @JsonProperty("notNull") boolean isNotNull,
30
- @JsonProperty("uniqueKey") boolean isUniqueKey)
31
- {
32
- this.name = name;
33
- this.simpleTypeName = simpleTypeName;
34
- this.sqlType = sqlType;
35
- this.sizeTypeParameter = sizeTypeParameter;
36
- this.scaleTypeParameter = scaleTypeParameter;
37
- this.dataLength = dataLength;
38
- this.declaredType = declaredType;
39
- this.isNotNull = isNotNull;
40
- this.isUniqueKey = isUniqueKey;
41
- }
42
-
43
- public static JdbcColumn newGenericTypeColumn(String name, int sqlType,
44
- String simpleTypeName, int sizeTypeParameter, int scaleTypeParameter, int dataLength,
45
- boolean isNotNull, boolean isUniqueKey)
46
- {
47
- return new JdbcColumn(name, sqlType,
48
- simpleTypeName, sizeTypeParameter, scaleTypeParameter, dataLength,
49
- Optional.<String>absent(), isNotNull, isUniqueKey);
50
- }
51
-
52
- public static JdbcColumn newGenericTypeColumn(String name, int sqlType,
53
- String simpleTypeName, int sizeTypeParameter, int scaleTypeParameter,
54
- boolean isNotNull, boolean isUniqueKey)
55
- {
56
- return new JdbcColumn(name, sqlType,
57
- simpleTypeName, sizeTypeParameter, scaleTypeParameter, sizeTypeParameter,
58
- Optional.<String>absent(), isNotNull, isUniqueKey);
59
- }
60
-
61
- public static JdbcColumn newTypeDeclaredColumn(String name, int sqlType,
62
- String declaredType, boolean isNotNull, boolean isUniqueKey)
63
- {
64
- return new JdbcColumn(name, sqlType,
65
- declaredType, 0, 0, 0,
66
- Optional.of(declaredType), isNotNull, isUniqueKey);
67
- }
68
-
69
- @JsonIgnore
70
- public static JdbcColumn skipColumn()
71
- {
72
- return new JdbcColumn(null, 0, null, 0, 0, 0, Optional.<String>absent(), false, false);
73
- }
74
-
75
- @JsonIgnore
76
- public boolean isSkipColumn()
77
- {
78
- return name == null;
79
- }
80
-
81
- @JsonProperty("name")
82
- public String getName()
83
- {
84
- return name;
85
- }
86
-
87
- @JsonProperty("sqlType")
88
- public int getSqlType()
89
- {
90
- return sqlType;
91
- }
92
-
93
- @JsonProperty("simpleTypeName")
94
- public String getSimpleTypeName()
95
- {
96
- return simpleTypeName;
97
- }
98
-
99
- @JsonProperty("sizeTypeParameter")
100
- public int getSizeTypeParameter()
101
- {
102
- return sizeTypeParameter;
103
- }
104
-
105
- @JsonProperty("scaleTypeParameter")
106
- public int getScaleTypeParameter()
107
- {
108
- return scaleTypeParameter;
109
- }
110
-
111
- @JsonProperty("dataLength")
112
- public int getDataLength()
113
- {
114
- return dataLength;
115
- }
116
-
117
- @JsonProperty("declaredType")
118
- public Optional<String> getDeclaredType()
119
- {
120
- return declaredType;
121
- }
122
-
123
- @JsonProperty("notNull")
124
- public boolean isNotNull()
125
- {
126
- return isNotNull;
127
- }
128
-
129
- @JsonProperty("uniqueKey")
130
- public boolean isUniqueKey()
131
- {
132
- return isUniqueKey;
133
- }
134
- }
@@ -1,34 +0,0 @@
1
- package org.embulk.output.jdbc;
2
-
3
- import com.google.common.base.Optional;
4
- import org.joda.time.DateTimeZone;
5
- import org.jruby.embed.ScriptingContainer;
6
- import org.embulk.config.Task;
7
- import org.embulk.config.Config;
8
- import org.embulk.config.ConfigDefault;
9
- import org.embulk.config.ConfigInject;
10
- import org.embulk.spi.time.TimestampFormat;
11
-
12
- public interface JdbcColumnOption
13
- extends Task
14
- {
15
- @Config("type")
16
- @ConfigDefault("null")
17
- public Optional<String> getType();
18
-
19
- @Config("value_type")
20
- @ConfigDefault("\"coerce\"")
21
- public String getValueType();
22
-
23
- @Config("timestamp_format")
24
- @ConfigDefault("\"%Y-%m-%d %H:%M:%S.%6N\"")
25
- public TimestampFormat getTimestampFormat();
26
-
27
- @Config("timezone")
28
- @ConfigDefault("null")
29
- public Optional<DateTimeZone> getTimeZone();
30
-
31
- // required by TimestampFormatter
32
- @ConfigInject
33
- public ScriptingContainer getJRuby();
34
- }
@@ -1,549 +0,0 @@
1
- package org.embulk.output.jdbc;
2
-
3
- import java.util.List;
4
- import java.nio.charset.Charset;
5
- import java.nio.charset.StandardCharsets;
6
- import java.sql.Connection;
7
- import java.sql.DatabaseMetaData;
8
- import java.sql.PreparedStatement;
9
- import java.sql.ResultSet;
10
- import java.sql.SQLException;
11
- import java.sql.Statement;
12
-
13
- import org.slf4j.Logger;
14
- import com.google.common.base.Optional;
15
- import org.embulk.spi.Exec;
16
-
17
- public class JdbcOutputConnection
18
- implements AutoCloseable
19
- {
20
- private final Logger logger = Exec.getLogger(JdbcOutputConnection.class);
21
- protected final Connection connection;
22
- protected final String schemaName;
23
- protected final DatabaseMetaData databaseMetaData;
24
- protected String identifierQuoteString;
25
-
26
- public JdbcOutputConnection(Connection connection, String schemaName)
27
- throws SQLException
28
- {
29
- this.connection = connection;
30
- this.schemaName = schemaName;
31
- this.databaseMetaData = connection.getMetaData();
32
- this.identifierQuoteString = databaseMetaData.getIdentifierQuoteString();
33
- if (schemaName != null) {
34
- setSearchPath(schemaName);
35
- }
36
- }
37
-
38
- @Override
39
- public void close() throws SQLException
40
- {
41
- if (!connection.isClosed()) {
42
- connection.close();
43
- }
44
- }
45
-
46
- public String getSchemaName()
47
- {
48
- return schemaName;
49
- }
50
-
51
- public DatabaseMetaData getMetaData() throws SQLException
52
- {
53
- return databaseMetaData;
54
- }
55
-
56
- public Charset getTableNameCharset() throws SQLException
57
- {
58
- return StandardCharsets.UTF_8;
59
- }
60
-
61
- protected void setSearchPath(String schema) throws SQLException
62
- {
63
- Statement stmt = connection.createStatement();
64
- try {
65
- String sql = "DATABASE " + quoteIdentifierString(schema);
66
- executeUpdate(stmt, sql);
67
- commitIfNecessary(connection);
68
- } finally {
69
- stmt.close();
70
- }
71
- }
72
-
73
- public boolean tableExists(String tableName) throws SQLException
74
- {
75
- try (ResultSet rs = connection.getMetaData().getTables(null, schemaName, tableName, null)) {
76
- return rs.next();
77
- }
78
- }
79
-
80
- public void dropTableIfExists(String tableName) throws SQLException
81
- {
82
- Statement stmt = connection.createStatement();
83
- try {
84
- dropTableIfExists(stmt, tableName);
85
- commitIfNecessary(connection);
86
- } catch (SQLException ex) {
87
- throw safeRollback(connection, ex);
88
- } finally {
89
- stmt.close();
90
- }
91
- }
92
-
93
- protected void dropTableIfExists(Statement stmt, String tableName) throws SQLException
94
- {
95
- if (existTable(tableName))
96
- {
97
- String sql = String.format("DROP TABLE %s", quoteIdentifierString(tableName));
98
- executeUpdate(stmt, sql);
99
- }
100
- }
101
-
102
- // TODO: Teradata doesn't support IF EXISTS
103
- public boolean existTable(String tableName)
104
- {
105
- try{
106
- String sql = String.format("SELECT COUNT(1) FROM %s", quoteIdentifierString(tableName));
107
- executeSql(sql);
108
- } catch (SQLException se){
109
- return false;
110
- }
111
- return true;
112
- }
113
-
114
- public void dropTable(String tableName) throws SQLException
115
- {
116
- Statement stmt = connection.createStatement();
117
- try {
118
- dropTable(stmt, tableName);
119
- commitIfNecessary(connection);
120
- } catch (SQLException ex) {
121
- throw safeRollback(connection, ex);
122
- } finally {
123
- stmt.close();
124
- }
125
- }
126
-
127
- protected void dropTable(Statement stmt, String tableName) throws SQLException
128
- {
129
- String sql = String.format("DROP TABLE %s", quoteIdentifierString(tableName));
130
- executeUpdate(stmt, sql);
131
- }
132
-
133
- public void createTableIfNotExists(String tableName, JdbcSchema schema) throws SQLException
134
- {
135
- Statement stmt = connection.createStatement();
136
- try {
137
- String sql = buildCreateTableIfNotExistsSql(tableName, schema);
138
-
139
- if (!tableExists(tableName)) {
140
- executeUpdate(stmt, sql);
141
- commitIfNecessary(connection);
142
- }
143
-
144
- } catch (SQLException ex) {
145
- throw safeRollback(connection, ex);
146
- } finally {
147
- stmt.close();
148
- }
149
- }
150
-
151
- protected String buildCreateTableIfNotExistsSql(String name, JdbcSchema schema)
152
- {
153
- StringBuilder sb = new StringBuilder();
154
-
155
- sb.append("CREATE TABLE ");
156
- quoteIdentifierString(sb, name);
157
- sb.append(buildCreateTableSchemaSql(schema));
158
- sb.append(" NO PRIMARY INDEX");
159
- return sb.toString();
160
- }
161
-
162
- protected String buildCreateTableSchemaSql(JdbcSchema schema)
163
- {
164
- StringBuilder sb = new StringBuilder();
165
-
166
- sb.append(" (");
167
- for (int i=0; i < schema.getCount(); i++) {
168
- if (i != 0) { sb.append(", "); }
169
- quoteIdentifierString(sb, schema.getColumnName(i));
170
- sb.append(" ");
171
- String typeName = getCreateTableTypeName(schema.getColumn(i));
172
- sb.append(typeName);
173
- }
174
- sb.append(")");
175
-
176
- return sb.toString();
177
- }
178
-
179
- protected String buildRenameTableSql(String fromTable, String toTable)
180
- {
181
- StringBuilder sb = new StringBuilder();
182
- sb.append("ALTER TABLE ");
183
- quoteIdentifierString(sb, fromTable);
184
- sb.append(" RENAME TO ");
185
- quoteIdentifierString(sb, toTable);
186
- return sb.toString();
187
- }
188
-
189
- public static enum ColumnDeclareType
190
- {
191
- SIMPLE,
192
- SIZE,
193
- SIZE_AND_SCALE,
194
- SIZE_AND_OPTIONAL_SCALE,
195
- };
196
-
197
- protected String getCreateTableTypeName(JdbcColumn c)
198
- {
199
- if (c.getDeclaredType().isPresent()) {
200
- return c.getDeclaredType().get();
201
- } else {
202
- return buildColumnTypeName(c);
203
- }
204
- }
205
-
206
- protected String buildColumnTypeName(JdbcColumn c)
207
- {
208
- String simpleTypeName = c.getSimpleTypeName();
209
- switch (getColumnDeclareType(simpleTypeName, c)) {
210
- case SIZE:
211
- return String.format("%s(%d)", simpleTypeName, c.getSizeTypeParameter());
212
- case SIZE_AND_SCALE:
213
- if (c.getScaleTypeParameter() < 0) {
214
- return String.format("%s(%d,0)", simpleTypeName, c.getSizeTypeParameter());
215
- } else {
216
- return String.format("%s(%d,%d)", simpleTypeName, c.getSizeTypeParameter(), c.getScaleTypeParameter());
217
- }
218
- case SIZE_AND_OPTIONAL_SCALE:
219
- if (c.getScaleTypeParameter() < 0) {
220
- return String.format("%s(%d)", simpleTypeName, c.getSizeTypeParameter());
221
- } else {
222
- return String.format("%s(%d,%d)", simpleTypeName, c.getSizeTypeParameter(), c.getScaleTypeParameter());
223
- }
224
- default: // SIMPLE
225
- return simpleTypeName;
226
- }
227
- }
228
-
229
- // TODO
230
- private static final String[] STANDARD_SIZE_TYPE_NAMES = new String[] {
231
- "CHAR",
232
- "VARCHAR", "CHAR VARYING", "CHARACTER VARYING", "LONGVARCHAR",
233
- "NCHAR",
234
- "NVARCHAR", "NCHAR VARYING", "NATIONAL CHAR VARYING", "NATIONAL CHARACTER VARYING",
235
- "BINARY",
236
- "VARBINARY", "BINARY VARYING", "LONGVARBINARY",
237
- "BIT",
238
- "VARBIT", "BIT VARYING",
239
- "FLOAT", // SQL standard's FLOAT[(p)] optionally accepts precision
240
- };
241
-
242
- private static final String[] STANDARD_SIZE_AND_SCALE_TYPE_NAMES = new String[] {
243
- "DECIMAL",
244
- "NUMERIC",
245
- };
246
-
247
- protected ColumnDeclareType getColumnDeclareType(String convertedTypeName, JdbcColumn col)
248
- {
249
- for (String x : STANDARD_SIZE_TYPE_NAMES) {
250
- if (x.equals(convertedTypeName)) {
251
- return ColumnDeclareType.SIZE;
252
- }
253
- }
254
-
255
- for (String x : STANDARD_SIZE_AND_SCALE_TYPE_NAMES) {
256
- if (x.equals(convertedTypeName)) {
257
- return ColumnDeclareType.SIZE_AND_SCALE;
258
- }
259
- }
260
-
261
- return ColumnDeclareType.SIMPLE;
262
- }
263
-
264
- public PreparedStatement prepareBatchInsertStatement(String toTable, JdbcSchema toTableSchema, Optional<MergeConfig> mergeConfig) throws SQLException
265
- {
266
- String sql;
267
- if (mergeConfig.isPresent()) {
268
- sql = buildPreparedMergeSql(toTable, toTableSchema, mergeConfig.get());
269
- } else {
270
- sql = buildPreparedInsertSql(toTable, toTableSchema);
271
- }
272
- logger.info("Prepared SQL: {}", sql);
273
- return connection.prepareStatement(sql);
274
- }
275
-
276
- protected String buildPreparedInsertSql(String toTable, JdbcSchema toTableSchema) throws SQLException
277
- {
278
- StringBuilder sb = new StringBuilder();
279
-
280
- sb.append("INSERT INTO ");
281
- quoteIdentifierString(sb, toTable);
282
-
283
- sb.append(" (");
284
- for (int i=0; i < toTableSchema.getCount(); i++) {
285
- if(i != 0) { sb.append(", "); }
286
- quoteIdentifierString(sb, toTableSchema.getColumnName(i));
287
- }
288
- sb.append(") VALUES (");
289
- for(int i=0; i < toTableSchema.getCount(); i++) {
290
- if(i != 0) { sb.append(", "); }
291
- sb.append("?");
292
- }
293
- sb.append(")");
294
-
295
- return sb.toString();
296
- }
297
-
298
- protected String buildPreparedMergeSql(String toTable, JdbcSchema toTableSchema, MergeConfig mergeConfig) throws SQLException
299
- {
300
- throw new UnsupportedOperationException("not implemented");
301
- }
302
-
303
- protected void executeSql(String sql) throws SQLException
304
- {
305
- Statement stmt = connection.createStatement();
306
- try {
307
- executeUpdate(stmt, sql);
308
- commitIfNecessary(connection);
309
- } catch (SQLException ex) {
310
- throw safeRollback(connection, ex);
311
- } finally {
312
- stmt.close();
313
- }
314
- }
315
-
316
- protected void collectInsert(List<String> fromTables, JdbcSchema schema, String toTable,
317
- boolean truncateDestinationFirst, Optional<String> additionalSql) throws SQLException
318
- {
319
- if (fromTables.isEmpty()) {
320
- return;
321
- }
322
-
323
- Statement stmt = connection.createStatement();
324
- try {
325
- if (truncateDestinationFirst) {
326
- String sql = buildTruncateSql(toTable);
327
- executeUpdate(stmt, sql);
328
- }
329
- String sql = buildCollectInsertSql(fromTables, schema, toTable);
330
- executeUpdate(stmt, sql);
331
- if (additionalSql.isPresent()) {
332
- executeUpdate(stmt, additionalSql.get());
333
- }
334
- commitIfNecessary(connection);
335
- } catch (SQLException ex) {
336
- throw safeRollback(connection, ex);
337
- } finally {
338
- stmt.close();
339
- }
340
- }
341
-
342
- protected String buildTruncateSql(String table)
343
- {
344
- StringBuilder sb = new StringBuilder();
345
-
346
- sb.append("DELETE FROM ");
347
- quoteIdentifierString(sb, table);
348
-
349
- return sb.toString();
350
- }
351
-
352
- protected String buildCollectInsertSql(List<String> fromTables, JdbcSchema schema, String toTable)
353
- {
354
- StringBuilder sb = new StringBuilder();
355
-
356
- sb.append("INSERT INTO ");
357
- quoteIdentifierString(sb, toTable);
358
- sb.append(" (");
359
- for (int i=0; i < schema.getCount(); i++) {
360
- if (i != 0) { sb.append(", "); }
361
- quoteIdentifierString(sb, schema.getColumnName(i));
362
- }
363
- sb.append(") ");
364
- for (int i=0; i < fromTables.size(); i++) {
365
- if (i != 0) { sb.append(" UNION ALL "); }
366
- sb.append("SELECT ");
367
- for (int j=0; j < schema.getCount(); j++) {
368
- if (j != 0) { sb.append(", "); }
369
- quoteIdentifierString(sb, schema.getColumnName(j));
370
- }
371
- sb.append(" FROM ");
372
- quoteIdentifierString(sb, fromTables.get(i));
373
- }
374
-
375
- return sb.toString();
376
- }
377
-
378
- protected void collectMerge(List<String> fromTables, JdbcSchema schema, String toTable, MergeConfig mergeConfig,
379
- Optional<String> additionalSql) throws SQLException
380
- {
381
- if (fromTables.isEmpty()) {
382
- return;
383
- }
384
-
385
- Statement stmt = connection.createStatement();
386
- try {
387
- String sql = buildCollectMergeSql(fromTables, schema, toTable, mergeConfig);
388
- executeUpdate(stmt, sql);
389
- if (additionalSql.isPresent()) {
390
- executeUpdate(stmt, additionalSql.get());
391
- }
392
- commitIfNecessary(connection);
393
- } catch (SQLException ex) {
394
- throw safeRollback(connection, ex);
395
- } finally {
396
- stmt.close();
397
- }
398
- }
399
-
400
- protected String buildCollectMergeSql(List<String> fromTables, JdbcSchema schema, String toTable, MergeConfig mergeConfig) throws SQLException
401
- {
402
- throw new UnsupportedOperationException("not implemented");
403
- }
404
-
405
- public void replaceTable(String fromTable, JdbcSchema schema, String toTable, Optional<String> additionalSql) throws SQLException
406
- {
407
- Statement stmt = connection.createStatement();
408
- try {
409
- dropTableIfExists(stmt, toTable);
410
- executeUpdate(stmt, buildRenameTableSql(fromTable, toTable));
411
- if (additionalSql.isPresent()) {
412
- executeUpdate(stmt, additionalSql.get());
413
- }
414
- commitIfNecessary(connection);
415
- } catch (SQLException ex) {
416
- throw safeRollback(connection, ex);
417
- } finally {
418
- stmt.close();
419
- }
420
- }
421
-
422
- protected void quoteIdentifierString(StringBuilder sb, String str)
423
- {
424
- sb.append(quoteIdentifierString(str, identifierQuoteString));
425
- }
426
-
427
- protected String quoteIdentifierString(String str)
428
- {
429
- return quoteIdentifierString(str, identifierQuoteString);
430
- }
431
-
432
- protected String quoteIdentifierString(String str, String quoteString)
433
- {
434
- // TODO if identifierQuoteString.equals(" ") && str.contains([^a-zA-Z0-9_connection.getMetaData().getExtraNameCharacters()])
435
- // TODO if str.contains(identifierQuoteString);
436
- return quoteString + str + quoteString;
437
- }
438
-
439
- // PostgreSQL JDBC driver implements isValid() method. But the
440
- // implementation throws following exception:
441
- // "java.io.IOException: Method org.postgresql.jdbc4.Jdbc4Connection.isValid(int) is not yet implemented."
442
- //
443
- // So, checking mechanism doesn't work at all.
444
- // Thus here just runs "SELECT 1" to check connectivity.
445
- //
446
- public boolean isValidConnection(int timeout) throws SQLException
447
- {
448
- Statement stmt = connection.createStatement();
449
- try {
450
- stmt.executeQuery("SELECT 1").close();
451
- return true;
452
- } catch (SQLException ex) {
453
- return false;
454
- } finally {
455
- stmt.close();
456
- }
457
- }
458
-
459
- protected String[] getDeterministicSqlStates()
460
- {
461
- return new String[0];
462
- }
463
-
464
- protected int[] getDeterministicErrorCodes()
465
- {
466
- return new int[0];
467
- }
468
-
469
- protected Class[] getDeterministicRootCauses()
470
- {
471
- return new Class[] {
472
- // Don't retry on UnknownHostException.
473
- java.net.UnknownHostException.class,
474
-
475
- //// we should not retry on connect() error?
476
- //java.net.ConnectException.class,
477
- };
478
- }
479
-
480
- public boolean isRetryableException(SQLException exception)
481
- {
482
- String sqlState = exception.getSQLState();
483
- for (String deterministic : getDeterministicSqlStates()) {
484
- if (sqlState.equals(deterministic)) {
485
- return false;
486
- }
487
- }
488
-
489
- int errorCode = exception.getErrorCode();
490
- for (int deterministic : getDeterministicErrorCodes()) {
491
- if (errorCode == deterministic) {
492
- return false;
493
- }
494
- }
495
-
496
- Throwable rootCause = getRootCause(exception);
497
- for (Class deterministic : getDeterministicRootCauses()) {
498
- if (deterministic.equals(rootCause.getClass())) {
499
- return false;
500
- }
501
- }
502
-
503
- return true;
504
- }
505
-
506
- private Throwable getRootCause(Throwable e) {
507
- while (e.getCause() != null) {
508
- e = e.getCause();
509
- }
510
- return e;
511
- }
512
-
513
- protected int executeUpdate(Statement stmt, String sql) throws SQLException
514
- {
515
- logger.info("SQL: " + sql);
516
- long startTime = System.currentTimeMillis();
517
- int count = stmt.executeUpdate(sql);
518
- double seconds = (System.currentTimeMillis() - startTime) / 1000.0;
519
- if (count == 0) {
520
- logger.info(String.format("> %.2f seconds", seconds));
521
- } else {
522
- logger.info(String.format("> %.2f seconds (%,d rows)", seconds, count));
523
- }
524
- return count;
525
- }
526
-
527
- protected void commitIfNecessary(Connection con) throws SQLException
528
- {
529
- if (!con.getAutoCommit()) {
530
- con.commit();
531
- }
532
- }
533
-
534
- protected SQLException safeRollback(Connection con, SQLException cause)
535
- {
536
- try {
537
- if (!con.getAutoCommit()) {
538
- con.rollback();
539
- }
540
- return cause;
541
- } catch (SQLException ex) {
542
- if (cause != null) {
543
- cause.addSuppressed(ex);
544
- return cause;
545
- }
546
- return ex;
547
- }
548
- }
549
- }