mysql2 2.2.2 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/Changelog.md CHANGED
@@ -1,3 +1,29 @@
1
+ 2.3.0
2
+ - Add PoolCluster promise wrappers #1369, #1363
3
+ - support for connect and query timeouts #1364
4
+ - add missing query() method on PoolCluster #1362
5
+ - fix incorrect parsing of passwords
6
+ containing ":" #1357
7
+ - handle errors generated by asynchronous
8
+ authentication plugins #1354
9
+ - add proper handshake fatal error handling #1352
10
+ - fix tests to work with the latest MySQL
11
+ server versions (up to 8.0.25) #1338
12
+ - expose SQL query in errors #1295
13
+ - typing and readme docs for rowAsArray #1288
14
+ - allow unnamed placeholders even if the
15
+ namedPlaceholders flag is enabled #1251
16
+ - better ESM support #1217
17
+
18
+ 2.2.5 ( 21/09/2020 )
19
+ - typings: add ResultSetHeader #1213
20
+
21
+ 2.2.4 ( 21/09/2020 )
22
+ - use bundled types/mysql instead of dependency #1211
23
+
24
+ 2.2.3 ( 21/09/2020 )
25
+ - use github:types/mysql as base for types #1208
26
+
1
27
  2.2.2 ( 19/09/2020 )
2
28
  - Add the authPlugins types to ConnectionOptions #1206
3
29
 
package/README.md CHANGED
@@ -216,6 +216,32 @@ con.promise().query("SELECT 1")
216
216
  .then( () => con.end());
