embulk-output-jdbc 0.4.5 → 0.5.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6f3b78600d620d03f0332b8f0f883e19ae0fa4df
4
- data.tar.gz: ccd435e6f57e287920de400cad04d32e0e58322c
3
+ metadata.gz: 22fb481777c119acfc41002c96d50fb4bd336afd
4
+ data.tar.gz: 7757ee98f9ff666421f81efe882020df6f22aa7a
5
5
  SHA512:
6
- metadata.gz: 72a1e2506e4499a24ea405d63262ddcf0fd853d6f970516b457f965a66ab28d1bd38e1963083e6aa33eaf33cad7f244a2bfa291ac7a96ae850764d2c9b99711a
7
- data.tar.gz: afdf7da10965fa9f8c5d5c8dd5d9d584f68221c882a75db3b29c72a0d1a6306ee46b3e3759d45c6ed4d64d14b1bc79d5d033516fd63904c44b15b3cd1b968526
6
+ metadata.gz: 6e5fb5117260aaa6b8b42b3f0582b33fb5f842c3f20b349f2ca13120904053428f2e0edb7c87fdee1a32332243c421e1700d4ef09b03bcb9b224f8562a8c3399
7
+ data.tar.gz: 29f4a992a7fce0809993b044f7833d1baf620a1a1dc3527acfba917671ac784ce6bf8f20498c38fb56232fe03730dbdf600e5dd16764dbf8695bf29c72d480a0
@@ -13,8 +13,10 @@ import java.sql.Types;
13
13
  import java.sql.ResultSet;
14
14
  import java.sql.DatabaseMetaData;
15
15
  import java.sql.SQLException;
16
+
16
17
  import org.slf4j.Logger;
17
18
  import org.joda.time.DateTimeZone;
19
+
18
20
  import com.fasterxml.jackson.annotation.JsonCreator;
19
21
  import com.fasterxml.jackson.annotation.JsonValue;
20
22
  import com.fasterxml.jackson.annotation.JsonProperty;
@@ -25,6 +27,7 @@ import com.google.common.base.Throwables;
25
27
  import com.google.common.collect.Lists;
26
28
  import com.google.common.collect.ImmutableList;
27
29
  import com.google.common.collect.ImmutableSet;
30
+
28
31
  import org.embulk.config.Config;
29
32
  import org.embulk.config.ConfigDefault;
30
33
  import org.embulk.config.ConfigDiff;
@@ -47,6 +50,7 @@ import org.embulk.output.jdbc.setter.ColumnSetter;
47
50
  import org.embulk.output.jdbc.setter.ColumnSetterFactory;
48
51
  import org.embulk.output.jdbc.setter.ColumnSetterVisitor;
49
52
  import org.embulk.spi.util.RetryExecutor.Retryable;
53
+
50
54
  import static org.embulk.spi.util.RetryExecutor.retryExecutor;
51
55
  import static org.embulk.output.jdbc.JdbcSchema.filterSkipColumns;
52
56
 
@@ -102,9 +106,30 @@ public abstract class AbstractJdbcOutputPlugin
102
106
  public void setIntermediateTables(Optional<List<String>> names);
103
107
  }
104
108
 
109
+ public static enum LengthSemantics
110
+ {
111
+ BYTES {
112
+ @Override
113
+ public int countLength(Charset charset, String s)
114
+ {
115
+ return charset.encode(s).remaining();
116
+ }
117
+ },
118
+ CHARACTERS {
119
+ @Override
120
+ public int countLength(Charset charset, String s)
121
+ {
122
+ return s.length();
123
+ }
124
+ };
125
+
126
+ public abstract int countLength(Charset charset, String s);
127
+ }
128
+
105
129
  public static class Features
106
130
  {
107
131
  private int maxTableNameLength = 64;
132
+ private LengthSemantics tableNameLengthSemantics = LengthSemantics.BYTES;
108
133
  private Set<Mode> supportedModes = ImmutableSet.copyOf(Mode.values());
109
134
  private boolean ignoreMergeKeys = false;
110
135
 
@@ -124,6 +149,18 @@ public abstract class AbstractJdbcOutputPlugin
124
149
  return this;
125
150
  }
