@depup/mysql2 3.19.0-depup.0 → 3.20.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 CHANGED
@@ -1,114 +1,25 @@
1
- [npm-image]: https://img.shields.io/npm/v/mysql2.svg
2
- [npm-url]: https://npmjs.com/package/mysql2
3
- [node-version-image]: https://img.shields.io/node/v/mysql2.svg
4
- [node-version-url]: https://nodejs.org/en/download
5
- [downloads-image]: https://img.shields.io/npm/dm/mysql2.svg
6
- [downloads-url]: https://npmjs.com/package/mysql2
7
- [license-url]: https://github.com/sidorares/node-mysql2/blob/master/License
8
- [license-image]: https://img.shields.io/npm/l/mysql2.svg?maxAge=2592000
9
- [node-mysql]: https://github.com/mysqljs/mysql
10
- [mysqljs]: https://github.com/mysqljs
11
- [mysql-native]: https://github.com/sidorares/nodejs-mysql-native
12
- [sidorares]: https://github.com/sidorares
13
- [TooTallNate]: https://gist.github.com/TooTallNate
14
- [starttls.js]: https://gist.github.com/TooTallNate/848444
15
- [node-mariasql]: https://github.com/mscdex/node-mariasql
16
- [contributors]: https://github.com/sidorares/node-mysql2/graphs/contributors
17
- [contributing]: https://github.com/sidorares/node-mysql2/blob/master/Contributing.md
18
- [docs-base]: https://sidorares.github.io/node-mysql2/docs
19
- [docs-base-zh-CN]: https://sidorares.github.io/node-mysql2/zh-CN/docs
20
- [docs-base-pt-BR]: https://sidorares.github.io/node-mysql2/pt-BR/docs
21
- [docs-prepared-statements]: https://sidorares.github.io/node-mysql2/docs/documentation/prepared-statements
22
- [docs-mysql-server]: https://sidorares.github.io/node-mysql2/docs/documentation/mysql-server
23
- [docs-promise-wrapper]: https://sidorares.github.io/node-mysql2/docs/documentation/promise-wrapper
24
- [docs-authentication-switch]: https://sidorares.github.io/node-mysql2/docs/documentation/authentication-switch
25
- [docs-streams]: https://sidorares.github.io/node-mysql2/docs/documentation/extras
26
- [docs-typescript-docs]: https://sidorares.github.io/node-mysql2/docs/documentation/typescript-examples
27
- [docs-qs-pooling]: https://sidorares.github.io/node-mysql2/docs#using-connection-pools
28
- [docs-qs-first-query]: https://sidorares.github.io/node-mysql2/docs#first-query
29
- [docs-qs-using-prepared-statements]: https://sidorares.github.io/node-mysql2/docs#using-prepared-statements
30
- [docs-examples]: https://sidorares.github.io/node-mysql2/docs/examples
31
- [docs-faq]: https://sidorares.github.io/node-mysql2/docs/faq
32
- [docs-documentation]: https://sidorares.github.io/node-mysql2/docs/documentation
33
- [docs-contributing]: https://sidorares.github.io/node-mysql2/docs/contributing/website
34
- [coverage]: https://img.shields.io/codecov/c/github/sidorares/node-mysql2
35
- [coverage-url]: https://app.codecov.io/github/sidorares/node-mysql2
36
- [ci-url]: https://github.com/sidorares/node-mysql2/actions/workflows/ci-coverage.yml?query=branch%3Amaster
37
- [ci-image]: https://img.shields.io/github/actions/workflow/status/sidorares/node-mysql2/ci-coverage.yml?event=push&style=flat&label=CI&branch=master
1
+ # @depup/mysql2
38
2
 
