embulk-output-jdbc 0.4.5 → 0.5.0

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