diff --git a/.travis.install-mysql-5.7.sh b/.travis.install-mysql-5.7.sh new file mode 100644 index 000000000..7241cb3e5 --- /dev/null +++ b/.travis.install-mysql-5.7.sh @@ -0,0 +1,27 @@ +sudo DEBIAN_FRONTEND=noninteractive apt-get -y -q remove --purge "^mysql.*" +sudo rm -rf /var/lib/mysql /var/log/mysql /etc/mysql +sudo DEBIAN_FRONTEND=noninteractive apt-get -y -q autoremove +sudo DEBIAN_FRONTEND=noninteractive apt-get -y -q autoclean +sudo deluser mysql +sudo service apparmor restart +wget https://dev.mysql.com/get/mysql-apt-config_0.7.3-1_all.deb +sudo DEBIAN_FRONTEND=noninteractive dpkg --force-confold --install mysql-apt-config_0.7.3-1_all.deb +echo mysql-apt-config mysql-apt-config/preview-component string | sudo debconf-set-selections +echo mysql-apt-config mysql-apt-config/repo-url string http://repo.mysql.com/apt | sudo debconf-set-selections +echo mysql-apt-config mysql-apt-config/select-product select Ok | sudo debconf-set-selections +echo mysql-apt-config mysql-apt-config/select-tools select Disabled | sudo debconf-set-selections +echo mysql-apt-config mysql-apt-config/select-server select mysql-5.7 | sudo debconf-set-selections +echo mysql-apt-config mysql-apt-config/select-preview select Disabled | sudo debconf-set-selections +echo mysql-apt-config mysql-apt-config/unsupported-platform select abort | sudo debconf-set-selections +echo mysql-apt-config mysql-apt-config/repo-distro select ubuntu | sudo debconf-set-selections +echo mysql-apt-config mysql-apt-config/tools-component string | sudo debconf-set-selections +echo mysql-apt-config mysql-apt-config/repo-codename select precise | sudo debconf-set-selections +echo mysql-apt-config mysql-apt-config/tools-component string | sudo debconf-set-selections +sudo DEBIAN_FRONTEND=noninteractive dpkg-reconfigure mysql-apt-config +sudo DEBIAN_FRONTEND=noninteractive apt-get -y -q update +echo mysql-community-server mysql-community-server/root-pass password pass | sudo debconf-set-selections +echo mysql-community-server mysql-community-server/re-root-pass password pass | sudo debconf-set-selections +echo mysql-community-server mysql-community-server/root-pass-mismatch error | sudo debconf-set-selections +echo mysql-community-server mysql-community-server/data-dir note | sudo debconf-set-selections +echo mysql-community-server mysql-community-server/remove-data-dir boolean false | sudo debconf-set-selections +sudo DEBIAN_FRONTEND=noninteractive apt-get -q -y -f install mysql-server diff --git a/.travis.yml b/.travis.yml index 1c8dbf58e..72b52f942 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,24 +12,16 @@ node_js: - '5.11' - '6.2' -matrix: - include: - - node_js: '4.4' - env: MYSQL_TYPE=mariadb MYSQL_HOST=localhost MYSQL_DATABASE=node_mysql MYSQL_USER=root MYSQL_PASSWORD= - addons: {mariadb: '10.1'} - allow_failures: - # Allow MariaDB to fail while https://github.com/travis-ci/travis-ci/issues/5837 is being resolved - - node_js: '4.4' - env: MYSQL_TYPE=mariadb MYSQL_HOST=localhost MYSQL_DATABASE=node_mysql MYSQL_USER=root MYSQL_PASSWORD= - addons: {mariadb: '10.1'} - -sudo: false +sudo: required cache: directories: - node_modules before_install: + # install MySQL 5.7 + - bash .travis.install-mysql-5.7.sh + # Setup Node.js version-specific dependencies - "test $TRAVIS_NODE_VERSION != '0.6' || npm rm --save-dev istanbul" - "test $TRAVIS_NODE_VERSION != '0.8' || npm rm --save-dev istanbul" @@ -40,7 +32,7 @@ before_install: - "test ! -d node_modules || npm rebuild" before_script: -- "mysql -e 'create database node_mysql; select version();'" +- "mysql -u root -ppass -e 'create database node_mysql; select version();'" script: # Run test script, depending on istanbul install @@ -52,7 +44,7 @@ after_script: - "test -e ./coverage/lcov.info && npm install coveralls@2 && cat ./coverage/lcov.info | coveralls" env: - - MYSQL_TYPE=mysql MYSQL_HOST=localhost MYSQL_DATABASE=node_mysql MYSQL_USER=root MYSQL_PASSWORD= + - MYSQL_TYPE=mysql MYSQL_HOST=localhost MYSQL_DATABASE=node_mysql MYSQL_USER=root MYSQL_PASSWORD=pass mysql: adapter: mysql2 diff --git a/Readme.md b/Readme.md index 237ae4fd3..5bb4a5b56 100644 --- a/Readme.md +++ b/Readme.md @@ -42,6 +42,8 @@ - [Stored procedures](#stored-procedures) - [Joins with overlapping column names](#joins-with-overlapping-column-names) - [Transactions](#transactions) +- [Ping](#ping) +- [Reset connection](#reset-connection) - [Timeouts](#timeouts) - [Error handling](#error-handling) - [Exception Safety](#exception-safety) @@ -1033,6 +1035,22 @@ connection.ping(function (err) { }) ``` +## Reset Connection + +The `connection.reset` method causes the server to clear the session state (such as +user variables and temporary tables). This is similar to but more light-weight than +`connection.changeUser`, because reset does not close the connection and reauthenticate. + +Documentation defining what is cleared. +[mysql-reset-connection]: https://dev.mysql.com/doc/refman/5.7/en/mysql-reset-connection.html + +```js +connection.ping(function (err) { + if (err) throw err; + console.log('Server responded to ping'); +}) +``` + ## Timeouts Every operation takes an optional inactivity timeout option. This allows you to diff --git a/lib/Connection.js b/lib/Connection.js index 7c5065505..7ed0f88cd 100644 --- a/lib/Connection.js +++ b/lib/Connection.js @@ -234,6 +234,11 @@ Connection.prototype.statistics = function statistics(options, callback) { this._protocol.stats(options, bindToCurrentDomain(callback)); }; +Connection.prototype.reset = function reset(callback) { + this._implyConnect(); + this._protocol.resetConnection(bindToCurrentDomain(callback)); +}; + Connection.prototype.end = function end(options, callback) { var cb = callback; var opts = options; diff --git a/lib/protocol/Protocol.js b/lib/protocol/Protocol.js index 2fca5fc8a..fd7eb3361 100644 --- a/lib/protocol/Protocol.js +++ b/lib/protocol/Protocol.js @@ -78,6 +78,10 @@ Protocol.prototype.stats = function stats(options, callback) { return this._enqueue(new Sequences.Statistics(options, callback)); }; +Protocol.prototype.resetConnection = function resetConnection(callback) { + return this._enqueue(new Sequences.ResetConnection(callback)); +}; + Protocol.prototype.quit = function quit(options, callback) { if (typeof options === 'function') { callback = options; diff --git a/lib/protocol/packets/ComResetConnectionPacket.js b/lib/protocol/packets/ComResetConnectionPacket.js new file mode 100644 index 000000000..0258c5ce5 --- /dev/null +++ b/lib/protocol/packets/ComResetConnectionPacket.js @@ -0,0 +1,12 @@ +module.exports = ComResetConnectionPacket; +function ComResetConnectionPacket(sql) { + this.command = 0x1f; +} + +ComResetConnectionPacket.prototype.write = function(writer) { + writer.writeUnsignedNumber(1, this.command); +}; + +ComResetConnectionPacket.prototype.parse = function(parser) { + this.command = parser.parseUnsignedNumber(1); +}; diff --git a/lib/protocol/packets/index.js b/lib/protocol/packets/index.js index 5c63df53a..4e8d33c81 100644 --- a/lib/protocol/packets/index.js +++ b/lib/protocol/packets/index.js @@ -3,6 +3,7 @@ exports.ComChangeUserPacket = require('./ComChangeUserPacket'); exports.ComPingPacket = require('./ComPingPacket'); exports.ComQueryPacket = require('./ComQueryPacket'); exports.ComQuitPacket = require('./ComQuitPacket'); +exports.ComResetConnectionPacket = require('./ComResetConnectionPacket'); exports.ComStatisticsPacket = require('./ComStatisticsPacket'); exports.EmptyPacket = require('./EmptyPacket'); exports.EofPacket = require('./EofPacket'); diff --git a/lib/protocol/sequences/ResetConnection.js b/lib/protocol/sequences/ResetConnection.js new file mode 100644 index 000000000..c21dfdd54 --- /dev/null +++ b/lib/protocol/sequences/ResetConnection.js @@ -0,0 +1,14 @@ +var Sequence = require('./Sequence'); +var Util = require('util'); +var Packets = require('../packets'); + +module.exports = ResetConnection; +Util.inherits(ResetConnection, Sequence); + +function ResetConnection(callback) { + Sequence.call(this, callback); +} + +ResetConnection.prototype.start = function() { + this.emit('packet', new Packets.ComResetConnectionPacket); +}; diff --git a/lib/protocol/sequences/index.js b/lib/protocol/sequences/index.js index 0eae5ce63..99d5d9111 100644 --- a/lib/protocol/sequences/index.js +++ b/lib/protocol/sequences/index.js @@ -3,5 +3,6 @@ exports.Handshake = require('./Handshake'); exports.Ping = require('./Ping'); exports.Query = require('./Query'); exports.Quit = require('./Quit'); +exports.ResetConnection = require('./ResetConnection'); exports.Sequence = require('./Sequence'); exports.Statistics = require('./Statistics'); diff --git a/test/integration/connection/test-query-dates-as-strings.js b/test/integration/connection/test-query-dates-as-strings.js index d45371a49..7c18c8c7b 100644 --- a/test/integration/connection/test-query-dates-as-strings.js +++ b/test/integration/connection/test-query-dates-as-strings.js @@ -4,7 +4,7 @@ var util = require('util'); var table = 'dates_as_strings'; -common.getTestConnection(function (err, connection) { +common.getTestConnection({dateStrings: true}, function (err, connection) { assert.ifError(err); common.useTestDb(connection); @@ -17,23 +17,62 @@ common.getTestConnection(function (err, connection) { ') ENGINE=InnoDB DEFAULT CHARSET=utf8' ].join('\n'), [table], assert.ifError); - connection.query('INSERT INTO ?? SET ?', [table, {dt: '0000-00-00'}]); - connection.query('INSERT INTO ?? SET ?', [table, {dt: '2013-00-00'}]); - connection.query('INSERT INTO ?? SET ?', [table, {dt: '2013-03-00'}]); + connection.query('INSERT INTO ?? SET ?', [table, {dt: '1000-01-01'}]); + connection.query('INSERT INTO ?? SET ?', [table, {dt: '2013-01-01'}]); connection.query('INSERT INTO ?? SET ?', [table, {dt: '2013-03-01'}]); connection.query('SELECT * FROM ??', [table], function (err, rows) { assert.ifError(err); - assert.equal(rows.length, 4); + assert.equal(rows.length, 3); assert.equal(rows[0].id, 1); - assert.equal(rows[0].dt, '0000-00-00'); + assert.equal(rows[0].dt, '1000-01-01'); assert.equal(rows[1].id, 2); - assert.equal(rows[1].dt, '2013-00-00'); + assert.equal(rows[1].dt, '2013-01-01'); assert.equal(rows[2].id, 3); - assert.equal(rows[2].dt, '2013-03-00'); - assert.equal(rows[3].id, 4); - assert(util.isDate(rows[3].dt)); + assert.equal(rows[2].dt, '2013-03-01'); + connection.end(assert.ifError); + }); +}); +common.getTestConnection({dateStrings: false}, function (err, connection) { + assert.ifError(err); + + common.useTestDb(connection); + + connection.query([ + 'CREATE TEMPORARY TABLE ?? (', + '`id` int(11) unsigned NOT NULL AUTO_INCREMENT,', + '`dt` DATE,', + 'PRIMARY KEY (`id`)', + ') ENGINE=InnoDB DEFAULT CHARSET=utf8' + ].join('\n'), [table], assert.ifError); + + connection.query('INSERT INTO ?? SET ?', [table, {dt: '1000-01-01'}]); + connection.query('INSERT INTO ?? SET ?', [table, {dt: '2013-01-01'}]); + connection.query('INSERT INTO ?? SET ?', [table, {dt: '2013-03-01'}]); + + connection.query('SELECT * FROM ??', [table], function (err, rows) { + assert.ifError(err); + assert.equal(rows.length, 3); + + assert.equal(rows[0].id, 1); + assert.equal(rows[0].dt.getFullYear(), 1000); + assert.equal(rows[0].dt.getMonth()+1, 1); + assert.equal(rows[0].dt.getDate(), 1); + assert(util.isDate(rows[0].dt)); + + assert.equal(rows[1].id, 2); + assert.equal(rows[1].dt.getFullYear(), 2013); + assert.equal(rows[1].dt.getMonth()+1, 1); + assert.equal(rows[1].dt.getDate(), 1); + assert(util.isDate(rows[1].dt)); + + assert.equal(rows[2].id, 3); + assert.equal(rows[2].dt.getFullYear(), 2013); + assert.equal(rows[2].dt.getMonth()+1, 3); + assert.equal(rows[2].dt.getDate(), 1); + assert(util.isDate(rows[2].dt)); + connection.end(assert.ifError); }); }); diff --git a/test/integration/connection/test-reset-connection.js b/test/integration/connection/test-reset-connection.js new file mode 100644 index 000000000..bb1e25f17 --- /dev/null +++ b/test/integration/connection/test-reset-connection.js @@ -0,0 +1,26 @@ +var assert = require('assert'); +var common = require('../../common'); + +common.getTestConnection(function (err, connection) { + assert.ifError(err); + + connection.query('SET @var1 = ?', [1234], assert.ifError); + + connection.query('SELECT @var1 AS var1', function(err, rows) { + assert.ifError(err); + assert.equal(rows.length, 1); + assert.equal(rows[0].var1, 1234); + + connection.reset(function(err) { + assert.ifError(err); + + connection.query('SELECT @var1 AS var1', function(err, rows2) { + assert.ifError(err); + assert.equal(rows2.length, 1); + assert.equal(rows2[0].var1, null); + }); + + connection.end(assert.ifError); + }); + }); +}); \ No newline at end of file