embulk-filter-calcite 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (25) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -1
  3. data/CHANGELOG.md +12 -0
  4. data/README.md +7 -0
  5. data/build.gradle +7 -11
  6. data/config/checkstyle/README.md +6 -0
  7. data/config/checkstyle/checkstyle-suppressions.xml +8 -0
  8. data/config/checkstyle/checkstyle.xml +195 -104
  9. data/config/checkstyle/google_checks.xml +218 -0
  10. data/src/main/java/org/embulk/filter/calcite/CalciteFilterPlugin.java +111 -118
  11. data/src/main/java/org/embulk/filter/calcite/PageConverter.java +19 -36
  12. data/src/main/java/org/embulk/filter/calcite/adapter/page/PageEnumerator.java +14 -15
  13. data/src/main/java/org/embulk/filter/calcite/adapter/page/PageFieldType.java +9 -15
  14. data/src/main/java/org/embulk/filter/calcite/adapter/page/PageSchema.java +4 -9
  15. data/src/main/java/org/embulk/filter/calcite/adapter/page/PageSchemaFactory.java +7 -8
  16. data/src/main/java/org/embulk/filter/calcite/adapter/page/PageTable.java +23 -14
  17. data/src/main/java/org/embulk/filter/calcite/getter/FilterColumnGetterFactory.java +23 -11
  18. data/src/main/java/org/embulk/filter/calcite/getter/FilterTimestampColumnGetter.java +10 -14
  19. data/src/test/java/org/embulk/filter/calcite/TestCalciteFilterPlugin.java +81 -55
  20. data/src/test/resources/org/embulk/filter/calcite/test/test_timestamp_conv_expected.csv +4 -0
  21. data/src/test/resources/org/embulk/filter/calcite/test/test_timestamp_conv_filter.yml +3 -0
  22. data/src/test/resources/org/embulk/filter/calcite/test/test_timestamp_conv_in.yml +18 -0
  23. data/src/test/resources/org/embulk/filter/calcite/test/test_timestamp_conv_source.csv +5 -0
  24. metadata +14 -7
  25. data/config/checkstyle/default.xml +0 -108
@@ -5,6 +5,15 @@ import com.google.common.base.Throwables;
5
5
  import com.google.common.collect.ImmutableList;
6
6
  import com.google.common.collect.ImmutableMap;
7
7
  import com.google.inject.Inject;
8
+ import java.sql.Connection;
9
+ import java.sql.ResultSet;
10
+ import java.sql.ResultSetMetaData;
11
+ import java.sql.SQLException;
12
+ import java.sql.Statement;
13
+ import java.util.List;
14
+ import java.util.Locale;
15
+ import java.util.Map;
16
+ import java.util.Properties;
8
17
  import org.apache.calcite.jdbc.Driver;
9
18
  import org.embulk.config.Config;
10
19
  import org.embulk.config.ConfigDefault;
@@ -23,65 +32,27 @@ import org.embulk.input.jdbc.JdbcSchema;
23
32
  import org.embulk.input.jdbc.getter.ColumnGetter;
24
33
  import org.embulk.input.jdbc.getter.ColumnGetterFactory;
25
34
  import org.embulk.spi.BufferAllocator;
35
+ import org.embulk.spi.Exec;
26
36
  import org.embulk.spi.FilterPlugin;
27
37
  import org.embulk.spi.Page;
28
38
  import org.embulk.spi.PageBuilder;
29
39
  import org.embulk.spi.PageOutput;
30
40
  import org.embulk.spi.Schema;
41
+ import org.embulk.spi.unit.ToStringMap;
31
42
  import org.joda.time.DateTimeZone;
32
43
  import org.slf4j.Logger;
33
44
 
