Skip to content

Commit e76d196

Browse files
authored
Merge pull request #1338 from ruiquelhas/master
Fix tests to work with the latest MySQL server versions
2 parents 07a429d + 888e977 commit e76d196

14 files changed

+236
-30
lines changed

.travis.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# This file was modified by Oracle on June 14, 2021.
2+
# The changes involve the introduction of a local cache for Docker images.
3+
# Modifications copyright (c) 2021, Oracle and/or its affiliates.
4+
15
sudo: required
26
dist: trusty
37

@@ -9,9 +13,19 @@ language: node_js
913
cache:
1014
yarn: true
1115
directories:
16+
- docker_images
1217
- node_modules
1318
- $HOME/.yarn-cache
1419

20+
before_cache:
21+
# save all docker images to a local cache in order to avoid the rate limit
22+
# on Docker Hub
23+
- docker save -o docker_images/images.tar $(docker images -a -q)
24+
25+
before_install:
26+
# load docker images from the local cache
27+
- docker load -i docker_images/images.tar || true
28+
1529
# Node.js version:
1630
# we test only maintained LTS versions
1731
# and lastest dev version

lib/connection.js

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
// This file was modified by Oracle on June 1, 2021.
2+
// The changes involve new logic to handle an additional ERR Packet sent by
3+
// the MySQL server when the connection is closed unexpectedly.
4+
// Modifications copyright (c) 2021, Oracle and/or its affiliates.
5+
16
'use strict';
27

38
const Net = require('net');
@@ -188,7 +193,7 @@ class Connection extends EventEmitter {
188193
if (this.connectTimeout) {
189194
Timers.clearTimeout(this.connectTimeout);
190195
this.connectTimeout = null;
191-
}
196+
}
192197
// prevent from emitting 'PROTOCOL_CONNECTION_LOST' after EPIPE or ECONNRESET
193198
if (this._fatalError) {
194199
return;
@@ -368,6 +373,14 @@ class Connection extends EventEmitter {
368373
}
369374

370375
protocolError(message, code) {
376+
// Starting with MySQL 8.0.24, if the client closes the connection
377+
// unexpectedly, the server will send a last ERR Packet, which we can
378+
// safely ignore.
379+
// https://dev.mysql.com/worklog/task/?id=12999
380+
if (this._closing) {
381+
return;
382+
}
383+
371384
const err = new Error(message);
372385
err.fatal = true;
373386
err.code = code || 'PROTOCOL_ERROR';
@@ -415,10 +428,18 @@ class Connection extends EventEmitter {
415428
}
416429
}
417430
if (!this._command) {
418-
this.protocolError(
419-
'Unexpected packet while no commands in the queue',
420-
'PROTOCOL_UNEXPECTED_PACKET'
421-
);
431+
const marker = packet.peekByte();
432+
// If it's an Err Packet, we should use it.
433+
if (marker === 0xff) {
434+
const error = Packets.Error.fromPacket(packet);
435+
this.protocolError(error.message, error.code);
436+
} else {
437+
// Otherwise, it means it's some other unexpected packet.
438+
this.protocolError(
439+
'Unexpected packet while no commands in the queue',
440+
'PROTOCOL_UNEXPECTED_PACKET'
441+
);
442+
}
422443
this.close();
423444
return;
424445
}

lib/constants/errors.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
// This file was modified by Oracle on June 1, 2021.
2+
// An entry was created for a new error reported by the MySQL server due to
3+
// client inactivity.
4+
// Modifications copyright (c) 2021, Oracle and/or its affiliates.
5+
16
'use strict';
27

38
// copy from https://raw.githubusercontent.com/mysqljs/mysql/7770ee5bb13260c56a160b91fe480d9165dbeeba/lib/protocol/constants/errors.js
@@ -994,6 +999,7 @@ exports.ER_INNODB_FT_AUX_NOT_HEX_ID = 1879;
994999
exports.ER_OLD_TEMPORALS_UPGRADED = 1880;
9951000
exports.ER_INNODB_FORCED_RECOVERY = 1881;
9961001
exports.ER_AES_INVALID_IV = 1882;
1002+
exports.ER_CLIENT_INTERACTION_TIMEOUT = 4031;
9971003

9981004
// Lookup-by-number table
9991005
exports[1] = 'EE_CANTCREATEFILE';
@@ -1982,3 +1988,4 @@ exports[1879] = 'ER_INNODB_FT_AUX_NOT_HEX_ID';
19821988
exports[1880] = 'ER_OLD_TEMPORALS_UPGRADED';
19831989
exports[1881] = 'ER_INNODB_FORCED_RECOVERY';
19841990
exports[1882] = 'ER_AES_INVALID_IV';
1991+
exports[4031] = 'ER_CLIENT_INTERACTION_TIMEOUT';

lib/packets/index.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
// This file was modified by Oracle on June 1, 2021.
2+
// A utility method was introduced to generate an Error instance from a
3+
// binary server packet.
4+
// Modifications copyright (c) 2021, Oracle and/or its affiliates.
5+
16
'use strict';
27

38
const process = require('process');
@@ -122,6 +127,20 @@ class Error {
122127
packet._name = 'Error';
123128
return packet;
124129
}
130+
131+
static fromPacket(packet) {
132+
packet.readInt8(); // marker
133+
const code = packet.readInt16();
134+
packet.readString(1, 'ascii'); // sql state marker
135+
// The SQL state of the ERR_Packet which is always 5 bytes long.
136+
// https://dev.mysql.com/doc/dev/mysql-server/8.0.11/page_protocol_basic_dt_strings.html#sect_protocol_basic_dt_string_fix
137+
packet.readString(5, 'ascii'); // sql state (ignore for now)
138+
const message = packet.readNullTerminatedString('utf8');
139+
const error = new Error();
140+
error.message = message;
141+
error.code = code;
142+
return error;
143+
}
125144
}
126145