126
151
 
152
+ public LengthSemantics getTableNameLengthSemantics()
153
+ {
154
+ return tableNameLengthSemantics;
155
+ }
156
+
157
+ @JsonProperty
158
+ public Features setTableNameLengthSemantics(LengthSemantics tableNameLengthSemantics)
159
+ {
160
+ this.tableNameLengthSemantics = tableNameLengthSemantics;
161
+ return this;
162
+ }
163
+
127
164
  @JsonProperty
128
165
  public Set<Mode> getSupportedModes()
129
166
  {
@@ -412,12 +449,14 @@ public abstract class AbstractJdbcOutputPlugin
412
449
  // direct modify mode doesn't need intermediate tables.
413
450
  ImmutableList.Builder<String> intermTableNames = ImmutableList.builder();
414
451
  if (mode.tempTablePerTask()) {
415
- String namePrefix = generateIntermediateTableNamePrefix(task.getTable(), con, 3, task.getFeatures().getMaxTableNameLength());
452
+ String namePrefix = generateIntermediateTableNamePrefix(task.getTable(), con, 3,
453
+ task.getFeatures().getMaxTableNameLength(), task.getFeatures().getTableNameLengthSemantics());
416
454
  for (int i=0; i < taskCount; i++) {
417
455
  intermTableNames.add(namePrefix + String.format("%03d", i));
418
456
  }
419
457
  } else {
420
- String name = generateIntermediateTableNamePrefix(task.getTable(), con, 0, task.getFeatures().getMaxTableNameLength());
458
+ String name = generateIntermediateTableNamePrefix(task.getTable(), con, 0,
459
+ task.getFeatures().getMaxTableNameLength(), task.getFeatures().getTableNameLengthSemantics());
421
460
  intermTableNames.add(name);
422
461
  }
423
462
  // create the intermediate tables here
@@ -452,7 +491,7 @@ public abstract class AbstractJdbcOutputPlugin
452
491
 
453
492
  // validate column_options
454
493
  newColumnSetters(
455
- new ColumnSetterFactory(null, task.getDefaultTimeZone()), // TODO create a dummy BatchInsert
494
+ newColumnSetterFactory(null, task.getDefaultTimeZone()), // TODO create a dummy BatchInsert
456
495
  task.getTargetTableSchema(), schema,
457
496
  task.getColumnOptions());
458
497
 
@@ -491,7 +530,13 @@ public abstract class AbstractJdbcOutputPlugin
491
530
  }
492
531
  }
493
532
 
494
- protected String generateIntermediateTableNamePrefix(String baseTableName, JdbcOutputConnection con, int suffixLength, int maxLength) throws SQLException
533
+ protected ColumnSetterFactory newColumnSetterFactory(BatchInsert batch, DateTimeZone defaultTimeZone)
534
+ {
535
+ return new ColumnSetterFactory(batch, defaultTimeZone);
536
+ }
537
+
538
+ protected String generateIntermediateTableNamePrefix(String baseTableName, JdbcOutputConnection con,
539
+ int suffixLength, int maxLength, LengthSemantics lengthSemantics) throws SQLException
495
540
  {
496
541
  Charset tableNameCharset = con.getTableNameCharset();
497
542
  String tableName = baseTableName;
@@ -500,7 +545,7 @@ public abstract class AbstractJdbcOutputPlugin
500
545
 
501
546
  // way to count length of table name varies by DBMSs (bytes or characters),
502
547
  // so truncate swap table name by one character.
503
- while (!checkTableNameLength(tableName + "_" + uniqueSuffix, tableNameCharset, suffixLength, maxLength)) {
548
+ while (!checkTableNameLength(tableName + "_" + uniqueSuffix, tableNameCharset, suffixLength, maxLength, lengthSemantics)) {
504
549
  if (uniqueSuffix.length() > 8 + suffix.length()) {
505
550
  // truncate transaction unique name
506
551
  // (include 8 characters of the transaction name at least)
@@ -572,9 +617,10 @@ public abstract class AbstractJdbcOutputPlugin
572
617
  });
573
618
  }
574
619
 
575
- private boolean checkTableNameLength(String tableName, Charset tableNameCharset, int suffixLength, int maxLength)
620
+ private boolean checkTableNameLength(String tableName, Charset tableNameCharset,
621
+ int suffixLength, int maxLength, LengthSemantics lengthSemantics)
576
622
  {
577
- return tableNameCharset.encode(tableName).remaining() + suffixLength <= maxLength;
623
+ return lengthSemantics.countLength(tableNameCharset, tableName) + suffixLength <= maxLength;
578
624
  }
579
625
 
580
626
  protected void doCommit(JdbcOutputConnection con, PluginTask task, int taskCount)
@@ -773,7 +819,7 @@ public abstract class AbstractJdbcOutputPlugin
773
819
  PageReader reader = new PageReader(schema);
774
820
 
775
821
  List<ColumnSetter> columnSetters = newColumnSetters(
776
- new ColumnSetterFactory(batch, task.getDefaultTimeZone()),
822
+ newColumnSetterFactory(batch, task.getDefaultTimeZone()),
777
823
  task.getTargetTableSchema(), schema,
778
824
  task.getColumnOptions());
779
825
  JdbcSchema insertIntoSchema = filterSkipColumns(task.getTargetTableSchema());
@@ -153,6 +153,16 @@ public class JdbcOutputConnection
153
153
  return sb.toString();
154
154
  }
