embulk-output-oracle 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.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +0 -50
  3. data/build.gradle +1 -0
  4. data/classpath/embulk-output-jdbc-0.5.0.jar +0 -0
  5. data/classpath/embulk-output-oracle-0.5.0.jar +0 -0
  6. data/src/main/java/org/embulk/output/oracle/DirectBatchInsert.java +16 -14
  7. data/src/main/java/org/embulk/output/oracle/OracleOutputConnection.java +5 -5
  8. data/src/main/java/org/embulk/output/oracle/oci/ColumnDefinition.java +39 -15
  9. data/src/main/java/org/embulk/output/oracle/oci/OCI.java +125 -133
  10. data/src/main/java/org/embulk/output/oracle/oci/OCIWrapper.java +403 -33
  11. data/src/main/java/org/embulk/output/oracle/oci/RowBuffer.java +39 -40
  12. data/src/main/java/org/embulk/output/oracle/oci/TableDefinition.java +17 -3
  13. data/src/test/java/org/embulk/output/oracle/OracleOutputPluginTest.java +2 -2
  14. data/src/test/java/org/embulk/output/oracle/OracleOutputPluginTestImpl.java +38 -143
  15. data/src/test/resources/{data → oracle/data}/test1/test1.csv +0 -0
  16. data/src/test/resources/{yml → oracle/yml}/test-insert-direct-direct-method.yml +1 -1
  17. data/src/test/resources/{yml → oracle/yml}/test-insert-direct-empty.yml +1 -1
  18. data/src/test/resources/{yml → oracle/yml}/test-insert-direct-oci-method-split.yml +1 -1
  19. data/src/test/resources/{yml → oracle/yml}/test-insert-direct-oci-method.yml +1 -1
  20. data/src/test/resources/{yml → oracle/yml}/test-insert-direct.yml +1 -1
  21. data/src/test/resources/{yml → oracle/yml}/test-insert-empty.yml +1 -1
  22. data/src/test/resources/{yml → oracle/yml}/test-insert.yml +1 -1
  23. data/src/test/resources/{yml → oracle/yml}/test-replace-empty.yml +1 -1
  24. data/src/test/resources/{yml → oracle/yml}/test-replace-long-name-multibyte.yml +1 -1
  25. data/src/test/resources/{yml → oracle/yml}/test-replace-long-name.yml +1 -1
  26. data/src/test/resources/{yml → oracle/yml}/test-replace-oci-method.yml +1 -1
  27. data/src/test/resources/{yml → oracle/yml}/test-replace.yml +1 -1
  28. data/src/test/resources/{yml → oracle/yml}/test-string-timestamp.yml +1 -1
  29. data/src/test/resources/{yml → oracle/yml}/test-truncate-insert-oci-method.yml +1 -1
  30. data/src/test/resources/{yml → oracle/yml}/test-truncate-insert.yml +1 -1
  31. data/src/test/resources/{yml → oracle/yml}/test-url.yml +1 -1
  32. metadata +21 -38
  33. data/classpath/embulk-output-jdbc-0.4.5.jar +0 -0
  34. data/classpath/embulk-output-oracle-0.4.5.jar +0 -0
  35. data/lib/embulk/linux_x64/libembulk-output-oracle.so +0 -0
  36. data/lib/embulk/win_x64/embulk-output-oracle.dll +0 -0
  37. data/src/main/cpp/common/dir-path-load.cpp +0 -425
  38. data/src/main/cpp/common/dir-path-load.h +0 -37
  39. data/src/main/cpp/common/embulk-output-oracle.cpp +0 -195
  40. data/src/main/cpp/common/org_embulk_output_oracle_oci_OCI.h +0 -77
  41. data/src/main/cpp/linux/build.sh +0 -21
  42. data/src/main/cpp/win/build.bat +0 -32
  43. data/src/main/cpp/win/dllmain.cpp +0 -25
  44. data/src/main/cpp/win/embulk-output-oracle.sln +0 -39
  45. data/src/main/cpp/win/embulk-output-oracle.vcxproj +0 -176
  46. data/src/test/cpp/common/embulk-output-oracle-test.cpp +0 -69
  47. data/src/test/cpp/linux/build.sh +0 -19
  48. data/src/test/cpp/win/build.bat +0 -29
  49. data/src/test/cpp/win/embulk-output-oracle-test.vcxproj +0 -155
  50. data/src/test/java/org/embulk/output/tester/EmbulkPluginTester.java +0 -79
  51. data/src/test/resources/dummy.txt +0 -1
