embulk-output-oracle 0.2.4 → 0.3.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 (55) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +155 -110
  3. data/build.gradle +6 -6
  4. data/classpath/embulk-output-jdbc-0.3.0.jar +0 -0
  5. data/classpath/embulk-output-oracle-0.3.0.jar +0 -0
  6. data/lib/embulk/output/oracle.rb +3 -3
  7. data/src/main/cpp/common/dir-path-load.cpp +424 -424
  8. data/src/main/cpp/common/dir-path-load.h +36 -36
  9. data/src/main/cpp/common/embulk-output-oracle.cpp +196 -196
  10. data/src/main/cpp/common/org_embulk_output_oracle_oci_OCI.h +77 -77
  11. data/src/main/cpp/linux/build.sh +21 -21
  12. data/src/main/cpp/win/build.bat +31 -31
  13. data/src/main/cpp/win/dllmain.cpp +25 -25
  14. data/src/main/cpp/win/embulk-output-oracle.sln +39 -39
  15. data/src/main/cpp/win/embulk-output-oracle.vcxproj +175 -175
  16. data/src/main/java/org/embulk/output/OracleOutputPlugin.java +22 -66
  17. data/src/main/java/org/embulk/output/oracle/DirectBatchInsert.java +289 -289
  18. data/src/main/java/org/embulk/output/oracle/InsertMethod.java +8 -8
  19. data/src/main/java/org/embulk/output/oracle/OracleCharset.java +32 -19
  20. data/src/main/java/org/embulk/output/oracle/OracleOutputConnection.java +165 -134
  21. data/src/main/java/org/embulk/output/oracle/OracleOutputConnector.java +49 -49
  22. data/src/main/java/org/embulk/output/oracle/TimestampFormat.java +37 -37
  23. data/src/main/java/org/embulk/output/oracle/oci/ColumnDefinition.java +26 -26
  24. data/src/main/java/org/embulk/output/oracle/oci/OCI.java +139 -139
  25. data/src/main/java/org/embulk/output/oracle/oci/OCIManager.java +64 -64
  26. data/src/main/java/org/embulk/output/oracle/oci/OCIWrapper.java +96 -96
  27. data/src/main/java/org/embulk/output/oracle/oci/RowBuffer.java +99 -99
  28. data/src/main/java/org/embulk/output/oracle/oci/TableDefinition.java +24 -24
  29. data/src/test/cpp/common/embulk-output-oracle-test.cpp +69 -69
  30. data/src/test/cpp/linux/build.sh +19 -19
  31. data/src/test/cpp/win/build.bat +28 -28
  32. data/src/test/cpp/win/embulk-output-oracle-test.vcxproj +154 -154
  33. data/src/test/java/org/embulk/input/filesplit/LocalFileSplitInputPlugin.java +187 -187
  34. data/src/test/java/org/embulk/input/filesplit/PartialFile.java +49 -49
  35. data/src/test/java/org/embulk/input/filesplit/PartialFileInputStream.java +154 -154
  36. data/src/test/java/org/embulk/output/oracle/ChildFirstClassLoader.java +42 -42
  37. data/src/test/java/org/embulk/output/oracle/EmbulkPluginTester.java +120 -120
  38. data/src/test/java/org/embulk/output/oracle/EmptyConfigSource.java +100 -100
  39. data/src/test/java/org/embulk/output/oracle/OracleOutputPluginTest.java +172 -161
  40. data/src/test/java/org/embulk/output/oracle/OracleOutputPluginTestImpl.java +445 -413
  41. data/src/test/java/org/embulk/output/oracle/TimestampFormatTest.java +57 -57
  42. data/src/test/resources/data/test1/test1.csv +3 -3
  43. data/src/test/resources/yml/test-insert-direct.yml +26 -26
  44. data/src/test/resources/yml/test-insert-oci-split.yml +26 -26
  45. data/src/test/resources/yml/test-insert-oci.yml +26 -26
  46. data/src/test/resources/yml/test-insert.yml +25 -25
  47. data/src/test/resources/yml/test-replace-long-name-multibyte.yml +25 -0
  48. data/src/test/resources/yml/test-replace-long-name.yml +25 -25
  49. data/src/test/resources/yml/test-replace.yml +25 -25
  50. data/src/test/resources/yml/test-string-timestamp.yml +25 -0
  51. data/src/test/resources/yml/test-url.yml +24 -24
  52. metadata +6 -5
  53. data/classpath/embulk-output-jdbc-0.2.4.jar +0 -0
  54. data/classpath/embulk-output-oracle-0.2.4.jar +0 -0
  55. data/src/main/java/org/embulk/output/oracle/setter/OracleColumnSetterFactory.java +0 -31
