node-firebird-driver 3.2.2 → 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.
Files changed (41) hide show
  1. package/README.md +1 -1
  2. package/dist/lib/impl/attachment.d.ts +4 -4
  3. package/dist/lib/impl/attachment.js +8 -6
  4. package/dist/lib/impl/attachment.js.map +1 -1
  5. package/dist/lib/impl/blob.js.map +1 -1
  6. package/dist/lib/impl/client.js +3 -2
  7. package/dist/lib/impl/client.js.map +1 -1
  8. package/dist/lib/impl/date-time.js +2 -1
  9. package/dist/lib/impl/date-time.js.map +1 -1
  10. package/dist/lib/impl/events.js +2 -1
  11. package/dist/lib/impl/events.js.map +1 -1
  12. package/dist/lib/impl/fb-util.d.ts +2 -1
  13. package/dist/lib/impl/fb-util.js +100 -81
  14. package/dist/lib/impl/fb-util.js.map +1 -1
  15. package/dist/lib/impl/resultset.js +11 -5
  16. package/dist/lib/impl/resultset.js.map +1 -1
  17. package/dist/lib/impl/statement.js +4 -2
  18. package/dist/lib/impl/statement.js.map +1 -1
  19. package/dist/lib/impl/time-zones.js +5 -3
  20. package/dist/lib/impl/time-zones.js.map +1 -1
  21. package/dist/lib/impl/transaction.js +2 -1
  22. package/dist/lib/impl/transaction.js.map +1 -1
  23. package/dist/lib/index.d.ts +8 -1
  24. package/dist/lib/index.js +7 -1
  25. package/dist/lib/index.js.map +1 -1
  26. package/dist/test/tests.js +176 -68
  27. package/dist/test/tests.js.map +1 -1
  28. package/package.json +6 -5
  29. package/src/lib/impl/attachment.ts +290 -253
  30. package/src/lib/impl/blob.ts +37 -35
  31. package/src/lib/impl/client.ts +60 -61
  32. package/src/lib/impl/date-time.ts +33 -33
  33. package/src/lib/impl/events.ts +17 -18
  34. package/src/lib/impl/fb-util.ts +552 -448
  35. package/src/lib/impl/resultset.ts +94 -86
  36. package/src/lib/impl/statement.ts +154 -127
  37. package/src/lib/impl/time-zones.ts +643 -641
  38. package/src/lib/impl/transaction.ts +37 -38
  39. package/src/lib/index.ts +325 -285
  40. package/src/test/tests.ts +996 -860
  41. package/tsconfig.json +7 -13
@@ -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
- Attachment,
13
- Blob,
14
- BlobStream,
15
- ConnectOptions,
16
- CreateBlobOptions,
17
- CreateDatabaseOptions,
18
- Transaction,
19
- TransactionIsolation,
20
- TransactionOptions,
21
- ZonedDate,
22
- ZonedDateEx
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
- 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;
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
- /* tslint:disable */
56
- export const version1 = 1;
57
- export const lc_ctype = 48;
58
- export const force_write = 24;
59
- export const user_name = 28;
60
- export const password = 29;
61
- export const sql_role_name = 60;
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
- /* tslint:disable */
68
- export const version1 = 1;
69
- export const consistency = 1;
70
- export const concurrency = 2;
71
- export const wait = 6;
72
- export const nowait = 7;
73
- export const read = 8;
74
- export const write = 9;
75
- export const ignore_limbo = 14;
76
- export const read_committed = 15;
77
- export const autocommit = 16;
78
- export const rec_version = 17;
79
- export const no_rec_version = 18;
80
- export const restart_requests = 19;
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
- /* tslint:disable */
88
- export const version1 = 1;
89
- export const source_type = 1;
90
- export const target_type = 2;
91
- export const type = 3;
92
- export const source_interp = 4;
93
- export const target_interp = 5;
94
- export const filter_parameter = 6;
95
- export const storage = 7;
96
-
97
- export const type_segmented = 0x0;
98
- export const type_stream = 0x1;
99
- export const storage_main = 0x0;
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
- /* tslint:disable */
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
- export const totalLength = 6;
106
+ export const totalLength = 6;
114
107
  }