@@ -1,20 +1,38 @@
1
1
  package org.embulk.output.oracle.oci;
2
2
 
3
+ import java.nio.ByteBuffer;
3
4
  import java.nio.charset.Charset;
4
5
  import java.sql.SQLException;
5
6
 
7
+ import jnr.ffi.LibraryLoader;
8
+ import jnr.ffi.Pointer;
9
+ import jnr.ffi.Runtime;
10
+ import jnr.ffi.provider.BoundedMemoryIO;
11
+ import jnr.ffi.provider.jffi.ArrayMemoryIO;
12
+ import jnr.ffi.provider.jffi.ByteBufferMemoryIO;
13
+
6
14
  import org.embulk.spi.Exec;
7
15
  import org.slf4j.Logger;
8
16
 
9
17
 
10
- public class OCIWrapper implements AutoCloseable
18
+ public class OCIWrapper
11
19
  {
20
+ private static OCI oci;
21
+
12
22
  private final Logger logger = Exec.getLogger(getClass());
13
23
 
14
- private final OCI oci = new OCI();
15
- // used for messages
16
- private final Charset defaultCharset;
17
- private byte[] context;
24
+ private final Charset systemCharset;
25
+ private Pointer envHandle;
26
+ private Pointer errHandle;
27
+ private Pointer svcHandlePointer;
28
+ private Pointer svcHandle;
29
+ private Pointer dpHandle;
30
+ private Pointer dpcaHandle;
31
+ private Pointer dpstrHandle;
32
+
33
+ private TableDefinition tableDefinition;
34
+ private int maxRowCount;
35
+
18
36
  private boolean errorOccured;
19
37
  private boolean committedOrRollbacked;
20
38
 
@@ -22,28 +40,299 @@ public class OCIWrapper implements AutoCloseable
22
40
  public OCIWrapper()
23
41
  {
24
42
  // enable to change default encoding for test
25
- defaultCharset = Charset.forName(System.getProperty("file.encoding"));
26
- context = oci.createContext();
43
+ systemCharset = Charset.forName(System.getProperty("file.encoding"));
44
+
45
+ synchronized (OCIWrapper.class) {
46
+ if (oci == null) {
47
+ oci = loadLibrary();
48
+ }
49
+ }
27
50
  }
28
51
 
29
- public void open(String dbName, String userName, String password) throws SQLException
52
+ private OCI loadLibrary()
30
53
  {
31
- if (!oci.open(context, dbName, userName, password)) {
32
- throwException();
54
+ logger.info("Loading OCI library.");
55
+
56
+ // "oci" for Windows, "clntsh" for Linux
57
+ StringBuilder libraryNames = new StringBuilder();
58
+ for (String libraryName : new String[]{"oci", "clntsh"}) {
59
+ try {
60
+ return LibraryLoader.create(OCI.class).failImmediately().load(libraryName);
61
+ } catch (UnsatisfiedLinkError e) {
62
+ }
63
+
64
+ if (libraryNames.length() > 0) {
65
+ libraryNames.append(" / ");
66
+ }
67
+ libraryNames.append(System.mapLibraryName(libraryName));
33
68
  }
69
+
70
+ throw new UnsatisfiedLinkError("Cannot find library: " + libraryNames);
71
+ }
72
+
73
+ public void open(String dbName, String userName, String password) throws SQLException
74
+ {
75
+ Pointer envHandlePointer = createPointerPointer();
76
+ check("OCIEnvCreate", oci.OCIEnvCreate(
77
+ envHandlePointer,
78
+ OCI.OCI_THREADED | OCI.OCI_OBJECT,
79
+ null,
80
+ null,
81
+ null,
82
+ null,
83
+ 0,
84
+ null));
85
+ envHandle = envHandlePointer.getPointer(0);
86
+
87
+ // error handle
88
+ Pointer errHandlePointer = createPointerPointer();
89
+ check("OCIHandleAlloc(OCI_HTYPE_ERROR)", oci.OCIHandleAlloc(
90
+ envHandle,
91
+ errHandlePointer,
92
+ OCI.OCI_HTYPE_ERROR,
93
+ 0,
94
+ null));
95
+ errHandle = errHandlePointer.getPointer(0);
96
+
97
+ // service context
98
+ svcHandlePointer = createPointerPointer();
99
+ check("OCIHandleAlloc(OCI_HTYPE_SVCCTX)", oci.OCIHandleAlloc(
100
+ envHandle,
101
+ svcHandlePointer,
102
+ OCI.OCI_HTYPE_SVCCTX,
103
+ 0,
104
+ null));
105
+
106
+ // logon
107
+ // dbName should be defined in 'tnsnames.ora' or a form of "host:port/db"
108
+ check("OCILogon", oci.OCILogon(
109
+ envHandle,
110
+ errHandle,
111
+ svcHandlePointer,
112
+ userName,
113
+ userName.length(),
114
+ password,
115
+ password.length(),
116
+ dbName,
117
+ dbName.length()));
118
+ svcHandle = svcHandlePointer.getPointer(0);
119
+
120
+ Pointer dpHandlePointer = createPointerPointer();
121
+ check("OCIHandleAlloc(OCI_HTYPE_DIRPATH_CTX)", oci.OCIHandleAlloc(
122
+ envHandle,
123
+ dpHandlePointer,
124
+ OCI.OCI_HTYPE_DIRPATH_CTX,
125
+ 0,
126
+ null));
127
+ dpHandle = dpHandlePointer.getPointer(0);
34
128
  }
35
129
 
36
130
  public void prepareLoad(TableDefinition tableDefinition) throws SQLException
37
131
  {
38
- if (!oci.prepareLoad(context, tableDefinition)) {
39
- throwException();
132
+ this.tableDefinition = tableDefinition;
133
+
134
+ // load table name
135
+ Pointer tableName = createPointer(tableDefinition.getTableName());
136
+ check("OCIAttrSet(OCI_ATTR_NAME)", oci.OCIAttrSet(
137
+ dpHandle,
138
+ OCI.OCI_HTYPE_DIRPATH_CTX,
139
+ tableName,
140
+ (int)tableName.size()
141
+ , OCI.OCI_ATTR_NAME,
142
+ errHandle));
143
+
144
+ Pointer cols = createPointer((short)tableDefinition.getColumnCount());
145
+ check("OCIAttrSet(OCI_ATTR_NUM_COLS)", oci.OCIAttrSet(
146
+ dpHandle,
147
+ OCI.OCI_HTYPE_DIRPATH_CTX,
148
+ cols,
149
+ (int)cols.size(),
150
+ OCI.OCI_ATTR_NUM_COLS,
151
+ errHandle));
152
+
153
+ Pointer columnsPointer = createPointerPointer();
154
+ check("OCIAttrGet(OCI_ATTR_LIST_COLUMNS)", oci.OCIAttrGet(
155
+ dpHandle,
156
+ OCI.OCI_HTYPE_DIRPATH_CTX,
157
+ columnsPointer,
158
+ null,
159
+ OCI.OCI_ATTR_LIST_COLUMNS,
160
+ errHandle));
161
+ Pointer columns = columnsPointer.getPointer(0);
162
+
163
+ for (int i = 0; i < tableDefinition.getColumnCount(); i++) {
164
+ ColumnDefinition columnDefinition = tableDefinition.getColumn(i);
165
+
166
+ Pointer columnPointer = createPointerPointer();
167
+ check("OCIParamGet(OCI_DTYPE_PARAM)", oci.OCIParamGet(
168
+ columns,
169
+ OCI.OCI_DTYPE_PARAM,
170
+ errHandle,
171
+ columnPointer,
172
+ i + 1));
173
+ Pointer column = columnPointer.getPointer(0);
174
+
175
+ Pointer columnName = createPointer(columnDefinition.getColumnName());
176
+ check("OCIAttrSet(OCI_ATTR_NAME)", oci.OCIAttrSet(
177
+ column,
178
+ OCI.OCI_DTYPE_PARAM,
179
+ columnName,
180
+ (int)columnName.size(),
181
+ OCI.OCI_ATTR_NAME,
182
+ errHandle));
183
+
184
+ Pointer dataType = createPointer(columnDefinition.getDataType());
185
+ check("OCIAttrSet(OCI_ATTR_DATA_TYPE)", oci.OCIAttrSet(
186
+ column,
187
+ OCI.OCI_DTYPE_PARAM,
188
+ dataType,
189
+ (int)dataType.size(),
190
+ OCI.OCI_ATTR_DATA_TYPE,
191
+ errHandle));
192
+
193
+ Pointer dataSize = createPointer(columnDefinition.getDataSize());
194
+ check("OCIAttrSet(OCI_ATTR_DATA_SIZE)", oci.OCIAttrSet(
195
+ column,
196
+ OCI.OCI_DTYPE_PARAM,
197
+ dataSize,
198
+ (int)dataSize.size(),
199
+ OCI.OCI_ATTR_DATA_SIZE,
200
+ errHandle));
201
+
202
+ // need to set charset explicitly because database charset is not set by default.
203
+ Pointer charsetId = createPointer(columnDefinition.getCharset().getId());
204
+ check("OCIAttrSet(OCI_ATTR_CHARSET_ID)", oci.OCIAttrSet(
205
+ column,
206
+ OCI.OCI_DTYPE_PARAM,
207
+ charsetId,
208
+ (int)charsetId.size(),
209
+ OCI.OCI_ATTR_CHARSET_ID,
210
+ errHandle));
211
+
212
+ if (columnDefinition.getDateFormat() != null) {
213
+ Pointer dateFormat = createPointer(columnDefinition.getDateFormat());
214
+ check("OCIAttrSet(OCI_ATTR_DATEFORMAT)", oci.OCIAttrSet(
215
+ column,
216
+ OCI.OCI_DTYPE_PARAM,
217
+ dateFormat,
218
+ (int)dateFormat.size(),
219
+ OCI.OCI_ATTR_DATEFORMAT,
220
+ errHandle));
221
+ }
222
+
223
+ check("OCIDescriptorFree(OCI_DTYPE_PARAM)", oci.OCIDescriptorFree(
224
+ column,
225
+ OCI.OCI_DTYPE_PARAM));
226
+ }
227
+
228
+ check("OCIDirPathPrepare", oci.OCIDirPathPrepare(
229
+ dpHandle,
230
+ svcHandle,
231
+ errHandle));
232
+
233
+ // direct path column array
234
+ Pointer dpcaHandlePointer = createPointerPointer();
235
+ check("OCIHandleAlloc(OCI_HTYPE_DIRPATH_COLUMN_ARRAY)", oci.OCIHandleAlloc(
236
+ dpHandle,
237
+ dpcaHandlePointer,
238
+ OCI.OCI_HTYPE_DIRPATH_COLUMN_ARRAY,
239
+ 0,
240
+ null));
241
+ dpcaHandle = dpcaHandlePointer.getPointer(0);
242
+
243
+ Pointer dpstrHandlePointer = createPointerPointer();
244
+ check("OCIHandleAlloc(OCI_HTYPE_DIRPATH_STREAM)", oci.OCIHandleAlloc(
245
+ dpHandle,
246
+ dpstrHandlePointer,
247
+ OCI.OCI_HTYPE_DIRPATH_STREAM,
248
+ 0,
249
+ null));
250
+ dpstrHandle = dpstrHandlePointer.getPointer(0);
251
+
252
+ Pointer maxRowCountPointer = createPointer(0);
253
+
254
+ check("OCIAttrGet(OCI_ATTR_NUM_ROWS)", oci.OCIAttrGet(
255
+ dpcaHandle,
256
+ OCI.OCI_HTYPE_DIRPATH_COLUMN_ARRAY,
257
+ maxRowCountPointer,
258
+ null,
259
+ OCI.OCI_ATTR_NUM_ROWS,
260
+ errHandle));
261
+ maxRowCount = maxRowCountPointer.getInt(0);
262
+ }
263
+
264
+ public void loadBuffer(RowBuffer rowBuffer) throws SQLException
265
+ {
266
+ Pointer pointer = new ByteBufferMemoryIO(Runtime.getSystemRuntime(), rowBuffer.getBuffer());
267
+ short[] sizes = rowBuffer.getSizes();
268
+
269
+ int i = 0;
270
+ int position = 0;
271
+ int rowCount = 0;
272
+ for (int row = 0; row < rowBuffer.getRowCount(); row++) {
273
+ for (short col = 0; col < tableDefinition.getColumnCount(); col++) {
274
+ short size = sizes[i++];
275
+
276
+ check("OCIDirPathColArrayEntrySet", oci.OCIDirPathColArrayEntrySet(
277
+ dpcaHandle,
278
+ errHandle,
279
+ rowCount,
280
+ col,
281
+ new BoundedMemoryIO(pointer, position, size),
282
+ size,
283
+ OCI.OCI_DIRPATH_COL_COMPLETE));
284
+
285
+ position += size;
286
+ }
287
+
288
+ rowCount++;
289
+ if (rowCount == maxRowCount) {
290
+ loadRows(rowCount);
291
+ rowCount = 0;
292
+ }
293
+ }
294
+
295
+ if (rowCount > 0) {
296
+ loadRows(rowCount);
40
297
  }
41
298
  }
42
299
 
43
- public void loadBuffer(byte[] buffer, int rowCount) throws SQLException
300
+ private void loadRows(int rowCount) throws SQLException
44
301
  {
45
- if (!oci.loadBuffer(context, buffer, rowCount)) {
46
- throwException();
302
+ for (int offset = 0; offset < rowCount;) {
303
+ check("OCIDirPathStreamReset", oci.OCIDirPathStreamReset(
304
+ dpstrHandle,
305
+ errHandle));
306
+
307
+ short result = oci.OCIDirPathColArrayToStream(
308
+ dpcaHandle,
309
+ dpHandle,
310
+ dpstrHandle,
311
+ errHandle,
312
+ rowCount,
313
+ offset);
314
+ if (result != OCI.OCI_SUCCESS && result != OCI.OCI_CONTINUE) {
315
+ check("OCIDirPathColArrayToStream", result);
316
+ }
317
+
318
+ check("OCIDirPathLoadStream", oci.OCIDirPathLoadStream(
319
+ dpHandle,
320
+ dpstrHandle,
321
+ errHandle));
322
+
323
+ if (result == OCI.OCI_SUCCESS) {
324
+ offset = rowCount;
325
+ } else {
326
+ Pointer loadedRowCount = createPointer(0);
327
+ check("OCIAttrGet(OCI_ATTR_ROW_COUNT)", oci.OCIAttrGet(
328
+ dpcaHandle,
329
+ OCI.OCI_HTYPE_DIRPATH_COLUMN_ARRAY,
330
+ loadedRowCount,
331
+ null,
332
+ OCI.OCI_ATTR_ROW_COUNT,
333
+ errHandle));
334
+ offset += loadedRowCount.getInt(0);
335
+ }
47
336
  }
48
337
  }
49
338
 
@@ -51,33 +340,27 @@ public class OCIWrapper implements AutoCloseable
51
340
  {
52
341
  committedOrRollbacked = true;
53
342
  logger.info("OCI : start to commit.");
54
- if (!oci.commit(context)) {
55
- throwException();
56
- }
343
+
344
+ check("OCIDirPathFinish", oci.OCIDirPathFinish(dpHandle, errHandle));
345
+
346
+ check("OCILogoff", oci.OCILogoff(svcHandle, errHandle));
347
+ svcHandle = null;
57
348
  }
58
349
 
59
350
  public void rollback() throws SQLException
60
351
  {
61
352
  committedOrRollbacked = true;
62
353
  logger.info("OCI : start to rollback.");
63
- if (!oci.rollback(context)) {
64
- throwException();
65
- }
66
- }
67
354
 
68
- private void throwException() throws SQLException
69
- {
70
- errorOccured = true;
71
- String message = new String(oci.getLasetMessage(context), defaultCharset);
72
- logger.error(message);
73
- throw new SQLException(message);
74
- }
355
+ check("OCIDirPathAbort", oci.OCIDirPathAbort(dpHandle, errHandle));
75
356
 
357
+ check("OCILogoff", oci.OCILogoff(svcHandle, errHandle));
358
+ svcHandle = null;
359
+ }
76
360
 
77
- @Override
78
361
  public void close() throws SQLException
79
362
  {
80
- if (context != null) {
363
+ if (dpHandle != null) {
81
364
  try {
82
365
  if (!committedOrRollbacked) {
83
366
  if (errorOccured) {
@@ -87,10 +370,97 @@ public class OCIWrapper implements AutoCloseable
87
370
  }
88
371
  }
89
372
  } finally {
90
- oci.close(context);
91
- context = null;
373
+ freeHandle(OCI.OCI_HTYPE_DIRPATH_STREAM, dpstrHandle);
374
+ dpcaHandle = null;
375
+
376
+ freeHandle(OCI.OCI_HTYPE_DIRPATH_COLUMN_ARRAY, dpcaHandle);
377
+ dpcaHandle = null;
378
+
379
+ freeHandle(OCI.OCI_HTYPE_DIRPATH_CTX, dpHandle);
380
+ dpHandle = null;
381
+
382
+ freeHandle(OCI.OCI_HTYPE_SVCCTX, svcHandle);
383
+ svcHandle = null;
384
+
385
+ freeHandle(OCI.OCI_HTYPE_ERROR, errHandle);
386
+ errHandle = null;
387
+
388
+ freeHandle(OCI.OCI_HTYPE_ENV, envHandle);
389
+ envHandle = null;
92
390
  }
93
391
  }
94
392
  }
95
393
 
394
+ private Pointer createPointerPointer()
395
+ {
396
+ return new ArrayMemoryIO(Runtime.getSystemRuntime(), com.kenai.jffi.Type.POINTER.size());
397
+ }
398
+
399
+ private Pointer createPointer(String s)
400
+ {
401
+ return Pointer.wrap(Runtime.getSystemRuntime(), ByteBuffer.wrap(s.getBytes()));
402
+ }
403
+
404
+ private Pointer createPointer(short n)
405
+ {
406
+ Pointer pointer = new ArrayMemoryIO(Runtime.getSystemRuntime(), 2);
407
+ pointer.putShort(0, n);
408
+ return pointer;
409
+ }
410
+
411
+ private Pointer createPointer(int n)
412
+ {
413
+ Pointer pointer = new ArrayMemoryIO(Runtime.getSystemRuntime(), 4);
414
+ pointer.putInt(0, n);
415
+ return pointer;
416
+ }
417
+
418
+ private void freeHandle(int type, Pointer handle)
419
+ {
420
+ if (handle != null) {
421
+ try {
422
+ check("OCIHandleFree", oci.OCIHandleFree(handle, type));
423
+ } catch (SQLException e) {
424
+ logger.warn(String.format("Warning (OCIHandleFree(%d)) : %s", type, e.getMessage()));
425
+ }
426
+ }
427
+ }
428
+
429
+ private void check(String operation, short result) throws SQLException
430
+ {
431
+ switch (result) {
432
+ case OCI.OCI_SUCCESS:
433
+ break;
434
+
435
+ case OCI.OCI_ERROR:
436
+ if (errHandle == null) {
437
+ throwException("OCI : %s failed : %d.", operation, result);
438
+ }
439
+ ArrayMemoryIO errrCode = new ArrayMemoryIO(Runtime.getSystemRuntime(), 4);
440
+ ArrayMemoryIO buffer = new ArrayMemoryIO(Runtime.getSystemRuntime(), 512);
441
+ if (oci.OCIErrorGet(errHandle, 1, null, errrCode, buffer, (int)buffer.size(), OCI.OCI_HTYPE_ERROR) != OCI.OCI_SUCCESS) {
442
+ throwException("OCI : %s failed : %d. OCIErrorGet failed.", operation, result);
443
+ }
444
+
445
+ String message = new String(buffer.array(), systemCharset);
446
+ throwException("OCI : %s failed : %d. %s", operation, result, message);
447
+
448
+ case OCI.OCI_INVALID_HANDLE:
449
+ throwException("OCI : %s failed : invalid handle.", operation);
450
+
451
+ case OCI.OCI_NO_DATA:
452
+ throwException("OCI : %s failed : no data.", operation);
453
+
454
+ default:
455
+ throwException("OCI : %s failed : %d.", operation, result);
456
+ }
457
+ }
458
+
459
+ private void throwException(String format, Object... args) throws SQLException
460
+ {
461
+ errorOccured = true;
462
+ String message = String.format(format, args);
463
+ logger.error(message);
464
+ throw new SQLException(message);
465
+ }
96
466
  }
@@ -5,33 +5,47 @@ import java.nio.ByteBuffer;
5
5
  import java.nio.charset.Charset;
6
6
  import java.sql.SQLException;
7
7
 
8
+ import jnr.ffi.Runtime;
9
+
10
+ import org.embulk.output.oracle.oci.ColumnDefinition;
11
+ import org.embulk.output.oracle.oci.TableDefinition;
8
12
 
9
13
  public class RowBuffer
10
14
  {
11
15
  private final TableDefinition table;
12
16
  private final int rowCount;
13
- private final byte[] buffer;
17
+
14
18
  private int currentRow = 0;
15
19
  private int currentColumn = 0;
16
- private int currentPosition = 0;
17
- private final Charset charset;
18
20
 
19
- public RowBuffer(TableDefinition table, int rowCount, Charset charset)
21
+ private final short[] sizes;
22
+ private final ByteBuffer buffer;
23
+ private final ByteBuffer defaultBuffer;
24
+
25
+ public RowBuffer(TableDefinition table, int rowCount)
20
26
  {
21
27
  this.table = table;
22
28
  this.rowCount = rowCount;
23
- this.charset = charset;
24
29
 
25
30
  int rowSize = 0;
26
- for (ColumnDefinition column : table.columns) {
27
- if (column.columnType == ColumnDefinition.SQLT_CHR) {
28
- // for length of string
29
- rowSize += 2;
30
- }
31
- rowSize += column.columnSize;
31
+ for (int i = 0; i < table.getColumnCount(); i++) {
32
+ rowSize += table.getColumn(i).getDataSize();
32
33
  }
33
34
 
34
- buffer = new byte[rowSize * rowCount];
35
+ // should be direct because used by native library
36
+ buffer = ByteBuffer.allocateDirect(rowSize * rowCount).order(Runtime.getSystemRuntime().byteOrder());
37
+ // position is not updated
38
+ defaultBuffer = buffer.duplicate();
39
+
40
+ sizes = new short[table.getColumnCount() * rowCount];
41
+ }
42
+
43
+ public ByteBuffer getBuffer() {
44
+ return defaultBuffer;
45
+ }
46
+
47
+ public short[] getSizes() {
48
+ return sizes;
35
49
  }
36
50
 
37
51
  public void addValue(int value)
@@ -40,40 +54,33 @@ public class RowBuffer
40
54
  throw new IllegalStateException();
41
55
  }
42
56
 
43
- buffer[currentPosition] = (byte)value;
44
- buffer[currentPosition + 1] = (byte)(value >> 8);
45
- buffer[currentPosition + 2] = (byte)(value >> 16);
46
- buffer[currentPosition + 3] = (byte)(value >> 24);
57
+ buffer.putInt(value);
47
58
 
48
- next();
59
+ next((short)4);
49
60
  }
50
61
 
51
62
  public void addValue(String value) throws SQLException
52
- {
53
- addValue(value, charset);
54
- }
55
-
56
- public void addValue(String value, Charset charset) throws SQLException
57
63
  {
58
64
  if (isFull()) {
59
65
  throw new IllegalStateException();
60
66
  }
61
67
 
68
+ ColumnDefinition column = table.getColumn(currentColumn);
69
+ Charset charset = column.getCharset().getJavaCharset();
70
+
62
71
  ByteBuffer bytes = charset.encode(value);
63
72
  int length = bytes.remaining();
64
73
  if (length > 65535) {
65
74
  throw new SQLException(String.format("byte count of string is too large (max : 65535, actual : %d).", length));
66
75
  }
67
- if (length > table.columns[currentColumn].columnSize) {
76
+ if (length > column.getDataSize()) {
68
77
  throw new SQLException(String.format("byte count of string is too large for column \"%s\" (max : %d, actual : %d).",
69
- table.columns[currentColumn].columnName, table.columns[currentColumn].columnSize, length));
78
+ column.getColumnName(), column.getDataSize(), length));
70
79
  }
71
80
 
72
- buffer[currentPosition] = (byte)length;
73
- buffer[currentPosition + 1] = (byte)(length >> 8);
74
- bytes.get(buffer, currentPosition + 2, length);
81
+ buffer.put(bytes);
75
82
 
76
- next();
83
+ next((short)length);
77
84
  }
78
85
 
79
86
  public void addValue(BigDecimal value) throws SQLException
@@ -81,25 +88,17 @@ public class RowBuffer
81
88
  addValue(value.toPlainString());
82
89
  }
83
90
 
84
- private void next()
91
+ private void next(short size)
85
92
  {
86
- if (table.columns[currentColumn].columnType == ColumnDefinition.SQLT_CHR) {
87
- currentPosition += 2;
88
- }
89
- currentPosition += table.columns[currentColumn].columnSize;
93
+ sizes[currentRow * table.getColumnCount() + currentColumn] = size;
90
94
 
91
95
  currentColumn++;
92
- if (currentColumn == table.columns.length) {
96
+ if (currentColumn == table.getColumnCount()) {
93
97
  currentColumn = 0;
94
98
  currentRow++;
95
99
  }
96
100
  }
97
101
 
98
- public byte[] getBuffer()
99
- {
100
- return buffer;
101
- }
102
-
103
102
  public int getCurrentColumn()
104
103
  {
105
104
  return currentColumn;
@@ -117,9 +116,9 @@ public class RowBuffer
117
116
 
118
117
  public void clear()
119
118
  {
120
- currentPosition = 0;
121
119
  currentRow = 0;
122
120
  currentColumn = 0;
121
+ buffer.clear();
123
122
  }
124
123
 
125
124
  }
@@ -4,9 +4,8 @@ import java.util.List;
4
4
 
5
5
  public class TableDefinition
6
6
  {
7
-
8
- public final String tableName;
9
- public final ColumnDefinition[] columns;
7
+ private final String tableName;
8
+ private final ColumnDefinition[] columns;
10
9
 
11
10
 
12
11
  public TableDefinition(String tableName, ColumnDefinition... columns)
@@ -19,4 +18,19 @@ public class TableDefinition
19
18
  {
20
19
  this(tableName, columns.toArray(new ColumnDefinition[columns.size()]));
21
20
  }
21
+
22
+ public String getTableName()
23
+ {
24
+ return tableName;
25
+ }
26
+
27
+ public int getColumnCount()
28
+ {
29
+ return columns.length;
30
+ }
31
+
32
+ public ColumnDefinition getColumn(int index)
33
+ {
34
+ return columns[index];
35
+ }
22
36
  }
@@ -67,7 +67,7 @@ public class OracleOutputPluginTest
67
67
 
68
68
  List<URL> urls = new ArrayList<URL>();
69
69
 
70
- File testRoot = new File(OracleOutputPluginTest.class.getResource("/dummy.txt").toURI()).getParentFile();
70
+ File testRoot = new File(OracleOutputPluginTest.class.getResource("/oracle/").toURI()).getParentFile();
71
71
  String pluginClassName = "org.embulk.output.OracleOutputPlugin";
72
72
  URL pluginClassUrl = OracleOutputPluginTest.class.getResource("/" +pluginClassName.replace('.', '/') + ".class");
73
73
  File root = new File(pluginClassUrl.toURI()).getParentFile().getParentFile().getParentFile().getParentFile();
@@ -135,7 +135,7 @@ public class OracleOutputPluginTest
135
135
  // because the driver returns sqlType=1111 for NCHAR/NVARCHAR2,
136
136
  // and ColumnSetterFactory#newCoalesceColumnSetter throws Exception.
137
137
  // even if setting {value_type: string} for NCHAR/NVARCHAR2,
138
- // PreparedStatement#setNull(parameterIndex, sqlType=1111) throws Exception.
138
+ // PreparedStatement#setNull(parameterIndex, sqlType=1111) throws Exception.
139
139
  invoke(test12c, "testInsert");
140
140
  }
141
141