@depup/mysql2 3.19.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.
Files changed (124) hide show
  1. package/License +19 -0
  2. package/README.md +114 -0
  3. package/index.d.ts +1 -0
  4. package/index.js +77 -0
  5. package/lib/auth_41.js +95 -0
  6. package/lib/auth_plugins/caching_sha2_password.js +114 -0
  7. package/lib/auth_plugins/caching_sha2_password.md +18 -0
  8. package/lib/auth_plugins/index.js +8 -0
  9. package/lib/auth_plugins/mysql_clear_password.js +17 -0
  10. package/lib/auth_plugins/mysql_native_password.js +34 -0
  11. package/lib/auth_plugins/sha256_password.js +68 -0
  12. package/lib/base/connection.js +988 -0
  13. package/lib/base/pool.js +282 -0
  14. package/lib/base/pool_connection.js +77 -0
  15. package/lib/commands/auth_switch.js +129 -0
  16. package/lib/commands/binlog_dump.js +109 -0
  17. package/lib/commands/change_user.js +68 -0
  18. package/lib/commands/client_handshake.js +383 -0
  19. package/lib/commands/close_statement.js +18 -0
  20. package/lib/commands/command.js +54 -0
  21. package/lib/commands/execute.js +112 -0
  22. package/lib/commands/index.js +27 -0
  23. package/lib/commands/ping.js +36 -0
  24. package/lib/commands/prepare.js +143 -0
  25. package/lib/commands/query.js +361 -0
  26. package/lib/commands/quit.js +29 -0
  27. package/lib/commands/register_slave.js +27 -0
  28. package/lib/commands/server_handshake.js +202 -0
  29. package/lib/compressed_protocol.js +153 -0
  30. package/lib/connection.js +12 -0
  31. package/lib/connection_config.js +293 -0
  32. package/lib/constants/charset_encodings.js +317 -0
  33. package/lib/constants/charsets.js +317 -0
  34. package/lib/constants/client.js +38 -0
  35. package/lib/constants/commands.js +36 -0
  36. package/lib/constants/cursor.js +8 -0
  37. package/lib/constants/encoding_charset.js +50 -0
  38. package/lib/constants/errors.js +3973 -0
  39. package/lib/constants/field_flags.js +20 -0
  40. package/lib/constants/server_status.js +44 -0
  41. package/lib/constants/session_track.js +11 -0
  42. package/lib/constants/ssl_profiles.js +11 -0
  43. package/lib/constants/types.js +64 -0
  44. package/lib/create_connection.js +10 -0
  45. package/lib/create_pool.js +10 -0
  46. package/lib/create_pool_cluster.js +9 -0
  47. package/lib/helpers.js +83 -0
  48. package/lib/packet_parser.js +195 -0
  49. package/lib/packets/auth_next_factor.js +35 -0
  50. package/lib/packets/auth_switch_request.js +38 -0
  51. package/lib/packets/auth_switch_request_more_data.js +33 -0
  52. package/lib/packets/auth_switch_response.js +30 -0
  53. package/lib/packets/binary_row.js +95 -0
  54. package/lib/packets/binlog_dump.js +33 -0
  55. package/lib/packets/binlog_query_statusvars.js +115 -0
  56. package/lib/packets/change_user.js +97 -0
  57. package/lib/packets/close_statement.js +21 -0
  58. package/lib/packets/column_definition.js +291 -0
  59. package/lib/packets/execute.js +214 -0
  60. package/lib/packets/handshake.js +112 -0
  61. package/lib/packets/handshake_response.js +173 -0
  62. package/lib/packets/index.js +152 -0
  63. package/lib/packets/packet.js +946 -0
  64. package/lib/packets/prepare_statement.js +27 -0
  65. package/lib/packets/prepared_statement_header.js +16 -0
  66. package/lib/packets/query.js +27 -0
  67. package/lib/packets/register_slave.js +46 -0
  68. package/lib/packets/resultset_header.js +124 -0
  69. package/lib/packets/ssl_request.js +25 -0
  70. package/lib/packets/text_row.js +47 -0
  71. package/lib/parsers/binary_parser.js +235 -0
  72. package/lib/parsers/parser_cache.js +68 -0
  73. package/lib/parsers/static_binary_parser.js +213 -0
  74. package/lib/parsers/static_text_parser.js +152 -0
  75. package/lib/parsers/string.js +50 -0
  76. package/lib/parsers/text_parser.js +214 -0
  77. package/lib/pool.js +12 -0
  78. package/lib/pool_cluster.js +375 -0
  79. package/lib/pool_config.js +30 -0
  80. package/lib/pool_connection.js +12 -0
  81. package/lib/promise/connection.js +228 -0
  82. package/lib/promise/inherit_events.js +27 -0
  83. package/lib/promise/make_done_cb.js +19 -0
  84. package/lib/promise/pool.js +118 -0
  85. package/lib/promise/pool_cluster.js +54 -0
  86. package/lib/promise/pool_connection.js +23 -0
  87. package/lib/promise/prepared_statement_info.js +32 -0
  88. package/lib/results_stream.js +38 -0
  89. package/lib/server.js +37 -0
  90. package/package.json +96 -0
  91. package/promise.d.ts +139 -0
  92. package/promise.js +208 -0
  93. package/typings/mysql/LICENSE.txt +15 -0
  94. package/typings/mysql/index.d.ts +84 -0
  95. package/typings/mysql/info.txt +1 -0
  96. package/typings/mysql/lib/Auth.d.ts +30 -0
  97. package/typings/mysql/lib/Connection.d.ts +442 -0
  98. package/typings/mysql/lib/Pool.d.ts +71 -0
  99. package/typings/mysql/lib/PoolCluster.d.ts +92 -0
  100. package/typings/mysql/lib/PoolConnection.d.ts +11 -0
  101. package/typings/mysql/lib/Server.d.ts +11 -0
  102. package/typings/mysql/lib/constants/CharsetToEncoding.d.ts +8 -0
  103. package/typings/mysql/lib/constants/Charsets.d.ts +326 -0
  104. package/typings/mysql/lib/constants/Types.d.ts +70 -0
  105. package/typings/mysql/lib/constants/index.d.ts +5 -0
  106. package/typings/mysql/lib/parsers/ParserCache.d.ts +4 -0
  107. package/typings/mysql/lib/parsers/index.d.ts +18 -0
  108. package/typings/mysql/lib/parsers/typeCast.d.ts +54 -0
  109. package/typings/mysql/lib/protocol/packets/Field.d.ts +10 -0
  110. package/typings/mysql/lib/protocol/packets/FieldPacket.d.ts +27 -0
  111. package/typings/mysql/lib/protocol/packets/OkPacket.d.ts +23 -0
  112. package/typings/mysql/lib/protocol/packets/ProcedurePacket.d.ts +13 -0
  113. package/typings/mysql/lib/protocol/packets/ResultSetHeader.d.ts +18 -0
  114. package/typings/mysql/lib/protocol/packets/RowDataPacket.d.ts +9 -0
  115. package/typings/mysql/lib/protocol/packets/index.d.ts +28 -0
  116. package/typings/mysql/lib/protocol/packets/params/ErrorPacketParams.d.ts +6 -0
  117. package/typings/mysql/lib/protocol/packets/params/OkPacketParams.d.ts +9 -0
  118. package/typings/mysql/lib/protocol/sequences/ExecutableBase.d.ts +41 -0
  119. package/typings/mysql/lib/protocol/sequences/Prepare.d.ts +65 -0
  120. package/typings/mysql/lib/protocol/sequences/Query.d.ts +228 -0
  121. package/typings/mysql/lib/protocol/sequences/QueryableBase.d.ts +41 -0
  122. package/typings/mysql/lib/protocol/sequences/Sequence.d.ts +5 -0
  123. package/typings/mysql/lib/protocol/sequences/promise/ExecutableBase.d.ts +17 -0
  124. package/typings/mysql/lib/protocol/sequences/promise/QueryableBase.d.ts +18 -0
