node-firebird 2.11.0 → 2.13.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.
@@ -1,4 +1,47 @@
1
+ import type { TextCodec } from './codepages';
1
2
  import type { XdrReader, XdrWriter, BlrWriter } from './serialize';
3
+ import type { RecordCounts } from '../types';
4
+ export declare function getFirebirdCharsetWidth(charset?: string): number;
5
+ /**
6
+ * Resolve the Node.js Buffer encoding to use when decoding text from a
7
+ * Firebird response buffer.
8
+ *
9
+ * @param {object|null} options Connection options object (may be falsy).
10
+ * @returns {string} A Node.js-compatible encoding string.
11
+ */
12
+ export declare function resolveTextEncoding(options?: any): BufferEncoding;
13
+ /**
14
+ * Codec for the CONNECTION charset when it is a codepage Node cannot
15
+ * handle natively (WIN1251, ISO8859_7, KOI8R, …); null on the native
16
+ * path (UTF8/latin1/ascii) and for unknown charsets. With a codec
17
+ * connection charset the server transliterates all text to that
18
+ * codepage, so every text column, parameter, SQL string and text blob
19
+ * goes through the codec (issues #319/#301).
20
+ */
21
+ export declare function resolveTextCodec(options?: any): TextCodec | null;
22
+ interface TextState {
23
+ key: string | undefined;
24
+ codec: TextCodec | null;
25
+ enc: BufferEncoding;
26
+ width: number;
27
+ }
28
+ /**
29
+ * Per-connection text handling, resolved once and memoized on the
30
+ * long-lived options object: the decode loop calls this per CELL, and
31
+ * recomputing uppercased names + map lookups a million times per large
32
+ * fetch is pure waste. Invalidated if options.encoding ever changes.
33
+ */
34
+ export declare function resolveTextState(options?: any): TextState;
35
+ /**
36
+ * Encode text in the CONNECTION charset — the byte form the server
37
+ * expects for parameters, SQL statement text and text-blob content.
38
+ */
39
+ export declare function encodeConnectionText(options: any, value: string): Buffer;
40
+ /**
41
+ * Decode connection-charset bytes to text (the read counterpart of
42
+ * encodeConnectionText — used for text blobs).
43
+ */
44
+ export declare function decodeConnectionText(options: any, buffer: Buffer): string;
2
45
  /**
3
46
  * Common shape of all SQLVar descriptor objects. The metadata properties
4
47
  * are populated externally (in connection.ts) from the op_prepare_statement
@@ -18,6 +61,9 @@ export declare abstract class SQLVarBase {
18
61
  owner?: string;
19
62
  charSetId?: number;
20
63
  collationId?: number;
64
+ /** Original declared byte length when scaleOutputLengths widened
65
+ * `length` for the fetch capacity check (issue #422). */
66
+ nativeLength?: number;
21
67
  abstract decode(data: XdrReader, lowerV13: boolean, options?: any): any;
22
68
  abstract calcBlr(blr: BlrWriter): void;
23
69
  }
