@ind-rcg/backend 246.1008.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/LICENSE.md +37 -0
  2. package/README.md +7 -0
  3. package/bin/libsqliteExtension.dll +0 -0
  4. package/bin/libsqliteExtension.dylib +0 -0
  5. package/binding.gyp +21 -0
  6. package/configuration.template.json +24 -0
  7. package/log4js.json +11 -0
  8. package/nativeSrc/PriceEngineWrap.cc +157 -0
  9. package/nativeSrc/PriceEngineWrap.h +24 -0
  10. package/nativeSrc/common/DBAccess/SimpleDBConnection.cpp +800 -0
  11. package/nativeSrc/common/DBAccess/SimpleDBConnection.h +54 -0
  12. package/nativeSrc/common/Libs/cJSON/CHANGELOG.md +428 -0
  13. package/nativeSrc/common/Libs/cJSON/LICENSE +20 -0
  14. package/nativeSrc/common/Libs/cJSON/README.md +571 -0
  15. package/nativeSrc/common/Libs/cJSON/cJSON.c +3110 -0
  16. package/nativeSrc/common/Libs/cJSON/cJSON.h +293 -0
  17. package/nativeSrc/common/Libs/sqlcipher/sqlite3.c +241624 -0
  18. package/nativeSrc/common/Libs/sqlcipher/sqlite3.h +12836 -0
  19. package/nativeSrc/common/Libs/sqlcipher/sqlite3ext.h +701 -0
  20. package/nativeSrc/common/LogAdapter/LogAdapter.cpp +25 -0
  21. package/nativeSrc/common/LogAdapter/LogAdapter.h +20 -0
  22. package/nativeSrc/common/PriceEngine/PriceEngine.cpp +251 -0
  23. package/nativeSrc/common/PriceEngine/PriceEngine.h +67 -0
  24. package/nativeSrc/common/Utils/StringFormat.cpp +905 -0
  25. package/nativeSrc/common/Utils/StringFormat.h +116 -0
  26. package/nativeSrc/common/Utils/miniz/timer.cpp +165 -0
  27. package/nativeSrc/common/Utils/miniz/timer.h +40 -0
  28. package/nativeSrc/common/stdngm.h +92 -0
  29. package/nativeSrc/nativeWrapper.cc +15 -0
  30. package/package.json +70 -0
  31. package/src/argsParser.js +73 -0
  32. package/src/bootstrap.js +156 -0
  33. package/src/fsHelper.js +36 -0
  34. package/src/globalConfig.js +23 -0
  35. package/src/local.js +546 -0
  36. package/src/server.js +64 -0
  37. package/src/sfAttachmentsHandler.js +283 -0
  38. package/src/utils.js +91 -0
  39. package/src/zipHandler.js +153 -0
