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