39
- # MySQL2
3
+ > Dependency-bumped version of [mysql2](https://www.npmjs.com/package/mysql2)
40
4
 
41
- [![NPM Version][npm-image]][npm-url]
42
- [![NPM Downloads][downloads-image]][downloads-url]
43
- [![Node.js Version][node-version-image]][node-version-url]
44
- [![GitHub Workflow Status (with event)][ci-image]][ci-url]
45
- [![Codecov][coverage]][coverage-url]
46
- [![License][license-image]][license-url]
47
-
48
- [English][docs-base] | [简体中文][docs-base-zh-CN] | [Português (BR)][docs-base-pt-BR]
49
-
50
- > MySQL client for Node.js with focus on performance. Supports prepared statements, non-utf8 encodings, binary log protocol, compression, ssl [much more][docs-documentation].
51
-
52
- **Table of Contents**
53
-
54
- - [History and Why MySQL2](#history-and-why-mysql2)
55
- - [Installation](#installation)
56
- - [Documentation](#documentation)
57
- - [Acknowledgements](#acknowledgements)
58
- - [Contributing](#contributing)
59
-
60
- ## History and Why MySQL2
61
-
62
- MySQL2 project is a continuation of [MySQL-Native][mysql-native]. Protocol parser code was rewritten from scratch and api changed to match popular [Node MySQL][node-mysql]. MySQL2 team is working together with [Node MySQL][node-mysql] team to factor out shared code and move it under [mysqljs][mysqljs] organization.
63
-
64
- MySQL2 is mostly API compatible with [Node MySQL][node-mysql] and supports majority of features. MySQL2 also offers these additional features:
65
-
66
- - Faster / Better Performance
67
- - [Prepared Statements][docs-prepared-statements]
68
- - MySQL Binary Log Protocol
69
- - [MySQL Server][docs-mysql-server]
70
- - Extended support for Encoding and Collation
71
- - [Promise Wrapper][docs-promise-wrapper]
72
- - Compression
73
- - SSL and [Authentication Switch][docs-authentication-switch]
74
- - [Custom Streams][docs-streams]
75
- - [Pooling][docs-qs-pooling]
5
+ Generated by [DepUp](https://github.com/depup/npm) -- all production
6
+ dependencies bumped to latest versions.
76
7
 
77
8
  ## Installation
78
9
 
79
- MySQL2 is free from native bindings and can be installed on Linux, Mac OS or Windows without any issues.
80
-
81
10
  ```bash
82
- npm install --save mysql2
11
+ npm install @depup/mysql2
83
12
  ```
84
13
 
85
- If you are using TypeScript, you will need to install `@types/node`.
86
-
87
- ```bash
88
- npm install --save-dev @types/node
89
- ```
90
-
91
- > For TypeScript documentation and examples, see [here][docs-typescript-docs].
92
-
93
- ## Documentation
94
-
95
- - [Quickstart][docs-base]
96
- - [First Query][docs-qs-first-query], [Using Prepared Statements][docs-qs-using-prepared-statements], [Using Connection Pools][docs-qs-pooling] and more.
97
- - [Documentation][docs-documentation]
98
- - [Examples][docs-examples]
99
- - [FAQ][docs-faq]
100
-
101
- ## Acknowledgements
102
-
103
- - Internal protocol is written by [@sidorares][sidorares] [MySQL-Native][mysql-native].
104
- - Constants, SQL parameters interpolation, Pooling, `ConnectionConfig` class taken from [Node MySQL][node-mysql].
105
- - SSL upgrade code based on [@TooTallNate][TooTallNate] [code][starttls.js].
106
- - Secure connection / compressed connection api flags compatible to [MariaSQL][node-mariasql] client.
107
- - [Contributors][contributors].
14
+ | Field | Value |
15
+ |-------|-------|
16
+ | Original | [mysql2](https://www.npmjs.com/package/mysql2) @ 3.20.0 |
17
+ | Processed | 2026-03-16 |
18
+ | Smoke test | passed |
19
+ | Deps updated | 0 |
108
20
 
109
- ## Contributing
21
+ ---
110
22
 
111
- Want to improve something in **MySQL2**?
112
- Please check [Contributing.md][contributing] for detailed instruction on how to get started.
23
+ Source: https://github.com/depup/npm | Original: https://www.npmjs.com/package/mysql2
113
24
 
114
- To contribute in **MySQL2 Documentation**, please visit the [Website Contributing Guidelines][docs-contributing] for detailed instruction on how to get started.
25
+ License inherited from the original package.
@@ -36,6 +36,7 @@ function encrypt(password, scramble, key) {
36
36
  return crypto.publicEncrypt(
37
37
  {
38
38
  key,
39
+ oaepHash: 'sha1',
39
40
  padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
40
41
  },
41
42
  stage1
@@ -13,7 +13,13 @@ const STATE_FINAL = -1;
13
13
 
14
14
  function encrypt(password, scramble, key) {
15
15
  const stage1 = xorRotating(Buffer.from(`${password}\0`, 'utf8'), scramble);
16
- return crypto.publicEncrypt(key, stage1);
16
+ return crypto.publicEncrypt(
17
+ {
18
+ key,
19
+ oaepHash: 'sha1',
20
+ },
21
+ stage1
22
+ );
17
23
  }
18
24
 
19
25
  module.exports =
@@ -28,6 +28,15 @@ const Packets = require('../packets/index.js');
28
28
  const Commands = require('../commands/index.js');
29
29
  const ConnectionConfig = require('../connection_config.js');
30
30
  const CharsetToEncoding = require('../constants/charset_encodings.js');
31
+ const {
32
+ traceCallback,
33
+ tracePromise,
34
+ getServerContext,
35
+ shouldTrace,
36
+ queryChannel,
37
+ executeChannel,
38
+ connectChannel,
39
+ } = require('../tracing.js');
31
40
 
32
41
  let _connectionId = 0;
33
42
 
@@ -141,6 +150,41 @@ class BaseConnection extends EventEmitter {
141
150
  this._notifyError(err);
142
151
  });
143
152
  this.addCommand(handshakeCommand);
153
+
154
+ // Trace the connection handshake
155
+ if (shouldTrace(connectChannel)) {
156
+ const config = this.config;
157
+ tracePromise(
158
+ connectChannel,
159
+ () =>
160
+ new Promise((resolve, reject) => {
161
+ /* eslint-disable prefer-const */
162
+ let onConnect, onError;
163
+ onConnect = (param) => {
164
+ this.removeListener('error', onError);
165
+ resolve(param);
166
+ };
167
+ onError = (err) => {
168
+ this.removeListener('connect', onConnect);
169
+ reject(err);
170
+ };
171
+ /* eslint-enable prefer-const */
172
+ this.once('connect', onConnect);
173
+ this.once('error', onError);
174
+ }),
175
+ () => {
176
+ const server = getServerContext(config);
177
+ return {
178
+ database: config.database || '',
179
+ serverAddress: server.serverAddress,
180
+ serverPort: server.serverPort,
181
+ user: config.user || '',
182
+ };
183
+ }
184
+ ).catch(() => {
185
+ // errors are already handled by the handshake error listener
186
+ });
187
+ }
144
188
  }
145
189
  // in case there was no initial handshake but we need to read sting, assume it utf-8
146
190
  // most common example: "Too many connections" error ( packet is sent immediately on connection attempt, we don't know server encoding yet)
@@ -601,7 +645,57 @@ class BaseConnection extends EventEmitter {
601
645
  cmdQuery.values !== undefined ? cmdQuery.values : []
602
646
  );
603
647
  cmdQuery.sql = rawSql;
604
- return this.addCommand(cmdQuery);
648
+
649
+ if (cmdQuery.onResult) {
650
+ // Callback mode: traceCallback wraps the callback with tracing lifecycle, or calls through directly when no subscribers are registered
651
+ traceCallback(
652
+ queryChannel,
653
+ (wrappedCb) => {
654
+ cmdQuery.onResult = wrappedCb;
655
+ this.addCommand(cmdQuery);
656
+ },
657
+ 0,
658
+ () => {
659
+ const server = getServerContext(this.config);
660
+ return {
661
+ query: cmdQuery.sql,
662
+ values: cmdQuery.values,
663
+ database: this.config.database || '',
664
+ serverAddress: server.serverAddress,
665
+ serverPort: server.serverPort,
666
+ };
667
+ },
668
+ null,
669
+ cmdQuery.onResult
670
+ );
671
+ } else if (shouldTrace(queryChannel)) {
672
+ // Event-emitter mode: tracePromise wraps the async lifecycle
673
+ tracePromise(
674
+ queryChannel,
675
+ () =>
676
+ new Promise((resolve, reject) => {
677
+ cmdQuery.once('error', reject);
678
+ cmdQuery.once('end', () => resolve());
679
+ this.addCommand(cmdQuery);
680
+ }),
681
+ () => {
682
+ const server = getServerContext(this.config);
683
+ return {
684
+ query: cmdQuery.sql,
685
+ values: cmdQuery.values,
686
+ database: this.config.database || '',
687
+ serverAddress: server.serverAddress,
688
+ serverPort: server.serverPort,
689
+ };
690
+ }
691
+ ).catch(() => {
692
+ // errors are already emitted on the command
693
+ });
694
+ } else {
695
+ this.addCommand(cmdQuery);
696
+ }
697
+
698
+ return cmdQuery;
605
699
  }
606
700
 
607
701
  pause() {
@@ -702,25 +796,78 @@ class BaseConnection extends EventEmitter {
702
796
  });
703
797
  }
704
798
  const executeCommand = new Commands.Execute(options, cb);
705
- const prepareCommand = new Commands.Prepare(options, (err, stmt) => {
706
- if (err) {
707
- // skip execute command if prepare failed, we have main
708
- // combined callback here
709
- executeCommand.start = function () {
710
- return null;
711
- };
712
- if (cb) {
713
- cb(err);
714
- } else {
715
- executeCommand.emit('error', err);
799
+
800
+ const prepareAndExecute = (errorCb) => {
801
+ const prepareCommand = new Commands.Prepare(options, (err, stmt) => {
802
+ if (err) {
803
+ // skip execute command if prepare failed
804
+ executeCommand.start = function () {
805
+ return null;
806
+ };
807
+ errorCb(err);
808
+ executeCommand.emit('end');
809
+ return;
716
810
  }
717
- executeCommand.emit('end');
718
- return;
719
- }
720
- executeCommand.statement = stmt;
721
- });
722
- this.addCommand(prepareCommand);
723
- this.addCommand(executeCommand);
811
+ executeCommand.statement = stmt;
812
+ });
813
+ this.addCommand(prepareCommand);
814
+ this.addCommand(executeCommand);
815
+ };
816
+
817
+ if (executeCommand.onResult) {
818
+ // Callback mode: traceCallback wraps the callback with tracing lifecycle, or calls through directly when no subscribers are registered
819
+ const origExecCb = executeCommand.onResult;
820
+ traceCallback(
821
+ executeChannel,
822
+ (wrappedCb) => {
823
+ executeCommand.onResult = wrappedCb;
824
+ prepareAndExecute(wrappedCb);
825
+ },
826
+ 0,
827
+ () => {
828
+ const server = getServerContext(this.config);
829
+ return {
830
+ query: options.sql,
831
+ values: options.values,
832
+ database: this.config.database || '',
833
+ serverAddress: server.serverAddress,
834
+ serverPort: server.serverPort,
835
+ };
836
+ },
837
+ null,
838
+ origExecCb
839
+ );
840
+ } else if (shouldTrace(executeChannel)) {
841
+ // Event-emitter mode: tracePromise wraps the async lifecycle
842
+ tracePromise(
843
+ executeChannel,
844
+ () =>
845
+ new Promise((resolve, reject) => {
846
+ prepareAndExecute((err) => {
847
+ executeCommand.emit('error', err);
848
+ });
849
+ executeCommand.once('error', reject);
850
+ executeCommand.once('end', () => resolve());
851
+ }),
852
+ () => {
853
+ const server = getServerContext(this.config);
854
+ return {
855
+ query: options.sql,
856
+ values: options.values,
857
+ database: this.config.database || '',
858
+ serverAddress: server.serverAddress,
859
+ serverPort: server.serverPort,
860
+ };
861
+ }
862
+ ).catch(() => {
863
+ // errors are already emitted on the command
864
+ });
865
+ } else {
866
+ prepareAndExecute((err) => {
867
+ executeCommand.emit('error', err);
868
+ });
869
+ }
870
+
724
871
  return executeCommand;
725
872
  }
726
873
 
package/lib/base/pool.js CHANGED
@@ -7,6 +7,11 @@ const PoolConnection = require('../pool_connection.js');
7
7
  const Queue = require('denque');
8
8
  const BaseConnection = require('./connection.js');
9
9
  const Errors = require('../constants/errors.js');
10
+ const {
11
+ traceCallback,
12
+ getServerContext,
13
+ poolConnectChannel,
14
+ } = require('../tracing.js');
10
15
 
11
16
  // Source: https://github.com/go-sql-driver/mysql/blob/76c00e35a8d48f8f70f0e7dffe584692bd3fa612/packets.go#L598-L613
12
17
  function isReadOnlyError(err) {
@@ -49,46 +54,69 @@ class BasePool extends EventEmitter {
49
54
  }
50
55
 
51
56
  getConnection(cb) {
52
- if (this._closed) {
53
- return process.nextTick(() => cb(new Error('Pool is closed.')));
54
- }
55
- let connection;
56
- if (this._freeConnections.length > 0) {
57
- connection = this._freeConnections.pop();
58
- this.emit('acquire', connection);
59
- return process.nextTick(() => cb(null, connection));
60
- }
61
- if (
62
- this.config.connectionLimit === 0 ||
63
- this._allConnections.length < this.config.connectionLimit
64
- ) {
65
- connection = new PoolConnection(this, {
66
- config: this.config.connectionConfig,
67
- });
68
- this._allConnections.push(connection);
69
- return connection.connect((err) => {
70
- if (this._closed) {
71
- return cb(new Error('Pool is closed.'));
72
- }
73
- if (err) {
74
- return cb(err);
75
- }
76
- this.emit('connection', connection);
57
+ const _getConnection = (cb) => {
58
+ if (this._closed) {
59
+ return process.nextTick(() => cb(new Error('Pool is closed.')));
60
+ }
61
+ let connection;
62
+ if (this._freeConnections.length > 0) {
63
+ connection = this._freeConnections.pop();
77
64
  this.emit('acquire', connection);
78
- return cb(null, connection);
79
- });
80
- }
81
- if (!this.config.waitForConnections) {
82
- return process.nextTick(() => cb(new Error('No connections available.')));
83
- }
84
- if (
85
- this.config.queueLimit &&
86
- this._connectionQueue.length >= this.config.queueLimit
87
- ) {
88
- return cb(new Error('Queue limit reached.'));
89
- }
90
- this.emit('enqueue');
91
- return this._connectionQueue.push(cb);
65
+ return process.nextTick(() => {
66
+ connection._released = false;
67
+ cb(null, connection);
68
+ });
69
+ }
70
+ if (
71
+ this.config.connectionLimit === 0 ||
72
+ this._allConnections.length < this.config.connectionLimit
73
+ ) {
74
+ connection = new PoolConnection(this, {
75
+ config: this.config.connectionConfig,
76
+ });
77
+ this._allConnections.push(connection);
78
+ return connection.connect((err) => {
79
+ if (this._closed) {
80
+ return cb(new Error('Pool is closed.'));
81
+ }
82
+ if (err) {
83
+ return cb(err);
84
+ }
85
+ this.emit('connection', connection);
86
+ this.emit('acquire', connection);
87
+ return cb(null, connection);
88
+ });
89
+ }
90
+ if (!this.config.waitForConnections) {
91
+ return process.nextTick(() =>
92
+ cb(new Error('No connections available.'))
93
+ );
94
+ }
95
+ if (
96
+ this.config.queueLimit &&
97
+ this._connectionQueue.length >= this.config.queueLimit
98
+ ) {
99
+ return cb(new Error('Queue limit reached.'));
100
+ }
101
+ this.emit('enqueue');
102
+ return this._connectionQueue.push(cb);
103
+ };
104
+ const config = this.config.connectionConfig;
105
+ traceCallback(
106
+ poolConnectChannel,
107
+ _getConnection,
108
+ 0,
109
+ () => {
110
+ const server = getServerContext(config);
111
+ return {
112
+ database: config.database || '',
113
+ serverAddress: server.serverAddress,
114
+ serverPort: server.serverPort,
115
+ };
116
+ },
117
+ null,
118
+ cb
119
+ );
92
120
  }
93
121
 
94
122
  releaseConnection(connection) {
@@ -101,7 +129,10 @@ class BasePool extends EventEmitter {
101
129
  }
102
130
  } else if (this._connectionQueue.length) {
103
131
  cb = this._connectionQueue.shift();
104
- process.nextTick(cb.bind(null, null, connection));
132
+ process.nextTick(() => {
133
+ connection._released = false;
134
+ cb(null, connection);
135
+ });
105
136
  } else {
106
137
  this._freeConnections.push(connection);
107
138
  this.emit('release', connection);
@@ -277,7 +277,10 @@ class ConnectionConfig {
277
277
  user: decodeURIComponent(parsedUrl.username),
278
278
  password: decodeURIComponent(parsedUrl.password),
279
279
  };
280
- parsedUrl.searchParams.forEach((value, key) => {
280
+ for (const [key, value] of parsedUrl.searchParams) {
281
+ if (key in options) {
282
+ continue;
283
+ }
281
284
  try {
282
285
  // Try to parse this as a JSON expression first
283
286
  options[key] = JSON.parse(value);
@@ -285,7 +288,7 @@ class ConnectionConfig {
285
288
  // Otherwise assume it is a plain string
286
289
  options[key] = value;
287
290
  }
288
- });
291
+ }
289
292
  return options;
290
293
  }
291
294
  }
@@ -406,8 +406,8 @@ class Packet {
406
406
  readNullTerminatedString(encoding) {
407
407
  const start = this.offset;
408
408
  let end = this.offset;
409
- while (this.buffer[end]) {
410
- end = end + 1; // TODO: handle OOB check
409
+ while (end < this.end && this.buffer[end] !== 0x00) {
410
+ end = end + 1;
411
411
  }
412
412
  this.offset = end + 1;
413
413
  return StringParser.decode(this.buffer, encoding, start, end);
@@ -516,16 +516,20 @@ class Packet {
516
516
  return result * sign;
517
517
  }
518
518
 
519
- // copy-paste from https://github.com/mysqljs/mysql/blob/master/lib/protocol/Parser.js
519
+ // adapted from https://github.com/mysqljs/mysql/blob/dc9c152a87ec51a1f647447268917243d2eab1fd/lib/protocol/Parser.js
520
520
  parseGeometryValue() {
521
521
  const buffer = this.readLengthCodedBuffer();
522
522
  let offset = 4;
523
523
  if (buffer === null || !buffer.length) {
524
524
  return null;
525
525
  }
526
+ const bufferLength = buffer.length;
526
527
  function parseGeometry() {
527
- let x, y, i, j, numPoints, line;
528
+ let x, y, i, j, numPoints, numRings, num, line;
528
529
  let result = null;
530
+ if (offset + 5 > bufferLength) {
531
+ return null;
532
+ }
529
533
  const byteOrder = buffer.readUInt8(offset);
530
534
  offset += 1;
531
535
  const wkbType = byteOrder
@@ -534,6 +538,9 @@ class Packet {
534
538
  offset += 4;
535
539
  switch (wkbType) {
536
540
  case 1: // WKBPoint
541
+ if (offset + 16 > bufferLength) {
542
+ return null;
543
+ }
537
544
  x = byteOrder
538
545
  ? buffer.readDoubleLE(offset)
539
546
  : buffer.readDoubleBE(offset);
@@ -545,12 +552,21 @@ class Packet {
545
552
  result = { x: x, y: y };
546
553
  break;
547
554
  case 2: // WKBLineString
555
+ if (offset + 4 > bufferLength) {
556
+ return null;
557
+ }
548
558
  numPoints = byteOrder
549
559
  ? buffer.readUInt32LE(offset)
550
560
  : buffer.readUInt32BE(offset);
551
561
  offset += 4;
562
+ if (numPoints > (bufferLength - offset) / 16) {
563
+ return null;
564
+ }
552
565
  result = [];
553
566
  for (i = numPoints; i > 0; i--) {
567
+ if (offset + 16 > bufferLength) {
568
+ break;
569
+ }
554
570
  x = byteOrder
555
571
  ? buffer.readDoubleLE(offset)
556
572
  : buffer.readDoubleBE(offset);
@@ -563,19 +579,30 @@ class Packet {
563
579
  }
564
580
  break;
565
581
  case 3: // WKBPolygon
566
- // eslint-disable-next-line no-case-declarations
567
- const numRings = byteOrder
582
+ if (offset + 4 > bufferLength) {
583
+ return null;
584
+ }
585
+ numRings = byteOrder
568
586
  ? buffer.readUInt32LE(offset)
569
587
  : buffer.readUInt32BE(offset);
570
588
  offset += 4;
589
+ if (numRings > (bufferLength - offset) / 4) {
590
+ return null;
591
+ }
571
592
  result = [];
572
593
  for (i = numRings; i > 0; i--) {
594
+ if (offset + 4 > bufferLength) {
595
+ break;
596
+ }
573
597
  numPoints = byteOrder
574
598
  ? buffer.readUInt32LE(offset)
575
599
  : buffer.readUInt32BE(offset);
576
600
  offset += 4;
577
601
  line = [];
578
602
  for (j = numPoints; j > 0; j--) {
603
+ if (offset + 16 > bufferLength) {
604
+ break;
605
+ }
579
606
  x = byteOrder
580
607
  ? buffer.readDoubleLE(offset)
581
608
  : buffer.readDoubleBE(offset);
@@ -593,11 +620,16 @@ class Packet {
593
620
  case 5: // WKBMultiLineString
594
621
  case 6: // WKBMultiPolygon
595
622
  case 7: // WKBGeometryCollection
596
- // eslint-disable-next-line no-case-declarations
597
- const num = byteOrder
623
+ if (offset + 4 > bufferLength) {
624
+ return null;
625
+ }
626
+ num = byteOrder
598
627
  ? buffer.readUInt32LE(offset)
599
628
  : buffer.readUInt32BE(offset);
600
629
  offset += 4;
630
+ if (num > (bufferLength - offset) / 9) {
631
+ return null;
632
+ }
601
633
  result = [];
602
634
  for (i = num; i > 0; i--) {
603
635
  result.push(parseGeometry());
@@ -1,12 +1,81 @@
1
1
  'use strict';
2
2
 
3
- const BasePoolConnection = require('./base/pool_connection.js');
3
+ const Connection = require('./connection.js');
4
+
5
+ class PoolConnection extends Connection {
6
+ constructor(pool, options) {
7
+ super(options);
8
+ this._pool = pool;
9
+ this._released = false;
10
+ this.lastActiveTime = Date.now();
11
+ this.once('end', () => {
12
+ this._removeFromPool();
13
+ });
14
+ this.once('error', () => {
15
+ this._removeFromPool();
16
+ });
17
+ }
18
+
19
+ release() {
20
+ if (this._released) {
21
+ return;
22
+ }
23
+ if (!this._pool || this._pool._closed) {
24
+ return;
25
+ }
26
+ this._released = true;
27
+ this.lastActiveTime = Date.now();
28
+ this._pool.releaseConnection(this);
29
+ }
30
+
31
+ [Symbol.dispose]() {
32
+ this.release();
33
+ }
34
+
35
+ end(callback) {
36
+ if (this.config.gracefulEnd) {
37
+ this._removeFromPool();
38
+ super.end(callback);
39
+
40
+ return;
41
+ }
42
+
43
+ const err = new Error(
44
+ 'Calling conn.end() to release a pooled connection is ' +
45
+ 'deprecated. In next version calling conn.end() will be ' +
46
+ 'restored to default conn.end() behavior. Use ' +
47
+ 'conn.release() instead.'
48
+ );
49
+ this.emit('warn', err);
50
+ console.warn(err.message);
51
+ this.release();
52
+ if (typeof callback === 'function') {
53
+ callback();
54
+ }
55
+ }
56
+
57
+ destroy() {
58
+ this._removeFromPool();
59
+ super.destroy();
60
+ }
61
+
62
+ _removeFromPool() {
63
+ if (!this._pool || this._pool._closed) {
64
+ return;
65
+ }
66
+ const pool = this._pool;
67
+ this._pool = null;
68
+ pool._removeConnection(this);
69
+ }
4
70
 
5
- class PoolConnection extends BasePoolConnection {
6
71
  promise(promiseImpl) {
7
72
  const PromisePoolConnection = require('./promise/pool_connection.js');
8
73
  return new PromisePoolConnection(this, promiseImpl);
9
74
  }
10
75
  }
11
76
 
77
+ PoolConnection.statementKey = Connection.statementKey;
12
78
  module.exports = PoolConnection;
79
+
80
+ // TODO: Remove this when we are removing PoolConnection#end
81
+ PoolConnection.prototype._realEnd = Connection.prototype.end;
@@ -1,7 +1,6 @@
1
1
  'use strict';
2
2
 
3
3
  const PromiseConnection = require('./connection.js');
4
- const BasePoolConnection = require('../base/pool_connection.js');
5
4
 
6
5
  class PromisePoolConnection extends PromiseConnection {
7
6
  constructor(connection, promiseImpl) {
@@ -9,10 +8,7 @@ class PromisePoolConnection extends PromiseConnection {
9
8
  }
10
9
 
11
10
  destroy() {
12
- return BasePoolConnection.prototype.destroy.apply(
13
- this.connection,
14
- arguments
15
- );
11
+ return this.connection.destroy();
16
12
  }
17
13
 
18
14
  async [Symbol.asyncDispose]() {
package/lib/tracing.js ADDED
@@ -0,0 +1,81 @@
1
+ 'use strict';
2
+
3
+ const process = require('process');
4
+
5
+ // Safe load: use getBuiltinModule if available, fallback to require, catch if unavailable
6
+ const dc = (() => {
7
+ try {
8
+ return 'getBuiltinModule' in process
9
+ ? process.getBuiltinModule('node:diagnostics_channel')
10
+ : require('node:diagnostics_channel');
11
+ } catch {
12
+ return undefined;
13
+ }
14
+ })();
15
+
16
+ const hasTracingChannel = typeof dc?.tracingChannel === 'function';
17
+
18
+ const queryChannel = hasTracingChannel
19
+ ? dc.tracingChannel('mysql2:query')
20
+ : undefined;
21
+
22
+ const executeChannel = hasTracingChannel
23
+ ? dc.tracingChannel('mysql2:execute')
24
+ : undefined;
25
+
26
+ const connectChannel = hasTracingChannel
27
+ ? dc.tracingChannel('mysql2:connect')
28
+ : undefined;
29
+
30
+ const poolConnectChannel = hasTracingChannel
31
+ ? dc.tracingChannel('mysql2:pool:connect')
32
+ : undefined;
33
+
34
+ function getServerContext(config) {
35
+ if (config.socketPath) {
36
+ return { serverAddress: config.socketPath, serverPort: undefined };
37
+ }
38
+ return {
39
+ serverAddress: config.host || 'localhost',
40
+ serverPort: config.port || 3306,
41
+ };
42
+ }
43
+
44
+ // Node 20+: TracingChannel has an aggregated hasSubscribers getter.
45
+ // Node 18.x: that getter is missing (undefined), fall back to start sub-channel.
46
+ function shouldTrace(channel) {
47
+ if (channel === undefined || channel === null) {
48
+ return false;
49
+ }
50
+ return channel.hasSubscribers ?? channel.start?.hasSubscribers ?? false;
51
+ }
52
+
53
+ // Generic traceCallback wrapper — calls fn synchronously, wraps the callback
54
+ // at args[position] to emit asyncStart/asyncEnd/error. No promises involved.
55
+ function traceCallback(channel, fn, position, context, thisArg, ...args) {
56
+ if (shouldTrace(channel)) {
57
+ return channel.traceCallback(fn, position, context(), thisArg, ...args);
58
+ }
59
+ return fn.apply(thisArg, args);
60
+ }
61
+
62
+ // tracePromise for operations that are inherently async (connection handshake)
63
+ function tracePromise(channel, fn, contextFactory) {
64
+ if (shouldTrace(channel)) {
65
+ return channel.tracePromise(fn, contextFactory());
66
+ }
67
+ return fn();
68
+ }
69
+
70
+ module.exports = {
71
+ dc,
72
+ hasTracingChannel,
73
+ shouldTrace,
74
+ queryChannel,
75
+ executeChannel,
76
+ connectChannel,
77
+ poolConnectChannel,
78
+ getServerContext,
79
+ traceCallback,
80
+ tracePromise,
81
+ };
package/package.json CHANGED
@@ -1,22 +1,16 @@
1
1
  {
2
2
  "name": "@depup/mysql2",
3
- "version": "3.19.0-depup.0",
4
- "description": "fast mysql driver. Implements core protocol, prepared statements, ssl and compression in native JS",
3
+ "version": "3.20.0-depup.0",
4
+ "description": "[DepUp] fast mysql driver. Implements core protocol, prepared statements, ssl and compression in native JS",
5
5
  "main": "index.js",
6
6
  "typings": "typings/mysql/index",
7
7
  "type": "commonjs",
8
8
  "scripts": {
9
9
  "lint": "eslint . && prettier --check .",
10
10
  "lint:fix": "eslint . --fix && prettier --write .",
11
- "test": "npm run test:parallel && npm run test:global",
12
- "test:parallel": "poku -c=\"poku.config.mjs\" test",
13
- "test:global": "cross-env SUITE=global poku -c=\"poku.config.mjs\" test/global",
14
- "test:bun": "npm run test:bun:parallel && npm run test:bun:global",
15
- "test:bun:parallel": "bun poku -c=\"poku.config.mjs\" test",
16
- "test:bun:global": "cross-env SUITE=global bun poku -c=\"poku.config.mjs\" test/global",
17
- "test:deno": "npm run test:deno:parallel && npm run test:deno:global",
18
- "test:deno:parallel": "deno run --allow-read --allow-env --allow-run npm:poku@canary -c=\"poku.config.mjs\" test",
19
- "test:deno:global": "cross-env SUITE=global deno run --allow-read --allow-env --allow-run npm:poku@canary -c=\"poku.config.mjs\" test/global",
11
+ "test": "poku",
12
+ "test:bun": "bun poku",
13
+ "test:deno": "deno run -A npm:poku",
20
14
  "test:docker:up": "docker compose -f test/docker-compose.yml up --abort-on-container-exit --remove-orphans",
21
15
  "test:docker:down": "docker compose -f test/docker-compose.yml down",
22
16
  "test:docker:node": "npm run test:docker:up -- node && npm run test:docker:down",
@@ -24,6 +18,7 @@
24
18
  "test:docker:deno": "npm run test:docker:up -- deno && npm run test:docker:down",
25
19
  "test:docker:coverage": "npm run test:docker:up -- coverage && npm run test:docker:down",
26
20
  "test:coverage": "c8 npm test",
21
+ "test:build": "rollup -c",
27
22
  "typecheck": "cd \"test/tsc-build\" && tsc -p \"tsconfig.json\" && cd .. && tsc -p \"tsconfig.json\" --noEmit",
28
23
  "benchmark": "node ./benchmarks/benchmark.js",
29
24
  "wait-port": "wait-on"
@@ -34,6 +29,10 @@
34
29
  },
35
30
  "homepage": "https://sidorares.github.io/node-mysql2/docs",
36
31
  "keywords": [
32
+ "depup",
33
+ "dependency-bumped",
34
+ "updated-deps",
35
+ "mysql2",
37
36
  "mysql",
38
37
  "client",
39
38
  "server"
@@ -75,22 +74,34 @@
75
74
  "@eslint/js": "^9.39.2",
76
75
  "@eslint/markdown": "^7.5.1",
77
76
  "@ianvs/prettier-plugin-sort-imports": "^4.7.1",
77
+ "@pokujs/multi-suite": "^1.0.0",
78
+ "@rollup/plugin-commonjs": "^29.0.2",
79
+ "@rollup/plugin-json": "^6.1.0",
80
+ "@rollup/plugin-node-resolve": "^16.0.3",
78
81
  "@types/node": "^25.3.0",
79
82
  "@typescript-eslint/eslint-plugin": "^8.56.0",
80
83
  "@typescript-eslint/parser": "^8.56.0",
81
84
  "assert-diff": "^3.0.4",
82
85
  "benchmark": "^2.1.4",
83
86
  "c8": "^11.0.0",
84
- "cross-env": "^10.1.0",
85
87
  "error-stack-parser": "^2.1.4",
86
88
  "eslint-config-prettier": "^10.1.8",
87
89
  "eslint-plugin-async-await": "^0.0.0",
88
90
  "eslint-plugin-prettier": "^5.5.5",
89
91
  "globals": "^17.3.0",
90
- "poku": "^3.0.3-canary.8f374795",
92
+ "poku": "^4.1.0",
91
93
  "portfinder": "^1.0.38",
92
94
  "prettier": "^3.8.1",
95
+ "rollup": "^4.59.0",
93
96
  "tsx": "^4.21.0",
94
97
  "typescript": "^5.9.3"
98
+ },
99
+ "depup": {
100
+ "changes": {},
101
+ "depsUpdated": 0,
102
+ "originalPackage": "mysql2",
103
+ "originalVersion": "3.20.0",
104
+ "processedAt": "2026-03-16T00:39:43.420Z",
105
+ "smokeTest": "passed"
95
106
  }
96
107
  }
package/promise.d.ts CHANGED
@@ -40,7 +40,7 @@ export interface PreparedStatementInfo {
40
40
  >;
41
41
  }
42
42
 
43
- export interface Connection extends QueryableAndExecutableBase {
43
+ export declare class Connection extends QueryableAndExecutableBase {
44
44
  config: ConnectionOptions;
45
45
 
46
46
  threadId: number;
@@ -81,7 +81,7 @@ export interface Connection extends QueryableAndExecutableBase {
81
81
  format(sql: string, values?: any | any[] | { [param: string]: any }): string;
82
82
  }
83
83
 
84
- export interface PoolConnection extends Connection {
84
+ export declare class PoolConnection extends Connection {
85
85
  release(): void;
86
86
  connection: Connection;
87
87
  [Symbol.asyncDispose](): Promise<void>;
package/promise.js CHANGED
@@ -185,6 +185,8 @@ exports.escape = SqlString.escape;
185
185
  exports.escapeId = SqlString.escapeId;
186
186
  exports.format = SqlString.format;
187
187
  exports.raw = SqlString.raw;
188
+ exports.Connection = PromiseConnection;
189
+ exports.PoolConnection = PromisePoolConnection;
188
190
  exports.PromisePool = PromisePool;
189
191
  exports.PromiseConnection = PromiseConnection;
190
192
  exports.PromisePoolConnection = PromisePoolConnection;
@@ -14,7 +14,6 @@ import {
14
14
  PoolClusterOptions,
15
15
  PoolNamespace,
16
16
  } from './lib/PoolCluster.js';
17
- import { PoolConnection as BasePoolConnection } from './lib/PoolConnection.js';
18
17
  import {
19
18
  Prepare as BasePrepare,
20
19
  PrepareStatementInfo,
@@ -44,11 +43,10 @@ export * from './lib/Auth.js';
44
43
  export * from './lib/constants/index.js';
45
44
  export * from './lib/parsers/index.js';
46
45
  export * from './lib/Connection.js';
46
+ export * from './lib/PoolConnection.js';
47
47
 
48
48
  // Expose class interfaces
49
- export interface Connection extends BaseConnection {}
50
49
  export interface Pool extends BasePool {}
51
- export interface PoolConnection extends BasePoolConnection {}
52
50
  export interface PoolCluster extends BasePoolCluster {}
53
51
  export interface Query extends BaseQuery {}
54
52
  export interface Prepare extends BasePrepare {}
@@ -82,3 +80,10 @@ export interface ConnectionConfig extends ConnectionOptions {
82
80
  }
83
81
 
84
82
  export function createServer(handler: (conn: BaseConnection) => any): Server;
83
+
84
+ export type {
85
+ QueryTraceContext,
86
+ ExecuteTraceContext,
87
+ ConnectTraceContext,
88
+ PoolConnectTraceContext,
89
+ } from './lib/Tracing.js';
@@ -0,0 +1,71 @@
1
+ import type { TracingChannel } from 'node:diagnostics_channel';
2
+
3
+ export interface QueryTraceContext {
4
+ query: string;
5
+ values: any;
6
+ database: string;
7
+ serverAddress: string;
8
+ serverPort: number | undefined;
9
+ }
10
+
11
+ export interface ExecuteTraceContext {
12
+ query: string;
13
+ values: any;
14
+ database: string;
15
+ serverAddress: string;
16
+ serverPort: number | undefined;
17
+ }
18
+
19
+ export interface ConnectTraceContext {
20
+ database: string;
21
+ serverAddress: string;
22
+ serverPort: number | undefined;
23
+ user: string;
24
+ }
25
+
26
+ export interface PoolConnectTraceContext {
27
+ database: string;
28
+ serverAddress: string;
29
+ serverPort: number | undefined;
30
+ }
31
+
32
+ export declare const dc: typeof import('node:diagnostics_channel') | undefined;
33
+ export declare const hasTracingChannel: boolean;
34
+
35
+ export declare function shouldTrace(
36
+ channel: TracingChannel<object> | undefined | null
37
+ ): boolean;
38
+
39
+ export declare function traceCallback<T extends object>(
40
+ channel: TracingChannel<T> | undefined | null,
41
+ fn: (...args: any[]) => any,
42
+ position: number,
43
+ contextFactory: () => T,
44
+ thisArg: any,
45
+ ...args: any[]
46
+ ): any;
47
+
48
+ export declare function tracePromise<T extends object, R>(
49
+ channel: TracingChannel<T> | undefined | null,
50
+ fn: () => Promise<R>,
51
+ contextFactory: () => T
52
+ ): Promise<R>;
53
+
54
+ export declare const queryChannel:
55
+ | TracingChannel<QueryTraceContext>
56
+ | undefined;
57
+ export declare const executeChannel:
58
+ | TracingChannel<ExecuteTraceContext>
59
+ | undefined;
60
+ export declare const connectChannel:
61
+ | TracingChannel<ConnectTraceContext>
62
+ | undefined;
63
+ export declare const poolConnectChannel:
64
+ | TracingChannel<PoolConnectTraceContext>
65
+ | undefined;
66
+
67
+ export declare function getServerContext(config: {
68
+ socketPath?: string;
69
+ host?: string;
70
+ port?: number;
71
+ }): { serverAddress: string; serverPort: number | undefined };
@@ -1,77 +0,0 @@
1
- 'use strict';
2
-
3
- const BaseConnection = require('./connection.js');
4
-
5
- class BasePoolConnection extends BaseConnection {
6
- constructor(pool, options) {
7
- super(options);
8
- this._pool = pool;
9
- // The last active time of this connection
10
- this.lastActiveTime = Date.now();
11
- // When a fatal error occurs the connection's protocol ends, which will cause
12
- // the connection to end as well, thus we only need to watch for the end event
13
- // and we will be notified of disconnects.
14
- // REVIEW: Moved to `once`
15
- this.once('end', () => {
16
- this._removeFromPool();
17
- });
18
- this.once('error', () => {
19
- this._removeFromPool();
20
- });
21
- }
22
-
23
- release() {
24
- if (!this._pool || this._pool._closed) {
25
- return;
26
- }
27
- // update last active time
28
- this.lastActiveTime = Date.now();
29
- this._pool.releaseConnection(this);
30
- }
31
-
32
- [Symbol.dispose]() {
33
- this.release();
34
- }
35
-
36
- end(callback) {
37
- if (this.config.gracefulEnd) {
38
- this._removeFromPool();
39
- super.end(callback);
40
-
41
- return;
42
- }
43
-
44
- const err = new Error(
45
- 'Calling conn.end() to release a pooled connection is ' +
46
- 'deprecated. In next version calling conn.end() will be ' +
47
- 'restored to default conn.end() behavior. Use ' +
48
- 'conn.release() instead.'
49
- );
50
- this.emit('warn', err);
51
- console.warn(err.message);
52
- this.release();
53
- if (typeof callback === 'function') {
54
- callback();
55
- }
56
- }
57
-
58
- destroy() {
59
- this._removeFromPool();
60
- super.destroy();
61
- }
62
-
63
- _removeFromPool() {
64
- if (!this._pool || this._pool._closed) {
65
- return;
66
- }
67
- const pool = this._pool;
68
- this._pool = null;
69
- pool._removeConnection(this);
70
- }
71
- }
72
-
73
- BasePoolConnection.statementKey = BaseConnection.statementKey;
74
- module.exports = BasePoolConnection;
75
-
76
- // TODO: Remove this when we are removing PoolConnection#end
77
- BasePoolConnection.prototype._realEnd = BaseConnection.prototype.end;