@depup/mysql2 3.23.4-depup.0 → 3.24.0-depup.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 +2 -2
- package/changes.json +1 -1
- package/index.js +5 -0
- package/lib/base/connection.js +3 -1
- package/lib/commands/execute.js +4 -1
- package/lib/commands/query.js +8 -8
- package/lib/compressed_protocol.js +5 -2
- package/lib/constants/types.js +1 -0
- package/lib/packet_parser.js +20 -16
- package/lib/packets/column_definition.js +11 -10
- package/lib/packets/encode_parameter.js +37 -7
- package/lib/packets/execute.js +74 -34
- package/lib/packets/packet.js +150 -20
- package/lib/packets/query.js +102 -66
- package/lib/packets/typed_parameter.js +381 -0
- package/lib/parsers/binary_parser.js +2 -2
- package/lib/parsers/parser_cache.js +21 -15
- package/lib/parsers/string.js +41 -0
- package/lib/promise/connection.js +6 -2
- package/lib/promise/pool.js +6 -2
- package/package.json +3 -3
- package/promise.js +5 -0
- package/typings/mysql/index.d.ts +1 -0
- package/typings/mysql/lib/TypedParameter.d.ts +84 -0
- package/typings/mysql/lib/protocol/sequences/Query.d.ts +2 -0
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const Types = require('../constants/types.js');
|
|
4
|
+
const Packet = require('./packet.js');
|
|
5
|
+
const StringParser = require('../parsers/string.js');
|
|
6
|
+
|
|
7
|
+
const INTEGER_BYTES = {
|
|
8
|
+
[Types.TINY]: 1,
|
|
9
|
+
[Types.SHORT]: 2,
|
|
10
|
+
[Types.YEAR]: 2,
|
|
11
|
+
[Types.INT24]: 4,
|
|
12
|
+
[Types.LONG]: 4,
|
|
13
|
+
[Types.LONGLONG]: 8,
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const TEMPORAL = [Types.DATE, Types.DATETIME, Types.TIMESTAMP];
|
|
17
|
+
|
|
18
|
+
// MySQL rejects INT24, YEAR, ENUM, SET, BIT and GEOMETRY as bind types, and
|
|
19
|
+
// MariaDB rejects JSON and VECTOR. Each is transmitted as the narrowest type
|
|
20
|
+
// both servers accept, which carries the same value.
|
|
21
|
+
const WIRE_TYPE = {
|
|
22
|
+
[Types.INT24]: Types.LONG,
|
|
23
|
+
[Types.YEAR]: Types.SHORT,
|
|
24
|
+
[Types.ENUM]: Types.STRING,
|
|
25
|
+
[Types.SET]: Types.STRING,
|
|
26
|
+
[Types.VECTOR]: Types.BLOB,
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
// Only these may be adopted from a server hint: they are valid bind types on
|
|
30
|
+
// every server, so upgrading can never make a working statement fail.
|
|
31
|
+
const HINT_UPGRADABLE = new Set([
|
|
32
|
+
Types.TINY,
|
|
33
|
+
Types.SHORT,
|
|
34
|
+
Types.LONG,
|
|
35
|
+
Types.LONGLONG,
|
|
36
|
+
]);
|
|
37
|
+
|
|
38
|
+
const LENGTH_CODED = [
|
|
39
|
+
Types.DECIMAL,
|
|
40
|
+
Types.NEWDECIMAL,
|
|
41
|
+
Types.VARCHAR,
|
|
42
|
+
Types.VAR_STRING,
|
|
43
|
+
Types.STRING,
|
|
44
|
+
Types.ENUM,
|
|
45
|
+
Types.SET,
|
|
46
|
+
Types.JSON,
|
|
47
|
+
Types.VECTOR,
|
|
48
|
+
Types.TINY_BLOB,
|
|
49
|
+
Types.MEDIUM_BLOB,
|
|
50
|
+
Types.LONG_BLOB,
|
|
51
|
+
Types.BLOB,
|
|
52
|
+
];
|
|
53
|
+
|
|
54
|
+
function writeNothing() {}
|
|
55
|
+
|
|
56
|
+
const TIME_PATTERN = /^(-)?(\d+):([0-5]?\d):([0-5]?\d)(?:\.(\d{1,6}))?$/;
|
|
57
|
+
|
|
58
|
+
class TypedParameter {
|
|
59
|
+
constructor(type, value, unsigned) {
|
|
60
|
+
this.type = type;
|
|
61
|
+
this.value = value;
|
|
62
|
+
this.unsigned = unsigned;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
[Symbol.for('nodejs.util.inspect.custom')]() {
|
|
66
|
+
const name = Types[this.type] || `0x${this.type.toString(16)}`;
|
|
67
|
+
return `${name}${this.unsigned ? ' UNSIGNED' : ''}(${String(this.value)})`;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function toInteger(value, name) {
|
|
72
|
+
switch (typeof value) {
|
|
73
|
+
case 'bigint':
|
|
74
|
+
return value;
|
|
75
|
+
case 'boolean':
|
|
76
|
+
return value ? 1n : 0n;
|
|
77
|
+
case 'number':
|
|
78
|
+
if (!Number.isInteger(value)) {
|
|
79
|
+
throw new TypeError(
|
|
80
|
+
`${name} parameter must be an integer, got ${value}`
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
if (!Number.isSafeInteger(value)) {
|
|
84
|
+
throw new RangeError(
|
|
85
|
+
`${name} parameter ${value} exceeds Number.MAX_SAFE_INTEGER and has already lost precision; pass a string or BigInt instead`
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
return BigInt(value);
|
|
89
|
+
case 'string':
|
|
90
|
+
try {
|
|
91
|
+
return BigInt(value.trim());
|
|
92
|
+
} catch (cause) {
|
|
93
|
+
throw new TypeError(
|
|
94
|
+
`${name} parameter must be an integer, got ${JSON.stringify(value)}`,
|
|
95
|
+
{ cause }
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
default:
|
|
99
|
+
throw new TypeError(
|
|
100
|
+
`${name} parameter must be an integer, got ${typeof value}`
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function checkedInteger(value, type, bytes, unsigned) {
|
|
106
|
+
const name = Types[type];
|
|
107
|
+
const bits = BigInt(bytes * 8);
|
|
108
|
+
const n = toInteger(value, name);
|
|
109
|
+
const min = unsigned ? 0n : -(1n << (bits - 1n));
|
|
110
|
+
const max = unsigned ? (1n << bits) - 1n : (1n << (bits - 1n)) - 1n;
|
|
111
|
+
if (n < min || n > max) {
|
|
112
|
+
throw new RangeError(
|
|
113
|
+
`${name}${unsigned ? ' UNSIGNED' : ''} parameter out of range: ${n} is not within ${min}..${max}`
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
return n;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// The server reports an integer type whenever it knows a placeholder holds one,
|
|
120
|
+
// and MySQL rejects a DOUBLE in some of those positions. Adopting the hint is
|
|
121
|
+
// only safe when the value is already an integer that fits, so every other case
|
|
122
|
+
// returns null and keeps the type inferred from JavaScript.
|
|
123
|
+
function integerHint(value, type, unsigned) {
|
|
124
|
+
const bytes = INTEGER_BYTES[type];
|
|
125
|
+
if (!bytes || !HINT_UPGRADABLE.has(type)) {
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
let n;
|
|
129
|
+
if (typeof value === 'bigint') {
|
|
130
|
+
n = value;
|
|
131
|
+
} else if (typeof value === 'boolean') {
|
|
132
|
+
n = value ? 1n : 0n;
|
|
133
|
+
} else if (typeof value === 'number' && Number.isSafeInteger(value)) {
|
|
134
|
+
n = BigInt(value);
|
|
135
|
+
} else {
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
const bits = BigInt(bytes * 8);
|
|
139
|
+
const min = unsigned ? 0n : -(1n << (bits - 1n));
|
|
140
|
+
const max = unsigned ? (1n << bits) - 1n : (1n << (bits - 1n)) - 1n;
|
|
141
|
+
if (n < min || n > max) {
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
return new TypedParameter(type, n, unsigned);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function wireType(type, jsonAsString) {
|
|
148
|
+
if (type === Types.JSON && jsonAsString) {
|
|
149
|
+
return Types.VAR_STRING;
|
|
150
|
+
}
|
|
151
|
+
return WIRE_TYPE[type] || type;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function integerEncoder(type, bytes) {
|
|
155
|
+
return (value, unsigned) => {
|
|
156
|
+
const wire = BigInt.asUintN(
|
|
157
|
+
bytes * 8,
|
|
158
|
+
checkedInteger(value, type, bytes, unsigned)
|
|
159
|
+
);
|
|
160
|
+
return {
|
|
161
|
+
value: bytes === 8 ? wire : Number(wire),
|
|
162
|
+
length: bytes,
|
|
163
|
+
writer(v) {
|
|
164
|
+
this.writeUIntLE(v, bytes);
|
|
165
|
+
},
|
|
166
|
+
};
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function toDate(value, name) {
|
|
171
|
+
const date = value instanceof Date ? value : new Date(value);
|
|
172
|
+
if (Number.isNaN(date.getTime())) {
|
|
173
|
+
throw new TypeError(
|
|
174
|
+
`${name} parameter must be a valid Date, got ${String(value)}`
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
return date;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function temporalEncoder(type, timezone) {
|
|
181
|
+
const name = Types[type];
|
|
182
|
+
return (value) => ({
|
|
183
|
+
value: toDate(value, name),
|
|
184
|
+
length: 12,
|
|
185
|
+
writer(v) {
|
|
186
|
+
this.writeDate(v, timezone);
|
|
187
|
+
},
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function toTimeParts(value) {
|
|
192
|
+
if (typeof value === 'number') {
|
|
193
|
+
const negative = value < 0;
|
|
194
|
+
let rest = Math.abs(value);
|
|
195
|
+
const microseconds = Math.round((rest % 1000) * 1000);
|
|
196
|
+
rest = Math.floor(rest / 1000);
|
|
197
|
+
const seconds = rest % 60;
|
|
198
|
+
const minutes = Math.floor(rest / 60) % 60;
|
|
199
|
+
const totalHours = Math.floor(rest / 3600);
|
|
200
|
+
return {
|
|
201
|
+
negative,
|
|
202
|
+
days: Math.floor(totalHours / 24),
|
|
203
|
+
hours: totalHours % 24,
|
|
204
|
+
minutes,
|
|
205
|
+
seconds,
|
|
206
|
+
microseconds,
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
const match = TIME_PATTERN.exec(String(value));
|
|
210
|
+
if (!match) {
|
|
211
|
+
throw new TypeError(
|
|
212
|
+
`TIME parameter must be 'HH:MM:SS[.ffffff]' or milliseconds, got ${JSON.stringify(String(value))}`
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
const hours = Number(match[2]);
|
|
216
|
+
return {
|
|
217
|
+
negative: Boolean(match[1]),
|
|
218
|
+
days: Math.floor(hours / 24),
|
|
219
|
+
hours: hours % 24,
|
|
220
|
+
minutes: Number(match[3]),
|
|
221
|
+
seconds: Number(match[4]),
|
|
222
|
+
microseconds: match[5] ? Number(match[5].padEnd(6, '0')) : 0,
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function timeEncoder() {
|
|
227
|
+
return (value) => {
|
|
228
|
+
const parts = toTimeParts(value);
|
|
229
|
+
return {
|
|
230
|
+
value: parts,
|
|
231
|
+
length: Packet.timeLength(parts),
|
|
232
|
+
writer(v) {
|
|
233
|
+
this.writeTime(v);
|
|
234
|
+
},
|
|
235
|
+
};
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
function lengthCodedEncoder(encoding) {
|
|
240
|
+
return (value) => {
|
|
241
|
+
const buffer = Buffer.isBuffer(value)
|
|
242
|
+
? value
|
|
243
|
+
: StringParser.encode(
|
|
244
|
+
typeof value === 'string' ? value : String(value),
|
|
245
|
+
encoding
|
|
246
|
+
);
|
|
247
|
+
return {
|
|
248
|
+
value: buffer,
|
|
249
|
+
length: Packet.lengthCodedNumberLength(buffer.length) + buffer.length,
|
|
250
|
+
writer: Packet.prototype.writeLengthCodedBuffer,
|
|
251
|
+
};
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function jsonEncoder(encoding) {
|
|
256
|
+
const encodeText = lengthCodedEncoder(encoding);
|
|
257
|
+
return (value) =>
|
|
258
|
+
encodeText(
|
|
259
|
+
typeof value === 'string' || Buffer.isBuffer(value)
|
|
260
|
+
? value
|
|
261
|
+
: JSON.stringify(value)
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
function encoderFor(type, encoding, timezone) {
|
|
266
|
+
if (INTEGER_BYTES[type]) {
|
|
267
|
+
return integerEncoder(type, INTEGER_BYTES[type]);
|
|
268
|
+
}
|
|
269
|
+
if (type === Types.DOUBLE) {
|
|
270
|
+
return (value) => ({
|
|
271
|
+
value: Number(value),
|
|
272
|
+
length: 8,
|
|
273
|
+
writer: Packet.prototype.writeDouble,
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
if (type === Types.FLOAT) {
|
|
277
|
+
return (value) => ({
|
|
278
|
+
value: Number(value),
|
|
279
|
+
length: 4,
|
|
280
|
+
writer: Packet.prototype.writeFloat,
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
if (TEMPORAL.includes(type)) {
|
|
284
|
+
return temporalEncoder(type, timezone);
|
|
285
|
+
}
|
|
286
|
+
if (type === Types.TIME) {
|
|
287
|
+
return timeEncoder();
|
|
288
|
+
}
|
|
289
|
+
if (type === Types.JSON) {
|
|
290
|
+
return jsonEncoder(encoding);
|
|
291
|
+
}
|
|
292
|
+
if (LENGTH_CODED.includes(type)) {
|
|
293
|
+
return lengthCodedEncoder(encoding);
|
|
294
|
+
}
|
|
295
|
+
throw new TypeError(
|
|
296
|
+
`No parameter encoder for MySQL type 0x${type.toString(16)}`
|
|
297
|
+
);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
function encodeTypedParameter(parameter, encoding, timezone, jsonAsString) {
|
|
301
|
+
if (parameter.value === null || parameter.type === Types.NULL) {
|
|
302
|
+
return {
|
|
303
|
+
value: '',
|
|
304
|
+
type: wireType(parameter.type, jsonAsString),
|
|
305
|
+
length: 0,
|
|
306
|
+
writer: writeNothing,
|
|
307
|
+
unsigned: parameter.unsigned,
|
|
308
|
+
isNull: true,
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
const encoded = encoderFor(
|
|
312
|
+
parameter.type,
|
|
313
|
+
encoding,
|
|
314
|
+
timezone
|
|
315
|
+
)(parameter.value, parameter.unsigned);
|
|
316
|
+
return {
|
|
317
|
+
...encoded,
|
|
318
|
+
type: wireType(parameter.type, jsonAsString),
|
|
319
|
+
unsigned: parameter.unsigned,
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
const ALIASES = {
|
|
324
|
+
MEDIUMTEXT: 'MEDIUM_BLOB',
|
|
325
|
+
LONGTEXT: 'LONG_BLOB',
|
|
326
|
+
TINYINT: 'TINY',
|
|
327
|
+
SMALLINT: 'SHORT',
|
|
328
|
+
MEDIUMINT: 'INT24',
|
|
329
|
+
INT: 'LONG',
|
|
330
|
+
INTEGER: 'LONG',
|
|
331
|
+
BIGINT: 'LONGLONG',
|
|
332
|
+
REAL: 'DOUBLE',
|
|
333
|
+
CHAR: 'STRING',
|
|
334
|
+
VARBINARY: 'VAR_STRING',
|
|
335
|
+
BINARY: 'STRING',
|
|
336
|
+
TEXT: 'BLOB',
|
|
337
|
+
};
|
|
338
|
+
|
|
339
|
+
const SUPPORTED = [
|
|
340
|
+
...Object.keys(INTEGER_BYTES),
|
|
341
|
+
Types.FLOAT,
|
|
342
|
+
Types.DOUBLE,
|
|
343
|
+
Types.TIME,
|
|
344
|
+
...TEMPORAL,
|
|
345
|
+
...LENGTH_CODED,
|
|
346
|
+
].map(Number);
|
|
347
|
+
|
|
348
|
+
const types = Object.create(null);
|
|
349
|
+
|
|
350
|
+
for (const type of SUPPORTED) {
|
|
351
|
+
const name = Types[type];
|
|
352
|
+
const bytes = INTEGER_BYTES[type];
|
|
353
|
+
const build = bytes
|
|
354
|
+
? (value, unsigned) =>
|
|
355
|
+
new TypedParameter(
|
|
356
|
+
type,
|
|
357
|
+
value === null ? null : checkedInteger(value, type, bytes, unsigned),
|
|
358
|
+
unsigned
|
|
359
|
+
)
|
|
360
|
+
: (value, unsigned) => new TypedParameter(type, value, unsigned);
|
|
361
|
+
const factory = (value) => build(value, false);
|
|
362
|
+
if (bytes) {
|
|
363
|
+
factory.unsigned = (value) => build(value, true);
|
|
364
|
+
}
|
|
365
|
+
types[name] = factory;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
types.NULL = () => new TypedParameter(Types.NULL, null, false);
|
|
369
|
+
|
|
370
|
+
for (const [alias, target] of Object.entries(ALIASES)) {
|
|
371
|
+
if (types[target] && !types[alias]) {
|
|
372
|
+
types[alias] = types[target];
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
module.exports = {
|
|
377
|
+
TypedParameter,
|
|
378
|
+
encodeTypedParameter,
|
|
379
|
+
integerHint,
|
|
380
|
+
types,
|
|
381
|
+
};
|
|
@@ -233,11 +233,11 @@ function compile(fields, options, config) {
|
|
|
233
233
|
if (options.typeCast === false) {
|
|
234
234
|
parserFn(`${lvalue} = packet.readLengthCodedBuffer();`);
|
|
235
235
|
} else {
|
|
236
|
-
const fieldWrapperVar = `fieldWrapper${i}`;
|
|
237
|
-
parserFn(`const ${fieldWrapperVar} = wrap(fields[${i}], packet);`);
|
|
238
236
|
const readCode = readCodeFor(fields[i], config, options, i);
|
|
239
237
|
|
|
240
238
|
if (typeof options.typeCast === 'function') {
|
|
239
|
+
const fieldWrapperVar = `fieldWrapper${i}`;
|
|
240
|
+
parserFn(`const ${fieldWrapperVar} = wrap(fields[${i}], packet);`);
|
|
241
241
|
parserFn(
|
|
242
242
|
`${lvalue} = options.typeCast(${fieldWrapperVar}, function() { return ${readCode} });`
|
|
243
243
|
);
|
|
@@ -6,8 +6,19 @@ const parserCache = createLRU({
|
|
|
6
6
|
max: 15000,
|
|
7
7
|
});
|
|
8
8
|
|
|
9
|
+
// the fixed-size options head keeps JSON.stringify (cheap for a flat array,
|
|
10
|
+
// and it normalizes exotic values the same way as before); the per-field part
|
|
11
|
+
// is built by hand with length-prefixed strings, so no delimiter collision is
|
|
12
|
+
// possible and no throwaway nested arrays are allocated per query
|
|
13
|
+
function appendString(key, value) {
|
|
14
|
+
if (value === undefined || value === null) {
|
|
15
|
+
return `${key}u/`;
|
|
16
|
+
}
|
|
17
|
+
return `${key}${value.length}#${value}/`;
|
|
18
|
+
}
|
|
19
|
+
|
|
9
20
|
function keyFromFields(type, fields, options, config) {
|
|
10
|
-
|
|
21
|
+
let key = JSON.stringify([
|
|
11
22
|
type,
|
|
12
23
|
typeof options.nestTables,
|
|
13
24
|
options.nestTables,
|
|
@@ -21,25 +32,20 @@ function keyFromFields(type, fields, options, config) {
|
|
|
21
32
|
Boolean(options.decimalNumbers),
|
|
22
33
|
options.dateStrings,
|
|
23
34
|
Boolean(config.jsonStrings),
|
|
24
|
-
];
|
|
35
|
+
]);
|
|
25
36
|
|
|
26
37
|
for (let i = 0; i < fields.length; ++i) {
|
|
27
38
|
const field = fields[i];
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
field.flags,
|
|
36
|
-
field.characterSet,
|
|
37
|
-
field.extendedTypeName,
|
|
38
|
-
field.extendedFormat,
|
|
39
|
-
]);
|
|
39
|
+
key = appendString(key, field.name);
|
|
40
|
+
key += `${field.columnType}/${field.length}/`;
|
|
41
|
+
key = appendString(key, field.schema);
|
|
42
|
+
key = appendString(key, field.table);
|
|
43
|
+
key += `${field.flags}/${field.characterSet}/`;
|
|
44
|
+
key = appendString(key, field.extendedTypeName);
|
|
45
|
+
key = appendString(key, field.extendedFormat);
|
|
40
46
|
}
|
|
41
47
|
|
|
42
|
-
return
|
|
48
|
+
return key;
|
|
43
49
|
}
|
|
44
50
|
|
|
45
51
|
function getParser(type, fields, options, config, compiler) {
|
package/lib/parsers/string.js
CHANGED
|
@@ -7,7 +7,48 @@ const decoderCache = createLRU({
|
|
|
7
7
|
max: 500,
|
|
8
8
|
});
|
|
9
9
|
|
|
10
|
+
// Direct slice methods skip the per-call encoding normalization and dispatch
|
|
11
|
+
// inside buffer.toString(); they have been stable Node internals for years
|
|
12
|
+
// but fall back gracefully where missing (other runtimes)
|
|
13
|
+
const hasFastSlices =
|
|
14
|
+
typeof Buffer.prototype.utf8Slice === 'function' &&
|
|
15
|
+
typeof Buffer.prototype.latin1Slice === 'function' &&
|
|
16
|
+
typeof Buffer.prototype.asciiSlice === 'function';
|
|
17
|
+
|
|
10
18
|
exports.decode = function (buffer, encoding, start, end, options) {
|
|
19
|
+
if (hasFastSlices) {
|
|
20
|
+
// replicate buffer.toString() bounds coercion exactly (the *Slice
|
|
21
|
+
// methods throw on anything out of range): negative, NaN, fractional
|
|
22
|
+
// and oversized offsets all clamp instead of throwing
|
|
23
|
+
const len = buffer.length;
|
|
24
|
+
if (start <= 0) {
|
|
25
|
+
start = 0;
|
|
26
|
+
} else if (start >= len) {
|
|
27
|
+
return '';
|
|
28
|
+
} else {
|
|
29
|
+
start |= 0;
|
|
30
|
+
}
|
|
31
|
+
if (end === undefined || end > len) {
|
|
32
|
+
end = len;
|
|
33
|
+
} else {
|
|
34
|
+
end |= 0;
|
|
35
|
+
}
|
|
36
|
+
if (end <= start) {
|
|
37
|
+
return '';
|
|
38
|
+
}
|
|
39
|
+
switch (encoding) {
|
|
40
|
+
case 'utf8':
|
|
41
|
+
case 'utf-8':
|
|
42
|
+
return buffer.utf8Slice(start, end);
|
|
43
|
+
case 'latin1':
|
|
44
|
+
case 'binary':
|
|
45
|
+
return buffer.latin1Slice(start, end);
|
|
46
|
+
case 'ascii':
|
|
47
|
+
return buffer.asciiSlice(start, end);
|
|
48
|
+
default:
|
|
49
|
+
break;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
11
52
|
if (Buffer.isEncoding(encoding)) {
|
|
12
53
|
return buffer.toString(encoding, start, end);
|
|
13
54
|
}
|
|
@@ -30,7 +30,9 @@ class PromiseConnection extends EventEmitter {
|
|
|
30
30
|
|
|
31
31
|
query(query, params) {
|
|
32
32
|
const c = this.connection;
|
|
33
|
-
const stackHolder =
|
|
33
|
+
const stackHolder = c.config.trace
|
|
34
|
+
? captureStackHolder(PromiseConnection.prototype.query)
|
|
35
|
+
: undefined;
|
|
34
36
|
if (typeof params === 'function') {
|
|
35
37
|
throw new Error(
|
|
36
38
|
'Callback function is not available with promise clients.'
|
|
@@ -48,7 +50,9 @@ class PromiseConnection extends EventEmitter {
|
|
|
48
50
|
|
|
49
51
|
execute(query, params) {
|
|
50
52
|
const c = this.connection;
|
|
51
|
-
const stackHolder =
|
|
53
|
+
const stackHolder = c.config.trace
|
|
54
|
+
? captureStackHolder(PromiseConnection.prototype.execute)
|
|
55
|
+
: undefined;
|
|
52
56
|
if (typeof params === 'function') {
|
|
53
57
|
throw new Error(
|
|
54
58
|
'Callback function is not available with promise clients.'
|
package/lib/promise/pool.js
CHANGED
|
@@ -37,7 +37,9 @@ class PromisePool extends EventEmitter {
|
|
|
37
37
|
|
|
38
38
|
query(sql, args) {
|
|
39
39
|
const corePool = this.pool;
|
|
40
|
-
const stackHolder =
|
|
40
|
+
const stackHolder = corePool.config.connectionConfig.trace
|
|
41
|
+
? captureStackHolder(PromisePool.prototype.query)
|
|
42
|
+
: undefined;
|
|
41
43
|
if (typeof args === 'function') {
|
|
42
44
|
throw new Error(
|
|
43
45
|
'Callback function is not available with promise clients.'
|
|
@@ -55,7 +57,9 @@ class PromisePool extends EventEmitter {
|
|
|
55
57
|
|
|
56
58
|
execute(sql, args) {
|
|
57
59
|
const corePool = this.pool;
|
|
58
|
-
const stackHolder =
|
|
60
|
+
const stackHolder = corePool.config.connectionConfig.trace
|
|
61
|
+
? captureStackHolder(PromisePool.prototype.execute)
|
|
62
|
+
: undefined;
|
|
59
63
|
if (typeof args === 'function') {
|
|
60
64
|
throw new Error(
|
|
61
65
|
'Callback function is not available with promise clients.'
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@depup/mysql2",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.24.0-depup.0",
|
|
4
4
|
"description": "fast mysql driver. Implements core protocol, prepared statements, ssl and compression in native JS (with updated dependencies)",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"typings": "typings/mysql/index",
|
|
@@ -95,8 +95,8 @@
|
|
|
95
95
|
"changes": {},
|
|
96
96
|
"depsUpdated": 0,
|
|
97
97
|
"originalPackage": "mysql2",
|
|
98
|
-
"originalVersion": "3.
|
|
99
|
-
"processedAt": "2026-08-
|
|
98
|
+
"originalVersion": "3.24.0",
|
|
99
|
+
"processedAt": "2026-08-24T00:15:48.665Z",
|
|
100
100
|
"smokeTest": "passed"
|
|
101
101
|
}
|
|
102
102
|
}
|
package/promise.js
CHANGED
|
@@ -192,6 +192,11 @@ exports.PromisePoolConnection = PromisePoolConnection;
|
|
|
192
192
|
|
|
193
193
|
exports.__defineGetter__('Types', () => require('./lib/constants/types.js'));
|
|
194
194
|
|
|
195
|
+
exports.__defineGetter__(
|
|
196
|
+
'TypedParameter',
|
|
197
|
+
() => require('./lib/packets/typed_parameter.js').types
|
|
198
|
+
);
|
|
199
|
+
|
|
195
200
|
exports.__defineGetter__('Charsets', () =>
|
|
196
201
|
require('./lib/constants/charsets.js')
|
|
197
202
|
);
|
package/typings/mysql/index.d.ts
CHANGED
|
@@ -46,6 +46,7 @@ export * from './lib/protocol/packets/index.js';
|
|
|
46
46
|
export * from './lib/Auth.js';
|
|
47
47
|
export * from './lib/constants/index.js';
|
|
48
48
|
export * from './lib/parsers/index.js';
|
|
49
|
+
export * from './lib/TypedParameter.js';
|
|
49
50
|
export * from './lib/Connection.js';
|
|
50
51
|
export * from './lib/PoolConnection.js';
|
|
51
52
|
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A bind parameter carrying an explicit MySQL type.
|
|
3
|
+
*
|
|
4
|
+
* Produced by the `TypedParameter` factories and accepted anywhere
|
|
5
|
+
* `execute()` takes a value. The declared type is sent verbatim in
|
|
6
|
+
* `COM_STMT_EXECUTE` instead of being inferred from the JavaScript type.
|
|
7
|
+
*/
|
|
8
|
+
export interface TypedParameterValue {
|
|
9
|
+
readonly type: number;
|
|
10
|
+
readonly value: unknown;
|
|
11
|
+
readonly unsigned: boolean;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export type TypedParameterInput =
|
|
15
|
+
string | number | bigint | boolean | Date | Buffer | Uint8Array | null;
|
|
16
|
+
|
|
17
|
+
export interface TypedParameterFactory {
|
|
18
|
+
(value: TypedParameterInput): TypedParameterValue;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface IntegerTypedParameterFactory extends TypedParameterFactory {
|
|
22
|
+
unsigned(value: TypedParameterInput): TypedParameterValue;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface JsonTypedParameterFactory {
|
|
26
|
+
(value: TypedParameterInput | object): TypedParameterValue;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface TypedParameter {
|
|
30
|
+
TINY: IntegerTypedParameterFactory;
|
|
31
|
+
SHORT: IntegerTypedParameterFactory;
|
|
32
|
+
YEAR: IntegerTypedParameterFactory;
|
|
33
|
+
INT24: IntegerTypedParameterFactory;
|
|
34
|
+
LONG: IntegerTypedParameterFactory;
|
|
35
|
+
LONGLONG: IntegerTypedParameterFactory;
|
|
36
|
+
|
|
37
|
+
TINYINT: IntegerTypedParameterFactory;
|
|
38
|
+
SMALLINT: IntegerTypedParameterFactory;
|
|
39
|
+
MEDIUMINT: IntegerTypedParameterFactory;
|
|
40
|
+
INT: IntegerTypedParameterFactory;
|
|
41
|
+
INTEGER: IntegerTypedParameterFactory;
|
|
42
|
+
BIGINT: IntegerTypedParameterFactory;
|
|
43
|
+
|
|
44
|
+
FLOAT: TypedParameterFactory;
|
|
45
|
+
DOUBLE: TypedParameterFactory;
|
|
46
|
+
REAL: TypedParameterFactory;
|
|
47
|
+
|
|
48
|
+
DATE: TypedParameterFactory;
|
|
49
|
+
DATETIME: TypedParameterFactory;
|
|
50
|
+
TIMESTAMP: TypedParameterFactory;
|
|
51
|
+
TIME: TypedParameterFactory;
|
|
52
|
+
|
|
53
|
+
DECIMAL: TypedParameterFactory;
|
|
54
|
+
NEWDECIMAL: TypedParameterFactory;
|
|
55
|
+
VARCHAR: TypedParameterFactory;
|
|
56
|
+
VAR_STRING: TypedParameterFactory;
|
|
57
|
+
STRING: TypedParameterFactory;
|
|
58
|
+
CHAR: TypedParameterFactory;
|
|
59
|
+
VARBINARY: TypedParameterFactory;
|
|
60
|
+
BINARY: TypedParameterFactory;
|
|
61
|
+
ENUM: TypedParameterFactory;
|
|
62
|
+
SET: TypedParameterFactory;
|
|
63
|
+
BIT: TypedParameterFactory;
|
|
64
|
+
GEOMETRY: TypedParameterFactory;
|
|
65
|
+
VECTOR: TypedParameterFactory;
|
|
66
|
+
TINY_BLOB: TypedParameterFactory;
|
|
67
|
+
MEDIUM_BLOB: TypedParameterFactory;
|
|
68
|
+
LONG_BLOB: TypedParameterFactory;
|
|
69
|
+
BLOB: TypedParameterFactory;
|
|
70
|
+
TEXT: TypedParameterFactory;
|
|
71
|
+
|
|
72
|
+
JSON: JsonTypedParameterFactory;
|
|
73
|
+
|
|
74
|
+
NULL(): TypedParameterValue;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Constant `TypedParameter`.
|
|
79
|
+
*
|
|
80
|
+
* Please note that `TypedParameter` can only be accessed from the `mysql` object and not imported directly.
|
|
81
|
+
*/
|
|
82
|
+
declare const TypedParameter: TypedParameter;
|
|
83
|
+
|
|
84
|
+
export { TypedParameter };
|
|
@@ -3,8 +3,10 @@ import { OkPacket, RowDataPacket, FieldPacket } from '../packets/index.js';
|
|
|
3
3
|
import { Readable } from 'stream';
|
|
4
4
|
import { Raw, Timezone } from 'sql-escaper';
|
|
5
5
|
import { TypeCast } from '../../parsers/typeCast.js';
|
|
6
|
+
import { TypedParameterValue } from '../../TypedParameter.js';
|
|
6
7
|
|
|
7
8
|
export type ExecuteValues =
|
|
9
|
+
| TypedParameterValue
|
|
8
10
|
| string
|
|
9
11
|
| number
|
|
10
12
|
| bigint
|