embulk-input-athena 0.1.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 (45) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +13 -0
  3. data/Dockerfile +8 -0
  4. data/LICENSE +21 -0
  5. data/README.md +46 -0
  6. data/build.gradle +101 -0
  7. data/config/checkstyle/checkstyle.xml +128 -0
  8. data/config/checkstyle/default.xml +108 -0
  9. data/docker-compose.yml +10 -0
  10. data/gradle/wrapper/gradle-wrapper.jar +0 -0
  11. data/gradle/wrapper/gradle-wrapper.properties +5 -0
  12. data/gradlew +172 -0
  13. data/gradlew.bat +84 -0
  14. data/lib/embulk/input/athena.rb +3 -0
  15. data/src/main/java/org/embulk/input/athena/AthenaInputConnection.java +49 -0
  16. data/src/main/java/org/embulk/input/athena/AthenaInputPlugin.java +202 -0
  17. data/src/main/java/org/embulk/input/athena/AthenaInputPlugin.java.tmp1 +192 -0
  18. data/src/main/java/org/embulk/input/jdbc/AbstractJdbcInputPlugin.java +674 -0
  19. data/src/main/java/org/embulk/input/jdbc/JdbcColumn.java +58 -0
  20. data/src/main/java/org/embulk/input/jdbc/JdbcColumnOption.java +31 -0
  21. data/src/main/java/org/embulk/input/jdbc/JdbcInputConnection.java +397 -0
  22. data/src/main/java/org/embulk/input/jdbc/JdbcLiteral.java +38 -0
  23. data/src/main/java/org/embulk/input/jdbc/JdbcSchema.java +55 -0
  24. data/src/main/java/org/embulk/input/jdbc/Ssl.java +37 -0
  25. data/src/main/java/org/embulk/input/jdbc/ToString.java +54 -0
  26. data/src/main/java/org/embulk/input/jdbc/ToStringMap.java +35 -0
  27. data/src/main/java/org/embulk/input/jdbc/getter/AbstractColumnGetter.java +105 -0
  28. data/src/main/java/org/embulk/input/jdbc/getter/AbstractIncrementalHandler.java +45 -0
  29. data/src/main/java/org/embulk/input/jdbc/getter/AbstractTimestampColumnGetter.java +38 -0
  30. data/src/main/java/org/embulk/input/jdbc/getter/BigDecimalColumnGetter.java +59 -0
  31. data/src/main/java/org/embulk/input/jdbc/getter/BooleanColumnGetter.java +56 -0
  32. data/src/main/java/org/embulk/input/jdbc/getter/ColumnGetter.java +21 -0
  33. data/src/main/java/org/embulk/input/jdbc/getter/ColumnGetterFactory.java +207 -0
  34. data/src/main/java/org/embulk/input/jdbc/getter/DateColumnGetter.java +37 -0
  35. data/src/main/java/org/embulk/input/jdbc/getter/DoubleColumnGetter.java +66 -0
  36. data/src/main/java/org/embulk/input/jdbc/getter/FloatColumnGetter.java +66 -0
  37. data/src/main/java/org/embulk/input/jdbc/getter/JsonColumnGetter.java +57 -0
  38. data/src/main/java/org/embulk/input/jdbc/getter/LongColumnGetter.java +70 -0
  39. data/src/main/java/org/embulk/input/jdbc/getter/StringColumnGetter.java +96 -0
  40. data/src/main/java/org/embulk/input/jdbc/getter/TimeColumnGetter.java +37 -0
  41. data/src/main/java/org/embulk/input/jdbc/getter/TimestampColumnGetter.java +36 -0
  42. data/src/main/java/org/embulk/input/jdbc/getter/TimestampWithTimeZoneIncrementalHandler.java +83 -0
  43. data/src/main/java/org/embulk/input/jdbc/getter/TimestampWithoutTimeZoneIncrementalHandler.java +75 -0
  44. data/src/test/java/org/embulk/input/athena/TestAthenaInputPlugin.java +5 -0
  45. metadata +258 -0
