@zowe/db2-for-zowe-cli 6.1.17 → 6.1.18
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.
- package/README.md +12 -10
- package/lib/Db2PluginLifeCycle.d.ts +11 -9
- package/lib/Db2PluginLifeCycle.js +18 -13
- package/lib/Db2PluginLifeCycle.js.map +1 -1
- package/node_modules/axios/CHANGELOG.md +62 -0
- package/node_modules/axios/README.md +233 -5
- package/node_modules/axios/dist/axios.js +387 -89
- package/node_modules/axios/dist/axios.min.js +3 -3
- package/node_modules/axios/dist/axios.min.js.map +1 -1
- package/node_modules/axios/dist/browser/axios.cjs +458 -98
- package/node_modules/axios/dist/esm/axios.js +458 -98
- package/node_modules/axios/dist/esm/axios.min.js +2 -2
- package/node_modules/axios/dist/esm/axios.min.js.map +1 -1
- package/node_modules/axios/dist/node/axios.cjs +568 -116
- package/node_modules/axios/index.d.cts +4 -0
- package/node_modules/axios/index.d.ts +4 -0
- package/node_modules/axios/lib/adapters/fetch.js +64 -11
- package/node_modules/axios/lib/adapters/http.js +134 -50
- package/node_modules/axios/lib/adapters/xhr.js +52 -3
- package/node_modules/axios/lib/core/Axios.js +19 -14
- package/node_modules/axios/lib/core/InterceptorManager.js +107 -8
- package/node_modules/axios/lib/core/buildFullPath.js +1 -13
- package/node_modules/axios/lib/core/dispatchRequest.js +8 -2
- package/node_modules/axios/lib/core/mergeConfig.js +1 -1
- package/node_modules/axios/lib/core/methodList.js +17 -0
- package/node_modules/axios/lib/defaults/index.js +2 -1
- package/node_modules/axios/lib/env/data.js +1 -1
- package/node_modules/axios/lib/helpers/Http2Sessions.js +2 -0
- package/node_modules/axios/lib/helpers/HttpStatusCode.js +11 -1
- package/node_modules/axios/lib/helpers/fromDataURI.js +5 -4
- package/node_modules/axios/lib/helpers/normalizeURLForProtocolCheck.js +24 -0
- package/node_modules/axios/lib/helpers/progressEventReducer.js +1 -1
- package/node_modules/axios/lib/helpers/resolveConfig.js +4 -2
- package/node_modules/axios/lib/helpers/shouldBypassProxy.js +182 -6
- package/node_modules/axios/lib/helpers/throttle.js +3 -2
- package/node_modules/axios/lib/helpers/toFormData.js +14 -21
- package/node_modules/axios/lib/utils.js +134 -13
- package/node_modules/axios/package.json +1 -1
- package/node_modules/ibm_db/APIDocumentation.md +2883 -2024
- package/node_modules/ibm_db/LICENSE +23 -23
- package/node_modules/ibm_db/README.md +735 -735
- package/node_modules/ibm_db/binding.gyp +99 -98
- package/node_modules/ibm_db/installer/driverInstall.js +984 -958
- package/node_modules/ibm_db/installer/ifx.sh +38 -38
- package/node_modules/ibm_db/installer/setenv.sh +23 -23
- package/node_modules/ibm_db/installer/testODBCConnection.bat +51 -51
- package/node_modules/ibm_db/installer/testODBCConnection.sh +61 -61
- package/node_modules/ibm_db/lib/climacros.js +431 -431
- package/node_modules/ibm_db/lib/odbc.js +4293 -3487
- package/node_modules/ibm_db/lib/simple-queue.js +41 -41
- package/node_modules/ibm_db/package.json +70 -70
- package/node_modules/ibm_db/src/odbc.cpp +1495 -1396
- package/node_modules/ibm_db/src/odbc.h +477 -473
- package/node_modules/ibm_db/src/odbc_connection.cpp +1762 -1612
- package/node_modules/ibm_db/src/odbc_connection.h +228 -215
- package/node_modules/ibm_db/src/odbc_result.cpp +1547 -1547
- package/node_modules/ibm_db/src/odbc_result.h +152 -152
- package/node_modules/ibm_db/src/odbc_statement.cpp +2047 -861
- package/node_modules/ibm_db/src/odbc_statement.h +257 -135
- package/node_modules/ibm_db/src/strptime.c +389 -389
- package/node_modules/ibm_db/src/strptime.h +46 -46
- package/node_modules/ibm_db/test/README +23 -23
- package/node_modules/ibm_db/test/bench-insert.js +62 -62
- package/node_modules/ibm_db/test/bench-insertBatch10.js +74 -74
- package/node_modules/ibm_db/test/bench-insertBatch100.js +75 -75
- package/node_modules/ibm_db/test/bench-insertBatch1000.js +75 -75
- package/node_modules/ibm_db/test/bench-insertBatch10000.js +75 -75
- package/node_modules/ibm_db/test/bench-prepare-bind-execute-closeSync.js +60 -60
- package/node_modules/ibm_db/test/bench-prepare-bind-executeNonQuery.js +53 -53
- package/node_modules/ibm_db/test/bench-prepare-bindSync-execute-closeSync.js +50 -50
- package/node_modules/ibm_db/test/bench-prepare-bindSync-executeNonQuery.js +48 -48
- package/node_modules/ibm_db/test/bench-prepare-execute-closeSync.js +51 -51
- package/node_modules/ibm_db/test/bench-prepare-executeNonQuery.js +47 -47
- package/node_modules/ibm_db/test/bench-prepare-not.js +43 -43
- package/node_modules/ibm_db/test/bench-query-fetch.js +59 -59
- package/node_modules/ibm_db/test/bench-query-fetchAll.js +49 -49
- package/node_modules/ibm_db/test/bench-query-fetchAllSync.js +43 -43
- package/node_modules/ibm_db/test/bench-query.js +40 -40
- package/node_modules/ibm_db/test/bench-querySync-fetchArray.js +28 -28
- package/node_modules/ibm_db/test/bench-querySync.js +29 -29
- package/node_modules/ibm_db/test/common.d.ts +10 -10
- package/node_modules/ibm_db/test/common.js +127 -127
- package/node_modules/ibm_db/test/config.json +7 -7
- package/node_modules/ibm_db/test/config.zos.json +4 -4
- package/node_modules/ibm_db/test/data/sample1.txt +9 -9
- package/node_modules/ibm_db/test/data/trc.fmt +30114 -30114
- package/node_modules/ibm_db/test/nodeEE-leak-huge-query.js +152 -152
- package/node_modules/ibm_db/test/nodeEE-leak-multiple-query-multiple-connections.js +148 -148
- package/node_modules/ibm_db/test/nodeEE-leak-multiple-query-pool-connections.js +154 -154
- package/node_modules/ibm_db/test/nodeEE-leak-multiple-query.js +133 -133
- package/node_modules/ibm_db/test/nodeEE-stress-async-waterfall-multiple-connections.js +174 -174
- package/node_modules/ibm_db/test/nodeEE-stress-async-waterfall.js +169 -169
- package/node_modules/ibm_db/test/nodeEE-stress-mixed-query-multiple-connections.js +159 -159
- package/node_modules/ibm_db/test/nodeEE-stress-mixed-query.js +148 -148
- package/node_modules/ibm_db/test/odbc-bench.c +123 -123
- package/node_modules/ibm_db/test/perfTest.js +53 -53
- package/node_modules/ibm_db/test/quick-example.sh +30 -30
- package/node_modules/ibm_db/test/quick-example.ts +80 -80
- package/node_modules/ibm_db/test/run-bench.js +96 -96
- package/node_modules/ibm_db/test/run-nodeEE.js +132 -132
- package/node_modules/ibm_db/test/run-tests.js +132 -138
- package/node_modules/ibm_db/test/sql-cli.js +28 -28
- package/node_modules/ibm_db/test/test-all-data-types.js +109 -109
- package/node_modules/ibm_db/test/test-array-insert.js +178 -178
- package/node_modules/ibm_db/test/test-async-await.js +105 -105
- package/node_modules/ibm_db/test/test-attributes.js +34 -34
- package/node_modules/ibm_db/test/test-bad-pool-connection-prepare-execute.js +57 -57
- package/node_modules/ibm_db/test/test-basic-test.js +138 -138
- package/node_modules/ibm_db/test/test-binary-array-insert.js +73 -73
- package/node_modules/ibm_db/test/test-blob-from-file.js +90 -90
- package/node_modules/ibm_db/test/test-blob-insert.js +144 -144
- package/node_modules/ibm_db/test/test-blob-stream-insert.js +321 -299
- package/node_modules/ibm_db/test/test-blob-to-file.js +370 -370
- package/node_modules/ibm_db/test/test-block-fetch.js +364 -364
- package/node_modules/ibm_db/test/test-blocking-issue210.js +123 -123
- package/node_modules/ibm_db/test/test-call-async.js +64 -64
- package/node_modules/ibm_db/test/test-call-stmt.js +53 -53
- package/node_modules/ibm_db/test/test-cancel.js +703 -0
- package/node_modules/ibm_db/test/test-chinese-char.js +59 -59
- package/node_modules/ibm_db/test/test-connection.js +306 -0
- package/node_modules/ibm_db/test/test-date.js +32 -32
- package/node_modules/ibm_db/test/test-dbclob.js +93 -93
- package/node_modules/ibm_db/test/test-decimals.js +135 -135
- package/node_modules/ibm_db/test/test-describe-metadata.js +148 -0
- package/node_modules/ibm_db/test/test-executeFile.js +167 -167
- package/node_modules/ibm_db/test/test-executeFileSync.js +85 -85
- package/node_modules/ibm_db/test/test-fetch-apis.js +146 -146
- package/node_modules/ibm_db/test/test-fetchN.js +130 -130
- package/node_modules/ibm_db/test/test-getinfo.js +197 -197
- package/node_modules/ibm_db/test/test-ibm-db-issue14.js +58 -58
- package/node_modules/ibm_db/test/test-ibm-db-issue17.js +54 -54
- package/node_modules/ibm_db/test/test-ibm-db-issue18.js +54 -54
- package/node_modules/ibm_db/test/test-issue-1059-fetchAll-undefined.js +67 -67
- package/node_modules/ibm_db/test/test-issue-1080-array-blob-insert.js +40 -0
- package/node_modules/ibm_db/test/test-issue-54.js +39 -39
- package/node_modules/ibm_db/test/test-issue-get-column-value-2.js +44 -44
- package/node_modules/ibm_db/test/test-issue211.js +80 -80
- package/node_modules/ibm_db/test/test-issue253.js +39 -39
- package/node_modules/ibm_db/test/test-max-pool-size.js +96 -96
- package/node_modules/ibm_db/test/test-memory-leaks-new-objects.js +32 -32
- package/node_modules/ibm_db/test/test-multi-open-query-close.js +75 -75
- package/node_modules/ibm_db/test/test-param-put-data.js +713 -0
- package/node_modules/ibm_db/test/test-pool-idle-connection.js +72 -72
- package/node_modules/ibm_db/test/test-pool-operations.js +325 -0
- package/node_modules/ibm_db/test/test-pool-stale-connections.js +111 -111
- package/node_modules/ibm_db/test/test-pool-uncommited.js +33 -33
- package/node_modules/ibm_db/test/test-prepare-execute.js +339 -0
- package/node_modules/ibm_db/test/test-prepareSync-multiple-execution.js +93 -93
- package/node_modules/ibm_db/test/test-primary-foreign-keys.js +246 -0
- package/node_modules/ibm_db/test/test-procedures.js +243 -0
- package/node_modules/ibm_db/test/test-promise-all-data-types.js +42 -42
- package/node_modules/ibm_db/test/test-query-operations.js +405 -0
- package/node_modules/ibm_db/test/test-quick-example.js +25 -25
- package/node_modules/ibm_db/test/test-row-array-insert.js +167 -167
- package/node_modules/ibm_db/test/test-sp-array.js +54 -54
- package/node_modules/ibm_db/test/test-sp-dbc-6000.js +88 -88
- package/node_modules/ibm_db/test/test-sp-memleak.js +136 -136
- package/node_modules/ibm_db/test/test-sp-resultset-execute.js +269 -269
- package/node_modules/ibm_db/test/test-sp-resultset.js +228 -228
- package/node_modules/ibm_db/test/test-transactions.js +261 -0
- package/node_modules/ibm_db/test/test-typescript.js +48 -48
- package/node_modules/ibm_db/test/test-xml-datatype.js +70 -70
- package/node_modules/ibm_db/test/testWebApp.js +56 -56
- package/node_modules/ibm_db/test/trace +51 -51
- package/node_modules/ibm_db/test/typescript-apis-test.js +978 -978
- package/node_modules/ibm_db/test/webapp.html +17 -17
- package/node_modules/ibm_db/test/webapp.js +79 -79
- package/node_modules/ibm_db/typescript/README.md +28 -28
- package/node_modules/ibm_db/typescript/dist/Database.d.ts +26 -0
- package/node_modules/ibm_db/typescript/dist/ODBCStatement.d.ts +93 -0
- package/package.json +10 -6
- package/node_modules/ibm_db/test/disabled/test-binding-statement-rebinding.js +0 -59
- package/node_modules/ibm_db/test/disabled/test-open-dont-close.js +0 -12
- package/node_modules/ibm_db/test/disabled/test-param-select-with-booleans-only.js +0 -21
- package/node_modules/ibm_db/test/disabled/test-param-select-with-decimals-only.js +0 -20
- package/node_modules/ibm_db/test/disabled/test-param-select-with-null.js +0 -21
- package/node_modules/ibm_db/test/disabled/test-param-select-with-nulls-mixed.js +0 -23
- package/node_modules/ibm_db/test/disabled/test-param-select-with-numbers-mixed.js +0 -22
- package/node_modules/ibm_db/test/disabled/test-param-select-with-numbers-only.js +0 -24
- package/node_modules/ibm_db/test/disabled/test-param-select-with-strings-only.js +0 -23
- package/node_modules/ibm_db/test/disabled/test-param-select-with-unicode.js +0 -15
- package/node_modules/ibm_db/test/disabled/test-prepare-bind-execute-closeSync.js +0 -62
- package/node_modules/ibm_db/test/disabled/test-prepare-bind-execute-error.js +0 -49
- package/node_modules/ibm_db/test/disabled/test-prepare-bind-execute-long-string.js +0 -63
- package/node_modules/ibm_db/test/disabled/test-prepare-bind-executeNonQuery.js +0 -63
- package/node_modules/ibm_db/test/disabled/test-prepare-bindSync-execute-closeSync.js +0 -46
- package/node_modules/ibm_db/test/disabled/test-prepare-bindSync-executeNonQuery.js +0 -50
- package/node_modules/ibm_db/test/disabled/test-prepare.js +0 -34
- package/node_modules/ibm_db/test/disabled/test-prepareSync.js +0 -29
- package/node_modules/ibm_db/test/disabled/test-query-select-fetchAll.js +0 -23
- package/node_modules/ibm_db/test/disabled/test-query-select-fetchAllSync.js +0 -23
- package/node_modules/ibm_db/test/disabled/test-query-select-unicode.js +0 -15
- package/node_modules/ibm_db/test/disabled/test-querySync-select-unicode.js +0 -20
- package/node_modules/ibm_db/test/test-affected-rows.js +0 -55
- package/node_modules/ibm_db/test/test-bad-connection-string.js +0 -30
- package/node_modules/ibm_db/test/test-binding-connection-timeOut.js +0 -31
- package/node_modules/ibm_db/test/test-binding-statement-executeSync.js +0 -84
- package/node_modules/ibm_db/test/test-binding-transaction-commit.js +0 -79
- package/node_modules/ibm_db/test/test-binding-transaction-commitSync.js +0 -53
- package/node_modules/ibm_db/test/test-closed.js +0 -14
- package/node_modules/ibm_db/test/test-connection-object.js +0 -16
- package/node_modules/ibm_db/test/test-describe-column.js +0 -92
- package/node_modules/ibm_db/test/test-describe-database.js +0 -18
- package/node_modules/ibm_db/test/test-describe-table.js +0 -31
- package/node_modules/ibm_db/test/test-domains-open.js +0 -19
- package/node_modules/ibm_db/test/test-global-open-close.js +0 -11
- package/node_modules/ibm_db/test/test-instantiate-one-and-end.js +0 -9
- package/node_modules/ibm_db/test/test-multi-open-close.js +0 -45
- package/node_modules/ibm_db/test/test-multi-openSync-closeSync.js +0 -52
- package/node_modules/ibm_db/test/test-open-close.js +0 -29
- package/node_modules/ibm_db/test/test-open-connectTimeout.js +0 -33
- package/node_modules/ibm_db/test/test-openSync.js +0 -31
- package/node_modules/ibm_db/test/test-pool-close.js +0 -120
- package/node_modules/ibm_db/test/test-pool-connect.js +0 -36
- package/node_modules/ibm_db/test/test-pool-rollbackTransaction.js +0 -35
- package/node_modules/ibm_db/test/test-prepareSync-bad-sql.js +0 -34
- package/node_modules/ibm_db/test/test-promise-open-close.js +0 -33
- package/node_modules/ibm_db/test/test-query-create-table-fetchSync.js +0 -23
- package/node_modules/ibm_db/test/test-query-create-table.js +0 -12
- package/node_modules/ibm_db/test/test-query-drop-table.js +0 -13
- package/node_modules/ibm_db/test/test-query-insert.js +0 -38
- package/node_modules/ibm_db/test/test-query-select-fetch.js +0 -21
- package/node_modules/ibm_db/test/test-query-select-fetchMode-array.js +0 -17
- package/node_modules/ibm_db/test/test-query-select.js +0 -64
- package/node_modules/ibm_db/test/test-queryResult.js +0 -35
- package/node_modules/ibm_db/test/test-queryStream.js +0 -43
- package/node_modules/ibm_db/test/test-querySync-select-with-exception.js +0 -25
- package/node_modules/ibm_db/test/test-querySync-select.js +0 -28
- package/node_modules/ibm_db/test/test-require-and-end.js +0 -8
- package/node_modules/ibm_db/test/test-statement-close.js +0 -118
- package/node_modules/ibm_db/test/test-transaction-commit-sync.js +0 -54
- package/node_modules/ibm_db/test/test-transaction-commit.js +0 -79
|
@@ -1,1396 +1,1495 @@
|
|
|
1
|
-
/*
|
|
2
|
-
Copyright (c) 2013, Dan VerWeire <dverweire@gmail.com>
|
|
3
|
-
Copyright (c) 2010, Lee Smith<notwink@gmail.com>
|
|
4
|
-
|
|
5
|
-
Permission to use, copy, modify, and/or distribute this software for any
|
|
6
|
-
purpose with or without fee is hereby granted, provided that the above
|
|
7
|
-
copyright notice and this permission notice appear in all copies.
|
|
8
|
-
|
|
9
|
-
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
10
|
-
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
11
|
-
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
12
|
-
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
13
|
-
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
14
|
-
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
15
|
-
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
16
|
-
*/
|
|
17
|
-
#ifdef __MVS__
|
|
18
|
-
#define _AE_BIMODAL
|
|
19
|
-
#include <_Nascii.h>
|
|
20
|
-
#endif
|
|
21
|
-
|
|
22
|
-
// On AIX, GCC auto-generates _GLOBAL__FI_*/_GLOBAL__FD_* init/fini functions
|
|
23
|
-
// in every shared library via crtcxa.o. The fini function calls __cxa_finalize
|
|
24
|
-
// which crashes with SIGILL (jump to 0x0) because atexit handlers registered
|
|
25
|
-
// by libdb2.a become invalid during process exit. (#439, #1045)
|
|
26
|
-
// We override the init/fini with this no-op to prevent the crash.
|
|
27
|
-
#ifdef _AIX
|
|
28
|
-
extern "C" void __ibmdb_aix_noop(void) {}
|
|
29
|
-
#endif
|
|
30
|
-
|
|
31
|
-
#include <string.h>
|
|
32
|
-
#include <stdint.h>
|
|
33
|
-
#include <type_traits>
|
|
34
|
-
#include <time.h>
|
|
35
|
-
#include <cassert>
|
|
36
|
-
#include <cstdlib>
|
|
37
|
-
#include <uv.h>
|
|
38
|
-
#ifdef _AIX
|
|
39
|
-
#include <signal.h>
|
|
40
|
-
#include <unistd.h>
|
|
41
|
-
#
|
|
42
|
-
|
|
43
|
-
#include
|
|
44
|
-
#include
|
|
45
|
-
#
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
#
|
|
49
|
-
#include "
|
|
50
|
-
#
|
|
51
|
-
|
|
52
|
-
#
|
|
53
|
-
#
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
unsigned long long
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
unsigned long long
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
StaticValue("
|
|
92
|
-
StaticValue("
|
|
93
|
-
StaticValue("
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
#ifdef __MVS__
|
|
134
|
-
__ae_thread_swapmode(
|
|
135
|
-
#endif
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
data
|
|
179
|
-
data
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
Napi::
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
Napi::
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
#
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
ret = SQLColAttribute(hStmt, columns[i].index,
|
|
307
|
-
NULL, 0, NULL, &columns[i].
|
|
308
|
-
ret = SQLColAttribute(hStmt, columns[i].index,
|
|
309
|
-
NULL, 0, NULL, &columns[i].
|
|
310
|
-
ret = SQLColAttribute(hStmt, columns[i].index,
|
|
311
|
-
NULL, 0, NULL, &columns[i].
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
columns[i].
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
delete[] columns;
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
{
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
case
|
|
398
|
-
case
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
#
|
|
417
|
-
struct tm timeInfo = {
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
#
|
|
421
|
-
|
|
422
|
-
#
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
timeInfo.
|
|
431
|
-
timeInfo.
|
|
432
|
-
timeInfo.
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
#
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
case
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
bufferSize =
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
#
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
#
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
#
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
case
|
|
588
|
-
case
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
return Napi::Number::New(env,
|
|
595
|
-
else if (prm->length == sizeof(
|
|
596
|
-
return Napi::Number::New(env,
|
|
597
|
-
else
|
|
598
|
-
return Napi::Number::New(env, *(
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
case
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
case
|
|
610
|
-
return Napi::
|
|
611
|
-
break;
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
{
|
|
620
|
-
prm->
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
#
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
params[i].
|
|
696
|
-
params[i].
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
val = paramArray.Get((uint32_t)
|
|
716
|
-
if (val.IsNumber()) params[i].
|
|
717
|
-
else params[i].
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
{
|
|
732
|
-
|
|
733
|
-
}
|
|
734
|
-
else if (val.
|
|
735
|
-
{
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
}
|
|
748
|
-
else if (val.
|
|
749
|
-
{
|
|
750
|
-
|
|
751
|
-
}
|
|
752
|
-
else if (val.
|
|
753
|
-
{
|
|
754
|
-
|
|
755
|
-
}
|
|
756
|
-
else
|
|
757
|
-
{
|
|
758
|
-
|
|
759
|
-
}
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
}
|
|
765
|
-
else if (value.
|
|
766
|
-
{
|
|
767
|
-
|
|
768
|
-
}
|
|
769
|
-
else if (value.
|
|
770
|
-
{
|
|
771
|
-
|
|
772
|
-
}
|
|
773
|
-
else if (value.
|
|
774
|
-
{
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
}
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
param->
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
if (
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
param->
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
param->
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
}
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
param->length =
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
param->
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
param->
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
param->
|
|
1015
|
-
param->
|
|
1016
|
-
param->
|
|
1017
|
-
param->
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
param->
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
param->
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
param->
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
if (
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
{
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
if (
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
{
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
//
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
}
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1
|
+
/*
|
|
2
|
+
Copyright (c) 2013, Dan VerWeire <dverweire@gmail.com>
|
|
3
|
+
Copyright (c) 2010, Lee Smith<notwink@gmail.com>
|
|
4
|
+
|
|
5
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
6
|
+
purpose with or without fee is hereby granted, provided that the above
|
|
7
|
+
copyright notice and this permission notice appear in all copies.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
10
|
+
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
11
|
+
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
12
|
+
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
13
|
+
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
14
|
+
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
15
|
+
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
16
|
+
*/
|
|
17
|
+
#ifdef __MVS__
|
|
18
|
+
#define _AE_BIMODAL
|
|
19
|
+
#include <_Nascii.h>
|
|
20
|
+
#endif
|
|
21
|
+
|
|
22
|
+
// On AIX, GCC auto-generates _GLOBAL__FI_*/_GLOBAL__FD_* init/fini functions
|
|
23
|
+
// in every shared library via crtcxa.o. The fini function calls __cxa_finalize
|
|
24
|
+
// which crashes with SIGILL (jump to 0x0) because atexit handlers registered
|
|
25
|
+
// by libdb2.a become invalid during process exit. (#439, #1045)
|
|
26
|
+
// We override the init/fini with this no-op to prevent the crash.
|
|
27
|
+
#ifdef _AIX
|
|
28
|
+
extern "C" void __ibmdb_aix_noop(void) {}
|
|
29
|
+
#endif
|
|
30
|
+
|
|
31
|
+
#include <string.h>
|
|
32
|
+
#include <stdint.h>
|
|
33
|
+
#include <type_traits>
|
|
34
|
+
#include <time.h>
|
|
35
|
+
#include <cassert>
|
|
36
|
+
#include <cstdlib>
|
|
37
|
+
#include <uv.h>
|
|
38
|
+
#ifdef _AIX
|
|
39
|
+
#include <signal.h>
|
|
40
|
+
#include <unistd.h>
|
|
41
|
+
#include <exception>
|
|
42
|
+
#include <cstdio>
|
|
43
|
+
#include <typeinfo>
|
|
44
|
+
#include <cxxabi.h>
|
|
45
|
+
#endif
|
|
46
|
+
|
|
47
|
+
#include "odbc.h"
|
|
48
|
+
#include "odbc_connection.h"
|
|
49
|
+
#include "odbc_result.h"
|
|
50
|
+
#include "odbc_statement.h"
|
|
51
|
+
|
|
52
|
+
#ifdef _WIN32
|
|
53
|
+
#include "strptime.h"
|
|
54
|
+
#endif
|
|
55
|
+
|
|
56
|
+
#define FILE_PARAM 3
|
|
57
|
+
#define DATA_AT_EXEC_PARAM 5
|
|
58
|
+
|
|
59
|
+
namespace {
|
|
60
|
+
template <typename HandleType>
|
|
61
|
+
unsigned long long HandleToLogValueImpl(HandleType handle, std::true_type)
|
|
62
|
+
{
|
|
63
|
+
return static_cast<unsigned long long>(reinterpret_cast<uintptr_t>(handle));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
template <typename HandleType>
|
|
67
|
+
unsigned long long HandleToLogValueImpl(HandleType handle, std::false_type)
|
|
68
|
+
{
|
|
69
|
+
return static_cast<unsigned long long>(handle);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
template <typename HandleType>
|
|
73
|
+
unsigned long long HandleToLogValue(HandleType handle)
|
|
74
|
+
{
|
|
75
|
+
return HandleToLogValueImpl(handle, typename std::is_pointer<HandleType>::type());
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
uv_mutex_t ODBC::g_odbcMutex;
|
|
80
|
+
uv_async_t ODBC::g_async;
|
|
81
|
+
|
|
82
|
+
Napi::FunctionReference ODBC::constructor;
|
|
83
|
+
|
|
84
|
+
Napi::Object ODBC::Init(Napi::Env env, Napi::Object exports)
|
|
85
|
+
{
|
|
86
|
+
DEBUG_PRINTF("ODBC::Init\n");
|
|
87
|
+
|
|
88
|
+
Napi::Function func = DefineClass(env, "ODBC", {
|
|
89
|
+
InstanceMethod("createConnection", &ODBC::CreateConnection, NAPI_METHOD_ATTR),
|
|
90
|
+
InstanceMethod("createConnectionSync", &ODBC::CreateConnectionSync, NAPI_METHOD_ATTR),
|
|
91
|
+
StaticValue("SQL_CLOSE", Napi::Number::New(env, SQL_CLOSE), napi_enumerable),
|
|
92
|
+
StaticValue("SQL_DROP", Napi::Number::New(env, SQL_DROP), napi_enumerable),
|
|
93
|
+
StaticValue("SQL_UNBIND", Napi::Number::New(env, SQL_UNBIND), napi_enumerable),
|
|
94
|
+
StaticValue("SQL_RESET_PARAMS", Napi::Number::New(env, SQL_RESET_PARAMS), napi_enumerable),
|
|
95
|
+
StaticValue("SQL_DESTROY", Napi::Number::New(env, SQL_DESTROY), napi_enumerable),
|
|
96
|
+
StaticValue("FETCH_ARRAY", Napi::Number::New(env, FETCH_ARRAY), napi_enumerable),
|
|
97
|
+
StaticValue("FETCH_OBJECT", Napi::Number::New(env, FETCH_OBJECT), napi_enumerable),
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
constructor = Napi::Persistent(func);
|
|
101
|
+
constructor.SuppressDestruct();
|
|
102
|
+
exports.Set("ODBC", func);
|
|
103
|
+
|
|
104
|
+
// Initialize the cross platform mutex provided by libuv
|
|
105
|
+
uv_mutex_init(&ODBC::g_odbcMutex);
|
|
106
|
+
|
|
107
|
+
return exports;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
ODBC::~ODBC()
|
|
111
|
+
{
|
|
112
|
+
DEBUG_PRINTF("ODBC::~ODBC\n");
|
|
113
|
+
this->Free();
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
void ODBC::Free()
|
|
117
|
+
{
|
|
118
|
+
DEBUG_PRINTF("ODBC::Free: m_hEnv = 0x%llx\n", HandleToLogValue(m_hEnv));
|
|
119
|
+
if (m_hEnv)
|
|
120
|
+
{
|
|
121
|
+
SQLFreeHandle(SQL_HANDLE_ENV, m_hEnv);
|
|
122
|
+
m_hEnv = (SQLHENV)NULL;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
ODBC::ODBC(const Napi::CallbackInfo &info) : Napi::ObjectWrap<ODBC>(info)
|
|
127
|
+
{
|
|
128
|
+
Napi::Env env = info.Env();
|
|
129
|
+
DEBUG_PRINTF("ODBC::New - Entry\n");
|
|
130
|
+
|
|
131
|
+
m_hEnv = (SQLHENV)NULL;
|
|
132
|
+
|
|
133
|
+
#ifdef __MVS__
|
|
134
|
+
int ori_mode = __ae_thread_swapmode(__AE_EBCDIC_MODE);
|
|
135
|
+
#endif
|
|
136
|
+
int ret = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &m_hEnv);
|
|
137
|
+
#ifdef __MVS__
|
|
138
|
+
__ae_thread_swapmode(ori_mode);
|
|
139
|
+
#endif
|
|
140
|
+
if (!SQL_SUCCEEDED(ret))
|
|
141
|
+
{
|
|
142
|
+
DEBUG_PRINTF("ODBC::New - ERROR ALLOCATING ENV HANDLE!!\n");
|
|
143
|
+
Napi::Value objError = ODBC::GetSQLError(env, SQL_HANDLE_ENV, m_hEnv);
|
|
144
|
+
napi_throw(env, objError);
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
ret = SQLSetEnvAttr(m_hEnv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, SQL_IS_UINTEGER);
|
|
149
|
+
|
|
150
|
+
if (!SQL_SUCCEEDED(ret))
|
|
151
|
+
{
|
|
152
|
+
DEBUG_PRINTF("ODBC::New - ERROR SETTING ODBC VERSION!!\n");
|
|
153
|
+
Napi::Value objError = ODBC::GetSQLError(env, SQL_HANDLE_ENV, m_hEnv);
|
|
154
|
+
SQLFreeHandle(SQL_HANDLE_ENV, m_hEnv);
|
|
155
|
+
m_hEnv = (SQLHENV)NULL;
|
|
156
|
+
napi_throw(env, objError);
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
DEBUG_PRINTF("ODBC::New - Exit\n");
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/*
|
|
164
|
+
* CreateConnection
|
|
165
|
+
*/
|
|
166
|
+
Napi::Value ODBC::CreateConnection(const Napi::CallbackInfo &info)
|
|
167
|
+
{
|
|
168
|
+
DEBUG_PRINTF("ODBC::CreateConnection - Entry\n");
|
|
169
|
+
Napi::Env env = info.Env();
|
|
170
|
+
|
|
171
|
+
REQ_FUN_ARG(0, cb);
|
|
172
|
+
|
|
173
|
+
uv_work_t *work_req = (uv_work_t *)(calloc(1, sizeof(uv_work_t)));
|
|
174
|
+
MEMCHECK(work_req);
|
|
175
|
+
|
|
176
|
+
create_connection_work_data *data =
|
|
177
|
+
(create_connection_work_data *)(calloc(1, sizeof(create_connection_work_data)));
|
|
178
|
+
if (!data) free(work_req);
|
|
179
|
+
MEMCHECK(data);
|
|
180
|
+
|
|
181
|
+
data->cb = new Napi::FunctionReference(Napi::Persistent(cb));
|
|
182
|
+
data->dbo = this;
|
|
183
|
+
data->env = env;
|
|
184
|
+
|
|
185
|
+
work_req->data = data;
|
|
186
|
+
|
|
187
|
+
uv_queue_work(uv_default_loop(), work_req, UV_CreateConnection, (uv_after_work_cb)UV_AfterCreateConnection);
|
|
188
|
+
|
|
189
|
+
this->Ref();
|
|
190
|
+
|
|
191
|
+
DEBUG_PRINTF("ODBC::CreateConnection - Exit\n");
|
|
192
|
+
return env.Undefined();
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
void ODBC::UV_CreateConnection(uv_work_t *req)
|
|
196
|
+
{
|
|
197
|
+
DEBUG_PRINTF("ODBC::UV_CreateConnection - Entry\n");
|
|
198
|
+
create_connection_work_data *data = (create_connection_work_data *)(req->data);
|
|
199
|
+
data->result = SQLAllocHandle(SQL_HANDLE_DBC, data->dbo->m_hEnv, &data->hDBC);
|
|
200
|
+
DEBUG_PRINTF("ODBC::UV_CreateConnection - Exit: hDBC = 0x%llx\n", HandleToLogValue(data->hDBC));
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
void ODBC::UV_AfterCreateConnection(uv_work_t *req, int status)
|
|
204
|
+
{
|
|
205
|
+
DEBUG_PRINTF("ODBC::UV_AfterCreateConnection - Entry\n");
|
|
206
|
+
create_connection_work_data *data = (create_connection_work_data *)(req->data);
|
|
207
|
+
Napi::Env env(data->env);
|
|
208
|
+
Napi::HandleScope scope(env);
|
|
209
|
+
|
|
210
|
+
if (!SQL_SUCCEEDED(data->result))
|
|
211
|
+
{
|
|
212
|
+
Napi::Value error = ODBC::GetSQLError(env, SQL_HANDLE_ENV, data->dbo->m_hEnv);
|
|
213
|
+
data->cb->Call({error});
|
|
214
|
+
}
|
|
215
|
+
else
|
|
216
|
+
{
|
|
217
|
+
Napi::Value args[2] = {
|
|
218
|
+
Napi::External<void>::New(env, (void *)(intptr_t)data->dbo->m_hEnv),
|
|
219
|
+
Napi::External<void>::New(env, (void *)(intptr_t)data->hDBC)
|
|
220
|
+
};
|
|
221
|
+
Napi::Object js_result = ODBCConnection::constructor.New({args[0], args[1]});
|
|
222
|
+
data->cb->Call({env.Null(), js_result});
|
|
223
|
+
}
|
|
224
|
+
PropagateCallbackException(env);
|
|
225
|
+
|
|
226
|
+
data->dbo->Unref();
|
|
227
|
+
delete data->cb;
|
|
228
|
+
free(data);
|
|
229
|
+
free(req);
|
|
230
|
+
DEBUG_PRINTF("ODBC::UV_AfterCreateConnection - Exit\n");
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/*
|
|
234
|
+
* CreateConnectionSync
|
|
235
|
+
*/
|
|
236
|
+
Napi::Value ODBC::CreateConnectionSync(const Napi::CallbackInfo &info)
|
|
237
|
+
{
|
|
238
|
+
DEBUG_PRINTF("ODBC::CreateConnectionSync - Entry\n");
|
|
239
|
+
Napi::Env env = info.Env();
|
|
240
|
+
|
|
241
|
+
SQLHDBC hDBC;
|
|
242
|
+
SQLRETURN ret = SQLAllocHandle(SQL_HANDLE_DBC, m_hEnv, &hDBC);
|
|
243
|
+
|
|
244
|
+
if (!SQL_SUCCEEDED(ret))
|
|
245
|
+
{
|
|
246
|
+
// TODO: do something!
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
Napi::Value params[2] = {
|
|
250
|
+
Napi::External<void>::New(env, (void *)(intptr_t)m_hEnv),
|
|
251
|
+
Napi::External<void>::New(env, (void *)(intptr_t)hDBC)
|
|
252
|
+
};
|
|
253
|
+
Napi::Object js_result = ODBCConnection::constructor.New({params[0], params[1]});
|
|
254
|
+
|
|
255
|
+
DEBUG_PRINTF("ODBC::CreateConnectionSync - Exit: hDBC = 0x%llx\n", HandleToLogValue(hDBC));
|
|
256
|
+
return js_result;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/*
|
|
260
|
+
* GetColumns
|
|
261
|
+
*/
|
|
262
|
+
Column *ODBC::GetColumns(SQLHSTMT hStmt, short *colCount)
|
|
263
|
+
{
|
|
264
|
+
SQLRETURN ret;
|
|
265
|
+
SQLSMALLINT buflen;
|
|
266
|
+
SQLSMALLINT typebuflen;
|
|
267
|
+
DEBUG_PRINTF("ODBC::GetColumns - Entry\n");
|
|
268
|
+
|
|
269
|
+
*colCount = 0;
|
|
270
|
+
ret = SQLNumResultCols(hStmt, colCount);
|
|
271
|
+
|
|
272
|
+
if (!SQL_SUCCEEDED(ret))
|
|
273
|
+
{
|
|
274
|
+
return new Column[0];
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
Column *columns = new Column[*colCount];
|
|
278
|
+
char colname[MAX_FIELD_SIZE];
|
|
279
|
+
|
|
280
|
+
for (int i = 0; i < *colCount; i++)
|
|
281
|
+
{
|
|
282
|
+
columns[i].index = i + 1;
|
|
283
|
+
columns[i].getData = false;
|
|
284
|
+
columns[i].isFileBound = false;
|
|
285
|
+
colname[0] = '\0';
|
|
286
|
+
buflen = 0;
|
|
287
|
+
|
|
288
|
+
ret = SQLColAttribute(hStmt, columns[i].index,
|
|
289
|
+
#ifdef STRICT_COLUMN_NAMES
|
|
290
|
+
SQL_DESC_NAME,
|
|
291
|
+
#else
|
|
292
|
+
SQL_DESC_LABEL,
|
|
293
|
+
#endif
|
|
294
|
+
colname, (SQLSMALLINT)MAX_FIELD_SIZE, &buflen, NULL);
|
|
295
|
+
|
|
296
|
+
columns[i].name_len = buflen;
|
|
297
|
+
if (buflen > 0)
|
|
298
|
+
{
|
|
299
|
+
columns[i].name = new unsigned char[buflen + 2];
|
|
300
|
+
memcpy(columns[i].name, colname, buflen);
|
|
301
|
+
columns[i].name[buflen] = '\0';
|
|
302
|
+
columns[i].name[buflen + 1] = '\0';
|
|
303
|
+
}
|
|
304
|
+
DEBUG_PRINTF("ODBC::GetColumns index = %i, buflen=%i\n", columns[i].index, buflen);
|
|
305
|
+
|
|
306
|
+
ret = SQLColAttribute(hStmt, columns[i].index, SQL_DESC_DISPLAY_SIZE,
|
|
307
|
+
NULL, 0, NULL, &columns[i].max_display_len);
|
|
308
|
+
ret = SQLColAttribute(hStmt, columns[i].index, SQL_DESC_PRECISION,
|
|
309
|
+
NULL, 0, NULL, &columns[i].precision);
|
|
310
|
+
ret = SQLColAttribute(hStmt, columns[i].index, SQL_DESC_SCALE,
|
|
311
|
+
NULL, 0, NULL, &columns[i].scale);
|
|
312
|
+
ret = SQLColAttribute(hStmt, columns[i].index, SQL_DESC_LENGTH,
|
|
313
|
+
NULL, 0, NULL, &columns[i].field_len);
|
|
314
|
+
ret = SQLColAttribute(hStmt, columns[i].index, SQL_DESC_CONCISE_TYPE,
|
|
315
|
+
NULL, 0, NULL, &columns[i].type);
|
|
316
|
+
|
|
317
|
+
columns[i].type_name = new unsigned char[(MAX_FIELD_SIZE)];
|
|
318
|
+
columns[i].type_name[0] = '\0';
|
|
319
|
+
|
|
320
|
+
ret = SQLColAttribute(hStmt, columns[i].index, SQL_DESC_TYPE_NAME,
|
|
321
|
+
columns[i].type_name, (SQLSMALLINT)(MAX_FIELD_SIZE),
|
|
322
|
+
&typebuflen, NULL);
|
|
323
|
+
}
|
|
324
|
+
DEBUG_PRINTF("ODBC::GetColumns - Exit\n");
|
|
325
|
+
return columns;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/*
|
|
329
|
+
* FreeColumns
|
|
330
|
+
*/
|
|
331
|
+
void ODBC::FreeColumns(Column *&columns, short *colCount)
|
|
332
|
+
{
|
|
333
|
+
DEBUG_PRINTF("ODBC::FreeColumns - Entry\n");
|
|
334
|
+
for (int i = 0; i < *colCount; i++)
|
|
335
|
+
{
|
|
336
|
+
delete[] columns[i].name;
|
|
337
|
+
delete[] columns[i].type_name;
|
|
338
|
+
}
|
|
339
|
+
if (columns != NULL)
|
|
340
|
+
{
|
|
341
|
+
delete[] columns;
|
|
342
|
+
columns = NULL;
|
|
343
|
+
}
|
|
344
|
+
*colCount = 0;
|
|
345
|
+
DEBUG_PRINTF("ODBC::FreeColumns - Exit\n");
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/*
|
|
349
|
+
* GetColumnValue
|
|
350
|
+
*/
|
|
351
|
+
Napi::Value ODBC::GetColumnValue(Napi::Env env, SQLHSTMT hStmt, Column column,
|
|
352
|
+
uint16_t *buffer, size_t bufferLength)
|
|
353
|
+
{
|
|
354
|
+
if (column.isFileBound) {
|
|
355
|
+
return env.Null();
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
SQLLEN len = 0;
|
|
359
|
+
SQLLEN maxBuffSize = 0;
|
|
360
|
+
unsigned short terCharLen = 1;
|
|
361
|
+
SQLRETURN ret = SQL_SUCCESS;
|
|
362
|
+
SQLSMALLINT ctype = SQL_C_TCHAR;
|
|
363
|
+
char *errmsg = (char *)"[node-ibm_db] Error in ODBC::GetColumnValue";
|
|
364
|
+
|
|
365
|
+
#ifdef UNICODE
|
|
366
|
+
terCharLen = 2;
|
|
367
|
+
#endif
|
|
368
|
+
|
|
369
|
+
DEBUG_PRINTF("Column Type : %i\t%i\t%i\t%i\n", column.type, SQL_DATETIME,
|
|
370
|
+
SQL_TIMESTAMP, SQL_TYPE_TIME);
|
|
371
|
+
|
|
372
|
+
switch (column.type)
|
|
373
|
+
{
|
|
374
|
+
case SQL_BLOB:
|
|
375
|
+
case SQL_BINARY:
|
|
376
|
+
case SQL_VARBINARY:
|
|
377
|
+
case SQL_LONGVARBINARY:
|
|
378
|
+
terCharLen = 0;
|
|
379
|
+
ctype = SQL_C_BINARY;
|
|
380
|
+
break;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
switch (column.type)
|
|
384
|
+
{
|
|
385
|
+
case SQL_INTEGER:
|
|
386
|
+
case SQL_SMALLINT:
|
|
387
|
+
case SQL_TINYINT:
|
|
388
|
+
{
|
|
389
|
+
SQLINTEGER value;
|
|
390
|
+
ret = SQLGetData(hStmt, column.index, SQL_C_SLONG, &value, sizeof(value), &len);
|
|
391
|
+
|
|
392
|
+
if (len == SQL_NULL_DATA) return env.Null();
|
|
393
|
+
return Napi::Number::New(env, (double)value);
|
|
394
|
+
}
|
|
395
|
+
break;
|
|
396
|
+
|
|
397
|
+
case SQL_NUMERIC:
|
|
398
|
+
case SQL_DECIMAL:
|
|
399
|
+
case SQL_DECFLOAT:
|
|
400
|
+
case SQL_FLOAT:
|
|
401
|
+
case SQL_REAL:
|
|
402
|
+
case SQL_DOUBLE:
|
|
403
|
+
{
|
|
404
|
+
double value;
|
|
405
|
+
ret = SQLGetData(hStmt, column.index, SQL_C_DOUBLE, &value, sizeof(value), &len);
|
|
406
|
+
|
|
407
|
+
if (len == SQL_NULL_DATA) return env.Null();
|
|
408
|
+
return Napi::Number::New(env, value);
|
|
409
|
+
}
|
|
410
|
+
break;
|
|
411
|
+
|
|
412
|
+
case SQL_DATETIME:
|
|
413
|
+
case SQL_TIMESTAMP:
|
|
414
|
+
{
|
|
415
|
+
SQL_TIMESTAMP_STRUCT odbcTime;
|
|
416
|
+
#ifdef _WIN32
|
|
417
|
+
struct tm timeInfo = {};
|
|
418
|
+
ret = SQLGetData(hStmt, column.index, SQL_C_CHAR, &odbcTime, sizeof(odbcTime), &len);
|
|
419
|
+
#else
|
|
420
|
+
#if defined(_AIX) || defined(__MVS__)
|
|
421
|
+
struct tm timeInfo = {0, 0, 0, 0, 0, 0, 0, 0, 0};
|
|
422
|
+
#else
|
|
423
|
+
struct tm timeInfo = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
|
424
|
+
#endif
|
|
425
|
+
ret = SQLGetData(hStmt, column.index, SQL_C_TYPE_TIMESTAMP, &odbcTime, sizeof(odbcTime), &len);
|
|
426
|
+
#endif
|
|
427
|
+
|
|
428
|
+
if (len == SQL_NULL_DATA) return env.Null();
|
|
429
|
+
|
|
430
|
+
timeInfo.tm_year = odbcTime.year - 1900;
|
|
431
|
+
timeInfo.tm_mon = odbcTime.month - 1;
|
|
432
|
+
timeInfo.tm_mday = odbcTime.day;
|
|
433
|
+
timeInfo.tm_hour = odbcTime.hour;
|
|
434
|
+
timeInfo.tm_min = odbcTime.minute;
|
|
435
|
+
timeInfo.tm_sec = odbcTime.second;
|
|
436
|
+
timeInfo.tm_isdst = -1;
|
|
437
|
+
|
|
438
|
+
#ifdef TIMEGM
|
|
439
|
+
return Napi::Date::New(env, (double(timegm(&timeInfo)) * 1000) + (odbcTime.fraction / 1000000));
|
|
440
|
+
#else
|
|
441
|
+
return Napi::Date::New(env, (double(mktime(&timeInfo)) * 1000) + (odbcTime.fraction / 1000000));
|
|
442
|
+
#endif
|
|
443
|
+
}
|
|
444
|
+
break;
|
|
445
|
+
|
|
446
|
+
case SQL_BIT:
|
|
447
|
+
{
|
|
448
|
+
char bit[4] = {'\0'};
|
|
449
|
+
ret = SQLGetData(hStmt, column.index, SQL_C_CHAR, &bit, 4, &len);
|
|
450
|
+
if (len == SQL_NULL_DATA) return env.Null();
|
|
451
|
+
return Napi::Boolean::New(env, (*bit == '0') ? false : true);
|
|
452
|
+
}
|
|
453
|
+
break;
|
|
454
|
+
|
|
455
|
+
case SQL_TYPE_TIME:
|
|
456
|
+
case SQL_BIGINT:
|
|
457
|
+
if (column.type == SQL_BIGINT) ctype = SQL_C_CHAR;
|
|
458
|
+
/* fall through */
|
|
459
|
+
case SQL_DBCLOB:
|
|
460
|
+
if (column.type == SQL_DBCLOB) ctype = SQL_C_CHAR;
|
|
461
|
+
/* fall through */
|
|
462
|
+
default:
|
|
463
|
+
{
|
|
464
|
+
uint16_t *tmp_out_ptr = NULL;
|
|
465
|
+
uint32_t bufferSize = 0;
|
|
466
|
+
uint32_t newbufflen = 0;
|
|
467
|
+
unsigned short secondGetData = 0;
|
|
468
|
+
len = 0;
|
|
469
|
+
bufferSize = bufferLength + terCharLen;
|
|
470
|
+
|
|
471
|
+
if (buffer == NULL)
|
|
472
|
+
{
|
|
473
|
+
buffer = (uint16_t *)malloc(bufferSize);
|
|
474
|
+
if (buffer == NULL)
|
|
475
|
+
{
|
|
476
|
+
errmsg = (char *)"Failed to allocate memory buffer for column data.";
|
|
477
|
+
napi_throw(env, ODBC::GetSQLError(env, SQL_HANDLE_STMT, hStmt, errmsg));
|
|
478
|
+
return env.Undefined();
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
maxBuffSize = bufferSize;
|
|
482
|
+
memset(buffer, '\0', bufferSize);
|
|
483
|
+
ret = SQLGetData(hStmt, column.index, ctype, (char *)buffer, maxBuffSize, &len);
|
|
484
|
+
|
|
485
|
+
if (column.getData) { secondGetData = 1; }
|
|
486
|
+
else if (ret == SQL_SUCCESS_WITH_INFO && len > 0)
|
|
487
|
+
{
|
|
488
|
+
if (len + terCharLen > 0x3fffffff)
|
|
489
|
+
newbufflen = 0x3fffffff;
|
|
490
|
+
else
|
|
491
|
+
newbufflen = len + terCharLen;
|
|
492
|
+
|
|
493
|
+
tmp_out_ptr = (uint16_t *)malloc(newbufflen);
|
|
494
|
+
if (tmp_out_ptr == NULL)
|
|
495
|
+
{
|
|
496
|
+
ret = (SQLRETURN)-3;
|
|
497
|
+
newbufflen = bufferSize;
|
|
498
|
+
}
|
|
499
|
+
else
|
|
500
|
+
{
|
|
501
|
+
memcpy(tmp_out_ptr, (char *)buffer, bufferLength);
|
|
502
|
+
free((uint16_t *)buffer);
|
|
503
|
+
buffer = tmp_out_ptr;
|
|
504
|
+
maxBuffSize = newbufflen - bufferLength;
|
|
505
|
+
len = 0;
|
|
506
|
+
ret = SQLGetData(hStmt, column.index, ctype, (char *)buffer + bufferLength, maxBuffSize, &len);
|
|
507
|
+
ret = SQL_SUCCESS;
|
|
508
|
+
len = newbufflen;
|
|
509
|
+
secondGetData = 1;
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
if (len >= 0) newbufflen = len;
|
|
513
|
+
|
|
514
|
+
if (len == SQL_NULL_DATA)
|
|
515
|
+
{
|
|
516
|
+
FREE(buffer);
|
|
517
|
+
return env.Null();
|
|
518
|
+
}
|
|
519
|
+
else if (SQL_SUCCEEDED(ret) || secondGetData)
|
|
520
|
+
{
|
|
521
|
+
if (ctype == SQL_C_BINARY)
|
|
522
|
+
{
|
|
523
|
+
// Return binary data as buffer - transfer ownership to Node
|
|
524
|
+
Napi::Buffer<char> buf = Napi::Buffer<char>::Copy(env, (char *)buffer, newbufflen);
|
|
525
|
+
FREE(buffer);
|
|
526
|
+
return buf;
|
|
527
|
+
}
|
|
528
|
+
else
|
|
529
|
+
{
|
|
530
|
+
#ifdef UNICODE
|
|
531
|
+
Napi::Value str = Napi::String::New(env, (char16_t *)buffer);
|
|
532
|
+
#else
|
|
533
|
+
Napi::Value str = Napi::String::New(env, (char *)buffer);
|
|
534
|
+
#endif
|
|
535
|
+
FREE(buffer);
|
|
536
|
+
return str;
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
else
|
|
540
|
+
{
|
|
541
|
+
FREE(buffer);
|
|
542
|
+
if (ret == SQL_INVALID_HANDLE)
|
|
543
|
+
{
|
|
544
|
+
unsigned long long hstmt_value = HandleToLogValue(hStmt);
|
|
545
|
+
#ifdef __MVS__
|
|
546
|
+
__fprintf_a(stdout, "Invalid Handle: SQLGetData return code = %i, stmt handle = 0x%llx"
|
|
547
|
+
", columnType = %i, index = %i\n",
|
|
548
|
+
ret, hstmt_value, (int)column.type, column.index);
|
|
549
|
+
#else
|
|
550
|
+
fprintf(stdout, "Invalid Handle: SQLGetData return code = %i, stmt handle = 0x%llx"
|
|
551
|
+
", columnType = %i, index = %i\n",
|
|
552
|
+
ret, hstmt_value, (int)column.type, column.index);
|
|
553
|
+
#endif
|
|
554
|
+
assert(ret != SQL_INVALID_HANDLE);
|
|
555
|
+
}
|
|
556
|
+
napi_throw(env, ODBC::GetSQLError(env, SQL_HANDLE_STMT, hStmt, errmsg));
|
|
557
|
+
return env.Undefined();
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
/*
|
|
564
|
+
* GetOutputParameter
|
|
565
|
+
*/
|
|
566
|
+
Napi::Value ODBC::GetOutputParameter(Napi::Env env, Parameter *prm)
|
|
567
|
+
{
|
|
568
|
+
bool sqlTypeBinary = false;
|
|
569
|
+
|
|
570
|
+
switch (prm->type)
|
|
571
|
+
{
|
|
572
|
+
case SQL_BLOB:
|
|
573
|
+
case SQL_BINARY:
|
|
574
|
+
case SQL_VARBINARY:
|
|
575
|
+
case SQL_LONGVARBINARY:
|
|
576
|
+
sqlTypeBinary = true;
|
|
577
|
+
break;
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
if (((int)prm->length == SQL_NULL_DATA) || !prm->buffer)
|
|
581
|
+
{
|
|
582
|
+
return env.Null();
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
switch (prm->type)
|
|
586
|
+
{
|
|
587
|
+
case SQL_INTEGER:
|
|
588
|
+
case SQL_SMALLINT:
|
|
589
|
+
case SQL_TINYINT:
|
|
590
|
+
case SQL_BOOLEAN:
|
|
591
|
+
case SQL_NUMERIC:
|
|
592
|
+
case SQL_BIGINT:
|
|
593
|
+
if (prm->length == sizeof(int))
|
|
594
|
+
return Napi::Number::New(env, *(int *)prm->buffer);
|
|
595
|
+
else if (prm->length == sizeof(short))
|
|
596
|
+
return Napi::Number::New(env, *(short *)prm->buffer);
|
|
597
|
+
else if (prm->length == sizeof(long))
|
|
598
|
+
return Napi::Number::New(env, (double)*(long *)prm->buffer);
|
|
599
|
+
else if (prm->length == sizeof(long long))
|
|
600
|
+
return Napi::Number::New(env, (double)*(long long *)prm->buffer);
|
|
601
|
+
else
|
|
602
|
+
return Napi::Number::New(env, *(char *)prm->buffer);
|
|
603
|
+
break;
|
|
604
|
+
|
|
605
|
+
case SQL_DECIMAL:
|
|
606
|
+
case SQL_FLOAT:
|
|
607
|
+
case SQL_DECFLOAT:
|
|
608
|
+
case SQL_REAL:
|
|
609
|
+
case SQL_DOUBLE:
|
|
610
|
+
return Napi::Number::New(env, *(double *)prm->buffer);
|
|
611
|
+
break;
|
|
612
|
+
|
|
613
|
+
case SQL_BIT:
|
|
614
|
+
return Napi::Boolean::New(env, (*((char *)prm->buffer) == '0') ? false : true);
|
|
615
|
+
break;
|
|
616
|
+
|
|
617
|
+
default:
|
|
618
|
+
if (prm->isBuffer)
|
|
619
|
+
{
|
|
620
|
+
return Napi::Buffer<char>::Copy(env, (char *)prm->buffer, prm->length);
|
|
621
|
+
}
|
|
622
|
+
else if (sqlTypeBinary || prm->c_type == SQL_C_BINARY)
|
|
623
|
+
{
|
|
624
|
+
prm->isBuffer = true;
|
|
625
|
+
return Napi::Buffer<char>::Copy(env, (char *)prm->buffer, prm->length);
|
|
626
|
+
}
|
|
627
|
+
else
|
|
628
|
+
{
|
|
629
|
+
#ifdef UNICODE
|
|
630
|
+
return Napi::String::New(env, (char16_t *)prm->buffer);
|
|
631
|
+
#else
|
|
632
|
+
return Napi::String::New(env, (char *)prm->buffer);
|
|
633
|
+
#endif
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
/*
|
|
639
|
+
* GetRecordTuple
|
|
640
|
+
*/
|
|
641
|
+
Napi::Object ODBC::GetRecordTuple(Napi::Env env, SQLHSTMT hStmt, Column *columns,
|
|
642
|
+
short *colCount, uint16_t *buffer, size_t bufferLength)
|
|
643
|
+
{
|
|
644
|
+
Napi::Object tuple = Napi::Object::New(env);
|
|
645
|
+
|
|
646
|
+
for (int i = 0; i < *colCount; i++)
|
|
647
|
+
{
|
|
648
|
+
#ifdef UNICODE
|
|
649
|
+
tuple.Set(Napi::String::New(env, (char16_t *)columns[i].name),
|
|
650
|
+
GetColumnValue(env, hStmt, columns[i], buffer, bufferLength));
|
|
651
|
+
#else
|
|
652
|
+
tuple.Set(Napi::String::New(env, (const char *)columns[i].name),
|
|
653
|
+
GetColumnValue(env, hStmt, columns[i], buffer, bufferLength));
|
|
654
|
+
#endif
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
return tuple;
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
/*
|
|
661
|
+
* GetRecordArray
|
|
662
|
+
*/
|
|
663
|
+
Napi::Value ODBC::GetRecordArray(Napi::Env env, SQLHSTMT hStmt, Column *columns,
|
|
664
|
+
short *colCount, uint16_t *buffer, size_t bufferLength)
|
|
665
|
+
{
|
|
666
|
+
Napi::Array array = Napi::Array::New(env);
|
|
667
|
+
|
|
668
|
+
for (int i = 0; i < *colCount; i++)
|
|
669
|
+
{
|
|
670
|
+
array.Set(i, GetColumnValue(env, hStmt, columns[i], buffer, bufferLength));
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
return array;
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
/*
|
|
677
|
+
* GetParametersFromArray
|
|
678
|
+
*/
|
|
679
|
+
Parameter *ODBC::GetParametersFromArray(Napi::Env env, Napi::Array values, int *paramCount)
|
|
680
|
+
{
|
|
681
|
+
DEBUG_PRINTF("ODBC::GetParametersFromArray\n");
|
|
682
|
+
*paramCount = values.Length();
|
|
683
|
+
|
|
684
|
+
Parameter *params = (Parameter *)malloc(*paramCount * sizeof(Parameter));
|
|
685
|
+
if (*paramCount != 0 && !params)
|
|
686
|
+
{
|
|
687
|
+
Napi::Error::New(env, "Could not allocate enough memory for params").ThrowAsJavaScriptException();
|
|
688
|
+
return params;
|
|
689
|
+
}
|
|
690
|
+
memset(params, '\0', *paramCount * sizeof(Parameter));
|
|
691
|
+
|
|
692
|
+
for (int i = 0; i < *paramCount; i++)
|
|
693
|
+
{
|
|
694
|
+
Napi::Value value = values.Get(i);
|
|
695
|
+
params[i].paramtype = SQL_PARAM_INPUT;
|
|
696
|
+
params[i].size = 0;
|
|
697
|
+
params[i].length = SQL_NULL_DATA;
|
|
698
|
+
params[i].buffer_length = 0;
|
|
699
|
+
params[i].decimals = 0;
|
|
700
|
+
params[i].isBuffer = false;
|
|
701
|
+
|
|
702
|
+
if (value.IsArray())
|
|
703
|
+
{
|
|
704
|
+
Napi::Array paramArray = value.As<Napi::Array>();
|
|
705
|
+
int arrlen = paramArray.Length();
|
|
706
|
+
if (arrlen < 4)
|
|
707
|
+
{
|
|
708
|
+
Napi::Error::New(env, "Wrong param format!").ThrowAsJavaScriptException();
|
|
709
|
+
return params;
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
Napi::Value val = paramArray.Get((uint32_t)0);
|
|
713
|
+
if (val.IsNumber()) params[i].paramtype = val.As<Napi::Number>().Int32Value();
|
|
714
|
+
|
|
715
|
+
val = paramArray.Get((uint32_t)1);
|
|
716
|
+
if (val.IsNumber()) params[i].c_type = val.As<Napi::Number>().Int32Value();
|
|
717
|
+
else params[i].c_type = SQL_C_CHAR;
|
|
718
|
+
|
|
719
|
+
val = paramArray.Get((uint32_t)2);
|
|
720
|
+
if (val.IsNumber()) params[i].type = val.As<Napi::Number>().Int32Value();
|
|
721
|
+
else params[i].type = SQL_CHAR;
|
|
722
|
+
|
|
723
|
+
if (arrlen == 5)
|
|
724
|
+
{
|
|
725
|
+
val = paramArray.Get((uint32_t)4);
|
|
726
|
+
if (val.IsNumber()) params[i].buffer_length = val.As<Napi::Number>().Int32Value();
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
val = paramArray.Get((uint32_t)3);
|
|
730
|
+
if (params[i].paramtype == DATA_AT_EXEC_PARAM && val.IsArray())
|
|
731
|
+
{
|
|
732
|
+
GetDataAtExecParam(env, val, ¶ms[i], i + 1);
|
|
733
|
+
}
|
|
734
|
+
else if (val.IsNull() || val.IsUndefined())
|
|
735
|
+
{
|
|
736
|
+
GetNullParam(¶ms[i], i + 1);
|
|
737
|
+
}
|
|
738
|
+
else if (val.IsNumber() && !val.IsNull() && params[i].type != 3)
|
|
739
|
+
{
|
|
740
|
+
// Check if integer
|
|
741
|
+
double dval = val.As<Napi::Number>().DoubleValue();
|
|
742
|
+
int32_t ival = val.As<Napi::Number>().Int32Value();
|
|
743
|
+
if (dval == (double)ival && params[i].type != 3)
|
|
744
|
+
GetInt32Param(env, val, ¶ms[i], i + 1);
|
|
745
|
+
else
|
|
746
|
+
GetNumberParam(env, val, ¶ms[i], i + 1);
|
|
747
|
+
}
|
|
748
|
+
else if (val.IsBoolean())
|
|
749
|
+
{
|
|
750
|
+
GetBoolParam(env, val, ¶ms[i], i + 1);
|
|
751
|
+
}
|
|
752
|
+
else if (val.IsArray())
|
|
753
|
+
{
|
|
754
|
+
GetArrayParam(env, val, ¶ms[i], i + 1);
|
|
755
|
+
}
|
|
756
|
+
else if (val.IsBuffer())
|
|
757
|
+
{
|
|
758
|
+
GetBufferParam(val, ¶ms[i], i + 1);
|
|
759
|
+
}
|
|
760
|
+
else
|
|
761
|
+
{
|
|
762
|
+
GetStringParam(env, val, ¶ms[i], i + 1);
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
else if (value.IsBuffer())
|
|
766
|
+
{
|
|
767
|
+
GetBufferParam(value, ¶ms[i], i + 1);
|
|
768
|
+
}
|
|
769
|
+
else if (value.IsString())
|
|
770
|
+
{
|
|
771
|
+
GetStringParam(env, value, ¶ms[i], i + 1);
|
|
772
|
+
}
|
|
773
|
+
else if (value.IsNull() || value.IsUndefined())
|
|
774
|
+
{
|
|
775
|
+
GetNullParam(¶ms[i], i + 1);
|
|
776
|
+
}
|
|
777
|
+
else if (value.IsNumber())
|
|
778
|
+
{
|
|
779
|
+
double dval = value.As<Napi::Number>().DoubleValue();
|
|
780
|
+
int32_t ival = value.As<Napi::Number>().Int32Value();
|
|
781
|
+
if (dval == (double)ival)
|
|
782
|
+
GetInt32Param(env, value, ¶ms[i], i + 1);
|
|
783
|
+
else
|
|
784
|
+
GetNumberParam(env, value, ¶ms[i], i + 1);
|
|
785
|
+
}
|
|
786
|
+
else if (value.IsBoolean())
|
|
787
|
+
{
|
|
788
|
+
GetBoolParam(env, value, ¶ms[i], i + 1);
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
if (env.IsExceptionPending())
|
|
792
|
+
{
|
|
793
|
+
return params;
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
return params;
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
void ODBC::GetStringParam(Napi::Env env, Napi::Value value, Parameter *param, int num)
|
|
800
|
+
{
|
|
801
|
+
int length = 0;
|
|
802
|
+
int bufflen = 0;
|
|
803
|
+
int terCharLen = 1;
|
|
804
|
+
bool isBinary = (param->c_type == SQL_C_BINARY);
|
|
805
|
+
|
|
806
|
+
Napi::String stringValue = value.ToString();
|
|
807
|
+
if (stringValue.IsEmpty())
|
|
808
|
+
{
|
|
809
|
+
return;
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
// Determine string length using encoding that matches NAN behavior:
|
|
813
|
+
// SQL_C_BINARY -> Latin-1 (WriteOneByte), UNICODE -> UTF-16 (Write), else -> UTF-8
|
|
814
|
+
if (isBinary) {
|
|
815
|
+
size_t latin1_len = 0;
|
|
816
|
+
napi_get_value_string_latin1(env, value, NULL, 0, &latin1_len);
|
|
817
|
+
length = (int)latin1_len;
|
|
818
|
+
}
|
|
819
|
+
#ifdef UNICODE
|
|
820
|
+
else {
|
|
821
|
+
size_t utf16_len = 0;
|
|
822
|
+
napi_get_value_string_utf16(env, value, NULL, 0, &utf16_len);
|
|
823
|
+
length = (int)utf16_len;
|
|
824
|
+
}
|
|
825
|
+
#else
|
|
826
|
+
else {
|
|
827
|
+
std::string utf8str = stringValue.Utf8Value();
|
|
828
|
+
length = (int)utf8str.length();
|
|
829
|
+
}
|
|
830
|
+
#endif
|
|
831
|
+
|
|
832
|
+
bufflen = length;
|
|
833
|
+
param->length = length;
|
|
834
|
+
if (!param->c_type || (param->c_type == SQL_CHAR))
|
|
835
|
+
param->c_type = SQL_C_TCHAR;
|
|
836
|
+
#ifdef UNICODE
|
|
837
|
+
param->length = SQL_NTS;
|
|
838
|
+
if (!param->type || (param->type == SQL_CHAR))
|
|
839
|
+
param->type = (length >= 8000) ? SQL_WLONGVARCHAR : SQL_WVARCHAR;
|
|
840
|
+
if (!isBinary)
|
|
841
|
+
bufflen = (length + 1) * sizeof(uint16_t);
|
|
842
|
+
terCharLen = 2;
|
|
843
|
+
#else
|
|
844
|
+
if (!param->type || (param->type == SQL_CHAR))
|
|
845
|
+
param->type = (length >= 8000) ? SQL_LONGVARCHAR : SQL_VARCHAR;
|
|
846
|
+
if (!isBinary)
|
|
847
|
+
{
|
|
848
|
+
std::string utf8str = stringValue.Utf8Value();
|
|
849
|
+
bufflen = (int)utf8str.length() + 1;
|
|
850
|
+
param->length = bufflen - 1;
|
|
851
|
+
}
|
|
852
|
+
#endif
|
|
853
|
+
if (isBinary) { bufflen = length + 1; }
|
|
854
|
+
if (bufflen <= param->buffer_length &&
|
|
855
|
+
((param->paramtype % 2 == 0) || (param->arraySize > 0)))
|
|
856
|
+
{
|
|
857
|
+
bufflen = param->buffer_length + terCharLen;
|
|
858
|
+
}
|
|
859
|
+
param->buffer_length = bufflen;
|
|
860
|
+
param->size = bufflen;
|
|
861
|
+
|
|
862
|
+
param->buffer = malloc(param->buffer_length);
|
|
863
|
+
if (!param->buffer) return;
|
|
864
|
+
memset(param->buffer, 0, param->buffer_length);
|
|
865
|
+
|
|
866
|
+
// Copy string data using correct encoding (matching NAN behavior)
|
|
867
|
+
if (param->paramtype == FILE_PARAM) {
|
|
868
|
+
// FILE_PARAM: use UTF-8 (matches NAN's WriteUtf8)
|
|
869
|
+
std::string utf8str = stringValue.Utf8Value();
|
|
870
|
+
memcpy(param->buffer, utf8str.c_str(), utf8str.length());
|
|
871
|
+
} else if (isBinary) {
|
|
872
|
+
// SQL_C_BINARY: use Latin-1 (matches NAN's WriteOneByte)
|
|
873
|
+
size_t copied = 0;
|
|
874
|
+
napi_get_value_string_latin1(env, value, (char *)param->buffer, param->buffer_length, &copied);
|
|
875
|
+
} else {
|
|
876
|
+
#ifdef UNICODE
|
|
877
|
+
// UNICODE text: use UTF-16 (matches NAN's String::Write)
|
|
878
|
+
size_t copied = 0;
|
|
879
|
+
napi_get_value_string_utf16(env, value, (char16_t *)param->buffer, length + 1, &copied);
|
|
880
|
+
#else
|
|
881
|
+
// Non-UNICODE text: use UTF-8 (matches NAN's WriteUtf8)
|
|
882
|
+
std::string utf8str = stringValue.Utf8Value();
|
|
883
|
+
memcpy(param->buffer, utf8str.c_str(), utf8str.length());
|
|
884
|
+
#endif
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
#ifdef UNICODE
|
|
888
|
+
((char *)param->buffer)[param->buffer_length - 2] = '\0';
|
|
889
|
+
#endif
|
|
890
|
+
((char *)param->buffer)[param->buffer_length - 1] = '\0';
|
|
891
|
+
|
|
892
|
+
if (param->paramtype == FILE_PARAM)
|
|
893
|
+
{
|
|
894
|
+
param->decimals = param->buffer_length;
|
|
895
|
+
param->fileOption = SQL_FILE_READ;
|
|
896
|
+
param->fileIndicator = 0;
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
void ODBC::GetBufferParam(Napi::Value value, Parameter *param, int num)
|
|
901
|
+
{
|
|
902
|
+
Napi::Buffer<char> buffer = value.As<Napi::Buffer<char>>();
|
|
903
|
+
param->buffer = (char *)buffer.Data();
|
|
904
|
+
param->length = buffer.Length();
|
|
905
|
+
int bufflen = param->length;
|
|
906
|
+
param->isBuffer = true;
|
|
907
|
+
|
|
908
|
+
if (bufflen <= param->buffer_length &&
|
|
909
|
+
((param->paramtype % 2 == 0) || (param->arraySize > 0)))
|
|
910
|
+
{
|
|
911
|
+
bufflen = param->buffer_length;
|
|
912
|
+
}
|
|
913
|
+
param->buffer_length = bufflen;
|
|
914
|
+
param->size = bufflen;
|
|
915
|
+
|
|
916
|
+
if (!param->c_type || (param->c_type == SQL_CHAR))
|
|
917
|
+
param->c_type = SQL_C_TCHAR;
|
|
918
|
+
#ifdef UNICODE
|
|
919
|
+
param->length = SQL_NTS;
|
|
920
|
+
if (!param->type || (param->type == SQL_CHAR))
|
|
921
|
+
param->type = (param->length >= 8000) ? SQL_WLONGVARCHAR : SQL_WVARCHAR;
|
|
922
|
+
if (param->c_type != SQL_C_BINARY) param->size /= 2;
|
|
923
|
+
#else
|
|
924
|
+
if (!param->type || (param->type == SQL_CHAR))
|
|
925
|
+
param->type = (param->length >= 8000) ? SQL_LONGVARCHAR : SQL_VARCHAR;
|
|
926
|
+
#endif
|
|
927
|
+
|
|
928
|
+
if (param->paramtype == FILE_PARAM)
|
|
929
|
+
{
|
|
930
|
+
param->decimals = param->buffer_length;
|
|
931
|
+
param->fileOption = SQL_FILE_READ;
|
|
932
|
+
param->fileIndicator = 0;
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
void ODBC::GetDataAtExecParam(Napi::Env env, Napi::Value value, Parameter *param, int num)
|
|
937
|
+
{
|
|
938
|
+
Napi::Array chunkArray = value.As<Napi::Array>();
|
|
939
|
+
int numChunks = chunkArray.Length();
|
|
940
|
+
|
|
941
|
+
if (numChunks == 0)
|
|
942
|
+
{
|
|
943
|
+
Napi::Error::New(env, "DATA_AT_EXEC: Data array must not be empty").ThrowAsJavaScriptException();
|
|
944
|
+
return;
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
param->chunks = (void **)calloc(numChunks, sizeof(void *));
|
|
948
|
+
param->chunkLens = (SQLLEN *)calloc(numChunks, sizeof(SQLLEN));
|
|
949
|
+
if (!param->chunks || !param->chunkLens)
|
|
950
|
+
{
|
|
951
|
+
Napi::Error::New(env, "Failed to allocate chunk arrays for DATA_AT_EXEC").ThrowAsJavaScriptException();
|
|
952
|
+
return;
|
|
953
|
+
}
|
|
954
|
+
param->chunkCount = numChunks;
|
|
955
|
+
|
|
956
|
+
SQLLEN totalSize = 0;
|
|
957
|
+
for (int j = 0; j < numChunks; j++)
|
|
958
|
+
{
|
|
959
|
+
Napi::Value chunk = chunkArray.Get(j);
|
|
960
|
+
if (!chunk.IsBuffer())
|
|
961
|
+
{
|
|
962
|
+
Napi::Error::New(env, "DATA_AT_EXEC: each element in Data array must be a Buffer").ThrowAsJavaScriptException();
|
|
963
|
+
return;
|
|
964
|
+
}
|
|
965
|
+
Napi::Buffer<char> buf = chunk.As<Napi::Buffer<char>>();
|
|
966
|
+
param->chunks[j] = buf.Data();
|
|
967
|
+
param->chunkLens[j] = (SQLLEN)buf.Length();
|
|
968
|
+
totalSize += param->chunkLens[j];
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
if (param->buffer_length > 0)
|
|
972
|
+
param->size = param->buffer_length;
|
|
973
|
+
else
|
|
974
|
+
param->size = totalSize;
|
|
975
|
+
|
|
976
|
+
param->buffer = NULL;
|
|
977
|
+
param->buffer_length = 0;
|
|
978
|
+
param->length = SQL_LEN_DATA_AT_EXEC((SQLLEN)param->size);
|
|
979
|
+
param->isBuffer = true;
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
void ODBC::GetNullParam(Parameter *param, int num)
|
|
983
|
+
{
|
|
984
|
+
param->c_type = param->c_type ? param->c_type : SQL_C_DEFAULT;
|
|
985
|
+
param->type = param->type ? param->type : SQL_VARCHAR;
|
|
986
|
+
param->length = SQL_NULL_DATA;
|
|
987
|
+
|
|
988
|
+
if (param->paramtype % 2 == 0)
|
|
989
|
+
{
|
|
990
|
+
if (param->type == SQL_BIGINT || param->type == SQL_INTEGER ||
|
|
991
|
+
param->type == SQL_BOOLEAN || param->type == SQL_SMALLINT ||
|
|
992
|
+
param->type == SQL_TINYINT)
|
|
993
|
+
{
|
|
994
|
+
param->buffer = new int64_t(0);
|
|
995
|
+
}
|
|
996
|
+
else if (param->type == SQL_DECIMAL || param->type == SQL_DOUBLE ||
|
|
997
|
+
param->type == SQL_REAL || param->type == SQL_FLOAT ||
|
|
998
|
+
param->type == SQL_NUMERIC || param->type == SQL_DECFLOAT)
|
|
999
|
+
{
|
|
1000
|
+
param->buffer = new double(0);
|
|
1001
|
+
}
|
|
1002
|
+
else if (param->buffer_length > 0)
|
|
1003
|
+
{
|
|
1004
|
+
param->buffer = malloc(param->buffer_length);
|
|
1005
|
+
}
|
|
1006
|
+
else
|
|
1007
|
+
param->buffer = malloc(8);
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
void ODBC::GetInt32Param(Napi::Env env, Napi::Value value, Parameter *param, int num)
|
|
1012
|
+
{
|
|
1013
|
+
int64_t *number = new int64_t(value.As<Napi::Number>().Int32Value());
|
|
1014
|
+
param->c_type = SQL_C_SBIGINT;
|
|
1015
|
+
if (!param->type || (param->type == 1)) param->type = SQL_BIGINT;
|
|
1016
|
+
param->buffer = number;
|
|
1017
|
+
param->length = sizeof(number);
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
void ODBC::GetNumberParam(Napi::Env env, Napi::Value value, Parameter *param, int num)
|
|
1021
|
+
{
|
|
1022
|
+
double *number = new double(value.As<Napi::Number>().DoubleValue());
|
|
1023
|
+
std::string string = value.ToString().Utf8Value();
|
|
1024
|
+
int length = (int)string.length();
|
|
1025
|
+
char *ptr = strchr((char *)string.c_str(), '.');
|
|
1026
|
+
|
|
1027
|
+
if (!param->c_type || (param->c_type == SQL_C_CHAR)) param->c_type = SQL_C_DOUBLE;
|
|
1028
|
+
if (!param->type || (param->type == SQL_CHAR)) param->type = SQL_DECIMAL;
|
|
1029
|
+
param->buffer = number;
|
|
1030
|
+
param->buffer_length = sizeof(double);
|
|
1031
|
+
param->length = param->buffer_length;
|
|
1032
|
+
param->size = sizeof(double);
|
|
1033
|
+
if (ptr)
|
|
1034
|
+
{
|
|
1035
|
+
param->decimals = length - (ptr - string.c_str()) - 1;
|
|
1036
|
+
if (param->type == SQL_DECIMAL) param->size = length - 1;
|
|
1037
|
+
}
|
|
1038
|
+
else
|
|
1039
|
+
{
|
|
1040
|
+
param->decimals = 0;
|
|
1041
|
+
if (param->type == SQL_DECIMAL) param->size = length;
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
1044
|
+
|
|
1045
|
+
void ODBC::GetBoolParam(Napi::Env env, Napi::Value value, Parameter *param, int num)
|
|
1046
|
+
{
|
|
1047
|
+
bool boolean = value.As<Napi::Boolean>().Value();
|
|
1048
|
+
int64_t *number = new int64_t(boolean ? 1 : 0);
|
|
1049
|
+
param->c_type = SQL_C_SBIGINT;
|
|
1050
|
+
if (!param->type || (param->type == 1)) param->type = SQL_BIGINT;
|
|
1051
|
+
param->buffer = number;
|
|
1052
|
+
param->length = sizeof(number);
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
void ODBC::GetArrayParam(Napi::Env env, Napi::Value value, Parameter *param, int num)
|
|
1056
|
+
{
|
|
1057
|
+
Napi::Array valueArray = value.As<Napi::Array>();
|
|
1058
|
+
int arrlen = valueArray.Length();
|
|
1059
|
+
|
|
1060
|
+
param->arraySize = arrlen;
|
|
1061
|
+
if (arrlen <= 0)
|
|
1062
|
+
{
|
|
1063
|
+
param->buffer = new int[0];
|
|
1064
|
+
return;
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
param->strLenArray = new SQLINTEGER[arrlen];
|
|
1068
|
+
|
|
1069
|
+
for (int j = 0; j < arrlen; j++)
|
|
1070
|
+
{
|
|
1071
|
+
Napi::Value val = valueArray.Get(j);
|
|
1072
|
+
if (val.IsNull() || val.IsUndefined())
|
|
1073
|
+
{
|
|
1074
|
+
param->strLenArray[j] = SQL_NULL_DATA;
|
|
1075
|
+
if (j == arrlen - 1)
|
|
1076
|
+
{
|
|
1077
|
+
GetNullParam(param, num);
|
|
1078
|
+
param->buffer = new int[arrlen];
|
|
1079
|
+
}
|
|
1080
|
+
continue;
|
|
1081
|
+
}
|
|
1082
|
+
else if (val.IsNumber())
|
|
1083
|
+
{
|
|
1084
|
+
double dval = val.As<Napi::Number>().DoubleValue();
|
|
1085
|
+
int32_t ival = val.As<Napi::Number>().Int32Value();
|
|
1086
|
+
if (dval == (double)ival && param->type != 3)
|
|
1087
|
+
{
|
|
1088
|
+
int64_t *number = new int64_t[arrlen];
|
|
1089
|
+
for (int i = j; i < arrlen; i++)
|
|
1090
|
+
{
|
|
1091
|
+
if (i != j)
|
|
1092
|
+
{
|
|
1093
|
+
val = valueArray.Get(i);
|
|
1094
|
+
if (val.IsNull() || val.IsUndefined()) { param->strLenArray[i] = SQL_NULL_DATA; continue; }
|
|
1095
|
+
}
|
|
1096
|
+
number[i] = val.As<Napi::Number>().Int64Value();
|
|
1097
|
+
param->strLenArray[i] = sizeof(int64_t);
|
|
1098
|
+
}
|
|
1099
|
+
param->c_type = SQL_C_SBIGINT;
|
|
1100
|
+
if (!param->type || (param->type == 1)) param->type = SQL_BIGINT;
|
|
1101
|
+
param->buffer = number;
|
|
1102
|
+
}
|
|
1103
|
+
else
|
|
1104
|
+
{
|
|
1105
|
+
double *number = new double[arrlen];
|
|
1106
|
+
int decimals = 0;
|
|
1107
|
+
for (int i = j; i < arrlen; i++)
|
|
1108
|
+
{
|
|
1109
|
+
if (i != j)
|
|
1110
|
+
{
|
|
1111
|
+
val = valueArray.Get(i);
|
|
1112
|
+
if (val.IsNull() || val.IsUndefined()) { param->strLenArray[i] = SQL_NULL_DATA; continue; }
|
|
1113
|
+
}
|
|
1114
|
+
GetNumberParam(env, val, param, num);
|
|
1115
|
+
number[i] = *(double *)param->buffer;
|
|
1116
|
+
param->strLenArray[i] = param->length;
|
|
1117
|
+
delete (double *)param->buffer;
|
|
1118
|
+
param->buffer = NULL;
|
|
1119
|
+
decimals = (decimals < param->decimals) ? param->decimals : decimals;
|
|
1120
|
+
}
|
|
1121
|
+
param->decimals = decimals;
|
|
1122
|
+
param->buffer = number;
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
else if (val.IsBoolean())
|
|
1126
|
+
{
|
|
1127
|
+
int64_t *boolean = new int64_t[arrlen];
|
|
1128
|
+
for (int i = j; i < arrlen; i++)
|
|
1129
|
+
{
|
|
1130
|
+
if (i != j)
|
|
1131
|
+
{
|
|
1132
|
+
val = valueArray.Get(i);
|
|
1133
|
+
if (val.IsNull() || val.IsUndefined()) { param->strLenArray[i] = SQL_NULL_DATA; continue; }
|
|
1134
|
+
}
|
|
1135
|
+
GetBoolParam(env, val, param, num);
|
|
1136
|
+
boolean[i] = *(int64_t *)(param->buffer);
|
|
1137
|
+
param->strLenArray[i] = (SQLINTEGER)param->length;
|
|
1138
|
+
delete (int64_t *)param->buffer;
|
|
1139
|
+
param->buffer = NULL;
|
|
1140
|
+
}
|
|
1141
|
+
param->buffer = boolean;
|
|
1142
|
+
}
|
|
1143
|
+
else
|
|
1144
|
+
{
|
|
1145
|
+
SQLPOINTER *buff = (SQLPOINTER *)NULL;
|
|
1146
|
+
SQLULEN bufflen = 0;
|
|
1147
|
+
SQLULEN cbValueMax = 0;
|
|
1148
|
+
|
|
1149
|
+
SQLPOINTER *elemBufs = new SQLPOINTER[arrlen]();
|
|
1150
|
+
SQLULEN *elemLens = new SQLULEN[arrlen]();
|
|
1151
|
+
SQLLEN *elemDataLens = new SQLLEN[arrlen]();
|
|
1152
|
+
bool *elemIsBuf = new bool[arrlen]();
|
|
1153
|
+
|
|
1154
|
+
for (int i = j; i < arrlen; i++)
|
|
1155
|
+
{
|
|
1156
|
+
if (i != j)
|
|
1157
|
+
{
|
|
1158
|
+
val = valueArray.Get(i);
|
|
1159
|
+
if (val.IsNull() || val.IsUndefined()) { param->strLenArray[i] = SQL_NULL_DATA; continue; }
|
|
1160
|
+
}
|
|
1161
|
+
if (val.IsBuffer())
|
|
1162
|
+
{
|
|
1163
|
+
GetBufferParam(val, param, num);
|
|
1164
|
+
}
|
|
1165
|
+
else
|
|
1166
|
+
{
|
|
1167
|
+
GetStringParam(env, val, param, num);
|
|
1168
|
+
if (env.IsExceptionPending()) break;
|
|
1169
|
+
#ifdef UNICODE
|
|
1170
|
+
param->buffer_length -= 2;
|
|
1171
|
+
#else
|
|
1172
|
+
param->buffer_length -= 1;
|
|
1173
|
+
#endif
|
|
1174
|
+
}
|
|
1175
|
+
elemBufs[i] = param->buffer;
|
|
1176
|
+
elemLens[i] = param->buffer_length;
|
|
1177
|
+
elemDataLens[i] = param->length;
|
|
1178
|
+
elemIsBuf[i] = param->isBuffer;
|
|
1179
|
+
param->buffer = NULL;
|
|
1180
|
+
|
|
1181
|
+
if ((SQLULEN)param->buffer_length > cbValueMax)
|
|
1182
|
+
cbValueMax = (SQLULEN)param->buffer_length;
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
bufflen = (SQLULEN)arrlen * cbValueMax;
|
|
1186
|
+
buff = (SQLPOINTER *)malloc(bufflen);
|
|
1187
|
+
memset(buff, 0, bufflen);
|
|
1188
|
+
|
|
1189
|
+
for (int i = j; i < arrlen; i++)
|
|
1190
|
+
{
|
|
1191
|
+
if (elemBufs[i] == NULL) continue;
|
|
1192
|
+
SQLULEN copyLen = cbValueMax;
|
|
1193
|
+
if (copyLen > (SQLULEN)elemDataLens[i]) copyLen = (SQLULEN)elemDataLens[i];
|
|
1194
|
+
memcpy((char *)buff + (SQLULEN)i * cbValueMax, elemBufs[i], copyLen);
|
|
1195
|
+
param->strLenArray[i] = (SQLINTEGER)copyLen;
|
|
1196
|
+
if (!elemIsBuf[i]) FREE(elemBufs[i]);
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
delete[] elemBufs;
|
|
1200
|
+
delete[] elemLens;
|
|
1201
|
+
delete[] elemDataLens;
|
|
1202
|
+
delete[] elemIsBuf;
|
|
1203
|
+
|
|
1204
|
+
param->buffer = buff;
|
|
1205
|
+
param->buffer_length = cbValueMax;
|
|
1206
|
+
param->size = cbValueMax;
|
|
1207
|
+
}
|
|
1208
|
+
break;
|
|
1209
|
+
}
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1212
|
+
SQLRETURN ODBC::BindParameters(SQLHSTMT hSTMT, Parameter params[], int count)
|
|
1213
|
+
{
|
|
1214
|
+
SQLRETURN ret = SQL_SUCCESS;
|
|
1215
|
+
Parameter prm;
|
|
1216
|
+
|
|
1217
|
+
for (int i = 0; i < count; i++)
|
|
1218
|
+
{
|
|
1219
|
+
prm = params[i];
|
|
1220
|
+
|
|
1221
|
+
if (prm.paramtype == FILE_PARAM)
|
|
1222
|
+
{
|
|
1223
|
+
ret = SQLBindFileToParam(hSTMT, i + 1, prm.type, (SQLCHAR *)prm.buffer,
|
|
1224
|
+
NULL, ¶ms[i].fileOption, prm.decimals, ¶ms[i].fileIndicator);
|
|
1225
|
+
}
|
|
1226
|
+
else if (prm.paramtype == DATA_AT_EXEC_PARAM)
|
|
1227
|
+
{
|
|
1228
|
+
ret = SQLBindParameter(hSTMT, i + 1, SQL_PARAM_INPUT, prm.c_type, prm.type,
|
|
1229
|
+
prm.size, 0, (SQLPOINTER)(intptr_t)(i + 1), 0, ¶ms[i].length);
|
|
1230
|
+
}
|
|
1231
|
+
else if (prm.arraySize > 0)
|
|
1232
|
+
{
|
|
1233
|
+
ret = SQLBindParameter(hSTMT, i + 1, prm.paramtype, prm.c_type, prm.type,
|
|
1234
|
+
prm.size, prm.decimals, prm.buffer, prm.buffer_length, prm.strLenArray);
|
|
1235
|
+
}
|
|
1236
|
+
else
|
|
1237
|
+
{
|
|
1238
|
+
ret = SQLBindParameter(hSTMT, i + 1, prm.paramtype, prm.c_type, prm.type,
|
|
1239
|
+
prm.size, prm.decimals, prm.buffer, prm.buffer_length, ¶ms[i].length);
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1242
|
+
if (ret == SQL_ERROR) break;
|
|
1243
|
+
}
|
|
1244
|
+
return ret;
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1247
|
+
SQLRETURN ODBC::PutDataLoop(SQLHSTMT hSTMT, Parameter params[], int count)
|
|
1248
|
+
{
|
|
1249
|
+
SQLRETURN ret;
|
|
1250
|
+
SQLPOINTER token;
|
|
1251
|
+
|
|
1252
|
+
DEBUG_PRINTF("ODBC::PutDataLoop - Entry\n");
|
|
1253
|
+
|
|
1254
|
+
while ((ret = SQLParamData(hSTMT, &token)) == SQL_NEED_DATA)
|
|
1255
|
+
{
|
|
1256
|
+
int paramIdx = (int)(intptr_t)token - 1;
|
|
1257
|
+
|
|
1258
|
+
if (paramIdx < 0 || paramIdx >= count ||
|
|
1259
|
+
params[paramIdx].chunks == NULL || params[paramIdx].chunkCount == 0)
|
|
1260
|
+
{
|
|
1261
|
+
return SQL_ERROR;
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
for (int j = 0; j < params[paramIdx].chunkCount; j++)
|
|
1265
|
+
{
|
|
1266
|
+
ret = SQLPutData(hSTMT, params[paramIdx].chunks[j], params[paramIdx].chunkLens[j]);
|
|
1267
|
+
if (!SQL_SUCCEEDED(ret)) return ret;
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1271
|
+
DEBUG_PRINTF("ODBC::PutDataLoop - Exit, ret=%d\n", ret);
|
|
1272
|
+
return ret;
|
|
1273
|
+
}
|
|
1274
|
+
|
|
1275
|
+
/*
|
|
1276
|
+
* CallbackSQLError
|
|
1277
|
+
*/
|
|
1278
|
+
Napi::Value ODBC::CallbackSQLError(Napi::Env env, SQLSMALLINT handleType,
|
|
1279
|
+
SQLHANDLE handle, Napi::FunctionReference *cb)
|
|
1280
|
+
{
|
|
1281
|
+
return CallbackSQLError(env, handleType, handle, (char *)"[node-ibm_db] SQL_ERROR", cb);
|
|
1282
|
+
}
|
|
1283
|
+
|
|
1284
|
+
Napi::Value ODBC::CallbackSQLError(Napi::Env env, SQLSMALLINT handleType,
|
|
1285
|
+
SQLHANDLE handle, char *message,
|
|
1286
|
+
Napi::FunctionReference *cb)
|
|
1287
|
+
{
|
|
1288
|
+
Napi::Value objError = ODBC::GetSQLError(env, handleType, handle, message);
|
|
1289
|
+
cb->Call({objError});
|
|
1290
|
+
return env.Undefined();
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1293
|
+
/*
|
|
1294
|
+
* GetSQLError
|
|
1295
|
+
*/
|
|
1296
|
+
Napi::Value ODBC::GetSQLError(Napi::Env env, SQLSMALLINT handleType, SQLHANDLE handle)
|
|
1297
|
+
{
|
|
1298
|
+
return GetSQLError(env, handleType, handle, (char *)"[ibm_db] SQL_ERROR");
|
|
1299
|
+
}
|
|
1300
|
+
|
|
1301
|
+
Napi::Value ODBC::GetSQLError(Napi::Env env, SQLSMALLINT handleType,
|
|
1302
|
+
SQLHANDLE handle, char *message)
|
|
1303
|
+
{
|
|
1304
|
+
DEBUG_PRINTF("ODBC::GetSQLError : handleType=%i, handle=0x%llx\n", handleType, HandleToLogValue(handle));
|
|
1305
|
+
|
|
1306
|
+
SQLINTEGER i = 0;
|
|
1307
|
+
SQLINTEGER native;
|
|
1308
|
+
SQLSMALLINT len;
|
|
1309
|
+
SQLRETURN ret;
|
|
1310
|
+
char errorSQLState[14];
|
|
1311
|
+
char errorMessage[SQL_MAX_MESSAGE_LENGTH];
|
|
1312
|
+
errorMessage[0] = '\0';
|
|
1313
|
+
errorSQLState[0] = '\0';
|
|
1314
|
+
native = 0;
|
|
1315
|
+
|
|
1316
|
+
ret = SQLGetDiagRec(handleType, handle, 1,
|
|
1317
|
+
(SQLTCHAR *)errorSQLState, &native,
|
|
1318
|
+
(SQLTCHAR *)errorMessage, sizeof(errorMessage), &len);
|
|
1319
|
+
|
|
1320
|
+
if (ret == -2)
|
|
1321
|
+
{
|
|
1322
|
+
strcpy(errorMessage, "CLI0600E Invalid connection handle or connection is closed. SQLSTATE=S1000");
|
|
1323
|
+
strcpy(errorSQLState, "S1000");
|
|
1324
|
+
native = -1;
|
|
1325
|
+
}
|
|
1326
|
+
|
|
1327
|
+
// Create a proper Error object so that (err instanceof Error) === true
|
|
1328
|
+
#ifdef UNICODE
|
|
1329
|
+
Napi::Error error = Napi::Error::New(env, Napi::String::New(env, (char16_t *)errorMessage));
|
|
1330
|
+
#else
|
|
1331
|
+
Napi::Error error = Napi::Error::New(env, Napi::String::New(env, errorMessage));
|
|
1332
|
+
#endif
|
|
1333
|
+
Napi::Object objError = error.Value();
|
|
1334
|
+
objError.Set("error", Napi::String::New(env, message));
|
|
1335
|
+
objError.Set("sqlcode", Napi::Number::New(env, (double)native));
|
|
1336
|
+
#ifdef UNICODE
|
|
1337
|
+
objError.Set("sqlstate", Napi::String::New(env, (char16_t *)errorSQLState));
|
|
1338
|
+
#else
|
|
1339
|
+
objError.Set("sqlstate", Napi::String::New(env, errorSQLState));
|
|
1340
|
+
#endif
|
|
1341
|
+
|
|
1342
|
+
return objError;
|
|
1343
|
+
}
|
|
1344
|
+
|
|
1345
|
+
/*
|
|
1346
|
+
* GetAllRecordsSync
|
|
1347
|
+
*/
|
|
1348
|
+
Napi::Array ODBC::GetAllRecordsSync(Napi::Env env, SQLHENV hENV, SQLHDBC hDBC,
|
|
1349
|
+
SQLHSTMT hSTMT, uint16_t *buffer, size_t bufferLength)
|
|
1350
|
+
{
|
|
1351
|
+
DEBUG_PRINTF("ODBC::GetAllRecordsSync\n");
|
|
1352
|
+
|
|
1353
|
+
int count = 0;
|
|
1354
|
+
short colCount = 0;
|
|
1355
|
+
Column *columns = GetColumns(hSTMT, &colCount);
|
|
1356
|
+
Napi::Array rows = Napi::Array::New(env);
|
|
1357
|
+
|
|
1358
|
+
while (true)
|
|
1359
|
+
{
|
|
1360
|
+
SQLRETURN ret = SQLFetch(hSTMT);
|
|
1361
|
+
|
|
1362
|
+
if (ret == SQL_ERROR)
|
|
1363
|
+
{
|
|
1364
|
+
// error - break and return what we have
|
|
1365
|
+
break;
|
|
1366
|
+
}
|
|
1367
|
+
if (ret == SQL_NO_DATA) break;
|
|
1368
|
+
|
|
1369
|
+
rows.Set(count, ODBC::GetRecordTuple(env, hSTMT, columns, &colCount, buffer, bufferLength));
|
|
1370
|
+
count++;
|
|
1371
|
+
}
|
|
1372
|
+
ODBC::FreeColumns(columns, &colCount);
|
|
1373
|
+
return rows;
|
|
1374
|
+
}
|
|
1375
|
+
|
|
1376
|
+
#ifdef _AIX
|
|
1377
|
+
// On AIX, GCC's _GLOBAL__FD_node calls __cxa_finalize(NULL) during exit()
|
|
1378
|
+
// which crashes with SIGILL (jump to 0x0) because libdb2's __cxa_atexit
|
|
1379
|
+
// handlers become invalid. We install a SIGILL handler at module load time
|
|
1380
|
+
// so it is in place before any exit path runs module finalization.
|
|
1381
|
+
// Note: atexit() runs AFTER __modfini64 on AIX, and env cleanup hooks
|
|
1382
|
+
// are skipped by process.exit(), so neither approach works alone.
|
|
1383
|
+
// Installing at load time covers all exit paths. (#439, #1045)
|
|
1384
|
+
static void AIX_SigillHandler(int sig)
|
|
1385
|
+
{
|
|
1386
|
+
_exit(0);
|
|
1387
|
+
}
|
|
1388
|
+
|
|
1389
|
+
// GSKit v9.x throws C++ exceptions (gsk09000006::GSKException) from internal
|
|
1390
|
+
// threads during SSL handshake failures. Since those threads have no exception
|
|
1391
|
+
// handler, std::terminate() is called, leading to abort() and coredump.
|
|
1392
|
+
// We install a custom terminate handler to convert this to a graceful exit
|
|
1393
|
+
// with an error message instead of a coredump.
|
|
1394
|
+
static std::terminate_handler g_oldTerminateHandler = nullptr;
|
|
1395
|
+
|
|
1396
|
+
// Helper to demangle C++ type names
|
|
1397
|
+
static const char* DemangleTypeName(const char* mangledName)
|
|
1398
|
+
{
|
|
1399
|
+
int status = 0;
|
|
1400
|
+
char* demangled = abi::__cxa_demangle(mangledName, nullptr, nullptr, &status);
|
|
1401
|
+
if (status == 0 && demangled) {
|
|
1402
|
+
return demangled; // Caller should free this
|
|
1403
|
+
}
|
|
1404
|
+
return mangledName;
|
|
1405
|
+
}
|
|
1406
|
+
|
|
1407
|
+
static void AIX_TerminateHandler()
|
|
1408
|
+
{
|
|
1409
|
+
// Try to get exception info
|
|
1410
|
+
std::exception_ptr eptr = std::current_exception();
|
|
1411
|
+
if (eptr) {
|
|
1412
|
+
try {
|
|
1413
|
+
std::rethrow_exception(eptr);
|
|
1414
|
+
} catch (const std::exception& e) {
|
|
1415
|
+
fprintf(stderr, "[ibm_db] GSKit SSL exception: %s\n", e.what());
|
|
1416
|
+
} catch (...) {
|
|
1417
|
+
// Try to get the exception type using GCC's internal ABI
|
|
1418
|
+
std::type_info* ti = abi::__cxa_current_exception_type();
|
|
1419
|
+
if (ti) {
|
|
1420
|
+
const char* typeName = DemangleTypeName(ti->name());
|
|
1421
|
+
fprintf(stderr, "\n[ibm_db] ERROR: GSKit v9.x SSL connection failed.\n");
|
|
1422
|
+
fprintf(stderr, "Exception type: %s\n\n", typeName);
|
|
1423
|
+
fprintf(stderr, "This is a known incompatibility between GSKit v9.x (compiled with IBM XLC)\n");
|
|
1424
|
+
fprintf(stderr, "and GCC-compiled applications like Node.js on AIX. GSKit v9 throws C++\n");
|
|
1425
|
+
fprintf(stderr, "exceptions from internal threads using XLC's exception handling ABI,\n");
|
|
1426
|
+
fprintf(stderr, "which is incompatible with GCC's libstdc++ runtime.\n\n");
|
|
1427
|
+
fprintf(stderr, "SOLUTION: Use a Db2 CLI driver (clidriver) that includes GSKit v8.x instead\n");
|
|
1428
|
+
fprintf(stderr, "of GSKit v9.x. GSKit v8.x does not have this incompatibility.\n\n");
|
|
1429
|
+
fprintf(stderr, "Db2 client from version 12.1.5.0 onwards comes with GSKit v9.x library.\n");
|
|
1430
|
+
fprintf(stderr, "Use an older Db2 CLI driver (clidriver) to avoid this issue.\n\n");
|
|
1431
|
+
fprintf(stderr, "To check your GSKit version:\n");
|
|
1432
|
+
fprintf(stderr, " ls $IBM_DB_HOME/lib/icc/libgsk*.so\n");
|
|
1433
|
+
fprintf(stderr, " - libgsk8*.so = GSKit v8 (compatible)\n");
|
|
1434
|
+
fprintf(stderr, " - libgsk9*.so = GSKit v9 (incompatible with GCC-compiled Node.js)\n\n");
|
|
1435
|
+
} else {
|
|
1436
|
+
fprintf(stderr, "[ibm_db] GSKit SSL exception (unknown type)\n");
|
|
1437
|
+
}
|
|
1438
|
+
}
|
|
1439
|
+
} else {
|
|
1440
|
+
fprintf(stderr, "[ibm_db] Terminate called without active exception\n");
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1443
|
+
// Exit without coredump - use _exit to avoid running atexit handlers
|
|
1444
|
+
// which could cause additional crashes
|
|
1445
|
+
_exit(1);
|
|
1446
|
+
}
|
|
1447
|
+
|
|
1448
|
+
// SIGABRT handler as a fallback - catches abort() calls from GSKit threads
|
|
1449
|
+
static void AIX_SigabrtHandler(int sig)
|
|
1450
|
+
{
|
|
1451
|
+
fprintf(stderr, "\n[ibm_db] ERROR: SIGABRT received - GSKit v9.x SSL connection failed.\n\n");
|
|
1452
|
+
fprintf(stderr, "This is a known incompatibility between GSKit v9.x and GCC-compiled\n");
|
|
1453
|
+
fprintf(stderr, "Node.js on AIX. Use a clidriver older than v12.1.5.0 instead.\n\n");
|
|
1454
|
+
fprintf(stderr, "Check: ls $IBM_DB_HOME/lib/icc/libgsk*.so\n");
|
|
1455
|
+
fprintf(stderr, " - libgsk8*.so = GSKit v8 (compatible)\n");
|
|
1456
|
+
fprintf(stderr, " - libgsk9*.so = GSKit v9 (incompatible)\n\n");
|
|
1457
|
+
_exit(1);
|
|
1458
|
+
}
|
|
1459
|
+
#endif
|
|
1460
|
+
|
|
1461
|
+
// Module initialization
|
|
1462
|
+
Napi::Object InitAll(Napi::Env env, Napi::Object exports)
|
|
1463
|
+
{
|
|
1464
|
+
ODBC::Init(env, exports);
|
|
1465
|
+
ODBCResult::Init(env, exports);
|
|
1466
|
+
ODBCConnection::Init(env, exports);
|
|
1467
|
+
ODBCStatement::Init(env, exports);
|
|
1468
|
+
|
|
1469
|
+
#ifdef _AIX
|
|
1470
|
+
// Install custom terminate handler to catch GSKit v9.x exceptions thrown
|
|
1471
|
+
// from internal threads. This converts coredumps to graceful error exits.
|
|
1472
|
+
g_oldTerminateHandler = std::set_terminate(AIX_TerminateHandler);
|
|
1473
|
+
|
|
1474
|
+
// Install SIGABRT handler as fallback for abort() calls
|
|
1475
|
+
struct sigaction sa_abrt;
|
|
1476
|
+
memset(&sa_abrt, 0, sizeof(sa_abrt));
|
|
1477
|
+
sa_abrt.sa_handler = AIX_SigabrtHandler;
|
|
1478
|
+
sigemptyset(&sa_abrt.sa_mask);
|
|
1479
|
+
sa_abrt.sa_flags = 0;
|
|
1480
|
+
sigaction(SIGABRT, &sa_abrt, NULL);
|
|
1481
|
+
|
|
1482
|
+
// Install SIGILL handler early — must be in place before exit() triggers
|
|
1483
|
+
// __modfini64 → _GLOBAL__FD_node → __cxa_finalize(NULL) crash.
|
|
1484
|
+
struct sigaction sa;
|
|
1485
|
+
memset(&sa, 0, sizeof(sa));
|
|
1486
|
+
sa.sa_handler = AIX_SigillHandler;
|
|
1487
|
+
sigemptyset(&sa.sa_mask);
|
|
1488
|
+
sa.sa_flags = 0;
|
|
1489
|
+
sigaction(SIGILL, &sa, NULL);
|
|
1490
|
+
#endif
|
|
1491
|
+
|
|
1492
|
+
return exports;
|
|
1493
|
+
}
|
|
1494
|
+
|
|
1495
|
+
NODE_API_MODULE(odbc_bindings, InitAll)
|