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.
- package/README.md +287 -9
- package/lib/pool.d.ts +14 -1
- package/lib/pool.js +59 -16
- package/lib/sql-template.d.ts +81 -0
- package/lib/sql-template.js +162 -0
- package/lib/types.d.ts +152 -5
- package/lib/uri.js +53 -2
- package/lib/utils.d.ts +12 -0
- package/lib/utils.js +20 -2
- package/lib/wire/batch-stream.d.ts +26 -0
- package/lib/wire/batch-stream.js +109 -0
- package/lib/wire/codepages.d.ts +23 -0
- package/lib/wire/codepages.js +137 -0
- package/lib/wire/connection.d.ts +44 -4
- package/lib/wire/connection.js +344 -80
- package/lib/wire/const.d.ts +5 -0
- package/lib/wire/const.js +12 -0
- package/lib/wire/database.d.ts +18 -0
- package/lib/wire/database.js +40 -13
- package/lib/wire/serialize.d.ts +2 -0
- package/lib/wire/serialize.js +14 -0
- package/lib/wire/socket.js +9 -3
- package/lib/wire/transaction.d.ts +33 -0
- package/lib/wire/transaction.js +156 -13
- package/lib/wire/xsqlvar.d.ts +118 -2
- package/lib/wire/xsqlvar.js +271 -34
- package/package.json +19 -1
- package/src/pool.ts +57 -14
- package/src/sql-template.ts +196 -0
- package/src/types.ts +153 -6
- package/src/uri.ts +54 -2
- package/src/utils.ts +19 -1
- package/src/wire/batch-stream.ts +121 -0
- package/src/wire/codepages.ts +147 -0
- package/src/wire/connection.ts +374 -86
- package/src/wire/const.ts +13 -0
- package/src/wire/database.ts +46 -15
- package/src/wire/serialize.ts +16 -1
- package/src/wire/socket.ts +9 -3
- package/src/wire/transaction.ts +166 -19
- package/src/wire/xsqlvar.ts +298 -34
|
@@ -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
|
+
}
|
package/lib/wire/connection.d.ts
CHANGED
|
@@ -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
|
|
124
|
-
*
|
|
125
|
-
*
|
|
126
|
-
*
|
|
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;
|