@@ -41,7 +87,23 @@ export interface ColumnKey {
41
87
  * decoder and by fetchBlobSyncRow, which must agree on where each column
42
88
  * landed in the row.
43
89
  */
44
- export declare function computeColumnKeys(output: SQLVarBase[], nestTables: boolean | string | undefined, lowercaseKeys: boolean | undefined): ColumnKey[];
90
+ export declare function computeColumnKeys(output: SQLVarBase[], nestTables: boolean | string | undefined, lowercaseKeys: boolean | undefined, transform?: (key: string) => string): ColumnKey[];
91
+ /** transformKeys option value: the built-in 'camel', or a custom mapper. */
92
+ export type KeyTransform = 'camel' | ((key: string) => string);
93
+ /** FIRST_NAME → firstName (the transformKeys: 'camel' built-in). */
94
+ export declare function camelizeKey(key: string): string;
95
+ /**
96
+ * Resolve the effective transformKeys value (per-query wins over the
97
+ * connection option) into a callable mapper, or undefined when off.
98
+ * A custom mapper is guarded like the typeCast hook: a throw inside the
99
+ * row-decode loop would be mistaken for an incomplete packet and desync
100
+ * the response queue, so failures fall back to the untransformed key.
101
+ */
102
+ export declare function resolveKeyTransform(queryOptions: {
103
+ transformKeys?: KeyTransform;
104
+ } | undefined, connectionOptions: {
105
+ transformKeys?: KeyTransform;
106
+ } | undefined): ((key: string) => string) | undefined;
45
107
  /**
46
108
  * Resolve the effective nestTables value: the per-query option wins over
47
109
  * the connection option. The decoder and fetchBlobSyncRow both use this —
@@ -60,6 +122,50 @@ export declare function resolveNestTables(queryOptions: {
60
122
  * cell by ColumnKey must resolve it through here.
61
123
  */
62
124
  export declare function nestCell(row: any, table: string | undefined): any;
125
+ /** Human-readable names for the SQL_* wire type codes. */
126
+ export declare const SQL_TYPE_NAMES: Record<number, string>;
127
+ /**
128
+ * Public column-metadata shape for one output descriptor: the vocabulary
129
+ * both the typeCast hook and withMeta `fields` deliver. Keep the two in
130
+ * lockstep by building both through here.
131
+ */
132
+ export declare function describeField(meta: Partial<SQLVarBase>): {
133
+ type: number;
134
+ typeName: string;
135
+ subType: number | undefined;
136
+ scale: number | undefined;
137
+ length: number | undefined;
138
+ nullable: boolean | undefined;
139
+ field: string | undefined;
140
+ relation: string | undefined;
141
+ relationAlias: string | undefined;
142
+ relationSchema: string | undefined;
143
+ alias: string | undefined;
144
+ };
145
+ /**
146
+ * Map a statement's output descriptors to the column-metadata array
147
+ * delivered in withMeta results ({ rows, fields, ... }).
148
+ */
149
+ export declare function describeFields(output: SQLVarBase[]): {
150
+ type: number;
151
+ typeName: string;
152
+ subType: number | undefined;
153
+ scale: number | undefined;
154
+ length: number | undefined;
155
+ nullable: boolean | undefined;
156
+ field: string | undefined;
157
+ relation: string | undefined;
158
+ relationAlias: string | undefined;
159
+ relationSchema: string | undefined;
160
+ alias: string | undefined;
161
+ }[];
162
+ /**
163
+ * Parse the op_info_sql response buffer of a Const.RECORDS_INFO request
164
+ * into per-verb row counts. The buffer holds an isc_info_sql_records
165
+ * cluster (2-byte total length, then nested isc_info_req_*_count items,
166
+ * each 2-byte length + little-endian integer) terminated by isc_info_end.
167
+ */
168
+ export declare function parseRecordCounts(buffer: Buffer | undefined): RecordCounts;
63
169
  export declare class SQLVarText extends SQLVarBase {
64
170
  decode(data: XdrReader, lowerV13: boolean, options?: any): string | Buffer<ArrayBufferLike> | null | undefined;
65
171
  calcBlr(blr: BlrWriter): void;
@@ -217,7 +323,17 @@ export declare class SQLParamDate {
217
323
  }
218
324
  export declare class SQLParamBool {
219
325
  value: any;
220
- constructor(value: any);
326
+ /**
327
+ * Encode as a real BOOLEAN (blr_bool + xdr opaque byte) instead of the
328
+ * legacy blr_short 0/1. Set when the DESCRIBED parameter type is
329
+ * SQL_BOOLEAN: Firebird refuses smallint→BOOLEAN conversion
330
+ * ("conversion error from string", issue #122), and conversely BOOLEAN
331
+ * does not convert to numbers — so smallint targets keep the legacy
332
+ * form for compatibility.
333
+ */
334
+ asBoolean: boolean;
335
+ constructor(value: any, asBoolean?: boolean);
221
336
  encode(data: XdrWriter): void;
222
337
  calcBlr(blr: BlrWriter): void;
223
338
  }
339
+ export {};
@@ -3,12 +3,25 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.SQLParamBool = exports.SQLParamDate = exports.SQLParamQuad = exports.SQLParamBuffer = exports.SQLParamString = exports.SQLParamDouble = exports.SQLParamDecFloat34 = exports.SQLParamDecFloat16 = exports.SQLParamInt128 = exports.SQLParamInt64 = exports.SQLParamInt = exports.SQLVarBoolean = exports.SQLVarTimeStampTzEx = exports.SQLVarTimeStampTz = exports.SQLVarTimeTzEx = exports.SQLVarTimeTz = exports.SQLVarTimeStamp = exports.SQLVarTime = exports.SQLVarDate = exports.SQLVarDouble = exports.SQLVarFloat = exports.SQLVarDecFloat34 = exports.SQLVarDecFloat16 = exports.SQLVarInt128 = exports.SQLVarInt64 = exports.SQLVarShort = exports.SQLVarInt = exports.SQLVarArray = exports.SQLVarBlob = exports.SQLVarQuad = exports.SQLVarString = exports.SQLVarNull = exports.SQLVarText = exports.SQLVarBase = void 0;
6
+ exports.SQLParamBool = exports.SQLParamDate = exports.SQLParamQuad = exports.SQLParamBuffer = exports.SQLParamString = exports.SQLParamDouble = exports.SQLParamDecFloat34 = exports.SQLParamDecFloat16 = exports.SQLParamInt128 = exports.SQLParamInt64 = exports.SQLParamInt = exports.SQLVarBoolean = exports.SQLVarTimeStampTzEx = exports.SQLVarTimeStampTz = exports.SQLVarTimeTzEx = exports.SQLVarTimeTz = exports.SQLVarTimeStamp = exports.SQLVarTime = exports.SQLVarDate = exports.SQLVarDouble = exports.SQLVarFloat = exports.SQLVarDecFloat34 = exports.SQLVarDecFloat16 = exports.SQLVarInt128 = exports.SQLVarInt64 = exports.SQLVarShort = exports.SQLVarInt = exports.SQLVarArray = exports.SQLVarBlob = exports.SQLVarQuad = exports.SQLVarString = exports.SQLVarNull = exports.SQLVarText = exports.SQL_TYPE_NAMES = exports.SQLVarBase = void 0;
7
+ exports.getFirebirdCharsetWidth = getFirebirdCharsetWidth;
8
+ exports.resolveTextEncoding = resolveTextEncoding;
9
+ exports.resolveTextCodec = resolveTextCodec;
10
+ exports.resolveTextState = resolveTextState;
11
+ exports.encodeConnectionText = encodeConnectionText;
12
+ exports.decodeConnectionText = decodeConnectionText;
7
13
  exports.computeColumnKeys = computeColumnKeys;
14
+ exports.camelizeKey = camelizeKey;
15
+ exports.resolveKeyTransform = resolveKeyTransform;
8
16
  exports.resolveNestTables = resolveNestTables;
9
17
  exports.nestCell = nestCell;
18
+ exports.describeField = describeField;
19
+ exports.describeFields = describeFields;
20
+ exports.parseRecordCounts = parseRecordCounts;
10
21
  exports.encodeDateTimeParts = encodeDateTimeParts;
11
22
  const const_1 = __importDefault(require("./const"));
23
+ const serialize_1 = require("./serialize");
24
+ const codepages_1 = require("./codepages");
12
25
  /***************************************
13
26
  *
14
27
  * SQLVar
@@ -16,6 +29,7 @@ const const_1 = __importDefault(require("./const"));
16
29
  ***************************************/
17
30
  const ScaleDivisor = [1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, 10000000000, 100000000000, 1000000000000, 10000000000000, 100000000000000, 1000000000000000];
18
31
  const DateOffset = 40587, TimeCoeff = 86400000, MsPerMinute = 60000;
32
+ const EMPTY_BUFFER = Buffer.alloc(0);
19
33
  /**
20
34
  * Maps Firebird character-set names (upper-case) to the Node.js Buffer
21
35
  * encoding string used by Buffer.toString() / Buffer.from().
@@ -40,8 +54,16 @@ const FirebirdToNodeEncoding = Object.freeze({
40
54
  const FirebirdCharsetWidths = {
41
55
  'UTF8': 4,
42
56
  'UNICODE_FSS': 3,
43
- 'SJIS': 2,
44
- 'EUCJ': 2
57
+ // real Firebird names — the bare 'SJIS'/'EUCJ' keys never matched a
58
+ // valid encoding option and silently resolved to width 1
59
+ 'SJIS_0208': 2,
60
+ 'EUCJ_0208': 2,
61
+ 'KSC_5601': 2,
62
+ 'BIG_5': 2,
63
+ 'GB_2312': 2,
64
+ 'GBK': 2,
65
+ 'CP943C': 2,
66
+ 'GB18030': 4,
45
67
  };
46
68
  function getFirebirdCharsetWidth(charset) {
47
69
  if (!charset)
@@ -62,6 +84,67 @@ function resolveTextEncoding(options) {
62
84
  : const_1.default.DEFAULT_ENCODING;
63
85
  return (FirebirdToNodeEncoding[encoding] || const_1.default.DEFAULT_ENCODING.toLowerCase());
64
86
  }
87
+ /**
88
+ * Codec for the CONNECTION charset when it is a codepage Node cannot
89
+ * handle natively (WIN1251, ISO8859_7, KOI8R, …); null on the native
90
+ * path (UTF8/latin1/ascii) and for unknown charsets. With a codec
91
+ * connection charset the server transliterates all text to that
92
+ * codepage, so every text column, parameter, SQL string and text blob
93
+ * goes through the codec (issues #319/#301).
94
+ */
95
+ function resolveTextCodec(options) {
96
+ return resolveTextState(options).codec;
97
+ }
98
+ /**
99
+ * Per-connection text handling, resolved once and memoized on the
100
+ * long-lived options object: the decode loop calls this per CELL, and
101
+ * recomputing uppercased names + map lookups a million times per large
102
+ * fetch is pure waste. Invalidated if options.encoding ever changes.
103
+ */
104
+ function resolveTextState(options) {
105
+ const key = options && options.encoding;
106
+ if (options && options.__textState && options.__textState.key === key) {
107
+ return options.__textState;
108
+ }
109
+ const encoding = (key || const_1.default.DEFAULT_ENCODING).toUpperCase();
110
+ const state = {
111
+ key,
112
+ codec: FirebirdToNodeEncoding[encoding] ? null : (0, codepages_1.getCodec)(encoding),
113
+ enc: (FirebirdToNodeEncoding[encoding] || const_1.default.DEFAULT_ENCODING.toLowerCase()),
114
+ width: getFirebirdCharsetWidth(encoding),
115
+ };
116
+ if (options) {
117
+ options.__textState = state;
118
+ }
119
+ return state;
120
+ }
121
+ /**
122
+ * Encode text in the CONNECTION charset — the byte form the server
123
+ * expects for parameters, SQL statement text and text-blob content.
124
+ */
125
+ function encodeConnectionText(options, value) {
126
+ const state = resolveTextState(options);
127
+ if (state.codec) {
128
+ return state.codec.encode(value);
129
+ }
130
+ if (state.enc === 'ascii') {
131
+ // Node's 'ascii' encoding masks high bits (0xE4 → 'd') — replace
132
+ // non-ASCII with '?' instead, matching the codec policy
133
+ value = value.replace(/[^\x00-\x7F]/g, '?');
134
+ }
135
+ return Buffer.from(value, state.enc);
136
+ }
137
+ /**
138
+ * Decode connection-charset bytes to text (the read counterpart of
139
+ * encodeConnectionText — used for text blobs).
140
+ */
141
+ function decodeConnectionText(options, buffer) {
142
+ const codec = resolveTextCodec(options);
143
+ if (codec) {
144
+ return codec.decode(buffer);
145
+ }
146
+ return buffer.toString(resolveTextEncoding(options));
147
+ }
65
148
  //------------------------------------------------------
66
149
  /**
67
150
  * Common shape of all SQLVar descriptor objects. The metadata properties
@@ -84,12 +167,15 @@ exports.SQLVarBase = SQLVarBase;
84
167
  * decoder and by fetchBlobSyncRow, which must agree on where each column
85
168
  * landed in the row.
86
169
  */
87
- function computeColumnKeys(output, nestTables, lowercaseKeys) {
170
+ function computeColumnKeys(output, nestTables, lowercaseKeys, transform) {
88
171
  return output.map((column) => {
89
172
  let key = column.alias || '';
90
173
  if (lowercaseKeys) {
91
174
  key = key.toLowerCase();
92
175
  }
176
+ if (transform) {
177
+ key = transform(key);
178
+ }
93
179
  if (nestTables !== true && typeof nestTables !== 'string') {
94
180
  return { key };
95
181
  }
@@ -97,12 +183,63 @@ function computeColumnKeys(output, nestTables, lowercaseKeys) {
97
183
  if (lowercaseKeys) {
98
184
  table = table.toLowerCase();
99
185
  }
186
+ if (transform) {
187
+ table = transform(table);
188
+ }
100
189
  if (nestTables === true) {
101
190
  return { table, key };
102
191
  }
103
192
  return { key: table + nestTables + key };
104
193
  });
105
194
  }
195
+ /** FIRST_NAME → firstName (the transformKeys: 'camel' built-in). */
196
+ function camelizeKey(key) {
197
+ const parts = String(key).toLowerCase().split('_');
198
+ let out = parts[0] || '';
199
+ for (let i = 1; i < parts.length; i++) {
200
+ const part = parts[i];
201
+ if (part) {
202
+ out += part.charAt(0).toUpperCase() + part.slice(1);
203
+ }
204
+ }
205
+ return out;
206
+ }
207
+ /**
208
+ * Resolve the effective transformKeys value (per-query wins over the
209
+ * connection option) into a callable mapper, or undefined when off.
210
+ * A custom mapper is guarded like the typeCast hook: a throw inside the
211
+ * row-decode loop would be mistaken for an incomplete packet and desync
212
+ * the response queue, so failures fall back to the untransformed key.
213
+ */
214
+ function resolveKeyTransform(queryOptions, connectionOptions) {
215
+ const value = resolveQueryOption('transformKeys', queryOptions, connectionOptions);
216
+ if (value === 'camel') {
217
+ return camelizeKey;
218
+ }
219
+ if (typeof value !== 'function') {
220
+ return undefined;
221
+ }
222
+ return (key) => {
223
+ try {
224
+ return String(value(key));
225
+ }
226
+ catch (err) {
227
+ console.warn('[node-firebird] transformKeys mapper threw for key "%s": %s — using the untransformed key', key, err && err.message);
228
+ return key;
229
+ }
230
+ };
231
+ }
232
+ /**
233
+ * Shared precedence rule for per-query-overridable connection options:
234
+ * the per-query value wins whenever it is present (even if falsy), the
235
+ * connection option applies otherwise.
236
+ */
237
+ function resolveQueryOption(name, queryOptions, connectionOptions) {
238
+ if (queryOptions && queryOptions[name] !== undefined) {
239
+ return queryOptions[name];
240
+ }
241
+ return connectionOptions ? connectionOptions[name] : undefined;
242
+ }
106
243
  /**
107
244
  * Resolve the effective nestTables value: the per-query option wins over
108
245
  * the connection option. The decoder and fetchBlobSyncRow both use this —
@@ -110,10 +247,7 @@ function computeColumnKeys(output, nestTables, lowercaseKeys) {
110
247
  * up in the wrong place.
111
248
  */
112
249
  function resolveNestTables(queryOptions, connectionOptions) {
113
- if (queryOptions && queryOptions.nestTables !== undefined) {
114
- return queryOptions.nestTables;
115
- }
116
- return connectionOptions && connectionOptions.nestTables;
250
+ return resolveQueryOption('nestTables', queryOptions, connectionOptions);
117
251
  }
118
252
  /**
119
253
  * The object a column's value lives in: the row itself, or — when the
@@ -128,26 +262,119 @@ function nestCell(row, table) {
128
262
  return row[table] || (row[table] = {});
129
263
  }
130
264
  //------------------------------------------------------
265
+ /** Human-readable names for the SQL_* wire type codes. */
266
+ exports.SQL_TYPE_NAMES = {
267
+ [const_1.default.SQL_TEXT]: 'TEXT',
268
+ [const_1.default.SQL_VARYING]: 'VARYING',
269
+ [const_1.default.SQL_SHORT]: 'SHORT',
270
+ [const_1.default.SQL_LONG]: 'LONG',
271
+ [const_1.default.SQL_FLOAT]: 'FLOAT',
272
+ [const_1.default.SQL_DOUBLE]: 'DOUBLE',
273
+ [const_1.default.SQL_D_FLOAT]: 'D_FLOAT',
274
+ [const_1.default.SQL_TIMESTAMP]: 'TIMESTAMP',
275
+ [const_1.default.SQL_BLOB]: 'BLOB',
276
+ [const_1.default.SQL_ARRAY]: 'ARRAY',
277
+ [const_1.default.SQL_QUAD]: 'QUAD',
278
+ [const_1.default.SQL_TYPE_TIME]: 'TIME',
279
+ [const_1.default.SQL_TYPE_DATE]: 'DATE',
280
+ [const_1.default.SQL_INT64]: 'INT64',
281
+ [const_1.default.SQL_INT128]: 'INT128',
282
+ [const_1.default.SQL_TIMESTAMP_TZ]: 'TIMESTAMP_TZ',
283
+ [const_1.default.SQL_TIMESTAMP_TZ_EX]: 'TIMESTAMP_TZ_EX',
284
+ [const_1.default.SQL_TIME_TZ]: 'TIME_TZ',
285
+ [const_1.default.SQL_TIME_TZ_EX]: 'TIME_TZ_EX',
286
+ [const_1.default.SQL_DEC16]: 'DEC16',
287
+ [const_1.default.SQL_DEC34]: 'DEC34',
288
+ [const_1.default.SQL_BOOLEAN]: 'BOOLEAN',
289
+ [const_1.default.SQL_NULL]: 'NULL',
290
+ };
291
+ /**
292
+ * Public column-metadata shape for one output descriptor: the vocabulary
293
+ * both the typeCast hook and withMeta `fields` deliver. Keep the two in
294
+ * lockstep by building both through here.
295
+ */
296
+ function describeField(meta) {
297
+ return {
298
+ type: meta.type,
299
+ typeName: exports.SQL_TYPE_NAMES[meta.type] || 'UNKNOWN',
300
+ subType: meta.subType,
301
+ scale: meta.scale,
302
+ // report the column's true declared length, not the widened fetch
303
+ // buffer (see scaleOutputLengths)
304
+ length: meta.nativeLength !== undefined ? meta.nativeLength : meta.length,
305
+ nullable: meta.nullable,
306
+ field: meta.field,
307
+ relation: meta.relation,
308
+ relationAlias: meta.relationAlias,
309
+ relationSchema: meta.relationSchema,
310
+ alias: meta.alias,
311
+ };
312
+ }
313
+ /**
314
+ * Map a statement's output descriptors to the column-metadata array
315
+ * delivered in withMeta results ({ rows, fields, ... }).
316
+ */
317
+ function describeFields(output) {
318
+ return (output || []).map(describeField);
319
+ }
320
+ /**
321
+ * Parse the op_info_sql response buffer of a Const.RECORDS_INFO request
322
+ * into per-verb row counts. The buffer holds an isc_info_sql_records
323
+ * cluster (2-byte total length, then nested isc_info_req_*_count items,
324
+ * each 2-byte length + little-endian integer) terminated by isc_info_end.
325
+ */
326
+ function parseRecordCounts(buffer) {
327
+ const counts = { selectCount: 0, insertCount: 0, updateCount: 0, deleteCount: 0 };
328
+ if (!buffer || !buffer.length) {
329
+ return counts;
330
+ }
331
+ // this runs inside a response callback — a malformed/truncated buffer
332
+ // must yield partial counts, never a throw
333
+ try {
334
+ const br = new serialize_1.BlrReader(buffer);
335
+ while (br.pos < br.buffer.length) {
336
+ const item = br.readByteCode();
337
+ if (item === const_1.default.isc_info_end || item === const_1.default.isc_info_truncated) {
338
+ break;
339
+ }
340
+ if (item === const_1.default.isc_info_sql_records) {
341
+ br.pos += 2; // skip the cluster's total length; nested items follow
342
+ continue;
343
+ }
344
+ switch (item) {
345
+ case const_1.default.isc_info_req_select_count:
346
+ counts.selectCount = br.readInt() || 0;
347
+ break;
348
+ case const_1.default.isc_info_req_insert_count:
349
+ counts.insertCount = br.readInt() || 0;
350
+ break;
351
+ case const_1.default.isc_info_req_update_count:
352
+ counts.updateCount = br.readInt() || 0;
353
+ break;
354
+ case const_1.default.isc_info_req_delete_count:
355
+ counts.deleteCount = br.readInt() || 0;
356
+ break;
357
+ default:
358
+ // unknown item: its 2-byte length prefix tells us how far to skip
359
+ br.pos += 2 + br.buffer.readUInt16LE(br.pos);
360
+ }
361
+ }
362
+ }
363
+ catch (e) {
364
+ // fall through with whatever was parsed so far
365
+ }
366
+ return counts;
367
+ }
368
+ //------------------------------------------------------
131
369
  class SQLVarText extends SQLVarBase {
132
370
  decode(data, lowerV13, options) {
133
371
  let ret;
134
- const textEncoding = resolveTextEncoding(options);
135
- if (this.subType > 1) {
136
- // ToDo: with column charset
137
- ret = data.readText(this.length, textEncoding);
138
- const encoding = options && options.encoding ? options.encoding : 'UTF8';
139
- const width = getFirebirdCharsetWidth(encoding);
140
- const charLength = Math.floor(this.length / width);
141
- if (ret.length > charLength) {
142
- ret = ret.substring(0, charLength);
143
- }
144
- }
145
- else if (this.subType === 0) {
146
- // without charset definition
147
- ret = data.readText(this.length, textEncoding);
148
- const encoding = options && options.encoding ? options.encoding : 'UTF8';
149
- const width = getFirebirdCharsetWidth(encoding);
150
- const charLength = Math.floor(this.length / width);
372
+ if (this.subType > 1 || this.subType === 0) {
373
+ const state = resolveTextState(options);
374
+ ret = state.codec
375
+ ? state.codec.decode(data.readBuffer(this.length) || EMPTY_BUFFER)
376
+ : data.readText(this.length, state.enc);
377
+ const charLength = Math.floor(this.length / state.width);
151
378
  if (ret.length > charLength) {
152
379
  ret = ret.substring(0, charLength);
153
380
  }
@@ -174,14 +401,11 @@ exports.SQLVarNull = SQLVarNull;
174
401
  class SQLVarString extends SQLVarBase {
175
402
  decode(data, lowerV13, options) {
176
403
  let ret;
177
- const textEncoding = resolveTextEncoding(options);
178
- if (this.subType > 1) {
179
- // ToDo: with column charset
180
- ret = data.readString(textEncoding);
181
- }
182
- else if (this.subType === 0) {
183
- // without charset definition
184
- ret = data.readString(textEncoding);
404
+ if (this.subType > 1 || this.subType === 0) {
405
+ const state = resolveTextState(options);
406
+ ret = state.codec
407
+ ? state.codec.decode(data.readArray() || EMPTY_BUFFER)
408
+ : data.readString(state.enc);
185
409
  }
186
410
  else {
187
411
  ret = data.readBuffer();
@@ -716,10 +940,19 @@ class SQLParamDate {
716
940
  exports.SQLParamDate = SQLParamDate;
717
941
  //------------------------------------------------------
718
942
  class SQLParamBool {
719
- constructor(value) {
943
+ constructor(value, asBoolean = false) {
720
944
  this.value = value;
945
+ this.asBoolean = asBoolean;
721
946
  }
722
947
  encode(data) {
948
+ if (this.asBoolean) {
949
+ // xdr_datum sends booleans as 1 opaque value byte + 3 pad bytes
950
+ // (NOT a big-endian int: the value byte comes FIRST — addInt(1)
951
+ // would decode server-side as false). Matches the batch encoder.
952
+ data.addBuffer(Buffer.from([this.value ? 1 : 0]));
953
+ data.addAlignment(1);
954
+ return;
955
+ }
723
956
  if (this.value != null) {
724
957
  data.addInt(this.value ? 1 : 0);
725
958
  }
@@ -729,6 +962,10 @@ class SQLParamBool {
729
962
  }
730
963
  }
731
964
  calcBlr(blr) {
965
+ if (this.asBoolean) {
966
+ blr.addByte(const_1.default.blr_bool);
967
+ return;
968
+ }
732
969
  blr.addByte(const_1.default.blr_short);
733
970
  blr.addShort(0);
734
971
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-firebird",
3
- "version": "2.11.0",
3
+ "version": "2.13.0",
4
4
  "description": "Pure JavaScript and Asynchronous Firebird client for Node.js.",
5
5
  "keywords": [
6
6
  "firebird",
@@ -23,6 +23,24 @@
23
23
  ],
24
24
  "main": "./lib/index.js",
25
25
  "types": "./lib/index.d.ts",
26
+ "exports": {
27
+ ".": {
28
+ "types": "./lib/index.d.ts",
29
+ "import": "./lib/index.js",
30
+ "require": "./lib/index.js"
31
+ },
32
+ "./lib/firebird.msg": "./lib/firebird.msg",
33
+ "./lib/firebird.msg.json": "./lib/firebird.msg.json",
34
+ "./lib/*.js": {
35
+ "types": "./lib/*.d.ts",
36
+ "default": "./lib/*.js"
37
+ },
38
+ "./lib/*": {
39
+ "types": "./lib/*.d.ts",
40
+ "default": "./lib/*.js"
41
+ },
42
+ "./package.json": "./package.json"
43
+ },
26
44
  "files": [
27
45
  "lib",
28
46
  "src"