115
108
 
116
109
  /** Statement info. */
117
110
  export namespace statementInfo {
118
- export const sqlExecPathBlrText = 32;
111
+ export const sqlExecPathBlrText = 32;
119
112
  }
120
113
 
121
114
  /** Common info. */
122
115
  export namespace commonInfo {
123
- export const end = 1;
124
- export const truncated = 2;
125
- export const error = 3;
126
- export const dataNotReady = 4;
127
- export const length = 126;
128
- export const flagEnd = 127;
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
- export const disable = 1;
133
- export const enable = 2;
134
- export const raise = 3;
135
- export const abort = 4;
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
- export const ascii = 2;
132
+ export const ascii = 2;
140
133
  }
141
134
 
142
135
  export function createDpb(options?: ConnectOptions | CreateDatabaseOptions): Buffer {
143
- const code = (c: number) => String.fromCharCode(c);
144
- const charSet = 'utf8';
145
- let ret = `${code(dpb.version1)}${code(dpb.lc_ctype)}${code(charSet.length)}${charSet}`;
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
- if (!options)
148
- options = {};
140
+ if (!options) {
141
+ options = {};
142
+ }
149
143
 
150
- if (!options.username)
151
- options.username = process.env.ISC_USER;
144
+ if (!options.username) {
145
+ options.username = process.env.ISC_USER;
146
+ }
152
147
 
153
- if (!options.password)
154
- options.password = process.env.ISC_PASSWORD;
148
+ if (!options.password) {
149
+ options.password = process.env.ISC_PASSWORD;
150
+ }
155
151
 
156
- if (options.username)
157
- ret += `${code(dpb.user_name)}${code(options.username.length)}${options.username}`;
152
+ if (options.username) {
153
+ ret += `${code(dpb.user_name)}${code(options.username.length)}${options.username}`;
154
+ }
158
155
 
159
- if (options.password)
160
- ret += `${code(dpb.password)}${code(options.password.length)}${options.password}`;
156
+ if (options.password) {
157
+ ret += `${code(dpb.password)}${code(options.password.length)}${options.password}`;
158
+ }
161
159
 
162
- if (options.role)
163
- ret += `${code(dpb.sql_role_name)}${code(options.role.length)}${options.role}`;
160
+ if (options.role) {
161
+ ret += `${code(dpb.sql_role_name)}${code(options.role.length)}${options.role}`;
162
+ }
164
163
 
165
- const createOptions = options as CreateDatabaseOptions;
164
+ const createOptions = options as CreateDatabaseOptions;
166
165
 
167
- if (createOptions.forcedWrite != undefined)
168
- ret += `${code(dpb.force_write)}${code(1)}${code(createOptions.forcedWrite ? 1 : 0)}`;
166
+ if (createOptions.forcedWrite != undefined) {
167
+ ret += `${code(dpb.force_write)}${code(1)}${code(createOptions.forcedWrite ? 1 : 0)}`;
168
+ }
169
169
 
170
- return Buffer.from(ret);
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
- const code = (c: number) => String.fromCharCode(c);
175
- let ret = code(tpb.version1);
176
-
177
- if (!options)
178
- options = {};
179
-
180
- switch (options.accessMode) {
181
- case 'READ_ONLY':
182
- ret += code(tpb.read);
183
- break;
184
-
185
- case 'READ_WRITE':
186
- ret += code(tpb.write);
187
- break;
188
- }
189
-
190
- switch (options.waitMode) {
191
- case 'NO_WAIT':
192
- ret += code(tpb.nowait);
193
- break;
194
-
195
- case 'WAIT':
196
- ret += code(tpb.wait);
197
- break;
198
- }
199
-
200
- switch (options.isolation) {
201
- case TransactionIsolation.CONSISTENCY:
202
- ret += code(tpb.consistency);
203
- break;
204
-
205
- case TransactionIsolation.SNAPSHOT:
206
- ret += code(tpb.concurrency);
207
- break;
208
-
209
- case TransactionIsolation.READ_COMMITTED:
210
- ret += code(tpb.read_committed) +
211
- code(options.readCommittedMode == 'RECORD_VERSION' ? tpb.rec_version : tpb.no_rec_version);
212
- break;
213
- }
214
-
215
- if (options.noAutoUndo)
216
- ret += code(tpb.no_auto_undo);
217
-
218
- if (options.ignoreLimbo)
219
- ret += code(tpb.ignore_limbo);
220
-
221
- if (options.restartRequests)
222
- ret += code(tpb.restart_requests);
223
-
224
- if (options.autoCommit)
225
- ret += code(tpb.autocommit);
226
-
227
- return Buffer.from(ret);
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
- const code = (c: number) => String.fromCharCode(c);
232
- let ret = code(bpb.version1);
243
+ const code = (c: number) => String.fromCharCode(c);
244
+ let ret = code(bpb.version1);
233
245
 
234
- if (!options)
235
- options = {};
246
+ if (!options) {
247
+ options = {};
248
+ }
236
249
 
237
- switch (options.type) {
238
- case 'SEGMENTED':
239
- ret += `${code(bpb.type)}${code(1)}${code(bpb.type_segmented)}`;
240
- break;
250
+ switch (options.type) {
251
+ case 'SEGMENTED':
252
+ ret += `${code(bpb.type)}${code(1)}${code(bpb.type_segmented)}`;
253
+ break;
241
254
 
242
- case 'STREAM':
243
- ret += `${code(bpb.type)}${code(1)}${code(bpb.type_stream)}`;
244
- break;
245
- }
255
+ case 'STREAM':
256
+ ret += `${code(bpb.type)}${code(1)}${code(bpb.type_stream)}`;
257
+ break;
258
+ }
246
259
 
247
- return Buffer.from(ret);
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
- if (!buffer || length <= 0 || length > 8)
269
- return 0;
281
+ if (!buffer || length <= 0 || length > 8) {
282
+ return 0;
283
+ }
270
284
 
271
- let value = 0;
272
- let pos = 0;
285
+ let value = 0;
286
+ let pos = 0;
273
287
 
274
- for (let shift = 0; --length >= 0; shift += 8)
275
- value += buffer[pos++] << shift;
288
+ for (let shift = 0; --length >= 0; shift += 8) {
289
+ value += buffer[pos++] << shift;
290
+ }
276
291
 
277
- return value;
292
+ return value;
278
293
  }
