node-firebird-driver 3.2.0 → 3.3.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 +7 -4
- package/dist/lib/impl/attachment.d.ts +4 -4
- package/dist/lib/impl/attachment.js +8 -6
- package/dist/lib/impl/attachment.js.map +1 -1
- package/dist/lib/impl/blob.d.ts +0 -1
- package/dist/lib/impl/blob.js.map +1 -1
- package/dist/lib/impl/client.js +3 -2
- package/dist/lib/impl/client.js.map +1 -1
- package/dist/lib/impl/date-time.js +6 -6
- package/dist/lib/impl/date-time.js.map +1 -1
- package/dist/lib/impl/events.js +2 -1
- package/dist/lib/impl/events.js.map +1 -1
- package/dist/lib/impl/fb-util.d.ts +2 -2
- package/dist/lib/impl/fb-util.js +107 -88
- package/dist/lib/impl/fb-util.js.map +1 -1
- package/dist/lib/impl/resultset.js +11 -5
- package/dist/lib/impl/resultset.js.map +1 -1
- package/dist/lib/impl/statement.js +4 -2
- package/dist/lib/impl/statement.js.map +1 -1
- package/dist/lib/impl/time-zones.js +7 -6
- package/dist/lib/impl/time-zones.js.map +1 -1
- package/dist/lib/impl/transaction.js +2 -1
- package/dist/lib/impl/transaction.js.map +1 -1
- package/dist/lib/index.d.ts +8 -2
- package/dist/lib/index.js +7 -1
- package/dist/lib/index.js.map +1 -1
- package/dist/test/tests.js +177 -70
- package/dist/test/tests.js.map +1 -1
- package/package.json +6 -5
- package/src/lib/impl/attachment.ts +290 -253
- package/src/lib/impl/blob.ts +37 -35
- package/src/lib/impl/client.ts +60 -61
- package/src/lib/impl/date-time.ts +33 -33
- package/src/lib/impl/events.ts +17 -18
- package/src/lib/impl/fb-util.ts +552 -448
- package/src/lib/impl/resultset.ts +94 -86
- package/src/lib/impl/statement.ts +154 -127
- package/src/lib/impl/time-zones.ts +643 -641
- package/src/lib/impl/transaction.ts +37 -38
- package/src/lib/index.ts +325 -285
- package/src/test/tests.ts +996 -860
- package/tsconfig.json +7 -13
package/src/test/tests.ts
CHANGED
|
@@ -1,330 +1,369 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
2
|
+
Blob,
|
|
3
|
+
BlobSeekWhence,
|
|
4
|
+
Client,
|
|
5
|
+
DatabaseReadWriteMode,
|
|
6
|
+
TransactionIsolation,
|
|
7
|
+
ZonedDate,
|
|
8
|
+
ZonedDateEx,
|
|
8
9
|
} from '../lib';
|
|
9
10
|
|
|
10
11
|
import * as fs from 'fs-extra-promise';
|
|
11
12
|
import * as tmp from 'temp-fs';
|
|
12
13
|
|
|
13
|
-
|
|
14
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
14
15
|
require('dotenv').config({ path: '../../.env' });
|
|
15
16
|
|
|
16
|
-
|
|
17
17
|
export function runCommonTests(client: Client) {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
18
|
+
function dateToString(d: Date) {
|
|
19
|
+
return d && `${(d.getFullYear() + '').padStart(4, '0')}-${d.getMonth() + 1}-${d.getDate()}`;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function timeToString(d: Date) {
|
|
23
|
+
return d && `${d.getHours()}:${d.getMinutes()}:${d.getSeconds()}.${d.getMilliseconds()}`;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function timeTzToString(zd: ZonedDateEx) {
|
|
27
|
+
if (!zd) {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const d = new Date(zd.date.getTime() + zd.offset * 60 * 1000);
|
|
32
|
+
|
|
33
|
+
return `time '${d.getUTCHours()}:${d.getUTCMinutes()}:${d.getUTCSeconds()}.${d.getUTCMilliseconds()} ${zd.timeZone}'`;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function dateTimeToString(d: Date) {
|
|
37
|
+
return d && `${dateToString(d)} ${timeToString(d)}`;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function dateTimeTzToString(zd: ZonedDateEx) {
|
|
41
|
+
if (!zd) {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const d = new Date(zd.date.getTime() + zd.offset * 60 * 1000);
|
|
46
|
+
|
|
47
|
+
return (
|
|
48
|
+
`timestamp '${(d.getUTCFullYear() + '').padStart(4, '0')}-${d.getUTCMonth() + 1}-${d.getUTCDate()} ` +
|
|
49
|
+
`${d.getUTCHours()}:${d.getUTCMinutes()}:${d.getUTCSeconds()}.${d.getUTCMilliseconds()} ${zd.timeZone}'`
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
describe('node-firebird-driver', () => {
|
|
54
|
+
const testConfig = {
|
|
55
|
+
username: process.env.ISC_USER,
|
|
56
|
+
password: process.env.ISC_PASSWORD,
|
|
57
|
+
host: process.env.NODE_FB_TEST_HOST,
|
|
58
|
+
port: process.env.NODE_FB_TEST_PORT,
|
|
59
|
+
tmpDir: process.env.NODE_FB_TEST_TMP_DIR,
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
function isLocal(): boolean {
|
|
63
|
+
return testConfig.host == undefined || testConfig.host == 'localhost' || testConfig.host == '127.0.0.1';
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function getTempFile(name: string): string {
|
|
67
|
+
const database = `${testConfig.tmpDir}/${name}`;
|
|
68
|
+
return (
|
|
69
|
+
(testConfig.host ?? '') +
|
|
70
|
+
(testConfig.host && testConfig.port ? `/${testConfig.port}` : '') +
|
|
71
|
+
(testConfig.host ? ':' : '') +
|
|
72
|
+
database
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
jest.setTimeout(10000);
|
|
77
|
+
|
|
78
|
+
beforeAll(() => {
|
|
79
|
+
expect(client.isValid).toBeTruthy();
|
|
80
|
+
|
|
81
|
+
if (isLocal() && !testConfig.tmpDir) {
|
|
82
|
+
testConfig.tmpDir = tmp.mkdirSync().path.toString();
|
|
83
|
+
|
|
84
|
+
// Important for MacOS tests with non-embedded server.
|
|
85
|
+
fs.chmodSync(testConfig.tmpDir, 0o777);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const defaultOptions = {
|
|
89
|
+
password: testConfig.password,
|
|
90
|
+
username: testConfig.username,
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
client.defaultCreateDatabaseOptions = {
|
|
94
|
+
forcedWrite: false,
|
|
95
|
+
...defaultOptions,
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
client.defaultConnectOptions = {
|
|
99
|
+
...defaultOptions,
|
|
100
|
+
};
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
afterAll(async () => {
|
|
104
|
+
await client.dispose();
|
|
105
|
+
|
|
106
|
+
expect(client.isValid).toBeFalsy();
|
|
107
|
+
|
|
108
|
+
if (isLocal()) {
|
|
109
|
+
fs.rmdirSync(testConfig.tmpDir!);
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
describe('Client', () => {
|
|
114
|
+
test('#createDatabase()', async () => {
|
|
115
|
+
const attachment = await client.createDatabase(getTempFile('Client-createDatabase.fdb'));
|
|
116
|
+
await attachment.dropDatabase();
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
test('#connect()', async () => {
|
|
120
|
+
const filename = getTempFile('Client-connect.fdb');
|
|
121
|
+
const attachment1 = await client.createDatabase(filename);
|
|
122
|
+
const attachment2 = await client.connect(filename);
|
|
123
|
+
|
|
124
|
+
expect(attachment1.isValid).toBeTruthy();
|
|
125
|
+
expect(attachment2.isValid).toBeTruthy();
|
|
126
|
+
|
|
127
|
+
await attachment2.disconnect();
|
|
128
|
+
await attachment1.dropDatabase();
|
|
129
|
+
|
|
130
|
+
expect(attachment1.isValid).toBeFalsy();
|
|
131
|
+
expect(attachment2.isValid).toBeFalsy();
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
test('setDatabaseReadWriteMode', async () => {
|
|
135
|
+
const filename = getTempFile('setDatabaseReadWriteMode.fdb');
|
|
136
|
+
const attachment1 = await client.createDatabase(filename);
|
|
137
|
+
await attachment1.disconnect();
|
|
138
|
+
|
|
139
|
+
const attachment2 = await client.connect(filename, {
|
|
140
|
+
setDatabaseReadWriteMode: DatabaseReadWriteMode.READ_ONLY,
|
|
141
|
+
});
|
|
142
|
+
try {
|
|
143
|
+
const transaction = await attachment2.startTransaction();
|
|
144
|
+
await expect(attachment2.execute(transaction, 'create table t1 (id integer)')).rejects.toThrow();
|
|
145
|
+
await transaction.rollback();
|
|
146
|
+
} finally {
|
|
147
|
+
await attachment2.disconnect();
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const attachment3 = await client.connect(filename, {
|
|
151
|
+
setDatabaseReadWriteMode: DatabaseReadWriteMode.READ_WRITE,
|
|
152
|
+
});
|
|
153
|
+
try {
|
|
154
|
+
const transaction = await attachment3.startTransaction();
|
|
155
|
+
await attachment3.execute(transaction, 'create table t1 (id integer)');
|
|
156
|
+
await transaction.commit();
|
|
157
|
+
} finally {
|
|
158
|
+
await attachment3.disconnect();
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const attachment4 = await client.connect(filename);
|
|
162
|
+
await attachment4.dropDatabase();
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
describe('Attachment', () => {
|
|
167
|
+
test('#startTransaction()', async () => {
|
|
168
|
+
const attachment = await client.createDatabase(getTempFile('Attachment-startTransaction.fdb'));
|
|
169
|
+
|
|
170
|
+
const isolationQuery = "select rdb$get_context('SYSTEM', 'ISOLATION_LEVEL') from rdb$database";
|
|
171
|
+
|
|
172
|
+
const transaction1 = await attachment.startTransaction();
|
|
173
|
+
expect(transaction1.isValid).toBeTruthy();
|
|
174
|
+
expect((await attachment.executeSingleton(transaction1, isolationQuery))[0]).toBe('SNAPSHOT');
|
|
175
|
+
await transaction1.commit();
|
|
176
|
+
expect(transaction1.isValid).toBeFalsy();
|
|
177
|
+
|
|
178
|
+
const transaction2 = await attachment.startTransaction({
|
|
179
|
+
isolation: TransactionIsolation.READ_COMMITTED,
|
|
180
|
+
});
|
|
181
|
+
expect(transaction2.isValid).toBeTruthy();
|
|
182
|
+
expect((await attachment.executeSingleton(transaction2, isolationQuery))[0]).toBe('READ COMMITTED');
|
|
183
|
+
await transaction2.commit();
|
|
184
|
+
expect(transaction2.isValid).toBeFalsy();
|
|
185
|
+
|
|
186
|
+
const transaction3 = await attachment.startTransaction({
|
|
187
|
+
isolation: TransactionIsolation.CONSISTENCY,
|
|
188
|
+
});
|
|
189
|
+
expect(transaction3.isValid).toBeTruthy();
|
|
190
|
+
expect((await attachment.executeSingleton(transaction3, isolationQuery))[0]).toBe('CONSISTENCY');
|
|
191
|
+
await transaction3.commit();
|
|
192
|
+
expect(transaction3.isValid).toBeFalsy();
|
|
193
|
+
|
|
194
|
+
await attachment.dropDatabase();
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
test('#prepare()', async () => {
|
|
198
|
+
const attachment = await client.createDatabase(getTempFile('Attachment-prepare.fdb'));
|
|
199
|
+
const transaction = await attachment.startTransaction();
|
|
200
|
+
|
|
201
|
+
const statement = await attachment.prepare(transaction, 'create table t1 (n1 integer)');
|
|
202
|
+
expect(statement.isValid).toBeTruthy();
|
|
203
|
+
await statement.dispose();
|
|
204
|
+
expect(statement.isValid).toBeFalsy();
|
|
205
|
+
|
|
206
|
+
let error: Error | undefined;
|
|
207
|
+
try {
|
|
208
|
+
await attachment.prepare(transaction, 'create select t1 (n1 integer)');
|
|
209
|
+
} catch (e) {
|
|
210
|
+
error = e as Error;
|
|
211
|
+
expect(error.message).toBe(
|
|
212
|
+
'Dynamic SQL Error\n' + '-SQL error code = -104\n' + '-Token unknown - line 1, column 8\n' + '-select',
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
expect(error).toBeTruthy();
|
|
217
|
+
|
|
218
|
+
await transaction.commit();
|
|
219
|
+
await attachment.dropDatabase();
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
//// TODO: #executeTransaction
|
|
223
|
+
|
|
224
|
+
test('#execute()', async () => {
|
|
225
|
+
const attachment = await client.createDatabase(getTempFile('Attachment-execute.fdb'));
|
|
226
|
+
const transaction = await attachment.startTransaction();
|
|
227
|
+
|
|
228
|
+
await attachment.execute(transaction, 'create table t1 (n1 integer)');
|
|
229
|
+
await transaction.commitRetaining();
|
|
230
|
+
|
|
231
|
+
await attachment.execute(transaction, 'insert into t1 (n1) values (1)');
|
|
232
|
+
|
|
233
|
+
await transaction.commit();
|
|
234
|
+
await attachment.dropDatabase();
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
test('#executeQuery()', async () => {
|
|
238
|
+
const attachment = await client.createDatabase(getTempFile('Attachment-executeQuery.fdb'));
|
|
239
|
+
const transaction = await attachment.startTransaction();
|
|
240
|
+
|
|
241
|
+
await attachment.execute(transaction, 'create table t1 (n1 integer)');
|
|
242
|
+
await transaction.commitRetaining();
|
|
243
|
+
|
|
244
|
+
const resultSet = await attachment.executeQuery(transaction, 'select n1 from t1');
|
|
245
|
+
expect(resultSet.isValid).toBeTruthy();
|
|
246
|
+
await resultSet.close();
|
|
247
|
+
expect(resultSet.isValid).toBeFalsy();
|
|
248
|
+
|
|
249
|
+
await transaction.commit();
|
|
250
|
+
await attachment.dropDatabase();
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
test('#executeSingleton()', async () => {
|
|
254
|
+
const attachment = await client.createDatabase(getTempFile('Attachment-executeSingleton.fdb'));
|
|
255
|
+
const transaction = await attachment.startTransaction();
|
|
256
|
+
|
|
257
|
+
await attachment.execute(transaction, 'create table t1 (n1 integer)');
|
|
258
|
+
await transaction.commitRetaining();
|
|
259
|
+
|
|
260
|
+
const result = await attachment.executeSingleton(transaction, 'insert into t1 values (11) returning n1');
|
|
261
|
+
expect(result.length).toBe(1);
|
|
262
|
+
expect(result[0]).toBe(11);
|
|
263
|
+
|
|
264
|
+
await transaction.commit();
|
|
265
|
+
await attachment.dropDatabase();
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
test('#executeSingletonAsObject()', async () => {
|
|
269
|
+
const attachment = await client.createDatabase(getTempFile('Attachment-executeSingletonAsObject.fdb'));
|
|
270
|
+
const transaction = await attachment.startTransaction();
|
|
271
|
+
|
|
272
|
+
await attachment.execute(transaction, 'create table t1 (n1 integer)');
|
|
273
|
+
await transaction.commitRetaining();
|
|
274
|
+
|
|
275
|
+
const output = await attachment.executeSingletonAsObject<{
|
|
276
|
+
N1: number;
|
|
277
|
+
}>(transaction, 'insert into t1 values (11) returning n1');
|
|
278
|
+
expect(output.N1).toBe(11);
|
|
279
|
+
|
|
280
|
+
await transaction.commit();
|
|
281
|
+
await attachment.dropDatabase();
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
test('#executeReturning()', async () => {
|
|
285
|
+
const attachment = await client.createDatabase(getTempFile('Attachment-executeReturning.fdb'));
|
|
286
|
+
const transaction = await attachment.startTransaction();
|
|
287
|
+
|
|
288
|
+
await attachment.execute(transaction, 'create table t1 (n1 integer)');
|
|
289
|
+
await transaction.commitRetaining();
|
|
290
|
+
|
|
291
|
+
const result = await attachment.executeReturning(transaction, 'insert into t1 values (11) returning n1');
|
|
292
|
+
expect(result.length).toBe(1);
|
|
293
|
+
expect(result[0]).toBe(11);
|
|
294
|
+
|
|
295
|
+
await transaction.commit();
|
|
296
|
+
await attachment.dropDatabase();
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
test('#executeReturningAsObject()', async () => {
|
|
300
|
+
const attachment = await client.createDatabase(getTempFile('Attachment-executeReturningAsObject.fdb'));
|
|
301
|
+
const transaction = await attachment.startTransaction();
|
|
302
|
+
|
|
303
|
+
await attachment.execute(transaction, 'create table t1 (n1 integer)');
|
|
304
|
+
await transaction.commitRetaining();
|
|
305
|
+
|
|
306
|
+
const output = await attachment.executeReturningAsObject<{
|
|
307
|
+
N1: number;
|
|
308
|
+
}>(transaction, 'insert into t1 values (11) returning n1');
|
|
309
|
+
expect(output.N1).toBe(11);
|
|
310
|
+
|
|
311
|
+
await transaction.commit();
|
|
312
|
+
await attachment.dropDatabase();
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
test('#queueEvents()', async () => {
|
|
316
|
+
const attachment = await client.createDatabase(getTempFile('Attachment-queueEvents.fdb'));
|
|
317
|
+
|
|
318
|
+
const eventNames: [string, number][] = [
|
|
319
|
+
['EVENT1', 16],
|
|
320
|
+
['EVENT2', 8],
|
|
321
|
+
];
|
|
322
|
+
|
|
323
|
+
const eventsObj = eventNames.map(([name, expected]) => {
|
|
324
|
+
let resolver: () => void = undefined!;
|
|
325
|
+
|
|
326
|
+
const obj = {
|
|
327
|
+
name,
|
|
328
|
+
expected,
|
|
329
|
+
count: 0,
|
|
330
|
+
promise: new Promise<void>((resolve) => (resolver = resolve)),
|
|
331
|
+
};
|
|
332
|
+
|
|
333
|
+
return { ...obj, resolver };
|
|
334
|
+
});
|
|
335
|
+
const eventsMap = new Map(eventsObj.map((ev) => [ev.name, ev]));
|
|
336
|
+
|
|
337
|
+
const eventHandler = async (counters: [string, number][]) => {
|
|
338
|
+
counters.forEach(([name, count]) => {
|
|
339
|
+
const obj = eventsMap.get(name)!;
|
|
340
|
+
const newCount = obj.count + count;
|
|
341
|
+
obj.count = newCount;
|
|
342
|
+
|
|
343
|
+
if (newCount >= obj.expected) {
|
|
344
|
+
obj.resolver();
|
|
345
|
+
}
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
if (Array.from(eventsMap.values()).every((obj) => obj.count >= obj.expected)) {
|
|
349
|
+
if (events) {
|
|
350
|
+
await events.cancel();
|
|
351
|
+
expect(events.isValid).toBeFalsy();
|
|
352
|
+
events = null!;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
};
|
|
356
|
+
|
|
357
|
+
let events = await attachment.queueEvents(Array.from(eventsMap.keys()), eventHandler);
|
|
358
|
+
|
|
359
|
+
const transaction = await attachment.startTransaction();
|
|
360
|
+
try {
|
|
361
|
+
// Iterate more times than the neccessary so that
|
|
362
|
+
// eventHandler may have a chance to cancel the events.
|
|
363
|
+
for (let i = 0; i < 20; ++i) {
|
|
364
|
+
await attachment.execute(
|
|
365
|
+
transaction,
|
|
366
|
+
`
|
|
328
367
|
execute block as
|
|
329
368
|
begin
|
|
330
369
|
post_event 'EVENT1';
|
|
@@ -332,379 +371,463 @@ export function runCommonTests(client: Client) {
|
|
|
332
371
|
post_event 'EVENT2';
|
|
333
372
|
post_event 'EVENT3';
|
|
334
373
|
end
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
`select sum(n1) || ', ' || count(n1) || ', ' || count(*) ret from t1`);
|
|
448
|
-
const ret = await rs.fetchAsObject<{ RET: string }>();
|
|
449
|
-
await rs.close();
|
|
450
|
-
|
|
451
|
-
expect(ret[0].RET).toStrictEqual('111, 3, 4');
|
|
374
|
+
`,
|
|
375
|
+
);
|
|
376
|
+
|
|
377
|
+
// Commit retaining to test internal event rescheduling
|
|
378
|
+
// after each handler dispatch.
|
|
379
|
+
await transaction.commitRetaining();
|
|
380
|
+
expect(transaction.isValid).toBeTruthy();
|
|
381
|
+
}
|
|
382
|
+
} finally {
|
|
383
|
+
await transaction.commit();
|
|
384
|
+
expect(transaction.isValid).toBeFalsy();
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
await Promise.all(eventsObj.map((ev) => ev.promise));
|
|
388
|
+
|
|
389
|
+
if (events) {
|
|
390
|
+
await events.cancel();
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
eventsObj.forEach((ev) => expect(ev.count).toBeGreaterThanOrEqual(ev.expected));
|
|
394
|
+
|
|
395
|
+
await attachment.dropDatabase();
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
test('#cancelOperation()', async () => {
|
|
399
|
+
const attachment = await client.createDatabase(getTempFile('Attachment-cancelOperation.fdb'));
|
|
400
|
+
const transaction1 = await attachment.startTransaction();
|
|
401
|
+
|
|
402
|
+
await attachment.execute(transaction1, 'create table t1(n1 integer)');
|
|
403
|
+
await transaction1.commitRetaining();
|
|
404
|
+
|
|
405
|
+
await attachment.execute(transaction1, 'insert into t1 values (1)');
|
|
406
|
+
await transaction1.commitRetaining();
|
|
407
|
+
|
|
408
|
+
await attachment.execute(transaction1, 'update t1 set n1 = n1 + 1');
|
|
409
|
+
|
|
410
|
+
await attachment.enableCancellation(true);
|
|
411
|
+
|
|
412
|
+
const transaction2 = await attachment.startTransaction();
|
|
413
|
+
|
|
414
|
+
const promise = attachment
|
|
415
|
+
.execute(transaction2, 'update t1 set n1 = n1 - 1')
|
|
416
|
+
.catch((e) => `Error: ${e.message}`);
|
|
417
|
+
|
|
418
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
419
|
+
|
|
420
|
+
await attachment.cancelOperation();
|
|
421
|
+
|
|
422
|
+
await expect(promise).resolves.toEqual('Error: operation was cancelled');
|
|
423
|
+
|
|
424
|
+
await transaction2.commit();
|
|
425
|
+
await transaction1.commit();
|
|
426
|
+
await attachment.dropDatabase();
|
|
427
|
+
});
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
describe('Transaction', () => {
|
|
431
|
+
test('#commit()', async () => {
|
|
432
|
+
const attachment = await client.createDatabase(getTempFile('Transaction-commit.fdb'));
|
|
433
|
+
const transaction = await attachment.startTransaction();
|
|
434
|
+
await transaction.commit();
|
|
435
|
+
await attachment.dropDatabase();
|
|
436
|
+
});
|
|
437
|
+
|
|
438
|
+
test('#commitRetaining()', async () => {
|
|
439
|
+
const attachment = await client.createDatabase(getTempFile('Transaction-commitRetaining.fdb'));
|
|
440
|
+
const transaction = await attachment.startTransaction();
|
|
441
|
+
await transaction.commitRetaining();
|
|
442
|
+
await transaction.commit();
|
|
443
|
+
await attachment.dropDatabase();
|
|
444
|
+
});
|
|
445
|
+
|
|
446
|
+
test('#rollback()', async () => {
|
|
447
|
+
const attachment = await client.createDatabase(getTempFile('Transaction-rollback.fdb'));
|
|
448
|
+
const transaction = await attachment.startTransaction();
|
|
449
|
+
await transaction.rollback();
|
|
450
|
+
await attachment.dropDatabase();
|
|
451
|
+
});
|
|
452
|
+
|
|
453
|
+
test('#rollbackRetaining()', async () => {
|
|
454
|
+
const attachment = await client.createDatabase(getTempFile('Transaction-rollbackRetaining.fdb'));
|
|
455
|
+
const transaction = await attachment.startTransaction();
|
|
456
|
+
await transaction.rollbackRetaining();
|
|
457
|
+
await transaction.rollback();
|
|
458
|
+
await attachment.dropDatabase();
|
|
459
|
+
});
|
|
460
|
+
|
|
461
|
+
test('transaction left opened', async () => {
|
|
462
|
+
const attachment = await client.createDatabase(getTempFile('Transaction-left-opened.fdb'));
|
|
463
|
+
await attachment.startTransaction();
|
|
464
|
+
await attachment.dropDatabase();
|
|
465
|
+
});
|
|
466
|
+
});
|
|
467
|
+
|
|
468
|
+
describe('Statement', () => {
|
|
469
|
+
test('#execute()', async () => {
|
|
470
|
+
const attachment = await client.createDatabase(getTempFile('Statement-execute.fdb'));
|
|
471
|
+
const transaction = await attachment.startTransaction();
|
|
472
|
+
|
|
473
|
+
const statement1 = await attachment.prepare(transaction, 'create table t1 (n1 integer)');
|
|
474
|
+
await statement1.execute(transaction);
|
|
475
|
+
await statement1.dispose();
|
|
476
|
+
await transaction.commitRetaining();
|
|
477
|
+
|
|
478
|
+
const statement2 = await attachment.prepare(transaction, 'insert into t1 (n1) values (?)');
|
|
479
|
+
await statement2.execute(transaction, [1]);
|
|
480
|
+
await statement2.execute(transaction, [null]);
|
|
481
|
+
await statement2.execute(transaction, [10]);
|
|
482
|
+
await statement2.execute(transaction, [100]);
|
|
483
|
+
expect(statement2.isValid).toBeTruthy();
|
|
484
|
+
await statement2.dispose();
|
|
485
|
+
expect(statement2.isValid).toBeFalsy();
|
|
452
486
|
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
487
|
+
const rs = await attachment.executeQuery(
|
|
488
|
+
transaction,
|
|
489
|
+
`select sum(n1) || ', ' || count(n1) || ', ' || count(*) ret from t1`,
|
|
490
|
+
);
|
|
491
|
+
const ret = await rs.fetchAsObject<{ RET: string }>();
|
|
492
|
+
await rs.close();
|
|
493
|
+
|
|
494
|
+
expect(ret[0].RET).toStrictEqual('111, 3, 4');
|
|
495
|
+
|
|
496
|
+
await transaction.commit();
|
|
497
|
+
await attachment.dropDatabase();
|
|
498
|
+
});
|
|
499
|
+
|
|
500
|
+
test('#executeQuery()', async () => {
|
|
501
|
+
const attachment = await client.createDatabase(getTempFile('Statement-executeQuery.fdb'));
|
|
502
|
+
const transaction = await attachment.startTransaction();
|
|
503
|
+
|
|
504
|
+
const statement1 = await attachment.prepare(transaction, 'create table t1 (n1 integer)');
|
|
505
|
+
await statement1.execute(transaction);
|
|
506
|
+
await statement1.dispose();
|
|
507
|
+
await transaction.commitRetaining();
|
|
508
|
+
|
|
509
|
+
const statement2 = await attachment.prepare(transaction, 'select n1 from t1');
|
|
510
|
+
const resultSet2 = await statement2.executeQuery(transaction);
|
|
511
|
+
await resultSet2.close();
|
|
512
|
+
await statement2.dispose();
|
|
513
|
+
|
|
514
|
+
await transaction.commit();
|
|
515
|
+
await attachment.dropDatabase();
|
|
516
|
+
});
|
|
517
|
+
|
|
518
|
+
test('#executeSingleton()', async () => {
|
|
519
|
+
const attachment = await client.createDatabase(getTempFile('Attachment-executeSingleton.fdb'));
|
|
520
|
+
const transaction = await attachment.startTransaction();
|
|
521
|
+
|
|
522
|
+
await attachment.execute(transaction, 'create table t1 (n1 integer)');
|
|
523
|
+
await transaction.commitRetaining();
|
|
524
|
+
|
|
525
|
+
const statement = await attachment.prepare(transaction, 'insert into t1 values (11) returning n1, n1 * 2');
|
|
526
|
+
|
|
527
|
+
const result = await statement.executeSingleton(transaction);
|
|
528
|
+
expect(result.length).toBe(2);
|
|
529
|
+
expect(result[0]).toBe(11);
|
|
530
|
+
expect(result[1]).toBe(11 * 2);
|
|
531
|
+
|
|
532
|
+
await statement.dispose();
|
|
533
|
+
|
|
534
|
+
await transaction.commit();
|
|
535
|
+
await attachment.dropDatabase();
|
|
536
|
+
});
|
|
537
|
+
|
|
538
|
+
test('#executeReturning()', async () => {
|
|
539
|
+
const attachment = await client.createDatabase(getTempFile('Attachment-executeReturning.fdb'));
|
|
540
|
+
const transaction = await attachment.startTransaction();
|
|
541
|
+
|
|
542
|
+
await attachment.execute(transaction, 'create table t1 (n1 integer)');
|
|
543
|
+
await transaction.commitRetaining();
|
|
544
|
+
|
|
545
|
+
const statement = await attachment.prepare(transaction, 'insert into t1 values (11) returning n1, n1 * 2');
|
|
546
|
+
|
|
547
|
+
const result = await statement.executeReturning(transaction);
|
|
548
|
+
expect(result.length).toBe(2);
|
|
549
|
+
expect(result[0]).toBe(11);
|
|
550
|
+
expect(result[1]).toBe(11 * 2);
|
|
551
|
+
|
|
552
|
+
await statement.dispose();
|
|
553
|
+
|
|
554
|
+
await transaction.commit();
|
|
555
|
+
await attachment.dropDatabase();
|
|
556
|
+
});
|
|
557
|
+
|
|
558
|
+
test('#columnLabels()', async () => {
|
|
559
|
+
const attachment = await client.createDatabase(getTempFile('Statement-columnLabels.fdb'));
|
|
560
|
+
const transaction = await attachment.startTransaction();
|
|
561
|
+
|
|
562
|
+
const statement1 = await attachment.prepare(transaction, 'create table t1 (n1 integer)');
|
|
563
|
+
expect(await statement1.columnLabels).toStrictEqual([]);
|
|
564
|
+
await statement1.execute(transaction);
|
|
565
|
+
await statement1.dispose();
|
|
566
|
+
await transaction.commitRetaining();
|
|
567
|
+
|
|
568
|
+
const statement2 = await attachment.prepare(transaction, 'select n1, n1 x from t1');
|
|
569
|
+
expect(await statement2.columnLabels).toStrictEqual(['N1', 'X']);
|
|
570
|
+
await statement2.dispose();
|
|
571
|
+
|
|
572
|
+
await transaction.commit();
|
|
573
|
+
await attachment.dropDatabase();
|
|
574
|
+
});
|
|
575
|
+
|
|
576
|
+
test('#hasResultSet()', async () => {
|
|
577
|
+
const attachment = await client.createDatabase(getTempFile('Statement-hasResultSet.fdb'));
|
|
578
|
+
const transaction = await attachment.startTransaction();
|
|
579
|
+
|
|
580
|
+
const statement1 = await attachment.prepare(transaction, 'create table t1 (n1 integer)');
|
|
581
|
+
expect(statement1.hasResultSet).toBe(false);
|
|
582
|
+
await statement1.execute(transaction);
|
|
583
|
+
await statement1.dispose();
|
|
584
|
+
|
|
585
|
+
await transaction.commitRetaining();
|
|
586
|
+
|
|
587
|
+
const statement2 = await attachment.prepare(transaction, 'insert into t1 values (1)');
|
|
588
|
+
expect(statement2.hasResultSet).toBe(false);
|
|
589
|
+
await statement2.dispose();
|
|
590
|
+
|
|
591
|
+
const statement3 = await attachment.prepare(transaction, 'insert into t1 values (1) returning *');
|
|
592
|
+
expect(statement3.hasResultSet).toBe(false);
|
|
593
|
+
await statement3.dispose();
|
|
594
|
+
|
|
595
|
+
const statement4 = await attachment.prepare(transaction, 'execute block as begin end');
|
|
596
|
+
expect(statement4.hasResultSet).toBe(false);
|
|
597
|
+
await statement4.dispose();
|
|
598
|
+
|
|
599
|
+
const statement5 = await attachment.prepare(transaction, 'select * from t1');
|
|
600
|
+
expect(statement5.hasResultSet).toBe(true);
|
|
601
|
+
await statement5.dispose();
|
|
602
|
+
|
|
603
|
+
const statement6 = await attachment.prepare(
|
|
604
|
+
transaction,
|
|
605
|
+
'execute block returns (n integer) as begin suspend; end',
|
|
606
|
+
);
|
|
607
|
+
expect(statement6.hasResultSet).toBe(true);
|
|
608
|
+
await statement6.dispose();
|
|
609
|
+
|
|
610
|
+
const statement7 = await attachment.prepare(transaction, 'execute block returns (n integer) as begin end');
|
|
611
|
+
expect(statement7.hasResultSet).toBe(true);
|
|
612
|
+
await statement7.dispose();
|
|
613
|
+
|
|
614
|
+
await transaction.commit();
|
|
615
|
+
await attachment.dropDatabase();
|
|
616
|
+
});
|
|
617
|
+
});
|
|
618
|
+
|
|
619
|
+
describe('ResultSet', () => {
|
|
620
|
+
test('#fetch()', async () => {
|
|
621
|
+
const attachment = await client.createDatabase(getTempFile('ResultSet-fetch.fdb'));
|
|
622
|
+
|
|
623
|
+
let transaction = await attachment.startTransaction();
|
|
624
|
+
|
|
625
|
+
const blobBuffer = Buffer.alloc(11, '12345678á9');
|
|
626
|
+
|
|
627
|
+
const fields = [
|
|
628
|
+
{ name: 'x_short', type: 'numeric(2)', valToStr: (v: any) => v },
|
|
629
|
+
{ name: 'x_int', type: 'integer', valToStr: (v: any) => v },
|
|
630
|
+
{
|
|
631
|
+
name: 'x_int_scale',
|
|
632
|
+
type: 'numeric(5, 2)',
|
|
633
|
+
valToStr: (v: any) => v,
|
|
634
|
+
},
|
|
635
|
+
{ name: 'x_bigint', type: 'bigint', valToStr: (v: any) => v },
|
|
636
|
+
{
|
|
637
|
+
name: 'x_bigint_scale',
|
|
638
|
+
type: 'numeric(15, 2)',
|
|
639
|
+
valToStr: (v: any) => v,
|
|
640
|
+
},
|
|
641
|
+
{ name: 'x_int128', type: 'int128', valToStr: (v: any) => v },
|
|
642
|
+
{
|
|
643
|
+
name: 'x_int128_scale',
|
|
644
|
+
type: 'numeric(20, 2)',
|
|
645
|
+
valToStr: (v: any) => v,
|
|
646
|
+
},
|
|
647
|
+
{ name: 'x_dec16', type: 'decfloat(16)', valToStr: (v: any) => v },
|
|
648
|
+
{ name: 'x_dec34', type: 'decfloat(34)', valToStr: (v: any) => v },
|
|
649
|
+
{
|
|
650
|
+
name: 'x_double',
|
|
651
|
+
type: 'double precision',
|
|
652
|
+
valToStr: (v: any) => v,
|
|
653
|
+
},
|
|
654
|
+
{
|
|
655
|
+
name: 'x_date1',
|
|
656
|
+
type: 'date',
|
|
657
|
+
valToStr: (v: any) => `date '${dateToString(v)}'`,
|
|
658
|
+
},
|
|
659
|
+
{
|
|
660
|
+
name: 'x_date2',
|
|
661
|
+
type: 'date',
|
|
662
|
+
valToStr: (v: any) => `date '${dateToString(v)}'`,
|
|
663
|
+
},
|
|
664
|
+
{
|
|
665
|
+
name: 'x_date3',
|
|
666
|
+
type: 'date',
|
|
667
|
+
valToStr: (v: any) => `date '${dateToString(v)}'`,
|
|
668
|
+
},
|
|
669
|
+
{
|
|
670
|
+
name: 'x_time',
|
|
671
|
+
type: 'time',
|
|
672
|
+
valToStr: (v: any) => `time '${timeToString(v)}'`,
|
|
673
|
+
},
|
|
674
|
+
{
|
|
675
|
+
name: 'x_time_tz1',
|
|
676
|
+
type: 'time with time zone',
|
|
677
|
+
valToStr: (v: ZonedDate) =>
|
|
678
|
+
`${timeTzToString({ date: v.date, timeZone: 'GMT', offset: 0 })} at time zone '${v.timeZone}'`,
|
|
679
|
+
},
|
|
680
|
+
{
|
|
681
|
+
name: 'x_time_tz2',
|
|
682
|
+
type: 'time with time zone',
|
|
683
|
+
valToStr: (v: ZonedDate) =>
|
|
684
|
+
`${timeTzToString({ date: v.date, timeZone: 'GMT', offset: 0 })} at time zone '${v.timeZone}'`,
|
|
685
|
+
},
|
|
686
|
+
{
|
|
687
|
+
name: 'x_timestamp1',
|
|
688
|
+
type: 'timestamp',
|
|
689
|
+
valToStr: (v: any) => `timestamp '${dateTimeToString(v)}'`,
|
|
690
|
+
},
|
|
691
|
+
{
|
|
692
|
+
name: 'x_timestamp2',
|
|
693
|
+
type: 'timestamp',
|
|
694
|
+
valToStr: (v: any) => `timestamp '${dateTimeToString(v)}'`,
|
|
695
|
+
},
|
|
696
|
+
{
|
|
697
|
+
name: 'x_timestamp3',
|
|
698
|
+
type: 'timestamp',
|
|
699
|
+
valToStr: (v: any) => `timestamp '${dateTimeToString(v)}'`,
|
|
700
|
+
},
|
|
701
|
+
{
|
|
702
|
+
name: 'x_timestamp_tz1',
|
|
703
|
+
type: 'timestamp with time zone',
|
|
704
|
+
valToStr: (v: ZonedDate) =>
|
|
705
|
+
`${dateTimeTzToString({ date: v.date, timeZone: 'GMT', offset: 0 })} at time zone '${v.timeZone}'`,
|
|
706
|
+
},
|
|
707
|
+
{
|
|
708
|
+
name: 'x_timestamp_tz2',
|
|
709
|
+
type: 'timestamp with time zone',
|
|
710
|
+
valToStr: (v: ZonedDate) =>
|
|
711
|
+
`${dateTimeTzToString({ date: v.date, timeZone: 'GMT', offset: 0 })} at time zone '${v.timeZone}'`,
|
|
712
|
+
},
|
|
713
|
+
{ name: 'x_boolean', type: 'boolean', valToStr: (v: any) => v },
|
|
714
|
+
{
|
|
715
|
+
name: 'x_varchar',
|
|
716
|
+
type: 'varchar(10) character set utf8',
|
|
717
|
+
valToStr: (v: any) => `'${v}'`,
|
|
718
|
+
},
|
|
719
|
+
{
|
|
720
|
+
name: 'x_char',
|
|
721
|
+
type: 'char(10) character set utf8',
|
|
722
|
+
valToStr: (v: any) => `'${v}'`,
|
|
723
|
+
},
|
|
724
|
+
{
|
|
725
|
+
name: 'x_blob1',
|
|
726
|
+
type: 'blob',
|
|
727
|
+
valToStr: (v: Buffer) => `'${v.toString()}'`,
|
|
728
|
+
},
|
|
729
|
+
{
|
|
730
|
+
name: 'x_blob2',
|
|
731
|
+
type: 'blob',
|
|
732
|
+
valToStr: () => `'${blobBuffer.toString()}'`,
|
|
733
|
+
},
|
|
734
|
+
];
|
|
735
|
+
|
|
736
|
+
const statement1 = await attachment.prepare(
|
|
737
|
+
transaction,
|
|
738
|
+
`create table t1 (${fields.map((f) => `${f.name} ${f.type}`).join(', ')})`,
|
|
739
|
+
);
|
|
740
|
+
await statement1.execute(transaction);
|
|
741
|
+
await statement1.dispose();
|
|
742
|
+
await transaction.commitRetaining();
|
|
743
|
+
|
|
744
|
+
const recordCount = 5;
|
|
745
|
+
let parameters: any[];
|
|
746
|
+
|
|
747
|
+
{
|
|
748
|
+
// scope
|
|
749
|
+
const statement2a = await attachment.prepare(
|
|
750
|
+
transaction,
|
|
751
|
+
`insert into t1 (${fields.map((f) => f.name).join(', ')}) values (${fields.map(() => '?').join(', ')})`,
|
|
752
|
+
);
|
|
753
|
+
|
|
754
|
+
// Test execution in a new transaction, after the one used in prepare was committed.
|
|
755
|
+
await transaction.commit();
|
|
756
|
+
transaction = await attachment.startTransaction();
|
|
757
|
+
|
|
758
|
+
const blob = await attachment.createBlob(transaction);
|
|
759
|
+
expect(blob.isValid).toBeTruthy();
|
|
760
|
+
await blob.write(blobBuffer);
|
|
761
|
+
expect(blob.isValid).toBeTruthy();
|
|
762
|
+
await blob.close();
|
|
763
|
+
expect(blob.isValid).toBeFalsy();
|
|
764
|
+
|
|
765
|
+
parameters = [
|
|
766
|
+
-1,
|
|
767
|
+
-2,
|
|
768
|
+
-3.45,
|
|
769
|
+
-2,
|
|
770
|
+
-3.45,
|
|
771
|
+
'-45699999999999999999999999999999999876',
|
|
772
|
+
'-45699999999999999999999999999999999.87',
|
|
773
|
+
'-456999999999876',
|
|
774
|
+
'-456999999999999999999999999999.87',
|
|
775
|
+
-4.567,
|
|
776
|
+
new Date(2017, 3 - 1, 26),
|
|
777
|
+
new Date(new Date(2000, 3 - 1, 26).setFullYear(50)),
|
|
778
|
+
new Date(9999, 3 - 1, 26),
|
|
779
|
+
new Date(2020, 1 - 1, 1, 11, 56, 32, 123),
|
|
780
|
+
{
|
|
781
|
+
date: new Date(Date.UTC(2020, 1 - 1, 1, 11, 56, 32, 123)),
|
|
782
|
+
timeZone: 'America/New_York',
|
|
783
|
+
} as ZonedDate,
|
|
784
|
+
{
|
|
785
|
+
date: new Date(Date.UTC(2020, 1 - 1, 1, 11, 56, 32, 123)),
|
|
786
|
+
timeZone: 'America/Sao_Paulo',
|
|
787
|
+
} as ZonedDate,
|
|
788
|
+
new Date(2017, 3 - 1, 26, 11, 56, 32, 123),
|
|
789
|
+
new Date(new Date(2000, 3 - 1, 26, 11, 56, 32, 123).setFullYear(50)),
|
|
790
|
+
new Date(9999, 3 - 1, 26, 11, 56, 32, 123),
|
|
791
|
+
{
|
|
792
|
+
date: new Date(Date.UTC(2021, 6 - 1, 7, 11, 56, 32, 123)),
|
|
793
|
+
timeZone: 'America/New_York',
|
|
794
|
+
} as ZonedDate,
|
|
795
|
+
{
|
|
796
|
+
date: new Date(Date.UTC(2021, 6 - 1, 7, 11, 56, 32, 123)),
|
|
797
|
+
timeZone: 'America/Sao_Paulo',
|
|
798
|
+
} as ZonedDate,
|
|
799
|
+
true,
|
|
800
|
+
'123áé4567',
|
|
801
|
+
'123áé4567',
|
|
802
|
+
blobBuffer,
|
|
803
|
+
blob,
|
|
804
|
+
];
|
|
805
|
+
|
|
806
|
+
for (let i = 0; i < recordCount; ++i) {
|
|
807
|
+
await statement2a.execute(transaction, parameters);
|
|
808
|
+
}
|
|
809
|
+
await statement2a.dispose();
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
{
|
|
813
|
+
// scope
|
|
814
|
+
const statement2b = await attachment.prepare(
|
|
815
|
+
transaction,
|
|
816
|
+
`insert into t1 (${fields.map((f) => f.name).join(', ')}) ` +
|
|
817
|
+
`values (${parameters.map((val, index) => fields[index].valToStr(val)).join(', ')})`,
|
|
818
|
+
);
|
|
819
|
+
|
|
820
|
+
for (let i = 0; i < recordCount; ++i) {
|
|
821
|
+
await statement2b.execute(transaction);
|
|
822
|
+
}
|
|
823
|
+
await statement2b.dispose();
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
await transaction.commitRetaining();
|
|
827
|
+
|
|
828
|
+
const statement3 = await attachment.prepare(
|
|
829
|
+
transaction,
|
|
830
|
+
`select x_short,
|
|
708
831
|
x_int,
|
|
709
832
|
x_int_scale,
|
|
710
833
|
x_bigint,
|
|
@@ -736,92 +859,98 @@ export function runCommonTests(client: Client) {
|
|
|
736
859
|
x_char || null,
|
|
737
860
|
x_blob1,
|
|
738
861
|
x_blob2
|
|
739
|
-
from t1
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
862
|
+
from t1`,
|
|
863
|
+
);
|
|
864
|
+
const resultSet3 = await statement3.executeQuery(transaction);
|
|
865
|
+
|
|
866
|
+
const data = await resultSet3.fetch();
|
|
867
|
+
expect(data.length).toBe(recordCount * 2);
|
|
868
|
+
|
|
869
|
+
for (const columns of data) {
|
|
870
|
+
let n = 0;
|
|
871
|
+
expect(columns[n++]).toBe(-1);
|
|
872
|
+
expect(columns[n++]).toBe(-2);
|
|
873
|
+
expect(columns[n++]).toBe(-3.45);
|
|
874
|
+
expect(columns[n++]).toBe(-2);
|
|
875
|
+
expect(columns[n++]).toBe(-3.45);
|
|
876
|
+
expect(columns[n++]).toBe('-45699999999999999999999999999999999876');
|
|
877
|
+
expect(columns[n++]).toBe('-45699999999999999999999999999999999.87');
|
|
878
|
+
expect(columns[n++]).toBe('-456999999999876');
|
|
879
|
+
expect(columns[n++]).toBe('-456999999999999999999999999999.87');
|
|
880
|
+
expect(columns[n++]).toBe(-4.567);
|
|
881
|
+
expect(dateTimeToString(columns[n++])).toBe('2017-3-26 0:0:0.0');
|
|
882
|
+
expect(dateTimeToString(columns[n++])).toBe('0050-3-26 0:0:0.0');
|
|
883
|
+
expect(dateTimeToString(columns[n++])).toBe('9999-3-26 0:0:0.0');
|
|
884
|
+
expect(timeToString(columns[n++])).toBe('11:56:32.123');
|
|
885
|
+
expect(timeTzToString(columns[n++])).toBe(`time '6:56:32.123 America/New_York'`);
|
|
886
|
+
expect(timeTzToString(columns[n++])).toBe(`time '8:56:32.123 America/Sao_Paulo'`);
|
|
887
|
+
expect(dateTimeToString(columns[n++])).toBe('2017-3-26 11:56:32.123');
|
|
888
|
+
expect(dateTimeToString(columns[n++])).toBe('0050-3-26 11:56:32.123');
|
|
889
|
+
expect(dateTimeToString(columns[n++])).toBe('9999-3-26 11:56:32.123');
|
|
890
|
+
expect(dateTimeTzToString(columns[n++])).toBe(`timestamp '2021-6-7 7:56:32.123 America/New_York'`);
|
|
891
|
+
expect(dateTimeTzToString(columns[n++])).toBe(`timestamp '2021-6-7 8:56:32.123 America/Sao_Paulo'`);
|
|
892
|
+
expect(columns[n++]).toBe(true);
|
|
893
|
+
expect(columns[n++]).toBe('123áé4567');
|
|
894
|
+
expect(columns[n++]).toBe(9);
|
|
895
|
+
expect(columns[n++]).toBe(11);
|
|
896
|
+
expect(columns[n++]).toBe('123áé4567 ');
|
|
897
|
+
expect(columns[n++]).toBe(10);
|
|
898
|
+
expect(columns[n++]).toBe(12);
|
|
899
|
+
expect(columns[n++]).toBeNull();
|
|
900
|
+
expect(columns[n++]).toBeNull();
|
|
901
|
+
|
|
902
|
+
for (const i = n + 2; n < i; ++n) {
|
|
903
|
+
const blob = columns[n] as Blob;
|
|
904
|
+
expect(blob.isValid).toBeTruthy();
|
|
905
|
+
const blobStream = await attachment.openBlob(transaction, blob);
|
|
906
|
+
const buffer = Buffer.alloc(await blobStream.length);
|
|
907
|
+
expect(await blobStream.read(buffer)).toBe(buffer.length);
|
|
908
|
+
expect(await blobStream.read(buffer)).toBe(-1);
|
|
909
|
+
|
|
910
|
+
await blobStream.close();
|
|
911
|
+
|
|
912
|
+
expect(buffer.toString()).toBe('12345678á9');
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
expect(columns.length).toBe(n);
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
expect((await resultSet3.fetch()).length).toBe(0);
|
|
919
|
+
expect((await resultSet3.fetch()).length).toBe(0);
|
|
920
|
+
|
|
921
|
+
await resultSet3.close();
|
|
922
|
+
await statement3.dispose();
|
|
923
|
+
|
|
924
|
+
await transaction.commit();
|
|
925
|
+
await attachment.dropDatabase();
|
|
926
|
+
});
|
|
927
|
+
|
|
928
|
+
test('#fetchAsObject()', async () => {
|
|
929
|
+
const attachment = await client.createDatabase(getTempFile('ResultSet-fetchAsObject.fdb'));
|
|
930
|
+
const transaction = await attachment.startTransaction();
|
|
931
|
+
const resultSet = await attachment.executeQuery(transaction, 'select 1 as a, 2 as b from rdb$database');
|
|
932
|
+
const output = await resultSet.fetchAsObject<{
|
|
933
|
+
A: number;
|
|
934
|
+
B: number;
|
|
935
|
+
}>();
|
|
936
|
+
expect(output[0].A).toBe(1);
|
|
937
|
+
expect(output[0].B).toBe(2);
|
|
938
|
+
await resultSet.close();
|
|
939
|
+
|
|
940
|
+
await transaction.commit();
|
|
941
|
+
await attachment.dropDatabase();
|
|
942
|
+
});
|
|
943
|
+
|
|
944
|
+
test('#fetch() with fetchSize', async () => {
|
|
945
|
+
const attachment = await client.createDatabase(getTempFile('ResultSet-fetch-with-fetchSize.fdb'));
|
|
946
|
+
const transaction = await attachment.startTransaction();
|
|
947
|
+
|
|
948
|
+
await attachment.execute(transaction, 'create table t1 (n1 integer)');
|
|
949
|
+
await transaction.commitRetaining();
|
|
950
|
+
|
|
951
|
+
await attachment.execute(
|
|
952
|
+
transaction,
|
|
953
|
+
`
|
|
825
954
|
execute block
|
|
826
955
|
as
|
|
827
956
|
declare n integer = 0;
|
|
@@ -832,32 +961,35 @@ export function runCommonTests(client: Client) {
|
|
|
832
961
|
n = n + 1;
|
|
833
962
|
end
|
|
834
963
|
end
|
|
835
|
-
|
|
964
|
+
`,
|
|
965
|
+
);
|
|
836
966
|
|
|
837
|
-
|
|
838
|
-
|
|
967
|
+
const rs = await attachment.executeQuery(transaction, 'select n1 from t1 order by n1');
|
|
968
|
+
rs.defaultFetchOptions = { fetchSize: 5 };
|
|
839
969
|
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
970
|
+
expect((await rs.fetch()).length).toBe(5);
|
|
971
|
+
expect((await rs.fetch({ fetchSize: 2 })).length).toBe(2);
|
|
972
|
+
expect((await rs.fetch()).length).toBe(5);
|
|
973
|
+
expect((await rs.fetch({ fetchSize: 36 })).length).toBe(36);
|
|
974
|
+
expect((await rs.fetch()).length).toBe(2);
|
|
975
|
+
expect((await rs.fetch()).length).toBe(0);
|
|
846
976
|
|
|
847
|
-
|
|
977
|
+
await rs.close();
|
|
848
978
|
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
979
|
+
await transaction.commit();
|
|
980
|
+
await attachment.dropDatabase();
|
|
981
|
+
});
|
|
852
982
|
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
983
|
+
test('#fetch() with fetchSize and exception', async () => {
|
|
984
|
+
const attachment = await client.createDatabase(getTempFile('ResultSet-fetch-with-fetchSize.fdb'));
|
|
985
|
+
const transaction = await attachment.startTransaction();
|
|
856
986
|
|
|
857
|
-
|
|
858
|
-
|
|
987
|
+
await attachment.execute(transaction, "create exception e1 'e1'");
|
|
988
|
+
await transaction.commitRetaining();
|
|
859
989
|
|
|
860
|
-
|
|
990
|
+
const rs = await attachment.executeQuery(
|
|
991
|
+
transaction,
|
|
992
|
+
`
|
|
861
993
|
execute block returns (n integer)
|
|
862
994
|
as
|
|
863
995
|
begin
|
|
@@ -869,91 +1001,95 @@ export function runCommonTests(client: Client) {
|
|
|
869
1001
|
n = 3;
|
|
870
1002
|
suspend;
|
|
871
1003
|
end
|
|
872
|
-
|
|
873
|
-
|
|
1004
|
+
`,
|
|
1005
|
+
);
|
|
1006
|
+
rs.defaultFetchOptions = { fetchSize: 5 };
|
|
874
1007
|
|
|
875
|
-
|
|
876
|
-
|
|
1008
|
+
expect((await rs.fetch()).length).toBe(2);
|
|
1009
|
+
expect(rs.fetch()).rejects.toBeTruthy();
|
|
877
1010
|
|
|
878
|
-
|
|
1011
|
+
await rs.close();
|
|
879
1012
|
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
1013
|
+
await transaction.commit();
|
|
1014
|
+
await attachment.dropDatabase();
|
|
1015
|
+
});
|
|
883
1016
|
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
1017
|
+
test('#fetch() with large blob', async () => {
|
|
1018
|
+
const attachment = await client.createDatabase(getTempFile('ResultSet-fetch-with-large-blob.fdb'));
|
|
1019
|
+
let transaction = await attachment.startTransaction();
|
|
1020
|
+
await attachment.execute(transaction, `create table t1 (x_blob blob)`);
|
|
888
1021
|
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
1022
|
+
await transaction.commit();
|
|
1023
|
+
transaction = await attachment.startTransaction();
|
|
1024
|
+
const buffer = Buffer.from('123'.repeat(60000));
|
|
892
1025
|
|
|
893
|
-
|
|
1026
|
+
await attachment.execute(transaction, `insert into t1 (x_blob) values (?)`, [buffer]);
|
|
894
1027
|
|
|
895
|
-
|
|
896
|
-
|
|
1028
|
+
await transaction.commit();
|
|
1029
|
+
transaction = await attachment.startTransaction();
|
|
897
1030
|
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
1031
|
+
const resultSet = await attachment.executeQuery(transaction, `select x_blob from t1`);
|
|
1032
|
+
const result = await resultSet.fetch();
|
|
1033
|
+
const readStream = await attachment.openBlob(transaction, result[0][0]);
|
|
901
1034
|
|
|
902
|
-
|
|
903
|
-
|
|
1035
|
+
const blobLength = await readStream.length;
|
|
1036
|
+
const resultBuffer = Buffer.alloc(blobLength);
|
|
904
1037
|
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
1038
|
+
let size = 0;
|
|
1039
|
+
let n: number;
|
|
1040
|
+
while (size < blobLength && (n = await readStream.read(resultBuffer.slice(size))) > 0) {
|
|
1041
|
+
size += n;
|
|
1042
|
+
}
|
|
909
1043
|
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
1044
|
+
await readStream.close();
|
|
1045
|
+
expect(resultBuffer.toString().length).toEqual(buffer.toString().length);
|
|
1046
|
+
expect(resultBuffer.toString()).toEqual(buffer.toString());
|
|
913
1047
|
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
1048
|
+
await resultSet.close();
|
|
1049
|
+
await transaction.commit();
|
|
1050
|
+
await attachment.dropDatabase();
|
|
1051
|
+
});
|
|
1052
|
+
});
|
|
919
1053
|
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
1054
|
+
describe('BlobStream', () => {
|
|
1055
|
+
test('#seek()', async () => {
|
|
1056
|
+
const attachment = await client.createDatabase(getTempFile('BlobStream-seek.fdb'));
|
|
1057
|
+
const transaction = await attachment.startTransaction();
|
|
924
1058
|
|
|
925
|
-
|
|
926
|
-
|
|
1059
|
+
await attachment.execute(transaction, 'create table t1 (b blob)');
|
|
1060
|
+
await transaction.commitRetaining();
|
|
927
1061
|
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
1062
|
+
const blobStream = await attachment.createBlob(transaction, {
|
|
1063
|
+
type: 'STREAM',
|
|
1064
|
+
});
|
|
1065
|
+
await blobStream.write(Buffer.alloc(10, '1234567890'));
|
|
1066
|
+
await blobStream.close();
|
|
1067
|
+
await attachment.execute(transaction, 'insert into t1 (b) values (?)', [blobStream.blob]);
|
|
932
1068
|
|
|
933
|
-
|
|
934
|
-
|
|
1069
|
+
const blob = (await attachment.executeSingleton(transaction, 'select b from t1'))[0] as Blob;
|
|
1070
|
+
const readBlobStream = await attachment.openBlob(transaction, blob);
|
|
935
1071
|
|
|
936
|
-
|
|
1072
|
+
const buffer = Buffer.alloc(3);
|
|
937
1073
|
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
1074
|
+
expect(await readBlobStream.seek(2)).toBe(2);
|
|
1075
|
+
expect(await readBlobStream.read(buffer)).toBe(3);
|
|
1076
|
+
expect(buffer.toString()).toBe('345');
|
|
941
1077
|
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
1078
|
+
expect(await readBlobStream.seek(-1, BlobSeekWhence.CURRENT)).toBe(4);
|
|
1079
|
+
expect(await readBlobStream.read(buffer)).toBe(3);
|
|
1080
|
+
expect(buffer.toString()).toBe('567');
|
|
945
1081
|
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
1082
|
+
expect(await readBlobStream.seek(1, BlobSeekWhence.START)).toBe(1);
|
|
1083
|
+
expect(await readBlobStream.read(buffer)).toBe(3);
|
|
1084
|
+
expect(buffer.toString()).toBe('234');
|
|
949
1085
|
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
1086
|
+
expect(await readBlobStream.seek(-2, BlobSeekWhence.END)).toBe(8);
|
|
1087
|
+
expect(await readBlobStream.read(buffer)).toBe(2);
|
|
1088
|
+
expect(buffer.slice(0, 2).toString()).toBe('90');
|
|
953
1089
|
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
1090
|
+
await transaction.commit();
|
|
1091
|
+
await attachment.dropDatabase();
|
|
1092
|
+
});
|
|
1093
|
+
});
|
|
1094
|
+
});
|
|
959
1095
|
}
|