@@ -0,0 +1,800 @@
1
+ #include "SimpleDBConnection.h"
2
+ #include "../stdngm.h"
3
+ #include "../Utils/StringFormat.h"
4
+ #include "../LogAdapter/LogAdapter.h"
5
+ #include "../Utils/miniz/timer.h"
6
+ //#ifdef WINAPI_FAMILY //WIN_PHONE
7
+ #if defined(WIN32) || defined(WINAPI_FAMILY)
8
+ #include <windows.h>
9
+ #endif
10
+
11
+ SimpleDBConnection::SimpleDBConnection()
12
+ {
13
+ m_DB = NULL;
14
+ }
15
+
16
+ SimpleDBConnection::~SimpleDBConnection()
17
+ {
18
+ if (isValid()) close();
19
+ }
20
+
21
+ bool SimpleDBConnection::close()
22
+ {
23
+
24
+ if (m_DB == NULL) {
25
+ if (LogAdapter::logConsole()) LogAdapter::Console("Open a database connection first, then pass the request");
26
+ return false;
27
+ }
28
+ int rc;
29
+ if (SQLITE_OK != (rc = sqlite3_close(m_DB))) {
30
+ if (LogAdapter::logConsole()) LogAdapter::Console("Something went wrong. Try closing the database connection again or contact Salesforce Support for help.");
31
+ return false;
32
+ }
33
+
34
+ m_DB = NULL;
35
+ return true;
36
+ }
37
+
38
+ void SimpleDBConnection::LogError(const char *modulename, const char *classname, const char *methodname, const char *message)
39
+ {
40
+ std::string msg = modulename;
41
+ msg = msg + " " + classname;
42
+ msg = msg + " " + methodname;
43
+ msg = msg + " " + message;
44
+ LogAdapter::Console(msg.c_str());
45
+ }
46
+
47
+ void SimpleDBConnection::LogPerformance(const char * message, double performance)
48
+ {
49
+ LogAdapter::Console(StringFormat("[%f] %s", performance, message).c_str());
50
+ }
51
+
52
+ bool SimpleDBConnection::openConnection(const char * sDBFullPath){
53
+
54
+ if (m_DB != NULL) {
55
+ if (LogAdapter::logConsole()) LogAdapter::Console("The database connection is already open.");
56
+ return true;
57
+ }
58
+
59
+ const int CREATE_FLAGS = SQLITE_OPEN_READWRITE | SQLITE_OPEN_FULLMUTEX;
60
+ m_DB = _concurrent_openConnection(sDBFullPath, CREATE_FLAGS);
61
+
62
+ return (m_DB != NULL) ? true : false;
63
+ }
64
+
65
+ sqlite3* SimpleDBConnection::_concurrent_openConnection(const char * sDBFullPath, const int CREATE_FLAGS){
66
+
67
+ int rc;
68
+ int n = 0;
69
+
70
+ sqlite3 *m_DB = NULL;
71
+
72
+ do {
73
+ rc = sqlite3_open_v2(sDBFullPath, &m_DB, CREATE_FLAGS, NULL);
74
+
75
+ if (SQLITE_BUSY == rc) {
76
+ n++;
77
+ msleep(SLEEP_LOCK_MS);
78
+ }
79
+ else if (SQLITE_OK != rc) {
80
+ rc = sqlite3_open_v2(sDBFullPath, &m_DB, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX, NULL);
81
+
82
+ if (SQLITE_OK != rc) {
83
+ std::string msg = "The SQLite library failed to open the database with the ";
84
+ msg += sqlite3_errmsg(m_DB);
85
+ msg += " error. For more information about the SQLite error codes, see Result and Error Codes in SQLite documentation.";
86
+ if (LogAdapter::logConsole()) LogAdapter::Console(msg.c_str());
87
+ break;
88
+ }
89
+ else {
90
+ if (LogAdapter::logConsole()) LogAdapter::Console("The database connection opened successfully.");
91
+ }
92
+ }
93
+ } while ((n < SLEEP_LOCK_TIMES) && (rc == SQLITE_BUSY));
94
+
95
+ if ((SQLITE_OK != rc) || (NULL == m_DB)) {
96
+ if (LogAdapter::logConsole()) LogAdapter::Console("Failed to open the database connection. You’ve reached the maximum retry attempts to open the database connection. Confirm whether the database file is accessible or that the database is readable. If the issue persists, contact Salesforce Support for help.");
97
+ }
98
+
99
+ return (SQLITE_OK == rc) ? m_DB : NULL;
100
+ }
101
+
102
+
103
+ cJSON * SimpleDBConnection::universalParameterizedBatch(cJSON *statements, bool isHESAMode, bool isExecute, bool enableLog /*= true*/)
104
+ {
105
+ // enableLog is false to avoid the new LogEntry being created when this
106
+ // API is invoked to inserts the Log into RpsLog Table.
107
+ sqlite3_stmt* stmt = NULL;
108
+
109
+ resetLastError();
110
+
111
+ if (!isValid())
112
+ {
113
+ handleException("universalParameterizedBatch() invalid call", 0);
114
+ return (cJSON *)0;
115
+ }
116
+
117
+ timer t;
118
+
119
+ if (enableLog)
120
+ {
121
+ t.start();
122
+ }
123
+
124
+ std::string check_begin = "BEGIN";
125
+ std::string check_commit = "COMMIT";
126
+ std::string check_rollback = "ROLLBACK";
127
+
128
+ std::string tx_rollback_reason = "";
129
+
130
+ bool req_begin = false;
131
+ bool req_commit = false;
132
+ bool req_rollback = false;
133
+
134
+ cJSON *statement = (NULL != statements) ? statements->child : NULL;
135
+ cJSON *result = cJSON_CreateArray();
136
+
137
+ while (statement)
138
+ {
139
+ int total_changes = sqlite3_total_changes(m_DB);
140
+
141
+ //Compatibility with HESA implementation
142
+ std::string qid_value = "0";
143
+
144
+ cJSON *sql = cJSON_GetObjectItem(statement, "sql");
145
+
146
+ //Compatibility with HESA implementation
147
+ if (NULL == sql) sql = cJSON_GetObjectItem(statement, "query");
148
+
149
+ cJSON *params = cJSON_GetObjectItem(statement, "params");
150
+
151
+ //Compatibility with HESA implementation
152
+ if (NULL == params) params = cJSON_GetObjectItem(statement, "parameters");
153
+
154
+ //Compatibility with HESA implementation
155
+ cJSON *qid = cJSON_GetObjectItem(statement, "qid");
156
+
157
+ //Compatibility with HESA implementation
158
+ if (NULL != qid) qid_value = (const char *)qid->valuestring;
159
+
160
+ const char *sSQL = (const char *)sql->valuestring;
161
+
162
+ int param_count = cJSON_GetArraySize(params);
163
+
164
+ if ((param_count < 1) && (safe_strlen(sSQL) < 32))
165
+ {
166
+ std::string command = to_upper(sSQL);
167
+
168
+ //Only start a new transaction of no transaction is running.
169
+ //Otherwise use the existing transaction and let the caller decide on result what to do.
170
+ //Note that an outer transaction also enables the the break on first error in the statement preparation.
171
+ if (starts_with(command, check_begin) && !inTransaction())
172
+ {
173
+ if (beginTransaction())
174
+ {
175
+ cJSON_AddItemToArray(result, CreateJSONSuccessObject(cJSON_CreateArray(), 0, qid_value.c_str(), isHESAMode, isExecute));
176
+ statement = statement->next;
177
+ req_begin = true;
178
+ req_commit = true;
179
+ continue;
180
+ }
181
+ else
182
+ {
183
+ cJSON_AddItemToArray(result, CreateJSONErrorObject("Unable to begin transaction", qid_value.c_str(), isHESAMode, isExecute));
184
+ break;
185
+ }
186
+ }
187
+ else if (starts_with(command, check_commit) || starts_with(command, check_rollback))
188
+ {
189
+ cJSON_AddItemToArray(result, CreateJSONSuccessObject(cJSON_CreateArray(), 0, qid_value.c_str(), isHESAMode, isExecute));
190
+ statement = statement->next;
191
+ continue;
192
+ }
193
+ }
194
+
195
+ if (LogAdapter::logDebug())
196
+ {
197
+ LogAdapter::Console(sSQL);
198
+ }
199
+
200
+ if (!concurrent_prepare(&stmt, sSQL))
201
+ {
202
+ std::string msg = "ERROR prepare stmt ";
203
+ msg += sqlite3_errmsg(m_DB);
204
+ msg += ": ";
205
+ msg += sSQL;
206
+ sqlite3_finalize(stmt);
207
+
208
+ cJSON_AddItemToArray(result, CreateJSONErrorObject(msg.c_str(), qid_value.c_str(), isHESAMode, isExecute));
209
+
210
+ if (req_begin) // we need to stop right now and make sure to roll back
211
+ {
212
+ // Can't call handleException(...) here yet because our own
213
+ // transaction would be blocking it from fullfilling it's destiny.
214
+ tx_rollback_reason = msg;
215
+
216
+ //All-Or-Nothing. The first error ends the batch.
217
+ req_commit = false;
218
+ req_rollback = true;
219
+ break;
220
+ }
221
+ else if (inTransaction())
222
+ {
223
+ // This case handles batches with an outer transaction.
224
+ handleException(msg, 0);
225
+ break;
226
+ }
227
+ else // keep it chill and carry on despite the failure
228
+ {
229
+ // This case handles batches without transaction.
230
+ handleException(msg, 0);
231
+ statement = statement->next;
232
+ continue;
233
+ }
234
+ }
235
+
236
+ bindParameters(stmt, params);
237
+
238
+ cJSON *rows = cJSON_CreateArray();
239
+ cJSON *columns = NULL;
240
+
241
+ int column_count = sqlite3_column_count(stmt);
242
+
243
+ if (column_count > 0)
244
+ {
245
+ int istep = 0;
246
+
247
+ cJSON *previous_row = NULL;
248
+
249
+ cJSON *previous_col = NULL;
250
+ columns = cJSON_CreateArray();
251
+ bool first_step = true;
252
+
253
+ while ((istep = concurrent_step(stmt)) == SQLITE_ROW) {
254
+ int col_type;
255
+
256
+ cJSON *row = cJSON_CreateObject();
257
+
258
+ for (int i = 0; i<column_count; i++) {
259
+ col_type = sqlite3_column_type(stmt, i);
260
+ std::string key = sqlite3_column_name(stmt, i);
261
+
262
+ if (first_step) {
263
+ cJSON *col_metadata = cJSON_CreateObject();
264
+ cJSON_AddStringToObject(col_metadata, "col_name", key.c_str());
265
+ cJSON_AddNumberToObject(col_metadata, "col_type", col_type);
266
+
267
+ if (previous_col == NULL) {
268
+ cJSON_AddItemToArray(columns, col_metadata);
269
+ } else {
270
+ previous_col->next = col_metadata;
271
+ col_metadata->prev = previous_col;
272
+ }
273
+
274
+ previous_col = col_metadata;
275
+ }
276
+
277
+ if (col_type == SQLITE_TEXT) {
278
+ const char *data = (const char *)sqlite3_column_text(stmt, i);
279
+
280
+ if (data != NULL) {
281
+ cJSON_AddStringToObject(row, key.c_str(), data);
282
+ }
283
+ else {
284
+ cJSON_AddNullToObject(row, key.c_str());
285
+ }
286
+ }
287
+ else if (col_type == SQLITE_FLOAT) {
288
+ double float_data = sqlite3_column_double(stmt, i);
289
+ cJSON_AddNumberToObject(row, key.c_str(), float_data);
290
+ }
291
+ else if (col_type == SQLITE_INTEGER) {
292
+ INT64 int_data = sqlite3_column_int64(stmt, i);
293
+ cJSON_AddNumberToObject(row, key.c_str(), (double)int_data);
294
+ }
295
+ else if (col_type == SQLITE_BLOB) {
296
+ cJSON_AddNullToObject(row, key.c_str());
297
+ }
298
+ else {
299
+ cJSON_AddNullToObject(row, key.c_str());
300
+ }
301
+ }
302
+
303
+ // The linked list implementation of the cJSON library does NOT have a pointer stored to the
304
+ // last item of the list which then forces the implementation of cJSON_AddItemToArray(...)
305
+ // to loop through all current items of the array whenever we want to add a new item at the end.
306
+ //
307
+ // The big o time complexity of this is a massive O( (1 + n)^0.5n )
308
+ // https://www.wolframalpha.com/input/?i=1+%2B+2+%2B+3+%2B+4+%2B+...+%2B+n
309
+ // Which leads to 15 minutes query execution time on my iPhone for the SQL:
310
+ // SELECT Id FROM 'Order_Item__c' (with 130k rows in the table).
311
+ //
312
+ // The optimization below keeps track of the last item's reference manually, outside of the cJSON
313
+ // implementation so that we can work with O(1) append time. Now the query from above runs in 3 seconds.
314
+ //
315
+ if (previous_row == NULL)
316
+ {
317
+ cJSON_AddItemToArray(rows, row);
318
+ }
319
+ else
320
+ {
321
+ previous_row->next = row;
322
+ row->prev = previous_row;
323
+ }
324
+ previous_row = row;
325
+
326
+ first_step = false;
327
+ }
328
+
329
+ if (SQLITE_DONE != istep) {
330
+ std::string msg = "ERROR execute select stmt ";
331
+ msg += sqlite3_errmsg(m_DB);
332
+ msg += ": ";
333
+ msg += sSQL;
334
+
335
+ cJSON_Delete(rows);
336
+ cJSON_AddItemToArray(result, CreateJSONErrorObject(msg.c_str(), qid_value.c_str(), isHESAMode, isExecute));
337
+
338
+ handleException(msg, 0);
339
+ }
340
+ }
341
+ else
342
+ {
343
+ if (SQLITE_DONE != concurrent_step(stmt)) {
344
+ std::string msg = "ERROR execute stmt ";
345
+ msg += sqlite3_errmsg(m_DB);
346
+ msg += ": ";
347
+ msg += sSQL;
348
+
349
+ cJSON_AddItemToArray(result, CreateJSONErrorObject(msg.c_str(), qid_value.c_str(), isHESAMode, isExecute));
350
+
351
+ handleException(msg, 0);
352
+ }
353
+ }
354
+
355
+ if (param_count > 0)
356
+ {
357
+ sqlite3_clear_bindings(stmt);
358
+ sqlite3_reset(stmt);
359
+ }
360
+
361
+ sqlite3_finalize(stmt);
362
+
363
+ //[{"type":"success", "result": {"rows":[], "rowsAffected" : 0}},
364
+ // {"type":"success", "result": {"rows":[], "rowsAffected" : 0}},
365
+ // {"type":"success", "result": {"rows":[], "rowsAffected" : 1, "insertId" : 1}}]
366
+
367
+ int rows_affected = sqlite3_total_changes(m_DB) - total_changes;
368
+
369
+ cJSON_AddItemToArray(result, CreateJSONSuccessObject(rows, rows_affected, qid_value.c_str(), isHESAMode, isExecute, columns));
370
+
371
+ statement = statement->next;
372
+ }
373
+
374
+ if (req_begin)
375
+ {
376
+ if (req_commit)
377
+ {
378
+ commit();
379
+ endTransaction();
380
+ }
381
+ else
382
+ {
383
+ endTransaction();
384
+
385
+ if (req_rollback)
386
+ {
387
+ handleException(tx_rollback_reason, 0);
388
+ }
389
+ }
390
+ }
391
+
392
+ if (enableLog)
393
+ {
394
+ t.stop();
395
+
396
+ timer_ticks ticks = t.get_elapsed_us();
397
+ double performance = t.ticks_to_ms(ticks) / 1000;
398
+
399
+ if (LogAdapter::logPerformance()) LogPerformance("universalParameterizedBatch", performance);
400
+ }
401
+
402
+ return result;
403
+ }
404
+
405
+ cJSON * SimpleDBConnection::CreateJSONErrorObject(const char *msg, const char *qid, bool isHESAMode, bool isExecute)
406
+ {
407
+ cJSON *err = cJSON_CreateObject();
408
+
409
+ if (isHESAMode)
410
+ {
411
+ cJSON_AddStringToObject(err, "qid", qid);
412
+
413
+ if (isExecute)
414
+ {
415
+ cJSON_AddBoolToObject(err, "result", false);
416
+ cJSON_AddNumberToObject(err, "rowsAffected", 0);
417
+ }
418
+ else
419
+ {
420
+ cJSON *rows = cJSON_CreateArray();
421
+ cJSON_AddItemToObject(err, "result", rows);
422
+ }
423
+ }
424
+ else
425
+ {
426
+ cJSON *res = cJSON_CreateObject();
427
+ cJSON_AddStringToObject(err, "type", "error");
428
+ cJSON_AddNumberToObject(res, "code", -1);
429
+ cJSON_AddStringToObject(res, "message", msg);
430
+ cJSON_AddItemToObject(err, "result", res);
431
+ }
432
+
433
+ return err;
434
+ }
435
+
436
+ int SimpleDBConnection::msleep(long int msec)
437
+ {
438
+ if (msec < 0) return -1;
439
+
440
+ if (LogAdapter::logDebug()) LogAdapter::Console("sleep()");
441
+ #if defined(WIN32) || defined(WINAPI_FAMILY)
442
+
443
+ Sleep(msec);
444
+ return 0;
445
+ #else
446
+ struct timespec timeout0;
447
+ struct timespec timeout1;
448
+
449
+ struct timespec* t0 = &timeout0;
450
+ struct timespec* t1 = &timeout1;
451
+ struct timespec* tmp;
452
+
453
+ t0->tv_sec = msec / 1000;
454
+ t0->tv_nsec = (msec % 1000) * (1000 * 1000);
455
+
456
+ while (nanosleep(t0, t1) == -1) {
457
+ if (errno == EINTR) {
458
+ tmp = t0; t0 = t1; t1 = tmp;
459
+ }
460
+ else {
461
+ return -1;
462
+ }
463
+ }
464
+
465
+ return 0;
466
+ #endif
467
+ }
468
+
469
+
470
+ int SimpleDBConnection::concurrent_step(sqlite3_stmt *stmt)
471
+ {
472
+ int rc;
473
+ int n=0;
474
+
475
+ do {
476
+ rc = sqlite3_step(stmt);
477
+
478
+ if (rc == SQLITE_LOCKED) {
479
+ rc = sqlite3_reset(stmt); /** Note: This will return SQLITE_LOCKED as well... **/
480
+ n++;
481
+ msleep(SLEEP_LOCK_MS);
482
+ } else if (rc == SQLITE_BUSY) {
483
+ msleep(SLEEP_LOCK_MS);
484
+ n++;
485
+ }
486
+ } while ((n < SLEEP_LOCK_TIMES) && ((rc == SQLITE_BUSY) || (rc == SQLITE_LOCKED)));
487
+
488
+ if ((rc != SQLITE_ROW && (rc != SQLITE_DONE) && (rc != SQLITE_SCHEMA))) {
489
+ if (LogAdapter::logConsole()) LogAdapter::Console(StringFormat("Failed concurrent_step(): %d", rc).c_str());
490
+ }
491
+
492
+ return rc;
493
+ }
494
+
495
+ cJSON * SimpleDBConnection::CreateJSONSuccessObject(cJSON *rows, int rows_affected, const char *qid, bool isHESAMode, bool isExecute, cJSON *columns)
496
+ {
497
+ cJSON *ok = cJSON_CreateObject();
498
+
499
+ if (isHESAMode)
500
+ {
501
+ cJSON_Delete(columns);
502
+ cJSON_AddStringToObject(ok, "qid", qid);
503
+
504
+ if (isExecute)
505
+ {
506
+ cJSON_AddBoolToObject(ok, "result", true);
507
+ cJSON_AddNumberToObject(ok, "rowsAffected", rows_affected);
508
+ }
509
+ else
510
+ {
511
+ cJSON_AddItemToObject(ok, "result", rows);
512
+ }
513
+ }
514
+ else
515
+ {
516
+ cJSON *res = cJSON_CreateObject();
517
+ cJSON_AddStringToObject(ok, "type", "success");
518
+ cJSON_AddItemToObject(res, "rows", rows);
519
+ cJSON_AddNumberToObject(res, "rowsAffected", rows_affected);
520
+ if (rows_affected > 0) cJSON_AddNumberToObject(res, "insertId", (double)sqlite3_last_insert_rowid(m_DB));
521
+ if (columns != NULL) cJSON_AddItemToObject(res, "columns", columns);
522
+
523
+ cJSON_AddItemToObject(ok, "result", res);
524
+ }
525
+
526
+ return ok;
527
+ }
528
+
529
+ bool SimpleDBConnection::beginTransaction()
530
+ {
531
+ if (LogAdapter::logConsole()) LogAdapter::Console("beginTransaction()");
532
+
533
+ bool ret = false;
534
+
535
+ resetLastError();
536
+
537
+ if (inTransaction()) {
538
+ if (LogAdapter::logConsole()) LogAdapter::Console("beginTransaction() other transaction already started");
539
+ return ret;
540
+ }
541
+
542
+ if (!isValid()) {
543
+ handleException("beginTransaction() invalid call",0);
544
+ return false;
545
+ }
546
+
547
+ ret = concurrent_beginTransaction();
548
+
549
+ if (ret) {
550
+ m_bInTransaction=true;
551
+ m_bTransactionCommit=false;
552
+ }
553
+
554
+ if (LogAdapter::logDebug()) LogAdapter::Console(StringFormat("beginTransaction OK (%d)", ret).c_str());
555
+
556
+ return ret;
557
+ }
558
+
559
+ bool SimpleDBConnection::concurrent_prepare(sqlite3_stmt **stmt, const char * sql)
560
+ {
561
+ int rc;
562
+ int n=0;
563
+
564
+ do {
565
+ rc = sqlite3_prepare_v2(m_DB, sql, -1, stmt, NULL);
566
+
567
+ if ((rc == SQLITE_BUSY) || (rc == SQLITE_LOCKED)) {
568
+ n++;
569
+ msleep(SLEEP_LOCK_MS);
570
+ }
571
+ } while ((n < SLEEP_LOCK_TIMES) && ((rc == SQLITE_BUSY) || (rc == SQLITE_LOCKED)));
572
+
573
+ if (rc != SQLITE_OK) {
574
+ if (LogAdapter::logConsole()) LogAdapter::Console(StringFormat("Failed concurrent_prepare(): %d : %s", rc, sql).c_str());
575
+ }
576
+
577
+ return (rc == SQLITE_OK) ? true : false;
578
+ }
579
+
580
+ void SimpleDBConnection::bindParameters(sqlite3_stmt *stmt, cJSON *params) {
581
+ if (stmt == NULL || params == NULL) return;
582
+ if (params->type != cJSON_Array) return;
583
+
584
+ std::string cvt_true = "1";
585
+ std::string cvt_false = "0";
586
+
587
+ int param_count = cJSON_GetArraySize(params);
588
+
589
+ for (int i=0, j=1; i < param_count; i++, j++)
590
+ {
591
+ cJSON *param = cJSON_GetArrayItem(params, i);
592
+
593
+ switch (param->type)
594
+ {
595
+ case cJSON_String:
596
+ if (sqlite3_bind_text(stmt, j, param->valuestring, -1, SQLITE_STATIC) != SQLITE_OK) {} //Todo
597
+ break;
598
+
599
+ case cJSON_Number:
600
+ //Range of int and double is assumed equal in cJSON, so it will crash when parsing a large
601
+ //number before even coming to this point. You need to patch cJSON to allow big numbers.
602
+ if (fabs(param->valuedouble - (double)param->valueint) < 1E-14)
603
+ {
604
+ if (sqlite3_bind_int(stmt, j, param->valueint) != SQLITE_OK) {} //Todo
605
+ }
606
+ else
607
+ {
608
+ INT64 valueInt64 = (INT64)param->valuedouble;
609
+ if (fabs(param->valuedouble - (double)valueInt64) < 1E-14){
610
+ if (sqlite3_bind_int64(stmt, j, valueInt64) != SQLITE_OK) {} //Todo
611
+ } else {
612
+ if (sqlite3_bind_double(stmt, j, param->valuedouble) != SQLITE_OK) {} //Todo
613
+ }
614
+ }
615
+ break;
616
+
617
+ case cJSON_True:
618
+ if (sqlite3_bind_text(stmt, j, cvt_true.c_str(), -1, SQLITE_STATIC) != SQLITE_OK){} //Todo
619
+ break;
620
+
621
+ case cJSON_False:
622
+ if (sqlite3_bind_text(stmt, j, cvt_false.c_str(), -1, SQLITE_STATIC) != SQLITE_OK) {} //Todo
623
+ break;
624
+
625
+ default:
626
+ if (sqlite3_bind_null(stmt, j) != SQLITE_OK) {} //Todo
627
+ break;
628
+ }
629
+ }
630
+ }
631
+
632
+ bool SimpleDBConnection::endTransaction()
633
+ {
634
+ if (LogAdapter::logConsole()) LogAdapter::Console("endTransaction()");
635
+
636
+ bool ret = false;
637
+
638
+ resetLastError();
639
+
640
+ if (!inTransaction()) {
641
+ if (LogAdapter::logConsole()) LogAdapter::Console("endTransaction() no open transaction to end");
642
+ return ret;
643
+ }
644
+
645
+ if (!isValid()) {
646
+ handleException("endTransaction() invalid call",0);
647
+ return false;
648
+ }
649
+
650
+ ret = concurrent_endTransaction(m_bTransactionCommit);
651
+
652
+ if (ret) {
653
+ m_bInTransaction = false;
654
+ m_bTransactionCommit = false;
655
+ }
656
+ if (LogAdapter::logDebug()) LogAdapter::Console(StringFormat("endTransaction OK (%d)", ret).c_str());
657
+
658
+ return ret;
659
+ }
660
+
661
+
662
+ void SimpleDBConnection::handleException(const char *err_text, int err_code)
663
+ {
664
+ if (LogAdapter::logConsole()) LogAdapter::Console(err_text);
665
+ //Always set the last error after error logging which otherwise resets the last error.
666
+ setLastError(err_text, err_code);
667
+ }
668
+
669
+ void SimpleDBConnection::handleException(std::string& err_text, int err_code)
670
+ {
671
+ handleException(err_text.c_str(), err_code);
672
+ }
673
+
674
+ bool SimpleDBConnection::concurrent_beginTransaction()
675
+ {
676
+ int rc;
677
+ sqlite3_stmt* bt_stmt;
678
+
679
+ bt_stmt = NULL;
680
+
681
+ if (!concurrent_prepare(&bt_stmt, "BEGIN EXCLUSIVE TRANSACTION")) {
682
+ if (LogAdapter::logConsole()) LogAdapter::Console("Failed concurrent_beginTransaction() in prepare");
683
+ return false;
684
+ }
685
+
686
+ rc = concurrent_step(bt_stmt);
687
+
688
+ if (rc != SQLITE_DONE) {
689
+ if (LogAdapter::logConsole()) LogAdapter::Console(StringFormat("Failed concurrent_beginTransaction() in step: %d.", rc).c_str());
690
+ }
691
+
692
+ sqlite3_finalize(bt_stmt);
693
+
694
+ return (rc == SQLITE_DONE) ? true : false;
695
+ }
696
+
697
+ bool SimpleDBConnection::concurrent_endTransaction(bool bCommit)
698
+ {
699
+ int rc;
700
+ sqlite3_stmt* bt_stmt;
701
+
702
+ const char * sql = (bCommit) ? "COMMIT TRANSACTION" : "ROLLBACK TRANSACTION";
703
+
704
+ if (!concurrent_prepare(&bt_stmt, sql)) {
705
+ if (LogAdapter::logConsole()) LogAdapter::Console("Failed concurrent_endTransaction() in prepare");
706
+ return false;
707
+ }
708
+
709
+ rc = concurrent_step(bt_stmt);
710
+
711
+ if (rc != SQLITE_DONE) {
712
+ if (LogAdapter::logConsole()) LogAdapter::Console(StringFormat("Failed concurrent_endTransaction() in step: %d.", rc).c_str());
713
+ }
714
+
715
+ sqlite3_finalize(bt_stmt);
716
+
717
+ return (rc == SQLITE_DONE ) ? true : false;
718
+ }
719
+
720
+ void SimpleDBConnection::setLastError(std::string error_message, int error_code) {
721
+ m_sLastError = StringFormat("(%d) %s", error_code, error_message.c_str());
722
+ }
723
+
724
+
725
+ cJSON * SimpleDBConnection::CreateJSONQuery()
726
+ {
727
+ cJSON *qry = cJSON_CreateArray();
728
+
729
+ return qry;
730
+ }
731
+
732
+
733
+ cJSON * SimpleDBConnection::AddJSONQueryItem(cJSON *qry, const char *sql)
734
+ {
735
+ if (((cJSON *)0 != qry) && ((const char *)0 != sql))
736
+ {
737
+ cJSON *itm = cJSON_CreateObject();
738
+ cJSON *par = cJSON_CreateArray();
739
+
740
+ cJSON_AddStringToObject(itm, "sql", sql);
741
+ cJSON_AddItemToObject(itm, "params", par);
742
+
743
+ cJSON_AddItemToArray(qry, itm);
744
+
745
+ return par;
746
+ }
747
+ else
748
+ {
749
+ return (cJSON *)0;
750
+ }
751
+ }
752
+
753
+ void SimpleDBConnection::AddJSONQueryItemParam(cJSON *par, const char *str)
754
+ {
755
+ if ((cJSON *)0 != par)
756
+ {
757
+ if ((const char *)0 != str)
758
+ {
759
+ cJSON_AddItemToArray(par, cJSON_CreateString(str));
760
+ }
761
+ else
762
+ {
763
+ cJSON_AddItemToArray(par, cJSON_CreateNull());
764
+ }
765
+ }
766
+ }
767
+
768
+ void SimpleDBConnection::AddJSONQueryItemParam(cJSON *par, int d)
769
+ {
770
+ if ((cJSON *)0 != par)
771
+ {
772
+ cJSON_AddItemToArray(par, cJSON_CreateNumber((double)d));
773
+ }
774
+ }
775
+
776
+ void SimpleDBConnection::AddJSONQueryItemParam(cJSON *par, double dbl)
777
+ {
778
+ if ((cJSON *)0 != par)
779
+ {
780
+ cJSON_AddItemToArray(par, cJSON_CreateNumber(dbl));
781
+ }
782
+ }
783
+
784
+ void SimpleDBConnection::AddJSONQueryItemParam(cJSON *par, bool bln)
785
+ {
786
+ if ((cJSON *)0 != par)
787
+ {
788
+ cJSON_AddItemToArray(par, ((bln) ? cJSON_CreateTrue() : cJSON_CreateFalse()));
789
+ }
790
+ }
791
+
792
+ void SimpleDBConnection::ReplaceJSONSqlStatement(cJSON *query, const char* sqlStatement) {
793
+ if ((cJSON *)0 == query || ((const char *)0 == sqlStatement)) return;
794
+
795
+ cJSON *statement = query->child;
796
+ if ((cJSON *)0 != statement) {
797
+ cJSON_DeleteItemFromObject(statement, "sql");
798
+ cJSON_AddStringToObject(statement, "sql", sqlStatement);
799
+ }
800
+ }