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.
@@ -0,0 +1,137 @@
1
+ "use strict";
2
+ /***************************************
3
+ *
4
+ * Single-byte codepage codecs (WIN125x, ISO8859_x, KOI8, DOS866)
5
+ *
6
+ * Node's Buffer only decodes utf8/latin1/ascii natively. These
7
+ * codepages are decoded through the WHATWG TextDecoder (backed by
8
+ * ICU — present in every official Node build) and encoded through
9
+ * reverse tables built from the same decoder at first use, so the
10
+ * two directions can never disagree. Issues #319/#301/#422.
11
+ *
12
+ ***************************************/
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.charsetWidthById = charsetWidthById;
15
+ exports.getCodec = getCodec;
16
+ /** Firebird charset name → WHATWG encoding label (single-byte only). */
17
+ const ICU_LABELS = Object.freeze({
18
+ WIN1250: 'windows-1250',
19
+ WIN1251: 'windows-1251',
20
+ WIN1253: 'windows-1253',
21
+ WIN1254: 'windows-1254',
22
+ WIN1255: 'windows-1255',
23
+ WIN1256: 'windows-1256',
24
+ WIN1257: 'windows-1257',
25
+ WIN1258: 'windows-1258',
26
+ ISO8859_2: 'iso-8859-2',
27
+ ISO8859_3: 'iso-8859-3',
28
+ ISO8859_4: 'iso-8859-4',
29
+ ISO8859_5: 'iso-8859-5',
30
+ ISO8859_6: 'iso-8859-6',
31
+ ISO8859_7: 'iso-8859-7',
32
+ ISO8859_8: 'iso-8859-8',
33
+ ISO8859_9: 'iso-8859-9',
34
+ ISO8859_13: 'iso-8859-13',
35
+ KOI8R: 'koi8-r',
36
+ KOI8U: 'koi8-u',
37
+ DOS866: 'ibm866',
38
+ });
39
+ /**
40
+ * Bytes-per-character by Firebird charset id (RDB$CHARACTER_SETS —
41
+ * verified against a live server). Everything not listed (NONE, ASCII,
42
+ * ISO8859_x, WIN125x, DOS*, KOI8*, CYRL, TIS620, …) is single-byte.
43
+ */
44
+ const CHARSET_WIDTH_BY_ID = Object.freeze({
45
+ 3: 3, // UNICODE_FSS
46
+ 4: 4, // UTF8
47
+ 5: 2, // SJIS_0208
48
+ 6: 2, // EUCJ_0208
49
+ 44: 2, // KSC_5601
50
+ 56: 2, // BIG_5
51
+ 57: 2, // GB_2312
52
+ 67: 2, // GBK
53
+ 68: 2, // CP943C
54
+ 69: 4, // GB18030
55
+ });
56
+ function charsetWidthById(id) {
57
+ if (id === undefined) {
58
+ return 1;
59
+ }
60
+ return CHARSET_WIDTH_BY_ID[id] || 1;
61
+ }
62
+ const cache = new Map();
63
+ function buildCodec(name) {
64
+ const label = ICU_LABELS[name];
65
+ if (!label) {
66
+ return null;
67
+ }
68
+ let decoder;
69
+ try {
70
+ decoder = new TextDecoder(label);
71
+ }
72
+ catch {
73
+ // Node built with small-icu: legacy encodings unavailable
74
+ return null;
75
+ }
76
+ // Build both directions from the decoder, one byte at a time — every
77
+ // byte of a single-byte codepage maps to exactly one BMP character
78
+ // (undefined bytes decode to U+FFFD, which is kept for decoding but
79
+ // never used for the reverse map).
80
+ const toCode = new Uint16Array(256);
81
+ const toByte = new Map();
82
+ const one = Buffer.alloc(1);
83
+ for (let i = 0; i < 256; i++) {
84
+ one[0] = i;
85
+ const ch = decoder.decode(one);
86
+ toCode[i] = ch.charCodeAt(0);
87
+ if (ch !== '�' && !toByte.has(ch)) {
88
+ toByte.set(ch, i);
89
+ }
90
+ }
91
+ return {
92
+ name,
93
+ decode(buffer) {
94
+ // batch through fromCharCode instead of per-byte string concat —
95
+ // wide CHAR columns and text blobs decode in O(chunks) allocations
96
+ const codes = new Array(buffer.length);
97
+ for (let i = 0; i < buffer.length; i++) {
98
+ codes[i] = toCode[buffer[i]];
99
+ }
100
+ const CHUNK = 4096;
101
+ if (codes.length <= CHUNK) {
102
+ return String.fromCharCode(...codes);
103
+ }
104
+ let out = '';
105
+ for (let i = 0; i < codes.length; i += CHUNK) {
106
+ out += String.fromCharCode(...codes.slice(i, i + CHUNK));
107
+ }
108
+ return out;
109
+ },
110
+ encode(value) {
111
+ const out = Buffer.alloc(value.length);
112
+ for (let i = 0; i < value.length; i++) {
113
+ const b = toByte.get(value[i]);
114
+ // unmappable characters become '?' — the convention every
115
+ // codepage transcoder (incl. iconv) uses by default
116
+ out[i] = b === undefined ? 0x3f : b;
117
+ }
118
+ return out;
119
+ },
120
+ };
121
+ }
122
+ /**
123
+ * Codec for a Firebird charset name, or null when the charset is unknown,
124
+ * natively handled by Buffer, or the ICU tables are unavailable. Cached.
125
+ */
126
+ function getCodec(charsetName) {
127
+ if (!charsetName) {
128
+ return null;
129
+ }
130
+ const name = String(charsetName).toUpperCase();
131
+ let codec = cache.get(name);
132
+ if (codec === undefined) {
133
+ codec = buildCodec(name);
134
+ cache.set(name, codec);
135
+ }
136
+ return codec;
137
+ }
@@ -78,6 +78,17 @@ declare class Connection {
78
78
  */
79
79
  releaseStatement(statement: Statement, callback?: QueueCallback): void;
80
80
  _rejectPending(err: any): void;
81
+ /**
82
+ * Deliver a connection-level error to 'error' listeners — and ONLY to
83
+ * listeners. Emitting an unlistened 'error' makes Node throw the error
84
+ * object as an uncaught exception; for errors that originate in
85
+ * background contexts (the reconnect timer, socket-level failures whose
86
+ * operations are separately rejected via _rejectPending) that crashes
87
+ * the process — or, under a test runner, fails whatever unrelated test
88
+ * happens to be running. The failing operations themselves always
89
+ * still receive their error through their own callbacks.
90
+ */
91
+ _emitError(err: any): void;
81
92
  _bind_events(host: string, port: number, callback: SimpleCallback | undefined): void;
82
93
  disconnect(): void;
83
94
  sendOpContAuth(authData: string, authDataEnc: BufferEncoding, pluginName: string): void;
@@ -120,24 +131,53 @@ declare class Connection {
120
131
  * gets an in-order response (op_batch_cs for exec), so the regular
121
132
  * response queue keeps everything in sync.
122
133
  *
123
- * rows: array of parameter arrays, one per record. BLOB/ARRAY columns
124
- * are not supported yet. The callback receives a completion object:
125
- * { recordCount, updateCounts, errors: [{recordNumber, error}],
126
- * errorRecordNumbers, success }.
134
+ * rows: array of parameter arrays, one per record. BLOB columns accept
135
+ * Buffers, strings, JSON-able objects or pre-created blob quad ids —
136
+ * values are uploaded as transaction blobs first (all initiated
137
+ * back-to-back so they pipeline) and the batch messages reference their
138
+ * ids. ARRAY columns are not supported. The callback receives a
139
+ * completion object: { recordCount, updateCounts, errors:
140
+ * [{recordNumber, error}], errorRecordNumbers, success }.
127
141
  */
128
142
  executeBatch(transaction: Transaction, statement: Statement, rows: QueryParams[], callback: BatchCb | undefined, options?: BatchOptions): this | undefined;
143
+ /** Encode and send the batch packets (rows are fully materialized:
144
+ * blob values already replaced by quad ids by executeBatch). */
145
+ _executeBatchEncoded(transaction: Transaction, statement: Statement, rows: any[][], callback: BatchCb | undefined, options: BatchOptions): void;
129
146
  /** `params` may be the callback itself when the statement has no parameters. */
130
147
  executeStatement(transaction: Transaction, statement: Statement, params: any, callback?: QueueCallback, custom?: InternalQueryOptions): this | undefined;
131
148
  sendExecute(op: number, statement: Statement, transaction: Transaction, callback: QueueCallback | undefined, parameters?: any[]): void;
132
149
  /** `count` may be the callback itself when no fetch size is given. */
133
150
  fetch(statement: Statement, transaction: Transaction, count: any, callback?: QueueCallback): void;
134
151
  fetchScroll(statement: Statement, transaction: Transaction, direction: string | number, offset: any, count: any, callback?: QueueCallback): void;
152
+ /**
153
+ * Query runtime information about a prepared statement via op_info_sql
154
+ * (e.g. Const.RECORDS_INFO for the per-verb DML row counts). The
155
+ * response is a plain op_response whose buffer holds the info clusters.
156
+ */
157
+ statementInfo(statement: Statement, items: number[], callback?: QueueCallback): this | undefined;
158
+ /**
159
+ * Resolve the pending blobAsText fetches of a decoded row batch
160
+ * (ret.arrBlob) and write the text back into ret.data. Reads run
161
+ * sequentially to respect Firebird's per-connection open-blob-handle
162
+ * limit (issue #387). Used by fetchAll for cursors and by
163
+ * transaction.execute for op_execute2 singletons (EXECUTE PROCEDURE /
164
+ * RETURNING — issue #305, whose blobs never resolved before).
165
+ */
166
+ resolveTextBlobs(transaction: Transaction, ret: any, callback: (err?: any) => void): void;
135
167
  fetchAll(statement: Statement, transaction: Transaction, callback: Callback<any[]>): void;
136
168
  openBlob(blob: Quad, transaction: Transaction, callback: QueueCallback): void;
137
169
  closeBlob(blob: any, callback?: QueueCallback, defer?: boolean): void;
138
170
  getSegment(blob: any, callback: QueueCallback): void;
139
171
  createBlob2(transaction: Transaction, callback: QueueCallback): void;
140
172
  batchSegments(blob: any, buffer: Buffer, callback: QueueCallback): void;
173
+ /**
174
+ * Create a transaction blob, upload `value` (Buffer, string, or a
175
+ * JSON-able object) and deliver its quad id. executeBatch's blob
176
+ * pre-pass uses this: batch messages reference pre-created transaction
177
+ * blobs (the batch parameter buffer's default BLOB_NONE policy), just
178
+ * like the classic execute path stores blob params.
179
+ */
180
+ uploadBlob(transaction: Transaction, value: any, callback: (err: any, oid?: any) => void): void;
141
181
  svcattach(options: InternalOptions, callback?: Callback<ServiceManager>, svc?: ServiceManager): void;
142
182
  svcstart(spbaction: BlrWriter, callback: QueueCallback | undefined): void;
143
183
  svcquery(spbquery: number[], resultbuffersize: number, timeout: number | undefined, callback: QueueCallback | undefined): void;