34
- import java.sql.Connection;
35
- import java.sql.ResultSet;
36
- import java.sql.ResultSetMetaData;
37
- import java.sql.SQLException;
38
- import java.sql.Statement;
39
- import java.util.List;
40
- import java.util.Map;
41
- import java.util.Properties;
42
-
43
- import static java.lang.String.format;
44
- import static java.lang.Thread.currentThread;
45
- import static java.util.Locale.ENGLISH;
46
- import static org.embulk.spi.Exec.getLogger;
47
- import static org.embulk.spi.Exec.getModelManager;
48
- import static org.embulk.spi.Exec.newConfigSource;
49
-
50
- public class CalciteFilterPlugin
51
- implements FilterPlugin
52
- {
53
- public interface PluginTask
54
- extends Task
55
- {
56
- @Config("query")
57
- public String getQuery();
58
-
59
- @Config("default_timezone")
60
- @ConfigDefault("\"UTC\"")
61
- public DateTimeZone getDefaultTimeZone();
62
-
63
- public JdbcSchema getQuerySchema();
64
- public void setQuerySchema(JdbcSchema querySchema);
65
-
66
- // TODO support jdbc Url properties
67
- // TODO support column_options: option
68
- // TODO support options: option
69
-
70
- @ConfigInject
71
- public BufferAllocator getBufferAllocator();
72
- }
45
+ public class CalciteFilterPlugin implements FilterPlugin {
73
46
 
74
47
  private final Logger log;
75
48
 
76
49
  @Inject
77
- public CalciteFilterPlugin()
78
- {
79
- this.log = getLogger(getClass());
50
+ public CalciteFilterPlugin() {
51
+ this.log = Exec.getLogger(getClass());
80
52
  }
81
53
 
82
54
  @Override
83
- public void transaction(ConfigSource config, Schema inputSchema, FilterPlugin.Control control)
84
- {
55
+ public void transaction(ConfigSource config, Schema inputSchema, FilterPlugin.Control control) {
85
56
  PluginTask task = config.loadConfig(PluginTask.class);
86
57
  Properties props = System.getProperties(); // TODO should be configured as config option
87
58
  setupProperties(task, props);
@@ -91,49 +62,55 @@ public class CalciteFilterPlugin
91
62
 
92
63
  // Set page converter as TLS variable in PageTable
93
64
  PageTable.pageConverter.set(newPageConverter(task, inputSchema));
65
+
66
+ final String jdbcUrl = buildJdbcUrl();
67
+ log.info(String.format(Locale.ENGLISH, "Generated Jdbc URL: %s", jdbcUrl));
68
+
94
69
  try {
95
70
  JdbcSchema querySchema;
96
- try (Connection conn = newConnection(props)) { // SQLException thrown by conn.close()
71
+ try (Connection conn = newConnection(jdbcUrl, props)) { // SQLException by conn.close()
97
72
  querySchema = getQuerySchema(task, conn);
98
73
  task.setQuerySchema(querySchema);
99
- }
100
- catch (SQLException e) {
74
+ } catch (SQLException e) {
101
75
  throw Throwables.propagate(e);
102
76
  }
103
77
 
104
78
  control.run(task.dump(), buildOutputSchema(task, querySchema));
105
- }
106
- finally {
79
+ } finally {
107
80
  PageTable.pageConverter.remove();
108
81
  }
109
82
  }
110
83
 
111
- private void setupProperties(PluginTask task, Properties props)
112
- {
84
+ private void setupProperties(PluginTask task, Properties props) {
113
85
  // @see https://calcite.apache.org/docs/adapter.html#jdbc-connect-string-parameters
86
+ final ToStringMap options = task.getOptions();
87
+ if (!options.containsKey("caseSensitive")) {
88
+ log.warn("JDBC parameter 'caseSensitive' is implicitly set to false as default in");
89
+ log.warn("embulk-filter-calcite 0.1 but, it's scheduled to change default with true");
90
+ log.warn("in 0.2. Please use 'options' option to set 'caseSensitive' to false.");
91
+ }
114
92
  props.setProperty("caseSensitive", "false"); // Relax case-sensitive
115
93
  props.setProperty("timeZone", task.getDefaultTimeZone().getID());
94
+
95
+ // overwrites props with 'options' option
96
+ props.putAll(options);
116
97
  }
117
98
 
118
- private PageConverter newPageConverter(PluginTask task, Schema inputSchema)
119
- {
99
+ private PageConverter newPageConverter(PluginTask task, Schema inputSchema) {
120
100
  return new PageConverter(inputSchema, task.getDefaultTimeZone().toTimeZone());
121
101
  }
122
102
 
123
- private Connection newConnection(Properties props)
124
- {
125
- String jdbcUrl = buildJdbcUrl();
103
+ private Connection newConnection(String jdbcUrl, Properties props) {
126
104
  try {
127
105
  return new Driver().connect(jdbcUrl, props);
128
- }
129
- catch (SQLException e) {
130
- String message = format(ENGLISH, "Cannot create connections by Jdbc URL: %s", jdbcUrl);
106
+ } catch (SQLException e) {
107
+ String message = String.format(Locale.ENGLISH,
108
+ "Cannot create connections by Jdbc URL: %s", jdbcUrl);
131
109
  throw new IllegalStateException(message, e);
132
110
  }
133
111
  }
134
112
 
135
- private String buildJdbcUrl()
136
- {
113
+ private String buildJdbcUrl() {
137
114
  // build a json model to apply Page storage adaptor
138
115
  // @see https://github.com/apache/calcite/blob/master/example/csv/src/test/resources/model.json
139
116
  ImmutableMap.Builder<String, Object> map = ImmutableMap.builder();
@@ -146,42 +123,23 @@ public class CalciteFilterPlugin
146
123
  "factory", PageSchemaFactory.class.getName()
147
124
  )
148
125
  ));
149
- String jsonModel = getModelManager().writeObject(map.build());
126
+ String jsonModel = Exec.getModelManager().writeObject(map.build());
150
127
 
151
128
  // build Jdbc URL
152
- String jdbcUrl = format(ENGLISH, "jdbc:calcite:model=inline:%s", jsonModel);
153
- log.info(format(ENGLISH, "Generated Jdbc URL: %s", jdbcUrl));
154
- return jdbcUrl;
129
+ return String.format(Locale.ENGLISH, "jdbc:calcite:model=inline:%s", jsonModel);
155
130
  }
156
131
 
157
132
  private JdbcSchema getQuerySchema(PluginTask task, Connection conn)
158
- throws SQLException
159
- {
133
+ throws SQLException {
160
134
  try (Statement stat = conn.createStatement(); // SQLException thrown by conn.close()
161
- ResultSet result = executeQuery(stat, task.getQuery())) { // SQLException thrown by rs.close()
135
+ ResultSet result = executeQuery(stat,
136
+ task.getQuery())) { // SQLException thrown by rs.close()
162
137
  return getQuerySchema(result.getMetaData());
163
138
  }
164
139
  }
165
140
 
166
- private ResultSet executeQuery(Statement stat, String query)
167
- {
168
- // This is a workaround to avoid NPE caused by commons-compiler v2.7.6
169
- ClassLoader cl = currentThread().getContextClassLoader();
170
- currentThread().setContextClassLoader(getClass().getClassLoader());
171
- try {
172
- return stat.executeQuery(query);
173
- }
174
- catch (SQLException e) {
175
- throw new ConfigException("Cannot execute a query: " + query, e);
176
- }
177
- finally {
178
- currentThread().setContextClassLoader(cl);
179
- }
180
- }
181
-
182
141
  private JdbcSchema getQuerySchema(ResultSetMetaData metadata)
183
- throws SQLException
184
- {
142
+ throws SQLException {
185
143
  ImmutableList.Builder<JdbcColumn> columns = ImmutableList.builder();
186
144
  for (int i = 0; i < metadata.getColumnCount(); i++) {
187
145
  int index = i + 1; // JDBC column index begins from 1
@@ -195,8 +153,20 @@ public class CalciteFilterPlugin
195
153
  return new JdbcSchema(columns.build());
196
154
  }
197
155
 
198
- private Schema buildOutputSchema(PluginTask task, JdbcSchema querySchema)
199
- {
156
+ private ResultSet executeQuery(Statement stat, String query) {
157
+ // This is a workaround to avoid NPE caused by commons-compiler v2.7.6
158
+ ClassLoader cl = Thread.currentThread().getContextClassLoader();
159
+ Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
160
+ try {
161
+ return stat.executeQuery(query);
162
+ } catch (SQLException e) {
163
+ throw new ConfigException("Cannot execute a query: " + query, e);
164
+ } finally {
165
+ Thread.currentThread().setContextClassLoader(cl);
166
+ }
167
+ }
168
+
169
+ private Schema buildOutputSchema(PluginTask task, JdbcSchema querySchema) {
200
170
  ColumnGetterFactory factory = newColumnGetterFactory(task, Optional.<PageBuilder>absent());
201
171
  List<ColumnGetter> getters = newColumnGetters(factory, querySchema);
202
172
 
@@ -207,18 +177,17 @@ public class CalciteFilterPlugin
207
177
  return schema.build();
208
178
  }
209
179
 
210
- private ColumnGetterFactory newColumnGetterFactory(PluginTask task, Optional<PageBuilder> pageBuilder)
211
- {
180
+ private ColumnGetterFactory newColumnGetterFactory(PluginTask task,
181
+ Optional<PageBuilder> pageBuilder) {
212
182
  if (pageBuilder.isPresent()) {
213
183
  return new FilterColumnGetterFactory(pageBuilder.get(), task.getDefaultTimeZone());
214
- }
215
- else {
184
+ } else {
216
185
  return new FilterColumnGetterFactory(null, task.getDefaultTimeZone());
217
186
  }
218
187
  }
219
188
 
220
- private List<ColumnGetter> newColumnGetters(ColumnGetterFactory factory, JdbcSchema querySchema)
221
- {
189
+ private List<ColumnGetter> newColumnGetters(ColumnGetterFactory factory,
190
+ JdbcSchema querySchema) {
222
191
  ImmutableList.Builder<ColumnGetter> getters = ImmutableList.builder();
223
192
  for (JdbcColumn column : querySchema.getColumns()) {
224
193
  getters.add(factory.newColumnGetter(null, null, column, newJdbcColumnOption()));
@@ -226,15 +195,14 @@ public class CalciteFilterPlugin
226
195
  return getters.build();
227
196
  }
228
197
 
229
- private JdbcColumnOption newJdbcColumnOption()
230
- {
198
+ private JdbcColumnOption newJdbcColumnOption() {
231
199
  // TODO need to improve for supporting column_options: option
232
- return newConfigSource().loadConfig(JdbcColumnOption.class);
200
+ return Exec.newConfigSource().loadConfig(JdbcColumnOption.class);
233
201
  }
234
202
 
235
203
  @Override
236
- public PageOutput open(TaskSource taskSource, Schema inputSchema, Schema outputSchema, PageOutput output)
237
- {
204
+ public PageOutput open(TaskSource taskSource, Schema inputSchema, Schema outputSchema,
205
+ PageOutput output) {
238
206
  PluginTask task = taskSource.loadTask(PluginTask.class);
239
207
 
240
208
  // Set input schema in PageSchema for various types of executor plugins
@@ -246,12 +214,42 @@ public class CalciteFilterPlugin
246
214
  List<ColumnGetter> getters = newColumnGetters(factory, task.getQuerySchema());
247
215
  Properties props = System.getProperties(); // TODO should be configured as config option
248
216
  setupProperties(task, props);
249
- return new FilterPageOutput(outputSchema, task.getQuery(), pageBuilder, pageConverter, getters, props);
217
+ return new FilterPageOutput(outputSchema,
218
+ task.getQuery(),
219
+ pageBuilder,
220
+ pageConverter,
221
+ getters,
222
+ props);
223
+ }
224
+
225
+ public interface PluginTask
226
+ extends Task {
227
+
228
+ @Config("query")
229
+ public String getQuery();
230
+
231
+ @Config("default_timezone")
232
+ @ConfigDefault("\"UTC\"")
233
+ public DateTimeZone getDefaultTimeZone();
234
+
235
+ public JdbcSchema getQuerySchema();
236
+
237
+ public void setQuerySchema(JdbcSchema querySchema);
238
+
239
+ // TODO support jdbc Url properties
240
+ // TODO support column_options: option
241
+
242
+ @Config("options")
243
+ @ConfigDefault("{}")
244
+ public ToStringMap getOptions();
245
+
246
+ @ConfigInject
247
+ public BufferAllocator getBufferAllocator();
250
248
  }
251
249
 
252
250
  private class FilterPageOutput
253
- implements PageOutput
254
- {
251
+ implements PageOutput {
252
+
255
253
  private final Schema outputSchema;
256
254
  private final String query;
257
255
  private final PageBuilder pageBuilder;
@@ -259,9 +257,9 @@ public class CalciteFilterPlugin
259
257
  private final List<ColumnGetter> getters;
260
258
  private final Properties props;
261
259
 
262
- private FilterPageOutput(Schema outputSchema, String query, PageBuilder pageBuilder, PageConverter pageConverter,
263
- List<ColumnGetter> getters, Properties props)
264
- {
260
+ private FilterPageOutput(Schema outputSchema, String query, PageBuilder pageBuilder,
261
+ PageConverter pageConverter,
262
+ List<ColumnGetter> getters, Properties props) {
265
263
  this.outputSchema = outputSchema;
266
264
  this.query = query;
267
265
  this.pageBuilder = pageBuilder;
@@ -271,17 +269,16 @@ public class CalciteFilterPlugin
271
269
  }
272
270
 
273
271
  @Override
274
- public void add(Page page)
275
- {
272
+ public void add(Page page) {
276
273
  // Set page converter as TLS variable in PageTable
277
274
  PageTable.pageConverter.set(pageConverter);
278
275
 
279
276
  // Set page as TLS variable in PageTable
280
277
  PageTable.page.set(page);
281
278
 
282
- try (Connection conn = newConnection(props);
283
- Statement stat = conn.createStatement();
284
- ResultSet result = executeQuery(stat, query)) {
279
+ try (Connection conn = newConnection(buildJdbcUrl(), props);
280
+ Statement stat = conn.createStatement();
281
+ ResultSet result = executeQuery(stat, query)) {
285
282
 
286
283
  while (result.next()) {
287
284
  for (int i = 0; i < getters.size(); i++) {
@@ -290,25 +287,21 @@ public class CalciteFilterPlugin
290
287
  }
291
288
  pageBuilder.addRecord();
292
289
  }
293
- }
294
- catch (SQLException e) {
290
+ } catch (SQLException e) {
295
291
  throw Throwables.propagate(e); // TODO better exception handling? error messages?
296
- }
297
- finally {
292
+ } finally {
298
293
  PageTable.pageConverter.remove();
299
294
  PageTable.page.remove();
300
295
  }
301
296
  }
302
297
 
303
298
  @Override
304
- public void finish()
305
- {
299
+ public void finish() {
306
300
  pageBuilder.finish();
307
301
  }
308
302
 
309
303
  @Override
310
- public void close()
311
- {
304
+ public void close() {
312
305
  pageBuilder.close();
313
306
  }
314
307
  }
@@ -1,100 +1,85 @@
1
1
  package org.embulk.filter.calcite;
2
2
 
3
+ import java.math.BigDecimal;
4
+ import java.util.TimeZone;
3
5
  import org.embulk.spi.Column;
4
6
  import org.embulk.spi.ColumnVisitor;
5
7
  import org.embulk.spi.PageReader;
6
8
  import org.embulk.spi.Schema;
7
9
 
8
- import java.math.BigDecimal;
9
- import java.util.TimeZone;
10
-
11
10
  /**
12
11
  * This class converts Embulk's Page values into Calcite's row types. It refers to
13
12
  * org.apache.calcite.adapter.csv.CsvEnumerator.
14
13
  */
15
- public class PageConverter
16
- implements ColumnVisitor
17
- {
14
+ public class PageConverter implements ColumnVisitor {
15
+
18
16
  private final TimeZone defaultTimeZone;
19
17
  private final Object[] row;
20
18
  private PageReader pageReader;
21
19
 
22
- public PageConverter(Schema schema, TimeZone defaultTimeZone)
23
- {
20
+ public PageConverter(Schema schema, TimeZone defaultTimeZone) {
24
21
  this.defaultTimeZone = defaultTimeZone;
25
22
  this.row = new Object[schema.getColumnCount()];
26
23
  }
27
24
 
28
- public Object[] getRow()
29
- {
25
+ public Object[] getRow() {
30
26
  return row;
31
27
  }
32
28
 
33
- public void setPageReader(PageReader pageReader)
34
- {
29
+ public void setPageReader(PageReader pageReader) {
35
30
  this.pageReader = pageReader;
36
31
  }
37
32
 
38
33
  @Override
39
- public void booleanColumn(Column column)
40
- {
34
+ public void booleanColumn(Column column) {
41
35
  // Embulk's boolean is converted into Java's boolean
42
36
  int i = column.getIndex();
43
37
  if (pageReader.isNull(i)) {
44
38
  row[i] = null;
45
- }
46
- else {
39
+ } else {
47
40
  row[i] = pageReader.getBoolean(i);
48
41
  }
49
42
  }
50
43
 
51
44
  @Override
52
- public void longColumn(Column column)
53
- {
45
+ public void longColumn(Column column) {
54
46
  // Embulk's long is converted into long type
55
47
  int i = column.getIndex();
56
48
  if (pageReader.isNull(i)) {
57
49
  row[i] = null;
58
- }
59
- else {
50
+ } else {
60
51
  row[i] = pageReader.getLong(i);
61
52
  }
62
53
  }
63
54
 
64
55
  @Override
65
- public void doubleColumn(Column column)
66
- {
56
+ public void doubleColumn(Column column) {
67
57
  // Embulk's double is converted into java.math.BigDecimal
68
58
  int i = column.getIndex();
69
59
  if (pageReader.isNull(i)) {
70
60
  row[i] = null;
71
- }
72
- else {
61
+ } else {
73
62
  row[i] = new BigDecimal(pageReader.getDouble(i));
74
63
  }
75
64
  }
76
65
 
77
66
  @Override
78
- public void stringColumn(Column column)
79
- {
67
+ public void stringColumn(Column column) {
80
68
  // Embulk's string is converted into java.lang.String
81
69
  int i = column.getIndex();
82
70
  if (pageReader.isNull(i)) {
83
71
  row[i] = null;
84
- }
85
- else {
72
+ } else {
86
73
  row[i] = pageReader.getString(i);
87
74
  }
88
75
  }
89
76
 
90
77
  @Override
91
- public void timestampColumn(Column column)
92
- {
78
+ public void timestampColumn(Column column) {
93
79
  int i = column.getIndex();
94
80
  if (pageReader.isNull(i)) {
95
81
  row[i] = null;
96
- }
97
- else {
82
+ } else {
98
83
  // Embulk's timestamp is converted into java.sql.Timestmap
99
84
  org.embulk.spi.time.Timestamp timestamp = pageReader.getTimestamp(i);
100
85
  long milliseconds = timestamp.getEpochSecond() * 1000 + timestamp.getNano() / 1000000;
@@ -105,14 +90,12 @@ public class PageConverter
105
90
  }
106
91
 
107
92
  @Override
108
- public void jsonColumn(Column column)
109
- {
93
+ public void jsonColumn(Column column) {
110
94
  // Embulk's json is converted into Java's string
111
95
  int i = column.getIndex();
112
96
  if (pageReader.isNull(i)) {
113
97
  row[i] = null;
114
- }
115
- else {
98
+ } else {
116
99
  row[i] = pageReader.getJson(i).toJson();
117
100
  }
118
101
  }