@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.
@@ -0,0 +1,610 @@
1
+ /*
2
+ Copyright (c) 2019, 2021 IBM
3
+ Copyright (c) 2013, Dan VerWeire<dverweire@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
+
18
+ #include <napi.h>
19
+ #include <time.h>
20
+ #include <string>
21
+
22
+ #include "odbc.h"
23
+ #include "odbc_connection.h"
24
+ #include "odbc_statement.h"
25
+ #include "odbc_cursor.h"
26
+
27
+ Napi::FunctionReference ODBCStatement::constructor;
28
+
29
+ Napi::Object ODBCStatement::Init(Napi::Env env, Napi::Object exports) {
30
+
31
+ Napi::HandleScope scope(env);
32
+
33
+ Napi::Function constructorFunction = DefineClass(env, "ODBCStatement", {
34
+ InstanceMethod("prepare", &ODBCStatement::Prepare),
35
+ InstanceMethod("bind", &ODBCStatement::Bind),
36
+ InstanceMethod("execute", &ODBCStatement::Execute),
37
+ InstanceMethod("close", &ODBCStatement::Close),
38
+ });
39
+
40
+ // Attach the Database Constructor to the target object
41
+ constructor = Napi::Persistent(constructorFunction);
42
+ constructor.SuppressDestruct();
43
+
44
+ return exports;
45
+ }
46
+
47
+
48
+ ODBCStatement::ODBCStatement(const Napi::CallbackInfo& info) : Napi::ObjectWrap<ODBCStatement>(info) {
49
+ this->data = new StatementData();
50
+ this->odbcConnection = info[0].As<Napi::External<ODBCConnection>>().Data();
51
+ this->data->hstmt = *(info[1].As<Napi::External<SQLHSTMT>>().Data());
52
+ this->data->fetch_array = this->odbcConnection->connectionOptions.fetchArray;
53
+ this->data->maxColumnNameLength = this->odbcConnection->getInfoResults.max_column_name_length;
54
+ this->data->get_data_supports = this->odbcConnection->getInfoResults.sql_get_data_supports;
55
+ }
56
+
57
+ ODBCStatement::~ODBCStatement() {
58
+ this->Free();
59
+ }
60
+
61
+ SQLRETURN ODBCStatement::Free() {
62
+
63
+ SQLRETURN return_code = SQL_SUCCESS;
64
+
65
+ if (this->data)
66
+ {
67
+ if (
68
+ this->data->hstmt &&
69
+ this->data->hstmt != SQL_NULL_HANDLE
70
+ )
71
+ {
72
+ uv_mutex_lock(&ODBC::g_odbcMutex);
73
+ return_code =
74
+ SQLFreeHandle
75
+ (
76
+ SQL_HANDLE_STMT,
77
+ this->data->hstmt
78
+ );
79
+ this->data->hstmt = SQL_NULL_HANDLE;
80
+ uv_mutex_unlock(&ODBC::g_odbcMutex);
81
+ }
82
+
83
+ delete this->data;
84
+ this->data = NULL;
85
+ }
86
+
87
+ return return_code;
88
+ }
89
+
90
+ /******************************************************************************
91
+ ********************************* PREPARE ************************************
92
+ *****************************************************************************/
93
+
94
+ // PrepareAsyncWorker, used by Prepare function (see below)
95
+ class PrepareAsyncWorker : public ODBCAsyncWorker {
96
+
97
+ private:
98
+ ODBCStatement *odbcStatement;
99
+ ODBCConnection *odbcConnection;
100
+ StatementData *data;
101
+
102
+ public:
103
+ PrepareAsyncWorker(ODBCStatement *odbcStatement, Napi::Function& callback) : ODBCAsyncWorker(callback),
104
+ odbcStatement(odbcStatement),
105
+ odbcConnection(odbcStatement->odbcConnection),
106
+ data(odbcStatement->data) {}
107
+
108
+ ~PrepareAsyncWorker() {}
109
+
110
+ void Execute() {
111
+
112
+ SQLRETURN return_code;
113
+
114
+ return_code = SQLPrepare
115
+ (
116
+ data->hstmt, // StatementHandle
117
+ data->sql, // StatementText
118
+ SQL_NTS // TextLength
119
+ );
120
+ if (!SQL_SUCCEEDED(return_code)) {
121
+ this->errors = GetODBCErrors(SQL_HANDLE_STMT, data->hstmt);
122
+ SetError("[odbc] Error preparing the statement\0");
123
+ return;
124
+ }
125
+
126
+ // front-load the work of SQLNumParams here, so we can convert
127
+ // NAPI/JavaScript values to C values immediately in Bind
128
+ return_code = SQLNumParams
129
+ (
130
+ data->hstmt, // StatementHandle
131
+ &data->parameterCount // ParameterCountPtr
132
+ );
133
+ if (!SQL_SUCCEEDED(return_code)) {
134
+ this->errors = GetODBCErrors(SQL_HANDLE_STMT, data->hstmt);
135
+ SetError("[odbc] Error retrieving number of parameter markers to be bound to the statement\0");
136
+ return;
137
+ }
138
+
139
+ data->parameters = new Parameter*[data->parameterCount];
140
+ for (SQLSMALLINT i = 0; i < data->parameterCount; i++) {
141
+ data->parameters[i] = new Parameter();
142
+ }
143
+ }
144
+
145
+ void OnOK() {
146
+
147
+ Napi::Env env = Env();
148
+ Napi::HandleScope scope(env);
149
+
150
+ std::vector<napi_value> callbackArguments;
151
+ callbackArguments.push_back(env.Null());
152
+ Callback().Call(callbackArguments);
153
+ }
154
+ };
155
+
156
+ /*
157
+ * ODBCStatement:Prepare (Async)
158
+ * Description: Prepares an SQL string so that it can be bound with
159
+ * parameters and then executed.
160
+ *
161
+ * Parameters:
162
+ * const Napi::CallbackInfo& info:
163
+ * The information passed by Napi from the JavaScript call, including
164
+ * arguments from the JavaScript function. In JavaScript, the
165
+ * prepare() function takes two arguments.
166
+ *
167
+ * info[0]: String: the SQL string to prepare.
168
+ * info[1]: Function: callback function:
169
+ * function(error, result)
170
+ * error: An error object if there was a problem getting results,
171
+ * or null if operation was successful.
172
+ * result: The number of rows affected by the executed query.
173
+ *
174
+ * Return:
175
+ * Napi::Value:
176
+ * Undefined (results returned in callback).
177
+ */
178
+ Napi::Value ODBCStatement::Prepare(const Napi::CallbackInfo& info) {
179
+
180
+ Napi::Env env = info.Env();
181
+ Napi::HandleScope scope(env);
182
+
183
+ this->napiParameters = Napi::Persistent(Napi::Array::New(env));
184
+
185
+ if(!info[0].IsString() || !info[1].IsFunction()){
186
+ Napi::TypeError::New(env, "Argument 0 must be a string , Argument 1 must be a function.").ThrowAsJavaScriptException();
187
+ return env.Null();
188
+ }
189
+
190
+ Napi::String sql = info[0].ToString();
191
+ Napi::Function callback = info[1].As<Napi::Function>();
192
+
193
+ if(this->data->hstmt == SQL_NULL_HANDLE) {
194
+ Napi::Error error = Napi::Error::New(env, "Statment handle is no longer valid. Cannot prepare SQL on an invalid statment handle.");
195
+ std::vector<napi_value> callbackArguments;
196
+ callbackArguments.push_back(error.Value());
197
+ callback.Call(callbackArguments);
198
+ return env.Undefined();
199
+ }
200
+
201
+ data->sql = ODBC::NapiStringToSQLTCHAR(sql);
202
+
203
+ PrepareAsyncWorker *worker = new PrepareAsyncWorker(this, callback);
204
+ worker->Queue();
205
+
206
+ return env.Undefined();
207
+ }
208
+
209
+ /******************************************************************************
210
+ *********************************** BIND *************************************
211
+ *****************************************************************************/
212
+
213
+ // BindAsyncWorker, used by Bind function (see below)
214
+ class BindAsyncWorker : public ODBCAsyncWorker {
215
+
216
+ public:
217
+
218
+ BindAsyncWorker(ODBCStatement *odbcStatement, Napi::Function& callback) : ODBCAsyncWorker(callback),
219
+ odbcStatement(odbcStatement),
220
+ odbcConnection(odbcStatement->odbcConnection),
221
+ data(odbcStatement->data) {}
222
+
223
+ private:
224
+
225
+ ODBCStatement *odbcStatement;
226
+ ODBCConnection *odbcConnection;
227
+ StatementData *data;
228
+
229
+ ~BindAsyncWorker() { }
230
+
231
+ void Execute() {
232
+
233
+ SQLRETURN return_code;
234
+
235
+ return_code = ODBC::DescribeParameters(data->hstmt, data->parameters, data->parameterCount);
236
+ if (!SQL_SUCCEEDED(return_code)) {
237
+ this->errors = GetODBCErrors(SQL_HANDLE_STMT, data->hstmt);
238
+ SetError("[odbc] Error retrieving information about the parameters in the statement\0");
239
+ return;
240
+ }
241
+
242
+ return_code = ODBC::BindParameters(data->hstmt, data->parameters, data->parameterCount);
243
+ if (!SQL_SUCCEEDED(return_code)) {
244
+ this->errors = GetODBCErrors(SQL_HANDLE_STMT, data->hstmt);
245
+ SetError("[odbc] Error binding parameters to the statement\0");
246
+ return;
247
+ }
248
+ }
249
+
250
+ void OnOK() {
251
+
252
+ Napi::Env env = Env();
253
+ Napi::HandleScope scope(env);
254
+
255
+ std::vector<napi_value> callbackArguments;
256
+ callbackArguments.push_back(env.Null());
257
+ Callback().Call(callbackArguments);
258
+ }
259
+ };
260
+
261
+ Napi::Value ODBCStatement::Bind(const Napi::CallbackInfo& info) {
262
+
263
+ Napi::Env env = info.Env();
264
+ Napi::HandleScope scope(env);
265
+
266
+ if ( !info[0].IsArray() || !info[1].IsFunction() ) {
267
+ Napi::TypeError::New(env, "Function signature is: bind(array, function)").ThrowAsJavaScriptException();
268
+ return env.Null();
269
+ }
270
+
271
+ Napi::Array napiArray = info[0].As<Napi::Array>();
272
+ this->napiParameters = Napi::Persistent(napiArray);
273
+ Napi::Function callback = info[1].As<Napi::Function>();
274
+
275
+ if(this->data->hstmt == SQL_NULL_HANDLE) {
276
+ Napi::Error error = Napi::Error::New(env, "Statment handle is no longer valid. Cannot bind SQL on an invalid statment handle.");
277
+ std::vector<napi_value> callbackArguments;
278
+ callbackArguments.push_back(error.Value());
279
+ callback.Call(callbackArguments);
280
+ return env.Undefined();
281
+ }
282
+
283
+ // if the parameter count isnt right, end right away
284
+ if (data->parameterCount != (SQLSMALLINT)this->napiParameters.Value().Length() || data->parameters == NULL) {
285
+ std::vector<napi_value> callbackArguments;
286
+
287
+ Napi::Error error = Napi::Error::New(env, Napi::String::New(env, "[node-odbc] Error in Statement::BindAsyncWorker::Bind: The number of parameters in the prepared statement (" + std::to_string(data->parameterCount) + ") doesn't match the number of parameters passed to bind (" + std::to_string((SQLSMALLINT)this->napiParameters.Value().Length()) + "}."));
288
+ callbackArguments.push_back(error.Value());
289
+
290
+ callback.Call(callbackArguments);
291
+ return env.Undefined();
292
+ }
293
+
294
+ // converts NAPI/JavaScript values to values used by SQLBindParameter
295
+ ODBC::StoreBindValues(&napiArray, this->data->parameters);
296
+
297
+ BindAsyncWorker *worker = new BindAsyncWorker(this, callback);
298
+ worker->Queue();
299
+
300
+ return env.Undefined();
301
+ }
302
+
303
+ /******************************************************************************
304
+ ********************************* EXECUTE ************************************
305
+ *****************************************************************************/
306
+
307
+ // ExecuteAsyncWorker, used by Execute function (see below)
308
+ class ExecuteAsyncWorker : public ODBCAsyncWorker {
309
+
310
+ private:
311
+ ODBCConnection *odbcConnection;
312
+ ODBCStatement *odbcStatement;
313
+ StatementData *data;
314
+
315
+ void Execute() {
316
+
317
+ SQLRETURN return_code;
318
+
319
+ // set SQL_ATTR_QUERY_TIMEOUT
320
+ if (data->query_options.timeout > 0) {
321
+ return_code =
322
+ SQLSetStmtAttr
323
+ (
324
+ data->hstmt,
325
+ SQL_ATTR_QUERY_TIMEOUT,
326
+ (SQLPOINTER) data->query_options.timeout,
327
+ IGNORED_PARAMETER
328
+ );
329
+
330
+ // It is possible that SQLSetStmtAttr returns a warning with SQLSTATE
331
+ // 01S02, indicating that the driver changed the value specified.
332
+ // Although we never use the timeout variable again (and so we don't
333
+ // REALLY need it to be correct in the code), its just good to have
334
+ // the correct value if we need it.
335
+ if (return_code == SQL_SUCCESS_WITH_INFO)
336
+ {
337
+ return_code =
338
+ SQLGetStmtAttr
339
+ (
340
+ data->hstmt,
341
+ SQL_ATTR_QUERY_TIMEOUT,
342
+ (SQLPOINTER) &data->query_options.timeout,
343
+ SQL_IS_UINTEGER,
344
+ IGNORED_PARAMETER
345
+ );
346
+ }
347
+
348
+ // Both of the SQL_ATTR_QUERY_TIMEOUT calls are combined here
349
+ if (!SQL_SUCCEEDED(return_code)) {
350
+ this->errors = GetODBCErrors(SQL_HANDLE_STMT, data->hstmt);
351
+ SetError("[odbc] Error setting the query timeout on the statement\0");
352
+ return;
353
+ }
354
+ }
355
+
356
+ return_code =
357
+ set_fetch_size
358
+ (
359
+ data,
360
+ data->query_options.fetch_size
361
+ );
362
+ if (!SQL_SUCCEEDED(return_code)) {
363
+ this->errors = GetODBCErrors(SQL_HANDLE_STMT, data->hstmt);
364
+ SetError("[odbc] Error setting the fetch size\0");
365
+ return;
366
+ }
367
+
368
+ return_code =
369
+ SQLExecute
370
+ (
371
+ data->hstmt // StatementHandle
372
+ );
373
+ if (!SQL_SUCCEEDED(return_code)) {
374
+ this->errors = GetODBCErrors(SQL_HANDLE_STMT, data->hstmt);
375
+ SetError("[odbc] Error executing the statement\0");
376
+ return;
377
+ }
378
+
379
+ if (return_code != SQL_NO_DATA) {
380
+
381
+ if (data->query_options.use_cursor)
382
+ {
383
+ if (data->query_options.cursor_name != NULL)
384
+ {
385
+ return_code =
386
+ SQLSetCursorName
387
+ (
388
+ data->hstmt,
389
+ data->query_options.cursor_name,
390
+ data->query_options.cursor_name_length
391
+ );
392
+
393
+ if (!SQL_SUCCEEDED(return_code)) {
394
+ this->errors = GetODBCErrors(SQL_HANDLE_STMT, data->hstmt);
395
+ SetError("[odbc] Error setting the cursor name on the statement\0");
396
+ return;
397
+ }
398
+ }
399
+ }
400
+
401
+ // set_fetch_size will swallow errors in the case that the driver
402
+ // doesn't implement SQL_ATTR_ROW_ARRAY_SIZE for SQLSetStmtAttr and
403
+ // the fetch size was 1. If the fetch size was set by the user to a
404
+ // value greater than 1, throw an error.
405
+ if (!SQL_SUCCEEDED(return_code)) {
406
+ this->errors = GetODBCErrors(SQL_HANDLE_STMT, data->hstmt);
407
+ SetError("[odbc] Error setting the fetch size on the statement\0");
408
+ return;
409
+ }
410
+
411
+ return_code =
412
+ prepare_for_fetch
413
+ (
414
+ data
415
+ );
416
+ if (!SQL_SUCCEEDED(return_code)) {
417
+ this->errors = GetODBCErrors(SQL_HANDLE_STMT, data->hstmt);
418
+ SetError("[odbc] Error preparing for fetch\0");
419
+ return;
420
+ }
421
+
422
+
423
+ if (!data->query_options.use_cursor)
424
+ {
425
+ bool alloc_error = false;
426
+ return_code =
427
+ fetch_all_and_store
428
+ (
429
+ data,
430
+ true,
431
+ &alloc_error
432
+ );
433
+ if (alloc_error)
434
+ {
435
+ SetError("[odbc] Error allocating or reallocating memory when fetching data. No ODBC error information available.\0");
436
+ return;
437
+ }
438
+ if (!SQL_SUCCEEDED(return_code)) {
439
+ this->errors = GetODBCErrors(SQL_HANDLE_STMT, data->hstmt);
440
+ SetError("[odbc] Error retrieving the result set from the statement\0");
441
+ return;
442
+ }
443
+ }
444
+ }
445
+ }
446
+
447
+ void OnOK() {
448
+
449
+ Napi::Env env = Env();
450
+ Napi::HandleScope scope(env);
451
+
452
+ std::vector<napi_value> callbackArguments;
453
+
454
+ if (data->query_options.use_cursor)
455
+ {
456
+ // arguments for the ODBCCursor constructor
457
+ std::vector<napi_value> cursor_arguments =
458
+ {
459
+ Napi::External<StatementData>::New(env, data),
460
+ Napi::External<ODBCConnection>::New(env, this->odbcConnection),
461
+ this->odbcStatement->napiParameters.Value(),
462
+ Napi::Boolean::New(env, false)
463
+ };
464
+
465
+ // create a new ODBCCursor object as a Napi::Value
466
+ Napi::Value cursorObject = ODBCCursor::constructor.New(cursor_arguments);
467
+
468
+ // return cursor
469
+ std::vector<napi_value> callbackArguments =
470
+ {
471
+ env.Null(),
472
+ cursorObject
473
+ };
474
+
475
+ Callback().Call(callbackArguments);
476
+ }
477
+ else
478
+ {
479
+ Napi::Array rows = process_data_for_napi(env, data, odbcStatement->napiParameters.Value());
480
+
481
+ std::vector<napi_value> callbackArguments;
482
+ callbackArguments.push_back(env.Null());
483
+ callbackArguments.push_back(rows);
484
+
485
+ Callback().Call(callbackArguments);
486
+ }
487
+
488
+ return;
489
+ }
490
+
491
+ public:
492
+ ExecuteAsyncWorker(ODBCStatement *odbcStatement, Napi::Function& callback) : ODBCAsyncWorker(callback),
493
+ odbcConnection(odbcStatement->odbcConnection),
494
+ odbcStatement(odbcStatement),
495
+ data(odbcStatement->data) {}
496
+
497
+ ~ExecuteAsyncWorker() {}
498
+ };
499
+
500
+ Napi::Value ODBCStatement::Execute(const Napi::CallbackInfo& info) {
501
+
502
+ Napi::Env env = info.Env();
503
+ Napi::HandleScope scope(env);
504
+
505
+ Napi::Function callback;
506
+
507
+ size_t argument_count = info.Length();
508
+ // ensuring the passed parameters are correct
509
+ if ((argument_count == 1 && info[0].IsFunction()) || (argument_count == 2 && info[1].IsFunction())) {
510
+ callback = info[argument_count - 1].As<Napi::Function>();
511
+ }
512
+
513
+ Napi::Value error;
514
+
515
+ // ensuring the passed parameters are correct
516
+ if (argument_count >= 1 && info[0].IsObject()) {
517
+ error =
518
+ parse_query_options
519
+ (
520
+ env,
521
+ info[0].As<Napi::Object>(),
522
+ &this->data->query_options
523
+ );
524
+ } else {
525
+ error =
526
+ parse_query_options
527
+ (
528
+ env,
529
+ env.Null(),
530
+ &this->data->query_options
531
+ );
532
+ }
533
+
534
+ if (!error.IsNull())
535
+ {
536
+ // Error when parsing the query options. Return the callback with the error
537
+ std::vector<napi_value> callback_argument =
538
+ {
539
+ error
540
+ };
541
+ callback.Call(callback_argument);
542
+ }
543
+
544
+ if(this->data->hstmt == SQL_NULL_HANDLE) {
545
+ Napi::Error error = Napi::Error::New(env, "Statment handle is no longer valid. Cannot execute SQL on an invalid statment handle.");
546
+ std::vector<napi_value> callbackArguments;
547
+ callbackArguments.push_back(error.Value());
548
+ callback.Call(callbackArguments);
549
+ return env.Undefined();
550
+ }
551
+
552
+ ExecuteAsyncWorker *worker = new ExecuteAsyncWorker(this, callback);
553
+ worker->Queue();
554
+
555
+ return env.Undefined();
556
+ }
557
+
558
+ /******************************************************************************
559
+ ********************************** CLOSE *************************************
560
+ *****************************************************************************/
561
+
562
+ // CloseStatementAsyncWorker, used by Close function (see below)
563
+ class CloseStatementAsyncWorker : public ODBCAsyncWorker {
564
+
565
+ private:
566
+ ODBCStatement *odbcStatement;
567
+ StatementData *data;
568
+
569
+ void Execute() {
570
+
571
+ SQLRETURN return_code;
572
+
573
+ return_code = odbcStatement->Free();
574
+ if (!SQL_SUCCEEDED(return_code)) {
575
+ this->errors = GetODBCErrors(SQL_HANDLE_STMT, data->hstmt);
576
+ SetError("[odbc] Error closing the Statement\0");
577
+ return;
578
+ }
579
+ }
580
+
581
+ void OnOK() {
582
+
583
+ Napi::Env env = Env();
584
+ Napi::HandleScope scope(env);
585
+
586
+ std::vector<napi_value> callbackArguments;
587
+ callbackArguments.push_back(env.Null());
588
+ Callback().Call(callbackArguments);
589
+ }
590
+
591
+ public:
592
+ CloseStatementAsyncWorker(ODBCStatement *odbcStatement, Napi::Function& callback) : ODBCAsyncWorker(callback),
593
+ odbcStatement(odbcStatement),
594
+ data(odbcStatement->data) {}
595
+
596
+ ~CloseStatementAsyncWorker() {}
597
+ };
598
+
599
+ Napi::Value ODBCStatement::Close(const Napi::CallbackInfo& info) {
600
+
601
+ Napi::Env env = info.Env();
602
+ Napi::HandleScope scope(env);
603
+
604
+ Napi::Function callback = info[0].As<Napi::Function>();
605
+
606
+ CloseStatementAsyncWorker *worker = new CloseStatementAsyncWorker(this, callback);
607
+ worker->Queue();
608
+
609
+ return env.Undefined();
610
+ }
@@ -0,0 +1,43 @@
1
+ /*
2
+ Copyright (c) 2019, 2021 IBM
3
+ Copyright (c) 2013, Dan VerWeire<dverweire@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
+
18
+ #ifndef _SRC_ODBC_STATEMENT_H
19
+ #define _SRC_ODBC_STATEMENT_H
20
+
21
+ #include <napi.h>
22
+
23
+ class ODBCStatement : public Napi::ObjectWrap<ODBCStatement> {
24
+ public:
25
+ static Napi::FunctionReference constructor;
26
+
27
+ static Napi::Object Init(Napi::Env env, Napi::Object exports);
28
+
29
+ ODBCConnection *odbcConnection;
30
+ Napi::Reference<Napi::Array> napiParameters;
31
+ StatementData *data;
32
+
33
+ SQLRETURN Free();
34
+
35
+ explicit ODBCStatement(const Napi::CallbackInfo& info);
36
+ ~ODBCStatement();
37
+
38
+ Napi::Value Prepare(const Napi::CallbackInfo& info);
39
+ Napi::Value Bind(const Napi::CallbackInfo& info);
40
+ Napi::Value Execute(const Napi::CallbackInfo& info);
41
+ Napi::Value Close(const Napi::CallbackInfo& info);
42
+ };
43
+ #endif