@@ -0,0 +1,946 @@
1
+ // This file was modified by Oracle on June 1, 2021.
2
+ // A comment describing some changes in the strict default SQL mode regarding
3
+ // non-standard dates was introduced.
4
+ // Modifications copyright (c) 2021, Oracle and/or its affiliates.
5
+
6
+ 'use strict';
7
+
8
+ const ErrorCodeToName = require('../constants/errors.js');
9
+ const NativeBuffer = require('buffer').Buffer;
10
+ const Long = require('long');
11
+ const StringParser = require('../parsers/string.js');
12
+ const Types = require('../constants/types.js');
13
+ const INVALID_DATE = new Date(NaN);
14
+
15
+ // this is nearly duplicate of previous function so generated code is not slower
16
+ // due to "if (dateStrings)" branching
17
+ const pad = '000000000000';
18
+ function leftPad(num, value) {
19
+ const s = value.toString();
20
+ // if we don't need to pad
21
+ if (s.length >= num) {
22
+ return s;
23
+ }
24
+ return (pad + s).slice(-num);
25
+ }
26
+
27
+ // The whole reason parse* function below exist
28
+ // is because String creation is relatively expensive (at least with V8), and if we have
29
+ // a buffer with "12345" content ideally we would like to bypass intermediate
30
+ // "12345" string creation and directly build 12345 number out of
31
+ // <Buffer 31 32 33 34 35> data.
32
+ // In my benchmarks the difference is ~25M 8-digit numbers per second vs
33
+ // 4.5 M using Number(packet.readLengthCodedString())
34
+ // not used when size is close to max precision as series of *10 accumulate error
35
+ // and approximate result mihgt be diffreent from (approximate as well) Number(bigNumStringValue))
36
+ // In the futire node version if speed difference is smaller parse* functions might be removed
37
+ // don't consider them as Packet public API
38
+
39
+ const minus = '-'.charCodeAt(0);
40
+ const plus = '+'.charCodeAt(0);
41
+
42
+ // TODO: handle E notation
43
+ const dot = '.'.charCodeAt(0);
44
+ const exponent = 'e'.charCodeAt(0);
45
+ const exponentCapital = 'E'.charCodeAt(0);
46
+
47
+ class Packet {
48
+ constructor(id, buffer, start, end) {
49
+ // hot path, enable checks when testing only
50
+ // if (!Buffer.isBuffer(buffer) || typeof start == 'undefined' || typeof end == 'undefined')
51
+ // throw new Error('invalid packet');
52
+ this.sequenceId = id;
53
+ this.numPackets = 1;
54
+ this.buffer = buffer;
55
+ this.start = start;
56
+ this.offset = start + 4;
57
+ this.end = end;
58
+ }
59
+
60
+ // ==============================
61
+ // readers
62
+ // ==============================
63
+ reset() {
64
+ this.offset = this.start + 4;
65
+ }
66
+
67
+ length() {
68
+ return this.end - this.start;
69
+ }
70
+
71
+ slice() {
72
+ return this.buffer.slice(this.start, this.end);
73
+ }
74
+
75
+ dump() {
76
+ console.log(
77
+ [this.buffer.asciiSlice(this.start, this.end)],
78
+ this.buffer.slice(this.start, this.end),
79
+ this.length(),
80
+ this.sequenceId
81
+ );
82
+ }
83
+
84
+ haveMoreData() {
85
+ return this.end > this.offset;
86
+ }
87
+
88
+ skip(num) {
89
+ this.offset += num;
90
+ }
91
+
92
+ readInt8() {
93
+ return this.buffer[this.offset++];
94
+ }
95
+
96
+ readInt16() {
97
+ this.offset += 2;
98
+ return this.buffer.readUInt16LE(this.offset - 2);
99
+ }
100
+
101
+ readInt24() {
102
+ return this.readInt16() + (this.readInt8() << 16);
103
+ }
104
+
105
+ readInt32() {
106
+ this.offset += 4;
107
+ return this.buffer.readUInt32LE(this.offset - 4);
108
+ }
109
+
110
+ readSInt8() {
111
+ return this.buffer.readInt8(this.offset++);
112
+ }
113
+
114
+ readSInt16() {
115
+ this.offset += 2;
116
+ return this.buffer.readInt16LE(this.offset - 2);
117
+ }
118
+
119
+ readSInt32() {
120
+ this.offset += 4;
121
+ return this.buffer.readInt32LE(this.offset - 4);
122
+ }
123
+
124
+ readInt64JSNumber() {
125
+ const word0 = this.readInt32();
126
+ const word1 = this.readInt32();
127
+ const l = new Long(word0, word1, true);
128
+ return l.toNumber();
129
+ }
130
+
131
+ readSInt64JSNumber() {
132
+ const word0 = this.readInt32();
133
+ const word1 = this.readInt32();
134
+ if (!(word1 & 0x80000000)) {
135
+ return word0 + 0x100000000 * word1;
136
+ }
137
+ const l = new Long(word0, word1, false);
138
+ return l.toNumber();
139
+ }
140
+
141
+ readInt64String() {
142
+ const word0 = this.readInt32();
143
+ const word1 = this.readInt32();
144
+ const res = new Long(word0, word1, true);
145
+ return res.toString();
146
+ }
147
+
148
+ readSInt64String() {
149
+ const word0 = this.readInt32();
150
+ const word1 = this.readInt32();
151
+ const res = new Long(word0, word1, false);
152
+ return res.toString();
153
+ }
154
+
155
+ readInt64() {
156
+ const word0 = this.readInt32();
157
+ const word1 = this.readInt32();
158
+ let res = new Long(word0, word1, true);
159
+ const resNumber = res.toNumber();
160
+ const resString = res.toString();
161
+ res = resNumber.toString() === resString ? resNumber : resString;
162
+ return res;
163
+ }
164
+
165
+ readSInt64() {
166
+ const word0 = this.readInt32();
167
+ const word1 = this.readInt32();
168
+ let res = new Long(word0, word1, false);
169
+ const resNumber = res.toNumber();
170
+ const resString = res.toString();
171
+ res = resNumber.toString() === resString ? resNumber : resString;
172
+ return res;
173
+ }
174
+
175
+ isEOF() {
176
+ return this.buffer[this.offset] === 0xfe && this.length() < 13;
177
+ }
178
+
179
+ eofStatusFlags() {
180
+ return this.buffer.readInt16LE(this.offset + 3);
181
+ }
182
+
183
+ eofWarningCount() {
184
+ return this.buffer.readInt16LE(this.offset + 1);
185
+ }
186
+
187
+ readLengthCodedNumber(bigNumberStrings, signed) {
188
+ const byte1 = this.buffer[this.offset++];
189
+ if (byte1 < 251) {
190
+ return byte1;
191
+ }
192
+ return this.readLengthCodedNumberExt(byte1, bigNumberStrings, signed);
193
+ }
194
+
195
+ readLengthCodedNumberSigned(bigNumberStrings) {
196
+ return this.readLengthCodedNumber(bigNumberStrings, true);
197
+ }
198
+
199
+ readLengthCodedNumberExt(tag, bigNumberStrings, signed) {
200
+ let word0, word1;
201
+ let res;
202
+ if (tag === 0xfb) {
203
+ return null;
204
+ }
205
+ if (tag === 0xfc) {
206
+ return this.readInt8() + (this.readInt8() << 8);
207
+ }
208
+ if (tag === 0xfd) {
209
+ return this.readInt8() + (this.readInt8() << 8) + (this.readInt8() << 16);
210
+ }
211
+ if (tag === 0xfe) {
212
+ // TODO: check version
213
+ // Up to MySQL 3.22, 0xfe was followed by a 4-byte integer.
214
+ word0 = this.readInt32();
215
+ word1 = this.readInt32();
216
+ if (word1 === 0) {
217
+ return word0; // don't convert to float if possible
218
+ }
219
+ if (word1 < 2097152) {
220
+ // max exact float point int, 2^52 / 2^32
221
+ return word1 * 0x100000000 + word0;
222
+ }
223
+ res = new Long(word0, word1, !signed); // Long need unsigned
224
+ const resNumber = res.toNumber();
225
+ const resString = res.toString();
226
+ res = resNumber.toString() === resString ? resNumber : resString;
227
+ return bigNumberStrings ? resString : res;
228
+ }
229
+
230
+ console.trace();
231
+ throw new Error(`Should not reach here: ${tag}`);
232
+ }
233
+
234
+ readFloat() {
235
+ const res = this.buffer.readFloatLE(this.offset);
236
+ this.offset += 4;
237
+ return res;
238
+ }
239
+
240
+ readDouble() {
241
+ const res = this.buffer.readDoubleLE(this.offset);
242
+ this.offset += 8;
243
+ return res;
244
+ }
245
+
246
+ readBuffer(len) {
247
+ if (typeof len === 'undefined') {
248
+ len = this.end - this.offset;
249
+ }
250
+ this.offset += len;
251
+ return this.buffer.slice(this.offset - len, this.offset);
252
+ }
253
+
254
+ // DATE, DATETIME and TIMESTAMP
255
+ readDateTime(timezone) {
256
+ if (!timezone || timezone === 'Z' || timezone === 'local') {
257
+ const length = this.readInt8();
258
+ if (length === 0xfb) {
259
+ return null;
260
+ }
261
+ let y = 0;
262
+ let m = 0;
263
+ let d = 0;
264
+ let H = 0;
265
+ let M = 0;
266
+ let S = 0;
267
+ let ms = 0;
268
+ if (length > 3) {
269
+ y = this.readInt16();
270
+ m = this.readInt8();
271
+ d = this.readInt8();
272
+ }
273
+ if (length > 6) {
274
+ H = this.readInt8();
275
+ M = this.readInt8();
276
+ S = this.readInt8();
277
+ }
278
+ if (length > 10) {
279
+ ms = this.readInt32() / 1000;
280
+ }
281
+ // NO_ZERO_DATE mode and NO_ZERO_IN_DATE mode are part of the strict
282
+ // default SQL mode used by MySQL 8.0. This means that non-standard
283
+ // dates like '0000-00-00' become NULL. For older versions and other
284
+ // possible MySQL flavours we still need to account for the
285
+ // non-standard behaviour.
286
+ if (y + m + d + H + M + S + ms === 0) {
287
+ return INVALID_DATE;
288
+ }
289
+ if (timezone === 'Z') {
290
+ return new Date(Date.UTC(y, m - 1, d, H, M, S, ms));
291
+ }
292
+ return new Date(y, m - 1, d, H, M, S, ms);
293
+ }
294
+ let str = this.readDateTimeString(6, 'T', null);
295
+ if (str.length === 10) {
296
+ str += 'T00:00:00';
297
+ }
298
+ return new Date(str + timezone);
299
+ }
300
+
301
+ readDateTimeString(decimals, timeSep, columnType) {
302
+ const length = this.readInt8();
303
+ let y = 0;
304
+ let m = 0;
305
+ let d = 0;
306
+ let H = 0;
307
+ let M = 0;
308
+ let S = 0;
309
+ let ms = 0;
310
+ let str;
311
+ if (length > 3) {
312
+ y = this.readInt16();
313
+ m = this.readInt8();
314
+ d = this.readInt8();
315
+ str = [leftPad(4, y), leftPad(2, m), leftPad(2, d)].join('-');
316
+ }
317
+ if (length > 6) {
318
+ H = this.readInt8();
319
+ M = this.readInt8();
320
+ S = this.readInt8();
321
+ str += `${timeSep || ' '}${[
322
+ leftPad(2, H),
323
+ leftPad(2, M),
324
+ leftPad(2, S),
325
+ ].join(':')}`;
326
+ } else if (columnType === Types.DATETIME) {
327
+ str += ' 00:00:00';
328
+ }
329
+ if (length > 10) {
330
+ ms = this.readInt32();
331
+ str += '.';
332
+ if (decimals) {
333
+ ms = leftPad(6, ms);
334
+ if (ms.length > decimals) {
335
+ ms = ms.substring(0, decimals); // rounding is done at the MySQL side, only 0 are here
336
+ }
337
+ }
338
+ str += ms;
339
+ }
340
+ return str;
341
+ }
342
+
343
+ // TIME - value as a string, Can be negative
344
+ readTimeString(convertTtoMs) {
345
+ const length = this.readInt8();
346
+ if (length === 0) {
347
+ return '00:00:00';
348
+ }
349
+ const sign = this.readInt8() ? -1 : 1; // 'isNegative' flag byte
350
+ let d = 0;
351
+ let H = 0;
352
+ let M = 0;
353
+ let S = 0;
354
+ let ms = 0;
355
+ if (length > 6) {
356
+ d = this.readInt32();
357
+ H = this.readInt8();
358
+ M = this.readInt8();
359
+ S = this.readInt8();
360
+ }
361
+ if (length > 10) {
362
+ ms = this.readInt32();
363
+ }
364
+ if (convertTtoMs) {
365
+ H += d * 24;
366
+ M += H * 60;
367
+ S += M * 60;
368
+ ms += S * 1000;
369
+ ms *= sign;
370
+ return ms;
371
+ }
372
+ // Format follows mySQL TIME format ([-][h]hh:mm:ss[.u[u[u[u[u[u]]]]]])
373
+ // For positive times below 24 hours, this makes it equal to ISO 8601 times
374
+ return (
375
+ (sign === -1 ? '-' : '') +
376
+ [leftPad(2, d * 24 + H), leftPad(2, M), leftPad(2, S)].join(':') +
377
+ (ms ? `.${ms}`.replace(/0+$/, '') : '')
378
+ );
379
+ }
380
+
381
+ readLengthCodedString(encoding) {
382
+ const len = this.readLengthCodedNumber();
383
+ // TODO: check manually first byte here to avoid polymorphic return type?
384
+ if (len === null) {
385
+ return null;
386
+ }
387
+ this.offset += len;
388
+ // TODO: Use characterSetCode to get proper encoding
389
+ // https://github.com/sidorares/node-mysql2/pull/374
390
+ return StringParser.decode(
391
+ this.buffer,
392
+ encoding,
393
+ this.offset - len,
394
+ this.offset
395
+ );
396
+ }
397
+
398
+ readLengthCodedBuffer() {
399
+ const len = this.readLengthCodedNumber();
400
+ if (len === null) {
401
+ return null;
402
+ }
403
+ return this.readBuffer(len);
404
+ }
405
+
406
+ readNullTerminatedString(encoding) {
407
+ const start = this.offset;
408
+ let end = this.offset;
409
+ while (this.buffer[end]) {
410
+ end = end + 1; // TODO: handle OOB check
411
+ }
412
+ this.offset = end + 1;
413
+ return StringParser.decode(this.buffer, encoding, start, end);
414
+ }
415
+
416
+ // TODO reuse?
417
+ readString(len, encoding) {
418
+ if (typeof len === 'string' && typeof encoding === 'undefined') {
419
+ encoding = len;
420
+ len = undefined;
421
+ }
422
+ if (typeof len === 'undefined') {
423
+ len = this.end - this.offset;
424
+ }
425
+ this.offset += len;
426
+ return StringParser.decode(
427
+ this.buffer,
428
+ encoding,
429
+ this.offset - len,
430
+ this.offset
431
+ );
432
+ }
433
+
434
+ parseInt(len, supportBigNumbers) {
435
+ if (len === null) {
436
+ return null;
437
+ }
438
+ if (len >= 14 && !supportBigNumbers) {
439
+ const s = this.buffer.toString('ascii', this.offset, this.offset + len);
440
+ this.offset += len;
441
+ return Number(s);
442
+ }
443
+ let result = 0;
444
+ const start = this.offset;
445
+ const end = this.offset + len;
446
+ let sign = 1;
447
+ if (len === 0) {
448
+ return 0; // TODO: assert? exception?
449
+ }
450
+ if (this.buffer[this.offset] === minus) {
451
+ this.offset++;
452
+ sign = -1;
453
+ }
454
+ // max precise int is 9007199254740992
455
+ let str;
456
+ const numDigits = end - this.offset;
457
+ if (supportBigNumbers) {
458
+ if (numDigits >= 15) {
459
+ str = this.readString(end - this.offset, 'binary');
460
+ result = parseInt(str, 10);
461
+ if (result.toString() === str) {
462
+ return sign * result;
463
+ }
464
+ return sign === -1 ? `-${str}` : str;
465
+ }
466
+ if (numDigits > 16) {
467
+ str = this.readString(end - this.offset);
468
+ return sign === -1 ? `-${str}` : str;
469
+ }
470
+ }
471
+ if (this.buffer[this.offset] === plus) {
472
+ this.offset++; // just ignore
473
+ }
474
+ while (this.offset < end) {
475
+ result *= 10;
476
+ result += this.buffer[this.offset] - 48;
477
+ this.offset++;
478
+ }
479
+ const num = result * sign;
480
+ if (!supportBigNumbers) {
481
+ return num;
482
+ }
483
+ str = this.buffer.toString('ascii', start, end);
484
+ if (num.toString() === str) {
485
+ return num;
486
+ }
487
+ return str;
488
+ }
489
+
490
+ // note that if value of inputNumberAsString is bigger than MAX_SAFE_INTEGER
491
+ // ( or smaller than MIN_SAFE_INTEGER ) the parseIntNoBigCheck result might be
492
+ // different from what you would get from Number(inputNumberAsString)
493
+ // String(parseIntNoBigCheck) <> String(Number(inputNumberAsString)) <> inputNumberAsString
494
+ parseIntNoBigCheck(len) {
495
+ if (len === null) {
496
+ return null;
497
+ }
498
+ let result = 0;
499
+ const end = this.offset + len;
500
+ let sign = 1;
501
+ if (len === 0) {
502
+ return 0; // TODO: assert? exception?
503
+ }
504
+ if (this.buffer[this.offset] === minus) {
505
+ this.offset++;
506
+ sign = -1;
507
+ }
508
+ if (this.buffer[this.offset] === plus) {
509
+ this.offset++; // just ignore
510
+ }
511
+ while (this.offset < end) {
512
+ result *= 10;
513
+ result += this.buffer[this.offset] - 48;
514
+ this.offset++;
515
+ }
516
+ return result * sign;
517
+ }
518
+
519
+ // copy-paste from https://github.com/mysqljs/mysql/blob/master/lib/protocol/Parser.js
520
+ parseGeometryValue() {
521
+ const buffer = this.readLengthCodedBuffer();
522
+ let offset = 4;
523
+ if (buffer === null || !buffer.length) {
524
+ return null;
525
+ }
526
+ function parseGeometry() {
527
+ let x, y, i, j, numPoints, line;
528
+ let result = null;
529
+ const byteOrder = buffer.readUInt8(offset);
530
+ offset += 1;
531
+ const wkbType = byteOrder
532
+ ? buffer.readUInt32LE(offset)
533
+ : buffer.readUInt32BE(offset);
534
+ offset += 4;
535
+ switch (wkbType) {
536
+ case 1: // WKBPoint
537
+ x = byteOrder
538
+ ? buffer.readDoubleLE(offset)
539
+ : buffer.readDoubleBE(offset);
540
+ offset += 8;
541
+ y = byteOrder
542
+ ? buffer.readDoubleLE(offset)
543
+ : buffer.readDoubleBE(offset);
544
+ offset += 8;
545
+ result = { x: x, y: y };
546
+ break;
547
+ case 2: // WKBLineString
548
+ numPoints = byteOrder
549
+ ? buffer.readUInt32LE(offset)
550
+ : buffer.readUInt32BE(offset);
551
+ offset += 4;
552
+ result = [];
553
+ for (i = numPoints; i > 0; i--) {
554
+ x = byteOrder
555
+ ? buffer.readDoubleLE(offset)
556
+ : buffer.readDoubleBE(offset);
557
+ offset += 8;
558
+ y = byteOrder
559
+ ? buffer.readDoubleLE(offset)
560
+ : buffer.readDoubleBE(offset);
561
+ offset += 8;
562
+ result.push({ x: x, y: y });
563
+ }
564
+ break;
565
+ case 3: // WKBPolygon
566
+ // eslint-disable-next-line no-case-declarations
567
+ const numRings = byteOrder
568
+ ? buffer.readUInt32LE(offset)
569
+ : buffer.readUInt32BE(offset);
570
+ offset += 4;
571
+ result = [];
572
+ for (i = numRings; i > 0; i--) {
573
+ numPoints = byteOrder
574
+ ? buffer.readUInt32LE(offset)
575
+ : buffer.readUInt32BE(offset);
576
+ offset += 4;
577
+ line = [];
578
+ for (j = numPoints; j > 0; j--) {
579
+ x = byteOrder
580
+ ? buffer.readDoubleLE(offset)
581
+ : buffer.readDoubleBE(offset);
582
+ offset += 8;
583
+ y = byteOrder
584
+ ? buffer.readDoubleLE(offset)
585
+ : buffer.readDoubleBE(offset);
586
+ offset += 8;
587
+ line.push({ x: x, y: y });
588
+ }
589
+ result.push(line);
590
+ }
591
+ break;
592
+ case 4: // WKBMultiPoint
593
+ case 5: // WKBMultiLineString
594
+ case 6: // WKBMultiPolygon
595
+ case 7: // WKBGeometryCollection
596
+ // eslint-disable-next-line no-case-declarations
597
+ const num = byteOrder
598
+ ? buffer.readUInt32LE(offset)
599
+ : buffer.readUInt32BE(offset);
600
+ offset += 4;
601
+ result = [];
602
+ for (i = num; i > 0; i--) {
603
+ result.push(parseGeometry());
604
+ }
605
+ break;
606
+ }
607
+ return result;
608
+ }
609
+ return parseGeometry();
610
+ }
611
+
612
+ parseVector() {
613
+ const bufLen = this.readLengthCodedNumber();
614
+ const vectorEnd = this.offset + bufLen;
615
+ const result = [];
616
+ while (this.offset < vectorEnd && this.offset < this.end) {
617
+ result.push(this.readFloat());
618
+ }
619
+ return result;
620
+ }
621
+
622
+ parseDate(timezone) {
623
+ const strLen = this.readLengthCodedNumber();
624
+ if (strLen === null) {
625
+ return null;
626
+ }
627
+ if (strLen !== 10) {
628
+ // we expect only YYYY-MM-DD here.
629
+ // if for some reason it's not the case return invalid date
630
+ return new Date(NaN);
631
+ }
632
+ const y = this.parseInt(4);
633
+ this.offset++; // -
634
+ const m = this.parseInt(2);
635
+ this.offset++; // -
636
+ const d = this.parseInt(2);
637
+ if (!timezone || timezone === 'local') {
638
+ return new Date(y, m - 1, d);
639
+ }
640
+ if (timezone === 'Z') {
641
+ return new Date(Date.UTC(y, m - 1, d));
642
+ }
643
+ return new Date(
644
+ `${leftPad(4, y)}-${leftPad(2, m)}-${leftPad(2, d)}T00:00:00${timezone}`
645
+ );
646
+ }
647
+
648
+ parseDateTime(timezone) {
649
+ const str = this.readLengthCodedString('binary');
650
+ if (str === null) {
651
+ return null;
652
+ }
653
+ if (!timezone || timezone === 'local') {
654
+ return new Date(str);
655
+ }
656
+ return new Date(`${str}${timezone}`);
657
+ }
658
+
659
+ parseFloat(len) {
660
+ if (len === null) {
661
+ return null;
662
+ }
663
+ if (len === 0) {
664
+ return 0; // TODO: assert? exception?
665
+ }
666
+
667
+ // For numbers with many digits (>17), use built-in parseFloat to avoid
668
+ // precision loss from accumulated rounding errors in repeated *10 operations.
669
+ // This fixes issues #2928 (MAX_VALUE doubles) and #3690 (DECIMAL(36,18))
670
+ // where very large numbers or numbers with many fractional digits lose precision.
671
+ // The threshold of 17 is based on IEEE 754 double precision (~15-17 significant digits).
672
+ // Testing shows minimal performance impact as most real-world numbers are shorter.
673
+ if (len > 17) {
674
+ const str = this.buffer.toString('utf8', this.offset, this.offset + len);
675
+ this.offset += len;
676
+ return Number.parseFloat(str);
677
+ }
678
+
679
+ let result = 0;
680
+ const end = this.offset + len;
681
+ let factor = 1;
682
+ let pastDot = false;
683
+ let charCode = 0;
684
+ if (this.buffer[this.offset] === minus) {
685
+ this.offset++;
686
+ factor = -1;
687
+ }
688
+ if (this.buffer[this.offset] === plus) {
689
+ this.offset++; // just ignore
690
+ }
691
+ while (this.offset < end) {
692
+ charCode = this.buffer[this.offset];
693
+ if (charCode === dot) {
694
+ pastDot = true;
695
+ this.offset++;
696
+ } else if (charCode === exponent || charCode === exponentCapital) {
697
+ // Scientific notation detected - bail out to parseFloat for exact match.
698
+ // Manual calculation with Math.pow(10, exp) cannot match parseFloat()
699
+ // exactly for most non-zero exponents due to accumulated rounding errors.
700
+ const start = end - len;
701
+ const str = this.buffer.toString('utf8', start, end);
702
+ this.offset = end;
703
+ return Number.parseFloat(str);
704
+ } else {
705
+ result *= 10;
706
+ result += this.buffer[this.offset] - 48;
707
+ this.offset++;
708
+ if (pastDot) {
709
+ factor = factor * 10;
710
+ }
711
+ }
712
+ }
713
+ return result / factor;
714
+ }
715
+
716
+ parseLengthCodedIntNoBigCheck() {
717
+ return this.parseIntNoBigCheck(this.readLengthCodedNumber());
718
+ }
719
+
720
+ parseLengthCodedInt(supportBigNumbers) {
721
+ return this.parseInt(this.readLengthCodedNumber(), supportBigNumbers);
722
+ }
723
+
724
+ parseLengthCodedIntString() {
725
+ return this.readLengthCodedString('binary');
726
+ }
727
+
728
+ parseLengthCodedFloat() {
729
+ return this.parseFloat(this.readLengthCodedNumber());
730
+ }
731
+
732
+ peekByte() {
733
+ return this.buffer[this.offset];
734
+ }
735
+
736
+ // OxFE is often used as "Alt" flag - not ok, not error.
737
+ // For example, it's first byte of AuthSwitchRequest
738
+ isAlt() {
739
+ return this.peekByte() === 0xfe;
740
+ }
741
+
742
+ isError() {
743
+ return this.peekByte() === 0xff;
744
+ }
745
+
746
+ asError(encoding) {
747
+ this.reset();
748
+ this.readInt8(); // fieldCount
749
+ const errorCode = this.readInt16();
750
+ let sqlState = '';
751
+ if (this.buffer[this.offset] === 0x23) {
752
+ this.skip(1);
753
+ sqlState = this.readBuffer(5).toString();
754
+ }
755
+ const message = this.readString(undefined, encoding);
756
+ const err = new Error(message);
757
+ err.code = ErrorCodeToName[errorCode];
758
+ err.errno = errorCode;
759
+ err.sqlState = sqlState;
760
+ err.sqlMessage = message;
761
+ return err;
762
+ }
763
+
764
+ writeInt32(n) {
765
+ this.buffer.writeUInt32LE(n, this.offset);
766
+ this.offset += 4;
767
+ }
768
+
769
+ writeInt24(n) {
770
+ this.writeInt8(n & 0xff);
771
+ this.writeInt16(n >> 8);
772
+ }
773
+
774
+ writeInt16(n) {
775
+ this.buffer.writeUInt16LE(n, this.offset);
776
+ this.offset += 2;
777
+ }
778
+
779
+ writeInt8(n) {
780
+ this.buffer.writeUInt8(n, this.offset);
781
+ this.offset++;
782
+ }
783
+
784
+ writeDouble(n) {
785
+ this.buffer.writeDoubleLE(n, this.offset);
786
+ this.offset += 8;
787
+ }
788
+
789
+ writeBuffer(b) {
790
+ b.copy(this.buffer, this.offset);
791
+ this.offset += b.length;
792
+ }
793
+
794
+ writeNull() {
795
+ this.buffer[this.offset] = 0xfb;
796
+ this.offset++;
797
+ }
798
+
799
+ // TODO: refactor following three?
800
+ writeNullTerminatedString(s, encoding) {
801
+ const buf = StringParser.encode(s, encoding);
802
+ this.buffer.length && buf.copy(this.buffer, this.offset);
803
+ this.offset += buf.length;
804
+ this.writeInt8(0);
805
+ }
806
+
807
+ writeString(s, encoding) {
808
+ if (s === null) {
809
+ this.writeInt8(0xfb);
810
+ return;
811
+ }
812
+ if (s.length === 0) {
813
+ return;
814
+ }
815
+ // const bytes = Buffer.byteLength(s, 'utf8');
816
+ // this.buffer.write(s, this.offset, bytes, 'utf8');
817
+ // this.offset += bytes;
818
+ const buf = StringParser.encode(s, encoding);
819
+ this.buffer.length && buf.copy(this.buffer, this.offset);
820
+ this.offset += buf.length;
821
+ }
822
+
823
+ writeLengthCodedString(s, encoding) {
824
+ const buf = StringParser.encode(s, encoding);
825
+ this.writeLengthCodedNumber(buf.length);
826
+ this.buffer.length && buf.copy(this.buffer, this.offset);
827
+ this.offset += buf.length;
828
+ }
829
+
830
+ writeLengthCodedBuffer(b) {
831
+ this.writeLengthCodedNumber(b.length);
832
+ b.copy(this.buffer, this.offset);
833
+ this.offset += b.length;
834
+ }
835
+
836
+ writeLengthCodedNumber(n) {
837
+ if (n < 0xfb) {
838
+ return this.writeInt8(n);
839
+ }
840
+ if (n < 0xffff) {
841
+ this.writeInt8(0xfc);
842
+ return this.writeInt16(n);
843
+ }
844
+ if (n < 0xffffff) {
845
+ this.writeInt8(0xfd);
846
+ return this.writeInt24(n);
847
+ }
848
+ if (n === null) {
849
+ return this.writeInt8(0xfb);
850
+ }
851
+ this.writeInt8(0xfe);
852
+ this.buffer.writeUInt32LE(n >>> 0, this.offset);
853
+ this.offset += 4;
854
+ this.buffer.writeUInt32LE(Math.floor(n / 0x100000000), this.offset);
855
+ this.offset += 4;
856
+ return this.offset;
857
+ }
858
+
859
+ writeDate(d, timezone) {
860
+ this.buffer.writeUInt8(11, this.offset);
861
+ if (!timezone || timezone === 'local') {
862
+ this.buffer.writeUInt16LE(d.getFullYear(), this.offset + 1);
863
+ this.buffer.writeUInt8(d.getMonth() + 1, this.offset + 3);
864
+ this.buffer.writeUInt8(d.getDate(), this.offset + 4);
865
+ this.buffer.writeUInt8(d.getHours(), this.offset + 5);
866
+ this.buffer.writeUInt8(d.getMinutes(), this.offset + 6);
867
+ this.buffer.writeUInt8(d.getSeconds(), this.offset + 7);
868
+ this.buffer.writeUInt32LE(d.getMilliseconds() * 1000, this.offset + 8);
869
+ } else {
870
+ if (timezone !== 'Z') {
871
+ const offset =
872
+ (timezone[0] === '-' ? -1 : 1) *
873
+ (parseInt(timezone.substring(1, 3), 10) * 60 +
874
+ parseInt(timezone.substring(4), 10));
875
+ if (offset !== 0) {
876
+ d = new Date(d.getTime() + 60000 * offset);
877
+ }
878
+ }
879
+ this.buffer.writeUInt16LE(d.getUTCFullYear(), this.offset + 1);
880
+ this.buffer.writeUInt8(d.getUTCMonth() + 1, this.offset + 3);
881
+ this.buffer.writeUInt8(d.getUTCDate(), this.offset + 4);
882
+ this.buffer.writeUInt8(d.getUTCHours(), this.offset + 5);
883
+ this.buffer.writeUInt8(d.getUTCMinutes(), this.offset + 6);
884
+ this.buffer.writeUInt8(d.getUTCSeconds(), this.offset + 7);
885
+ this.buffer.writeUInt32LE(d.getUTCMilliseconds() * 1000, this.offset + 8);
886
+ }
887
+ this.offset += 12;
888
+ }
889
+
890
+ writeHeader(sequenceId) {
891
+ const offset = this.offset;
892
+ this.offset = 0;
893
+ this.writeInt24(this.buffer.length - 4);
894
+ this.writeInt8(sequenceId);
895
+ this.offset = offset;
896
+ }
897
+
898
+ clone() {
899
+ return new Packet(this.sequenceId, this.buffer, this.start, this.end);
900
+ }
901
+
902
+ type() {
903
+ if (this.isEOF()) {
904
+ return 'EOF';
905
+ }
906
+ if (this.isError()) {
907
+ return 'Error';
908
+ }
909
+ if (this.buffer[this.offset] === 0) {
910
+ return 'maybeOK'; // could be other packet types as well
911
+ }
912
+ return '';
913
+ }
914
+
915
+ static lengthCodedNumberLength(n) {
916
+ if (n < 0xfb) {
917
+ return 1;
918
+ }
919
+ if (n < 0xffff) {
920
+ return 3;
921
+ }
922
+ if (n < 0xffffff) {
923
+ return 5;
924
+ }
925
+ return 9;
926
+ }
927
+
928
+ static lengthCodedStringLength(str, encoding) {
929
+ const buf = StringParser.encode(str, encoding);
930
+ const slen = buf.length;
931
+ return Packet.lengthCodedNumberLength(slen) + slen;
932
+ }
933
+
934
+ static MockBuffer() {
935
+ const noop = function () {};
936
+ const res = Buffer.alloc(0);
937
+ for (const op in NativeBuffer.prototype) {
938
+ if (typeof res[op] === 'function') {
939
+ res[op] = noop;
940
+ }
941
+ }
942
+ return res;
943
+ }
944
+ }
945
+
946
+ module.exports = Packet;