embulk-input-athena 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
+ }