diff -Nru node-mysql-2.16.0/appveyor.yml node-mysql-2.17.1/appveyor.yml --- node-mysql-2.16.0/appveyor.yml 2018-07-18 03:26:13.000000000 +0000 +++ node-mysql-2.17.1/appveyor.yml 2019-04-18 20:40:03.000000000 +0000 @@ -4,6 +4,7 @@ MYSQL_USER: root MYSQL_PASSWORD: Password12! MYSQL_PATH: C:\Program Files\MySQL\MySQL Server 5.7 + MYSQL_PORT: 3306 matrix: - nodejs_version: "0.8" @@ -14,11 +15,12 @@ - nodejs_version: "3.3" - nodejs_version: "4.9" - nodejs_version: "5.12" - - nodejs_version: "6.14" + - nodejs_version: "6.17" - nodejs_version: "7.10" - - nodejs_version: "8.11" + - nodejs_version: "8.16" - nodejs_version: "9.11" - - nodejs_version: "10.3" + - nodejs_version: "10.15" + - nodejs_version: "11.14" services: - mysql @@ -27,11 +29,12 @@ - node_modules install: - - ps: Install-Product node $env:nodejs_version + - ps: >- + try { Install-Product node $env:nodejs_version -ErrorAction Stop } + catch { Update-NodeJsInstallation (Get-NodeJsLatestBuild $env:nodejs_version) } - npm config set shrinkwrap false - - if "%nodejs_version%" equ "0.8" npm rm --save-dev nyc - if "%nodejs_version%" equ "0.8" npm config set strict-ssl false - - npm rm --save-dev eslint + - npm rm --silent --save-dev eslint - if exist node_modules npm prune - if exist node_modules npm rebuild - npm install @@ -40,14 +43,13 @@ before_test: - SET PATH=%MYSQL_PATH%\bin;%PATH% + - node tool/wait-mysql.js %MYSQL_PORT% %MYSQL_HOST% - mysqladmin --host=%MYSQL_HOST% --user=%MYSQL_USER% --password=%MYSQL_PASSWORD% create %MYSQL_DATABASE% test_script: - mysql --version - node --version - npm --version - - set npm_test_command=test - - for /f %%l in ('npm -ps ls nyc') do set npm_test_command=test-ci - - npm run %npm_test_command% + - npm test version: "{build}" diff -Nru node-mysql-2.16.0/Changes.md node-mysql-2.17.1/Changes.md --- node-mysql-2.16.0/Changes.md 2018-07-18 03:26:13.000000000 +0000 +++ node-mysql-2.17.1/Changes.md 2019-04-18 20:40:03.000000000 +0000 @@ -4,6 +4,23 @@ to add your changes here when sending pull requests. Also send corrections if you spot any mistakes. +## v2.17.1 (2019-04-18) + +* Update `bignumber.js` to 7.2.1 #2206 + - Fix npm deprecation warning + +## v2.17.0 (2019-04-17) + +* Add reverse type lookup for small performance gain #2170 +* Fix `connection.threadId` missing on handshake failure +* Fix duplicate packet name in debug output +* Fix no password support for old password protocol +* Remove special case for handshake in determine packet code +* Small performance improvement starting command sequence +* Support auth switch in change user flow #1776 +* Support Node.js 11.x +* Update `bignumber.js` to 6.0.0 + ## v2.16.0 (2018-07-17) * Add Amazon RDS GovCloud SSL certificates #1876 diff -Nru node-mysql-2.16.0/debian/changelog node-mysql-2.17.1/debian/changelog --- node-mysql-2.16.0/debian/changelog 2019-08-03 13:43:30.000000000 +0000 +++ node-mysql-2.17.1/debian/changelog 2019-09-10 19:43:28.000000000 +0000 @@ -1,3 +1,11 @@ +node-mysql (2.17.1-1) unstable; urgency=medium + + * Team upload + * New upstream version 2.17.1 + * Fix minimal version of node-bignumber + + -- Xavier Guimard Tue, 10 Sep 2019 21:43:28 +0200 + node-mysql (2.16.0-2) unstable; urgency=medium * Team upload diff -Nru node-mysql-2.16.0/debian/control node-mysql-2.17.1/debian/control --- node-mysql-2.16.0/debian/control 2019-08-01 18:14:27.000000000 +0000 +++ node-mysql-2.17.1/debian/control 2019-08-13 20:31:03.000000000 +0000 @@ -7,7 +7,7 @@ Build-Depends: debhelper-compat (= 12), nodejs, node-require-all, - node-bignumber, + node-bignumber (>= 7.2.1~), pkg-js-tools (>= 0.8.8) Standards-Version: 4.4.0 Vcs-Browser: https://salsa.debian.org/js-team/node-mysql diff -Nru node-mysql-2.16.0/lib/Connection.js node-mysql-2.17.1/lib/Connection.js --- node-mysql-2.16.0/lib/Connection.js 2018-07-18 03:26:13.000000000 +0000 +++ node-mysql-2.17.1/lib/Connection.js 2019-04-18 20:40:03.000000000 +0000 @@ -100,6 +100,7 @@ this._socket.on('error', this._handleNetworkError.bind(this)); this._socket.on('connect', this._handleProtocolConnect.bind(this)); this._protocol.on('handshake', this._handleProtocolHandshake.bind(this)); + this._protocol.on('initialize', this._handleProtocolInitialize.bind(this)); this._protocol.on('unhandledError', this._handleProtocolError.bind(this)); this._protocol.on('drain', this._handleProtocolDrain.bind(this)); this._protocol.on('end', this._handleProtocolEnd.bind(this)); @@ -276,52 +277,52 @@ if (tls.TLSSocket) { // 0.11+ environment Connection.prototype._startTLS = function _startTLS(onSecure) { - var connection = this; - var secureContext = tls.createSecureContext({ - ca : this.config.ssl.ca, - cert : this.config.ssl.cert, - ciphers : this.config.ssl.ciphers, - key : this.config.ssl.key, - passphrase : this.config.ssl.passphrase - }); - - // "unpipe" - this._socket.removeAllListeners('data'); - this._protocol.removeAllListeners('data'); + var connection = this; - // socket <-> encrypted - var rejectUnauthorized = this.config.ssl.rejectUnauthorized; - var secureEstablished = false; - var secureSocket = new tls.TLSSocket(this._socket, { - rejectUnauthorized : rejectUnauthorized, - requestCert : true, - secureContext : secureContext, - isServer : false - }); - - // error handler for secure socket - secureSocket.on('_tlsError', function(err) { - if (secureEstablished) { - connection._handleNetworkError(err); - } else { + createSecureContext(this.config, function (err, secureContext) { + if (err) { onSecure(err); + return; } - }); - // cleartext <-> protocol - secureSocket.pipe(this._protocol); - this._protocol.on('data', function(data) { - secureSocket.write(data); - }); + // "unpipe" + connection._socket.removeAllListeners('data'); + connection._protocol.removeAllListeners('data'); + + // socket <-> encrypted + var rejectUnauthorized = connection.config.ssl.rejectUnauthorized; + var secureEstablished = false; + var secureSocket = new tls.TLSSocket(connection._socket, { + rejectUnauthorized : rejectUnauthorized, + requestCert : true, + secureContext : secureContext, + isServer : false + }); - secureSocket.on('secure', function() { - secureEstablished = true; + // error handler for secure socket + secureSocket.on('_tlsError', function(err) { + if (secureEstablished) { + connection._handleNetworkError(err); + } else { + onSecure(err); + } + }); - onSecure(rejectUnauthorized ? this.ssl.verifyError() : null); - }); + // cleartext <-> protocol + secureSocket.pipe(connection._protocol); + connection._protocol.on('data', function(data) { + secureSocket.write(data); + }); - // start TLS communications - secureSocket._start(); + secureSocket.on('secure', function() { + secureEstablished = true; + + onSecure(rejectUnauthorized ? this.ssl.verifyError() : null); + }); + + // start TLS communications + secureSocket._start(); + }); }; } else { // pre-0.11 environment @@ -434,8 +435,11 @@ this.emit('connect'); }; -Connection.prototype._handleProtocolHandshake = function _handleProtocolHandshake(packet) { - this.state = 'authenticated'; +Connection.prototype._handleProtocolHandshake = function _handleProtocolHandshake() { + this.state = 'authenticated'; +}; + +Connection.prototype._handleProtocolInitialize = function _handleProtocolInitialize(packet) { this.threadId = packet.threadId; }; @@ -454,6 +458,25 @@ } }; +function createSecureContext (config, cb) { + var context = null; + var error = null; + + try { + context = tls.createSecureContext({ + ca : config.ssl.ca, + cert : config.ssl.cert, + ciphers : config.ssl.ciphers, + key : config.ssl.key, + passphrase : config.ssl.passphrase + }); + } catch (err) { + error = err; + } + + cb(error, context); +} + function unwrapFromDomain(fn) { return function () { var domains = []; diff -Nru node-mysql-2.16.0/lib/protocol/Auth.js node-mysql-2.17.1/lib/protocol/Auth.js --- node-mysql-2.16.0/lib/protocol/Auth.js 2018-07-18 03:26:13.000000000 +0000 +++ node-mysql-2.17.1/lib/protocol/Auth.js 2019-04-18 20:40:03.000000000 +0000 @@ -2,6 +2,18 @@ var Crypto = require('crypto'); var Auth = exports; +function auth(name, data, options) { + options = options || {}; + + switch (name) { + case 'mysql_native_password': + return Auth.token(options.password, data.slice(0, 20)); + default: + return undefined; + } +} +Auth.auth = auth; + function sha1(msg) { var hash = Crypto.createHash('sha1'); hash.update(msg, 'binary'); @@ -86,6 +98,10 @@ }; Auth.scramble323 = function(message, password) { + if (!password) { + return Buffer.alloc(0); + } + var to = Buffer.allocUnsafe(8); var hashPass = this.hashPassword(password); var hashMessage = this.hashPassword(message.slice(0, 8)); diff -Nru node-mysql-2.16.0/lib/protocol/constants/types.js node-mysql-2.17.1/lib/protocol/constants/types.js --- node-mysql-2.16.0/lib/protocol/constants/types.js 2018-07-18 03:26:13.000000000 +0000 +++ node-mysql-2.17.1/lib/protocol/constants/types.js 2019-04-18 20:40:03.000000000 +0000 @@ -1,33 +1,72 @@ -// Manually extracted from mysql-5.7.9/include/mysql.h.pp -// some more info here: http://dev.mysql.com/doc/refman/5.5/en/c-api-prepared-statement-type-codes.html -exports.DECIMAL = 0x00; // aka DECIMAL (http://dev.mysql.com/doc/refman/5.0/en/precision-math-decimal-changes.html) -exports.TINY = 0x01; // aka TINYINT, 1 byte -exports.SHORT = 0x02; // aka SMALLINT, 2 bytes -exports.LONG = 0x03; // aka INT, 4 bytes -exports.FLOAT = 0x04; // aka FLOAT, 4-8 bytes -exports.DOUBLE = 0x05; // aka DOUBLE, 8 bytes -exports.NULL = 0x06; // NULL (used for prepared statements, I think) -exports.TIMESTAMP = 0x07; // aka TIMESTAMP -exports.LONGLONG = 0x08; // aka BIGINT, 8 bytes -exports.INT24 = 0x09; // aka MEDIUMINT, 3 bytes -exports.DATE = 0x0a; // aka DATE -exports.TIME = 0x0b; // aka TIME -exports.DATETIME = 0x0c; // aka DATETIME -exports.YEAR = 0x0d; // aka YEAR, 1 byte (don't ask) -exports.NEWDATE = 0x0e; // aka ? -exports.VARCHAR = 0x0f; // aka VARCHAR (?) -exports.BIT = 0x10; // aka BIT, 1-8 byte -exports.TIMESTAMP2 = 0x11; // aka TIMESTAMP with fractional seconds -exports.DATETIME2 = 0x12; // aka DATETIME with fractional seconds -exports.TIME2 = 0x13; // aka TIME with fractional seconds -exports.JSON = 0xf5; // aka JSON -exports.NEWDECIMAL = 0xf6; // aka DECIMAL -exports.ENUM = 0xf7; // aka ENUM -exports.SET = 0xf8; // aka SET -exports.TINY_BLOB = 0xf9; // aka TINYBLOB, TINYTEXT -exports.MEDIUM_BLOB = 0xfa; // aka MEDIUMBLOB, MEDIUMTEXT -exports.LONG_BLOB = 0xfb; // aka LONGBLOG, LONGTEXT -exports.BLOB = 0xfc; // aka BLOB, TEXT -exports.VAR_STRING = 0xfd; // aka VARCHAR, VARBINARY -exports.STRING = 0xfe; // aka CHAR, BINARY -exports.GEOMETRY = 0xff; // aka GEOMETRY +/** + * MySQL type constants + * + * Extracted from version 5.7.19 + * + * !! Generated by generate-type-constants.js, do not modify by hand !! + */ + +exports.DECIMAL = 0; +exports.TINY = 1; +exports.SHORT = 2; +exports.LONG = 3; +exports.FLOAT = 4; +exports.DOUBLE = 5; +exports.NULL = 6; +exports.TIMESTAMP = 7; +exports.LONGLONG = 8; +exports.INT24 = 9; +exports.DATE = 10; +exports.TIME = 11; +exports.DATETIME = 12; +exports.YEAR = 13; +exports.NEWDATE = 14; +exports.VARCHAR = 15; +exports.BIT = 16; +exports.TIMESTAMP2 = 17; +exports.DATETIME2 = 18; +exports.TIME2 = 19; +exports.JSON = 245; +exports.NEWDECIMAL = 246; +exports.ENUM = 247; +exports.SET = 248; +exports.TINY_BLOB = 249; +exports.MEDIUM_BLOB = 250; +exports.LONG_BLOB = 251; +exports.BLOB = 252; +exports.VAR_STRING = 253; +exports.STRING = 254; +exports.GEOMETRY = 255; + +// Lookup-by-number table +exports[0] = 'DECIMAL'; +exports[1] = 'TINY'; +exports[2] = 'SHORT'; +exports[3] = 'LONG'; +exports[4] = 'FLOAT'; +exports[5] = 'DOUBLE'; +exports[6] = 'NULL'; +exports[7] = 'TIMESTAMP'; +exports[8] = 'LONGLONG'; +exports[9] = 'INT24'; +exports[10] = 'DATE'; +exports[11] = 'TIME'; +exports[12] = 'DATETIME'; +exports[13] = 'YEAR'; +exports[14] = 'NEWDATE'; +exports[15] = 'VARCHAR'; +exports[16] = 'BIT'; +exports[17] = 'TIMESTAMP2'; +exports[18] = 'DATETIME2'; +exports[19] = 'TIME2'; +exports[245] = 'JSON'; +exports[246] = 'NEWDECIMAL'; +exports[247] = 'ENUM'; +exports[248] = 'SET'; +exports[249] = 'TINY_BLOB'; +exports[250] = 'MEDIUM_BLOB'; +exports[251] = 'LONG_BLOB'; +exports[252] = 'BLOB'; +exports[253] = 'VAR_STRING'; +exports[254] = 'STRING'; +exports[255] = 'GEOMETRY'; diff -Nru node-mysql-2.16.0/lib/protocol/packets/Field.js node-mysql-2.17.1/lib/protocol/packets/Field.js --- node-mysql-2.16.0/lib/protocol/packets/Field.js 2018-07-18 03:26:13.000000000 +0000 +++ node-mysql-2.17.1/lib/protocol/packets/Field.js 2019-04-18 20:40:03.000000000 +0000 @@ -9,7 +9,7 @@ this.db = options.packet.db; this.table = options.packet.table; this.name = options.packet.name; - this.type = typeToString(options.packet.type); + this.type = Types[options.packet.type]; this.length = options.packet.length; } @@ -24,11 +24,3 @@ Field.prototype.geometry = function () { return this.parser.parseGeometryValue(); }; - -function typeToString(t) { - for (var k in Types) { - if (Types[k] === t) return k; - } - - return undefined; -} diff -Nru node-mysql-2.16.0/lib/protocol/packets/OldPasswordPacket.js node-mysql-2.17.1/lib/protocol/packets/OldPasswordPacket.js --- node-mysql-2.16.0/lib/protocol/packets/OldPasswordPacket.js 2018-07-18 03:26:13.000000000 +0000 +++ node-mysql-2.17.1/lib/protocol/packets/OldPasswordPacket.js 2019-04-18 20:40:03.000000000 +0000 @@ -6,10 +6,9 @@ } OldPasswordPacket.prototype.parse = function(parser) { - this.scrambleBuff = parser.parseNullTerminatedBuffer(); + this.scrambleBuff = parser.parsePacketTerminatedBuffer(); }; OldPasswordPacket.prototype.write = function(writer) { writer.writeBuffer(this.scrambleBuff); - writer.writeFiller(1); }; diff -Nru node-mysql-2.16.0/lib/protocol/packets/RowDataPacket.js node-mysql-2.17.1/lib/protocol/packets/RowDataPacket.js --- node-mysql-2.16.0/lib/protocol/packets/RowDataPacket.js 2018-07-18 03:26:13.000000000 +0000 +++ node-mysql-2.17.1/lib/protocol/packets/RowDataPacket.js 2019-04-18 20:40:03.000000000 +0000 @@ -123,10 +123,7 @@ function typeMatch(type, list) { if (Array.isArray(list)) { - for (var i = 0; i < list.length; i++) { - if (Types[list[i]] === type) return true; - } - return false; + return list.indexOf(Types[type]) !== -1; } else { return Boolean(list); } diff -Nru node-mysql-2.16.0/lib/protocol/Parser.js node-mysql-2.17.1/lib/protocol/Parser.js --- node-mysql-2.16.0/lib/protocol/Parser.js 2018-07-18 03:26:13.000000000 +0000 +++ node-mysql-2.17.1/lib/protocol/Parser.js 2019-04-18 20:40:03.000000000 +0000 @@ -1,9 +1,11 @@ -var MAX_PACKET_LENGTH = Math.pow(2, 24) - 1; -var MUL_32BIT = Math.pow(2, 32); -var PacketHeader = require('./PacketHeader'); -var BigNumber = require('bignumber.js'); -var Buffer = require('safe-buffer').Buffer; -var BufferList = require('./BufferList'); +var PacketHeader = require('./PacketHeader'); +var BigNumber = require('bignumber.js'); +var Buffer = require('safe-buffer').Buffer; +var BufferList = require('./BufferList'); + +var MAX_PACKET_LENGTH = Math.pow(2, 24) - 1; +var MUL_32BIT = Math.pow(2, 32); +var PACKET_HEADER_LENGTH = 4; module.exports = Parser; function Parser(options) { @@ -28,71 +30,17 @@ this._nextBuffers.push(chunk); while (!this._paused) { - if (!this._packetHeader) { - if (!this._combineNextBuffers(4)) { - break; - } - - this._packetHeader = new PacketHeader( - this.parseUnsignedNumber(3), - this.parseUnsignedNumber(1) - ); - - if (this._packetHeader.number !== this._nextPacketNumber) { - var err = new Error( - 'Packets out of order. Got: ' + this._packetHeader.number + ' ' + - 'Expected: ' + this._nextPacketNumber - ); - - err.code = 'PROTOCOL_PACKETS_OUT_OF_ORDER'; - err.fatal = true; + var packetHeader = this._tryReadPacketHeader(); - this._onError(err); - } - - this.incrementPacketNumber(); - } - - if (!this._combineNextBuffers(this._packetHeader.length)) { + if (!packetHeader) { break; } - this._packetEnd = this._offset + this._packetHeader.length; - this._packetOffset = this._offset; - - if (this._packetHeader.length === MAX_PACKET_LENGTH) { - this._longPacketBuffers.push(this._buffer.slice(this._packetOffset, this._packetEnd)); - - this._advanceToNextPacket(); - continue; + if (!this._combineNextBuffers(packetHeader.length)) { + break; } - this._combineLongPacketBuffers(); - - // Try...finally to ensure exception safety. Unfortunately this is costing - // us up to ~10% performance in some benchmarks. - var hadException = true; - try { - this._onPacket(this._packetHeader); - hadException = false; - } catch (err) { - if (!err || typeof err.code !== 'string' || err.code.substr(0, 7) !== 'PARSER_') { - throw err; // Rethrow non-MySQL errors - } - - // Pass down parser errors - this._onError(err); - hadException = false; - } finally { - this._advanceToNextPacket(); - - // If we had an exception, the parser while loop will be broken out - // of after the finally block. So we need to make sure to re-enter it - // to continue parsing any bytes that may already have been received. - if (hadException) { - process.nextTick(this.write.bind(this)); - } - } + this._parsePacket(packetHeader); } }; @@ -252,7 +200,7 @@ var value; if (high >>> 21) { - value = (new BigNumber(low)).plus((new BigNumber(MUL_32BIT)).times(high)).toString(); + value = BigNumber(MUL_32BIT).times(high).plus(low).toString(); if (this._supportBigNumbers) { return value; @@ -468,6 +416,73 @@ this._packetOffset = 0; }; +Parser.prototype._parsePacket = function _parsePacket(packetHeader) { + this._packetEnd = this._offset + packetHeader.length; + this._packetOffset = this._offset; + + if (packetHeader.length === MAX_PACKET_LENGTH) { + this._longPacketBuffers.push(this._buffer.slice(this._packetOffset, this._packetEnd)); + this._advanceToNextPacket(); + return; + } + + this._combineLongPacketBuffers(); + + var hadException = true; + try { + this._onPacket(packetHeader); + hadException = false; + } catch (err) { + if (!err || typeof err.code !== 'string' || err.code.substr(0, 7) !== 'PARSER_') { + throw err; // Rethrow non-MySQL errors + } + + // Pass down parser errors + this._onError(err); + hadException = false; + } finally { + this._advanceToNextPacket(); + + // If there was an exception, the parser while loop will be broken out + // of after the finally block. So schedule a blank write to re-enter it + // to continue parsing any bytes that may already have been received. + if (hadException) { + process.nextTick(this.write.bind(this)); + } + } +}; + +Parser.prototype._tryReadPacketHeader = function _tryReadPacketHeader() { + if (this._packetHeader) { + return this._packetHeader; + } + + if (!this._combineNextBuffers(PACKET_HEADER_LENGTH)) { + return null; + } + + this._packetHeader = new PacketHeader( + this.parseUnsignedNumber(3), + this.parseUnsignedNumber(1) + ); + + if (this._packetHeader.number !== this._nextPacketNumber) { + var err = new Error( + 'Packets out of order. Got: ' + this._packetHeader.number + ' ' + + 'Expected: ' + this._nextPacketNumber + ); + + err.code = 'PROTOCOL_PACKETS_OUT_OF_ORDER'; + err.fatal = true; + + this._onError(err); + } + + this.incrementPacketNumber(); + + return this._packetHeader; +}; + Parser.prototype._advanceToNextPacket = function() { this._offset = this._packetEnd; this._packetHeader = null; diff -Nru node-mysql-2.16.0/lib/protocol/Protocol.js node-mysql-2.17.1/lib/protocol/Protocol.js --- node-mysql-2.16.0/lib/protocol/Protocol.js 2018-07-18 03:26:13.000000000 +0000 +++ node-mysql-2.17.1/lib/protocol/Protocol.js 2019-04-18 20:40:03.000000000 +0000 @@ -156,9 +156,6 @@ sequence._timer.active(); self._emitPacket(packet); }) - .on('end', function() { - self._dequeue(sequence); - }) .on('timeout', function() { var err = new Error(sequence.constructor.name + ' inactivity timeout'); @@ -167,8 +164,10 @@ err.timeout = sequence._timeout; self._delegateError(err, sequence); - }) - .on('start-tls', function() { + }); + + if (sequence.constructor === Sequences.Handshake) { + sequence.on('start-tls', function () { sequence._timer.active(); self._connection._startTLS(function(err) { if (err) { @@ -184,6 +183,19 @@ }); }); + sequence.on('end', function () { + self._handshaked = true; + + if (!self._fatalError) { + self.emit('handshake', self._handshakeInitializationPacket); + } + }); + } + + sequence.on('end', function () { + self._dequeue(sequence); + }); + if (this._queue.length === 1) { this._parser.resetPacketNumber(); this._startSequence(sequence); @@ -262,6 +274,7 @@ if (Packet === Packets.HandshakeInitializationPacket) { this._handshakeInitializationPacket = packet; + this.emit('initialize', packet); } sequence._timer.active(); @@ -307,12 +320,7 @@ } switch (firstByte) { - case 0x00: - if (!this._handshaked) { - this._handshaked = true; - this.emit('handshake', this._handshakeInitializationPacket); - } - return Packets.OkPacket; + case 0x00: return Packets.OkPacket; case 0xfe: return Packets.EofPacket; case 0xff: return Packets.ErrorPacket; } @@ -436,22 +444,20 @@ Protocol.prototype._debugPacket = function(incoming, packet) { var connection = this._connection; - var headline = incoming - ? '<-- ' - : '--> '; - - if (connection && connection.threadId !== null) { - headline += '(' + connection.threadId + ') '; - } - - headline += packet.constructor.name; + var direction = incoming + ? '<--' + : '-->'; + var packetName = packet.constructor.name; + var threadId = connection && connection.threadId !== null + ? ' (' + connection.threadId + ')' + : ''; // check for debug packet restriction - if (Array.isArray(this._config.debug) && this._config.debug.indexOf(packet.constructor.name) === -1) { + if (Array.isArray(this._config.debug) && this._config.debug.indexOf(packetName) === -1) { return; } - console.log(headline); - console.log(packet); - console.log(''); + var packetPayload = Util.inspect(packet).replace(/^[^{]+/, ''); + + console.log('%s%s %s %s\n', direction, threadId, packetName, packetPayload); }; diff -Nru node-mysql-2.16.0/lib/protocol/sequences/ChangeUser.js node-mysql-2.17.1/lib/protocol/sequences/ChangeUser.js --- node-mysql-2.16.0/lib/protocol/sequences/ChangeUser.js 2018-07-18 03:26:13.000000000 +0000 +++ node-mysql-2.17.1/lib/protocol/sequences/ChangeUser.js 2019-04-18 20:40:03.000000000 +0000 @@ -15,6 +15,14 @@ this._currentConfig = options.currentConfig; } +ChangeUser.prototype.determinePacket = function determinePacket(firstByte) { + switch (firstByte) { + case 0xfe: return Packets.AuthSwitchRequestPacket; + case 0xff: return Packets.ErrorPacket; + default: return undefined; + } +}; + ChangeUser.prototype.start = function(handshakeInitializationPacket) { var scrambleBuff = handshakeInitializationPacket.scrambleBuff(); scrambleBuff = Auth.token(this._password, scrambleBuff); @@ -34,6 +42,24 @@ this.emit('packet', packet); }; +ChangeUser.prototype['AuthSwitchRequestPacket'] = function (packet) { + var name = packet.authMethodName; + var data = Auth.auth(name, packet.authMethodData, { + password: this._password + }); + + if (data !== undefined) { + this.emit('packet', new Packets.AuthSwitchResponsePacket({ + data: data + })); + } else { + var err = new Error('MySQL is requesting the ' + name + ' authentication method, which is not supported.'); + err.code = 'UNSUPPORTED_AUTH_METHOD'; + err.fatal = true; + this.end(err); + } +}; + ChangeUser.prototype['ErrorPacket'] = function(packet) { var err = this._packetToError(packet); err.fatal = true; diff -Nru node-mysql-2.16.0/lib/protocol/sequences/Handshake.js node-mysql-2.17.1/lib/protocol/sequences/Handshake.js --- node-mysql-2.16.0/lib/protocol/sequences/Handshake.js 2018-07-18 03:26:13.000000000 +0000 +++ node-mysql-2.17.1/lib/protocol/sequences/Handshake.js 2019-04-18 20:40:03.000000000 +0000 @@ -34,20 +34,19 @@ }; Handshake.prototype['AuthSwitchRequestPacket'] = function (packet) { - if (packet.authMethodName === 'mysql_native_password') { - var challenge = packet.authMethodData.slice(0, 20); + var name = packet.authMethodName; + var data = Auth.auth(name, packet.authMethodData, { + password: this._config.password + }); + if (data !== undefined) { this.emit('packet', new Packets.AuthSwitchResponsePacket({ - data: Auth.token(this._config.password, challenge) + data: data })); } else { - var err = new Error( - 'MySQL is requesting the ' + packet.authMethodName + ' authentication method, which is not supported.' - ); - - err.code = 'UNSUPPORTED_AUTH_METHOD'; + var err = new Error('MySQL is requesting the ' + name + ' authentication method, which is not supported.'); + err.code = 'UNSUPPORTED_AUTH_METHOD'; err.fatal = true; - this.end(err); } }; diff -Nru node-mysql-2.16.0/package.json node-mysql-2.17.1/package.json --- node-mysql-2.16.0/package.json 2018-07-18 03:26:13.000000000 +0000 +++ node-mysql-2.17.1/package.json 2019-04-18 20:40:03.000000000 +0000 @@ -1,7 +1,7 @@ { "name": "mysql", "description": "A node.js driver for mysql. It is written in JavaScript, does not require compiling, and is 100% MIT licensed.", - "version": "2.16.0", + "version": "2.17.1", "license": "MIT", "author": "Felix Geisendörfer (http://debuggable.com/)", "contributors": [ @@ -13,16 +13,15 @@ ], "repository": "mysqljs/mysql", "dependencies": { - "bignumber.js": "4.1.0", + "bignumber.js": "7.2.1", "readable-stream": "2.3.6", "safe-buffer": "5.1.2", "sqlstring": "2.3.1" }, "devDependencies": { "after": "0.8.2", - "eslint": "4.19.1", - "nyc": "10.3.2", - "seedrandom": "2.4.3", + "eslint": "5.15.1", + "seedrandom": "3.0.1", "timezone-mock": "0.0.7", "urun": "0.0.8", "utest": "0.0.8" @@ -40,8 +39,8 @@ "scripts": { "lint": "eslint .", "test": "node test/run.js", - "test-ci": "nyc --reporter=text npm test", - "test-cov": "nyc --reporter=html --reporter=text npm test", + "test-ci": "node tool/install-nyc.js --nyc-optional --reporter=text -- npm test", + "test-cov": "node tool/install-nyc.js --reporter=html --reporter=text -- npm test", "version": "node tool/version-changes.js && git add Changes.md" } } diff -Nru node-mysql-2.16.0/Readme.md node-mysql-2.17.1/Readme.md --- node-mysql-2.16.0/Readme.md 2018-07-18 03:26:13.000000000 +0000 +++ node-mysql-2.17.1/Readme.md 2019-04-18 20:40:03.000000000 +0000 @@ -1,8 +1,8 @@ # mysql -[![NPM Version][npm-image]][npm-url] -[![NPM Downloads][downloads-image]][downloads-url] -[![Node.js Version][node-version-image]][node-version-url] +[![NPM Version][npm-version-image]][npm-url] +[![NPM Downloads][npm-downloads-image]][npm-url] +[![Node.js Version][node-image]][node-url] [![Linux Build][travis-image]][travis-url] [![Windows Build][appveyor-image]][appveyor-url] [![Test Coverage][coveralls-image]][coveralls-url] @@ -221,7 +221,7 @@ objects only when they cannot be accurately represented with [JavaScript Number objects] (http://ecma262-5.com/ELS5_HTML.htm#Section_8.5) (which happens when they exceed the [-2^53, +2^53] range), otherwise they will be returned as Number objects. This option is ignored if `supportBigNumbers` is disabled. -* `dateStrings`: Force date types (TIMESTAMP, DATETIME, DATE) to be returned as strings rather then +* `dateStrings`: Force date types (TIMESTAMP, DATETIME, DATE) to be returned as strings rather than inflated into JavaScript Date objects. Can be `true`/`false` or an array of type names to keep as strings. (Default: `false`) * `debug`: Prints protocol details to stdout. Can be `true`/`false` or an array of packet type names @@ -381,7 +381,9 @@ * `acquireTimeout`: The milliseconds before a timeout occurs during the connection acquisition. This is slightly different from `connectTimeout`, because acquiring - a pool connection does not always involve making a connection. (Default: `10000`) + a pool connection does not always involve making a connection. If a connection + request is queued, the time the request spends in the queue does not count + towards this timeout. (Default: `10000`) * `waitForConnections`: Determines the pool's action when no connections are available and the limit has been reached. If `true`, the pool will queue the connection request and call it when one becomes available. If `false`, the @@ -1155,11 +1157,14 @@ Most errors created by this module are instances of the JavaScript [Error][] object. Additionally they typically come with two extra properties: -* `err.code`: Either a [MySQL server error][] (e.g. - `'ER_ACCESS_DENIED_ERROR'`), a Node.js error (e.g. `'ECONNREFUSED'`) or an - internal error (e.g. `'PROTOCOL_CONNECTION_LOST'`). +* `err.code`: String, contains the MySQL server error symbol if the error is + a [MySQL server error][] (e.g. `'ER_ACCESS_DENIED_ERROR'`), a Node.js error + code if it is a Node.js error (e.g. `'ECONNREFUSED'`), or an internal error + code (e.g. `'PROTOCOL_CONNECTION_LOST'`). +* `err.errno`: Number, contains the MySQL server error number. Only populated + from [MySQL server error][]. * `err.fatal`: Boolean, indicating if this error is terminal to the connection - object. If the error is not from a MySQL protocol operation, this properly + object. If the error is not from a MySQL protocol operation, this property will not be defined. * `err.sql`: String, contains the full SQL of the failed query. This can be useful when using a higher level interface like an ORM that is generating @@ -1169,7 +1174,7 @@ textual description of the error. Only populated from [MySQL server error][]. [Error]: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error -[MySQL server error]: http://dev.mysql.com/doc/refman/5.5/en/error-messages-server.html +[MySQL server error]: https://dev.mysql.com/doc/refman/5.5/en/server-error-reference.html Fatal errors are propagated to *all* pending callbacks. In the example below, a fatal error is triggered by trying to connect to an invalid port. Therefore the @@ -1303,37 +1308,58 @@ }); ``` +### Custom type casting + You can also pass a function and handle type casting yourself. You're given some column information like database, table and name and also type and length. If you just want to apply a custom type casting to a specific type you can do it and then -fallback to the default. Here's an example of converting `TINYINT(1)` to boolean: +fallback to the default. + +The function is provided two arguments `field` and `next` and is expected to +return the value for the given field by invoking the parser functions through +the `field` object. + +The `field` argument is a `Field` object and contains data about the field that +need to be parsed. The following are some of the properties on a `Field` object: + + * `db` - a string of the database the field came from. + * `table` - a string of the table the field came from. + * `name` - a string of the field name. + * `type` - a string of the field type in all caps. + * `length` - a number of the field length, as given by the database. + +The `next` argument is a `function` that, when called, will return the default +type conversaion for the given field. + +When getting the field data, the following helper methods are present on the +`field` object: + + * `.string()` - parse the field into a string. + * `.buffer()` - parse the field into a `Buffer`. + * `.geometry()` - parse the field as a geometry value. + +The MySQL protocol is a text-based protocol. This means that over the wire, all +field types are represented as a string, which is why only string-like functions +are available on the `field` object. Based on the type information (like `INT`), +the type cast should convert the string field into a different JavaScript type +(like a `number`). + +Here's an example of converting `TINYINT(1)` to boolean: ```js -connection.query({ - sql: '...', +connection = mysql.createConnection({ typeCast: function (field, next) { - if (field.type == 'TINY' && field.length == 1) { - return (field.string() == '1'); // 1 = true, 0 = false + if (field.type === 'TINY' && field.length === 1) { + return (field.string() === '1'); // 1 = true, 0 = false + } else { + return next(); } - return next(); } }); ``` -__WARNING: YOU MUST INVOKE the parser using one of these three field functions in your custom typeCast callback. They can only be called once. (see [#539](https://github.com/mysqljs/mysql/issues/539) for discussion)__ - -``` -field.string() -field.buffer() -field.geometry() -``` -are aliases for -``` -parser.parseLengthCodedString() -parser.parseLengthCodedBuffer() -parser.parseGeometryValue() -``` -__You can find which field function you need to use by looking at: [RowDataPacket.prototype._typeCast](https://github.com/mysqljs/mysql/blob/master/lib/protocol/packets/RowDataPacket.js#L41)__ +__WARNING: YOU MUST INVOKE the parser using one of these three field functions +in your custom typeCast callback. They can only be called once.__ ## Connection Flags @@ -1430,8 +1456,8 @@ addressed to without disclosing the issue or type of issue. An ideal report would include a clear indication of what the security issue is -and how it would be exploited, ideally with an accompaning proof of concept -("PoC") for collaborators to work again and validate potentional fixes against. +and how it would be exploited, ideally with an accompanying proof of concept +("PoC") for collaborators to work against and validate potentional fixes against. ## Contributing @@ -1490,15 +1516,14 @@ * Prepared statements * Support for encodings other than UTF-8 / ASCII -[npm-image]: https://img.shields.io/npm/v/mysql.svg -[npm-url]: https://npmjs.org/package/mysql -[node-version-image]: https://img.shields.io/node/v/mysql.svg -[node-version-url]: https://nodejs.org/en/download/ -[travis-image]: https://img.shields.io/travis/mysqljs/mysql/master.svg?label=linux -[travis-url]: https://travis-ci.org/mysqljs/mysql -[appveyor-image]: https://img.shields.io/appveyor/ci/dougwilson/node-mysql/master.svg?label=windows +[appveyor-image]: https://badgen.net/appveyor/ci/dougwilson/node-mysql/master?label=windows [appveyor-url]: https://ci.appveyor.com/project/dougwilson/node-mysql -[coveralls-image]: https://img.shields.io/coveralls/mysqljs/mysql/master.svg +[coveralls-image]: https://badgen.net/coveralls/c/github/mysqljs/mysql/master [coveralls-url]: https://coveralls.io/r/mysqljs/mysql?branch=master -[downloads-image]: https://img.shields.io/npm/dm/mysql.svg -[downloads-url]: https://npmjs.org/package/mysql +[node-image]: https://badgen.net/npm/node/mysql +[node-url]: https://nodejs.org/en/download +[npm-downloads-image]: https://badgen.net/npm/dm/mysql +[npm-url]: https://npmjs.org/package/mysql +[npm-version-image]: https://badgen.net/npm/v/mysql +[travis-image]: https://badgen.net/travis/mysqljs/mysql/master +[travis-url]: https://travis-ci.org/mysqljs/mysql diff -Nru node-mysql-2.16.0/test/unit/connection/test-auth-no-old-password.js node-mysql-2.17.1/test/unit/connection/test-auth-no-old-password.js --- node-mysql-2.16.0/test/unit/connection/test-auth-no-old-password.js 1970-01-01 00:00:00.000000000 +0000 +++ node-mysql-2.17.1/test/unit/connection/test-auth-no-old-password.js 2019-04-18 20:40:03.000000000 +0000 @@ -0,0 +1,36 @@ +var assert = require('assert'); +var common = require('../../common'); +var connection = common.createConnection({ + port : common.fakeServerPort, + user : 'root', + password : null, + insecureAuth : true +}); + +var server = common.createFakeServer(); + +server.listen(common.fakeServerPort, function (err) { + assert.ifError(err); + + connection.connect(function (err) { + assert.ifError(err); + connection.destroy(); + server.destroy(); + }); +}); + +server.on('connection', function(incomingConnection) { + incomingConnection.on('clientAuthentication', function () { + this._sendPacket(new common.Packets.UseOldPasswordPacket()); + }); + + incomingConnection.on('OldPasswordPacket', function (packet) { + if (packet.scrambleBuff.length === 0) { + this.ok(); + } else { + this.deny(); + } + }); + + incomingConnection.handshake(); +}); diff -Nru node-mysql-2.16.0/test/unit/connection/test-change-user-auth-switch.js node-mysql-2.17.1/test/unit/connection/test-change-user-auth-switch.js --- node-mysql-2.16.0/test/unit/connection/test-change-user-auth-switch.js 1970-01-01 00:00:00.000000000 +0000 +++ node-mysql-2.17.1/test/unit/connection/test-change-user-auth-switch.js 2019-04-18 20:40:03.000000000 +0000 @@ -0,0 +1,45 @@ +var assert = require('assert'); +var Crypto = require('crypto'); +var common = require('../../common'); +var connection = common.createConnection({ + port : common.fakeServerPort, + user : 'user_1', + password : 'pass_1' +}); + +var random = Crypto.pseudoRandomBytes || Crypto.randomBytes; // Depends on node.js version +var server = common.createFakeServer(); + +server.listen(common.fakeServerPort, function(err) { + assert.ifError(err); + + connection.query('SELECT CURRENT_USER()', function (err, result) { + assert.ifError(err); + assert.strictEqual(result[0]['CURRENT_USER()'], 'user_1@localhost'); + + connection.changeUser({user: 'user_2', password: 'pass_2'}, function (err) { + assert.ifError(err); + connection.destroy(); + server.destroy(); + }); + }); +}); + +server.on('connection', function (incomingConnection) { + random(20, function (err, scramble) { + assert.ifError(err); + + incomingConnection.on('authSwitchResponse', function (packet) { + this._sendAuthResponse(packet.data, common.Auth.token('pass_2', scramble)); + }); + + incomingConnection.on('changeUser', function () { + this.authSwitchRequest({ + authMethodName : 'mysql_native_password', + authMethodData : scramble + }); + }); + + incomingConnection.handshake(); + }); +}); diff -Nru node-mysql-2.16.0/test/unit/connection/test-change-user-auth-switch-unknown.js node-mysql-2.17.1/test/unit/connection/test-change-user-auth-switch-unknown.js --- node-mysql-2.16.0/test/unit/connection/test-change-user-auth-switch-unknown.js 1970-01-01 00:00:00.000000000 +0000 +++ node-mysql-2.17.1/test/unit/connection/test-change-user-auth-switch-unknown.js 2019-04-18 20:40:03.000000000 +0000 @@ -0,0 +1,40 @@ +var assert = require('assert'); +var Buffer = require('safe-buffer').Buffer; +var common = require('../../common'); +var connection = common.createConnection({ + port : common.fakeServerPort, + user : 'user_1', + password : 'pass_1' +}); + +var server = common.createFakeServer(); + +server.listen(common.fakeServerPort, function(err) { + assert.ifError(err); + + connection.query('SELECT CURRENT_USER()', function (err, result) { + assert.ifError(err); + assert.strictEqual(result[0]['CURRENT_USER()'], 'user_1@localhost'); + + connection.changeUser({user: 'user_2', password: 'pass_2'}, function (err) { + assert.ok(err); + assert.equal(err.code, 'UNSUPPORTED_AUTH_METHOD'); + assert.equal(err.fatal, true); + assert.ok(/foo_plugin_password/.test(err.message)); + + connection.destroy(); + server.destroy(); + }); + }); +}); + +server.on('connection', function (incomingConnection) { + incomingConnection.on('changeUser', function () { + this.authSwitchRequest({ + authMethodName : 'foo_plugin_password', + authMethodData : Buffer.alloc(0) + }); + }); + + incomingConnection.handshake(); +}); diff -Nru node-mysql-2.16.0/test/unit/connection/test-connection-thread-id-error.js node-mysql-2.17.1/test/unit/connection/test-connection-thread-id-error.js --- node-mysql-2.16.0/test/unit/connection/test-connection-thread-id-error.js 1970-01-01 00:00:00.000000000 +0000 +++ node-mysql-2.17.1/test/unit/connection/test-connection-thread-id-error.js 2019-04-18 20:40:03.000000000 +0000 @@ -0,0 +1,25 @@ +var assert = require('assert'); +var common = require('../../common'); +var connection = common.createConnection({port: common.fakeServerPort}); + +var server = common.createFakeServer(); + +server.listen(common.fakeServerPort, function (err) { + assert.ifError(err); + assert.strictEqual(connection.threadId, null); + + connection.connect(function (err) { + assert.ok(err); + assert.strictEqual(err.code, 'ER_ACCESS_DENIED_ERROR'); + assert.strictEqual(connection.threadId, 42); + + server.destroy(); + }); +}); + +server.on('connection', function (incomingConnection) { + incomingConnection.handshake({threadId: 42}); + incomingConnection.on('clientAuthentication', function () { + this.deny(); + }); +}); diff -Nru node-mysql-2.16.0/test/unit/connection/test-debug-exclude.js node-mysql-2.17.1/test/unit/connection/test-debug-exclude.js --- node-mysql-2.16.0/test/unit/connection/test-debug-exclude.js 2018-07-18 03:26:13.000000000 +0000 +++ node-mysql-2.17.1/test/unit/connection/test-debug-exclude.js 2019-04-18 20:40:03.000000000 +0000 @@ -4,6 +4,7 @@ debug : ['OkPacket', 'ComPingPacket'], port : common.fakeServerPort }); +var util = require('util'); var tid = 0; var server = common.createFakeServer(); @@ -13,9 +14,10 @@ var messages = []; - console.log = function (str) { - if (typeof str === 'string' && str.length !== 0) { - messages.push(str); + console.log = function () { + var msg = util.format.apply(this, arguments); + if (String(msg).indexOf('--') !== -1) { + messages.push(msg.split(' {')[0]); } }; diff -Nru node-mysql-2.16.0/test/unit/connection/test-debug.js node-mysql-2.17.1/test/unit/connection/test-debug.js --- node-mysql-2.16.0/test/unit/connection/test-debug.js 2018-07-18 03:26:13.000000000 +0000 +++ node-mysql-2.17.1/test/unit/connection/test-debug.js 2019-04-18 20:40:03.000000000 +0000 @@ -1,6 +1,7 @@ var assert = require('assert'); var common = require('../../common'); var connection = common.createConnection({debug: true, port: common.fakeServerPort}); +var util = require('util'); var tid = 0; var server = common.createFakeServer(); @@ -10,9 +11,10 @@ var messages = []; - console.log = function (str) { - if (typeof str === 'string' && str.length !== 0) { - messages.push(str); + console.log = function () { + var msg = util.format.apply(this, arguments); + if (String(msg).indexOf('--') !== -1) { + messages.push(msg.split(' {')[0]); } }; @@ -21,7 +23,7 @@ assert.equal(messages.length, 5); assert.deepEqual(messages, [ '<-- HandshakeInitializationPacket', - '--> ClientAuthenticationPacket', + '--> (1) ClientAuthenticationPacket', '<-- (1) OkPacket', '--> (1) ComPingPacket', '<-- (1) OkPacket' diff -Nru node-mysql-2.16.0/test/unit/connection/test-debug-parser-error.js node-mysql-2.17.1/test/unit/connection/test-debug-parser-error.js --- node-mysql-2.16.0/test/unit/connection/test-debug-parser-error.js 2018-07-18 03:26:13.000000000 +0000 +++ node-mysql-2.17.1/test/unit/connection/test-debug-parser-error.js 2019-04-18 20:40:03.000000000 +0000 @@ -1,6 +1,7 @@ var assert = require('assert'); var common = require('../../common'); var connection = common.createConnection({debug: true, port: common.fakeServerPort}); +var util = require('util'); var tid = 0; var server = common.createFakeServer(); @@ -10,9 +11,10 @@ var messages = []; - console.log = function (str) { - if (typeof str === 'string' && str.length !== 0) { - messages.push(str); + console.log = function () { + var msg = util.format.apply(this, arguments); + if (String(msg).indexOf('--') !== -1) { + messages.push(msg.split(' {')[0]); } }; @@ -21,7 +23,7 @@ assert.equal(messages.length, 6); assert.deepEqual(messages, [ '<-- HandshakeInitializationPacket', - '--> ClientAuthenticationPacket', + '--> (1) ClientAuthenticationPacket', '<-- (1) OkPacket', '--> (1) ComQueryPacket', '<-- (1) ResultSetHeaderPacket', diff -Nru node-mysql-2.16.0/test/unit/pool/test-debug.js node-mysql-2.17.1/test/unit/pool/test-debug.js --- node-mysql-2.16.0/test/unit/pool/test-debug.js 2018-07-18 03:26:13.000000000 +0000 +++ node-mysql-2.17.1/test/unit/pool/test-debug.js 2019-04-18 20:40:03.000000000 +0000 @@ -1,6 +1,7 @@ var assert = require('assert'); var common = require('../../common'); var pool = common.createPool({debug: true, port: common.fakeServerPort}); +var util = require('util'); var tid = 0; var server = common.createFakeServer(); @@ -10,9 +11,10 @@ var messages = []; - console.log = function (str) { - if (typeof str === 'string' && str.length !== 0) { - messages.push(str); + console.log = function () { + var msg = util.format.apply(this, arguments); + if (String(msg).indexOf('--') !== -1) { + messages.push(msg.split(' {')[0]); } }; @@ -31,7 +33,7 @@ assert.equal(messages.length, 20); assert.deepEqual(messages, [ '<-- HandshakeInitializationPacket', - '--> ClientAuthenticationPacket', + '--> (1) ClientAuthenticationPacket', '<-- (1) OkPacket', '--> (1) ComQueryPacket', '<-- (1) ResultSetHeaderPacket', @@ -40,7 +42,7 @@ '<-- (1) RowDataPacket', '<-- (1) EofPacket', '<-- HandshakeInitializationPacket', - '--> ClientAuthenticationPacket', + '--> (2) ClientAuthenticationPacket', '<-- (2) OkPacket', '--> (2) ComQueryPacket', '<-- (2) ResultSetHeaderPacket', diff -Nru node-mysql-2.16.0/test/unit/test-Mysql.js node-mysql-2.17.1/test/unit/test-Mysql.js --- node-mysql-2.16.0/test/unit/test-Mysql.js 2018-07-18 03:26:13.000000000 +0000 +++ node-mysql-2.17.1/test/unit/test-Mysql.js 2019-04-18 20:40:03.000000000 +0000 @@ -37,12 +37,24 @@ assert.equal(Mysql.Types, common.Types); }, - 'string names to integer values': function() { + 'contains string to integer values': function() { var types = Object.keys(Mysql.Types); assert.ok(types.length > 0); types.forEach(function (type) { - assert.ok(/^[A-Z_]+/.test(type)); - assert.equal(typeof Mysql.Types[type], 'number'); + if (!/^[0-9]+$/.test(type)) { + assert.ok(/^[A-Z_]+/.test(type)); + assert.equal(typeof Mysql.Types[type], 'number'); + } + }); + }, + + 'contains integer values to string names': function() { + var types = Object.keys(Mysql.Types); + assert.ok(types.length > 0); + types.forEach(function (type) { + if (/^[0-9]+$/.test(type)) { + assert.equal(typeof Mysql.Types[type], 'string'); + } }); } }); diff -Nru node-mysql-2.16.0/tool/free-port.js node-mysql-2.17.1/tool/free-port.js --- node-mysql-2.16.0/tool/free-port.js 1970-01-01 00:00:00.000000000 +0000 +++ node-mysql-2.17.1/tool/free-port.js 2019-04-18 20:40:03.000000000 +0000 @@ -0,0 +1,47 @@ +var Net = require('net'); + +var PORT_END = 60000; +var PORT_START = 1000; +var TCP_TIMEOUT = 1000; + +process.nextTick(run); + +function check(port, callback) { + var socket = Net.createConnection(port, 'localhost'); + var timer = setTimeout(function () { + socket.destroy(); + callback(undefined); + }, TCP_TIMEOUT); + + socket.on('connect', function () { + clearTimeout(timer); + socket.destroy(); + callback(true); + }); + + socket.on('error', function (err) { + clearTimeout(timer); + if (err.syscall === 'connect' && err.code === 'ECONNREFUSED') { + callback(false); + } else { + callback(undefined); + } + }); +} + +function run() { + function next() { + var port = PORT_START + Math.floor(Math.random() * (PORT_END - PORT_START + 1)); + + check(port, function (used) { + if (used === false) { + console.log('%d', port); + process.exit(0); + } else { + setTimeout(next, 0); + } + }); + } + + next(); +} diff -Nru node-mysql-2.16.0/tool/generate-type-constants.js node-mysql-2.17.1/tool/generate-type-constants.js --- node-mysql-2.16.0/tool/generate-type-constants.js 1970-01-01 00:00:00.000000000 +0000 +++ node-mysql-2.17.1/tool/generate-type-constants.js 2019-04-18 20:40:03.000000000 +0000 @@ -0,0 +1,91 @@ +#!/usr/bin/env node +var fs = require('fs'); +var path = require('path'); +var script = path.basename(__filename); + +var srcDir = process.argv[2]; +if (!srcDir) { + var args = []; + args[0] = process.argv[0].indexOf(' ') !== -1 + ? '"' + process.argv[0] + '"' + : process.argv[0]; + args[1] = process.argv[1].indexOf(' ') !== -1 + ? '"' + process.argv[1] + '"' + : process.argv[1]; + args[2] = path.join('path', 'to', 'mysql', 'src'); + console.error('Usage: ' + args.join(' ')); + process.exit(1); +} + +var types = extractTypes(srcDir); +var targetFile = path.join(__dirname, '..', 'lib', 'protocol', 'constants', 'types.js'); +var stream = fs.createWriteStream(targetFile); +var version = extractMySqlVersion(srcDir); + +stream.write('/**\n * MySQL type constants\n *\n * Extracted from version ' + version + '\n *\n * !! Generated by ' + script + ', do not modify by hand !!\n */\n\n'); + +var alignment = types.reduce(maxLength, 0); +for (var i = 0; i < types.length; i++) { + if (i in types) { + stream.write('exports.' + types[i] + (new Array(alignment - types[i].length + 1)).join(' ') + ' = ' + i + ';\n'); + } +} + +stream.write('\n// Lookup-by-number table\n'); + +var alignment = String(types.length).length; +for (var i = 0; i < types.length; i++) { + if (i in types) { + stream.write('exports[' + i + ']' + (new Array(alignment - String(i).length + 1)).join(' ') + ' = \'' + types[i] + '\';\n'); + } +} + +console.log('Wrote constants to ' + targetFile); + +function extractMySqlVersion(srcDir) { + var versionFile = path.join(srcDir, 'VERSION'); + var contents = fs.readFileSync(versionFile, 'utf-8'); + var dictionary = Object.create(null); + + contents.split('\n').forEach(function (line) { + var pair = line.split('='); + var key = pair[0]; + var val = pair.slice(1).join('=').trimRight(); + dictionary[key] = val; + }); + + return dictionary.MYSQL_VERSION_MAJOR + '.' + + dictionary.MYSQL_VERSION_MINOR + '.' + + dictionary.MYSQL_VERSION_PATCH; +} + +function extractTypes(srcDir) { + var headerFile = path.join(srcDir, 'include', 'mysql.h.pp'); + var contents = fs.readFileSync(headerFile, 'utf-8'); + var enumRegexp = /typedef enum enum_field_types {([^}]*)}/m; + var match = enumRegexp.exec(contents); + var regexp = /([A-Z0-9_]+)(?: *= *([0-9]+))?/g; + + if (!match) { + throw new Error('Cannot locate enum enum_field_types in "' + headerFile + '"'); + } + + var enumContents = match[1]; + var index = 0; + var types = []; + + while ((match = regexp.exec(enumContents))) { + var name = match[1]; + var num = Number(match[2]) || index++; + + if (name.indexOf('MYSQL_TYPE_') === 0) { + types[num] = name.substring(11); + } + } + + return types; +} + +function maxLength(max, value) { + return Math.max(max, value.length); +} diff -Nru node-mysql-2.16.0/tool/install-nyc.js node-mysql-2.17.1/tool/install-nyc.js --- node-mysql-2.16.0/tool/install-nyc.js 1970-01-01 00:00:00.000000000 +0000 +++ node-mysql-2.17.1/tool/install-nyc.js 2019-04-18 20:40:03.000000000 +0000 @@ -0,0 +1,96 @@ +var path = require('path'); +var spawn = require('child_process').spawn; + +process.nextTick(run); + +function installNpmModule(name, version, callback) { + if (getPackageVersion(name) === version) { + callback(); + return; + } + + var spec = name + '@' + version; + var args = ['install', '--silent', '--no-save', spec]; + var child = spawn('npm', args, { + cwd : path.join(__dirname, '..'), + shell : true + }); + + child.stderr.resume(); + child.stdout.resume(); + + child.on('exit', function (code) { + var err = null; + + if (code !== 0) { + err = new Error('npm install ' + spec + ' failed with exit code ' + code); + } + + callback(err); + }); +} + +function getNycVersion() { + var nodeVersion = process.version.replace(/^v/, '').split('.') + .map(function (s) { return Number(s); }); + + if (nodeVersion[0] === 0 && nodeVersion[1] < 10) { + return undefined; + } else if (nodeVersion[0] < 4) { + return '10.3.2'; + } else if (nodeVersion[0] < 6) { + return '11.9.0'; + } else { + return '13.2.0'; + } +} + +function getPackageVersion(name) { + try { + return require(name + '/package').version; + } catch (e) { + return undefined; + } +} + +function run() { + var args = process.argv.slice(2); + var cmd = null; + var divider = args.indexOf('--'); + var version = getNycVersion(); + + if (divider !== -1) { + cmd = args.slice(divider + 1); + args = args.slice(0, divider); + } + + if (!version && args.indexOf('--nyc-optional') === -1) { + console.error('nyc does not support current Node.js version'); + process.exit(1); + } else if (version) { + installNpmModule('nyc', version, function (err) { + if (err) { + console.error(err.message); + process.exit(1); + } else if (cmd) { + runCmd('nyc', args.concat(cmd)); + } + }); + } else if (cmd) { + runCmd(cmd[0], cmd.slice(1)); + } +} + +function runCmd(cmd, args) { + var child = spawn(cmd, args, { + cwd : path.join(__dirname, '..'), + shell : true + }); + + child.stderr.pipe(process.stderr, {end: false}); + child.stdout.pipe(process.stdout, {end: false}); + + child.on('exit', function (code) { + process.exit(code); + }); +} diff -Nru node-mysql-2.16.0/tool/mysql-version.js node-mysql-2.17.1/tool/mysql-version.js --- node-mysql-2.16.0/tool/mysql-version.js 1970-01-01 00:00:00.000000000 +0000 +++ node-mysql-2.17.1/tool/mysql-version.js 2019-04-18 20:40:03.000000000 +0000 @@ -0,0 +1,19 @@ +var common = require('../test/common'); + +process.nextTick(run); + +function run() { + var conn = common.createConnection(); + + conn.connect(function () { + conn.destroy(); + + try { + console.log(conn._protocol._handshakeInitializationPacket.serverVersion); + process.exit(0); + } catch (e) { + console.error('unable to get mysql version'); + process.exit(1); + } + }); +} diff -Nru node-mysql-2.16.0/tool/wait-mysql.js node-mysql-2.17.1/tool/wait-mysql.js --- node-mysql-2.16.0/tool/wait-mysql.js 1970-01-01 00:00:00.000000000 +0000 +++ node-mysql-2.17.1/tool/wait-mysql.js 2019-04-18 20:40:03.000000000 +0000 @@ -0,0 +1,49 @@ +var Net = require('net'); + +var CHECK_INTERVAL_MS = 200; +var CHECK_TIMEOUT = 120000; +var TCP_TIMEOUT = 1000; + +process.nextTick(run); + +function check(host, port, callback) { + var socket = Net.createConnection(port, host); + var timer = setTimeout(function () { + socket.destroy(); + callback(false); + }, TCP_TIMEOUT); + + socket.once('data', function () { + clearTimeout(timer); + socket.destroy(); + callback(true); + }); + + socket.on('error', function () { + clearTimeout(timer); + callback(false); + }); +} + +function run() { + var host = process.argv[3] || 'localhost'; + var port = Number(process.argv[2]); + + function next() { + check(host, port, function (connected) { + if (connected) { + console.log('connected to %s:%d', host, port); + process.exit(0); + } else { + setTimeout(next, CHECK_INTERVAL_MS); + } + }); + } + + setTimeout(function () { + console.error('timeout waiting for %s:%d', host, port); + process.exit(1); + }, CHECK_TIMEOUT); + + next(); +} diff -Nru node-mysql-2.16.0/.travis.yml node-mysql-2.17.1/.travis.yml --- node-mysql-2.16.0/.travis.yml 2018-07-18 03:26:13.000000000 +0000 +++ node-mysql-2.17.1/.travis.yml 2019-04-18 20:40:03.000000000 +0000 @@ -10,11 +10,12 @@ - "4.2.0" # Test timers regression - "4.9" - "5.12" - - "6.14" + - "6.17" - "7.10" - - "8.11" + - <s "8.16" - "9.11" - - "10.3" + - "10.15" + - "11.14" env: global: # Necessary to build Node.js 0.6 on Travis CI images @@ -23,19 +24,19 @@ - "DOCKER_MYSQL_TYPE=mysql DOCKER_MYSQL_VERSION=5.7" matrix: include: - - node_js: "6.14" + - node_js: *lts env: "DOCKER_MYSQL_TYPE=mysql DOCKER_MYSQL_VERSION=5.5" - - node_js: "6.14" + - node_js: *lts env: "DOCKER_MYSQL_TYPE=mysql DOCKER_MYSQL_VERSION=5.6" - - node_js: "6.14" + - node_js: *lts env: "DOCKER_MYSQL_TYPE=mariadb DOCKER_MYSQL_VERSION=5.5" - - node_js: "6.14" + - node_js: *lts env: "DOCKER_MYSQL_TYPE=mariadb DOCKER_MYSQL_VERSION=10.0" - - node_js: "6.14" + - node_js: *lts env: "DOCKER_MYSQL_TYPE=mariadb DOCKER_MYSQL_VERSION=10.1" - - node_js: "6.14" + - node_js: *lts env: "DOCKER_MYSQL_TYPE=mariadb DOCKER_MYSQL_VERSION=10.2" - - node_js: "6.14" + - node_js: *lts env: "DOCKER_MYSQL_TYPE=mariadb DOCKER_MYSQL_VERSION=10.3" dist: trusty @@ -56,9 +57,8 @@ - "npm config set shrinkwrap false" # Setup Node.js version-specific dependencies - - "test $TRAVIS_NODE_VERSION != '0.6' || npm rm --save-dev nyc" - - "test $TRAVIS_NODE_VERSION != '0.8' || npm rm --save-dev nyc" - - "test $(echo $TRAVIS_NODE_VERSION | cut -d. -f1) -ge 4 || npm rm --save-dev eslint" + - "node tool/install-nyc.js --nyc-optional" + - "test $(echo $TRAVIS_NODE_VERSION | cut -d. -f1) -ge 6 || npm rm --save-dev eslint" # Update Node.js modules - "test ! -d node_modules || npm prune" @@ -66,22 +66,23 @@ # Setup environment - "export MYSQL_DATABASE=node_mysql" + - "export MYSQL_HOST=localhost" + - "export MYSQL_PORT=$(node tool/free-port.js)" - "export MYSQL_USER=root" install: - - "docker run -d --name mysql -e MYSQL_ALLOW_EMPTY_PASSWORD=yes -e MYSQL_DATABASE=$MYSQL_DATABASE $DOCKER_MYSQL_TYPE:$DOCKER_MYSQL_VERSION" + - "docker run -d --name mysql -e MYSQL_ALLOW_EMPTY_PASSWORD=yes -e MYSQL_DATABASE=$MYSQL_DATABASE -p $MYSQL_PORT:3306 $DOCKER_MYSQL_TYPE:$DOCKER_MYSQL_VERSION" - "npm install" - - "docker run --link mysql:db -e CHECK_PORT=3306 -e CHECK_HOST=db giorgos/takis" + - "node tool/wait-mysql.js $MYSQL_PORT $MYSQL_HOST" before_script: - "docker --version" - - "docker exec mysql mysql -e 'select version()'" + - "node tool/mysql-version.js" script: - # Run test script, depending on nyc install - - "test ! -z $(npm -ps ls nyc) || npm test" - - "test -z $(npm -ps ls nyc) || npm run-script test-ci" - - "test -z $(npm -ps ls eslint) || npm run-script lint" + # Run test script + - "npm run-script test-ci" + - "test -z $(npm -ps ls eslint) || npm run-script lint" after_script: - "test -d .nyc_output && npm install coveralls@2 && nyc report --reporter=text-lcov | coveralls"