279
294
 
280
-
281
295
  /** Descriptor for a field or parameter. */
282
296
  export interface Descriptor {
283
- type: number;
284
- subType: number;
285
- length: number;
286
- scale: number;
287
- offset: number;
288
- nullOffset: number;
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
- const mappers = new Array<ItemReader>(descriptors.length);
298
-
299
- for (let i = 0; i < descriptors.length; ++i) {
300
- const descriptor = descriptors[i];
301
-
302
- mappers[i] = async (attachment: AbstractAttachment, transaction: AbstractTransaction, buffer: Uint8Array): Promise<any> => {
303
- const dataView = new DataView(buffer.buffer);
304
-
305
- if (dataView.getInt16(descriptor.nullOffset, littleEndian) == -1)
306
- return null;
307
-
308
- switch (descriptor.type) {
309
- // SQL_TEXT is handled changing its descriptor to SQL_VARYING with IMetadataBuilder.
310
- case sqlTypes.SQL_VARYING: {
311
- //// TODO: none, octets
312
- const varLength = dataView.getUint16(descriptor.offset, littleEndian);
313
- const decoder = new stringDecoder.StringDecoder('utf8');
314
- const buf = Buffer.from(buffer.buffer, descriptor.offset + 2, varLength);
315
- return decoder.end(buf);
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
- case sqlTypes.SQL_DOUBLE:
332
- return dataView.getFloat64(descriptor.offset, littleEndian);
333
-
334
- case sqlTypes.SQL_TYPE_TIME: {
335
- const now = new Date();
336
- const decodedTime = decodeTime(dataView.getUint32(descriptor.offset, littleEndian));
337
- return new Date(now.getFullYear(), now.getMonth(), now.getDate(),
338
- decodedTime.hours, decodedTime.minutes, decodedTime.seconds, decodedTime.fractions / 10);
339
- }
340
-
341
- case sqlTypes.SQL_TIME_TZ_EX: {
342
- const now = new Date();
343
- const decodedTime = decodeTime(dataView.getUint32(descriptor.offset, littleEndian));
344
- const date = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate(),
345
- decodedTime.hours, decodedTime.minutes, decodedTime.seconds, decodedTime.fractions / 10));
346
- const timeZone = tzIdToString(dataView.getUint16(descriptor.offset + 4, littleEndian));
347
- const offset = dataView.getInt16(descriptor.offset + 6, littleEndian);
348
-
349
- return {
350
- date,
351
- timeZone,
352
- offset
353
- } as ZonedDateEx;
354
- }
355
-
356
- case sqlTypes.SQL_TYPE_DATE: {
357
- const decodedDate = decodeDate(dataView.getInt32(descriptor.offset, littleEndian));
358
-
359
- if (decodedDate.year >= 100)
360
- return new Date(decodedDate.year, decodedDate.month - 1, decodedDate.day);
361
- else {
362
- const date = new Date(2000, decodedDate.month - 1, decodedDate.day);
363
- date.setFullYear(decodedDate.year);
364
- return date;
365
- }
366
- }
367
-
368
- case sqlTypes.SQL_TIMESTAMP: {
369
- const decodedDate = decodeDate(dataView.getInt32(descriptor.offset, littleEndian));
370
- const decodedTime = decodeTime(dataView.getUint32(descriptor.offset + 4, littleEndian));
371
-
372
- if (decodedDate.year >= 100) {
373
- return new Date(decodedDate.year, decodedDate.month - 1, decodedDate.day,
374
- decodedTime.hours, decodedTime.minutes, decodedTime.seconds, decodedTime.fractions / 10);
375
- }
376
- else {
377
- const date = new Date(2000, decodedDate.month - 1, decodedDate.day,
378
- decodedTime.hours, decodedTime.minutes, decodedTime.seconds, decodedTime.fractions / 10);
379
- date.setFullYear(decodedDate.year);
380
- return date;
381
- }
382
- }
383
-
384
- case sqlTypes.SQL_TIMESTAMP_TZ_EX: {
385
- const decodedDate = decodeDate(dataView.getInt32(descriptor.offset, littleEndian));
386
- const decodedTime = decodeTime(dataView.getUint32(descriptor.offset + 4, littleEndian));
387
- const timeZone = tzIdToString(dataView.getUint16(descriptor.offset + 8, littleEndian));
388
- const offset = dataView.getInt16(descriptor.offset + 10, littleEndian);
389
- let date: Date;
390
-
391
- if (decodedDate.year >= 100) {
392
- date = new Date(Date.UTC(decodedDate.year, decodedDate.month - 1, decodedDate.day,
393
- decodedTime.hours, decodedTime.minutes, decodedTime.seconds, decodedTime.fractions / 10));
394
- }
395
- else {
396
- date = new Date(Date.UTC(2000, decodedDate.month - 1, decodedDate.day,
397
- decodedTime.hours, decodedTime.minutes, decodedTime.seconds, decodedTime.fractions / 10));
398
- date.setUTCFullYear(decodedDate.year);
399
- }
400
-
401
- return {
402
- date,
403
- timeZone,
404
- offset
405
- } as ZonedDateEx;
406
- }
407
-
408
- case sqlTypes.SQL_BOOLEAN:
409
- return dataView.getInt8(descriptor.offset) != 0;
410
-
411
- case sqlTypes.SQL_BLOB:
412
- return new Blob(attachment, buffer.slice(descriptor.offset, descriptor.offset + 8));
413
-
414
- case sqlTypes.SQL_NULL:
415
- return null;
416
-
417
- default:
418
- throw new Error(`Unrecognized Firebird type number ${descriptor.type}`);
419
- }
420
- };
421
- }
422
-
423
- return async (attachment: Attachment, transaction: Transaction, buffer: Uint8Array): Promise<any[]> => {
424
- return await Promise.all(mappers.map(mapper => mapper(attachment, transaction, buffer)));
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
- export type DataWriter = (attachment: Attachment, transaction: Transaction,
430
- buffer: Uint8Array, values: Array<any> | undefined) => Promise<void>;
431
- export type ItemWriter = (attachment: Attachment, transaction: Transaction, buffer: Uint8Array, values: any) => Promise<void>;
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
- const mappers = new Array<ItemWriter>(descriptors.length);
507
+ const mappers = new Array<ItemWriter>(descriptors.length);
436
508
 
437
- for (let i = 0; i < descriptors.length; ++i) {
438
- const descriptor = descriptors[i];
509
+ for (let i = 0; i < descriptors.length; ++i) {
510
+ const descriptor = descriptors[i];
439
511
 
440
- mappers[i] = async (attachment: Attachment, transaction: Transaction, buffer: Uint8Array, value: any): Promise<void> => {
441
- const dataView = new DataView(buffer.buffer);
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
- if (value == null) {
444
- dataView.setInt16(descriptor.nullOffset, -1, littleEndian);
445
- return;
446
- }
520
+ if (value == null) {
521
+ dataView.setInt16(descriptor.nullOffset, -1, littleEndian);
522
+ return;
523
+ }
447
524
 
448
- dataView.setInt16(descriptor.nullOffset, 0, littleEndian);
525
+ dataView.setInt16(descriptor.nullOffset, 0, littleEndian);
449
526
 
450
- switch (descriptor.type) {
451
- // SQL_TEXT is handled changing its descriptor to SQL_VARYING with IMetadataBuilder.
452
- case sqlTypes.SQL_VARYING: {
453
- //// TODO: none, octets
454
- const str = value as string;
455
- const strBuffer = Buffer.from(str);
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
- const bytesArray = Uint8Array.from(strBuffer);
534
+ const bytesArray = Uint8Array.from(strBuffer);
458
535
 
459
- if (bytesArray.length > descriptor.length) {
460
- throw new Error(`Length in bytes of string '${str}' (${bytesArray.length}) is ` +
461
- `greater than maximum expect length ${descriptor.length}.`);
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
- dataView.setUint16(descriptor.offset, bytesArray.length, littleEndian);
543
+ dataView.setUint16(descriptor.offset, bytesArray.length, littleEndian);
465
544
 
466
- for (let j = 0; j < bytesArray.length; ++j)
467
- buffer[descriptor.offset + 2 + j] = bytesArray[j];
545
+ for (let j = 0; j < bytesArray.length; ++j) {
546
+ buffer[descriptor.offset + 2 + j] = bytesArray[j];
547
+ }
468
548
 
469
- break;
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
- case sqlTypes.SQL_DOUBLE:
489
- dataView.setFloat64(descriptor.offset, value, littleEndian);
490
- break;
491
-
492
- case sqlTypes.SQL_TYPE_TIME: {
493
- const date = value as Date;
494
- dataView.setUint32(descriptor.offset,
495
- encodeTime(date.getHours(), date.getMinutes(), date.getSeconds(), date.getMilliseconds() * 10),
496
- littleEndian);
497
- break;
498
- }
499
-
500
- case sqlTypes.SQL_TIME_TZ:
501
- case sqlTypes.SQL_TIME_TZ_EX: {
502
- const zonedDate = value as ZonedDate;
503
- dataView.setUint32(descriptor.offset,
504
- encodeTime(zonedDate.date.getUTCHours(), zonedDate.date.getUTCMinutes(), zonedDate.date.getUTCSeconds(),
505
- zonedDate.date.getUTCMilliseconds() * 10),
506
- littleEndian);
507
- dataView.setUint16(descriptor.offset + 4, tzStringToId(zonedDate.timeZone), littleEndian);
508
- break;
509
- }
510
-
511
- case sqlTypes.SQL_TYPE_DATE: {
512
- const date = value as Date;
513
- dataView.setInt32(descriptor.offset,
514
- encodeDate(date.getFullYear(), date.getMonth() + 1, date.getDate()),
515
- littleEndian);
516
- break;
517
- }
518
-
519
- case sqlTypes.SQL_TIMESTAMP: {
520
- const date = value as Date;
521
- dataView.setInt32(descriptor.offset,
522
- encodeDate(date.getFullYear(), date.getMonth() + 1, date.getDate()),
523
- littleEndian);
524
- dataView.setUint32(descriptor.offset + 4,
525
- encodeTime(date.getHours(), date.getMinutes(), date.getSeconds(), date.getMilliseconds() * 10),
526
- littleEndian);
527
- break;
528
- }
529
-
530
- case sqlTypes.SQL_TIMESTAMP_TZ:
531
- case sqlTypes.SQL_TIMESTAMP_TZ_EX: {
532
- const zonedDate = value as ZonedDate;
533
- dataView.setInt32(descriptor.offset,
534
- encodeDate(zonedDate.date.getUTCFullYear(), zonedDate.date.getUTCMonth() + 1, zonedDate.date.getUTCDate()),
535
- littleEndian);
536
- dataView.setUint32(descriptor.offset + 4,
537
- encodeTime(zonedDate.date.getUTCHours(), zonedDate.date.getUTCMinutes(), zonedDate.date.getUTCSeconds(),
538
- zonedDate.date.getUTCMilliseconds() * 10),
539
- littleEndian);
540
- dataView.setUint16(descriptor.offset + 8, tzStringToId(zonedDate.timeZone), littleEndian);
541
- break;
542
- }
543
-
544
- case sqlTypes.SQL_BOOLEAN:
545
- dataView.setInt8(descriptor.offset, value ? 1 : 0);
546
- break;
547
-
548
- case sqlTypes.SQL_BLOB:
549
- {
550
- const targetBlobId = buffer.subarray(descriptor.offset, descriptor.offset + 8);
551
-
552
- if (value instanceof BlobStream)
553
- value = value.blob;
554
-
555
- if (value instanceof Buffer) {
556
- const blobStream = await attachment.createBlob(transaction);
557
- try {
558
- await blobStream.write(value);
559
- }
560
- catch (e) {
561
- await blobStream.cancel();
562
- throw e;
563
- }
564
-
565
- await blobStream.close();
566
-
567
- targetBlobId.set(blobStream.blob.id);
568
- }
569
- else if (value instanceof Blob) {
570
- if (value.attachment == attachment)
571
- targetBlobId.set(value.id);
572
- else
573
- throw new Error('Cannot pass a BLOB from another attachment as parameter.'); //// TODO: add support for it
574
- }
575
- else
576
- throw new Error('Unrecognized type used as BLOB. Must be: Buffer or Blob.');
577
-
578
- break;
579
- }
580
-
581
- case sqlTypes.SQL_NULL:
582
- break;
583
-
584
- default:
585
- throw new Error(`Unrecognized Firebird type number ${descriptor.type}`);
586
- }
587
- };
588
- }
589
-
590
- return async (attachment: Attachment, transaction: Transaction, buffer: Uint8Array, values: Array<any>): Promise<void> => {
591
- if ((values || []).length !== descriptors.length)
592
- throw new Error(`Incorrect number of parameters: expected ${descriptors.length}, received ${(values || []).length}.`);
593
-
594
- await Promise.all(mappers.map((mapper, index) => mapper(attachment, transaction, buffer, values[index])));
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
  }