155
155
 
156
+ protected String buildRenameTableSql(String fromTable, String toTable)
157
+ {
158
+ StringBuilder sb = new StringBuilder();
159
+ sb.append("ALTER TABLE ");
160
+ quoteIdentifierString(sb, fromTable);
161
+ sb.append(" RENAME TO ");
162
+ quoteIdentifierString(sb, toTable);
163
+ return sb.toString();
164
+ }
165
+
156
166
  public static enum ColumnDeclareType
157
167
  {
158
168
  SIMPLE,
@@ -208,6 +218,7 @@ public class JdbcOutputConnection
208
218
 
209
219
  private static final String[] STANDARD_SIZE_AND_SCALE_TYPE_NAMES = new String[] {
210
220
  "DECIMAL",
221
+ "NUMERIC",
211
222
  };
212
223
 
213
224
  protected ColumnDeclareType getColumnDeclareType(String convertedTypeName, JdbcColumn col)
@@ -346,13 +357,7 @@ public class JdbcOutputConnection
346
357
  try {
347
358
  dropTableIfExists(stmt, toTable);
348
359
 
349
- StringBuilder sb = new StringBuilder();
350
- sb.append("ALTER TABLE ");
351
- quoteIdentifierString(sb, fromTable);
352
- sb.append(" RENAME TO ");
353
- quoteIdentifierString(sb, toTable);
354
- String sql = sb.toString();
355
- executeUpdate(stmt, sql);
360
+ executeUpdate(stmt, buildRenameTableSql(fromTable, toTable));
356
361
 
357
362
  commitIfNecessary(connection);
358
363
  } catch (SQLException ex) {
@@ -10,7 +10,7 @@ import org.embulk.output.jdbc.BatchInsert;
10
10
  public class SqlDateColumnSetter
11
11
  extends ColumnSetter
12
12
  {
13
- private final Calendar calendar;
13
+ protected final Calendar calendar;
14
14
 
15
15
  public SqlDateColumnSetter(BatchInsert batch, JdbcColumn column,
16
16
  DefaultValueSetter defaultValue,
@@ -10,7 +10,7 @@ import org.embulk.output.jdbc.BatchInsert;
10
10
  public class SqlTimeColumnSetter
11
11
  extends ColumnSetter
12
12
  {
13
- private final Calendar calendar;
13
+ protected final Calendar calendar;
14
14
 
15
15
  public SqlTimeColumnSetter(BatchInsert batch, JdbcColumn column,
16
16
  DefaultValueSetter defaultValue,
@@ -10,7 +10,7 @@ import org.embulk.output.jdbc.BatchInsert;
10
10
  public class SqlTimestampColumnSetter
11
11
  extends ColumnSetter
12
12
  {
13
- private final Calendar calendar;
13
+ protected final Calendar calendar;
14
14
 
15
15
  public SqlTimestampColumnSetter(BatchInsert batch, JdbcColumn column,
16
16
  DefaultValueSetter defaultValue,
@@ -0,0 +1,117 @@
1
+ package org.embulk.output;
2
+
3
+ import java.io.File;
4
+ import java.net.URISyntaxException;
5
+ import java.nio.charset.Charset;
6
+ import java.sql.Connection;
7
+ import java.sql.ResultSet;
8
+ import java.sql.SQLException;
9
+ import java.sql.Statement;
10
+ import java.util.ArrayList;
11
+ import java.util.Collections;
12
+ import java.util.Comparator;
13
+ import java.util.List;
14
+ import java.util.regex.Matcher;
15
+ import java.util.regex.Pattern;
16
+
17
+ import com.google.common.io.Files;
18
+
19
+ public abstract class AbstractJdbcOutputPluginTest
20
+ {
21
+ protected void dropTable(String table) throws SQLException
22
+ {
23
+ String sql = String.format("DROP TABLE %s", table);
24
+ executeSQL(sql, true);
25
+ }
26
+
27
+ protected List<List<Object>> select(String table) throws SQLException
28
+ {
29
+ try (Connection connection = connect()) {
30
+ try (Statement statement = connection.createStatement()) {
31
+ List<List<Object>> rows = new ArrayList<List<Object>>();
32
+ String sql = String.format("SELECT * FROM %s", table);
33
+ System.out.println(sql);
34
+ try (ResultSet resultSet = statement.executeQuery(sql)) {
35
+ while (resultSet.next()) {
36
+ List<Object> row = new ArrayList<Object>();
37
+ for (int i = 1; i <= resultSet.getMetaData().getColumnCount(); i++) {
38
+ row.add(getValue(resultSet, i));
39
+ }
40
+ rows.add(row);
41
+ }
42
+ }
43
+ // cannot sort by CLOB, so sort by Java
44
+ Collections.sort(rows, new Comparator<List<Object>>() {
45
+ @Override
46
+ public int compare(List<Object> o1, List<Object> o2) {
47
+ return o1.toString().compareTo(o2.toString());
48
+ }
49
+ });
50
+ return rows;
51
+ }
52
+ }
53
+
54
+ }
55
+
56
+ protected Object getValue(ResultSet resultSet, int index) throws SQLException
57
+ {
58
+ return resultSet.getObject(index);
59
+ }
60
+
61
+ protected void executeSQL(String sql) throws SQLException
62
+ {
63
+ executeSQL(sql, false);
64
+ }
65
+
66
+ protected void executeSQL(String sql, boolean ignoreError) throws SQLException
67
+ {
68
+ try (Connection connection = connect()) {
69
+ try {
70
+ connection.setAutoCommit(true);
71
+
72
+ try (Statement statement = connection.createStatement()) {
73
+ System.out.println(String.format("Execute SQL : \"%s\".", sql));
74
+ statement.execute(sql);
75
+ }
76
+
77
+ } catch (SQLException e) {
78
+ if (!ignoreError) {
79
+ throw e;
80
+ }
81
+ }
82
+ }
83
+ }
84
+
85
+ protected String convertYml(String ymlName) throws Exception
86
+ {
87
+ StringBuilder builder = new StringBuilder();
88
+ Pattern pathPrefixPattern = Pattern.compile("^ *path(_prefix)?: '(.*)'$");
89
+ for (String line : Files.readLines(convertPath(ymlName), Charset.defaultCharset())) {
90
+ line = convertYmlLine(line);
91
+ Matcher matcher = pathPrefixPattern.matcher(line);
92
+ if (matcher.matches()) {
93
+ int group = 2;
94
+ builder.append(line.substring(0, matcher.start(group)));
95
+ builder.append(convertPath(matcher.group(group)).getAbsolutePath());
96
+ builder.append(line.substring(matcher.end(group)));
97
+ } else {
98
+ builder.append(line);
99
+ }
100
+ builder.append(System.lineSeparator());
101
+ }
102
+ return builder.toString();
103
+ }
104
+
105
+ protected String convertYmlLine(String line)
106
+ {
107
+ return line;
108
+ }
109
+
110
+ protected File convertPath(String name) throws URISyntaxException
111
+ {
112
+ return new File(getClass().getResource(name).toURI());
113
+ }
114
+
115
+ protected abstract Connection connect() throws SQLException;
116
+
117
+ }
@@ -0,0 +1,78 @@
1
+ package org.embulk.output.tester;
2
+
3
+ import java.util.ArrayList;
4
+ import java.util.List;
5
+
6
+ import org.embulk.EmbulkEmbed;
7
+ import org.embulk.EmbulkEmbed.Bootstrap;
8
+ import org.embulk.config.ConfigSource;
9
+ import org.embulk.plugin.InjectedPluginSource;
10
+
11
+ import com.google.inject.Binder;
12
+ import com.google.inject.Module;
13
+
14
+ public class EmbulkPluginTester
15
+ {
16
+ private static class PluginDefinition
17
+ {
18
+ public final Class<?> iface;
19
+ public final String name;
20
+ public final Class<?> impl;
21
+
22
+
23
+ public PluginDefinition(Class<?> iface, String name, Class<?> impl)
24
+ {
25
+ this.iface = iface;
26
+ this.name = name;
27
+ this.impl = impl;
28
+ }
29
+
30
+ }
31
+
32
+ private final List<PluginDefinition> plugins = new ArrayList<PluginDefinition>();
33
+
34
+ private EmbulkEmbed embulk;
35
+
36
+ public EmbulkPluginTester()
37
+ {
38
+ }
39
+
40
+ public EmbulkPluginTester(Class<?> iface, String name, Class<?> impl)
41
+ {
42
+ addPlugin(iface, name, impl);
43
+ }
44
+
45
+ public void addPlugin(Class<?> iface, String name, Class<?> impl)
46
+ {
47
+ plugins.add(new PluginDefinition(iface, name, impl));
48
+ }
49
+
50
+ public void run(String yml) throws Exception
51
+ {
52
+ if (embulk == null) {
53
+ Bootstrap bootstrap = new EmbulkEmbed.Bootstrap();
54
+ bootstrap.addModules(new Module()
55
+ {
56
+ @Override
57
+ public void configure(Binder binder)
58
+ {
59
+ for (PluginDefinition plugin : plugins) {
60
+ InjectedPluginSource.registerPluginTo(binder, plugin.iface, plugin.name, plugin.impl);
61
+ }
62
+ }
63
+ });
64
+ embulk = bootstrap.initializeCloseable();
65
+ }
66
+ ConfigSource config = embulk.newConfigLoader().fromYamlString(yml);
67
+ embulk.run(config);
68
+ }
69
+
70
+ public void destroy()
71
+ {
72
+ if (embulk != null) {
73
+ embulk.destroy();
74
+ embulk = null;
75
+ }
76
+ }
77
+
78
+ }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: embulk-output-jdbc
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.5
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sadayuki Furuhashi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-01-14 00:00:00.000000000 Z
11
+ date: 2016-01-15 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Inserts or updates records to a table.
14
14
  email:
@@ -52,8 +52,10 @@ files:
52
52
  - src/main/java/org/embulk/output/jdbc/setter/SqlTimeColumnSetter.java
53
53
  - src/main/java/org/embulk/output/jdbc/setter/SqlTimestampColumnSetter.java
54
54
  - src/main/java/org/embulk/output/jdbc/setter/StringColumnSetter.java
55
+ - src/test/java/org/embulk/output/AbstractJdbcOutputPluginTest.java
55
56
  - src/test/java/org/embulk/output/TestJdbcOutputPlugin.java
56
- - classpath/embulk-output-jdbc-0.4.5.jar
57
+ - src/test/java/org/embulk/output/tester/EmbulkPluginTester.java
58
+ - classpath/embulk-output-jdbc-0.5.0.jar
57
59
  homepage: https://github.com/embulk/embulk-output-jdbc
58
60
  licenses:
59
61
  - Apache 2.0