From df88284bdaaf259e8dd4b6b0b7388fe4b55aab52 Mon Sep 17 00:00:00 2001 From: Kun Zhou Date: Thu, 19 Oct 2023 13:12:06 -0700 Subject: [PATCH 1/5] Fix server identity check --- lib/connection.js | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/lib/connection.js b/lib/connection.js index 113fc7d46c..7c53554ab2 100644 --- a/lib/connection.js +++ b/lib/connection.js @@ -362,25 +362,17 @@ class Connection extends EventEmitter { const secureSocket = Tls.connect({ rejectUnauthorized, requestCert: rejectUnauthorized, - checkServerIdentity: verifyIdentity - ? Tls.checkServerIdentity - : function() { return undefined; }, secureContext, isServer: false, socket: this.stream, - servername - }, () => { - secureEstablished = true; - if (rejectUnauthorized) { - if (typeof servername === 'string' && verifyIdentity) { - const cert = secureSocket.getPeerCertificate(true); - const serverIdentityCheckError = Tls.checkServerIdentity(servername, cert); - if (serverIdentityCheckError) { - onSecure(serverIdentityCheckError); - return; - } + servername, + checkServerIdentity: (servername, cert) => { + if (rejectUnauthorized && typeof servername === 'string' && verifyIdentity) { + return Tls.checkServerIdentity(servername, cert); } } + }, () => { + secureEstablished = true; onSecure(); }); // error handler for secure socket @@ -411,7 +403,7 @@ class Connection extends EventEmitter { err.code = code || 'PROTOCOL_ERROR'; this.emit('error', err); } - + get fatalError() { return this._fatalError; } From a023b8fb3bcafb317658b5c4e87e44f232ac66fd Mon Sep 17 00:00:00 2001 From: Kun Zhou Date: Wed, 25 Oct 2023 13:42:32 -0700 Subject: [PATCH 2/5] Fix error code for protocol error --- lib/connection.js | 3 ++- test/integration/test-server-close.test.cjs | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/connection.js b/lib/connection.js index 7c53554ab2..f8c03b5032 100644 --- a/lib/connection.js +++ b/lib/connection.js @@ -29,6 +29,7 @@ const Packets = require('./packets/index.js'); const Commands = require('./commands/index.js'); const ConnectionConfig = require('./connection_config.js'); const CharsetToEncoding = require('./constants/charset_encodings.js'); +const ErrorCodeToName = require('./constants/errors.js'); let _connectionId = 0; @@ -440,7 +441,7 @@ class Connection extends EventEmitter { // If it's an Err Packet, we should use it. if (marker === 0xff) { const error = Packets.Error.fromPacket(packet); - this.protocolError(error.message, error.code); + this.protocolError(error.message, ErrorCodeToName[error.code]); } else { // Otherwise, it means it's some other unexpected packet. this.protocolError( diff --git a/test/integration/test-server-close.test.cjs b/test/integration/test-server-close.test.cjs index f5fb76cd22..47c64abb1d 100644 --- a/test/integration/test-server-close.test.cjs +++ b/test/integration/test-server-close.test.cjs @@ -47,5 +47,5 @@ process.on('exit', () => { error.message, 'The client was disconnected by the server because of inactivity. See wait_timeout and interactive_timeout for configuring this behavior.', ); - assert.equal(error.code, errors.ER_CLIENT_INTERACTION_TIMEOUT); + assert.equal(error.code, 'ER_CLIENT_INTERACTION_TIMEOUT'); }); From ffa7bf37411e2302747215d306684078eade3ed8 Mon Sep 17 00:00:00 2001 From: Kun Zhou Date: Thu, 21 Sep 2023 00:18:22 -0700 Subject: [PATCH 3/5] Add warnings count for non-DML/DLL queries like SELECT --- lib/commands/execute.js | 1 + lib/commands/query.js | 14 +++++++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/lib/commands/execute.js b/lib/commands/execute.js index 8ab7304b5b..a685c3a198 100644 --- a/lib/commands/execute.js +++ b/lib/commands/execute.js @@ -20,6 +20,7 @@ class Execute extends Command { this._rows = []; this._fields = []; this._result = []; + this._warningCounts = []; this._fieldCount = 0; this._rowParser = null; this._executeOptions = options; diff --git a/lib/commands/query.js b/lib/commands/query.js index 67386bbfba..55a1aba2a0 100644 --- a/lib/commands/query.js +++ b/lib/commands/query.js @@ -26,6 +26,8 @@ class Query extends Command { this._fieldCount = 0; this._rowParser = null; this._fields = []; + // Warning counts for SELECT queries only, does not included warning counts for DML queries. + this._warningCounts = []; this._rows = []; this._receivedFieldsCount = 0; this._resultIndex = 0; @@ -73,21 +75,23 @@ class Query extends Command { this.queryTimeout = null; } if (this.onResult) { - let rows, fields; + let rows, fields, warningCounts; if (this._resultIndex === 0) { rows = this._rows[0]; fields = this._fields[0]; + warningCounts = this._warningCounts[0]; } else { rows = this._rows; fields = this._fields; + warningCounts = this._warningCounts } if (fields) { process.nextTick(() => { - this.onResult(null, rows, fields); + this.onResult(null, rows, fields, warningCounts); }); } else { process.nextTick(() => { - this.onResult(null, rows); + this.onResult(null, rows, fields, warningCounts); }); } } @@ -105,6 +109,7 @@ class Query extends Command { } this._rows.push(rs); this._fields.push(void 0); + this._warningCounts.push(void 0); this.emit('fields', void 0); this.emit('result', rs); if (rs.serverStatus & ServerStatus.SERVER_MORE_RESULTS_EXISTS) { @@ -132,6 +137,7 @@ class Query extends Command { this._receivedFieldsCount = 0; this._rows.push([]); this._fields.push([]); + this._warningCounts.push(0); return this.readField; } @@ -230,6 +236,8 @@ class Query extends Command { row(packet, _connection) { if (packet.isEOF()) { const status = packet.eofStatusFlags(); + this._warningCounts[this._resultIndex] = packet.eofWarningCount(); + const moreResults = status & ServerStatus.SERVER_MORE_RESULTS_EXISTS; if (moreResults) { this._resultIndex++; From 903107a053daafd400cd15e6469aa3d7815766ba Mon Sep 17 00:00:00 2001 From: Kun Zhou Date: Mon, 13 Nov 2023 19:25:07 -0800 Subject: [PATCH 4/5] Fix big number accuracy --- lib/packets/packet.js | 24 ++++++++----------- .../connection/test-insert-bigint.test.cjs | 16 ++++++------- 2 files changed, 18 insertions(+), 22 deletions(-) diff --git a/lib/packets/packet.js b/lib/packets/packet.js index ccf3a8458c..fc4d9c5388 100644 --- a/lib/packets/packet.js +++ b/lib/packets/packet.js @@ -222,10 +222,9 @@ class Packet { return word1 * 0x100000000 + word0; } res = new Long(word0, word1, !signed); // Long need unsigned - const resNumber = res.toNumber(); const resString = res.toString(); - res = resNumber.toString() === resString ? resNumber : resString; - return bigNumberStrings ? resString : res; + const safeResNumberPreferred = res.greaterThan(Number.MAX_SAFE_INTEGER) || res.lessThan(Number.MIN_SAFE_INTEGER) ? resString : res.toNumber(); + return bigNumberStrings ? resString : safeResNumberPreferred; } // eslint-disable-next-line no-console console.trace(); @@ -425,7 +424,7 @@ class Packet { return StringParser.decode( this.buffer, encoding, - this.offset - len, + this.offset - len, this.offset ); } @@ -450,21 +449,18 @@ class Packet { this.offset++; sign = -1; } - // max precise int is 9007199254740992 + // max precise int is Number.MAX_SAFE_INTEGER 9007199254740991 let str; const numDigits = end - this.offset; if (supportBigNumbers) { if (numDigits >= 15) { str = this.readString(end - this.offset, 'binary'); - result = parseInt(str, 10); - if (result.toString() === str) { - return sign * result; - } - return sign === -1 ? `-${str}` : str; - } - if (numDigits > 16) { - str = this.readString(end - this.offset); - return sign === -1 ? `-${str}` : str; + str = sign === -1 ? `-${str}` : str; + result = Long.fromString(str, false, 10); + if (result.greaterThan(Number.MAX_SAFE_INTEGER) || result.lessThan(Number.MIN_SAFE_INTEGER)) { + return result.toString(); + } + return result.toNumber(); } } if (this.buffer[this.offset] === plus) { diff --git a/test/integration/connection/test-insert-bigint.test.cjs b/test/integration/connection/test-insert-bigint.test.cjs index 664dd7ea25..5728c4c3af 100644 --- a/test/integration/connection/test-insert-bigint.test.cjs +++ b/test/integration/connection/test-insert-bigint.test.cjs @@ -26,18 +26,18 @@ connection.query("INSERT INTO bigs SET title='test1'", (err, result) => { connection.query("INSERT INTO bigs SET title='test2'", (err, result) => { assert.strictEqual(result.insertId, 123456790); // big int - connection.query("INSERT INTO bigs SET title='test', id=9007199254740992"); + connection.query("INSERT INTO bigs SET title='test', id=9007199254740991"); connection.query("INSERT INTO bigs SET title='test3'", (err, result) => { assert.strictEqual( - Long.fromString('9007199254740993').compare(result.insertId), + Long.fromString('9007199254740992').compare(result.insertId), 0, ); connection.query( - "INSERT INTO bigs SET title='test', id=90071992547409924", + "INSERT INTO bigs SET title='test', id=90071992547409923", ); connection.query("INSERT INTO bigs SET title='test4'", (err, result) => { assert.strictEqual( - Long.fromString('90071992547409925').compare(result.insertId), + Long.fromString('90071992547409924').compare(result.insertId), 0, ); connection.query( @@ -51,10 +51,10 @@ connection.query("INSERT INTO bigs SET title='test1'", (err, result) => { assert.strictEqual(result[1].id, 124); assert.strictEqual(result[2].id, 123456789); assert.strictEqual(result[3].id, 123456790); - assert.strictEqual(result[4].id, 9007199254740992); - assert.strictEqual(result[5].id, '9007199254740993'); - assert.strictEqual(result[6].id, '90071992547409924'); - assert.strictEqual(result[7].id, '90071992547409925'); + assert.strictEqual(result[4].id, 9007199254740991); + assert.strictEqual(result[5].id, '9007199254740992'); + assert.strictEqual(result[6].id, '90071992547409923'); + assert.strictEqual(result[7].id, '90071992547409924'); connection.end(); }, ); From 4f26387be98bb77140e6c27e505f7e40bd846ba4 Mon Sep 17 00:00:00 2001 From: Kun Zhou Date: Thu, 21 Mar 2024 03:11:32 -0700 Subject: [PATCH 5/5] Use the same regex as mysqljs for changed rows --- lib/packets/resultset_header.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/packets/resultset_header.js b/lib/packets/resultset_header.js index 8aa17e037e..43b1892a91 100644 --- a/lib/packets/resultset_header.js +++ b/lib/packets/resultset_header.js @@ -91,7 +91,8 @@ class ResultSetHeader { if (stateChanges) { this.stateChanges = stateChanges; } - const m = this.info.match(/\schanged:\s*(\d+)/i); + // Use the same regex as mysqljs at https://github.com/mysqljs/mysql/blob/dc9c152a87ec51a1f647447268917243d2eab1fd/lib/protocol/packets/OkPacket.js#L3C29-L3C91 + const m = this.info.match(/^[^:0-9]+: [0-9]+[^:0-9]+: ([0-9]+)[^:0-9]+: [0-9]+[^:0-9]*$/); if (m !== null) { this.changedRows = parseInt(m[1], 10); } else {