127146
exports.Error = Error;

lib/packets/packet.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
// This file was modified by Oracle on June 1, 2021.
2+
// A comment describing some changes in the strict default SQL mode regarding
3+
// non-standard dates was introduced.
4+
// Modifications copyright (c) 2021, Oracle and/or its affiliates.
5+
16
'use strict';
27

38
const ErrorCodeToName = require('../constants/errors.js');
@@ -274,6 +279,11 @@ class Packet {
274279
if (length > 10) {
275280
ms = this.readInt32() / 1000;
276281
}
282+
// NO_ZERO_DATE mode and NO_ZERO_IN_DATE mode are part of the strict
283+
// default SQL mode used by MySQL 8.0. This means that non-standard
284+
// dates like '0000-00-00' become NULL. For older versions and other
285+
// possible MySQL flavours we still need to account for the
286+
// non-standard behaviour.
277287
if (y + m + d + H + M + S + ms === 0) {
278288
return INVALID_DATE;
279289
}

test/integration/connection/test-binary-multiple-results.js

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
// This file was modified by Oracle on June 2, 2021.
2+
// The test has been updated to remove all expectations with regards to the
3+
// "columnLength" metadata field.
4+
// Modifications copyright (c) 2021, Oracle and/or its affiliates.
5+
16
'use strict';
27

38
const mysql = require('../../common.js').createConnection({
@@ -33,7 +38,6 @@ const fields1 = [
3338
{
3439
catalog: 'def',
3540
characterSet: 63,
36-
columnLength: 1,
3741
columnType: 8,
3842
decimals: 0,
3943
flags: 129,
@@ -48,7 +52,6 @@ const nr_fields = [
4852
{
4953
catalog: 'def',
5054
characterSet: 63,
51-
columnLength: 11,
5255
columnType: 3,
5356
decimals: 0,
5457
flags: 0,
@@ -140,7 +143,13 @@ function do_test(testIndex) {
140143
return void 0;
141144
}
142145

143-
return c.inspect();
146+
const column = c.inspect();
147+
// "columnLength" is non-deterministic and the display width for integer
148+
// data types was deprecated on MySQL 8.0.17.
149+
// https://dev.mysql.com/doc/refman/8.0/en/numeric-type-syntax.html
150+
delete column.columnLength;
151+
152+
return column;
144153
};
145154

146155
assert.deepEqual(expectation[0], _rows);

test/integration/connection/test-disconnects.js

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
// This file was modified by Oracle on January 21, 2021.
2+
// The connection with the mock server needs to happen in the same host where
3+
// the tests are running in order to avoid connecting a potential MySQL server
4+
// instance running in the host identified by the MYSQL_HOST environment
5+
// variable.
6+
// Modifications copyright (c) 2021, Oracle and/or its affiliates.
7+
18
'use strict';
29

310
const common = require('../../common');
@@ -10,7 +17,14 @@ const connections = [];
1017

1118
const server = common.createServer(
1219
() => {
13-
const connection = common.createConnection({ port: server._port });
20+
const connection = common.createConnection({
21+
// The mock server is running on the same host machine.
22+
// We need to explicitly define the host to avoid connecting to a potential
23+
// different host provided via MYSQL_HOST that identifies a real MySQL
24+
// server instance.
25+
host: 'localhost',
26+
port: server._port
27+
});
1428
connection.query('SELECT 123', (err, _rows, _fields) => {
1529
if (err) {
1630
throw err;

test/integration/connection/test-execute-nocolumndef.js

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
// This file was modified by Oracle on June 2, 2021.
2+
// The test has been updated to remove all expectations with regards to the
3+
// "columnLength" metadata field.
4+
// Modifications copyright (c) 2021, Oracle and/or its affiliates.
5+
16
'use strict';
27

38
const common = require('../../common');
@@ -47,7 +52,6 @@ const expectedFields = [
4752
table: '',
4853
orgTable: '',
4954
characterSet: 63,
50-
columnLength: 3,
5155
columnType: 8,
5256
flags: 161,
5357
decimals: 0
@@ -60,7 +64,6 @@ const expectedFields = [
6064
table: '',
6165
orgTable: '',
6266
characterSet: 224,
63-
columnLength: 76,
6467
columnType: 253,
6568
flags: 1,
6669
decimals: 31
@@ -73,7 +76,6 @@ const expectedFields = [
7376
table: '',
7477
orgTable: '',
7578
characterSet: 224,
76-
columnLength: 256,
7779
columnType: 253,
7880
flags: 0,
7981
decimals: 31
@@ -86,7 +88,6 @@ const expectedFields = [
8688
table: '',
8789
orgTable: '',
8890
characterSet: 224,
89-
columnLength: 25264128,
9091
columnType: 250,
9192
flags: 0,
9293
decimals: 31
@@ -99,7 +100,6 @@ const expectedFields = [
99100
table: '',
100101
orgTable: '',
101102
characterSet: 224,
102-
columnLength: 40,
103103
columnType: 253,
104104
flags: 0,
105105
decimals: 31
@@ -112,7 +112,6 @@ const expectedFields = [
112112
table: '',
113113
orgTable: '',
114114
characterSet: 224,
115-
columnLength: 16384,
116115
columnType: 253,
117116
flags: 0,
118117
decimals: 31
@@ -125,7 +124,6 @@ const expectedFields = [
125124
table: '',
126125
orgTable: '',
127126
characterSet: 224,
128-
columnLength: 256,
129127
columnType: 253,
130128
flags: 0,
131129
decimals: 31
@@ -138,7 +136,6 @@ const expectedFields = [
138136
table: '',
139137
orgTable: '',
140138
characterSet: 224,
141-
columnLength: 16384,
142139
columnType: 253,
143140
flags: 0,
144141
decimals: 31
@@ -151,7 +148,6 @@ const expectedFields = [
151148
table: '',
152149
orgTable: '',
153150
characterSet: 224,
154-
columnLength: 4096,
155151
columnType: 253,
156152
flags: 0,
157153
decimals: 31
@@ -164,7 +160,6 @@ const expectedFields = [
164160
table: '',
165161
orgTable: '',
166162
characterSet: 63,
167-
columnLength: 10,
168163
columnType: 8,
169164
flags: 160,
170165
decimals: 0
@@ -177,7 +172,6 @@ const expectedFields = [
177172
table: '',
178173
orgTable: '',
179174
characterSet: 63,
180-
columnLength: 4,
181175
columnType: 5,
182176
flags: 128,
183177
decimals: 2
@@ -190,7 +184,6 @@ const expectedFields = [
190184
table: '',
191185
orgTable: '',
192186
characterSet: 224,
193-
columnLength: 1020,
194187
columnType: 253,
195188
flags: 1,
196189
decimals: 31
@@ -201,6 +194,9 @@ process.on('exit', () => {
201194
assert.deepEqual(rows, expectedRows);
202195
fields.forEach((f, index) => {
203196
const fi = f.inspect();
197+
// "columnLength" is non-deterministic
198+
delete fi.columnLength;
199+
204200
assert.deepEqual(
205201
Object.keys(fi).sort(),
206202
Object.keys(expectedFields[index]).sort()

test/integration/connection/test-invalid-date-result.js

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
// This file was modified by Oracle on June 1, 2021.
2+
// The test has been updated to be able to pass with different default
3+
// strict modes used by different MySQL server versions.
4+
// Modifications copyright (c) 2021, Oracle and/or its affiliates.
5+
16
'use strict';
27

38
const common = require('../../common');
@@ -6,12 +11,34 @@ const assert = require('assert');
611

712
let rows = undefined;
813

9-
connection.execute('SELECT TIMESTAMP(0000-00-00) t', [], (err, _rows) => {
14+
// Disable NO_ZERO_DATE mode and NO_ZERO_IN_DATE mode to ensure the old
15+
// behaviour.
16+
const strictModes = ['NO_ZERO_DATE', 'NO_ZERO_IN_DATE'];
17+
18+
connection.query('SELECT variable_value as value FROM performance_schema.session_variables where variable_name = ?', ['sql_mode'], (err, _rows) => {
1019
if (err) {
1120
throw err;
1221
}
13-
rows = _rows;
14-
connection.end();
22+
23+
const deprecatedSqlMode = _rows[0].value
24+
.split(',')
25+
.filter(mode => strictModes.indexOf(mode) === -1)
26+
.join(',');
27+
28+
connection.query(`SET sql_mode=?`, [deprecatedSqlMode], err => {
29+
if (err) {
30+
throw err;
31+
}
32+
33+
connection.execute('SELECT TIMESTAMP(0000-00-00) t', [], (err, _rows) => {
34+
if (err) {
35+
throw err;
36+
}
37+
38+
rows = _rows;
39+
connection.end();
40+
});
41+
});
1542
});
1643

1744
function isInvalidTime(t) {

0 commit comments

Comments
 (0)