@stoolap/node 0.3.4 → 0.3.7
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 +23 -2
- package/index.d.ts +6 -0
- package/lib/database.js +10 -2
- package/lib/transaction.js +4 -2
- package/package.json +7 -6
- package/src/stoolap.c +82 -18
package/README.md
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
# @stoolap/node
|
|
2
2
|
|
|
3
|
-
High-performance
|
|
3
|
+
High-performance JavaScript driver for [Stoolap](https://github.com/stoolap/stoolap), a modern embedded SQL database with MVCC, time-travel queries, and full ACID compliance.
|
|
4
4
|
|
|
5
|
-
Built with a native N-API C addon for minimal overhead. Provides both async and sync APIs.
|
|
5
|
+
Built with a native N-API C addon for minimal overhead. Works with Node.js, Bun, and Deno. Provides both async and sync APIs.
|
|
6
6
|
|
|
7
7
|
[](LICENSE)
|
|
8
8
|
[](https://nodejs.org)
|
|
9
|
+
[](https://bun.sh)
|
|
10
|
+
[](https://deno.com)
|
|
9
11
|
|
|
10
12
|
## Installation
|
|
11
13
|
|
|
@@ -106,6 +108,7 @@ Sync methods run on the main thread. Faster for simple operations but block the
|
|
|
106
108
|
| Method | Returns | Description |
|
|
107
109
|
|--------|---------|-------------|
|
|
108
110
|
| `Database.openSync(path)` | `Database` | Open a database |
|
|
111
|
+
| `clone()` | `Database` | Clone handle (shared engine, own state) |
|
|
109
112
|
| `executeSync(sql, params?)` | `RunResult` | Execute DML statement |
|
|
110
113
|
| `execSync(sql)` | `void` | Execute a DDL statement |
|
|
111
114
|
| `querySync(sql, params?)` | `Object[]` | Query rows as objects |
|
|
@@ -187,6 +190,24 @@ Controls the durability vs. performance trade-off:
|
|
|
187
190
|
| `compression` | | Set both `wal_compression` and `snapshot_compression` |
|
|
188
191
|
| `compression_threshold` | `64` | Minimum bytes before compressing an entry |
|
|
189
192
|
|
|
193
|
+
#### Cloning
|
|
194
|
+
|
|
195
|
+
`clone()` creates a new `Database` handle that shares the same underlying engine (data, indexes, transactions) but has its own executor and error state. Useful for concurrent access patterns such as worker threads.
|
|
196
|
+
|
|
197
|
+
```js
|
|
198
|
+
const db = await Database.open('./mydata');
|
|
199
|
+
const db2 = db.clone();
|
|
200
|
+
|
|
201
|
+
// Both see the same data
|
|
202
|
+
await db.execute('INSERT INTO users VALUES ($1, $2)', [1, 'Alice']);
|
|
203
|
+
const row = db2.queryOneSync('SELECT * FROM users WHERE id = $1', [1]);
|
|
204
|
+
// { id: 1, name: 'Alice' }
|
|
205
|
+
|
|
206
|
+
// Each clone must be closed independently
|
|
207
|
+
await db2.close();
|
|
208
|
+
await db.close();
|
|
209
|
+
```
|
|
210
|
+
|
|
190
211
|
#### Raw Query Format
|
|
191
212
|
|
|
192
213
|
`queryRaw` / `queryRawSync` return `{ columns: string[], rows: any[][] }` instead of an array of objects. Faster when you don't need named keys.
|
package/index.d.ts
CHANGED
|
@@ -17,6 +17,12 @@ export declare class Database {
|
|
|
17
17
|
* Open a database synchronously.
|
|
18
18
|
*/
|
|
19
19
|
static openSync(path: string): Database;
|
|
20
|
+
/**
|
|
21
|
+
* Clone this database handle. The clone shares the same underlying engine
|
|
22
|
+
* (data, indexes, transactions) but has its own executor and error state.
|
|
23
|
+
* Each clone must be closed independently.
|
|
24
|
+
*/
|
|
25
|
+
clone(): Database;
|
|
20
26
|
/**
|
|
21
27
|
* Execute a DDL/DML statement. Returns Promise<{ changes: number }>.
|
|
22
28
|
*
|
package/lib/database.js
CHANGED
|
@@ -128,6 +128,14 @@ class Database {
|
|
|
128
128
|
return this.#stoolap.dbExecBatchBuf(this.#ptr, sql, batchBuf);
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
+
// -- Clone --
|
|
132
|
+
|
|
133
|
+
clone() {
|
|
134
|
+
this.#checkOpen();
|
|
135
|
+
const clonedPtr = this.#stoolap.dbClone(this.#ptr);
|
|
136
|
+
return new Database(clonedPtr, this.#stoolap);
|
|
137
|
+
}
|
|
138
|
+
|
|
131
139
|
// -- Execute (DML) --
|
|
132
140
|
|
|
133
141
|
async execute(sql, params) {
|
|
@@ -312,7 +320,7 @@ class Database {
|
|
|
312
320
|
|
|
313
321
|
async begin() {
|
|
314
322
|
const txPtr = await this._beginAsync();
|
|
315
|
-
const tx = new Transaction(txPtr, this.#stoolap, this);
|
|
323
|
+
const tx = new Transaction(txPtr, this.#stoolap, this, this.#ptr);
|
|
316
324
|
this._trackChild(tx);
|
|
317
325
|
return tx;
|
|
318
326
|
}
|
|
@@ -320,7 +328,7 @@ class Database {
|
|
|
320
328
|
beginSync() {
|
|
321
329
|
this.#checkOpen();
|
|
322
330
|
const txPtr = this.#stoolap.txBegin(this.#ptr);
|
|
323
|
-
const tx = new Transaction(txPtr, this.#stoolap, this);
|
|
331
|
+
const tx = new Transaction(txPtr, this.#stoolap, this, this.#ptr);
|
|
324
332
|
this._trackChild(tx);
|
|
325
333
|
return tx;
|
|
326
334
|
}
|
package/lib/transaction.js
CHANGED
|
@@ -6,15 +6,17 @@ const { parseRows, parseRaw } = require("./parse");
|
|
|
6
6
|
class Transaction {
|
|
7
7
|
#ptr = null;
|
|
8
8
|
#stoolap = null;
|
|
9
|
+
#dbPtr = null;
|
|
9
10
|
#pendingAsync = 0;
|
|
10
11
|
#tail = Promise.resolve();
|
|
11
12
|
#closingPromise = null;
|
|
12
13
|
#owner = null;
|
|
13
14
|
|
|
14
|
-
constructor(ptr, stoolap, owner) {
|
|
15
|
+
constructor(ptr, stoolap, owner, dbPtr) {
|
|
15
16
|
this.#ptr = ptr;
|
|
16
17
|
this.#stoolap = stoolap;
|
|
17
18
|
this.#owner = owner || null;
|
|
19
|
+
this.#dbPtr = dbPtr || null;
|
|
18
20
|
}
|
|
19
21
|
|
|
20
22
|
_invalidate() {
|
|
@@ -177,7 +179,7 @@ class Transaction {
|
|
|
177
179
|
executeBatchSync(sql, paramsArray) {
|
|
178
180
|
this.#checkSyncReady();
|
|
179
181
|
if (paramsArray.length > 0 && Array.isArray(paramsArray[0])) {
|
|
180
|
-
return this.#stoolap.txExecBatch(this.#ptr, sql, paramsArray);
|
|
182
|
+
return this.#stoolap.txExecBatch(this.#dbPtr, this.#ptr, sql, paramsArray);
|
|
181
183
|
}
|
|
182
184
|
let totalChanges = 0;
|
|
183
185
|
for (const params of paramsArray) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stoolap/node",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.7",
|
|
4
4
|
"description": "High-performance Node.js driver for Stoolap embedded SQL database",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -13,15 +13,16 @@
|
|
|
13
13
|
],
|
|
14
14
|
"scripts": {
|
|
15
15
|
"install": "node-gyp rebuild",
|
|
16
|
+
"build": "node-gyp rebuild",
|
|
16
17
|
"test": "node --test __test__/index.spec.mjs",
|
|
17
18
|
"bench": "node benchmark.mjs"
|
|
18
19
|
},
|
|
19
20
|
"optionalDependencies": {
|
|
20
|
-
"@stoolap/lib-darwin-arm64": "0.3.
|
|
21
|
-
"@stoolap/lib-darwin-x64": "0.3.
|
|
22
|
-
"@stoolap/lib-linux-arm64-gnu": "0.3.
|
|
23
|
-
"@stoolap/lib-linux-x64-gnu": "0.3.
|
|
24
|
-
"@stoolap/lib-win32-x64-msvc": "0.3.
|
|
21
|
+
"@stoolap/lib-darwin-arm64": "0.3.7",
|
|
22
|
+
"@stoolap/lib-darwin-x64": "0.3.7",
|
|
23
|
+
"@stoolap/lib-linux-arm64-gnu": "0.3.7",
|
|
24
|
+
"@stoolap/lib-linux-x64-gnu": "0.3.7",
|
|
25
|
+
"@stoolap/lib-win32-x64-msvc": "0.3.7"
|
|
25
26
|
},
|
|
26
27
|
"devDependencies": {
|
|
27
28
|
"better-sqlite3": "^12.6.2",
|
package/src/stoolap.c
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
#include <stdlib.h>
|
|
13
13
|
#include <string.h>
|
|
14
14
|
#include <stdint.h>
|
|
15
|
+
#include <stdio.h>
|
|
15
16
|
|
|
16
17
|
#ifdef _WIN32
|
|
17
18
|
#include <windows.h>
|
|
@@ -68,6 +69,7 @@ typedef struct {
|
|
|
68
69
|
typedef const char* (*fn_version)(void);
|
|
69
70
|
typedef int32_t (*fn_open)(const char*, StoolapDB**);
|
|
70
71
|
typedef int32_t (*fn_open_mem)(StoolapDB**);
|
|
72
|
+
typedef int32_t (*fn_clone)(StoolapDB*, StoolapDB**);
|
|
71
73
|
typedef int32_t (*fn_close)(StoolapDB*);
|
|
72
74
|
typedef const char* (*fn_errmsg)(const StoolapDB*);
|
|
73
75
|
typedef int32_t (*fn_exec)(StoolapDB*, const char*, int64_t*);
|
|
@@ -85,6 +87,8 @@ typedef int32_t (*fn_tx_exec)(StoolapTx*, const char*, int64_t*);
|
|
|
85
87
|
typedef int32_t (*fn_tx_exec_p)(StoolapTx*, const char*, const StoolapValue*, int32_t, int64_t*);
|
|
86
88
|
typedef int32_t (*fn_tx_query)(StoolapTx*, const char*, StoolapRows**);
|
|
87
89
|
typedef int32_t (*fn_tx_query_p)(StoolapTx*, const char*, const StoolapValue*, int32_t, StoolapRows**);
|
|
90
|
+
typedef int32_t (*fn_tx_stmt_exec)(StoolapTx*, StoolapStmt*, const StoolapValue*, int32_t, int64_t*);
|
|
91
|
+
typedef int32_t (*fn_tx_stmt_query)(StoolapTx*, StoolapStmt*, const StoolapValue*, int32_t, StoolapRows**);
|
|
88
92
|
typedef int32_t (*fn_tx_commit)(StoolapTx*);
|
|
89
93
|
typedef int32_t (*fn_tx_rollback)(StoolapTx*);
|
|
90
94
|
typedef const char* (*fn_tx_errmsg)(const StoolapTx*);
|
|
@@ -110,6 +114,7 @@ static struct {
|
|
|
110
114
|
fn_version version;
|
|
111
115
|
fn_open open;
|
|
112
116
|
fn_open_mem open_mem;
|
|
117
|
+
fn_clone clone;
|
|
113
118
|
fn_close close;
|
|
114
119
|
fn_errmsg errmsg;
|
|
115
120
|
fn_exec exec;
|
|
@@ -127,6 +132,8 @@ static struct {
|
|
|
127
132
|
fn_tx_exec_p tx_exec_p;
|
|
128
133
|
fn_tx_query tx_query;
|
|
129
134
|
fn_tx_query_p tx_query_p;
|
|
135
|
+
fn_tx_stmt_exec tx_stmt_exec;
|
|
136
|
+
fn_tx_stmt_query tx_stmt_query;
|
|
130
137
|
fn_tx_commit tx_commit;
|
|
131
138
|
fn_tx_rollback tx_rollback;
|
|
132
139
|
fn_tx_errmsg tx_errmsg;
|
|
@@ -152,6 +159,8 @@ static LibHandle lib_handle = NULL;
|
|
|
152
159
|
/* ---- Helpers ---- */
|
|
153
160
|
|
|
154
161
|
#define THROW(env, msg) do { napi_throw_error(env, NULL, msg); return NULL; } while(0)
|
|
162
|
+
#define ERR_SAVE(msg, fallback) \
|
|
163
|
+
char _eb[512]; snprintf(_eb, sizeof(_eb), "%s", (msg) ? (msg) : (fallback))
|
|
155
164
|
#define CHECK(env, status) if ((status) != napi_ok) return NULL
|
|
156
165
|
|
|
157
166
|
static napi_value make_changes(napi_env env, int64_t n) {
|
|
@@ -1506,6 +1515,7 @@ static napi_value fn_load_library(napi_env env, napi_callback_info info) {
|
|
|
1506
1515
|
LOAD(version, "stoolap_version");
|
|
1507
1516
|
LOAD(open, "stoolap_open");
|
|
1508
1517
|
LOAD(open_mem, "stoolap_open_in_memory");
|
|
1518
|
+
LOAD(clone, "stoolap_clone");
|
|
1509
1519
|
LOAD(close, "stoolap_close");
|
|
1510
1520
|
LOAD(errmsg, "stoolap_errmsg");
|
|
1511
1521
|
LOAD(exec, "stoolap_exec");
|
|
@@ -1523,6 +1533,10 @@ static napi_value fn_load_library(napi_env env, napi_callback_info info) {
|
|
|
1523
1533
|
LOAD(tx_exec_p, "stoolap_tx_exec_params");
|
|
1524
1534
|
LOAD(tx_query, "stoolap_tx_query");
|
|
1525
1535
|
LOAD(tx_query_p, "stoolap_tx_query_params");
|
|
1536
|
+
/* Optional symbols — not in all engine versions */
|
|
1537
|
+
S.tx_stmt_exec = (fn_tx_stmt_exec) DLSYM(lib_handle, "stoolap_tx_stmt_exec");
|
|
1538
|
+
S.tx_stmt_query = (fn_tx_stmt_query)DLSYM(lib_handle, "stoolap_tx_stmt_query");
|
|
1539
|
+
|
|
1526
1540
|
LOAD(tx_commit, "stoolap_tx_commit");
|
|
1527
1541
|
LOAD(tx_rollback, "stoolap_tx_rollback");
|
|
1528
1542
|
LOAD(tx_errmsg, "stoolap_tx_errmsg");
|
|
@@ -1578,6 +1592,27 @@ static napi_value fn_db_open(napi_env env, napi_callback_info info) {
|
|
|
1578
1592
|
return ext;
|
|
1579
1593
|
}
|
|
1580
1594
|
|
|
1595
|
+
/* dbClone(external): external */
|
|
1596
|
+
static napi_value fn_db_clone(napi_env env, napi_callback_info info) {
|
|
1597
|
+
size_t argc = 1;
|
|
1598
|
+
napi_value argv[1];
|
|
1599
|
+
napi_get_cb_info(env, info, &argc, argv, NULL, NULL);
|
|
1600
|
+
|
|
1601
|
+
StoolapDB* db;
|
|
1602
|
+
napi_get_value_external(env, argv[0], (void**)&db);
|
|
1603
|
+
|
|
1604
|
+
StoolapDB* cloned = NULL;
|
|
1605
|
+
int32_t rc = S.clone(db, &cloned);
|
|
1606
|
+
if (rc != STOOLAP_OK) {
|
|
1607
|
+
const char* msg = S.errmsg(db);
|
|
1608
|
+
THROW(env, msg ? msg : "Failed to clone database");
|
|
1609
|
+
}
|
|
1610
|
+
|
|
1611
|
+
napi_value ext;
|
|
1612
|
+
napi_create_external(env, cloned, NULL, NULL, &ext);
|
|
1613
|
+
return ext;
|
|
1614
|
+
}
|
|
1615
|
+
|
|
1581
1616
|
/* dbClose(external): void */
|
|
1582
1617
|
static napi_value fn_db_close(napi_env env, napi_callback_info info) {
|
|
1583
1618
|
size_t argc = 1;
|
|
@@ -2948,22 +2983,37 @@ static napi_value wrap_tx_rollback_async(napi_env env, napi_callback_info info)
|
|
|
2948
2983
|
* Batch exec in C — copies SQL once, pre-allocates param buffers,
|
|
2949
2984
|
* loops param sets in C. Eliminates N × JS↔C crossings + N×malloc/free. */
|
|
2950
2985
|
static napi_value wrap_tx_exec_batch(napi_env env, napi_callback_info info) {
|
|
2951
|
-
size_t argc =
|
|
2952
|
-
napi_value argv[
|
|
2986
|
+
size_t argc = 4;
|
|
2987
|
+
napi_value argv[4];
|
|
2953
2988
|
napi_get_cb_info(env, info, &argc, argv, NULL, NULL);
|
|
2954
2989
|
|
|
2990
|
+
StoolapDB* db;
|
|
2991
|
+
napi_get_value_external(env, argv[0], (void**)&db);
|
|
2992
|
+
|
|
2955
2993
|
StoolapTx* tx;
|
|
2956
|
-
napi_get_value_external(env, argv[
|
|
2994
|
+
napi_get_value_external(env, argv[1], (void**)&tx);
|
|
2957
2995
|
|
|
2958
|
-
GET_SQL_STRING(env, argv[
|
|
2996
|
+
GET_SQL_STRING(env, argv[2], sql);
|
|
2959
2997
|
|
|
2960
2998
|
uint32_t batch_len;
|
|
2961
|
-
napi_get_array_length(env, argv[
|
|
2999
|
+
napi_get_array_length(env, argv[3], &batch_len);
|
|
2962
3000
|
if (batch_len == 0) return make_changes(env, 0);
|
|
2963
3001
|
|
|
3002
|
+
/* Prepare statement once if tx_stmt_exec is available */
|
|
3003
|
+
StoolapStmt* stmt = NULL;
|
|
3004
|
+
int use_stmt = (S.tx_stmt_exec != NULL);
|
|
3005
|
+
int32_t rc;
|
|
3006
|
+
if (use_stmt) {
|
|
3007
|
+
rc = S.prepare(db, sql, &stmt);
|
|
3008
|
+
if (rc != STOOLAP_OK) {
|
|
3009
|
+
const char* msg = S.errmsg(db);
|
|
3010
|
+
THROW(env, msg ? msg : "Prepare error");
|
|
3011
|
+
}
|
|
3012
|
+
}
|
|
3013
|
+
|
|
2964
3014
|
/* Get param count from first element — pre-allocate ONCE */
|
|
2965
3015
|
napi_value first_arr;
|
|
2966
|
-
napi_get_element(env, argv[
|
|
3016
|
+
napi_get_element(env, argv[3], 0, &first_arr);
|
|
2967
3017
|
uint32_t param_count;
|
|
2968
3018
|
napi_get_array_length(env, first_arr, ¶m_count);
|
|
2969
3019
|
|
|
@@ -2974,7 +3024,7 @@ static napi_value wrap_tx_exec_batch(napi_env env, napi_callback_info info) {
|
|
|
2974
3024
|
|
|
2975
3025
|
for (uint32_t i = 0; i < batch_len; i++) {
|
|
2976
3026
|
napi_value params_arr;
|
|
2977
|
-
napi_get_element(env, argv[
|
|
3027
|
+
napi_get_element(env, argv[3], i, ¶ms_arr);
|
|
2978
3028
|
|
|
2979
3029
|
/* Convert params into pre-allocated buffers */
|
|
2980
3030
|
int tbuf_cnt = 0;
|
|
@@ -2982,23 +3032,28 @@ static napi_value wrap_tx_exec_batch(napi_env env, napi_callback_info info) {
|
|
|
2982
3032
|
napi_value elem;
|
|
2983
3033
|
napi_get_element(env, params_arr, j, &elem);
|
|
2984
3034
|
if (js_to_value(env, elem, &vals[j], tbufs, &tbuf_cnt) != 0) {
|
|
2985
|
-
/* Cleanup on error */
|
|
2986
3035
|
for (int k = 0; k < tbuf_cnt; k++) free(tbufs[k]);
|
|
2987
3036
|
free(vals); free(tbufs);
|
|
3037
|
+
if (stmt) S.stmt_finalize(stmt);
|
|
2988
3038
|
THROW(env, "Failed to convert parameters");
|
|
2989
3039
|
}
|
|
2990
3040
|
}
|
|
2991
3041
|
|
|
2992
3042
|
int64_t affected = 0;
|
|
2993
|
-
|
|
3043
|
+
if (use_stmt) {
|
|
3044
|
+
rc = S.tx_stmt_exec(tx, stmt, vals, (int32_t)param_count, &affected);
|
|
3045
|
+
} else {
|
|
3046
|
+
rc = S.tx_exec_p(tx, sql, vals, (int32_t)param_count, &affected);
|
|
3047
|
+
}
|
|
2994
3048
|
|
|
2995
3049
|
/* Free only text buffers, keep vals/tbufs arrays for reuse */
|
|
2996
3050
|
for (int k = 0; k < tbuf_cnt; k++) { free(tbufs[k]); tbufs[k] = NULL; }
|
|
2997
3051
|
|
|
2998
3052
|
if (rc != STOOLAP_OK) {
|
|
3053
|
+
ERR_SAVE(S.tx_errmsg(tx), "Transaction batch exec error");
|
|
2999
3054
|
free(vals); free(tbufs);
|
|
3000
|
-
|
|
3001
|
-
THROW(env,
|
|
3055
|
+
if (stmt) S.stmt_finalize(stmt);
|
|
3056
|
+
THROW(env, _eb);
|
|
3002
3057
|
}
|
|
3003
3058
|
|
|
3004
3059
|
total_affected += affected;
|
|
@@ -3006,6 +3061,7 @@ static napi_value wrap_tx_exec_batch(napi_env env, napi_callback_info info) {
|
|
|
3006
3061
|
|
|
3007
3062
|
free(vals);
|
|
3008
3063
|
free(tbufs);
|
|
3064
|
+
if (stmt) S.stmt_finalize(stmt);
|
|
3009
3065
|
return make_changes(env, total_affected);
|
|
3010
3066
|
}
|
|
3011
3067
|
|
|
@@ -3170,23 +3226,30 @@ static napi_value wrap_db_exec_batch_buf(napi_env env, napi_callback_info info)
|
|
|
3170
3226
|
int32_t rc = S.begin(db, &tx);
|
|
3171
3227
|
if (rc != STOOLAP_OK) { const char* msg = S.errmsg(db); THROW(env, msg ? msg : "Begin error"); }
|
|
3172
3228
|
StoolapStmt* stmt = NULL;
|
|
3173
|
-
|
|
3174
|
-
if (
|
|
3229
|
+
int use_stmt = (S.tx_stmt_exec != NULL);
|
|
3230
|
+
if (use_stmt) {
|
|
3231
|
+
rc = S.prepare(db, sql, &stmt);
|
|
3232
|
+
if (rc != STOOLAP_OK) { ERR_SAVE(S.errmsg(db), "Prepare error"); S.tx_rollback(tx); THROW(env, _eb); }
|
|
3233
|
+
}
|
|
3175
3234
|
int64_t total = 0;
|
|
3176
3235
|
for (uint32_t i = 0; i < row_count; i++) {
|
|
3177
3236
|
StoolapValue vals[MAX_STACK_PARAMS];
|
|
3178
3237
|
size_t consumed = 0;
|
|
3179
3238
|
int decoded = decode_params_buf(ptr, (size_t)(end - ptr), vals, ppr, &consumed);
|
|
3180
|
-
if (decoded != ppr) { S.stmt_finalize(stmt); S.tx_rollback(tx); THROW(env, "Batch param decode error"); }
|
|
3239
|
+
if (decoded != ppr) { if (stmt) S.stmt_finalize(stmt); S.tx_rollback(tx); THROW(env, "Batch param decode error"); }
|
|
3181
3240
|
ptr += consumed;
|
|
3182
3241
|
int64_t affected = 0;
|
|
3183
|
-
|
|
3184
|
-
|
|
3242
|
+
if (use_stmt) {
|
|
3243
|
+
rc = S.tx_stmt_exec(tx, stmt, vals, decoded, &affected);
|
|
3244
|
+
} else {
|
|
3245
|
+
rc = S.tx_exec_p(tx, sql, vals, decoded, &affected);
|
|
3246
|
+
}
|
|
3247
|
+
if (rc != STOOLAP_OK) { ERR_SAVE(S.tx_errmsg(tx), "Batch exec error"); if (stmt) S.stmt_finalize(stmt); S.tx_rollback(tx); THROW(env, _eb); }
|
|
3185
3248
|
total += affected;
|
|
3186
3249
|
}
|
|
3187
|
-
S.stmt_finalize(stmt);
|
|
3250
|
+
if (stmt) S.stmt_finalize(stmt);
|
|
3188
3251
|
rc = S.tx_commit(tx);
|
|
3189
|
-
if (rc != STOOLAP_OK) {
|
|
3252
|
+
if (rc != STOOLAP_OK) { THROW(env, "Commit error"); }
|
|
3190
3253
|
return make_changes(env, total);
|
|
3191
3254
|
}
|
|
3192
3255
|
|
|
@@ -3242,6 +3305,7 @@ static napi_value Init(napi_env env, napi_value exports) {
|
|
|
3242
3305
|
EXPORT_FN(env, exports, "loadLibrary", fn_load_library);
|
|
3243
3306
|
EXPORT_FN(env, exports, "dbOpen", fn_db_open);
|
|
3244
3307
|
EXPORT_FN(env, exports, "dbOpenAsync", fn_db_open_async);
|
|
3308
|
+
EXPORT_FN(env, exports, "dbClone", fn_db_clone);
|
|
3245
3309
|
EXPORT_FN(env, exports, "dbClose", fn_db_close);
|
|
3246
3310
|
EXPORT_FN(env, exports, "dbCloseAsync", fn_db_close_async);
|
|
3247
3311
|
EXPORT_FN(env, exports, "dbExec", fn_db_exec);
|