embulk-output-oracle 0.2.3 → 0.2.4
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 +110 -110
- data/build.gradle +6 -6
- data/classpath/{embulk-output-jdbc-0.2.3.jar → embulk-output-jdbc-0.2.4.jar} +0 -0
- data/classpath/{embulk-output-oracle-0.2.3.jar → embulk-output-oracle-0.2.4.jar} +0 -0
- data/lib/embulk/output/oracle.rb +3 -3
- data/src/main/cpp/common/dir-path-load.cpp +424 -424
- data/src/main/cpp/common/dir-path-load.h +36 -36
- data/src/main/cpp/common/embulk-output-oracle.cpp +196 -196
- data/src/main/cpp/common/org_embulk_output_oracle_oci_OCI.h +77 -77
- data/src/main/cpp/linux/build.sh +21 -21
- data/src/main/cpp/win/build.bat +31 -31
- data/src/main/cpp/win/dllmain.cpp +25 -25
- data/src/main/cpp/win/embulk-output-oracle.sln +39 -39
- data/src/main/cpp/win/embulk-output-oracle.vcxproj +175 -175
- data/src/main/java/org/embulk/output/oracle/DirectBatchInsert.java +289 -289
- data/src/main/java/org/embulk/output/oracle/InsertMethod.java +8 -8
- data/src/main/java/org/embulk/output/oracle/OracleCharset.java +19 -19
- data/src/main/java/org/embulk/output/oracle/OracleOutputConnection.java +134 -134
- data/src/main/java/org/embulk/output/oracle/OracleOutputConnector.java +49 -49
- data/src/main/java/org/embulk/output/oracle/TimestampFormat.java +37 -37
- data/src/main/java/org/embulk/output/oracle/oci/ColumnDefinition.java +26 -26
- data/src/main/java/org/embulk/output/oracle/oci/OCI.java +139 -139
- data/src/main/java/org/embulk/output/oracle/oci/OCIManager.java +64 -64
- data/src/main/java/org/embulk/output/oracle/oci/OCIWrapper.java +96 -96
- data/src/main/java/org/embulk/output/oracle/oci/RowBuffer.java +99 -99
- data/src/main/java/org/embulk/output/oracle/oci/TableDefinition.java +24 -24
- data/src/main/java/org/embulk/output/oracle/setter/OracleColumnSetterFactory.java +31 -31
- data/src/test/cpp/common/embulk-output-oracle-test.cpp +69 -69
- data/src/test/cpp/linux/build.sh +19 -19
- data/src/test/cpp/win/build.bat +28 -28
- data/src/test/cpp/win/embulk-output-oracle-test.vcxproj +154 -154
- data/src/test/java/org/embulk/input/filesplit/LocalFileSplitInputPlugin.java +187 -187
- data/src/test/java/org/embulk/input/filesplit/PartialFile.java +49 -49
- data/src/test/java/org/embulk/input/filesplit/PartialFileInputStream.java +154 -154
- data/src/test/java/org/embulk/output/oracle/ChildFirstClassLoader.java +42 -42
- data/src/test/java/org/embulk/output/oracle/EmbulkPluginTester.java +120 -120
- data/src/test/java/org/embulk/output/oracle/EmptyConfigSource.java +100 -100
- data/src/test/java/org/embulk/output/oracle/OracleOutputPluginTest.java +161 -161
- data/src/test/java/org/embulk/output/oracle/OracleOutputPluginTestImpl.java +413 -413
- data/src/test/java/org/embulk/output/oracle/TimestampFormatTest.java +57 -57
- data/src/test/resources/data/test1/test1.csv +3 -3
- data/src/test/resources/yml/test-insert-direct.yml +26 -26
- data/src/test/resources/yml/test-insert-oci-split.yml +26 -26
- data/src/test/resources/yml/test-insert-oci.yml +26 -26
- data/src/test/resources/yml/test-insert.yml +25 -25
- data/src/test/resources/yml/test-replace-long-name.yml +25 -25
- data/src/test/resources/yml/test-replace.yml +25 -25
- data/src/test/resources/yml/test-url.yml +24 -24
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2a7cad3add47cddbc5128dc4f5d72173f2fe5ad3
|
4
|
+
data.tar.gz: 73a1a3548254ddda090c7261bca4a5ab51bfff54
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ffce5efa888d957bf96d71654afa0abc9952fd04945d5dfc4cb4d10b09faaa55ca2ed0b8c81973330eab4f1f0309bee61f731183d22331d0680abd6a7072bfba
|
7
|
+
data.tar.gz: 9ec7a37715a78d391ba6979103cb3d441a11b95d7ea4bcfcef28f0e6307b237737af41161cce44aea9bd150f6163f7a7eb230231d08e03c0813e716765ea9153
|
data/README.md
CHANGED
@@ -1,110 +1,110 @@
|
|
1
|
-
# Oracle output plugins for Embulk
|
2
|
-
|
3
|
-
Oracle output plugins for Embulk loads records to Oracle.
|
4
|
-
|
5
|
-
## Overview
|
6
|
-
|
7
|
-
* **Plugin type**: output
|
8
|
-
* **Load all or nothing**: depends on the mode:
|
9
|
-
* **insert**: no
|
10
|
-
* **replace**: yes
|
11
|
-
* **Resume supported**: no
|
12
|
-
|
13
|
-
## Configuration
|
14
|
-
|
15
|
-
- **driver_path**: path to the jar file of the Oracle JDBC driver (string)
|
16
|
-
- **host**: database host name (string, required if url is not set or insert_method is "oci")
|
17
|
-
- **port**: database port number (integer, default: 1521)
|
18
|
-
- **user**: database login user name (string, required)
|
19
|
-
- **password**: database login password (string, default: "")
|
20
|
-
- **database**: destination database name (string, required if url is not set or insert_method is "oci")
|
21
|
-
- **url**: URL of the JDBC connection (string, optional)
|
22
|
-
- **table**: destination table name (string, required)
|
23
|
-
- **mode**: "replace" or "insert" (string, required)
|
24
|
-
- **insert_method**: see below
|
25
|
-
- **batch_size**: size of a single batch insert (integer, default: 16777216)
|
26
|
-
- **options**: extra connection properties (hash, default: {})
|
27
|
-
|
28
|
-
insert_method supports three options.
|
29
|
-
|
30
|
-
"normal" means normal insert (default). It requires Oracle JDBC driver.
|
31
|
-
|
32
|
-
"direct" means direct path insert. It is faster than 'normal.
|
33
|
-
It requires Oracle JDBC driver too, but the version 12 driver doesn't work (the version 11 driver works).
|
34
|
-
|
35
|
-
"oci" means direct path insert using OCI(Oracle Call Interface). It is fastest.
|
36
|
-
It requires both Oracle JDBC driver and Oracle Instant Client (version 12.1.0.2.0).
|
37
|
-
You must set the library loading path to the OCI library.
|
38
|
-
|
39
|
-
If you use "oci", platform dependent library written in cpp is required.
|
40
|
-
Windows(x64) library and Linux(x64) are bundled, but others are not bundled.
|
41
|
-
You should build by yourself and set the library loading path to it.
|
42
|
-
|
43
|
-
|
44
|
-
### Example
|
45
|
-
|
46
|
-
```yaml
|
47
|
-
out:
|
48
|
-
type: oracle
|
49
|
-
driver_path: /opt/oracle/ojdbc6.jar
|
50
|
-
host: localhost
|
51
|
-
user: root
|
52
|
-
password: ""
|
53
|
-
database: my_database
|
54
|
-
table: my_table
|
55
|
-
mode: insert
|
56
|
-
insert_method: direct
|
57
|
-
```
|
58
|
-
|
59
|
-
### Build
|
60
|
-
|
61
|
-
```
|
62
|
-
$ ./gradlew gem
|
63
|
-
```
|
64
|
-
|
65
|
-
#### Build environment for native library
|
66
|
-
|
67
|
-
For Windows (x64)
|
68
|
-
|
69
|
-
(1) Install JDK.
|
70
|
-
|
71
|
-
(2) Install Microsoft Visual Studio (only 2010 is tested).
|
72
|
-
|
73
|
-
(3) Install Oracle Instant Client SDK 11.1.0.6.0 for Microsoft Windows (x64).
|
74
|
-
|
75
|
-
(4) Set environment variables.
|
76
|
-
|
77
|
-
* JAVA_HOME
|
78
|
-
* OCI\_SDK_PATH ("sdk" directory of Oracle Instant Client)
|
79
|
-
|
80
|
-
(5) Open src/main/cpp/win/embulk-output-oracle.sln by Visual Studio and build.
|
81
|
-
|
82
|
-
For Windows command line, the following are needed in addition to (1) - (4).
|
83
|
-
|
84
|
-
(6) Set environment variables.
|
85
|
-
|
86
|
-
* MSVC_PATH (ex. C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC)
|
87
|
-
* MSSDK_PATH (ex. C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A)
|
88
|
-
|
89
|
-
(7) Execute src/main/cpp/win/build.bat .
|
90
|
-
|
91
|
-
|
92
|
-
For Linux (x64) (only Ubuntu Server 14.04 is tested)
|
93
|
-
|
94
|
-
(1) Install JDK.
|
95
|
-
|
96
|
-
(2) Install gcc and g++ .
|
97
|
-
|
98
|
-
(3) Install Oracle Instant Client Basic and SDK 11.1.0.6.0 for Linux (x64).
|
99
|
-
|
100
|
-
(4) Create symbolic links of OCI libraries.
|
101
|
-
|
102
|
-
ln -s libocci.so.11.1 libocci.so
|
103
|
-
ln -s libclntsh.so.11.1 libclntsh.so
|
104
|
-
|
105
|
-
(5) Set environment variables.
|
106
|
-
|
107
|
-
* JAVA_HOME
|
108
|
-
* OCI_PATH (the directory of Oracle Instant Client Basic and the parent of the "sdk" directory)
|
109
|
-
|
110
|
-
(6) Execute src/main/cpp/linux/build.sh .
|
1
|
+
# Oracle output plugins for Embulk
|
2
|
+
|
3
|
+
Oracle output plugins for Embulk loads records to Oracle.
|
4
|
+
|
5
|
+
## Overview
|
6
|
+
|
7
|
+
* **Plugin type**: output
|
8
|
+
* **Load all or nothing**: depends on the mode:
|
9
|
+
* **insert**: no
|
10
|
+
* **replace**: yes
|
11
|
+
* **Resume supported**: no
|
12
|
+
|
13
|
+
## Configuration
|
14
|
+
|
15
|
+
- **driver_path**: path to the jar file of the Oracle JDBC driver (string)
|
16
|
+
- **host**: database host name (string, required if url is not set or insert_method is "oci")
|
17
|
+
- **port**: database port number (integer, default: 1521)
|
18
|
+
- **user**: database login user name (string, required)
|
19
|
+
- **password**: database login password (string, default: "")
|
20
|
+
- **database**: destination database name (string, required if url is not set or insert_method is "oci")
|
21
|
+
- **url**: URL of the JDBC connection (string, optional)
|
22
|
+
- **table**: destination table name (string, required)
|
23
|
+
- **mode**: "replace" or "insert" (string, required)
|
24
|
+
- **insert_method**: see below
|
25
|
+
- **batch_size**: size of a single batch insert (integer, default: 16777216)
|
26
|
+
- **options**: extra connection properties (hash, default: {})
|
27
|
+
|
28
|
+
insert_method supports three options.
|
29
|
+
|
30
|
+
"normal" means normal insert (default). It requires Oracle JDBC driver.
|
31
|
+
|
32
|
+
"direct" means direct path insert. It is faster than 'normal.
|
33
|
+
It requires Oracle JDBC driver too, but the version 12 driver doesn't work (the version 11 driver works).
|
34
|
+
|
35
|
+
"oci" means direct path insert using OCI(Oracle Call Interface). It is fastest.
|
36
|
+
It requires both Oracle JDBC driver and Oracle Instant Client (version 12.1.0.2.0).
|
37
|
+
You must set the library loading path to the OCI library.
|
38
|
+
|
39
|
+
If you use "oci", platform dependent library written in cpp is required.
|
40
|
+
Windows(x64) library and Linux(x64) are bundled, but others are not bundled.
|
41
|
+
You should build by yourself and set the library loading path to it.
|
42
|
+
|
43
|
+
|
44
|
+
### Example
|
45
|
+
|
46
|
+
```yaml
|
47
|
+
out:
|
48
|
+
type: oracle
|
49
|
+
driver_path: /opt/oracle/ojdbc6.jar
|
50
|
+
host: localhost
|
51
|
+
user: root
|
52
|
+
password: ""
|
53
|
+
database: my_database
|
54
|
+
table: my_table
|
55
|
+
mode: insert
|
56
|
+
insert_method: direct
|
57
|
+
```
|
58
|
+
|
59
|
+
### Build
|
60
|
+
|
61
|
+
```
|
62
|
+
$ ./gradlew gem
|
63
|
+
```
|
64
|
+
|
65
|
+
#### Build environment for native library
|
66
|
+
|
67
|
+
For Windows (x64)
|
68
|
+
|
69
|
+
(1) Install JDK.
|
70
|
+
|
71
|
+
(2) Install Microsoft Visual Studio (only 2010 is tested).
|
72
|
+
|
73
|
+
(3) Install Oracle Instant Client SDK 11.1.0.6.0 for Microsoft Windows (x64).
|
74
|
+
|
75
|
+
(4) Set environment variables.
|
76
|
+
|
77
|
+
* JAVA_HOME
|
78
|
+
* OCI\_SDK_PATH ("sdk" directory of Oracle Instant Client)
|
79
|
+
|
80
|
+
(5) Open src/main/cpp/win/embulk-output-oracle.sln by Visual Studio and build.
|
81
|
+
|
82
|
+
For Windows command line, the following are needed in addition to (1) - (4).
|
83
|
+
|
84
|
+
(6) Set environment variables.
|
85
|
+
|
86
|
+
* MSVC_PATH (ex. C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC)
|
87
|
+
* MSSDK_PATH (ex. C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A)
|
88
|
+
|
89
|
+
(7) Execute src/main/cpp/win/build.bat .
|
90
|
+
|
91
|
+
|
92
|
+
For Linux (x64) (only Ubuntu Server 14.04 is tested)
|
93
|
+
|
94
|
+
(1) Install JDK.
|
95
|
+
|
96
|
+
(2) Install gcc and g++ .
|
97
|
+
|
98
|
+
(3) Install Oracle Instant Client Basic and SDK 11.1.0.6.0 for Linux (x64).
|
99
|
+
|
100
|
+
(4) Create symbolic links of OCI libraries.
|
101
|
+
|
102
|
+
ln -s libocci.so.11.1 libocci.so
|
103
|
+
ln -s libclntsh.so.11.1 libclntsh.so
|
104
|
+
|
105
|
+
(5) Set environment variables.
|
106
|
+
|
107
|
+
* JAVA_HOME
|
108
|
+
* OCI_PATH (the directory of Oracle Instant Client Basic and the parent of the "sdk" directory)
|
109
|
+
|
110
|
+
(6) Execute src/main/cpp/linux/build.sh .
|
data/build.gradle
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
[compileTestJava]*.options*.encoding = 'UTF-8'
|
2
|
-
|
3
|
-
dependencies {
|
4
|
-
compile project(':embulk-output-jdbc')
|
5
|
-
testCompile 'org.embulk:embulk-standards:0.5.5'
|
6
|
-
}
|
1
|
+
[compileTestJava]*.options*.encoding = 'UTF-8'
|
2
|
+
|
3
|
+
dependencies {
|
4
|
+
compile project(':embulk-output-jdbc')
|
5
|
+
testCompile 'org.embulk:embulk-standards:0.5.5'
|
6
|
+
}
|
Binary file
|
Binary file
|
data/lib/embulk/output/oracle.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
|
-
Embulk::JavaPlugin.register_output(
|
2
|
-
:oracle, "org.embulk.output.OracleOutputPlugin",
|
3
|
-
File.expand_path('../../../../classpath', __FILE__))
|
1
|
+
Embulk::JavaPlugin.register_output(
|
2
|
+
:oracle, "org.embulk.output.OracleOutputPlugin",
|
3
|
+
File.expand_path('../../../../classpath', __FILE__))
|
@@ -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
|
+
}
|