@miatechnet/node-odbc 2.4.10-multiresult.1

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/src/odbc.h ADDED
@@ -0,0 +1,362 @@
1
+ /*
2
+ Copyright (c) 2019, 2021 IBM
3
+ Copyright (c) 2013, Dan VerWeire <dverweire@gmail.com>
4
+ Copyright (c) 2010, Lee Smith <notwink@gmail.com>
5
+
6
+ Permission to use, copy, modify, and/or distribute this software for any
7
+ purpose with or without fee is hereby granted, provided that the above
8
+ copyright notice and this permission notice appear in all copies.
9
+
10
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
+ */
18
+
19
+ #if defined(UNICODE) && !defined(_WIN32)
20
+ #error "UNICODE builds only supported on Windows"
21
+ #endif
22
+
23
+ #ifndef _SRC_ODBC_H
24
+ #define _SRC_ODBC_H
25
+
26
+ #include <uv.h>
27
+ #include <napi.h>
28
+ #include <wchar.h>
29
+ #include <new>
30
+
31
+ #include <algorithm>
32
+
33
+ #include <stdlib.h>
34
+ #ifdef dynodbc
35
+ #include "dynodbc.h"
36
+ #else
37
+ #include <sql.h>
38
+ #include <sqlext.h>
39
+ #endif
40
+
41
+ #define MAX_FIELD_SIZE 1024
42
+ #define MAX_VALUE_SIZE 1048576
43
+
44
+ #ifdef UNICODE
45
+ #define ERROR_MESSAGE_BUFFER_BYTES 2048
46
+ #define ERROR_MESSAGE_BUFFER_CHARS 1024
47
+ #else
48
+ #define ERROR_MESSAGE_BUFFER_BYTES 2048
49
+ #define ERROR_MESSAGE_BUFFER_CHARS 2048
50
+ #endif
51
+
52
+ #define FETCH_ARRAY 3
53
+ #define FETCH_OBJECT 4
54
+ #define SQL_DESTROY 9999
55
+
56
+ #define IGNORED_PARAMETER 0
57
+
58
+ typedef struct ODBCError {
59
+ SQLTCHAR state[6];
60
+ SQLINTEGER code;
61
+ SQLTCHAR *message;
62
+ } ODBCError;
63
+
64
+ typedef struct GetDataExtensionsSupport {
65
+ bool any_column;
66
+ bool any_order;
67
+ bool block;
68
+ bool bound;
69
+ bool output_params;
70
+ } GetDataExtensionsSupport;
71
+
72
+ typedef struct GetInfoResults {
73
+ SQLSMALLINT max_column_name_length;
74
+ GetDataExtensionsSupport sql_get_data_supports;
75
+ SQLUINTEGER available_isolation_levels;
76
+ } GetInfoResults;
77
+
78
+ typedef struct ConnectionOptions {
79
+ unsigned int connectionTimeout;
80
+ unsigned int loginTimeout;
81
+ bool fetchArray;
82
+ } ConnectionOptions;
83
+
84
+ typedef struct Column {
85
+ SQLUSMALLINT index;
86
+ SQLTCHAR *ColumnName = NULL;
87
+ SQLSMALLINT BufferLength;
88
+ SQLSMALLINT NameLength;
89
+ SQLSMALLINT DataType;
90
+ SQLULEN ColumnSize;
91
+ SQLSMALLINT DecimalDigits;
92
+ SQLLEN StrLen_or_IndPtr;
93
+ SQLSMALLINT Nullable;
94
+ // data used when binding to the column
95
+ SQLSMALLINT bind_type; // when unraveling ColumnData
96
+ SQLLEN buffer_size; // size of the buffer bound
97
+ bool is_long_data; // set to true if data type is SQL_(W)LONG*
98
+ } Column;
99
+
100
+ typedef struct ColumnBuffer {
101
+ SQLPOINTER buffer;
102
+ SQLLEN *length_or_indicator_array;
103
+ } ColumnBuffer;
104
+
105
+ typedef struct BindData {
106
+ SQLLEN string_length_or_indicator;
107
+ SQLPOINTER data;
108
+ } BindData;
109
+
110
+ // Amalgamation of the information returned by SQLDescribeParam and
111
+ // SQLProcedureColumns as well as the information needed by SQLBindParameter
112
+ typedef struct Parameter {
113
+ SQLSMALLINT InputOutputType; // returned by SQLProcedureColumns
114
+ SQLSMALLINT ValueType;
115
+ SQLSMALLINT ParameterType;
116
+ SQLULEN ColumnSize;
117
+ SQLSMALLINT DecimalDigits;
118
+ SQLPOINTER ParameterValuePtr;
119
+ SQLLEN BufferLength;
120
+ SQLLEN StrLen_or_IndPtr;
121
+ SQLSMALLINT Nullable;
122
+ bool isbigint;
123
+ } Parameter;
124
+
125
+ typedef struct ColumnData {
126
+ SQLSMALLINT bind_type;
127
+ bool use_free;
128
+ union {
129
+ SQLCHAR *char_data;
130
+ SQLWCHAR *wchar_data;
131
+ SQLDOUBLE double_data;
132
+ SQLCHAR tinyint_data;
133
+ SQLUSMALLINT usmallint_data;
134
+ SQLSMALLINT smallint_data;
135
+ SQLINTEGER integer_data;
136
+ SQLBIGINT bigint_data;
137
+ };
138
+ SQLLEN size;
139
+
140
+ ~ColumnData() {
141
+ if (bind_type == SQL_C_CHAR || bind_type == SQL_C_BINARY) {
142
+ if (use_free) {
143
+ free(this->char_data);
144
+ }
145
+ else {
146
+ delete[] this->char_data;
147
+ }
148
+ }
149
+ else if (bind_type == SQL_C_WCHAR) {
150
+ if (use_free) {
151
+ free(this->wchar_data);
152
+ }
153
+ else {
154
+ delete[] this->wchar_data;
155
+ }
156
+ }
157
+ }
158
+
159
+ } ColumnData;
160
+
161
+ #define MB_SIZE 1048576
162
+
163
+ typedef struct QueryOptions {
164
+ bool use_cursor = false;
165
+ SQLTCHAR *cursor_name = nullptr;
166
+ SQLSMALLINT cursor_name_length = 0;
167
+ SQLULEN fetch_size = 1;
168
+ SQLULEN timeout = 0;
169
+ SQLLEN initial_long_data_buffer_size = MB_SIZE;
170
+
171
+ // JavaScript property keys for query options
172
+ static constexpr const char *CURSOR_PROPERTY = "cursor";
173
+ static constexpr const char *FETCH_SIZE_PROPERTY = "fetchSize";
174
+ static constexpr const char *TIMEOUT_PROPERTY = "timeout";
175
+ static constexpr const char *INITIAL_BUFFER_SIZE_PROPERTY = "initialBufferSize";
176
+
177
+ void reset() {
178
+ this->use_cursor = false;
179
+ this->cursor_name = nullptr;
180
+ this->cursor_name_length = 0;
181
+ this->fetch_size = 1;
182
+ this->timeout = 0;
183
+ this->initial_long_data_buffer_size = MB_SIZE;
184
+ };
185
+
186
+ } QueryOptions;
187
+
188
+ // StatementData
189
+ typedef struct StatementData {
190
+
191
+ SQLHENV henv;
192
+ SQLHDBC hdbc;
193
+ SQLHSTMT hstmt;
194
+
195
+ QueryOptions query_options;
196
+
197
+ GetDataExtensionsSupport get_data_supports;
198
+
199
+ // parameters
200
+ SQLSMALLINT parameterCount = 0;
201
+ Parameter** parameters = NULL;
202
+
203
+ // columns and rows
204
+ bool simple_binding = false;
205
+ Column **columns = NULL;
206
+ SQLSMALLINT column_count;
207
+ ColumnBuffer *bound_columns = NULL;
208
+ std::vector<ColumnData*> storedRows;
209
+ SQLLEN rowCount;
210
+
211
+ // Multiple result sets support (added by Pablo Pimentel)
212
+ std::vector<std::vector<ColumnData*>> allResultSets;
213
+
214
+ SQLSMALLINT maxColumnNameLength;
215
+
216
+ SQLUSMALLINT *row_status_array;
217
+ SQLUINTEGER fetch_size;
218
+ SQLULEN rows_fetched;
219
+ bool result_set_end_reached = false;
220
+
221
+ bool fetch_array = false;
222
+
223
+ // query options
224
+ SQLTCHAR *sql = NULL;
225
+ SQLTCHAR *catalog = NULL;
226
+ SQLTCHAR *schema = NULL;
227
+ SQLTCHAR *table = NULL;
228
+ SQLTCHAR *fkCatalog = NULL;
229
+ SQLTCHAR *fkSchema = NULL;
230
+ SQLTCHAR *fkTable = NULL;
231
+ SQLTCHAR *type = NULL;
232
+ SQLTCHAR *column = NULL;
233
+ SQLTCHAR *procedure = NULL;
234
+
235
+ ~StatementData() {
236
+ deleteColumns();
237
+
238
+ for (int i = 0; i < this->parameterCount; i++) {
239
+ Parameter* parameter = this->parameters[i];
240
+ if (parameter->ParameterValuePtr != NULL) {
241
+ switch (parameter->ValueType) {
242
+ case SQL_C_SBIGINT:
243
+ delete (int64_t*)parameter->ParameterValuePtr;
244
+ break;
245
+ case SQL_C_DOUBLE:
246
+ delete (double*)parameter->ParameterValuePtr;
247
+ break;
248
+ case SQL_C_BIT:
249
+ delete (bool*)parameter->ParameterValuePtr;
250
+ break;
251
+ case SQL_C_TCHAR:
252
+ default:
253
+ delete[] (SQLTCHAR*)parameter->ParameterValuePtr;
254
+ break;
255
+ }
256
+ }
257
+ parameter->ParameterValuePtr = NULL;
258
+
259
+ delete parameter;
260
+ }
261
+ delete[] this->parameters; this->parameters = NULL;
262
+ this->parameterCount = 0;
263
+
264
+ delete[] sql; sql = NULL;
265
+ delete[] this->catalog; this->catalog = NULL;
266
+ delete[] this->schema; this->schema = NULL;
267
+ delete[] this->table; this->table = NULL;
268
+ delete[] this->fkCatalog; this->fkCatalog = NULL;
269
+ delete[] this->fkSchema; this->fkSchema = NULL;
270
+ delete[] this->fkTable; this->fkTable = NULL;
271
+ delete[] this->type; this->type = NULL;
272
+ delete[] this->column; this->column = NULL;
273
+ delete[] this->procedure; this->procedure = NULL;
274
+ }
275
+
276
+ void deleteColumns() {
277
+ for (size_t h = 0; h < this->storedRows.size(); h++) {
278
+ delete[] storedRows[h];
279
+ }
280
+ this->storedRows.clear();
281
+
282
+ for (int i = 0; i < this->column_count; i++) {
283
+ switch (this->columns[i]->bind_type) {
284
+ case SQL_C_CHAR:
285
+ case SQL_C_UTINYINT:
286
+ case SQL_C_BINARY:
287
+ delete[] (SQLCHAR *)this->bound_columns[i].buffer;
288
+ break;
289
+ case SQL_C_WCHAR:
290
+ delete[] (SQLWCHAR *)this->bound_columns[i].buffer;
291
+ break;
292
+ case SQL_C_DOUBLE:
293
+ delete[] (SQLDOUBLE *)this->bound_columns[i].buffer;
294
+ break;
295
+ case SQL_C_USHORT:
296
+ delete[] (SQLUSMALLINT *)this->bound_columns[i].buffer;
297
+ break;
298
+ case SQL_C_SLONG:
299
+ delete[] (SQLUINTEGER *)this->bound_columns[i].buffer;
300
+ break;
301
+ case SQL_C_UBIGINT:
302
+ delete[] (SQLUBIGINT *)this->bound_columns[i].buffer;
303
+ break;
304
+ }
305
+
306
+ delete[] this->columns[i]->ColumnName;
307
+ delete[] this->bound_columns[i].length_or_indicator_array;
308
+ delete this->columns[i];
309
+ }
310
+ this->column_count = 0;
311
+
312
+ delete[] row_status_array; row_status_array = NULL;
313
+ delete[] columns; columns = NULL;
314
+ delete[] bound_columns; bound_columns = NULL;
315
+ }
316
+ } StatementData;
317
+
318
+ size_t strlen16(const char16_t* string);
319
+
320
+ class ODBC {
321
+
322
+ public:
323
+ static uv_mutex_t g_odbcMutex;
324
+ static SQLHENV hEnv;
325
+
326
+ static Napi::Value Init(Napi::Env env, Napi::Object exports);
327
+
328
+ static SQLTCHAR* NapiStringToSQLTCHAR(Napi::String string);
329
+
330
+ static void StoreBindValues(Napi::Array *values, Parameter **parameters);
331
+
332
+ static SQLRETURN DescribeParameters(SQLHSTMT hstmt, Parameter **parameters, SQLSMALLINT parameterCount);
333
+ static SQLRETURN BindParameters(SQLHSTMT hstmt, Parameter **parameters, SQLSMALLINT parameterCount);
334
+ static Napi::Array ParametersToArray(Napi::Env env, StatementData *data);
335
+
336
+ void Free();
337
+
338
+ ~ODBC();
339
+
340
+ static Napi::Value Connect(const Napi::CallbackInfo& info);
341
+
342
+ #ifdef dynodbc
343
+ static Napi::Value LoadODBCLibrary(const Napi::CallbackInfo& info);
344
+ #endif
345
+ };
346
+
347
+ class ODBCAsyncWorker : public Napi::AsyncWorker {
348
+
349
+ public:
350
+ ODBCAsyncWorker(Napi::Function& callback);
351
+ // ~ODBCAsyncWorker(); // TODO: Delete error stuff
352
+
353
+ protected:
354
+ ODBCError *errors;
355
+ SQLINTEGER errorCount = 0;
356
+
357
+ bool CheckAndHandleErrors(SQLRETURN return_code, SQLSMALLINT handleType, SQLHANDLE handle, const char *message);
358
+ ODBCError* GetODBCErrors(SQLSMALLINT handleType, SQLHANDLE handle);
359
+ void OnError(const Napi::Error &e);
360
+ };
361
+
362
+ #endif