node-firebird 1.0.0 → 1.1.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 +68 -0
- package/lib/index.d.ts +33 -0
- package/lib/index.js +185 -74
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -68,6 +68,7 @@ options.role = null; // default
|
|
|
68
68
|
options.pageSize = 4096; // default when creating database
|
|
69
69
|
options.pageSize = 4096; // default when creating database
|
|
70
70
|
options.retryConnectionInterval = 1000; // reconnect interval in case of connection drop
|
|
71
|
+
options.blobAsText = false; // set to true to get blob as text, only affects blob subtype 1
|
|
71
72
|
```
|
|
72
73
|
|
|
73
74
|
### Classic
|
|
@@ -223,6 +224,73 @@ Firebird.attach(options, function(err, db) {
|
|
|
223
224
|
});
|
|
224
225
|
```
|
|
225
226
|
|
|
227
|
+
### Reading Multiples Blobs (Asynchronous)
|
|
228
|
+
```js
|
|
229
|
+
Firebird.attach(options, (err, db) => {
|
|
230
|
+
if (err)
|
|
231
|
+
throw err;
|
|
232
|
+
|
|
233
|
+
db.transaction(Firebird.ISOLATION_READ_COMMITED, (err, transaction) => {
|
|
234
|
+
if (err) {
|
|
235
|
+
throw err;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
transaction.query('SELECT FIRST 10 * FROM JOB', (err, result) => {
|
|
239
|
+
if (err) {
|
|
240
|
+
transaction.rollback();
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
const arrBlob = [];
|
|
245
|
+
for (const item of result) {
|
|
246
|
+
const fields = Object.keys(item);
|
|
247
|
+
for (const key of fields) {
|
|
248
|
+
if (typeof item[key] === 'function') {
|
|
249
|
+
item[key] = new Promise((resolve, reject) => {
|
|
250
|
+
// the same transaction is used (better performance)
|
|
251
|
+
// this is optional
|
|
252
|
+
item[key](transaction, (error, name, event, row) => {
|
|
253
|
+
if (error) {
|
|
254
|
+
return reject(error);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// reading data
|
|
258
|
+
let value = '';
|
|
259
|
+
event.on('data', (chunk) => {
|
|
260
|
+
value += chunk.toString('binary');
|
|
261
|
+
});
|
|
262
|
+
event.on('end', () => {
|
|
263
|
+
resolve({ value, column: name, row });
|
|
264
|
+
});
|
|
265
|
+
});
|
|
266
|
+
});
|
|
267
|
+
arrBlob.push(item[key]);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
Promise.all(arrBlob).then((blobs) => {
|
|
273
|
+
for (const blob of blobs) {
|
|
274
|
+
result[blob.row][blob.column] = blob.value;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
transaction.commit((err) => {
|
|
278
|
+
if (err) {
|
|
279
|
+
transaction.rollback();
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
db.detach();
|
|
284
|
+
console.log(result);
|
|
285
|
+
});
|
|
286
|
+
}).catch((err) => {
|
|
287
|
+
transaction.rollback();
|
|
288
|
+
});
|
|
289
|
+
});
|
|
290
|
+
});
|
|
291
|
+
});
|
|
292
|
+
```
|
|
293
|
+
|
|
226
294
|
### Streaming a big data
|
|
227
295
|
|
|
228
296
|
```js
|
package/lib/index.d.ts
CHANGED
|
@@ -51,6 +51,37 @@ declare module 'node-firebird' {
|
|
|
51
51
|
rollbackRetaining(callback?: SimpleCallback): void;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
+
export type SupportedCharacterSet = |
|
|
55
|
+
'NONE' |
|
|
56
|
+
'CP943C' |
|
|
57
|
+
'DOS737' |
|
|
58
|
+
'DOS775' |
|
|
59
|
+
'DOS858' |
|
|
60
|
+
'DOS862' |
|
|
61
|
+
'DOS864' |
|
|
62
|
+
'DOS866' |
|
|
63
|
+
'DOS869' |
|
|
64
|
+
'GB18030' |
|
|
65
|
+
'GBK' |
|
|
66
|
+
'ISO8859_2' |
|
|
67
|
+
'ISO8859_3' |
|
|
68
|
+
'ISO8859_4' |
|
|
69
|
+
'ISO8859_5' |
|
|
70
|
+
'ISO8859_6' |
|
|
71
|
+
'ISO8859_7' |
|
|
72
|
+
'ISO8859_8' |
|
|
73
|
+
'ISO8859_9' |
|
|
74
|
+
'ISO8859_13' |
|
|
75
|
+
'KOI8R' |
|
|
76
|
+
'KOI8U' |
|
|
77
|
+
'TIS620' |
|
|
78
|
+
'UTF8' |
|
|
79
|
+
'WIN1255' |
|
|
80
|
+
'WIN1256' |
|
|
81
|
+
'WIN1257' |
|
|
82
|
+
'WIN1258' |
|
|
83
|
+
'WIN_1258';
|
|
84
|
+
|
|
54
85
|
export interface Options {
|
|
55
86
|
host?: string;
|
|
56
87
|
port?: number;
|
|
@@ -61,6 +92,8 @@ declare module 'node-firebird' {
|
|
|
61
92
|
role?: string;
|
|
62
93
|
pageSize?: number;
|
|
63
94
|
retryConnectionInterval?: number;
|
|
95
|
+
encoding?: SupportedCharacterSet;
|
|
96
|
+
blobAsText?: boolean; // only affects for blob subtype 1
|
|
64
97
|
}
|
|
65
98
|
|
|
66
99
|
export interface SvcMgrOptions extends Options {
|
package/lib/index.js
CHANGED
|
@@ -3200,6 +3200,8 @@ function decodeResponse(data, callback, cnx, lowercase_keys, cb) {
|
|
|
3200
3200
|
}
|
|
3201
3201
|
}
|
|
3202
3202
|
|
|
3203
|
+
const arrBlob = [];
|
|
3204
|
+
|
|
3203
3205
|
while (data.fcount && (data.fstatus !== 100)) {
|
|
3204
3206
|
var lowerV13 = statement.connection.accept.protocolVersion < PROTOCOL_VERSION13;
|
|
3205
3207
|
|
|
@@ -3209,10 +3211,16 @@ function decodeResponse(data, callback, cnx, lowercase_keys, cb) {
|
|
|
3209
3211
|
|
|
3210
3212
|
try {
|
|
3211
3213
|
_xdrpos = data.pos;
|
|
3212
|
-
|
|
3214
|
+
const key = custom.asObject ? data.fcols[data.fcolumn] : data.fcolumn;
|
|
3215
|
+
const row = data.frows.length;
|
|
3213
3216
|
let value = item.decode(data, lowerV13);
|
|
3214
|
-
if (item.type === SQL_BLOB) {
|
|
3215
|
-
|
|
3217
|
+
if (item.type === SQL_BLOB && value !== null) {
|
|
3218
|
+
if (item.subType === isc_blob_text && cnx.options.blobAsText) {
|
|
3219
|
+
value = fetch_blob_async_transaction(statement, value, key, row);
|
|
3220
|
+
arrBlob.push(value);
|
|
3221
|
+
} else {
|
|
3222
|
+
value = fetch_blob_async(statement, value, key, row);
|
|
3223
|
+
}
|
|
3216
3224
|
}
|
|
3217
3225
|
data.frow[key] = value;
|
|
3218
3226
|
} catch (e) {
|
|
@@ -3245,8 +3253,13 @@ function decodeResponse(data, callback, cnx, lowercase_keys, cb) {
|
|
|
3245
3253
|
_xdrpos = data.pos;
|
|
3246
3254
|
var key = custom.asObject ? data.fcols[data.fcolumn] : data.fcolumn;
|
|
3247
3255
|
var value = item.decode(data, lowerV13);
|
|
3248
|
-
if (item.type === SQL_BLOB) {
|
|
3249
|
-
|
|
3256
|
+
if (item.type === SQL_BLOB && value !== null) {
|
|
3257
|
+
if (item.subType === isc_blob_text && cnx.options.blobAsText) {
|
|
3258
|
+
value = fetch_blob_async_transaction(statement, value, key, data);
|
|
3259
|
+
arrBlob.push(value);
|
|
3260
|
+
} else {
|
|
3261
|
+
value = fetch_blob_async(statement, value, key);
|
|
3262
|
+
}
|
|
3250
3263
|
}
|
|
3251
3264
|
data.frow[key] = value;
|
|
3252
3265
|
} catch (e) {
|
|
@@ -3259,6 +3272,9 @@ function decodeResponse(data, callback, cnx, lowercase_keys, cb) {
|
|
|
3259
3272
|
}
|
|
3260
3273
|
|
|
3261
3274
|
data.fcolumn = 0;
|
|
3275
|
+
// ToDo: emit "row" with blob subtype string decoded
|
|
3276
|
+
// use: data.frow['fieldBlob'](transaction?).then(({ value }) => console.log(value))
|
|
3277
|
+
// arg "transaction" is optional
|
|
3262
3278
|
statement.connection.db.emit('row', data.frow, statement.nbrowsfetched, custom.asObject);
|
|
3263
3279
|
data.frows.push(data.frow);
|
|
3264
3280
|
data.frow = custom.asObject ? {} : new Array(output.length);
|
|
@@ -3293,8 +3309,9 @@ function decodeResponse(data, callback, cnx, lowercase_keys, cb) {
|
|
|
3293
3309
|
statement.nbrowsfetched++;
|
|
3294
3310
|
}
|
|
3295
3311
|
|
|
3296
|
-
|
|
3297
|
-
|
|
3312
|
+
// ToDo: emit "result" with blob subtype string decoded
|
|
3313
|
+
statement.connection.db.emit('result', data.frows, arrBlob);
|
|
3314
|
+
return cb(null, {data: data.frows, fetched: Boolean(!isOpFetch || data.fstatus === 100), arrBlob});
|
|
3298
3315
|
case op_accept:
|
|
3299
3316
|
case op_cond_accept:
|
|
3300
3317
|
case op_accept_data:
|
|
@@ -3605,7 +3622,7 @@ Connection.prototype.attach = function (options, callback, db) {
|
|
|
3605
3622
|
blr.pos = 0;
|
|
3606
3623
|
|
|
3607
3624
|
blr.addByte(isc_dpb_version1);
|
|
3608
|
-
blr.addString(isc_dpb_lc_ctype, 'UTF8', DEFAULT_ENCODING);
|
|
3625
|
+
blr.addString(isc_dpb_lc_ctype, options.encoding || 'UTF8', DEFAULT_ENCODING);
|
|
3609
3626
|
blr.addString(isc_dpb_user_name, user, DEFAULT_ENCODING);
|
|
3610
3627
|
if (options.password && !this.accept.authData) {
|
|
3611
3628
|
if (this.accept.protocolVersion < PROTOCOL_VERSION13) {
|
|
@@ -4413,63 +4430,129 @@ Connection.prototype.sendExecute = function (op, statement, transaction, callbac
|
|
|
4413
4430
|
this._queueEvent(callback);
|
|
4414
4431
|
}
|
|
4415
4432
|
|
|
4416
|
-
function
|
|
4417
|
-
|
|
4418
|
-
|
|
4419
|
-
|
|
4433
|
+
function fetch_blob_async_transaction(statement, id, name, row) {
|
|
4434
|
+
const infoValue = {
|
|
4435
|
+
row,
|
|
4436
|
+
column: name,
|
|
4437
|
+
value: ''
|
|
4438
|
+
};
|
|
4420
4439
|
|
|
4421
|
-
return
|
|
4422
|
-
|
|
4423
|
-
statement.connection.startTransaction(ISOLATION_READ_UNCOMMITTED, function(err, transaction) {
|
|
4440
|
+
return (transactionArg) => {
|
|
4441
|
+
const singleTransaction = transactionArg === undefined;
|
|
4424
4442
|
|
|
4425
|
-
|
|
4426
|
-
|
|
4427
|
-
|
|
4428
|
-
|
|
4443
|
+
let promiseTransaction;
|
|
4444
|
+
if (singleTransaction) {
|
|
4445
|
+
promiseTransaction = new Promise((resolve, reject) => {
|
|
4446
|
+
statement.connection.startTransaction(ISOLATION_READ_UNCOMMITTED, (err, transaction) => {
|
|
4447
|
+
if (err) {
|
|
4448
|
+
return reject(err);
|
|
4449
|
+
}
|
|
4450
|
+
resolve(transaction);
|
|
4451
|
+
});
|
|
4452
|
+
});
|
|
4453
|
+
} else {
|
|
4454
|
+
promiseTransaction = Promise.resolve(transactionArg);
|
|
4455
|
+
}
|
|
4429
4456
|
|
|
4430
|
-
|
|
4431
|
-
|
|
4457
|
+
return promiseTransaction.then((transaction) => {
|
|
4458
|
+
return new Promise((resolve, reject) => {
|
|
4459
|
+
statement.connection._pending.push('openBlob');
|
|
4460
|
+
statement.connection.openBlob(id, transaction, (err, blob) => {
|
|
4461
|
+
|
|
4462
|
+
if (err) {
|
|
4463
|
+
reject(err);
|
|
4464
|
+
return;
|
|
4465
|
+
}
|
|
4466
|
+
|
|
4467
|
+
const read = () => {
|
|
4468
|
+
statement.connection.getSegment(blob, (err, ret) => {
|
|
4469
|
+
|
|
4470
|
+
if (err) {
|
|
4471
|
+
if (singleTransaction) {
|
|
4472
|
+
transaction.rollback(() => reject(err));
|
|
4473
|
+
} else {
|
|
4474
|
+
reject(err);
|
|
4475
|
+
}
|
|
4476
|
+
return;
|
|
4477
|
+
}
|
|
4478
|
+
|
|
4479
|
+
if (ret.buffer) {
|
|
4480
|
+
const blr = new BlrReader(ret.buffer);
|
|
4481
|
+
const data = blr.readSegment();
|
|
4482
|
+
infoValue.value += data.toString(DEFAULT_ENCODING);
|
|
4483
|
+
}
|
|
4484
|
+
|
|
4485
|
+
if (ret.handle !== 2) {
|
|
4486
|
+
read();
|
|
4487
|
+
return;
|
|
4488
|
+
}
|
|
4489
|
+
|
|
4490
|
+
statement.connection.closeBlob(blob);
|
|
4491
|
+
if (singleTransaction) {
|
|
4492
|
+
transaction.commit((err) => {
|
|
4493
|
+
if (err) {
|
|
4494
|
+
reject(err);
|
|
4495
|
+
} else {
|
|
4496
|
+
resolve(infoValue);
|
|
4497
|
+
}
|
|
4498
|
+
});
|
|
4499
|
+
} else {
|
|
4500
|
+
resolve(infoValue);
|
|
4501
|
+
}
|
|
4502
|
+
});
|
|
4503
|
+
};
|
|
4504
|
+
|
|
4505
|
+
read();
|
|
4506
|
+
});
|
|
4507
|
+
});
|
|
4508
|
+
});
|
|
4509
|
+
};
|
|
4510
|
+
}
|
|
4432
4511
|
|
|
4433
|
-
|
|
4512
|
+
function fetch_blob_async(statement, id, name, row) {
|
|
4513
|
+
const cbTransaction = (transaction, close, callback) => {
|
|
4514
|
+
statement.connection._pending.push('openBlob');
|
|
4515
|
+
statement.connection.openBlob(id, transaction, (err, blob) => {
|
|
4516
|
+
let e = new Events.EventEmitter();
|
|
4434
4517
|
|
|
4435
|
-
|
|
4436
|
-
|
|
4437
|
-
|
|
4438
|
-
|
|
4439
|
-
|
|
4440
|
-
|
|
4441
|
-
|
|
4442
|
-
|
|
4518
|
+
e.pipe = (stream) => {
|
|
4519
|
+
e.on('data', (chunk) => {
|
|
4520
|
+
stream.write(chunk);
|
|
4521
|
+
});
|
|
4522
|
+
e.on('end', () => {
|
|
4523
|
+
stream.end();
|
|
4524
|
+
});
|
|
4525
|
+
};
|
|
4443
4526
|
|
|
4444
|
-
|
|
4445
|
-
|
|
4446
|
-
|
|
4447
|
-
}
|
|
4527
|
+
if (err) {
|
|
4528
|
+
return callback(err, name, e, row);
|
|
4529
|
+
}
|
|
4448
4530
|
|
|
4449
|
-
|
|
4450
|
-
|
|
4531
|
+
const read = () => {
|
|
4532
|
+
statement.connection.getSegment(blob, (err, ret) => {
|
|
4451
4533
|
|
|
4452
|
-
|
|
4453
|
-
|
|
4454
|
-
|
|
4455
|
-
|
|
4456
|
-
|
|
4457
|
-
|
|
4534
|
+
if (err) {
|
|
4535
|
+
transaction.rollback(() => {
|
|
4536
|
+
e.emit('error', err);
|
|
4537
|
+
});
|
|
4538
|
+
return;
|
|
4539
|
+
}
|
|
4458
4540
|
|
|
4459
|
-
|
|
4460
|
-
|
|
4461
|
-
|
|
4541
|
+
if (ret.buffer) {
|
|
4542
|
+
const blr = new BlrReader(ret.buffer);
|
|
4543
|
+
const data = blr.readSegment();
|
|
4462
4544
|
|
|
4463
|
-
|
|
4464
|
-
|
|
4545
|
+
e.emit('data', data);
|
|
4546
|
+
}
|
|
4465
4547
|
|
|
4466
|
-
|
|
4467
|
-
|
|
4468
|
-
|
|
4469
|
-
|
|
4548
|
+
if (ret.handle !== 2) {
|
|
4549
|
+
read();
|
|
4550
|
+
return;
|
|
4551
|
+
}
|
|
4470
4552
|
|
|
4471
|
-
|
|
4472
|
-
|
|
4553
|
+
statement.connection.closeBlob(blob);
|
|
4554
|
+
if (close) {
|
|
4555
|
+
transaction.commit((err) => {
|
|
4473
4556
|
if (err) {
|
|
4474
4557
|
e.emit('error', err);
|
|
4475
4558
|
} else {
|
|
@@ -4477,15 +4560,33 @@ function fetch_blob_async(statement, id, name) {
|
|
|
4477
4560
|
}
|
|
4478
4561
|
e = null;
|
|
4479
4562
|
});
|
|
4563
|
+
} else {
|
|
4564
|
+
e.emit('end');
|
|
4565
|
+
e = null;
|
|
4566
|
+
}
|
|
4567
|
+
});
|
|
4568
|
+
};
|
|
4480
4569
|
|
|
4481
|
-
|
|
4482
|
-
|
|
4483
|
-
|
|
4484
|
-
|
|
4485
|
-
read();
|
|
4570
|
+
callback(err, name, e, row);
|
|
4571
|
+
read();
|
|
4572
|
+
});
|
|
4573
|
+
};
|
|
4486
4574
|
|
|
4575
|
+
return (transaction, callback) => {
|
|
4576
|
+
// callback(error, nameField, eventEmitter, row)
|
|
4577
|
+
const singleTransaction = callback === undefined;
|
|
4578
|
+
if (singleTransaction) {
|
|
4579
|
+
callback = transaction;
|
|
4580
|
+
statement.connection.startTransaction(ISOLATION_READ_UNCOMMITTED, (err, transaction) => {
|
|
4581
|
+
if (err) {
|
|
4582
|
+
callback(err);
|
|
4583
|
+
return;
|
|
4584
|
+
}
|
|
4585
|
+
cbTransaction(transaction, singleTransaction, callback);
|
|
4487
4586
|
});
|
|
4488
|
-
}
|
|
4587
|
+
} else {
|
|
4588
|
+
cbTransaction(transaction, singleTransaction, callback);
|
|
4589
|
+
}
|
|
4489
4590
|
};
|
|
4490
4591
|
}
|
|
4491
4592
|
|
|
@@ -4514,24 +4615,34 @@ Connection.prototype.fetch = function(statement, transaction, count, callback) {
|
|
|
4514
4615
|
};
|
|
4515
4616
|
|
|
4516
4617
|
Connection.prototype.fetchAll = function (statement, transaction, callback) {
|
|
4517
|
-
|
|
4518
|
-
|
|
4618
|
+
const self = this, data = [];
|
|
4619
|
+
const loop = (err, ret) => {
|
|
4519
4620
|
if (err) {
|
|
4520
4621
|
return callback(err);
|
|
4521
4622
|
} else if (ret && ret.data && ret.data.length) {
|
|
4522
|
-
|
|
4523
|
-
|
|
4524
|
-
|
|
4525
|
-
|
|
4526
|
-
|
|
4527
|
-
|
|
4528
|
-
|
|
4529
|
-
|
|
4530
|
-
|
|
4531
|
-
|
|
4532
|
-
|
|
4533
|
-
|
|
4534
|
-
|
|
4623
|
+
const arrPromise = (ret.arrBlob || []).map(value => value(transaction));
|
|
4624
|
+
|
|
4625
|
+
Promise.all(arrPromise).then((arrBlob) => {
|
|
4626
|
+
for (let i = 0; i < arrBlob.length; i++) {
|
|
4627
|
+
const blob = arrBlob[i];
|
|
4628
|
+
ret.data[blob.row][blob.column] = blob.value;
|
|
4629
|
+
}
|
|
4630
|
+
|
|
4631
|
+
const lastIndex = ret.data.length - 1;
|
|
4632
|
+
for (let i = 0; i < ret.data.length; i++) {
|
|
4633
|
+
const pos = data.push(ret.data[i]);
|
|
4634
|
+
if (statement.custom && statement.custom.asStream && statement.custom.on) {
|
|
4635
|
+
statement.custom.on(ret.data[i], pos - 1);
|
|
4636
|
+
}
|
|
4637
|
+
if (i === lastIndex) {
|
|
4638
|
+
if (ret.fetched) {
|
|
4639
|
+
return callback(undefined, data);
|
|
4640
|
+
} else {
|
|
4641
|
+
self.fetch(statement, transaction, DEFAULT_FETCHSIZE, loop);
|
|
4642
|
+
}
|
|
4643
|
+
}
|
|
4644
|
+
}
|
|
4645
|
+
}).catch(callback);
|
|
4535
4646
|
} else if (ret.fetched) {
|
|
4536
4647
|
callback(undefined, data);
|
|
4537
4648
|
} else {
|