@@ -0,0 +1,58 @@
1
+ package org.embulk.input.jdbc;
2
+
3
+ import com.fasterxml.jackson.annotation.JsonCreator;
4
+ import com.fasterxml.jackson.annotation.JsonProperty;
5
+
6
+ public class JdbcColumn
7
+ {
8
+ private String name;
9
+ private String typeName;
10
+ private int sqlType;
11
+ private int precision;
12
+ private int scale;
13
+
14
+ @JsonCreator
15
+ public JdbcColumn(
16
+ @JsonProperty("name") String name,
17
+ @JsonProperty("typeName") String typeName,
18
+ @JsonProperty("sqlType") int sqlType,
19
+ @JsonProperty("precision") int precision,
20
+ @JsonProperty("scale") int scale)
21
+ {
22
+ this.name = name;
23
+ this.typeName = typeName;
24
+ this.sqlType = sqlType;
25
+ this.precision = precision;
26
+ this.scale = scale;
27
+ }
28
+
29
+ @JsonProperty("name")
30
+ public String getName()
31
+ {
32
+ return name;
33
+ }
34
+
35
+ @JsonProperty("typeName")
36
+ public String getTypeName()
37
+ {
38
+ return typeName;
39
+ }
40
+
41
+ @JsonProperty("sqlType")
42
+ public int getSqlType()
43
+ {
44
+ return sqlType;
45
+ }
46
+
47
+ @JsonProperty("precision")
48
+ public int getPrecision()
49
+ {
50
+ return precision;
51
+ }
52
+
53
+ @JsonProperty("scale")
54
+ public int getScale()
55
+ {
56
+ return scale;
57
+ }
58
+ }
@@ -0,0 +1,31 @@
1
+ package org.embulk.input.jdbc;
2
+
3
+ import org.embulk.config.Config;
4
+ import org.embulk.config.ConfigDefault;
5
+ import org.embulk.config.ConfigInject;
6
+ import org.embulk.config.Task;
7
+ import org.embulk.spi.time.TimestampFormat;
8
+ import org.embulk.spi.type.Type;
9
+ import org.joda.time.DateTimeZone;
10
+
11
+ import com.google.common.base.Optional;
12
+
13
+ public interface JdbcColumnOption
14
+ extends Task
15
+ {
16
+ @Config("value_type")
17
+ @ConfigDefault("\"coalesce\"")
18
+ public String getValueType();
19
+
20
+ @Config("type")
21
+ @ConfigDefault("null")
22
+ public Optional<Type> getType();
23
+
24
+ @Config("timestamp_format")
25
+ @ConfigDefault("null")
26
+ public Optional<TimestampFormat> getTimestampFormat();
27
+
28
+ @Config("timezone")
29
+ @ConfigDefault("null")
30
+ public Optional<DateTimeZone> getTimeZone();
31
+ }
@@ -0,0 +1,397 @@
1
+ package org.embulk.input.jdbc;
2
+
3
+ import java.sql.Connection;
4
+ import java.sql.DatabaseMetaData;
5
+ import java.sql.PreparedStatement;
6
+ import java.sql.ResultSet;
7
+ import java.sql.ResultSetMetaData;
8
+ import java.sql.SQLException;
9
+ import java.sql.Statement;
10
+ import java.util.Locale;
11
+ import java.util.Set;
12
+
13
+ import org.embulk.config.ConfigException;
14
+ import org.embulk.spi.Exec;
15
+ import org.embulk.input.jdbc.getter.ColumnGetter;
16
+ import org.slf4j.Logger;
17
+
18
+ import java.util.List;
19
+ import java.util.ArrayList;
20
+ import static java.util.Locale.ENGLISH;
21
+
22
+ import com.fasterxml.jackson.annotation.JsonCreator;
23
+ import com.fasterxml.jackson.annotation.JsonProperty;
24
+ import com.fasterxml.jackson.databind.JsonNode;
25
+ import com.google.common.base.Optional;
26
+ import com.google.common.collect.ImmutableList;
27
+ import com.google.common.collect.ImmutableSet;
28
+
29
+ public class JdbcInputConnection
30
+ implements AutoCloseable
31
+ {
32
+ protected final Logger logger = Exec.getLogger(getClass());
33
+
34
+ protected final Connection connection;
35
+ protected final String schemaName;
36
+ protected final DatabaseMetaData databaseMetaData;
37
+ protected String identifierQuoteString;
38
+
39
+ public JdbcInputConnection(Connection connection, String schemaName)
40
+ throws SQLException
41
+ {
42
+ this.connection = connection;
43
+ this.schemaName = schemaName;
44
+ this.databaseMetaData = connection.getMetaData();
45
+ this.identifierQuoteString = databaseMetaData.getIdentifierQuoteString();
46
+ if (schemaName != null) {
47
+ setSearchPath(schemaName);
48
+ }
49
+
50
+ // java.sql.SQLFeatureNotSupportedException: Disabling auto-commit mode not supported
51
+ // connection.setAutoCommit(false);
52
+ }
53
+
54
+ protected void setSearchPath(String schema) throws SQLException
55
+ {
56
+ String sql = "SET search_path TO " + quoteIdentifierString(schema);
57
+ executeUpdate(sql);
58
+ }
59
+
60
+ public JdbcSchema getSchemaOfQuery(String query) throws SQLException
61
+ {
62
+ PreparedStatement stmt = connection.prepareStatement(query);
63
+ try {
64
+ return getSchemaOfResultMetadata(stmt.getMetaData());
65
+ } finally {
66
+ stmt.close();
67
+ }
68
+ }
69
+
70
+ public List<String> getPrimaryKeys(String tableName) throws SQLException
71
+ {
72
+ ResultSet rs = databaseMetaData.getPrimaryKeys(null, schemaName, tableName);
73
+ ImmutableList.Builder<String> builder = ImmutableList.builder();
74
+ try {
75
+ while(rs.next()) {
76
+ builder.add(rs.getString("COLUMN_NAME"));
77
+ }
78
+ } finally {
79
+ rs.close();
80
+ }
81
+ return builder.build();
82
+ }
83
+
84
+ protected JdbcSchema getSchemaOfResultMetadata(ResultSetMetaData metadata) throws SQLException
85
+ {
86
+ ImmutableList.Builder<JdbcColumn> columns = ImmutableList.builder();
87
+ for (int i=0; i < metadata.getColumnCount(); i++) {
88
+ int index = i + 1; // JDBC column index begins from 1
89
+ String name = metadata.getColumnLabel(index);
90
+ String typeName = metadata.getColumnTypeName(index);
91
+ int sqlType = metadata.getColumnType(index);
92
+ int scale = metadata.getScale(index);
93
+ int precision = metadata.getPrecision(index);
94
+ columns.add(new JdbcColumn(name, typeName, sqlType, precision, scale));
95
+ }
96
+ return new JdbcSchema(columns.build());
97
+ }
98
+
99
+ public static class PreparedQuery
100
+ {
101
+ private final String query;
102
+ private final List<JdbcLiteral> parameters;
103
+
104
+ @JsonCreator
105
+ public PreparedQuery(
106
+ @JsonProperty("query") String query,
107
+ @JsonProperty("parameters") List<JdbcLiteral> parameters)
108
+ {
109
+ this.query = query;
110
+ this.parameters = parameters;
111
+ }
112
+
113
+ @JsonProperty("query")
114
+ public String getQuery()
115
+ {
116
+ return query;
117
+ }
118
+
119
+ @JsonProperty("parameters")
120
+ public List<JdbcLiteral> getParameters()
121
+ {
122
+ return parameters;
123
+ }
124
+ }
125
+
126
+ public BatchSelect newSelectCursor(PreparedQuery preparedQuery,
127
+ List<ColumnGetter> getters,
128
+ int fetchRows, int queryTimeout) throws SQLException
129
+ {
130
+ return newBatchSelect(preparedQuery, getters, fetchRows, queryTimeout);
131
+ }
132
+
133
+ protected BatchSelect newBatchSelect(PreparedQuery preparedQuery,
134
+ List<ColumnGetter> getters,
135
+ int fetchRows, int queryTimeout) throws SQLException
136
+ {
137
+ String query = preparedQuery.getQuery();
138
+ List<JdbcLiteral> params = preparedQuery.getParameters();
139
+
140
+ PreparedStatement stmt = connection.prepareStatement(query);
141
+ stmt.setFetchSize(fetchRows);
142
+ stmt.setQueryTimeout(queryTimeout);
143
+ logger.info("SQL: " + query);
144
+ if (!params.isEmpty()) {
145
+ logger.info("Parameters: {}", params);
146
+ prepareParameters(stmt, getters, params);
147
+ }
148
+ return new SingleSelect(stmt);
149
+ }
150
+
151
+ protected void prepareParameters(PreparedStatement stmt, List<ColumnGetter> getters,
152
+ List<JdbcLiteral> parameters)
153
+ throws SQLException
154
+ {
155
+ for (int i = 0; i < parameters.size(); i++) {
156
+ JdbcLiteral literal = parameters.get(i);
157
+ ColumnGetter getter = getters.get(literal.getColumnIndex());
158
+ int index = i + 1; // JDBC column index begins from 1
159
+ getter.decodeFromJsonTo(stmt, index, literal.getValue());
160
+ }
161
+ }
162
+
163
+ public interface BatchSelect
164
+ extends AutoCloseable
165
+ {
166
+ public ResultSet fetch() throws SQLException;
167
+
168
+ @Override
169
+ public void close() throws SQLException;
170
+ }
171
+
172
+ public class SingleSelect
173
+ implements BatchSelect
174
+ {
175
+ private final PreparedStatement fetchStatement;
176
+ private boolean fetched = false;
177
+
178
+ public SingleSelect(PreparedStatement fetchStatement)
179
+ {
180
+ this.fetchStatement = fetchStatement;
181
+ }
182
+
183
+ public ResultSet fetch() throws SQLException
184
+ {
185
+ if (fetched == true) {
186
+ return null;
187
+ }
188
+
189
+ long startTime = System.currentTimeMillis();
190
+
191
+ ResultSet rs = fetchStatement.executeQuery();
192
+
193
+ double seconds = (System.currentTimeMillis() - startTime) / 1000.0;
194
+ logger.info(String.format("> %.2f seconds", seconds));
195
+ fetched = true;
196
+ return rs;
197
+ }
198
+
199
+ public void close() throws SQLException
200
+ {
201
+ // TODO close?
202
+ }
203
+ }
204
+
205
+ @Override
206
+ public void close() throws SQLException
207
+ {
208
+ connection.close();
209
+ }
210
+
211
+ protected void executeUpdate(String sql) throws SQLException
212
+ {
213
+ logger.info("SQL: " + sql);
214
+ Statement stmt = connection.createStatement();
215
+ try {
216
+ stmt.executeUpdate(sql);
217
+ } finally {
218
+ stmt.close();
219
+ }
220
+ }
221
+
222
+ // TODO share code with embulk-output-jdbc
223
+ protected String quoteIdentifierString(String str)
224
+ {
225
+ return identifierQuoteString + str + identifierQuoteString;
226
+ }
227
+
228
+ protected String buildTableName(String tableName)
229
+ {
230
+ return quoteIdentifierString(tableName);
231
+ }
232
+
233
+ public String buildSelectQuery(String tableName,
234
+ Optional<String> selectExpression, Optional<String> whereCondition,
235
+ Optional<String> orderByExpression) throws SQLException
236
+ {
237
+ StringBuilder sb = new StringBuilder();
238
+
239
+ sb.append("SELECT ");
240
+ sb.append(selectExpression.or("*"));
241
+ sb.append(" FROM ").append(buildTableName(tableName));
242
+
243
+ if (whereCondition.isPresent()) {
244
+ sb.append(" WHERE ").append(whereCondition.get());
245
+ }
246
+
247
+ if (orderByExpression.isPresent()) {
248
+ sb.append(" ORDER BY ").append(orderByExpression.get());
249
+ }
250
+
251
+ return sb.toString();
252
+ }
253
+
254
+ public PreparedQuery rebuildIncrementalQuery(String tableName,
255
+ Optional<String> selectExpression, Optional<String> whereCondition,
256
+ JdbcSchema querySchema,
257
+ List<Integer> incrementalColumnIndexes, List<JsonNode> incrementalValues) throws SQLException
258
+ {
259
+ List<JdbcLiteral> parameters = ImmutableList.of();
260
+
261
+ Optional<String> newWhereCondition;
262
+ if (incrementalValues != null) {
263
+ StringBuilder sb = new StringBuilder();
264
+
265
+ if (whereCondition.isPresent()) {
266
+ sb.append("(");
267
+ sb.append(whereCondition.get());
268
+ sb.append(") AND ");
269
+ }
270
+
271
+ sb.append("(");
272
+ parameters = buildIncrementalConditionTo(sb,
273
+ querySchema, incrementalColumnIndexes, incrementalValues);
274
+ sb.append(")");
275
+
276
+ newWhereCondition = Optional.of(sb.toString());
277
+ }
278
+ else {
279
+ newWhereCondition = whereCondition;
280
+ }
281
+
282
+ Optional<String> newOrderByExpression;
283
+ {
284
+ StringBuilder sb = new StringBuilder();
285
+ buildIncrementalOrderTo(sb, querySchema, incrementalColumnIndexes);
286
+ newOrderByExpression = Optional.of(sb.toString());
287
+ }
288
+
289
+ String newQuery = buildSelectQuery(
290
+ tableName, selectExpression, newWhereCondition,
291
+ newOrderByExpression);
292
+
293
+ return new PreparedQuery(newQuery, parameters);
294
+ }
295
+
296
+ public PreparedQuery wrapIncrementalQuery(String rawQuery, JdbcSchema querySchema,
297
+ List<Integer> incrementalColumnIndexes, List<JsonNode> incrementalValues) throws SQLException
298
+ {
299
+ StringBuilder sb = new StringBuilder();
300
+ List<JdbcLiteral> parameters = ImmutableList.of();
301
+
302
+ sb.append("SELECT * FROM (");
303
+ sb.append(truncateStatementDelimiter(rawQuery));
304
+ sb.append(") embulk_incremental_");
305
+
306
+ if (incrementalValues != null) {
307
+ sb.append(" WHERE ");
308
+ parameters = buildIncrementalConditionTo(sb,
309
+ querySchema, incrementalColumnIndexes, incrementalValues);
310
+ }
311
+
312
+ sb.append(" ORDER BY ");
313
+ buildIncrementalOrderTo(sb, querySchema, incrementalColumnIndexes);
314
+
315
+ return new PreparedQuery(sb.toString(), parameters);
316
+ }
317
+
318
+ private List<JdbcLiteral> buildIncrementalConditionTo(
319
+ StringBuilder sb,
320
+ JdbcSchema querySchema,
321
+ List<Integer> incrementalColumnIndexes, List<JsonNode> incrementalValues) throws SQLException
322
+ {
323
+ ImmutableList.Builder<JdbcLiteral> parameters = ImmutableList.builder();
324
+
325
+ List<String> leftColumnNames = new ArrayList<>();
326
+ List<JdbcLiteral> rightLiterals = new ArrayList<>();
327
+ for (int n = 0; n < incrementalColumnIndexes.size(); n++) {
328
+ int columnIndex = incrementalColumnIndexes.get(n);
329
+ JsonNode value = incrementalValues.get(n);
330
+ leftColumnNames.add(querySchema.getColumnName(columnIndex));
331
+ rightLiterals.add(new JdbcLiteral(columnIndex, value));
332
+ }
333
+
334
+ for (int n = 0; n < leftColumnNames.size(); n++) {
335
+ if (n > 0) {
336
+ sb.append(" OR ");
337
+ }
338
+ sb.append("(");
339
+
340
+ for (int i = 0; i < n; i++) {
341
+ sb.append(quoteIdentifierString(leftColumnNames.get(i)));
342
+ sb.append(" = ?");
343
+ parameters.add(rightLiterals.get(i));
344
+ sb.append(" AND ");
345
+ }
346
+ sb.append(quoteIdentifierString(leftColumnNames.get(n)));
347
+ sb.append(" > ?");
348
+ parameters.add(rightLiterals.get(n));
349
+
350
+ sb.append(")");
351
+ }
352
+
353
+ return parameters.build();
354
+ }
355
+
356
+ private void buildIncrementalOrderTo(StringBuilder sb,
357
+ JdbcSchema querySchema, List<Integer> incrementalColumnIndexes)
358
+ {
359
+ boolean first = true;
360
+ for (int i : incrementalColumnIndexes) {
361
+ if (first) {
362
+ first = false;
363
+ } else {
364
+ sb.append(", ");
365
+ }
366
+ sb.append(quoteIdentifierString(querySchema.getColumnName(i)));
367
+ }
368
+ }
369
+
370
+ protected String truncateStatementDelimiter(String rawQuery) throws SQLException
371
+ {
372
+ return rawQuery.replaceAll(";\\s*$", "");
373
+ }
374
+
375
+ public boolean tableExists(String tableName) throws SQLException
376
+ {
377
+ try (ResultSet rs = connection.getMetaData().getTables(null, schemaName, tableName, null)) {
378
+ return rs.next();
379
+ }
380
+ }
381
+
382
+ private Set<String> getColumnNames(String tableName) throws SQLException
383
+ {
384
+ ImmutableSet.Builder<String> columnNamesBuilder = ImmutableSet.builder();
385
+ try (ResultSet rs = connection.getMetaData().getColumns(null, schemaName, tableName, null)) {
386
+ while (rs.next()) {
387
+ columnNamesBuilder.add(rs.getString("COLUMN_NAME"));
388
+ }
389
+ return columnNamesBuilder.build();
390
+ }
391
+ }
392
+
393
+ public void showDriverVersion() throws SQLException {
394
+ DatabaseMetaData meta = connection.getMetaData();
395
+ logger.info(String.format(Locale.ENGLISH,"Using JDBC Driver %s",meta.getDriverVersion()));
396
+ }
397
+ }