node-firebird 2.6.0 → 2.7.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.
- package/README.md +60 -4
- package/lib/types.d.ts +35 -0
- package/lib/wire/connection.d.ts +15 -0
- package/lib/wire/connection.js +461 -0
- package/lib/wire/const.d.ts +15 -0
- package/lib/wire/const.js +21 -0
- package/lib/wire/database.d.ts +11 -0
- package/lib/wire/database.js +46 -0
- package/lib/wire/serialize.d.ts +2 -1
- package/lib/wire/serialize.js +9 -4
- package/lib/wire/statement.d.ts +6 -0
- package/lib/wire/statement.js +11 -0
- package/lib/wire/transaction.d.ts +11 -0
- package/lib/wire/transaction.js +27 -0
- package/lib/wire/xsqlvar.d.ts +9 -0
- package/lib/wire/xsqlvar.js +22 -11
- package/package.json +1 -1
- package/src/types.ts +35 -0
- package/src/wire/connection.ts +498 -0
- package/src/wire/const.ts +22 -0
- package/src/wire/database.ts +53 -0
- package/src/wire/serialize.ts +11 -5
- package/src/wire/statement.ts +13 -0
- package/src/wire/transaction.ts +30 -0
- package/src/wire/xsqlvar.ts +25 -14
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
- [Connection types](#connection-types) — connection options, classic connections, pooling
|
|
15
15
|
- [Database object (db)](#database-object-db) — database, transaction and statement methods/options
|
|
16
16
|
- [Examples](#examples) — parametrized queries, BLOBs, streaming big data, transactions, driver events, database events (POST_EVENT), service manager, charsets/encoding, Firebird 3.0–6.0 features
|
|
17
|
-
- [Extensive Examples](#extensive-examples) — DECFLOAT/INT128, query cancellation (AbortSignal), statement timeouts, scrollable cursors, RETURNING multiple rows, SKIP LOCKED, advanced pooling
|
|
17
|
+
- [Extensive Examples](#extensive-examples) — DECFLOAT/INT128, query cancellation (AbortSignal), batch execution (bulk inserts), statement timeouts, scrollable cursors, RETURNING multiple rows, SKIP LOCKED, advanced pooling
|
|
18
18
|
- [Using node-firebird with Express.js](#using-node-firebird-with-expressjs)
|
|
19
19
|
- [FAQ](#faq)
|
|
20
20
|
- [Contributing](#contributing) · [Contributors](#contributors)
|
|
@@ -133,9 +133,9 @@ Available wrappers:
|
|
|
133
133
|
|
|
134
134
|
- **module** — `Firebird.attachAsync(options)`, `createAsync`, `attachOrCreateAsync`, `dropAsync`; resolve with a `Database` (or a `ServiceManager` when `options.manager` is `true`)
|
|
135
135
|
- **pool** — `pool.getAsync()`, `pool.destroyAsync()`, `pool.withConnection(work)`
|
|
136
|
-
- **database** — `db.queryAsync(sql, params?, options?)`, `executeAsync`, `sequentiallyAsync(sql, params?, onRow, options?)`, `transactionAsync(options?)`, `newStatementAsync(sql)`, `attachEventAsync()`, `detachAsync()`, `dropAsync()`, `db.withTransaction(work, options?)`
|
|
137
|
-
- **transaction** — `queryAsync`, `executeAsync`, `sequentiallyAsync`, `newStatementAsync`, `commitAsync`, `rollbackAsync`, `commitRetainingAsync`, `rollbackRetainingAsync`
|
|
138
|
-
- **statement** — `executeAsync(transaction, params?, options?)`, `fetchAsync`, `fetchScrollAsync`, `fetchAllAsync`, `closeAsync`, `dropAsync`, `releaseAsync`
|
|
136
|
+
- **database** — `db.queryAsync(sql, params?, options?)`, `executeAsync`, `executeBatchAsync(sql, rows, options?)`, `sequentiallyAsync(sql, params?, onRow, options?)`, `transactionAsync(options?)`, `newStatementAsync(sql)`, `attachEventAsync()`, `detachAsync()`, `dropAsync()`, `db.withTransaction(work, options?)`
|
|
137
|
+
- **transaction** — `queryAsync`, `executeAsync`, `executeBatchAsync`, `sequentiallyAsync`, `newStatementAsync`, `commitAsync`, `rollbackAsync`, `commitRetainingAsync`, `rollbackRetainingAsync`
|
|
138
|
+
- **statement** — `executeAsync(transaction, params?, options?)`, `executeBatchAsync(transaction, rows, options?)`, `fetchAsync`, `fetchScrollAsync`, `fetchAllAsync`, `closeAsync`, `dropAsync`, `releaseAsync`
|
|
139
139
|
|
|
140
140
|
Notes:
|
|
141
141
|
|
|
@@ -277,6 +277,7 @@ sequenceDiagram
|
|
|
277
277
|
|
|
278
278
|
- `db.query(query, [params], function(err, result), options)` - classic query, returns Array of Object
|
|
279
279
|
- `db.execute(query, [params], function(err, result), options)` - classic query, returns Array of Array
|
|
280
|
+
- `db.executeBatch(query, rows, function(err, result), options)` - bulk execution in one round-trip, all-or-nothing (FB >= 4.0, see [Batch Execution](#batch-execution-firebird-40))
|
|
280
281
|
- `db.sequentially(query, [params], function(row, index), function(err), options)` - sequentially query
|
|
281
282
|
- `db.detach(function(err))` detach a database
|
|
282
283
|
- `db.transaction(options, function(err, transaction))` create transaction
|
|
@@ -303,6 +304,7 @@ const options = {
|
|
|
303
304
|
|
|
304
305
|
- `transaction.query(query, [params], function(err, result), options)` - classic query, returns Array of Object
|
|
305
306
|
- `transaction.execute(query, [params], function(err, result), options)` - classic query, returns Array of Array
|
|
307
|
+
- `transaction.executeBatch(query, rows, function(err, result), options)` - bulk execution with per-record errors (FB >= 4.0, see [Batch Execution](#batch-execution-firebird-40))
|
|
306
308
|
- `transaction.sequentially(query, [params], function(row, index), function(err), options)` - sequentially query
|
|
307
309
|
- `transaction.commit(function(err))` commit current transaction
|
|
308
310
|
- `transaction.rollback(function(err))` rollback current transaction
|
|
@@ -1192,6 +1194,60 @@ Notes:
|
|
|
1192
1194
|
- A signal that is already aborted rejects immediately with an `AbortError`
|
|
1193
1195
|
without contacting the server; cancelling an idle connection is harmless.
|
|
1194
1196
|
|
|
1197
|
+
### Batch Execution (Firebird 4.0+)
|
|
1198
|
+
|
|
1199
|
+
`executeBatch` sends many parameter rows for one statement in a single
|
|
1200
|
+
round-trip using the Firebird 4 wire batch API (`op_batch_create` /
|
|
1201
|
+
`op_batch_msg` / `op_batch_exec`) — typically 5–10× faster than executing
|
|
1202
|
+
row by row. Available on the database, transaction and statement objects, in
|
|
1203
|
+
callback and promise flavours.
|
|
1204
|
+
|
|
1205
|
+
```js
|
|
1206
|
+
const rows = [
|
|
1207
|
+
[1, 'Alice', 10.50, new Date(), true, 100n],
|
|
1208
|
+
[2, 'Bob', null, new Date(), false, null], // NULLs per column
|
|
1209
|
+
[3, 'Carol', 7.25, new Date(), true, 300n],
|
|
1210
|
+
];
|
|
1211
|
+
|
|
1212
|
+
// database level: own transaction, all-or-nothing (rollback if any record fails)
|
|
1213
|
+
const res = await db.executeBatchAsync(
|
|
1214
|
+
'INSERT INTO t (id, name, amount, created, active, big) VALUES (?, ?, ?, ?, ?, ?)',
|
|
1215
|
+
rows);
|
|
1216
|
+
console.log(res.recordCount, res.updateCounts, res.success);
|
|
1217
|
+
|
|
1218
|
+
// transaction level: partial success — failed records are reported,
|
|
1219
|
+
// the rest can still be committed
|
|
1220
|
+
const tr = await db.transactionAsync();
|
|
1221
|
+
const r = await tr.executeBatchAsync('INSERT INTO t (...) VALUES (?, ?, ?, ?, ?, ?)', rows);
|
|
1222
|
+
if (!r.success) {
|
|
1223
|
+
console.log('failed record indexes:', r.errorRecordNumbers); // 0-based
|
|
1224
|
+
console.log('first error:', r.errors[0].error.message);
|
|
1225
|
+
}
|
|
1226
|
+
await tr.commitAsync();
|
|
1227
|
+
```
|
|
1228
|
+
|
|
1229
|
+
The result object contains `recordCount`, `updateCounts` (one entry per
|
|
1230
|
+
record), `errors` (`{ recordNumber, error }` with full gdscode details),
|
|
1231
|
+
`errorRecordNumbers` and `success`. At the database level a failed batch
|
|
1232
|
+
rejects with the first record error, carrying the full completion state as
|
|
1233
|
+
`err.batchCompletion`.
|
|
1234
|
+
|
|
1235
|
+
Options (last argument): `chunkSize` (rows per `op_batch_msg` packet,
|
|
1236
|
+
default 500), `multiError` (default `true` — collect all record errors
|
|
1237
|
+
instead of stopping at the first), `bufferSize` (server-side batch buffer
|
|
1238
|
+
in bytes).
|
|
1239
|
+
|
|
1240
|
+
Notes:
|
|
1241
|
+
|
|
1242
|
+
- Requires wire protocol 16+ (Firebird 4.0 or newer server).
|
|
1243
|
+
- Values are encoded from the statement's own parameter metadata, so
|
|
1244
|
+
NUMERIC/DECIMAL scale, `BIGINT`/`INT128` (pass `BigInt`), `BOOLEAN`,
|
|
1245
|
+
`TIMESTAMP`/`DATE`/`TIME`, `FLOAT`/`DOUBLE` and `DECFLOAT` all round-trip
|
|
1246
|
+
exactly. BLOB and ARRAY parameters are not supported in batches yet.
|
|
1247
|
+
- Oversized `CHAR`/`VARCHAR` values fail the batch client-side before
|
|
1248
|
+
anything is sent; server-side record errors (constraint violations,
|
|
1249
|
+
truncation…) are reported per record.
|
|
1250
|
+
|
|
1195
1251
|
### Statement Timeouts (Firebird 4.0+)
|
|
1196
1252
|
Setting a statement timeout allows the client to automatically abort queries that take too long on the server.
|
|
1197
1253
|
```js
|
package/lib/types.d.ts
CHANGED
|
@@ -64,6 +64,32 @@ export type TransactionOptions = {
|
|
|
64
64
|
wait?: boolean;
|
|
65
65
|
waitTimeout?: number;
|
|
66
66
|
};
|
|
67
|
+
/** Result of an executeBatch call (Firebird 4 batch API, protocol 16+). */
|
|
68
|
+
export interface BatchResult {
|
|
69
|
+
/** Total number of records processed by the server. */
|
|
70
|
+
recordCount: number;
|
|
71
|
+
/** Per-record update counts (in record order). */
|
|
72
|
+
updateCounts: number[];
|
|
73
|
+
/** Per-record failures with full status vectors (capped by `detailedErrors`). */
|
|
74
|
+
errors: Array<{
|
|
75
|
+
recordNumber: number;
|
|
76
|
+
error: Error;
|
|
77
|
+
}>;
|
|
78
|
+
/** Record numbers of ALL failed records (detailed + status-less). */
|
|
79
|
+
errorRecordNumbers: number[];
|
|
80
|
+
/** True when every record executed without error. */
|
|
81
|
+
success: boolean;
|
|
82
|
+
}
|
|
83
|
+
export type BatchOptions = {
|
|
84
|
+
/** Continue past per-record errors and report them all (default true). */
|
|
85
|
+
multiError?: boolean;
|
|
86
|
+
/** Server-side batch buffer limit in bytes (BATCH_TAG_BUFFER_BYTES_SIZE). */
|
|
87
|
+
bufferSize?: number;
|
|
88
|
+
/** Max number of detailed per-record status vectors returned (server default 64). */
|
|
89
|
+
detailedErrors?: number;
|
|
90
|
+
/** Rows per op_batch_msg packet (default 500). */
|
|
91
|
+
chunkSize?: number;
|
|
92
|
+
};
|
|
67
93
|
export type QueryOptions = {
|
|
68
94
|
timeout?: number;
|
|
69
95
|
scrollable?: boolean;
|
|
@@ -83,6 +109,8 @@ export interface Database {
|
|
|
83
109
|
newStatement(query: string, callback: (err: Error | null, statement: Statement) => void): Database;
|
|
84
110
|
query(query: string, params: any[], callback: QueryCallback, options?: QueryOptions): Database;
|
|
85
111
|
execute(query: string, params: any[], callback: QueryCallback, options?: QueryOptions): Database;
|
|
112
|
+
/** Bulk-execute in its own transaction, all-or-nothing (Firebird 4.0+). */
|
|
113
|
+
executeBatch(query: string, rows: any[][], callback?: (err: any, result: BatchResult) => void, options?: BatchOptions): Database;
|
|
86
114
|
sequentially(query: string, params: any[], rowCallback: SequentialCallback, callback: SimpleCallback, options?: QueryOptions | boolean): Database;
|
|
87
115
|
drop(callback: SimpleCallback): void;
|
|
88
116
|
escape(value: any): string;
|
|
@@ -93,6 +121,7 @@ export interface Database {
|
|
|
93
121
|
createSchema(schemaName: string, tablespaceName?: string | QueryCallback, callback?: QueryCallback): Database;
|
|
94
122
|
queryAsync<T = any>(query: string, params?: any[], options?: QueryOptions): Promise<T[]>;
|
|
95
123
|
executeAsync<T = any>(query: string, params?: any[], options?: QueryOptions): Promise<T[]>;
|
|
124
|
+
executeBatchAsync(query: string, rows: any[][], options?: BatchOptions): Promise<BatchResult>;
|
|
96
125
|
sequentiallyAsync(query: string, params: any[] | undefined, rowCallback: SequentialCallback, options?: QueryOptions | boolean): Promise<void>;
|
|
97
126
|
sequentiallyAsync(query: string, rowCallback: SequentialCallback, options?: QueryOptions | boolean): Promise<void>;
|
|
98
127
|
transactionAsync(options?: TransactionOptions | Isolation): Promise<Transaction>;
|
|
@@ -116,6 +145,8 @@ export interface Transaction {
|
|
|
116
145
|
newStatement(query: string, callback: (err: Error | null, statement: Statement) => void): void;
|
|
117
146
|
query(query: string, params: any[], callback: QueryCallback, options?: QueryOptions): void;
|
|
118
147
|
execute(query: string, params: any[], callback: QueryCallback, options?: QueryOptions): void;
|
|
148
|
+
/** Bulk-execute within this transaction; per-record failures do not roll back (Firebird 4.0+). */
|
|
149
|
+
executeBatch(query: string, rows: any[][], callback?: (err: any, result: BatchResult) => void, options?: BatchOptions): void;
|
|
119
150
|
sequentially(query: string, params: any[], rowCallback: SequentialCallback, callback: SimpleCallback, options?: QueryOptions | boolean): Database;
|
|
120
151
|
commit(callback?: SimpleCallback): void;
|
|
121
152
|
commitRetaining(callback?: SimpleCallback): void;
|
|
@@ -123,6 +154,7 @@ export interface Transaction {
|
|
|
123
154
|
rollbackRetaining(callback?: SimpleCallback): void;
|
|
124
155
|
queryAsync<T = any>(query: string, params?: any[], options?: QueryOptions): Promise<T[]>;
|
|
125
156
|
executeAsync<T = any>(query: string, params?: any[], options?: QueryOptions): Promise<T[]>;
|
|
157
|
+
executeBatchAsync(query: string, rows: any[][], options?: BatchOptions): Promise<BatchResult>;
|
|
126
158
|
sequentiallyAsync(query: string, params: any[] | undefined, rowCallback: SequentialCallback, options?: QueryOptions | boolean): Promise<void>;
|
|
127
159
|
sequentiallyAsync(query: string, rowCallback: SequentialCallback, options?: QueryOptions | boolean): Promise<void>;
|
|
128
160
|
newStatementAsync(query: string): Promise<Statement>;
|
|
@@ -139,7 +171,10 @@ export interface Statement {
|
|
|
139
171
|
fetch(transaction: Transaction, count: number, callback: QueryCallback): void;
|
|
140
172
|
fetchScroll(transaction: Transaction, direction: 'NEXT' | 'PRIOR' | 'FIRST' | 'LAST' | 'ABSOLUTE' | 'RELATIVE' | number, offset: number, count: number, callback: QueryCallback): void;
|
|
141
173
|
fetchAll(transaction: Transaction, callback: QueryCallback): void;
|
|
174
|
+
/** Execute this prepared statement once per row (Firebird 4.0+ batch API). */
|
|
175
|
+
executeBatch(transaction: Transaction, rows: any[][], callback?: (err: any, result: BatchResult) => void, options?: BatchOptions): void;
|
|
142
176
|
executeAsync(transaction: Transaction, params?: any[], options?: QueryOptions): Promise<any>;
|
|
177
|
+
executeBatchAsync(transaction: Transaction, rows: any[][], options?: BatchOptions): Promise<BatchResult>;
|
|
143
178
|
fetchAsync(transaction: Transaction, count: number | 'all'): Promise<any>;
|
|
144
179
|
fetchScrollAsync(transaction: Transaction, direction: 'NEXT' | 'PRIOR' | 'FIRST' | 'LAST' | 'ABSOLUTE' | 'RELATIVE' | number, offset?: number, count?: number): Promise<any>;
|
|
145
180
|
fetchAllAsync(transaction: Transaction): Promise<any>;
|
package/lib/wire/connection.d.ts
CHANGED
|
@@ -64,6 +64,8 @@ declare class Connection {
|
|
|
64
64
|
* op_cancel packet itself has no response, so nothing is queued here.
|
|
65
65
|
*/
|
|
66
66
|
cancelOperation(kind: any, callback: any): this;
|
|
67
|
+
/** Write a prebuilt packet and queue its response callback. */
|
|
68
|
+
_queueEventBuffer(buffer: any, callback: any): void;
|
|
67
69
|
_queueEvent(callback: any, defer?: boolean): void;
|
|
68
70
|
connect(options: any, callback: any): void;
|
|
69
71
|
attach(options: any, callback?: any, db?: any): void;
|
|
@@ -82,6 +84,19 @@ declare class Connection {
|
|
|
82
84
|
allocateAndPrepareStatement(transaction: any, query: any, plan: any, callback: any): void;
|
|
83
85
|
prepare(transaction: any, query: any, plan: any, callback: any): void;
|
|
84
86
|
prepareStatement(transaction: any, statement: any, query: any, plan: any, callback: any): this;
|
|
87
|
+
/**
|
|
88
|
+
* Execute a statement once per row using the Firebird 4 batch API
|
|
89
|
+
* (protocol 16+): op_batch_create + op_batch_msg(s) + op_batch_exec +
|
|
90
|
+
* op_batch_rls, all pipelined in a single network flush. Every packet
|
|
91
|
+
* gets an in-order response (op_batch_cs for exec), so the regular
|
|
92
|
+
* response queue keeps everything in sync.
|
|
93
|
+
*
|
|
94
|
+
* rows: array of parameter arrays, one per record. BLOB/ARRAY columns
|
|
95
|
+
* are not supported yet. The callback receives a completion object:
|
|
96
|
+
* { recordCount, updateCounts, errors: [{recordNumber, error}],
|
|
97
|
+
* errorRecordNumbers, success }.
|
|
98
|
+
*/
|
|
99
|
+
executeBatch(transaction: any, statement: any, rows: any, callback: any, options: any): this;
|
|
85
100
|
executeStatement(transaction: any, statement: any, params: any, callback: any, custom: any): this;
|
|
86
101
|
sendExecute(op: number, statement: any, transaction: any, callback: any, parameters?: any[]): void;
|
|
87
102
|
fetch(statement: any, transaction: any, count: any, callback: any): void;
|