node-firebird 2.4.2 → 2.6.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 +94 -1
- package/lib/callback.d.ts +13 -0
- package/lib/callback.js +31 -0
- package/lib/index.d.ts +6 -1
- package/lib/index.js +16 -0
- package/lib/pool.d.ts +7 -0
- package/lib/pool.js +25 -0
- package/lib/types.d.ts +49 -0
- package/lib/wire/connection.d.ts +7 -0
- package/lib/wire/connection.js +45 -14
- package/lib/wire/const.d.ts +4 -0
- package/lib/wire/const.js +8 -0
- package/lib/wire/database.d.ts +24 -0
- package/lib/wire/database.js +85 -0
- package/lib/wire/statement.d.ts +7 -0
- package/lib/wire/statement.js +30 -0
- package/lib/wire/transaction.d.ts +8 -5
- package/lib/wire/transaction.js +76 -0
- package/package.json +1 -1
- package/src/callback.ts +36 -0
- package/src/index.ts +28 -1
- package/src/pool.ts +28 -0
- package/src/types.ts +58 -0
- package/src/wire/connection.ts +51 -14
- package/src/wire/const.ts +9 -0
- package/src/wire/database.ts +97 -1
- package/src/wire/statement.ts +39 -0
- package/src/wire/transaction.ts +89 -1
package/lib/wire/statement.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Statement
|
|
5
5
|
*
|
|
6
6
|
***************************************/
|
|
7
|
+
const callback_1 = require("../callback");
|
|
7
8
|
class Statement {
|
|
8
9
|
constructor(connection) {
|
|
9
10
|
this.connection = connection;
|
|
@@ -48,5 +49,34 @@ class Statement {
|
|
|
48
49
|
fetchAll(transaction, callback) {
|
|
49
50
|
this.connection.fetchAll(this, transaction, callback);
|
|
50
51
|
}
|
|
52
|
+
/* Promise / async-await API — wrappers over the callback methods above. */
|
|
53
|
+
executeAsync(transaction, params, options) {
|
|
54
|
+
var self = this;
|
|
55
|
+
return (0, callback_1.fromCallback)(function (cb) { self.execute(transaction, params, cb, options); });
|
|
56
|
+
}
|
|
57
|
+
fetchAsync(transaction, count) {
|
|
58
|
+
var self = this;
|
|
59
|
+
return (0, callback_1.fromCallback)(function (cb) { self.fetch(transaction, count, cb); });
|
|
60
|
+
}
|
|
61
|
+
fetchScrollAsync(transaction, direction, offset, count) {
|
|
62
|
+
var self = this;
|
|
63
|
+
return (0, callback_1.fromCallback)(function (cb) { self.fetchScroll(transaction, direction, offset, count, cb); });
|
|
64
|
+
}
|
|
65
|
+
fetchAllAsync(transaction) {
|
|
66
|
+
var self = this;
|
|
67
|
+
return (0, callback_1.fromCallback)(function (cb) { self.fetchAll(transaction, cb); });
|
|
68
|
+
}
|
|
69
|
+
closeAsync() {
|
|
70
|
+
var self = this;
|
|
71
|
+
return (0, callback_1.fromCallback)(function (cb) { self.close(cb); });
|
|
72
|
+
}
|
|
73
|
+
dropAsync() {
|
|
74
|
+
var self = this;
|
|
75
|
+
return (0, callback_1.fromCallback)(function (cb) { self.drop(cb); });
|
|
76
|
+
}
|
|
77
|
+
releaseAsync() {
|
|
78
|
+
var self = this;
|
|
79
|
+
return (0, callback_1.fromCallback)(function (cb) { self.release(cb); });
|
|
80
|
+
}
|
|
51
81
|
}
|
|
52
82
|
module.exports = Statement;
|
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
/***************************************
|
|
2
|
-
*
|
|
3
|
-
* Transaction
|
|
4
|
-
*
|
|
5
|
-
***************************************/
|
|
6
1
|
declare class Transaction {
|
|
7
2
|
connection: any;
|
|
8
3
|
db: any;
|
|
@@ -17,5 +12,13 @@ declare class Transaction {
|
|
|
17
12
|
rollback(callback?: (err?: any) => void): void;
|
|
18
13
|
commitRetaining(callback?: (err?: any) => void): void;
|
|
19
14
|
rollbackRetaining(callback?: (err?: any) => void): void;
|
|
15
|
+
queryAsync(query: string, params?: any, options?: any): Promise<any[]>;
|
|
16
|
+
executeAsync(query: string, params?: any, options?: any): Promise<any[]>;
|
|
17
|
+
sequentiallyAsync(query: string, params?: any, on?: any, options?: any): Promise<void>;
|
|
18
|
+
newStatementAsync(query: string): Promise<any>;
|
|
19
|
+
commitAsync(): Promise<void>;
|
|
20
|
+
rollbackAsync(): Promise<void>;
|
|
21
|
+
commitRetainingAsync(): Promise<void>;
|
|
22
|
+
rollbackRetainingAsync(): Promise<void>;
|
|
20
23
|
}
|
|
21
24
|
export = Transaction;
|
package/lib/wire/transaction.js
CHANGED
|
@@ -10,6 +10,36 @@ const const_1 = __importDefault(require("./const"));
|
|
|
10
10
|
* Transaction
|
|
11
11
|
*
|
|
12
12
|
***************************************/
|
|
13
|
+
/** The error delivered when options.signal was already aborted on entry. */
|
|
14
|
+
function abortError(signal) {
|
|
15
|
+
if (signal && signal.reason instanceof Error)
|
|
16
|
+
return signal.reason;
|
|
17
|
+
var err = new Error('The operation was aborted');
|
|
18
|
+
err.name = 'AbortError';
|
|
19
|
+
err.code = 'ABORT_ERR';
|
|
20
|
+
return err;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Wire an AbortSignal to a running statement: on abort, send an out-of-band
|
|
24
|
+
* op_cancel so the server fails the executing operation with isc_cancelled
|
|
25
|
+
* (surfaced through the statement's own callback as err.gdscode ===
|
|
26
|
+
* GDSCode.CANCELLED). Returns the wrapped callback that detaches the
|
|
27
|
+
* listener once the operation settles.
|
|
28
|
+
*/
|
|
29
|
+
function hookAbortSignal(connection, signal, callback) {
|
|
30
|
+
var settled = false;
|
|
31
|
+
var onAbort = function () {
|
|
32
|
+
if (!settled)
|
|
33
|
+
connection.cancelOperation(const_1.default.fb_cancel_raise);
|
|
34
|
+
};
|
|
35
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
36
|
+
return function (err, result, meta, isSelect) {
|
|
37
|
+
settled = true;
|
|
38
|
+
signal.removeEventListener('abort', onAbort);
|
|
39
|
+
if (callback)
|
|
40
|
+
callback(err, result, meta, isSelect);
|
|
41
|
+
};
|
|
42
|
+
}
|
|
13
43
|
class Transaction {
|
|
14
44
|
constructor(connection) {
|
|
15
45
|
this.connection = connection;
|
|
@@ -32,6 +62,14 @@ class Transaction {
|
|
|
32
62
|
callback = params;
|
|
33
63
|
params = undefined;
|
|
34
64
|
}
|
|
65
|
+
var signal = options && options.signal;
|
|
66
|
+
if (signal) {
|
|
67
|
+
if (signal.aborted) {
|
|
68
|
+
(0, callback_1.doError)(abortError(signal), callback);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
callback = hookAbortSignal(this.connection, signal, callback);
|
|
72
|
+
}
|
|
35
73
|
var self = this;
|
|
36
74
|
this.newStatement(query, function (err, statement) {
|
|
37
75
|
if (err) {
|
|
@@ -174,5 +212,43 @@ class Transaction {
|
|
|
174
212
|
rollbackRetaining(callback) {
|
|
175
213
|
this.connection.rollbackRetaining(this, callback);
|
|
176
214
|
}
|
|
215
|
+
/* Promise / async-await API — wrappers over the callback methods above. */
|
|
216
|
+
queryAsync(query, params, options) {
|
|
217
|
+
var self = this;
|
|
218
|
+
return (0, callback_1.fromCallback)(function (cb) { self.query(query, params, cb, options); });
|
|
219
|
+
}
|
|
220
|
+
executeAsync(query, params, options) {
|
|
221
|
+
var self = this;
|
|
222
|
+
return (0, callback_1.fromCallback)(function (cb) { self.execute(query, params, cb, options); });
|
|
223
|
+
}
|
|
224
|
+
sequentiallyAsync(query, params, on, options) {
|
|
225
|
+
if (params instanceof Function) {
|
|
226
|
+
options = on;
|
|
227
|
+
on = params;
|
|
228
|
+
params = undefined;
|
|
229
|
+
}
|
|
230
|
+
var self = this;
|
|
231
|
+
return (0, callback_1.fromCallback)(function (cb) { self.sequentially(query, params, on, cb, options); });
|
|
232
|
+
}
|
|
233
|
+
newStatementAsync(query) {
|
|
234
|
+
var self = this;
|
|
235
|
+
return (0, callback_1.fromCallback)(function (cb) { self.newStatement(query, cb); });
|
|
236
|
+
}
|
|
237
|
+
commitAsync() {
|
|
238
|
+
var self = this;
|
|
239
|
+
return (0, callback_1.fromCallback)(function (cb) { self.commit(cb); });
|
|
240
|
+
}
|
|
241
|
+
rollbackAsync() {
|
|
242
|
+
var self = this;
|
|
243
|
+
return (0, callback_1.fromCallback)(function (cb) { self.rollback(cb); });
|
|
244
|
+
}
|
|
245
|
+
commitRetainingAsync() {
|
|
246
|
+
var self = this;
|
|
247
|
+
return (0, callback_1.fromCallback)(function (cb) { self.commitRetaining(cb); });
|
|
248
|
+
}
|
|
249
|
+
rollbackRetainingAsync() {
|
|
250
|
+
var self = this;
|
|
251
|
+
return (0, callback_1.fromCallback)(function (cb) { self.rollbackRetaining(cb); });
|
|
252
|
+
}
|
|
177
253
|
}
|
|
178
254
|
module.exports = Transaction;
|
package/package.json
CHANGED
package/src/callback.ts
CHANGED
|
@@ -20,6 +20,42 @@ export interface FbError extends Error {
|
|
|
20
20
|
export type SimpleCallback = (err?: any) => void;
|
|
21
21
|
export type Callback<T = any> = (err?: any, result?: T) => void;
|
|
22
22
|
|
|
23
|
+
/**
|
|
24
|
+
* Normalize the values the driver passes as the callback error argument.
|
|
25
|
+
* Most code paths already deliver Error instances, but a few older ones
|
|
26
|
+
* pass plain objects (status vectors, `{error, message}` wrappers). A
|
|
27
|
+
* Promise must reject with an Error, so wrap those while preserving all
|
|
28
|
+
* their properties (gdscode, gdsparams, status, sqlcode, ...).
|
|
29
|
+
*/
|
|
30
|
+
export function toError(err: any): Error {
|
|
31
|
+
if (err instanceof Error)
|
|
32
|
+
return err;
|
|
33
|
+
|
|
34
|
+
var error: FbError = new Error(
|
|
35
|
+
err != null && typeof err === 'object' && err.message ? err.message : String(err)
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
if (err != null && typeof err === 'object')
|
|
39
|
+
Object.assign(error, err);
|
|
40
|
+
|
|
41
|
+
return error;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Run a callback-style operation and return a Promise for its result.
|
|
46
|
+
* Usage: fromCallback<Database>(cb => attach(options, cb))
|
|
47
|
+
*/
|
|
48
|
+
export function fromCallback<T = any>(executor: (cb: Callback<T>) => void): Promise<T> {
|
|
49
|
+
return new Promise<T>(function(resolve, reject) {
|
|
50
|
+
executor(function(err?: any, result?: T) {
|
|
51
|
+
if (err)
|
|
52
|
+
reject(toError(err));
|
|
53
|
+
else
|
|
54
|
+
resolve(result as T);
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
23
59
|
export function doError(obj: any, callback?: (...args: any[]) => void): void {
|
|
24
60
|
if (callback)
|
|
25
61
|
callback(obj)
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import Const from './wire/const';
|
|
2
|
-
import { doError, doCallback } from './callback';
|
|
2
|
+
import { doError, doCallback, fromCallback } from './callback';
|
|
3
3
|
import Connection from './wire/connection';
|
|
4
4
|
import Pool from './pool';
|
|
5
5
|
import { escape as escapeValue } from './utils';
|
|
@@ -10,6 +10,8 @@ import type {
|
|
|
10
10
|
ServiceManagerCallback,
|
|
11
11
|
SimpleCallback,
|
|
12
12
|
ConnectionPool,
|
|
13
|
+
Database,
|
|
14
|
+
ServiceManager,
|
|
13
15
|
} from './types';
|
|
14
16
|
|
|
15
17
|
export * from './types';
|
|
@@ -155,3 +157,28 @@ export function attachOrCreate(options: Options, callback: DatabaseCallback): vo
|
|
|
155
157
|
export function pool(max: number, options: Options): ConnectionPool {
|
|
156
158
|
return new Pool(attach, max, Object.assign({}, options, { isPool: true }));
|
|
157
159
|
}
|
|
160
|
+
|
|
161
|
+
/*
|
|
162
|
+
* Promise / async-await API.
|
|
163
|
+
* Wrappers over the callback functions above; the callback API stays
|
|
164
|
+
* untouched. Rejections are always Error instances carrying the usual
|
|
165
|
+
* Firebird properties (gdscode, gdsparams, ...).
|
|
166
|
+
*/
|
|
167
|
+
|
|
168
|
+
export function attachAsync(options: SvcMgrOptions): Promise<ServiceManager>;
|
|
169
|
+
export function attachAsync(options: Options): Promise<Database>;
|
|
170
|
+
export function attachAsync(options: any): Promise<any> {
|
|
171
|
+
return fromCallback(function(cb) { attach(options, cb); });
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export function createAsync(options: Options): Promise<Database> {
|
|
175
|
+
return fromCallback(function(cb) { create(options, cb); });
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export function attachOrCreateAsync(options: Options): Promise<Database> {
|
|
179
|
+
return fromCallback(function(cb) { attachOrCreate(options, cb); });
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
export function dropAsync(options: Options): Promise<void> {
|
|
183
|
+
return fromCallback(function(cb) { drop(options, cb); });
|
|
184
|
+
}
|
package/src/pool.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*
|
|
5
5
|
***************************************/
|
|
6
6
|
|
|
7
|
+
import { fromCallback } from './callback';
|
|
7
8
|
import type { Callback } from './callback';
|
|
8
9
|
|
|
9
10
|
type AttachFn = (options: any, callback: Callback) => void;
|
|
@@ -204,6 +205,33 @@ class Pool {
|
|
|
204
205
|
}
|
|
205
206
|
});
|
|
206
207
|
}
|
|
208
|
+
|
|
209
|
+
/* Promise / async-await API — wrappers over the callback methods above. */
|
|
210
|
+
|
|
211
|
+
getAsync(): Promise<any> {
|
|
212
|
+
var self = this;
|
|
213
|
+
return fromCallback(function(cb) { self.get(cb); });
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
destroyAsync(): Promise<void> {
|
|
217
|
+
var self = this;
|
|
218
|
+
return fromCallback(function(cb) { self.destroy(cb); });
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Run `work` with a connection from the pool, returning it to the pool
|
|
223
|
+
* (detach) when the returned promise settles — success or failure.
|
|
224
|
+
*/
|
|
225
|
+
async withConnection<T>(work: (db: any) => Promise<T> | T): Promise<T> {
|
|
226
|
+
const db = await this.getAsync();
|
|
227
|
+
try {
|
|
228
|
+
return await work(db);
|
|
229
|
+
} finally {
|
|
230
|
+
// A pooled detach only returns the connection to the pool; do not
|
|
231
|
+
// let a detach hiccup mask the outcome of `work`.
|
|
232
|
+
await new Promise<void>(function(resolve) { db.detach(function() { resolve(); }); });
|
|
233
|
+
}
|
|
234
|
+
}
|
|
207
235
|
}
|
|
208
236
|
|
|
209
237
|
export = Pool;
|
package/src/types.ts
CHANGED
|
@@ -78,6 +78,15 @@ export type TransactionOptions = {
|
|
|
78
78
|
export type QueryOptions = {
|
|
79
79
|
timeout?: number;
|
|
80
80
|
scrollable?: boolean;
|
|
81
|
+
/**
|
|
82
|
+
* Abort the query when the signal fires (Firebird 2.5+ / protocol 12+).
|
|
83
|
+
* If the signal is already aborted the query is not sent at all and the
|
|
84
|
+
* callback/promise fails with an `AbortError`. If it fires mid-flight an
|
|
85
|
+
* out-of-band op_cancel is sent and the query fails with
|
|
86
|
+
* `err.gdscode === GDSCode.CANCELLED`. Cancellation is per-attachment:
|
|
87
|
+
* it cancels whatever is currently executing on the connection.
|
|
88
|
+
*/
|
|
89
|
+
signal?: AbortSignal;
|
|
81
90
|
}
|
|
82
91
|
|
|
83
92
|
export interface Database {
|
|
@@ -94,6 +103,29 @@ export interface Database {
|
|
|
94
103
|
alterTablespace(name: string, filePath: string, callback?: QueryCallback): Database;
|
|
95
104
|
dropTablespace(name: string, callback?: QueryCallback): Database;
|
|
96
105
|
createSchema(schemaName: string, tablespaceName?: string | QueryCallback, callback?: QueryCallback): Database;
|
|
106
|
+
|
|
107
|
+
// Promise / async-await API (see README § Promises / async–await).
|
|
108
|
+
// Result metadata is only available through the callback API.
|
|
109
|
+
queryAsync<T = any>(query: string, params?: any[], options?: QueryOptions): Promise<T[]>;
|
|
110
|
+
executeAsync<T = any>(query: string, params?: any[], options?: QueryOptions): Promise<T[]>;
|
|
111
|
+
sequentiallyAsync(query: string, params: any[] | undefined, rowCallback: SequentialCallback, options?: QueryOptions | boolean): Promise<void>;
|
|
112
|
+
sequentiallyAsync(query: string, rowCallback: SequentialCallback, options?: QueryOptions | boolean): Promise<void>;
|
|
113
|
+
transactionAsync(options?: TransactionOptions | Isolation): Promise<Transaction>;
|
|
114
|
+
startTransactionAsync(options?: TransactionOptions | Isolation): Promise<Transaction>;
|
|
115
|
+
newStatementAsync(query: string): Promise<Statement>;
|
|
116
|
+
detachAsync(force?: boolean): Promise<void>;
|
|
117
|
+
dropAsync(): Promise<void>;
|
|
118
|
+
attachEventAsync(): Promise<any>;
|
|
119
|
+
/** Starts a transaction, commits when `work` resolves, rolls back when it rejects. */
|
|
120
|
+
withTransaction<T>(work: (transaction: Transaction) => Promise<T> | T, options?: TransactionOptions | Isolation): Promise<T>;
|
|
121
|
+
/**
|
|
122
|
+
* Cancel the operation currently executing on this connection
|
|
123
|
+
* (Firebird 2.5+ / protocol 12+). The cancelled operation fails through
|
|
124
|
+
* its own callback/promise with `err.gdscode === GDSCode.CANCELLED`.
|
|
125
|
+
*/
|
|
126
|
+
cancel(callback?: SimpleCallback): Database;
|
|
127
|
+
cancel(kind: number, callback?: SimpleCallback): Database;
|
|
128
|
+
cancelAsync(kind?: number): Promise<void>;
|
|
97
129
|
}
|
|
98
130
|
|
|
99
131
|
export interface Transaction {
|
|
@@ -105,6 +137,17 @@ export interface Transaction {
|
|
|
105
137
|
commitRetaining(callback?: SimpleCallback): void;
|
|
106
138
|
rollback(callback?: SimpleCallback): void;
|
|
107
139
|
rollbackRetaining(callback?: SimpleCallback): void;
|
|
140
|
+
|
|
141
|
+
// Promise / async-await API
|
|
142
|
+
queryAsync<T = any>(query: string, params?: any[], options?: QueryOptions): Promise<T[]>;
|
|
143
|
+
executeAsync<T = any>(query: string, params?: any[], options?: QueryOptions): Promise<T[]>;
|
|
144
|
+
sequentiallyAsync(query: string, params: any[] | undefined, rowCallback: SequentialCallback, options?: QueryOptions | boolean): Promise<void>;
|
|
145
|
+
sequentiallyAsync(query: string, rowCallback: SequentialCallback, options?: QueryOptions | boolean): Promise<void>;
|
|
146
|
+
newStatementAsync(query: string): Promise<Statement>;
|
|
147
|
+
commitAsync(): Promise<void>;
|
|
148
|
+
commitRetainingAsync(): Promise<void>;
|
|
149
|
+
rollbackAsync(): Promise<void>;
|
|
150
|
+
rollbackRetainingAsync(): Promise<void>;
|
|
108
151
|
}
|
|
109
152
|
|
|
110
153
|
export interface Statement {
|
|
@@ -115,6 +158,15 @@ export interface Statement {
|
|
|
115
158
|
fetch(transaction: Transaction, count: number, callback: QueryCallback): void;
|
|
116
159
|
fetchScroll(transaction: Transaction, direction: 'NEXT' | 'PRIOR' | 'FIRST' | 'LAST' | 'ABSOLUTE' | 'RELATIVE' | number, offset: number, count: number, callback: QueryCallback): void;
|
|
117
160
|
fetchAll(transaction: Transaction, callback: QueryCallback): void;
|
|
161
|
+
|
|
162
|
+
// Promise / async-await API
|
|
163
|
+
executeAsync(transaction: Transaction, params?: any[], options?: QueryOptions): Promise<any>;
|
|
164
|
+
fetchAsync(transaction: Transaction, count: number | 'all'): Promise<any>;
|
|
165
|
+
fetchScrollAsync(transaction: Transaction, direction: 'NEXT' | 'PRIOR' | 'FIRST' | 'LAST' | 'ABSOLUTE' | 'RELATIVE' | number, offset?: number, count?: number): Promise<any>;
|
|
166
|
+
fetchAllAsync(transaction: Transaction): Promise<any>;
|
|
167
|
+
closeAsync(): Promise<void>;
|
|
168
|
+
dropAsync(): Promise<void>;
|
|
169
|
+
releaseAsync(): Promise<void>;
|
|
118
170
|
}
|
|
119
171
|
|
|
120
172
|
export type SupportedCharacterSet = |
|
|
@@ -240,6 +292,12 @@ export interface SvcMgrOptions extends Options {
|
|
|
240
292
|
export interface ConnectionPool {
|
|
241
293
|
get(callback: DatabaseCallback): void;
|
|
242
294
|
destroy(callback?: SimpleCallback): void;
|
|
295
|
+
|
|
296
|
+
// Promise / async-await API
|
|
297
|
+
getAsync(): Promise<Database>;
|
|
298
|
+
destroyAsync(): Promise<void>;
|
|
299
|
+
/** Acquire a connection, run `work`, always return the connection to the pool. */
|
|
300
|
+
withConnection<T>(work: (db: Database) => Promise<T> | T): Promise<T>;
|
|
243
301
|
}
|
|
244
302
|
|
|
245
303
|
export interface ReadableOptions {
|
package/src/wire/connection.ts
CHANGED
|
@@ -369,6 +369,38 @@ class Connection {
|
|
|
369
369
|
}
|
|
370
370
|
|
|
371
371
|
|
|
372
|
+
/**
|
|
373
|
+
* Send an out-of-band op_cancel packet (protocol 12+ / Firebird 2.5+).
|
|
374
|
+
* The server reads it asynchronously while an operation is executing and
|
|
375
|
+
* makes that operation fail with isc_cancelled (GDSCode.CANCELLED); the
|
|
376
|
+
* op_cancel packet itself has no response, so nothing is queued here.
|
|
377
|
+
*/
|
|
378
|
+
cancelOperation(kind, callback) {
|
|
379
|
+
if (typeof kind === 'function') {
|
|
380
|
+
callback = kind;
|
|
381
|
+
kind = undefined;
|
|
382
|
+
}
|
|
383
|
+
kind = kind || Const.fb_cancel_raise;
|
|
384
|
+
|
|
385
|
+
if (this._isClosed)
|
|
386
|
+
return this.throwClosed(callback);
|
|
387
|
+
|
|
388
|
+
if (!this.accept || this.accept.protocolVersion < Const.PROTOCOL_VERSION12) {
|
|
389
|
+
doError(new Error('Query cancellation requires protocol 12+ (Firebird 2.5 or newer)'), callback);
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
var msg = this._msg;
|
|
394
|
+
msg.pos = 0;
|
|
395
|
+
msg.addInt(Const.op_cancel);
|
|
396
|
+
msg.addInt(kind);
|
|
397
|
+
this._socket.write(msg.getData());
|
|
398
|
+
|
|
399
|
+
if (callback)
|
|
400
|
+
callback();
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
|
|
372
404
|
_queueEvent(callback, defer = false) {
|
|
373
405
|
var self = this;
|
|
374
406
|
|
|
@@ -2185,12 +2217,13 @@ function decodeResponse(data: any, callback: any, cnx: any, lowercase_keys: any,
|
|
|
2185
2217
|
pluginName: accept.pluginName
|
|
2186
2218
|
};
|
|
2187
2219
|
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2220
|
+
if (process.env.FIREBIRD_DEBUG) {
|
|
2221
|
+
console.log('--- DEBUG SRP Handshake ---');
|
|
2222
|
+
console.log('salt:', cnx.serverKeys.salt);
|
|
2223
|
+
console.log('server public key:', cnx.serverKeys.public.toString(16));
|
|
2224
|
+
console.log('client public key:', cnx.clientKeys.public.toString(16));
|
|
2225
|
+
console.log('hashAlgo:', accept.srpAlgo);
|
|
2226
|
+
}
|
|
2194
2227
|
|
|
2195
2228
|
const _t1 = Date.now();
|
|
2196
2229
|
var proof = srp.clientProof(
|
|
@@ -2203,8 +2236,11 @@ function decodeResponse(data: any, callback: any, cnx: any, lowercase_keys: any,
|
|
|
2203
2236
|
accept.srpAlgo
|
|
2204
2237
|
);
|
|
2205
2238
|
|
|
2206
|
-
|
|
2207
|
-
|
|
2239
|
+
if (process.env.FIREBIRD_DEBUG) {
|
|
2240
|
+
// Never log the private key or the session key: the
|
|
2241
|
+
// session key is the wire-encryption key material.
|
|
2242
|
+
console.log('client proof M1:', proof.authData.toString(16));
|
|
2243
|
+
}
|
|
2208
2244
|
|
|
2209
2245
|
if (process.env.FIREBIRD_DEBUG) {
|
|
2210
2246
|
console.log('[fb-debug] srp.clientProof(%s): %dms', accept.srpAlgo, Date.now() - _t1);
|
|
@@ -2309,12 +2345,13 @@ function decodeResponse(data: any, callback: any, cnx: any, lowercase_keys: any,
|
|
|
2309
2345
|
};
|
|
2310
2346
|
var srpAlgo = crypto[pluginName];
|
|
2311
2347
|
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2348
|
+
if (process.env.FIREBIRD_DEBUG) {
|
|
2349
|
+
console.log('--- DEBUG SRP Handshake ---');
|
|
2350
|
+
console.log('salt:', cnx.serverKeys.salt);
|
|
2351
|
+
console.log('server public key:', cnx.serverKeys.public.toString(16));
|
|
2352
|
+
console.log('client public key:', cnx.clientKeys.public.toString(16));
|
|
2353
|
+
console.log('hashAlgo:', srpAlgo);
|
|
2354
|
+
}
|
|
2318
2355
|
|
|
2319
2356
|
const _t1 = Date.now();
|
|
2320
2357
|
var proof = srp.clientProof(
|
package/src/wire/const.ts
CHANGED
|
@@ -132,6 +132,14 @@ const dsql = {
|
|
|
132
132
|
DSQL_unprepare : 4, // >: 2.5
|
|
133
133
|
};
|
|
134
134
|
|
|
135
|
+
// fb_cancel_operation kinds sent with op_cancel (protocol 12+ / Firebird 2.5+)
|
|
136
|
+
const cancelKind = {
|
|
137
|
+
fb_cancel_disable : 1, // disable execution of fb_cancel_raise requests
|
|
138
|
+
fb_cancel_enable : 2, // re-enable delivery of cancel requests
|
|
139
|
+
fb_cancel_raise : 3, // cancel the operation currently executing on the attachment
|
|
140
|
+
fb_cancel_abort : 4, // forcibly abort the attachment's current activity
|
|
141
|
+
};
|
|
142
|
+
|
|
135
143
|
const fetchOp = {
|
|
136
144
|
fetch_next : 0,
|
|
137
145
|
fetch_prior : 1,
|
|
@@ -859,6 +867,7 @@ const Const = Object.freeze({
|
|
|
859
867
|
...blr,
|
|
860
868
|
...blobType,
|
|
861
869
|
...buffer,
|
|
870
|
+
...cancelKind,
|
|
862
871
|
...cnct,
|
|
863
872
|
...common,
|
|
864
873
|
...connect,
|
package/src/wire/database.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import Events from 'events';
|
|
2
|
-
import { doError } from '../callback';
|
|
2
|
+
import { doError, fromCallback } from '../callback';
|
|
3
3
|
import { escape } from '../utils';
|
|
4
4
|
import Const from './const';
|
|
5
5
|
import EventConnection from './eventConnection';
|
|
@@ -322,6 +322,22 @@ class Database extends Events.EventEmitter {
|
|
|
322
322
|
return this.connection.dropDatabase(callback);
|
|
323
323
|
}
|
|
324
324
|
|
|
325
|
+
/**
|
|
326
|
+
* Cancel the operation currently executing on this connection by sending
|
|
327
|
+
* an out-of-band op_cancel (Firebird 2.5+ / protocol 12+). The cancelled
|
|
328
|
+
* operation fails through its own callback with err.gdscode ===
|
|
329
|
+
* GDSCode.CANCELLED. `kind` defaults to fb_cancel_raise; cancellation is
|
|
330
|
+
* per-attachment, not per-statement.
|
|
331
|
+
*/
|
|
332
|
+
cancel(kind?: number | ((err?: any) => void), callback?: (err?: any) => void): this {
|
|
333
|
+
if (typeof kind === 'function') {
|
|
334
|
+
callback = kind;
|
|
335
|
+
kind = undefined;
|
|
336
|
+
}
|
|
337
|
+
this.connection.cancelOperation(kind, callback);
|
|
338
|
+
return this;
|
|
339
|
+
}
|
|
340
|
+
|
|
325
341
|
attachEvent(callback: (err: any, evt?: any) => void): this {
|
|
326
342
|
var self = this;
|
|
327
343
|
const eventid = self.eventid++;
|
|
@@ -439,6 +455,86 @@ class Database extends Events.EventEmitter {
|
|
|
439
455
|
}
|
|
440
456
|
return this.execute(sql, [], callback);
|
|
441
457
|
}
|
|
458
|
+
|
|
459
|
+
/*
|
|
460
|
+
* Promise / async-await API.
|
|
461
|
+
* Each *Async method wraps its callback counterpart; the callback API
|
|
462
|
+
* stays untouched. Result metadata is only available through the
|
|
463
|
+
* callback API — the promises resolve with the rows alone.
|
|
464
|
+
*/
|
|
465
|
+
|
|
466
|
+
queryAsync(query: string, params?: any, options?: any): Promise<any[]> {
|
|
467
|
+
var self = this;
|
|
468
|
+
return fromCallback(function(cb) { self.query(query, params, cb, options); });
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
executeAsync(query: string, params?: any, options?: any): Promise<any[]> {
|
|
472
|
+
var self = this;
|
|
473
|
+
return fromCallback(function(cb) { self.execute(query, params, cb, options); });
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
sequentiallyAsync(query: string, params?: any, on?: any, options?: any): Promise<void> {
|
|
477
|
+
if (params instanceof Function) {
|
|
478
|
+
options = on;
|
|
479
|
+
on = params;
|
|
480
|
+
params = undefined;
|
|
481
|
+
}
|
|
482
|
+
var self = this;
|
|
483
|
+
return fromCallback(function(cb) { self.sequentially(query, params, on, cb, options); });
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
transactionAsync(options?: any): Promise<any> {
|
|
487
|
+
var self = this;
|
|
488
|
+
return fromCallback(function(cb) { self.startTransaction(options, cb); });
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
startTransactionAsync(options?: any): Promise<any> {
|
|
492
|
+
return this.transactionAsync(options);
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
newStatementAsync(query: string): Promise<any> {
|
|
496
|
+
var self = this;
|
|
497
|
+
return fromCallback(function(cb) { self.newStatement(query, cb); });
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
detachAsync(force?: boolean): Promise<void> {
|
|
501
|
+
var self = this;
|
|
502
|
+
return fromCallback(function(cb) { self.detach(cb, force); });
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
dropAsync(): Promise<void> {
|
|
506
|
+
var self = this;
|
|
507
|
+
return fromCallback(function(cb) { self.drop(cb); });
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
attachEventAsync(): Promise<any> {
|
|
511
|
+
var self = this;
|
|
512
|
+
return fromCallback(function(cb) { self.attachEvent(cb); });
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
cancelAsync(kind?: number): Promise<void> {
|
|
516
|
+
var self = this;
|
|
517
|
+
return fromCallback(function(cb) { self.cancel(kind, cb); });
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
/**
|
|
521
|
+
* Run `work` inside a transaction: commits when the returned promise
|
|
522
|
+
* resolves, rolls back when it rejects (the original error is rethrown,
|
|
523
|
+
* even if the rollback itself fails).
|
|
524
|
+
*/
|
|
525
|
+
async withTransaction<T>(work: (transaction: any) => Promise<T> | T, options?: any): Promise<T> {
|
|
526
|
+
const transaction = await this.transactionAsync(options);
|
|
527
|
+
try {
|
|
528
|
+
const result = await work(transaction);
|
|
529
|
+
await fromCallback(function(cb) { transaction.commit(cb); });
|
|
530
|
+
return result;
|
|
531
|
+
} catch (err) {
|
|
532
|
+
try {
|
|
533
|
+
await fromCallback(function(cb) { transaction.rollback(cb); });
|
|
534
|
+
} catch { /* surface the original error, not the rollback failure */ }
|
|
535
|
+
throw err;
|
|
536
|
+
}
|
|
537
|
+
}
|
|
442
538
|
}
|
|
443
539
|
|
|
444
540
|
export = Database;
|
package/src/wire/statement.ts
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
*
|
|
5
5
|
***************************************/
|
|
6
6
|
|
|
7
|
+
import { fromCallback } from '../callback';
|
|
8
|
+
|
|
7
9
|
class Statement {
|
|
8
10
|
connection: any;
|
|
9
11
|
query: string;
|
|
@@ -66,6 +68,43 @@ class Statement {
|
|
|
66
68
|
fetchAll(transaction: any, callback: (err: any, result?: any) => void): void {
|
|
67
69
|
this.connection.fetchAll(this, transaction, callback);
|
|
68
70
|
}
|
|
71
|
+
|
|
72
|
+
/* Promise / async-await API — wrappers over the callback methods above. */
|
|
73
|
+
|
|
74
|
+
executeAsync(transaction: any, params?: any, options?: any): Promise<any> {
|
|
75
|
+
var self = this;
|
|
76
|
+
return fromCallback(function(cb) { self.execute(transaction, params, cb, options); });
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
fetchAsync(transaction: any, count: number | string): Promise<any> {
|
|
80
|
+
var self = this;
|
|
81
|
+
return fromCallback(function(cb) { self.fetch(transaction, count, cb); });
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
fetchScrollAsync(transaction: any, direction: string | number, offset?: any, count?: any): Promise<any> {
|
|
85
|
+
var self = this;
|
|
86
|
+
return fromCallback(function(cb) { self.fetchScroll(transaction, direction, offset, count, cb); });
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
fetchAllAsync(transaction: any): Promise<any> {
|
|
90
|
+
var self = this;
|
|
91
|
+
return fromCallback(function(cb) { self.fetchAll(transaction, cb); });
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
closeAsync(): Promise<void> {
|
|
95
|
+
var self = this;
|
|
96
|
+
return fromCallback(function(cb) { self.close(cb); });
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
dropAsync(): Promise<void> {
|
|
100
|
+
var self = this;
|
|
101
|
+
return fromCallback(function(cb) { self.drop(cb); });
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
releaseAsync(): Promise<void> {
|
|
105
|
+
var self = this;
|
|
106
|
+
return fromCallback(function(cb) { self.release(cb); });
|
|
107
|
+
}
|
|
69
108
|
}
|
|
70
109
|
|
|
71
110
|
export = Statement;
|