217
217
  ```
218
218
 
219
+ ## Array results
220
+
221
+ If you have two columns with the same name, you might want to get results as an array rather than an object to prevent them from clashing. This is a deviation from the [Node MySQL][node-mysql] library.
222
+
223
+ For example: `select 1 as foo, 2 as foo`.
224
+
225
+ You can enable this setting at either the connection level (applies to all queries), or at the query level (applies only to that specific query).
226
+
227
+ ### Connection Option
228
+ ```js
229
+ const con = mysql.createConnection(
230
+ { host: 'localhost', database: 'test', user: 'root', rowsAsArray: true }
231
+ );
232
+
233
+ ```
234
+
235
+ ### Query Option
236
+
237
+ ```js
238
+ con.query({ sql: 'select 1 as foo, 2 as foo', rowsAsArray: true }, function(err, results, fields) {
239
+ console.log(results) // will be an array of arrays rather than an array of objects
240
+ console.log(fields) // these are unchanged
241
+ });
242
+
243
+ ```
244
+
219
245
  ## API and Configuration
220
246
 
221
247
  MySQL2 is mostly API compatible with [Node MySQL][node-mysql]. You should check their API documentation to see all available API options.
package/index.d.ts CHANGED
@@ -4,8 +4,8 @@ import {
4
4
  PoolConnection as PromisePoolConnection
5
5
  } from './promise';
6
6
 
7
- import * as mysql from 'mysql';
8
- export * from 'mysql';
7
+ import * as mysql from './typings/mysql';
8
+ export * from './typings/mysql';
9
9
 
10
10
  export interface Connection extends mysql.Connection {
11
11
  execute<
@@ -14,6 +14,7 @@ export interface Connection extends mysql.Connection {
14
14
  | mysql.RowDataPacket[]
15
15
  | mysql.OkPacket
16
16
  | mysql.OkPacket[]
17
+ | mysql.ResultSetHeader
17
18
  >(
18
19
  sql: string,
19
20
  callback?: (
@@ -28,6 +29,7 @@ export interface Connection extends mysql.Connection {
28
29
  | mysql.RowDataPacket[]
29
30
  | mysql.OkPacket
30
31
  | mysql.OkPacket[]
32
+ | mysql.ResultSetHeader
31
33
  >(
32
34
  sql: string,
33
35
  values: any | any[] | { [param: string]: any },
@@ -43,6 +45,7 @@ export interface Connection extends mysql.Connection {
43
45
  | mysql.RowDataPacket[]
44
46
  | mysql.OkPacket
45
47
  | mysql.OkPacket[]
48
+ | mysql.ResultSetHeader
46
49
  >(
47
50
  options: mysql.QueryOptions,
48
51
  callback?: (
@@ -57,6 +60,7 @@ export interface Connection extends mysql.Connection {
57
60
  | mysql.RowDataPacket[]
58
61
  | mysql.OkPacket
59
62
  | mysql.OkPacket[]
63
+ | mysql.ResultSetHeader
60
64
  >(
61
65
  options: mysql.QueryOptions,
62
66
  values: any | any[] | { [param: string]: any },
@@ -81,6 +85,7 @@ export interface Pool extends mysql.Connection {
81
85
  | mysql.RowDataPacket[]
82
86
  | mysql.OkPacket
83
87
  | mysql.OkPacket[]
88
+ | mysql.ResultSetHeader
84
89
  >(
85
90
  sql: string,
86
91
  callback?: (
@@ -95,6 +100,7 @@ export interface Pool extends mysql.Connection {
95
100
  | mysql.RowDataPacket[]
96
101
  | mysql.OkPacket
97
102
  | mysql.OkPacket[]
103
+ | mysql.ResultSetHeader
98
104
  >(
99
105
  sql: string,
100
106
  values: any | any[] | { [param: string]: any },
@@ -110,6 +116,7 @@ export interface Pool extends mysql.Connection {
110
116
  | mysql.RowDataPacket[]
111
117
  | mysql.OkPacket
112
118
  | mysql.OkPacket[]
119
+ | mysql.ResultSetHeader
113
120
  >(
114
121
  options: mysql.QueryOptions,
115
122
  callback?: (
@@ -124,6 +131,7 @@ export interface Pool extends mysql.Connection {
124
131
  | mysql.RowDataPacket[]
125
132
  | mysql.OkPacket
126
133
  | mysql.OkPacket[]
134
+ | mysql.ResultSetHeader
127
135
  >(
128
136
  options: mysql.QueryOptions,
129
137
  values: any | any[] | { [param: string]: any },
@@ -142,11 +150,14 @@ export interface Pool extends mysql.Connection {
142
150
  on(event: 'enqueue', listener: () => any): this;
143
151
  promise(promiseImpl?: PromiseConstructor): PromisePool;
144
152
  }
145
-
146
- type authPlugins =
147
- (pluginMetadata: { connection: Connection; command: string }) =>
148
- (pluginData: Buffer) => Promise<string>;
149
-
153
+
154
+ type authPlugins = (pluginMetadata: {
155
+ connection: Connection;
156
+ command: string;
157
+ }) => (
158
+ pluginData: Buffer
159
+ ) => Promise<string> | string | Buffer | Promise<Buffer> | null;
160
+
150
161
  export interface ConnectionOptions extends mysql.ConnectionOptions {
151
162
  charsetNumber?: number;
152
163
  compress?: boolean;
@@ -167,7 +178,7 @@ export interface ConnectionOptions extends mysql.ConnectionOptions {
167
178
  queueLimit?: number;
168
179
  waitForConnections?: boolean;
169
180
  authPlugins?: {
170
- [key: string]: authPlugins;
181
+ [key: string]: authPlugins;
171
182
  };
172
183
  }
173
184
 
package/index.js CHANGED
@@ -14,6 +14,7 @@ exports.connect = exports.createConnection;
14
14
  exports.Connection = Connection;
15
15
 
16
16
  const Pool = require('./lib/pool.js');
17
+ const PoolCluster = require('./lib/pool_cluster.js');
17
18
 
18
19
  exports.createPool = function(config) {
19
20
  const PoolConfig = require('./lib/pool_config.js');
@@ -29,6 +30,8 @@ exports.createQuery = Connection.createQuery;
29
30
 
30
31
  exports.Pool = Pool;
31
32
 
33
+ exports.PoolCluster = PoolCluster;
34
+
32
35
  exports.createServer = function(handler) {
33
36
  const Server = require('./lib/server.js');
34
37
  const s = new Server();
@@ -1,3 +1,8 @@
1
+ // This file was modified by Oracle on July 5, 2021.
2
+ // Errors generated by asynchronous authentication plugins are now being
3
+ // handled and subsequently emitted at the command level.
4
+ // Modifications copyright (c) 2021, Oracle and/or its affiliates.
5
+
1
6
  'use strict';
2
7
 
3
8
  const Packets = require('../packets/index.js');
@@ -17,6 +22,14 @@ function warnLegacyAuthSwitch() {
17
22
  );
18
23
  }
19
24
 
25
+ function authSwitchPluginError(error, command) {
26
+ // Authentication errors are fatal
27
+ error.code = 'AUTH_SWITCH_PLUGIN_ERROR';
28
+ error.fatal = true;
29
+
30
+ command.emit('error', error);
31
+ }
32
+
20
33
  function authSwitchRequest(packet, connection, command) {
21
34
  const { pluginName, pluginData } = Packets.AuthSwitchRequest.fromPacket(
22
35
  packet
@@ -34,8 +47,7 @@ function authSwitchRequest(packet, connection, command) {
34
47
  warnLegacyAuthSwitch();
35
48
  legacySwitchHandler({ pluginName, pluginData }, (err, data) => {
36
49
  if (err) {
37
- connection.emit('error', err);
38
- return;
50
+ return authSwitchPluginError(err, command);
39
51
  }
40
52
  connection.writePacket(new Packets.AuthSwitchResponse(data).toPacket());
41
53
  });
@@ -54,10 +66,12 @@ function authSwitchRequest(packet, connection, command) {
54
66
  if (data) {
55
67
  connection.writePacket(new Packets.AuthSwitchResponse(data).toPacket());
56
68
  }
69
+ }).catch(err => {
70
+ authSwitchPluginError(err, command);
57
71
  });
58
72
  }
59
73
 
60
- function authSwitchRequestMoreData(packet, connection) {
74
+ function authSwitchRequestMoreData(packet, connection, command) {
61
75
  const { data } = Packets.AuthSwitchRequestMoreData.fromPacket(packet);
62
76
 
63
77
  if (connection.config.authSwitchHandler) {
@@ -65,8 +79,7 @@ function authSwitchRequestMoreData(packet, connection) {
65
79
  warnLegacyAuthSwitch();
66
80
  legacySwitchHandler({ pluginData: data }, (err, data) => {
67
81
  if (err) {
68
- connection.emit('error', err);
69
- return;
82
+ return authSwitchPluginError(err, command);
70
83
  }
71
84
  connection.writePacket(new Packets.AuthSwitchResponse(data).toPacket());
72
85
  });
@@ -82,6 +95,8 @@ function authSwitchRequestMoreData(packet, connection) {
82
95
  if (data) {
83
96
  connection.writePacket(new Packets.AuthSwitchResponse(data).toPacket());
84
97
  }
98
+ }).catch(err => {
99
+ authSwitchPluginError(err, command);
85
100
  });
86
101
  }
87
102
 
@@ -1,3 +1,8 @@
1
+ // This file was modified by Oracle on June 17, 2021.
2
+ // Handshake errors are now maked as fatal and the corresponding events are
3
+ // emitted in the command instance itself.
4
+ // Modifications copyright (c) 2021, Oracle and/or its affiliates.
5
+
1
6
  'use strict';
2
7
 
3
8
  const Command = require('./command.js');
@@ -151,20 +156,28 @@ class ClientHandshake extends Command {
151
156
  }
152
157
  return ClientHandshake.prototype.handshakeResult;
153
158
  } catch (err) {
159
+ // Authentication errors are fatal
160
+ err.code = 'AUTH_SWITCH_PLUGIN_ERROR';
161
+ err.fatal = true;
162
+
154
163
  if (this.onResult) {
155
164
  this.onResult(err);
156
165
  } else {
157
- connection.emit('error', err);
166
+ this.emit('error', err);
158
167
  }
159
168
  return null;
160
169
  }
161
170
  }
162
171
  if (marker !== 0) {
163
172
  const err = new Error('Unexpected packet during handshake phase');
173
+ // Unknown handshake errors are fatal
174
+ err.code = 'HANDSHAKE_UNKNOWN_ERROR';
175
+ err.fatal = true;
176
+
164
177
  if (this.onResult) {
165
178
  this.onResult(err);
166
179
  } else {
167
- connection.emit('error', err);
180
+ this.emit('error', err);
168
181
  }
169
182
  return null;
170
183
  }
@@ -26,6 +26,7 @@ class Command extends EventEmitter {
26
26
  }
27
27
  if (packet && packet.isError()) {
28
28
  const err = packet.asError(connection.clientEncoding);
29
+ err.sql = this.sql || this.query;
29
30
  if (this.onResult) {
30
31
  this.onResult(err);
31
32
  this.emit('end');
@@ -15,6 +15,8 @@ class Execute extends Command {
15
15
  this.onResult = callback;
16
16
  this.parameters = options.values;
17
17
  this.insertId = 0;
18
+ this.timeout = options.timeout;
19
+ this.queryTimeout = null;
18
20
  this._rows = [];
19
21
  this._fields = [];
20
22
  this._result = [];
@@ -35,6 +37,7 @@ class Execute extends Command {
35
37
  start(packet, connection) {
36
38
  this._connection = connection;
37
39
  this.options = Object.assign({}, connection.config, this._executeOptions);
40
+ this._setTimeout();
38
41
  const executePacket = new Packets.Execute(
39
42
  this.statement.id,
40
43
  this.parameters,
@@ -96,6 +99,8 @@ Execute.prototype.resultsetHeader = Query.prototype.resultsetHeader;
96
99
  Execute.prototype._findOrCreateReadStream =
97
100
  Query.prototype._findOrCreateReadStream;
98
101
  Execute.prototype._streamLocalInfile = Query.prototype._streamLocalInfile;
102
+ Execute.prototype._setTimeout = Query.prototype._setTimeout;
103
+ Execute.prototype._handleTimeoutError = Query.prototype._handleTimeoutError;
99
104
  Execute.prototype.row = Query.prototype.row;
100
105
  Execute.prototype.stream = Query.prototype.stream;
101
106
 
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const process = require('process');
4
+ const Timers = require('timers');
4
5
 
5
6
  const Readable = require('stream').Readable;
6
7
 
@@ -21,6 +22,8 @@ class Query extends Command {
21
22
  this._queryOptions = options;
22
23
  this.namedPlaceholders = options.namedPlaceholders || false;
23
24
  this.onResult = callback;
25
+ this.timeout = options.timeout;
26
+ this.queryTimeout = null;
24
27
  this._fieldCount = 0;
25
28
  this._rowParser = null;
26
29
  this._fields = [];
@@ -48,6 +51,8 @@ class Query extends Command {
48
51
  }
49
52
  this._connection = connection;
50
53
  this.options = Object.assign({}, connection.config, this._queryOptions);
54
+ this._setTimeout();
55
+
51
56
  const cmdPacket = new Packets.Query(
52
57
  this.sql,
53
58
  connection.config.charsetNumber
@@ -58,6 +63,15 @@ class Query extends Command {
58
63
 
59
64
  done() {
60
65
  this._unpipeStream();
66
+ // if all ready timeout, return null directly
67
+ if (this.timeout && !this.queryTimeout) {
68
+ return null;
69
+ }
70
+ // else clear timer
71
+ if (this.queryTimeout) {
72
+ Timers.clearTimeout(this.queryTimeout);
73
+ this.queryTimeout = null;
74
+ }
61
75
  if (this.onResult) {
62
76
  let rows, fields;
63
77
  if (this._resultIndex === 0) {
@@ -272,6 +286,34 @@ class Query extends Command {
272
286
  });
273
287
  return stream;
274
288
  }
289
+
290
+ _setTimeout() {
291
+ if (this.timeout) {
292
+ const timeoutHandler = this._handleTimeoutError.bind(this);
293
+ this.queryTimeout = Timers.setTimeout(
294
+ timeoutHandler,
295
+ this.timeout
296
+ );
297
+ }
298
+ }
299
+
300
+ _handleTimeoutError() {
301
+ if (this.queryTimeout) {
302
+ Timers.clearTimeout(this.queryTimeout);
303
+ this.queryTimeout = null;
304
+ }
305
+
306
+ const err = new Error('Query inactivity timeout');
307
+ err.errorno = 'PROTOCOL_SEQUENCE_TIMEOUT';
308
+ err.code = 'PROTOCOL_SEQUENCE_TIMEOUT';
309
+ err.syscall = 'query';
310
+
311
+ if (this.onResult) {
312
+ this.onResult(err);
313
+ } else {
314
+ this.emit('error', err);
315
+ }
316
+ }
275
317
  }
276
318
 
277
319
  Query.prototype.catch = Query.prototype.then;
package/lib/connection.js CHANGED
@@ -1,3 +1,13 @@
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
+
6
+ // This file was modified by Oracle on June 17, 2021.
7
+ // The changes involve logic to ensure the socket connection is closed when
8
+ // there is a fatal error.
9
+ // Modifications copyright (c) 2021, Oracle and/or its affiliates.
10
+
1
11
  'use strict';
2
12
 
3
13
  const Net = require('net');
@@ -100,9 +110,10 @@ class Connection extends EventEmitter {
100
110
  if (!this.config.isServer) {
101
111
  handshakeCommand = new Commands.ClientHandshake(this.config.clientFlags);
102
112
  handshakeCommand.on('end', () => {
103
- // this happens when handshake finishes early and first packet is error
104
- // and not server hello ( for example, 'Too many connactions' error)
105
- if (!handshakeCommand.handshake) {
113
+ // this happens when handshake finishes early either because there was
114
+ // some fatal error or the server sent an error packet instead of
115
+ // an hello packet (for example, 'Too many connactions' error)
116
+ if (!handshakeCommand.handshake || this._fatalError || this._protocolError) {
106
117
  return;
107
118
  }
108
119
  this._handshakePacket = handshakeCommand.handshake;
@@ -188,7 +199,7 @@ class Connection extends EventEmitter {
188
199
  if (this.connectTimeout) {
189
200
  Timers.clearTimeout(this.connectTimeout);
190
201
  this.connectTimeout = null;
191
- }
202
+ }
192
203
  // prevent from emitting 'PROTOCOL_CONNECTION_LOST' after EPIPE or ECONNRESET
193
204
  if (this._fatalError) {
194
205
  return;
@@ -224,6 +235,10 @@ class Connection extends EventEmitter {
224
235
  if (bubbleErrorToConnection || this._pool) {
225
236
  this.emit('error', err);
226
237
  }
238
+ // close connection after emitting the event in case of a fatal error
239
+ if (err.fatal) {
240
+ this.close();
241
+ }
227
242
  }
228
243
 
229
244
  write(buffer) {
@@ -368,6 +383,14 @@ class Connection extends EventEmitter {
368
383
  }
369
384
 
370
385
  protocolError(message, code) {
386
+ // Starting with MySQL 8.0.24, if the client closes the connection
387
+ // unexpectedly, the server will send a last ERR Packet, which we can
388
+ // safely ignore.
389
+ // https://dev.mysql.com/worklog/task/?id=12999
390
+ if (this._closing) {
391
+ return;
392
+ }
393
+
371
394
  const err = new Error(message);
372
395
  err.fatal = true;
373
396
  err.code = code || 'PROTOCOL_ERROR';
@@ -415,10 +438,18 @@ class Connection extends EventEmitter {
415
438
  }
416
439
  }
417
440
  if (!this._command) {
418
- this.protocolError(
419
- 'Unexpected packet while no commands in the queue',
420
- 'PROTOCOL_UNEXPECTED_PACKET'
421
- );
441
+ const marker = packet.peekByte();
442
+ // If it's an Err Packet, we should use it.
443
+ if (marker === 0xff) {
444
+ const error = Packets.Error.fromPacket(packet);
445
+ this.protocolError(error.message, error.code);
446
+ } else {
447
+ // Otherwise, it means it's some other unexpected packet.
448
+ this.protocolError(
449
+ 'Unexpected packet while no commands in the queue',
450
+ 'PROTOCOL_UNEXPECTED_PACKET'
451
+ );
452
+ }
422
453
  this.close();
423
454
  return;
424
455
  }
@@ -488,6 +519,11 @@ class Connection extends EventEmitter {
488
519
  _resolveNamedPlaceholders(options) {
489
520
  let unnamed;
490
521
  if (this.config.namedPlaceholders || options.namedPlaceholders) {
522
+ if (Array.isArray(options.values)) {
523
+ // if an array is provided as the values, assume the conversion is not necessary.
524
+ // this allows the usage of unnamed placeholders even if the namedPlaceholders flag is enabled.
525
+ return
526
+ }
491
527
  if (convertNamedPlaceholders === null) {
492
528
  convertNamedPlaceholders = require('named-placeholders')();
493
529
  }
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const urlParse = require('url').parse;
3
+ const { URL } = require('url');
4
4
  const ClientConstants = require('./constants/client');
5
5
  const Charsets = require('./constants/charsets');
6
6
  let SSLProfiles = null;
@@ -232,29 +232,23 @@ class ConnectionConfig {
232
232
  }
233
233
 
234
234
  static parseUrl(url) {
235
- url = urlParse(url, true);
235
+ const parsedUrl = new URL(url);
236
236
  const options = {
237
- host: url.hostname,
238
- port: url.port,
239
- database: url.pathname.substr(1)
237
+ host: parsedUrl.hostname,
238
+ port: parsedUrl.port,
239
+ database: parsedUrl.pathname.substr(1),
240
+ user: parsedUrl.username,
241
+ password: parsedUrl.password
240
242
  };
241
- if (url.auth) {
242
- const auth = url.auth.split(':');
243
- options.user = auth[0];
244
- options.password = auth[1];
245
- }
246
- if (url.query) {
247
- for (const key in url.query) {
248
- const value = url.query[key];
249
- try {
250
- // Try to parse this as a JSON expression first
251
- options[key] = JSON.parse(value);
252
- } catch (err) {
253
- // Otherwise assume it is a plain string
254
- options[key] = value;
255
- }
243
+ parsedUrl.searchParams.forEach((value, key) => {
244
+ try {
245
+ // Try to parse this as a JSON expression first
246
+ options[key] = JSON.parse(value);
247
+ } catch (err) {
248
+ // Otherwise assume it is a plain string
249
+ options[key] = value;
256
250
  }
257
- }
251
+ });
258
252
  return options;
259
253
  }
260
254
  }
@@ -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
+
1
6
  'use strict';
2
7
 
3
8
  // 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;
994
999
  exports.ER_OLD_TEMPORALS_UPGRADED = 1880;
995
1000
  exports.ER_INNODB_FORCED_RECOVERY = 1881;
996
1001
  exports.ER_AES_INVALID_IV = 1882;
1002
+ exports.ER_CLIENT_INTERACTION_TIMEOUT = 4031;
997
1003
 
998
1004
  // Lookup-by-number table
999
1005
  exports[1] = 'EE_CANTCREATEFILE';
@@ -1982,3 +1988,4 @@ exports[1879] = 'ER_INNODB_FT_AUX_NOT_HEX_ID';
1982
1988
  exports[1880] = 'ER_OLD_TEMPORALS_UPGRADED';
1983
1989
  exports[1881] = 'ER_INNODB_FORCED_RECOVERY';
1984
1990
  exports[1882] = 'ER_AES_INVALID_IV';
1991
+ exports[4031] = 'ER_CLIENT_INTERACTION_TIMEOUT';
@@ -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
+
1
6
  'use strict';
2
7
 
3
8
  const process = require('process');
@@ -122,6 +127,20 @@ class Error {
122
127
  packet._name = 'Error';
123
128
  return packet;
124
129
  }
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
+ }
125
144
  }
126
145
 
127
146
  exports.Error = Error;
@@ -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
+
1
6
  'use strict';
2
7
 
3
8
  const ErrorCodeToName = require('../constants/errors.js');
@@ -274,6 +279,11 @@ class Packet {
274
279
  if (length > 10) {
275
280
  ms = this.readInt32() / 1000;
276
281
  }
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.
277
287
  if (y + m + d + H + M + S + ms === 0) {
278
288
  return INVALID_DATE;
279
289
  }