@@ -1,424 +1,424 @@
1
- #include <string.h>
2
- #include <stdio.h>
3
- #include <malloc.h>
4
- #include "dir-path-load.h"
5
-
6
- #pragma warning (disable: 4996)
7
-
8
-
9
- static int check(EMBULK_OUTPUT_ORACLE_OCI_CONTEXT *context, const char* message, sword result)
10
- {
11
- strcpy(context->message, "");
12
-
13
- if (result == OCI_ERROR) {
14
- sprintf(context->message, "OCI : %s failed.", message);
15
- sb4 errCode;
16
- OraText text[512];
17
- if (OCIErrorGet(context->err, 1, NULL, &errCode, text, sizeof(text) / sizeof(OraText), OCI_HTYPE_ERROR) != OCI_SUCCESS) {
18
- strcat(context->message, " OCIErrorGet failed.");
19
- } else {
20
- strcat(context->message, " ");
21
- strncat(context->message, (const char*)text, sizeof(context->message) - strlen(context->message) - 1);
22
- }
23
- return OCI_ERROR;
24
- }
25
-
26
- if (result == OCI_INVALID_HANDLE) {
27
- sprintf(context->message, "OCI : %s failed : invalid handle.", message);
28
- return OCI_ERROR;
29
- }
30
-
31
- if (result == OCI_NO_DATA) {
32
- sprintf(context->message, "OCI : %s failed : no data.", message);
33
- return OCI_ERROR;
34
- }
35
-
36
- if (result != OCI_SUCCESS) {
37
- sprintf(context->message, "OCI : %s failed : %d.", message, result);
38
- return OCI_ERROR;
39
- }
40
-
41
- return OCI_SUCCESS;
42
- }
43
-
44
- void embulk_output_oracle_freeDirPathHandles(EMBULK_OUTPUT_ORACLE_OCI_CONTEXT *context)
45
- {
46
- if (context->csv != NULL) fclose(context->csv);
47
- if (context->buffer != NULL) free(context->buffer);
48
- if (context->dpstr != NULL) OCIHandleFree(context->dpstr, OCI_HTYPE_DIRPATH_STREAM);
49
- if (context->dpca != NULL) OCIHandleFree(context->dpca, OCI_HTYPE_DIRPATH_COLUMN_ARRAY);
50
- if (context->dp != NULL) OCIHandleFree(context->dp, OCI_HTYPE_DIRPATH_CTX);
51
- if (context->svc != NULL) OCIHandleFree(context->svc, OCI_HTYPE_SVCCTX);
52
- if (context->err != NULL) OCIHandleFree(context->err, OCI_HTYPE_ERROR);
53
- if (context->env != NULL) OCIHandleFree(context->env, OCI_HTYPE_ENV);
54
- }
55
-
56
- int embulk_output_oracle_prepareDirPathCtx(EMBULK_OUTPUT_ORACLE_OCI_CONTEXT *context, const char *dbName, const char *userName, const char *password)
57
- {
58
- if (check(context, "OCIEnvCreate", OCIEnvCreate(&context->env,
59
- OCI_THREADED|OCI_OBJECT,
60
- (void *)0,
61
- 0,
62
- 0,
63
- 0,
64
- (size_t)0,
65
- (void **)0))) {
66
- return OCI_ERROR;
67
- }
68
-
69
- // error handle
70
- if (check(context, "OCIHandleAlloc(OCI_HTYPE_ERROR)", OCIHandleAlloc(
71
- context->env,
72
- (void **)&context->err,
73
- OCI_HTYPE_ERROR,
74
- (size_t)0,
75
- (void **)0))) {
76
- return OCI_ERROR;
77
- }
78
-
79
- // service context
80
- if (check(context, "OCIHandleAlloc(OCI_HTYPE_SVCCTX)", OCIHandleAlloc(
81
- context->env,
82
- (void **)&context->svc,
83
- OCI_HTYPE_SVCCTX,
84
- (size_t)0,
85
- (void **)0))) {
86
- return OCI_ERROR;
87
- }
88
-
89
- // logon
90
- if (check(context, "OCILogon", OCILogon(context->env,
91
- context->err,
92
- &context->svc,
93
- (const OraText*)userName,
94
- (ub4)strlen(userName),
95
- (const OraText*)password,
96
- (ub4)strlen(password),
97
- (const OraText*)dbName, // dbName should be defined in 'tnsnames.ora' or a form of "host:port/db"
98
- (ub4)strlen(dbName)))) {
99
- return OCI_ERROR;
100
- }
101
-
102
- // direct path context
103
- if (check(context, "OCIHandleAlloc(OCI_HTYPE_DIRPATH_CTX)", OCIHandleAlloc(
104
- context->env,
105
- (void **)&context->dp,
106
- OCI_HTYPE_DIRPATH_CTX,
107
- (size_t)0,
108
- (void **)0))) {
109
- return OCI_ERROR;
110
- }
111
-
112
- return OCI_SUCCESS;
113
- }
114
-
115
- static int isValid(EMBULK_OUTPUT_ORACLE_OCI_COL_DEF &colDef) {
116
- return colDef.type != 0;
117
- }
118
-
119
- int embulk_output_oracle_prepareDirPathStream(EMBULK_OUTPUT_ORACLE_OCI_CONTEXT *context, const char *tableName, short charsetId, EMBULK_OUTPUT_ORACLE_OCI_COL_DEF *colDefs) {
120
- // load table name
121
- if (check(context, "OCIAttrSet(OCI_ATTR_NAME)", OCIAttrSet(context->dp, OCI_HTYPE_DIRPATH_CTX, (void*)tableName, (ub4)strlen(tableName), OCI_ATTR_NAME, context->err))) {
122
- return OCI_ERROR;
123
- }
124
-
125
- // need to set charset explicitly because database charset is not set by default.
126
- ub2 tempCharsetId = charsetId;
127
- if (check(context, "OCIAttrSet(OCI_ATTR_CHARSET_ID)", OCIAttrSet(context->dp, OCI_HTYPE_DIRPATH_CTX, (void*)&tempCharsetId, sizeof(ub2), OCI_ATTR_CHARSET_ID, context->err))) {
128
- return OCI_ERROR;
129
- }
130
-
131
- ub2 cols;
132
- for (cols = 0; isValid(colDefs[cols]); cols++) ;
133
- if (check(context, "OCIAttrSet(OCI_ATTR_NUM_COLS)", OCIAttrSet(context->dp, OCI_HTYPE_DIRPATH_CTX, &cols, sizeof(ub2), OCI_ATTR_NUM_COLS, context->err))) {
134
- return OCI_ERROR;
135
- }
136
-
137
- OCIParam *columns;
138
- if (check(context, "OCIAttrGet(OCI_ATTR_LIST_COLUMNS)", OCIAttrGet(context->dp, OCI_HTYPE_DIRPATH_CTX, &columns, (ub4*)0, OCI_ATTR_LIST_COLUMNS, context->err))) {
139
- return OCI_ERROR;
140
- }
141
-
142
- for (int i = 0; i < cols; i++) {
143
- EMBULK_OUTPUT_ORACLE_OCI_COL_DEF &colDef = colDefs[i];
144
- OCIParam *column;
145
- if (check(context, "OCIParamGet(OCI_DTYPE_PARAM)", OCIParamGet(columns, OCI_DTYPE_PARAM, context->err, (void**)&column, i + 1))) {
146
- return OCI_ERROR;
147
- }
148
- if (check(context, "OCIAttrSet(OCI_ATTR_NAME)", OCIAttrSet(column, OCI_DTYPE_PARAM, (void*)colDef.name, (ub4)strlen(colDef.name), OCI_ATTR_NAME, context->err))) {
149
- return OCI_ERROR;
150
- }
151
- if (check(context, "OCIAttrSet(OCI_ATTR_DATA_TYPE)", OCIAttrSet(column, OCI_DTYPE_PARAM, &colDef.type, sizeof(ub4), OCI_ATTR_DATA_TYPE, context->err))) {
152
- return OCI_ERROR;
153
- }
154
- if (check(context, "OCIAttrSet(OCI_ATTR_DATA_SIZE)", OCIAttrSet(column, OCI_DTYPE_PARAM, &colDef.size, sizeof(ub4), OCI_ATTR_DATA_SIZE, context->err))) {
155
- return OCI_ERROR;
156
- }
157
- /*
158
- if (check(context, "OCIAttrSet(OCI_ATTR_PRECISION)", OCIAttrSet(column, OCI_DTYPE_PARAM, &colDefs[i].precision, sizeof(ub4), OCI_ATTR_PRECISION, context->err))) {
159
- return OCI_ERROR;
160
- }
161
- if (check(context, "OCIAttrSet(OCI_ATTR_SCALE)", OCIAttrSet(column, OCI_DTYPE_PARAM, &colDefs[i].scale, sizeof(ub4), OCI_ATTR_SCALE, context->err))) {
162
- return OCI_ERROR;
163
- }
164
- */
165
- if (colDef.dateFormat != NULL) {
166
- if (check(context, "OCIAttrSet(OCI_ATTR_DATEFORMAT)", OCIAttrSet(column, OCI_DTYPE_PARAM, (void*)colDef.dateFormat, (ub4)strlen(colDef.dateFormat), OCI_ATTR_DATEFORMAT, context->err))) {
167
- return OCI_ERROR;
168
- }
169
- }
170
-
171
- if (check(context, "OCIDescriptorFree(OCI_DTYPE_PARAM)", OCIDescriptorFree(column, OCI_DTYPE_PARAM))) {
172
- return OCI_ERROR;
173
- }
174
- }
175
-
176
- if (check(context, "OCIDirPathPrepare", OCIDirPathPrepare(context->dp, context->svc, context->err))) {
177
- return OCI_ERROR;
178
- }
179
-
180
- // direct path column array
181
- if (check(context, "OCIHandleAlloc(OCI_HTYPE_DIRPATH_COLUMN_ARRAY)", OCIHandleAlloc(
182
- context->dp,
183
- (void **)&context->dpca,
184
- OCI_HTYPE_DIRPATH_COLUMN_ARRAY,
185
- (size_t)0,
186
- (void **)0))) {
187
- return OCI_ERROR;
188
- }
189
-
190
- // direct path stream
191
- if (check(context, "OCIHandleAlloc(OCI_HTYPE_DIRPATH_STREAM)", OCIHandleAlloc(
192
- context->dp,
193
- (void **)&context->dpstr,
194
- OCI_HTYPE_DIRPATH_STREAM,
195
- (size_t)0,
196
- (void **)0))) {
197
- return OCI_ERROR;
198
- }
199
-
200
- return OCI_SUCCESS;
201
- }
202
-
203
- static void intToSqlInt(int n, char* buffer)
204
- {
205
- buffer[0] = n & 0xFF;
206
- buffer[1] = (n >> 8) & 0xFF;
207
- buffer[2] = (n >> 16) & 0xFF;
208
- buffer[3] = (n >> 24) & 0xFF;
209
- }
210
-
211
- static int strToSqlInt(const char *s, int size, char* buffer)
212
- {
213
- int n = 0;
214
- for (int i = 0; i < size; i++) {
215
- if (s[i] < '0' || s[i] > '9') {
216
- return OCI_ERROR;
217
- }
218
- n = n * 10 + s[i] - '0';
219
- }
220
-
221
- intToSqlInt(n, buffer);
222
-
223
- return OCI_SUCCESS;
224
- }
225
-
226
- static int loadRows(EMBULK_OUTPUT_ORACLE_OCI_CONTEXT *context, ub4 rowCount)
227
- {
228
- for (ub4 offset = 0; offset < rowCount;) {
229
- if (check(context, "OCIDirPathStreamReset", OCIDirPathStreamReset(context->dpstr, context->err))) {
230
- return OCI_ERROR;
231
- }
232
-
233
- sword result = OCIDirPathColArrayToStream(context->dpca, context->dp, context->dpstr, context->err, rowCount, offset);
234
- if (result != OCI_SUCCESS && result != OCI_CONTINUE) {
235
- check(context, "OCIDirPathColArrayToStream", result);
236
- return OCI_ERROR;
237
- }
238
-
239
- if (check(context, "OCIDirPathLoadStream", OCIDirPathLoadStream(context->dp, context->dpstr, context->err))) {
240
- return OCI_ERROR;
241
- }
242
-
243
- if (result == OCI_SUCCESS) {
244
- offset = rowCount;
245
- } else {
246
- ub4 temp;
247
- if (check(context, "OCIAttrGet(OCI_ATTR_ROW_COUNT)", OCIAttrGet(context->dpca, OCI_HTYPE_DIRPATH_COLUMN_ARRAY, &temp, 0, OCI_ATTR_ROW_COUNT, context->err))) {
248
- return OCI_ERROR;
249
- }
250
- offset += temp;
251
- }
252
- }
253
-
254
- return OCI_SUCCESS;
255
- }
256
-
257
-
258
- int embulk_output_oracle_loadBuffer(EMBULK_OUTPUT_ORACLE_OCI_CONTEXT *context, EMBULK_OUTPUT_ORACLE_OCI_COL_DEF *colDefs, const char *buffer, int rowCount)
259
- {
260
- ub4 maxRowCount = 0;
261
- if (check(context, "OCIAttrGet(OCI_ATTR_NUM_ROWS)", OCIAttrGet(context->dpca, OCI_HTYPE_DIRPATH_COLUMN_ARRAY, &maxRowCount, 0, OCI_ATTR_NUM_ROWS, context->err))) {
262
- return OCI_ERROR;
263
- }
264
-
265
- int rowSize = 0;
266
- for (int col = 0; isValid(colDefs[col]); col++) {
267
- rowSize += colDefs[col].size;
268
- }
269
- const char *current = buffer;
270
-
271
- int colArrayRowCount = 0;
272
- for (int row = 0; row < rowCount; row++) {
273
- for (int col = 0; isValid(colDefs[col]); col++) {
274
- ub4 size = colDefs[col].size;
275
- if (colDefs[col].type == SQLT_CHR) {
276
- size = (ub4)strnlen(current, size);
277
- }
278
-
279
- if (check(context, "OCIDirPathColArrayEntrySet", OCIDirPathColArrayEntrySet(context->dpca, context->err, colArrayRowCount, col, (ub1*)current, size, OCI_DIRPATH_COL_COMPLETE))) {
280
- return OCI_ERROR;
281
- }
282
- current += colDefs[col].size;
283
- }
284
-
285
- colArrayRowCount++;
286
- if (colArrayRowCount == maxRowCount) {
287
- if (loadRows(context, colArrayRowCount)) {
288
- return OCI_ERROR;
289
- }
290
-
291
- colArrayRowCount = 0;
292
- }
293
- }
294
-
295
- if (colArrayRowCount > 0) {
296
- if (loadRows(context, colArrayRowCount)) {
297
- return OCI_ERROR;
298
- }
299
- }
300
-
301
- return OCI_SUCCESS;
302
- }
303
-
304
-
305
- int embulk_output_oracle_loadCSV(EMBULK_OUTPUT_ORACLE_OCI_CONTEXT *context, EMBULK_OUTPUT_ORACLE_OCI_COL_DEF *colDefs, const char *csvFileName)
306
- {
307
- printf("load csv file \"%s\".\r\n", csvFileName);
308
- if ((context->csv = fopen(csvFileName, "r")) == NULL) {
309
- printf("Cannot open file.");
310
- return OCI_ERROR;
311
- }
312
-
313
- ub4 maxRowCount = 0;
314
- if (check(context, "OCIAttrGet(OCI_ATTR_NUM_ROWS)", OCIAttrGet(context->dpca, OCI_HTYPE_DIRPATH_COLUMN_ARRAY, &maxRowCount, 0, OCI_ATTR_NUM_ROWS, context->err))) {
315
- return OCI_ERROR;
316
- }
317
-
318
- int rowSize = 0;
319
- for (int i = 0; isValid(colDefs[i]); i++) {
320
- rowSize += colDefs[i].size;
321
- }
322
-
323
- // + 1 for '\0'
324
- if ((context->buffer = (char*)malloc(rowSize * maxRowCount + 1)) == NULL) {
325
- printf("Cannot alloc memory.");
326
- return OCI_ERROR;
327
- }
328
- char *current = context->buffer;
329
-
330
- // TODO: support a line over 1,000 bytes
331
- char line[1000];
332
- int row = 0;
333
- while (fgets(line, sizeof(line), context->csv) != NULL) {
334
- size_t len = strlen(line);
335
- int col = 0;
336
- for (const char *p = line; p < line + len;) {
337
- const char *comma = strchr(p, ',');
338
- const char *next;
339
- ub4 size;
340
- if (comma != NULL) {
341
- size = (ub4)(comma - p);
342
- next = comma + 1;
343
- } else {
344
- size = (ub4)(line + len - p);
345
- if (size > 0 && p[size - 1] == '\n') size--;
346
- if (size > 0 && p[size - 1] == '\r') size--;
347
- next = line + len;
348
- }
349
-
350
- if (colDefs[col].type == SQLT_INT) {
351
- if (strToSqlInt(p, size, current)) {
352
- printf("Not a number : \"%s\"\r\n", p);
353
- return OCI_ERROR;
354
- }
355
- size = colDefs[col].size;
356
- } else if (colDefs[col].type == SQLT_CHR) {
357
- strncpy(current, p, size);
358
- } else {
359
- printf("Unsupported type : %d\r\n", colDefs[col].type);
360
- return OCI_ERROR;
361
- }
362
-
363
- if (check(context, "OCIDirPathColArrayEntrySet", OCIDirPathColArrayEntrySet(context->dpca, context->err, row, col, (ub1*)current, size, OCI_DIRPATH_COL_COMPLETE))) {
364
- return OCI_ERROR;
365
- }
366
-
367
- p = next;
368
- current += size;
369
- col++;
370
- }
371
-
372
- row++;
373
- if (row == maxRowCount) {
374
- printf("Load %d rows.\r\n", row);
375
- if (loadRows(context, row)) {
376
- return OCI_ERROR;
377
- }
378
-
379
- current = context->buffer;
380
- row = 0;
381
- }
382
- }
383
-
384
- if (row > 0) {
385
- printf("Load %d rows.\r\n", row);
386
- if (loadRows(context, row)) {
387
- return OCI_ERROR;
388
- }
389
- }
390
-
391
- free(context->buffer);
392
- context->buffer = NULL;
393
-
394
- fclose(context->csv);
395
- context->csv = NULL;
396
-
397
- return OCI_SUCCESS;
398
- }
399
-
400
- int embulk_output_oracle_commitDirPath(EMBULK_OUTPUT_ORACLE_OCI_CONTEXT *context)
401
- {
402
- if (check(context, "OCIDirPathFinish", OCIDirPathFinish(context->dp, context->err))) {
403
- return OCI_ERROR;
404
- }
405
-
406
- if (check(context, "OCILogoff", OCILogoff(context->svc, context->err))) {
407
- return OCI_ERROR;
408
- }
409
-
410
- return OCI_SUCCESS;
411
- }
412
-
413
- int embulk_output_oracle_rollbackDirPath(EMBULK_OUTPUT_ORACLE_OCI_CONTEXT *context)
414
- {
415
- if (check(context, "OCIDirPathAbort", OCIDirPathAbort(context->dp, context->err))) {
416
- return OCI_ERROR;
417
- }
418
-
419
- if (check(context, "OCILogoff", OCILogoff(context->svc, context->err))) {
420
- return OCI_ERROR;
421
- }
422
-
423
- return OCI_SUCCESS;
424
- }
1
+ #include <string.h>
2
+ #include <stdio.h>
3
+ #include <malloc.h>
4
+ #include "dir-path-load.h"
5
+
6
+ #pragma warning (disable: 4996)
7
+
8
+
9
+ static int check(EMBULK_OUTPUT_ORACLE_OCI_CONTEXT *context, const char* message, sword result)
10
+ {
11
+ strcpy(context->message, "");
12
+
13
+ if (result == OCI_ERROR) {
14
+ sprintf(context->message, "OCI : %s failed.", message);
15
+ sb4 errCode;
16
+ OraText text[512];
17
+ if (OCIErrorGet(context->err, 1, NULL, &errCode, text, sizeof(text) / sizeof(OraText), OCI_HTYPE_ERROR) != OCI_SUCCESS) {
18
+ strcat(context->message, " OCIErrorGet failed.");
19
+ } else {
20
+ strcat(context->message, " ");
21
+ strncat(context->message, (const char*)text, sizeof(context->message) - strlen(context->message) - 1);
22
+ }
23
+ return OCI_ERROR;
24
+ }
25
+
26
+ if (result == OCI_INVALID_HANDLE) {
27
+ sprintf(context->message, "OCI : %s failed : invalid handle.", message);
28
+ return OCI_ERROR;
29
+ }
30
+
31
+ if (result == OCI_NO_DATA) {
32
+ sprintf(context->message, "OCI : %s failed : no data.", message);
33
+ return OCI_ERROR;
34
+ }
35
+
36
+ if (result != OCI_SUCCESS) {
37
+ sprintf(context->message, "OCI : %s failed : %d.", message, result);
38
+ return OCI_ERROR;
39
+ }
40
+
41
+ return OCI_SUCCESS;
42
+ }
43
+
44
+ void embulk_output_oracle_freeDirPathHandles(EMBULK_OUTPUT_ORACLE_OCI_CONTEXT *context)
45
+ {
46
+ if (context->csv != NULL) fclose(context->csv);
47
+ if (context->buffer != NULL) free(context->buffer);
48
+ if (context->dpstr != NULL) OCIHandleFree(context->dpstr, OCI_HTYPE_DIRPATH_STREAM);
49
+ if (context->dpca != NULL) OCIHandleFree(context->dpca, OCI_HTYPE_DIRPATH_COLUMN_ARRAY);
50
+ if (context->dp != NULL) OCIHandleFree(context->dp, OCI_HTYPE_DIRPATH_CTX);
51
+ if (context->svc != NULL) OCIHandleFree(context->svc, OCI_HTYPE_SVCCTX);
52
+ if (context->err != NULL) OCIHandleFree(context->err, OCI_HTYPE_ERROR);
53
+ if (context->env != NULL) OCIHandleFree(context->env, OCI_HTYPE_ENV);
54
+ }
55
+
56
+ int embulk_output_oracle_prepareDirPathCtx(EMBULK_OUTPUT_ORACLE_OCI_CONTEXT *context, const char *dbName, const char *userName, const char *password)
57
+ {
58
+ if (check(context, "OCIEnvCreate", OCIEnvCreate(&context->env,
59
+ OCI_THREADED|OCI_OBJECT,
60
+ (void *)0,
61
+ 0,
62
+ 0,
63
+ 0,
64
+ (size_t)0,
65
+ (void **)0))) {
66
+ return OCI_ERROR;
67
+ }
68
+
69
+ // error handle
70
+ if (check(context, "OCIHandleAlloc(OCI_HTYPE_ERROR)", OCIHandleAlloc(
71
+ context->env,
72
+ (void **)&context->err,
73
+ OCI_HTYPE_ERROR,
74
+ (size_t)0,
75
+ (void **)0))) {
76
+ return OCI_ERROR;
77
+ }
78
+
79
+ // service context
80
+ if (check(context, "OCIHandleAlloc(OCI_HTYPE_SVCCTX)", OCIHandleAlloc(
81
+ context->env,
82
+ (void **)&context->svc,
83
+ OCI_HTYPE_SVCCTX,
84
+ (size_t)0,
85
+ (void **)0))) {
86
+ return OCI_ERROR;
87
+ }
88
+
89
+ // logon
90
+ if (check(context, "OCILogon", OCILogon(context->env,
91
+ context->err,
92
+ &context->svc,
93
+ (const OraText*)userName,
94
+ (ub4)strlen(userName),
95
+ (const OraText*)password,
96
+ (ub4)strlen(password),
97
+ (const OraText*)dbName, // dbName should be defined in 'tnsnames.ora' or a form of "host:port/db"
98
+ (ub4)strlen(dbName)))) {
99
+ return OCI_ERROR;
100
+ }
101
+
102
+ // direct path context
103
+ if (check(context, "OCIHandleAlloc(OCI_HTYPE_DIRPATH_CTX)", OCIHandleAlloc(
104
+ context->env,
105
+ (void **)&context->dp,
106
+ OCI_HTYPE_DIRPATH_CTX,
107
+ (size_t)0,
108
+ (void **)0))) {
109
+ return OCI_ERROR;
110
+ }
111
+
112
+ return OCI_SUCCESS;
113
+ }
114
+
115
+ static int isValid(EMBULK_OUTPUT_ORACLE_OCI_COL_DEF &colDef) {
116
+ return colDef.type != 0;
117
+ }
118
+
119
+ int embulk_output_oracle_prepareDirPathStream(EMBULK_OUTPUT_ORACLE_OCI_CONTEXT *context, const char *tableName, short charsetId, EMBULK_OUTPUT_ORACLE_OCI_COL_DEF *colDefs) {
120
+ // load table name
121
+ if (check(context, "OCIAttrSet(OCI_ATTR_NAME)", OCIAttrSet(context->dp, OCI_HTYPE_DIRPATH_CTX, (void*)tableName, (ub4)strlen(tableName), OCI_ATTR_NAME, context->err))) {
122
+ return OCI_ERROR;
123
+ }
124
+
125
+ // need to set charset explicitly because database charset is not set by default.
126
+ ub2 tempCharsetId = charsetId;
127
+ if (check(context, "OCIAttrSet(OCI_ATTR_CHARSET_ID)", OCIAttrSet(context->dp, OCI_HTYPE_DIRPATH_CTX, (void*)&tempCharsetId, sizeof(ub2), OCI_ATTR_CHARSET_ID, context->err))) {
128
+ return OCI_ERROR;
129
+ }
130
+
131
+ ub2 cols;
132
+ for (cols = 0; isValid(colDefs[cols]); cols++) ;
133
+ if (check(context, "OCIAttrSet(OCI_ATTR_NUM_COLS)", OCIAttrSet(context->dp, OCI_HTYPE_DIRPATH_CTX, &cols, sizeof(ub2), OCI_ATTR_NUM_COLS, context->err))) {
134
+ return OCI_ERROR;
135
+ }
136
+
137
+ OCIParam *columns;
138
+ if (check(context, "OCIAttrGet(OCI_ATTR_LIST_COLUMNS)", OCIAttrGet(context->dp, OCI_HTYPE_DIRPATH_CTX, &columns, (ub4*)0, OCI_ATTR_LIST_COLUMNS, context->err))) {
139
+ return OCI_ERROR;
140
+ }
141
+
142
+ for (int i = 0; i < cols; i++) {
143
+ EMBULK_OUTPUT_ORACLE_OCI_COL_DEF &colDef = colDefs[i];
144
+ OCIParam *column;
145
+ if (check(context, "OCIParamGet(OCI_DTYPE_PARAM)", OCIParamGet(columns, OCI_DTYPE_PARAM, context->err, (void**)&column, i + 1))) {
146
+ return OCI_ERROR;
147
+ }
148
+ if (check(context, "OCIAttrSet(OCI_ATTR_NAME)", OCIAttrSet(column, OCI_DTYPE_PARAM, (void*)colDef.name, (ub4)strlen(colDef.name), OCI_ATTR_NAME, context->err))) {
149
+ return OCI_ERROR;
150
+ }
151
+ if (check(context, "OCIAttrSet(OCI_ATTR_DATA_TYPE)", OCIAttrSet(column, OCI_DTYPE_PARAM, &colDef.type, sizeof(ub4), OCI_ATTR_DATA_TYPE, context->err))) {
152
+ return OCI_ERROR;
153
+ }
154
+ if (check(context, "OCIAttrSet(OCI_ATTR_DATA_SIZE)", OCIAttrSet(column, OCI_DTYPE_PARAM, &colDef.size, sizeof(ub4), OCI_ATTR_DATA_SIZE, context->err))) {
155
+ return OCI_ERROR;
156
+ }
157
+ /*
158
+ if (check(context, "OCIAttrSet(OCI_ATTR_PRECISION)", OCIAttrSet(column, OCI_DTYPE_PARAM, &colDefs[i].precision, sizeof(ub4), OCI_ATTR_PRECISION, context->err))) {
159
+ return OCI_ERROR;
160
+ }
161
+ if (check(context, "OCIAttrSet(OCI_ATTR_SCALE)", OCIAttrSet(column, OCI_DTYPE_PARAM, &colDefs[i].scale, sizeof(ub4), OCI_ATTR_SCALE, context->err))) {
162
+ return OCI_ERROR;
163
+ }
164
+ */
165
+ if (colDef.dateFormat != NULL) {
166
+ if (check(context, "OCIAttrSet(OCI_ATTR_DATEFORMAT)", OCIAttrSet(column, OCI_DTYPE_PARAM, (void*)colDef.dateFormat, (ub4)strlen(colDef.dateFormat), OCI_ATTR_DATEFORMAT, context->err))) {
167
+ return OCI_ERROR;
168
+ }
169
+ }
170
+
171
+ if (check(context, "OCIDescriptorFree(OCI_DTYPE_PARAM)", OCIDescriptorFree(column, OCI_DTYPE_PARAM))) {
172
+ return OCI_ERROR;
173
+ }
174
+ }
175
+
176
+ if (check(context, "OCIDirPathPrepare", OCIDirPathPrepare(context->dp, context->svc, context->err))) {
177
+ return OCI_ERROR;
178
+ }
179
+
180
+ // direct path column array
181
+ if (check(context, "OCIHandleAlloc(OCI_HTYPE_DIRPATH_COLUMN_ARRAY)", OCIHandleAlloc(
182
+ context->dp,
183
+ (void **)&context->dpca,
184
+ OCI_HTYPE_DIRPATH_COLUMN_ARRAY,
185
+ (size_t)0,
186
+ (void **)0))) {
187
+ return OCI_ERROR;
188
+ }
189
+
190
+ // direct path stream
191
+ if (check(context, "OCIHandleAlloc(OCI_HTYPE_DIRPATH_STREAM)", OCIHandleAlloc(
192
+ context->dp,
193
+ (void **)&context->dpstr,
194
+ OCI_HTYPE_DIRPATH_STREAM,
195
+ (size_t)0,
196
+ (void **)0))) {
197
+ return OCI_ERROR;
198
+ }
199
+
200
+ return OCI_SUCCESS;
201
+ }
202
+
203
+ static void intToSqlInt(int n, char* buffer)
204
+ {
205
+ buffer[0] = n & 0xFF;
206
+ buffer[1] = (n >> 8) & 0xFF;
207
+ buffer[2] = (n >> 16) & 0xFF;
208
+ buffer[3] = (n >> 24) & 0xFF;
209
+ }
210
+
211
+ static int strToSqlInt(const char *s, int size, char* buffer)
212
+ {
213
+ int n = 0;
214
+ for (int i = 0; i < size; i++) {
215
+ if (s[i] < '0' || s[i] > '9') {
216
+ return OCI_ERROR;
217
+ }
218
+ n = n * 10 + s[i] - '0';
219
+ }
220
+
221
+ intToSqlInt(n, buffer);
222
+
223
+ return OCI_SUCCESS;
224
+ }
225
+
226
+ static int loadRows(EMBULK_OUTPUT_ORACLE_OCI_CONTEXT *context, ub4 rowCount)
227
+ {
228
+ for (ub4 offset = 0; offset < rowCount;) {
229
+ if (check(context, "OCIDirPathStreamReset", OCIDirPathStreamReset(context->dpstr, context->err))) {
230
+ return OCI_ERROR;
231
+ }
232
+
233
+ sword result = OCIDirPathColArrayToStream(context->dpca, context->dp, context->dpstr, context->err, rowCount, offset);
234
+ if (result != OCI_SUCCESS && result != OCI_CONTINUE) {
235
+ check(context, "OCIDirPathColArrayToStream", result);
236
+ return OCI_ERROR;
237
+ }
238
+
239
+ if (check(context, "OCIDirPathLoadStream", OCIDirPathLoadStream(context->dp, context->dpstr, context->err))) {
240
+ return OCI_ERROR;
241
+ }
242
+
243
+ if (result == OCI_SUCCESS) {
244
+ offset = rowCount;
245
+ } else {
246
+ ub4 temp;
247
+ if (check(context, "OCIAttrGet(OCI_ATTR_ROW_COUNT)", OCIAttrGet(context->dpca, OCI_HTYPE_DIRPATH_COLUMN_ARRAY, &temp, 0, OCI_ATTR_ROW_COUNT, context->err))) {
248
+ return OCI_ERROR;
249
+ }
250
+ offset += temp;
251
+ }
252
+ }
253
+
254
+ return OCI_SUCCESS;
255
+ }
256
+
257
+
258
+ int embulk_output_oracle_loadBuffer(EMBULK_OUTPUT_ORACLE_OCI_CONTEXT *context, EMBULK_OUTPUT_ORACLE_OCI_COL_DEF *colDefs, const char *buffer, int rowCount)
259
+ {
260
+ ub4 maxRowCount = 0;
261
+ if (check(context, "OCIAttrGet(OCI_ATTR_NUM_ROWS)", OCIAttrGet(context->dpca, OCI_HTYPE_DIRPATH_COLUMN_ARRAY, &maxRowCount, 0, OCI_ATTR_NUM_ROWS, context->err))) {
262
+ return OCI_ERROR;
263
+ }
264
+
265
+ int rowSize = 0;
266
+ for (int col = 0; isValid(colDefs[col]); col++) {
267
+ rowSize += colDefs[col].size;
268
+ }
269
+ const char *current = buffer;
270
+
271
+ int colArrayRowCount = 0;
272
+ for (int row = 0; row < rowCount; row++) {
273
+ for (int col = 0; isValid(colDefs[col]); col++) {
274
+ ub4 size = colDefs[col].size;
275
+ if (colDefs[col].type == SQLT_CHR) {
276
+ size = (ub4)strnlen(current, size);
277
+ }
278
+
279
+ if (check(context, "OCIDirPathColArrayEntrySet", OCIDirPathColArrayEntrySet(context->dpca, context->err, colArrayRowCount, col, (ub1*)current, size, OCI_DIRPATH_COL_COMPLETE))) {
280
+ return OCI_ERROR;
281
+ }
282
+ current += colDefs[col].size;
283
+ }
284
+
285
+ colArrayRowCount++;
286
+ if (colArrayRowCount == maxRowCount) {
287
+ if (loadRows(context, colArrayRowCount)) {
288
+ return OCI_ERROR;
289
+ }
290
+
291
+ colArrayRowCount = 0;
292
+ }
293
+ }
294
+
295
+ if (colArrayRowCount > 0) {
296
+ if (loadRows(context, colArrayRowCount)) {
297
+ return OCI_ERROR;
298
+ }
299
+ }
300
+
301
+ return OCI_SUCCESS;
302
+ }
303
+
304
+
305
+ int embulk_output_oracle_loadCSV(EMBULK_OUTPUT_ORACLE_OCI_CONTEXT *context, EMBULK_OUTPUT_ORACLE_OCI_COL_DEF *colDefs, const char *csvFileName)
306
+ {
307
+ printf("load csv file \"%s\".\r\n", csvFileName);
308
+ if ((context->csv = fopen(csvFileName, "r")) == NULL) {
309
+ printf("Cannot open file.");
310
+ return OCI_ERROR;
311
+ }
312
+
313
+ ub4 maxRowCount = 0;
314
+ if (check(context, "OCIAttrGet(OCI_ATTR_NUM_ROWS)", OCIAttrGet(context->dpca, OCI_HTYPE_DIRPATH_COLUMN_ARRAY, &maxRowCount, 0, OCI_ATTR_NUM_ROWS, context->err))) {
315
+ return OCI_ERROR;
316
+ }
317
+
318
+ int rowSize = 0;
319
+ for (int i = 0; isValid(colDefs[i]); i++) {
320
+ rowSize += colDefs[i].size;
321
+ }
322
+
323
+ // + 1 for '\0'
324
+ if ((context->buffer = (char*)malloc(rowSize * maxRowCount + 1)) == NULL) {
325
+ printf("Cannot alloc memory.");
326
+ return OCI_ERROR;
327
+ }
328
+ char *current = context->buffer;
329
+
330
+ // TODO: support a line over 1,000 bytes
331
+ char line[1000];
332
+ int row = 0;
333
+ while (fgets(line, sizeof(line), context->csv) != NULL) {
334
+ size_t len = strlen(line);
335
+ int col = 0;
336
+ for (const char *p = line; p < line + len;) {
337
+ const char *comma = strchr(p, ',');
338
+ const char *next;
339
+ ub4 size;
340
+ if (comma != NULL) {
341
+ size = (ub4)(comma - p);
342
+ next = comma + 1;
343
+ } else {
344
+ size = (ub4)(line + len - p);
345
+ if (size > 0 && p[size - 1] == '\n') size--;
346
+ if (size > 0 && p[size - 1] == '\r') size--;
347
+ next = line + len;
348
+ }
349
+
350
+ if (colDefs[col].type == SQLT_INT) {
351
+ if (strToSqlInt(p, size, current)) {
352
+ printf("Not a number : \"%s\"\r\n", p);
353
+ return OCI_ERROR;
354
+ }
355
+ size = colDefs[col].size;
356
+ } else if (colDefs[col].type == SQLT_CHR) {
357
+ strncpy(current, p, size);
358
+ } else {
359
+ printf("Unsupported type : %d\r\n", colDefs[col].type);
360
+ return OCI_ERROR;
361
+ }
362
+
363
+ if (check(context, "OCIDirPathColArrayEntrySet", OCIDirPathColArrayEntrySet(context->dpca, context->err, row, col, (ub1*)current, size, OCI_DIRPATH_COL_COMPLETE))) {
364
+ return OCI_ERROR;
365
+ }
366
+
367
+ p = next;
368
+ current += size;
369
+ col++;
370
+ }
371
+
372
+ row++;
373
+ if (row == maxRowCount) {
374
+ printf("Load %d rows.\r\n", row);
375
+ if (loadRows(context, row)) {
376
+ return OCI_ERROR;
377
+ }
378
+
379
+ current = context->buffer;
380
+ row = 0;
381
+ }
382
+ }
383
+
384
+ if (row > 0) {
385
+ printf("Load %d rows.\r\n", row);
386
+ if (loadRows(context, row)) {
387
+ return OCI_ERROR;
388
+ }
389
+ }
390
+
391
+ free(context->buffer);
392
+ context->buffer = NULL;
393
+
394
+ fclose(context->csv);
395
+ context->csv = NULL;
396
+
397
+ return OCI_SUCCESS;
398
+ }
399
+
400
+ int embulk_output_oracle_commitDirPath(EMBULK_OUTPUT_ORACLE_OCI_CONTEXT *context)
401
+ {
402
+ if (check(context, "OCIDirPathFinish", OCIDirPathFinish(context->dp, context->err))) {
403
+ return OCI_ERROR;
404
+ }
405
+
406
+ if (check(context, "OCILogoff", OCILogoff(context->svc, context->err))) {
407
+ return OCI_ERROR;
408
+ }
409
+
410
+ return OCI_SUCCESS;
411
+ }
412
+
413
+ int embulk_output_oracle_rollbackDirPath(EMBULK_OUTPUT_ORACLE_OCI_CONTEXT *context)
414
+ {
415
+ if (check(context, "OCIDirPathAbort", OCIDirPathAbort(context->dp, context->err))) {
416
+ return OCI_ERROR;
417
+ }
418
+
419
+ if (check(context, "OCILogoff", OCILogoff(context->svc, context->err))) {
420
+ return OCI_ERROR;
421
+ }
422
+
423
+ return OCI_SUCCESS;
424
+ }