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.
- checksums.yaml +4 -4
- data/README.md +0 -50
- data/build.gradle +1 -0
- data/classpath/embulk-output-jdbc-0.5.0.jar +0 -0
- data/classpath/embulk-output-oracle-0.5.0.jar +0 -0
- data/src/main/java/org/embulk/output/oracle/DirectBatchInsert.java +16 -14
- data/src/main/java/org/embulk/output/oracle/OracleOutputConnection.java +5 -5
- data/src/main/java/org/embulk/output/oracle/oci/ColumnDefinition.java +39 -15
- data/src/main/java/org/embulk/output/oracle/oci/OCI.java +125 -133
- data/src/main/java/org/embulk/output/oracle/oci/OCIWrapper.java +403 -33
- data/src/main/java/org/embulk/output/oracle/oci/RowBuffer.java +39 -40
- data/src/main/java/org/embulk/output/oracle/oci/TableDefinition.java +17 -3
- data/src/test/java/org/embulk/output/oracle/OracleOutputPluginTest.java +2 -2
- data/src/test/java/org/embulk/output/oracle/OracleOutputPluginTestImpl.java +38 -143
- data/src/test/resources/{data → oracle/data}/test1/test1.csv +0 -0
- data/src/test/resources/{yml → oracle/yml}/test-insert-direct-direct-method.yml +1 -1
- data/src/test/resources/{yml → oracle/yml}/test-insert-direct-empty.yml +1 -1
- data/src/test/resources/{yml → oracle/yml}/test-insert-direct-oci-method-split.yml +1 -1
- data/src/test/resources/{yml → oracle/yml}/test-insert-direct-oci-method.yml +1 -1
- data/src/test/resources/{yml → oracle/yml}/test-insert-direct.yml +1 -1
- data/src/test/resources/{yml → oracle/yml}/test-insert-empty.yml +1 -1
- data/src/test/resources/{yml → oracle/yml}/test-insert.yml +1 -1
- data/src/test/resources/{yml → oracle/yml}/test-replace-empty.yml +1 -1
- data/src/test/resources/{yml → oracle/yml}/test-replace-long-name-multibyte.yml +1 -1
- data/src/test/resources/{yml → oracle/yml}/test-replace-long-name.yml +1 -1
- data/src/test/resources/{yml → oracle/yml}/test-replace-oci-method.yml +1 -1
- data/src/test/resources/{yml → oracle/yml}/test-replace.yml +1 -1
- data/src/test/resources/{yml → oracle/yml}/test-string-timestamp.yml +1 -1
- data/src/test/resources/{yml → oracle/yml}/test-truncate-insert-oci-method.yml +1 -1
- data/src/test/resources/{yml → oracle/yml}/test-truncate-insert.yml +1 -1
- data/src/test/resources/{yml → oracle/yml}/test-url.yml +1 -1
- metadata +21 -38
- data/classpath/embulk-output-jdbc-0.4.5.jar +0 -0
- data/classpath/embulk-output-oracle-0.4.5.jar +0 -0
- data/lib/embulk/linux_x64/libembulk-output-oracle.so +0 -0
- data/lib/embulk/win_x64/embulk-output-oracle.dll +0 -0
- data/src/main/cpp/common/dir-path-load.cpp +0 -425
- data/src/main/cpp/common/dir-path-load.h +0 -37
- data/src/main/cpp/common/embulk-output-oracle.cpp +0 -195
- data/src/main/cpp/common/org_embulk_output_oracle_oci_OCI.h +0 -77
- data/src/main/cpp/linux/build.sh +0 -21
- data/src/main/cpp/win/build.bat +0 -32
- data/src/main/cpp/win/dllmain.cpp +0 -25
- data/src/main/cpp/win/embulk-output-oracle.sln +0 -39
- data/src/main/cpp/win/embulk-output-oracle.vcxproj +0 -176
- data/src/test/cpp/common/embulk-output-oracle-test.cpp +0 -69
- data/src/test/cpp/linux/build.sh +0 -19
- data/src/test/cpp/win/build.bat +0 -29
- data/src/test/cpp/win/embulk-output-oracle-test.vcxproj +0 -155
- data/src/test/java/org/embulk/output/tester/EmbulkPluginTester.java +0 -79
- 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
|
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
|
15
|
-
|
16
|
-
private
|
17
|
-
private
|
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
|
-
|
26
|
-
|
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
|
-
|
52
|
+
private OCI loadLibrary()
|
30
53
|
{
|
31
|
-
|
32
|
-
|
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
|
-
|
39
|
-
|
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
|
-
|
300
|
+
private void loadRows(int rowCount) throws SQLException
|
44
301
|
{
|
45
|
-
|
46
|
-
|
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
|
-
|
55
|
-
|
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
|
-
|
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 (
|
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
|
-
|
91
|
-
|
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
|
-
|
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
|
-
|
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 (
|
27
|
-
|
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
|
-
|
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
|
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 >
|
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
|
-
|
78
|
+
column.getColumnName(), column.getDataSize(), length));
|
70
79
|
}
|
71
80
|
|
72
|
-
buffer
|
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
|
-
|
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.
|
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
|
-
|
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("/
|
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
|
-
|
138
|
+
// PreparedStatement#setNull(parameterIndex, sqlType=1111) throws Exception.
|
139
139
|
invoke(test12c, "testInsert");
|
140
140
|
}
|
141
141
|
|