@depup/mysql2 3.19.1-depup.0 → 3.21.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
@@ -13,8 +13,8 @@ npm install @depup/mysql2
13
13
 
14
14
  | Field | Value |
15
15
  |-------|-------|
16
- | Original | [mysql2](https://www.npmjs.com/package/mysql2) @ 3.19.1 |
17
- | Processed | 2026-03-09 |
16
+ | Original | [mysql2](https://www.npmjs.com/package/mysql2) @ 3.21.0 |
17
+ | Processed | 2026-04-09 |
18
18
  | Smoke test | passed |
19
19
  | Deps updated | 0 |
20
20
 
package/changes.json ADDED
@@ -0,0 +1,5 @@
1
+ {
2
+ "bumped": {},
3
+ "timestamp": "2026-04-09T12:30:50.439Z",
4
+ "totalUpdated": 0
5
+ }
@@ -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);
@@ -43,11 +43,15 @@ class Execute extends Command {
43
43
  this._connection = connection;
44
44
  this.options = Object.assign({}, connection.config, this._executeOptions);
45
45
  this._setTimeout();
46
+ const clientFlags =
47
+ connection.config.clientFlags & (connection.serverCapabilityFlags || 0);
46
48
  const executePacket = new Packets.Execute(
47
49
  this.statement.id,
48
50
  this.parameters,
49
51
  connection.config.charsetNumber,
50
- connection.config.timezone
52
+ connection.config.timezone,
53
+ this._executeOptions.attributes,
54
+ clientFlags
51
55
  );
52
56
  //For reasons why this try-catch is here, please see
53
57
  // https://github.com/sidorares/node-mysql2/pull/689
@@ -53,9 +53,13 @@ class Query extends Command {
53
53
  this.options = Object.assign({}, connection.config, this._queryOptions);
54
54
  this._setTimeout();
55
55
 
56
+ const clientFlags =
57
+ connection.config.clientFlags & (connection.serverCapabilityFlags || 0);
56
58
  const cmdPacket = new Packets.Query(
57
59
  this.sql,
58
- connection.config.charsetNumber
60
+ connection.config.charsetNumber,
61
+ this._queryOptions.attributes,
62
+ clientFlags
59
63
  );
60
64
  connection.writePacket(cmdPacket.toPacket(1));
61
65
  return Query.prototype.resultsetHeader;
@@ -239,6 +239,7 @@ class ConnectionConfig {
239
239
  'TRANSACTIONS',
240
240
  'SESSION_TRACK',
241
241
  'CONNECT_ATTRS',
242
+ 'CLIENT_QUERY_ATTRIBUTES',
242
243
  ];
243
244
  if (options && options.multipleStatements) {
244
245
  defaultFlags.push('MULTI_STATEMENTS');
@@ -31,6 +31,7 @@ exports.CONNECT_ATTRS = 0x00100000; /* permits connection attributes */
31
31
  exports.PLUGIN_AUTH_LENENC_CLIENT_DATA = 0x00200000; /* Understands length-encoded integer for auth response data in Protocol::HandshakeResponse41. */
32
32
  exports.CAN_HANDLE_EXPIRED_PASSWORDS = 0x00400000; /* Announces support for expired password extension. */
33
33
  exports.SESSION_TRACK = 0x00800000; /* Can set SERVER_SESSION_STATE_CHANGED in the Status Flags and send session-state change data after a OK packet. */
34
+ exports.CLIENT_QUERY_ATTRIBUTES = 0x08000000; /* support query attributes in COM_QUERY and COM_STMT_EXECUTE */
34
35
 
35
36
  exports.SSL_VERIFY_SERVER_CERT = 0x40000000;
36
37
  exports.REMEMBER_OPTIONS = 0x80000000;
@@ -5,4 +5,5 @@ module.exports = {
5
5
  READ_ONLY: 1,
6
6
  FOR_UPDATE: 2,
7
7
  SCROLLABLE: 3,
8
+ PARAMETER_COUNT_AVAILABLE: 8,
8
9
  };
@@ -0,0 +1,69 @@
1
+ 'use strict';
2
+
3
+ const Types = require('../constants/types');
4
+ const Packet = require('../packets/packet');
5
+
6
+ function isJSON(value) {
7
+ return (
8
+ Array.isArray(value) ||
9
+ value.constructor === Object ||
10
+ (typeof value.toJSON === 'function' && !Buffer.isBuffer(value))
11
+ );
12
+ }
13
+
14
+ function toParameter(value, encoding, timezone) {
15
+ let type = Types.VAR_STRING;
16
+ let length;
17
+ let writer = function (value) {
18
+ // eslint-disable-next-line no-invalid-this
19
+ return Packet.prototype.writeLengthCodedString.call(this, value, encoding);
20
+ };
21
+ if (value !== null) {
22
+ switch (typeof value) {
23
+ case 'undefined':
24
+ throw new TypeError('Bind parameters must not contain undefined');
25
+
26
+ case 'number':
27
+ type = Types.DOUBLE;
28
+ length = 8;
29
+ writer = Packet.prototype.writeDouble;
30
+ break;
31
+
32
+ case 'boolean':
33
+ value = value | 0;
34
+ type = Types.TINY;
35
+ length = 1;
36
+ writer = Packet.prototype.writeInt8;
37
+ break;
38
+
39
+ case 'object':
40
+ if (Object.prototype.toString.call(value) === '[object Date]') {
41
+ type = Types.DATETIME;
42
+ length = 12;
43
+ writer = function (value) {
44
+ // eslint-disable-next-line no-invalid-this
45
+ return Packet.prototype.writeDate.call(this, value, timezone);
46
+ };
47
+ } else if (isJSON(value)) {
48
+ value = JSON.stringify(value);
49
+ type = Types.JSON;
50
+ } else if (Buffer.isBuffer(value)) {
51
+ length = Packet.lengthCodedNumberLength(value.length) + value.length;
52
+ writer = Packet.prototype.writeLengthCodedBuffer;
53
+ }
54
+ break;
55
+
56
+ default:
57
+ value = value.toString();
58
+ }
59
+ } else {
60
+ value = '';
61
+ type = Types.NULL;
62
+ }
63
+ if (!length) {
64
+ length = Packet.lengthCodedStringLength(value, encoding);
65
+ }
66
+ return { value, type, length, writer };
67
+ }
68
+
69
+ module.exports = { toParameter, isJSON };