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/lib/impl/fb-util.ts
CHANGED
|
@@ -4,247 +4,260 @@ const littleEndian = os.endianness() === 'LE';
|
|
|
4
4
|
import * as stringDecoder from 'string_decoder';
|
|
5
5
|
|
|
6
6
|
import { AbstractAttachment } from './attachment';
|
|
7
|
-
import { AbstractTransaction } from './transaction';
|
|
8
7
|
import { decodeDate, decodeTime, encodeDate, encodeTime } from './date-time';
|
|
9
8
|
import { tzIdToString, tzStringToId } from './time-zones';
|
|
9
|
+
import { AbstractTransaction } from './transaction';
|
|
10
10
|
|
|
11
11
|
import {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
12
|
+
Attachment,
|
|
13
|
+
Blob,
|
|
14
|
+
BlobStream,
|
|
15
|
+
ConnectOptions,
|
|
16
|
+
CreateBlobOptions,
|
|
17
|
+
CreateDatabaseOptions,
|
|
18
|
+
DatabaseReadWriteMode,
|
|
19
|
+
Transaction,
|
|
20
|
+
TransactionIsolation,
|
|
21
|
+
TransactionOptions,
|
|
22
|
+
ZonedDate,
|
|
23
|
+
ZonedDateEx,
|
|
23
24
|
} from '..';
|
|
24
25
|
|
|
25
|
-
|
|
26
26
|
/** SQL_* type constants */
|
|
27
27
|
export namespace sqlTypes {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
28
|
+
export const SQL_TEXT = 452;
|
|
29
|
+
export const SQL_VARYING = 448;
|
|
30
|
+
export const SQL_SHORT = 500;
|
|
31
|
+
export const SQL_LONG = 496;
|
|
32
|
+
export const SQL_FLOAT = 482;
|
|
33
|
+
export const SQL_DOUBLE = 480;
|
|
34
|
+
//export const SQL_D_FLOAT = 530;
|
|
35
|
+
export const SQL_TIMESTAMP = 510;
|
|
36
|
+
export const SQL_BLOB = 520;
|
|
37
|
+
//export const SQL_ARRAY = 540;
|
|
38
|
+
//export const SQL_QUAD = 550;
|
|
39
|
+
export const SQL_TYPE_TIME = 560;
|
|
40
|
+
export const SQL_TYPE_DATE = 570;
|
|
41
|
+
export const SQL_INT64 = 580;
|
|
42
|
+
export const SQL_TIMESTAMP_TZ_EX = 32748;
|
|
43
|
+
export const SQL_TIME_TZ_EX = 32750;
|
|
44
|
+
export const SQL_TIMESTAMP_TZ = 32754;
|
|
45
|
+
export const SQL_TIME_TZ = 32756;
|
|
46
|
+
export const SQL_INT128 = 32752;
|
|
47
|
+
export const SQL_DEC16 = 32760;
|
|
48
|
+
export const SQL_DEC34 = 32762;
|
|
49
|
+
export const SQL_BOOLEAN = 32764;
|
|
50
|
+
export const SQL_NULL = 32766;
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
/** DPB constants. */
|
|
54
54
|
export namespace dpb {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
/* tslint:enable */
|
|
55
|
+
export const version1 = 1;
|
|
56
|
+
export const lc_ctype = 48;
|
|
57
|
+
export const force_write = 24;
|
|
58
|
+
export const user_name = 28;
|
|
59
|
+
export const password = 29;
|
|
60
|
+
export const sql_role_name = 60;
|
|
61
|
+
export const set_db_readonly = 64;
|
|
63
62
|
}
|
|
64
63
|
|
|
65
64
|
/** TPB constants. */
|
|
66
65
|
export namespace tpb {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
export const no_auto_undo = 20;
|
|
82
|
-
/* tslint:enable */
|
|
66
|
+
export const version1 = 1;
|
|
67
|
+
export const consistency = 1;
|
|
68
|
+
export const concurrency = 2;
|
|
69
|
+
export const wait = 6;
|
|
70
|
+
export const nowait = 7;
|
|
71
|
+
export const read = 8;
|
|
72
|
+
export const write = 9;
|
|
73
|
+
export const ignore_limbo = 14;
|
|
74
|
+
export const read_committed = 15;
|
|
75
|
+
export const autocommit = 16;
|
|
76
|
+
export const rec_version = 17;
|
|
77
|
+
export const no_rec_version = 18;
|
|
78
|
+
export const restart_requests = 19;
|
|
79
|
+
export const no_auto_undo = 20;
|
|
83
80
|
}
|
|
84
81
|
|
|
85
82
|
/** BPB constants. */
|
|
86
83
|
export namespace bpb {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
export const storage_temp = 0x2;
|
|
101
|
-
/* tslint:enable */
|
|
84
|
+
export const version1 = 1;
|
|
85
|
+
export const source_type = 1;
|
|
86
|
+
export const target_type = 2;
|
|
87
|
+
export const type = 3;
|
|
88
|
+
export const source_interp = 4;
|
|
89
|
+
export const target_interp = 5;
|
|
90
|
+
export const filter_parameter = 6;
|
|
91
|
+
export const storage = 7;
|
|
92
|
+
|
|
93
|
+
export const type_segmented = 0x0;
|
|
94
|
+
export const type_stream = 0x1;
|
|
95
|
+
export const storage_main = 0x0;
|
|
96
|
+
export const storage_temp = 0x2;
|
|
102
97
|
}
|
|
103
98
|
|
|
104
99
|
/** EPB constants. */
|
|
105
100
|
export namespace epb {
|
|
106
|
-
|
|
107
|
-
export const version1 = 1;
|
|
108
|
-
/* tslint:enable */
|
|
101
|
+
export const version1 = 1;
|
|
109
102
|
}
|
|
110
103
|
|
|
111
104
|
/** Blob info. */
|
|
112
105
|
export namespace blobInfo {
|
|
113
|
-
|
|
106
|
+
export const totalLength = 6;
|
|
114
107
|
}
|
|
115
108
|
|
|
116
109
|
/** Statement info. */
|
|
117
110
|
export namespace statementInfo {
|
|
118
|
-
|
|
111
|
+
export const sqlExecPathBlrText = 32;
|
|
119
112
|
}
|
|
120
113
|
|
|
121
114
|
/** Common info. */
|
|
122
115
|
export namespace commonInfo {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
116
|
+
export const end = 1;
|
|
117
|
+
export const truncated = 2;
|
|
118
|
+
export const error = 3;
|
|
119
|
+
export const dataNotReady = 4;
|
|
120
|
+
export const length = 126;
|
|
121
|
+
export const flagEnd = 127;
|
|
129
122
|
}
|
|
130
123
|
|
|
131
124
|
export namespace cancelType {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
125
|
+
export const disable = 1;
|
|
126
|
+
export const enable = 2;
|
|
127
|
+
export const raise = 3;
|
|
128
|
+
export const abort = 4;
|
|
136
129
|
}
|
|
137
130
|
|
|
138
131
|
export namespace charSets {
|
|
139
|
-
|
|
132
|
+
export const ascii = 2;
|
|
140
133
|
}
|
|
141
134
|
|
|
142
135
|
export function createDpb(options?: ConnectOptions | CreateDatabaseOptions): Buffer {
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
136
|
+
const code = (c: number) => String.fromCharCode(c);
|
|
137
|
+
const charSet = 'utf8';
|
|
138
|
+
let ret = `${code(dpb.version1)}${code(dpb.lc_ctype)}${code(charSet.length)}${charSet}`;
|
|
146
139
|
|
|
147
|
-
|
|
148
|
-
|
|
140
|
+
if (!options) {
|
|
141
|
+
options = {};
|
|
142
|
+
}
|
|
149
143
|
|
|
150
|
-
|
|
151
|
-
|
|
144
|
+
if (!options.username) {
|
|
145
|
+
options.username = process.env.ISC_USER;
|
|
146
|
+
}
|
|
152
147
|
|
|
153
|
-
|
|
154
|
-
|
|
148
|
+
if (!options.password) {
|
|
149
|
+
options.password = process.env.ISC_PASSWORD;
|
|
150
|
+
}
|
|
155
151
|
|
|
156
|
-
|
|
157
|
-
|
|
152
|
+
if (options.username) {
|
|
153
|
+
ret += `${code(dpb.user_name)}${code(options.username.length)}${options.username}`;
|
|
154
|
+
}
|
|
158
155
|
|
|
159
|
-
|
|
160
|
-
|
|
156
|
+
if (options.password) {
|
|
157
|
+
ret += `${code(dpb.password)}${code(options.password.length)}${options.password}`;
|
|
158
|
+
}
|
|
161
159
|
|
|
162
|
-
|
|
163
|
-
|
|
160
|
+
if (options.role) {
|
|
161
|
+
ret += `${code(dpb.sql_role_name)}${code(options.role.length)}${options.role}`;
|
|
162
|
+
}
|
|
164
163
|
|
|
165
|
-
|
|
164
|
+
const createOptions = options as CreateDatabaseOptions;
|
|
166
165
|
|
|
167
|
-
|
|
168
|
-
|
|
166
|
+
if (createOptions.forcedWrite != undefined) {
|
|
167
|
+
ret += `${code(dpb.force_write)}${code(1)}${code(createOptions.forcedWrite ? 1 : 0)}`;
|
|
168
|
+
}
|
|
169
169
|
|
|
170
|
-
|
|
170
|
+
if (options.setDatabaseReadWriteMode) {
|
|
171
|
+
ret += `${code(dpb.set_db_readonly)}${code(1)}${code(
|
|
172
|
+
options.setDatabaseReadWriteMode == DatabaseReadWriteMode.READ_ONLY ? 1 : 0,
|
|
173
|
+
)}`;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return Buffer.from(ret);
|
|
171
177
|
}
|
|
172
178
|
|
|
173
179
|
export function createTpb(options?: TransactionOptions): Buffer {
|
|
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
|
-
|
|
180
|
+
const code = (c: number) => String.fromCharCode(c);
|
|
181
|
+
let ret = code(tpb.version1);
|
|
182
|
+
|
|
183
|
+
if (!options) {
|
|
184
|
+
options = {};
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
switch (options.accessMode) {
|
|
188
|
+
case 'READ_ONLY':
|
|
189
|
+
ret += code(tpb.read);
|
|
190
|
+
break;
|
|
191
|
+
|
|
192
|
+
case 'READ_WRITE':
|
|
193
|
+
ret += code(tpb.write);
|
|
194
|
+
break;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
switch (options.waitMode) {
|
|
198
|
+
case 'NO_WAIT':
|
|
199
|
+
ret += code(tpb.nowait);
|
|
200
|
+
break;
|
|
201
|
+
|
|
202
|
+
case 'WAIT':
|
|
203
|
+
ret += code(tpb.wait);
|
|
204
|
+
break;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
switch (options.isolation) {
|
|
208
|
+
case TransactionIsolation.CONSISTENCY:
|
|
209
|
+
ret += code(tpb.consistency);
|
|
210
|
+
break;
|
|
211
|
+
|
|
212
|
+
case TransactionIsolation.SNAPSHOT:
|
|
213
|
+
ret += code(tpb.concurrency);
|
|
214
|
+
break;
|
|
215
|
+
|
|
216
|
+
case TransactionIsolation.READ_COMMITTED:
|
|
217
|
+
ret +=
|
|
218
|
+
code(tpb.read_committed) +
|
|
219
|
+
code(options.readCommittedMode == 'RECORD_VERSION' ? tpb.rec_version : tpb.no_rec_version);
|
|
220
|
+
break;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
if (options.noAutoUndo) {
|
|
224
|
+
ret += code(tpb.no_auto_undo);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
if (options.ignoreLimbo) {
|
|
228
|
+
ret += code(tpb.ignore_limbo);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
if (options.restartRequests) {
|
|
232
|
+
ret += code(tpb.restart_requests);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if (options.autoCommit) {
|
|
236
|
+
ret += code(tpb.autocommit);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
return Buffer.from(ret);
|
|
228
240
|
}
|
|
229
241
|
|
|
230
242
|
export function createBpb(options?: CreateBlobOptions): Buffer {
|
|
231
|
-
|
|
232
|
-
|
|
243
|
+
const code = (c: number) => String.fromCharCode(c);
|
|
244
|
+
let ret = code(bpb.version1);
|
|
233
245
|
|
|
234
|
-
|
|
235
|
-
|
|
246
|
+
if (!options) {
|
|
247
|
+
options = {};
|
|
248
|
+
}
|
|
236
249
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
250
|
+
switch (options.type) {
|
|
251
|
+
case 'SEGMENTED':
|
|
252
|
+
ret += `${code(bpb.type)}${code(1)}${code(bpb.type_segmented)}`;
|
|
253
|
+
break;
|
|
241
254
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
255
|
+
case 'STREAM':
|
|
256
|
+
ret += `${code(bpb.type)}${code(1)}${code(bpb.type_stream)}`;
|
|
257
|
+
break;
|
|
258
|
+
}
|
|
246
259
|
|
|
247
|
-
|
|
260
|
+
return Buffer.from(ret);
|
|
248
261
|
}
|
|
249
262
|
|
|
250
263
|
/** Changes a number from a scale to another. */
|
|
@@ -265,57 +278,62 @@ export function changeScale(value: number, inputScale: number, outputScale: numb
|
|
|
265
278
|
|
|
266
279
|
/** Emulate Firebird isc_portable_integer. */
|
|
267
280
|
export function getPortableInteger(buffer: Uint8Array, length: number) {
|
|
268
|
-
|
|
269
|
-
|
|
281
|
+
if (!buffer || length <= 0 || length > 8) {
|
|
282
|
+
return 0;
|
|
283
|
+
}
|
|
270
284
|
|
|
271
|
-
|
|
272
|
-
|
|
285
|
+
let value = 0;
|
|
286
|
+
let pos = 0;
|
|
273
287
|
|
|
274
|
-
|
|
275
|
-
|
|
288
|
+
for (let shift = 0; --length >= 0; shift += 8) {
|
|
289
|
+
value += buffer[pos++] << shift;
|
|
290
|
+
}
|
|
276
291
|
|
|
277
|
-
|
|
292
|
+
return value;
|
|
278
293
|
}
|
|
279
294
|
|
|
280
|
-
|
|
281
295
|
/** Descriptor for a field or parameter. */
|
|
282
296
|
export interface Descriptor {
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
297
|
+
type: number;
|
|
298
|
+
subType: number;
|
|
299
|
+
length: number;
|
|
300
|
+
scale: number;
|
|
301
|
+
offset: number;
|
|
302
|
+
nullOffset: number;
|
|
289
303
|
}
|
|
290
304
|
|
|
291
|
-
|
|
292
305
|
export type DataReader = (attachment: Attachment, transaction: Transaction, buffer: Uint8Array) => Promise<any[]>;
|
|
293
306
|
export type ItemReader = (attachment: Attachment, transaction: Transaction, buffer: Uint8Array) => Promise<any>;
|
|
294
307
|
|
|
295
308
|
/** Creates a data reader. */
|
|
296
309
|
export function createDataReader(descriptors: Descriptor[]): DataReader {
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
310
|
+
const mappers = new Array<ItemReader>(descriptors.length);
|
|
311
|
+
|
|
312
|
+
for (let i = 0; i < descriptors.length; ++i) {
|
|
313
|
+
const descriptor = descriptors[i];
|
|
314
|
+
|
|
315
|
+
mappers[i] = async (
|
|
316
|
+
attachment: AbstractAttachment,
|
|
317
|
+
transaction: AbstractTransaction,
|
|
318
|
+
buffer: Uint8Array,
|
|
319
|
+
): Promise<any> => {
|
|
320
|
+
const dataView = new DataView(buffer.buffer);
|
|
321
|
+
|
|
322
|
+
if (dataView.getInt16(descriptor.nullOffset, littleEndian) == -1) {
|
|
323
|
+
return null;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
switch (descriptor.type) {
|
|
327
|
+
// SQL_TEXT is handled changing its descriptor to SQL_VARYING with IMetadataBuilder.
|
|
328
|
+
case sqlTypes.SQL_VARYING: {
|
|
329
|
+
//// TODO: none, octets
|
|
330
|
+
const varLength = dataView.getUint16(descriptor.offset, littleEndian);
|
|
331
|
+
const decoder = new stringDecoder.StringDecoder('utf8');
|
|
332
|
+
const buf = Buffer.from(buffer.buffer, descriptor.offset + 2, varLength);
|
|
333
|
+
return decoder.end(buf);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/***
|
|
319
337
|
case sqlTypes.SQL_SHORT:
|
|
320
338
|
return changeScale(dataView.getInt16(descriptor.offset, littleEndian), descriptor.scale, 0);
|
|
321
339
|
|
|
@@ -328,148 +346,210 @@ export function createDataReader(descriptors: Descriptor[]): DataReader {
|
|
|
328
346
|
return dataView.getFloat32(descriptor.offset, littleEndian);
|
|
329
347
|
***/
|
|
330
348
|
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
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
|
-
|
|
349
|
+
case sqlTypes.SQL_DOUBLE:
|
|
350
|
+
return dataView.getFloat64(descriptor.offset, littleEndian);
|
|
351
|
+
|
|
352
|
+
case sqlTypes.SQL_TYPE_TIME: {
|
|
353
|
+
const now = new Date();
|
|
354
|
+
const decodedTime = decodeTime(dataView.getUint32(descriptor.offset, littleEndian));
|
|
355
|
+
return new Date(
|
|
356
|
+
now.getFullYear(),
|
|
357
|
+
now.getMonth(),
|
|
358
|
+
now.getDate(),
|
|
359
|
+
decodedTime.hours,
|
|
360
|
+
decodedTime.minutes,
|
|
361
|
+
decodedTime.seconds,
|
|
362
|
+
decodedTime.fractions / 10,
|
|
363
|
+
);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
case sqlTypes.SQL_TIME_TZ_EX: {
|
|
367
|
+
const now = new Date();
|
|
368
|
+
const decodedTime = decodeTime(dataView.getUint32(descriptor.offset, littleEndian));
|
|
369
|
+
const date = new Date(
|
|
370
|
+
Date.UTC(
|
|
371
|
+
now.getUTCFullYear(),
|
|
372
|
+
now.getUTCMonth(),
|
|
373
|
+
now.getUTCDate(),
|
|
374
|
+
decodedTime.hours,
|
|
375
|
+
decodedTime.minutes,
|
|
376
|
+
decodedTime.seconds,
|
|
377
|
+
decodedTime.fractions / 10,
|
|
378
|
+
),
|
|
379
|
+
);
|
|
380
|
+
const timeZone = tzIdToString(dataView.getUint16(descriptor.offset + 4, littleEndian));
|
|
381
|
+
const offset = dataView.getInt16(descriptor.offset + 6, littleEndian);
|
|
382
|
+
|
|
383
|
+
return {
|
|
384
|
+
date,
|
|
385
|
+
timeZone,
|
|
386
|
+
offset,
|
|
387
|
+
} as ZonedDateEx;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
case sqlTypes.SQL_TYPE_DATE: {
|
|
391
|
+
const decodedDate = decodeDate(dataView.getInt32(descriptor.offset, littleEndian));
|
|
392
|
+
|
|
393
|
+
if (decodedDate.year >= 100) {
|
|
394
|
+
return new Date(decodedDate.year, decodedDate.month - 1, decodedDate.day);
|
|
395
|
+
} else {
|
|
396
|
+
const date = new Date(2000, decodedDate.month - 1, decodedDate.day);
|
|
397
|
+
date.setFullYear(decodedDate.year);
|
|
398
|
+
return date;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
case sqlTypes.SQL_TIMESTAMP: {
|
|
403
|
+
const decodedDate = decodeDate(dataView.getInt32(descriptor.offset, littleEndian));
|
|
404
|
+
const decodedTime = decodeTime(dataView.getUint32(descriptor.offset + 4, littleEndian));
|
|
405
|
+
|
|
406
|
+
if (decodedDate.year >= 100) {
|
|
407
|
+
return new Date(
|
|
408
|
+
decodedDate.year,
|
|
409
|
+
decodedDate.month - 1,
|
|
410
|
+
decodedDate.day,
|
|
411
|
+
decodedTime.hours,
|
|
412
|
+
decodedTime.minutes,
|
|
413
|
+
decodedTime.seconds,
|
|
414
|
+
decodedTime.fractions / 10,
|
|
415
|
+
);
|
|
416
|
+
} else {
|
|
417
|
+
const date = new Date(
|
|
418
|
+
2000,
|
|
419
|
+
decodedDate.month - 1,
|
|
420
|
+
decodedDate.day,
|
|
421
|
+
decodedTime.hours,
|
|
422
|
+
decodedTime.minutes,
|
|
423
|
+
decodedTime.seconds,
|
|
424
|
+
decodedTime.fractions / 10,
|
|
425
|
+
);
|
|
426
|
+
date.setFullYear(decodedDate.year);
|
|
427
|
+
return date;
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
case sqlTypes.SQL_TIMESTAMP_TZ_EX: {
|
|
432
|
+
const decodedDate = decodeDate(dataView.getInt32(descriptor.offset, littleEndian));
|
|
433
|
+
const decodedTime = decodeTime(dataView.getUint32(descriptor.offset + 4, littleEndian));
|
|
434
|
+
const timeZone = tzIdToString(dataView.getUint16(descriptor.offset + 8, littleEndian));
|
|
435
|
+
const offset = dataView.getInt16(descriptor.offset + 10, littleEndian);
|
|
436
|
+
let date: Date;
|
|
437
|
+
|
|
438
|
+
if (decodedDate.year >= 100) {
|
|
439
|
+
date = new Date(
|
|
440
|
+
Date.UTC(
|
|
441
|
+
decodedDate.year,
|
|
442
|
+
decodedDate.month - 1,
|
|
443
|
+
decodedDate.day,
|
|
444
|
+
decodedTime.hours,
|
|
445
|
+
decodedTime.minutes,
|
|
446
|
+
decodedTime.seconds,
|
|
447
|
+
decodedTime.fractions / 10,
|
|
448
|
+
),
|
|
449
|
+
);
|
|
450
|
+
} else {
|
|
451
|
+
date = new Date(
|
|
452
|
+
Date.UTC(
|
|
453
|
+
2000,
|
|
454
|
+
decodedDate.month - 1,
|
|
455
|
+
decodedDate.day,
|
|
456
|
+
decodedTime.hours,
|
|
457
|
+
decodedTime.minutes,
|
|
458
|
+
decodedTime.seconds,
|
|
459
|
+
decodedTime.fractions / 10,
|
|
460
|
+
),
|
|
461
|
+
);
|
|
462
|
+
date.setUTCFullYear(decodedDate.year);
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
return {
|
|
466
|
+
date,
|
|
467
|
+
timeZone,
|
|
468
|
+
offset,
|
|
469
|
+
} as ZonedDateEx;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
case sqlTypes.SQL_BOOLEAN:
|
|
473
|
+
return dataView.getInt8(descriptor.offset) != 0;
|
|
474
|
+
|
|
475
|
+
case sqlTypes.SQL_BLOB:
|
|
476
|
+
return new Blob(attachment, buffer.slice(descriptor.offset, descriptor.offset + 8));
|
|
477
|
+
|
|
478
|
+
case sqlTypes.SQL_NULL:
|
|
479
|
+
return null;
|
|
480
|
+
|
|
481
|
+
default:
|
|
482
|
+
throw new Error(`Unrecognized Firebird type number ${descriptor.type}`);
|
|
483
|
+
}
|
|
484
|
+
};
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
return async (attachment: Attachment, transaction: Transaction, buffer: Uint8Array): Promise<any[]> => {
|
|
488
|
+
return await Promise.all(mappers.map((mapper) => mapper(attachment, transaction, buffer)));
|
|
489
|
+
};
|
|
426
490
|
}
|
|
427
491
|
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
492
|
+
export type DataWriter = (
|
|
493
|
+
attachment: Attachment,
|
|
494
|
+
transaction: Transaction,
|
|
495
|
+
buffer: Uint8Array,
|
|
496
|
+
values: any[] | undefined,
|
|
497
|
+
) => Promise<void>;
|
|
498
|
+
export type ItemWriter = (
|
|
499
|
+
attachment: Attachment,
|
|
500
|
+
transaction: Transaction,
|
|
501
|
+
buffer: Uint8Array,
|
|
502
|
+
values: any,
|
|
503
|
+
) => Promise<void>;
|
|
432
504
|
|
|
433
505
|
/** Creates a data writer. */
|
|
434
506
|
export function createDataWriter(descriptors: Descriptor[]): DataWriter {
|
|
435
|
-
|
|
507
|
+
const mappers = new Array<ItemWriter>(descriptors.length);
|
|
436
508
|
|
|
437
|
-
|
|
438
|
-
|
|
509
|
+
for (let i = 0; i < descriptors.length; ++i) {
|
|
510
|
+
const descriptor = descriptors[i];
|
|
439
511
|
|
|
440
|
-
|
|
441
|
-
|
|
512
|
+
mappers[i] = async (
|
|
513
|
+
attachment: Attachment,
|
|
514
|
+
transaction: Transaction,
|
|
515
|
+
buffer: Uint8Array,
|
|
516
|
+
value: any,
|
|
517
|
+
): Promise<void> => {
|
|
518
|
+
const dataView = new DataView(buffer.buffer);
|
|
442
519
|
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
520
|
+
if (value == null) {
|
|
521
|
+
dataView.setInt16(descriptor.nullOffset, -1, littleEndian);
|
|
522
|
+
return;
|
|
523
|
+
}
|
|
447
524
|
|
|
448
|
-
|
|
525
|
+
dataView.setInt16(descriptor.nullOffset, 0, littleEndian);
|
|
449
526
|
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
527
|
+
switch (descriptor.type) {
|
|
528
|
+
// SQL_TEXT is handled changing its descriptor to SQL_VARYING with IMetadataBuilder.
|
|
529
|
+
case sqlTypes.SQL_VARYING: {
|
|
530
|
+
//// TODO: none, octets
|
|
531
|
+
const str = value as string;
|
|
532
|
+
const strBuffer = Buffer.from(str);
|
|
456
533
|
|
|
457
|
-
|
|
534
|
+
const bytesArray = Uint8Array.from(strBuffer);
|
|
458
535
|
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
536
|
+
if (bytesArray.length > descriptor.length) {
|
|
537
|
+
throw new Error(
|
|
538
|
+
`Length in bytes of string '${str}' (${bytesArray.length}) is ` +
|
|
539
|
+
`greater than maximum expect length ${descriptor.length}.`,
|
|
540
|
+
);
|
|
541
|
+
}
|
|
463
542
|
|
|
464
|
-
|
|
543
|
+
dataView.setUint16(descriptor.offset, bytesArray.length, littleEndian);
|
|
465
544
|
|
|
466
|
-
|
|
467
|
-
|
|
545
|
+
for (let j = 0; j < bytesArray.length; ++j) {
|
|
546
|
+
buffer[descriptor.offset + 2 + j] = bytesArray[j];
|
|
547
|
+
}
|
|
468
548
|
|
|
469
|
-
|
|
470
|
-
|
|
549
|
+
break;
|
|
550
|
+
}
|
|
471
551
|
|
|
472
|
-
|
|
552
|
+
/***
|
|
473
553
|
case sqlTypes.SQL_SHORT:
|
|
474
554
|
dataView.setInt16(descriptor.offset, changeScale(value, 0, descriptor.scale), littleEndian);
|
|
475
555
|
break;
|
|
@@ -485,112 +565,136 @@ export function createDataWriter(descriptors: Descriptor[]): DataWriter {
|
|
|
485
565
|
break;
|
|
486
566
|
***/
|
|
487
567
|
|
|
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
|
-
|
|
568
|
+
case sqlTypes.SQL_DOUBLE:
|
|
569
|
+
dataView.setFloat64(descriptor.offset, value, littleEndian);
|
|
570
|
+
break;
|
|
571
|
+
|
|
572
|
+
case sqlTypes.SQL_TYPE_TIME: {
|
|
573
|
+
const date = value as Date;
|
|
574
|
+
dataView.setUint32(
|
|
575
|
+
descriptor.offset,
|
|
576
|
+
encodeTime(date.getHours(), date.getMinutes(), date.getSeconds(), date.getMilliseconds() * 10),
|
|
577
|
+
littleEndian,
|
|
578
|
+
);
|
|
579
|
+
break;
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
case sqlTypes.SQL_TIME_TZ:
|
|
583
|
+
case sqlTypes.SQL_TIME_TZ_EX: {
|
|
584
|
+
const zonedDate = value as ZonedDate;
|
|
585
|
+
dataView.setUint32(
|
|
586
|
+
descriptor.offset,
|
|
587
|
+
encodeTime(
|
|
588
|
+
zonedDate.date.getUTCHours(),
|
|
589
|
+
zonedDate.date.getUTCMinutes(),
|
|
590
|
+
zonedDate.date.getUTCSeconds(),
|
|
591
|
+
zonedDate.date.getUTCMilliseconds() * 10,
|
|
592
|
+
),
|
|
593
|
+
littleEndian,
|
|
594
|
+
);
|
|
595
|
+
dataView.setUint16(descriptor.offset + 4, tzStringToId(zonedDate.timeZone), littleEndian);
|
|
596
|
+
break;
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
case sqlTypes.SQL_TYPE_DATE: {
|
|
600
|
+
const date = value as Date;
|
|
601
|
+
dataView.setInt32(
|
|
602
|
+
descriptor.offset,
|
|
603
|
+
encodeDate(date.getFullYear(), date.getMonth() + 1, date.getDate()),
|
|
604
|
+
littleEndian,
|
|
605
|
+
);
|
|
606
|
+
break;
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
case sqlTypes.SQL_TIMESTAMP: {
|
|
610
|
+
const date = value as Date;
|
|
611
|
+
dataView.setInt32(
|
|
612
|
+
descriptor.offset,
|
|
613
|
+
encodeDate(date.getFullYear(), date.getMonth() + 1, date.getDate()),
|
|
614
|
+
littleEndian,
|
|
615
|
+
);
|
|
616
|
+
dataView.setUint32(
|
|
617
|
+
descriptor.offset + 4,
|
|
618
|
+
encodeTime(date.getHours(), date.getMinutes(), date.getSeconds(), date.getMilliseconds() * 10),
|
|
619
|
+
littleEndian,
|
|
620
|
+
);
|
|
621
|
+
break;
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
case sqlTypes.SQL_TIMESTAMP_TZ:
|
|
625
|
+
case sqlTypes.SQL_TIMESTAMP_TZ_EX: {
|
|
626
|
+
const zonedDate = value as ZonedDate;
|
|
627
|
+
dataView.setInt32(
|
|
628
|
+
descriptor.offset,
|
|
629
|
+
encodeDate(zonedDate.date.getUTCFullYear(), zonedDate.date.getUTCMonth() + 1, zonedDate.date.getUTCDate()),
|
|
630
|
+
littleEndian,
|
|
631
|
+
);
|
|
632
|
+
dataView.setUint32(
|
|
633
|
+
descriptor.offset + 4,
|
|
634
|
+
encodeTime(
|
|
635
|
+
zonedDate.date.getUTCHours(),
|
|
636
|
+
zonedDate.date.getUTCMinutes(),
|
|
637
|
+
zonedDate.date.getUTCSeconds(),
|
|
638
|
+
zonedDate.date.getUTCMilliseconds() * 10,
|
|
639
|
+
),
|
|
640
|
+
littleEndian,
|
|
641
|
+
);
|
|
642
|
+
dataView.setUint16(descriptor.offset + 8, tzStringToId(zonedDate.timeZone), littleEndian);
|
|
643
|
+
break;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
case sqlTypes.SQL_BOOLEAN:
|
|
647
|
+
dataView.setInt8(descriptor.offset, value ? 1 : 0);
|
|
648
|
+
break;
|
|
649
|
+
|
|
650
|
+
case sqlTypes.SQL_BLOB: {
|
|
651
|
+
const targetBlobId = buffer.subarray(descriptor.offset, descriptor.offset + 8);
|
|
652
|
+
|
|
653
|
+
if (value instanceof BlobStream) {
|
|
654
|
+
value = value.blob;
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
if (value instanceof Buffer) {
|
|
658
|
+
const blobStream = await attachment.createBlob(transaction);
|
|
659
|
+
try {
|
|
660
|
+
await blobStream.write(value);
|
|
661
|
+
} catch (e) {
|
|
662
|
+
await blobStream.cancel();
|
|
663
|
+
throw e;
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
await blobStream.close();
|
|
667
|
+
|
|
668
|
+
targetBlobId.set(blobStream.blob.id);
|
|
669
|
+
} else if (value instanceof Blob) {
|
|
670
|
+
if (value.attachment == attachment) {
|
|
671
|
+
targetBlobId.set(value.id);
|
|
672
|
+
} else {
|
|
673
|
+
throw new Error('Cannot pass a BLOB from another attachment as parameter.');
|
|
674
|
+
} //// TODO: add support for it
|
|
675
|
+
} else {
|
|
676
|
+
throw new Error('Unrecognized type used as BLOB. Must be: Buffer or Blob.');
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
break;
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
case sqlTypes.SQL_NULL:
|
|
683
|
+
break;
|
|
684
|
+
|
|
685
|
+
default:
|
|
686
|
+
throw new Error(`Unrecognized Firebird type number ${descriptor.type}`);
|
|
687
|
+
}
|
|
688
|
+
};
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
return async (attachment: Attachment, transaction: Transaction, buffer: Uint8Array, values: any[]): Promise<void> => {
|
|
692
|
+
if ((values || []).length !== descriptors.length) {
|
|
693
|
+
throw new Error(
|
|
694
|
+
`Incorrect number of parameters: expected ${descriptors.length}, received ${(values || []).length}.`,
|
|
695
|
+
);
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
await Promise.all(mappers.map((mapper, index) => mapper(attachment, transaction, buffer, values[index])));
|
|
699
|
+
};
|
|
596
700
|
}
|