diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 000000000..4ebc8aea5 --- /dev/null +++ b/.eslintignore @@ -0,0 +1 @@ +coverage diff --git a/.eslintrc b/.eslintrc index 635f52b30..c50229d0f 100644 --- a/.eslintrc +++ b/.eslintrc @@ -4,10 +4,12 @@ }, "rules": { "comma-dangle": [2, "never"], + "comma-spacing": ["error", { "before": false, "after": true }], "consistent-return": 2, "eqeqeq": [2, "allow-null"], "indent": [2, 2, { "VariableDeclarator": 2, "SwitchCase": 1 }], "key-spacing": [2, { "align": { "beforeColon": true, "afterColon": true, "on": "colon" } }], + "keyword-spacing": 2, "new-parens": 2, "no-cond-assign": 2, "no-constant-condition": 2, @@ -31,9 +33,11 @@ "no-regex-spaces": 2, "no-sparse-arrays": 2, "no-trailing-spaces": 2, + "no-undef": 2, "no-unexpected-multiline": 2, "no-unreachable": 2, "no-unused-vars": 2, + "one-var": ["error", { "initialized": "never" }], "quotes": [2, "single", { "avoidEscape": true, "allowTemplateLiterals": true }], "semi": [2, "always"], "semi-spacing": 2, diff --git a/.gitignore b/.gitignore index 2f00b4b7b..dc10d5dd8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ +.nyc_output coverage/ -lib-cov/ node_modules/ npm-debug.log +package-lock.json diff --git a/.travis.yml b/.travis.yml index 1e95577e2..ef38685a2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,57 +1,90 @@ language: node_js node_js: - - '0.6' - - '0.8' - - '0.10' - - '0.12' - - '1.8' - - '2.5' - - '3.3' - - '4.2.0' # Test timers regression - - '4.7' - - '5.12' - - '6.9' - - '7.4' - + - "0.6" + - "0.8" + - "0.10" + - "0.12" + - "1.8" + - "2.5" + - "3.3" + - "4.2.0" # Test timers regression + - "4.9" + - "5.12" + - "6.17" + - "7.10" + - "8.17" + - "9.11" + - "10.18" + - "11.15" + - <s "12.14" + - "13.6" +env: + global: + # Necessary to build Node.js 0.6 on Travis CI images + - "CC=gcc-4.6 CXX=g++-4.6" + matrix: + - "DOCKER_MYSQL_TYPE=mysql DOCKER_MYSQL_VERSION=5.7" matrix: include: - - node_js: '4.7' - env: MYSQL_TYPE=mariadb MYSQL_HOST=localhost MYSQL_DATABASE=node_mysql MYSQL_USER=root MYSQL_PASSWORD= - addons: {mariadb: '10.1'} + - node_js: *lts + env: "DOCKER_MYSQL_TYPE=mysql DOCKER_MYSQL_VERSION=5.5" + - node_js: *lts + env: "DOCKER_MYSQL_TYPE=mysql DOCKER_MYSQL_VERSION=5.6" + - node_js: *lts + env: "DOCKER_MYSQL_TYPE=mariadb DOCKER_MYSQL_VERSION=5.5" + - node_js: *lts + env: "DOCKER_MYSQL_TYPE=mariadb DOCKER_MYSQL_VERSION=10.0" + - node_js: *lts + env: "DOCKER_MYSQL_TYPE=mariadb DOCKER_MYSQL_VERSION=10.1" + - node_js: *lts + env: "DOCKER_MYSQL_TYPE=mariadb DOCKER_MYSQL_VERSION=10.2" + - node_js: *lts + env: "DOCKER_MYSQL_TYPE=mariadb DOCKER_MYSQL_VERSION=10.3" -sudo: false +dist: trusty +addons: + apt: + packages: + - g++-4.6 +sudo: required +services: + - docker cache: directories: - node_modules before_install: + # Skip updating shrinkwrap / lock + - "npm config set shrinkwrap false" + # 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" - - "test $TRAVIS_NODE_VERSION = '4.7' || 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" - "test ! -d node_modules || npm rebuild" + # 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 -p $MYSQL_PORT:3306 $DOCKER_MYSQL_TYPE:$DOCKER_MYSQL_VERSION" + - "npm install" + - "node tool/wait-mysql.js $MYSQL_PORT $MYSQL_HOST" + before_script: -- "mysql -e 'create database node_mysql; select version();'" + - "docker --version" + - "node tool/mysql-version.js" script: - # Run test script, depending on istanbul install - - "test ! -z $(npm -ps ls istanbul) || npm test" - - "test -z $(npm -ps ls istanbul) || 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 -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: - adapter: mysql2 - username: root - encoding: utf8 - database: node_mysql + - "test -d .nyc_output && npm install coveralls@2 && nyc report --reporter=text-lcov | coveralls" diff --git a/Changes.md b/Changes.md index a42532d2f..73e549c8d 100644 --- a/Changes.md +++ b/Changes.md @@ -4,6 +4,82 @@ This file is a manually maintained list of changes for each release. Feel free to add your changes here when sending pull requests. Also send corrections if you spot any mistakes. +## v2.18.1 (2020-01-23) + +* Fix Amazon RDS profile for yaSSL MySQL servers with 2019 CA #2292 + +## v2.18.0 (2020-01-21) + +* Add `localInfile` option to control `LOAD DATA LOCAL INFILE` +* Add new Amazon RDS Root 2019 CA to Amazon RDS SSL profile #2280 +* Add new error codes up to MySQL 5.7.29 +* Fix early detection of bad callback to `connection.query` +* Support Node.js 12.x #2211 +* Support Node.js 13.x +* Support non-enumerable properties in object argument to `connection.query` #2253 +* Update `bignumber.js` to 9.0.0 +* Update `readable-stream` to 2.3.7 + +## 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 +* Add new error codes up to MySQL 5.7.21 +* Include connection ID in debug output +* Support Node.js 9.x +* Support Node.js 10.x #2003 #2024 #2026 #2034 +* Update Amazon RDS SSL certificates +* Update `bignumber.js` to 4.1.0 +* Update `readable-stream` to 2.3.6 +* Update `sqlstring` to 2.3.1 + - Fix incorrectly replacing non-placeholders in SQL + +## v2.15.0 (2017-10-05) + +* Add new Amazon RDS ca-central-1 certificate CA to Amazon RDS SSL profile #1809 +* Add new error codes up to MySQL 5.7.19 +* Add `mysql.raw()` to generate pre-escaped values #877 #1821 +* Fix "changedRows" to work on non-English servers #1819 +* Fix error when server sends RST on `QUIT` #1811 +* Fix typo in insecure auth error message +* Support `mysql_native_password` auth switch request for Azure #1396 #1729 #1730 +* Update `sqlstring` to 2.3.0 + - Add `.toSqlString()` escape overriding + - Small performance improvement on `escapeId` +* Update `bignumber.js` to 4.0.4 + +## v2.14.1 (2017-08-01) + +* Fix holding first closure for lifetime of connection #1785 + +## v2.14.0 (2017-07-25) + +* Add new Amazon RDS ap-south-1 certificate CA to Amazon RDS SSL profile #1780 +* Add new Amazon RDS eu-west-2 certificate CA to Amazon RDS SSL profile #1770 +* Add `sql` property to query `Error` objects #1462 #1628 #1629 +* Add `sqlMessage` property to `Error` objects #1714 +* Fix the MySQL 5.7.17 error codes +* Support Node.js 8.x +* Update `bignumber.js` to 4.0.2 +* Update `readable-stream` to 2.3.3 +* Use `safe-buffer` for improved Buffer API + ## v2.13.0 (2017-01-24) * Accept regular expression as pool cluster pattern #1572 @@ -268,6 +344,7 @@ you spot any mistakes. ## v2.0.0-alpha9 (2013-08-27) * Add query to pool to execute queries directly using the pool +* Add `sqlState` property to `Error` objects #556 * Pool option to set queue limit * Pool sends 'connection' event when it opens a new connection * Added stringifyObjects option to treat input as strings rather than objects (#501) diff --git a/Readme.md b/Readme.md index 8454f1de3..d7c9aa20c 100644 --- a/Readme.md +++ b/Readme.md @@ -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] @@ -16,44 +16,66 @@ - [Community](#community) - [Establishing connections](#establishing-connections) - [Connection options](#connection-options) -- [SSL options](#ssl-options) + - [SSL options](#ssl-options) + - [Connection flags](#connection-flags) - [Terminating connections](#terminating-connections) - [Pooling connections](#pooling-connections) - [Pool options](#pool-options) - [Pool events](#pool-events) + - [acquire](#acquire) + - [connection](#connection) + - [enqueue](#enqueue) + - [release](#release) - [Closing all the connections in a pool](#closing-all-the-connections-in-a-pool) - [PoolCluster](#poolcluster) -- [PoolCluster options](#poolcluster-options) + - [PoolCluster options](#poolcluster-options) - [Switching users and altering connection state](#switching-users-and-altering-connection-state) - [Server disconnects](#server-disconnects) - [Performing queries](#performing-queries) - [Escaping query values](#escaping-query-values) - [Escaping query identifiers](#escaping-query-identifiers) -- [Preparing Queries](#preparing-queries) -- [Custom format](#custom-format) + - [Preparing Queries](#preparing-queries) + - [Custom format](#custom-format) - [Getting the id of an inserted row](#getting-the-id-of-an-inserted-row) - [Getting the number of affected rows](#getting-the-number-of-affected-rows) - [Getting the number of changed rows](#getting-the-number-of-changed-rows) - [Getting the connection ID](#getting-the-connection-id) - [Executing queries in parallel](#executing-queries-in-parallel) - [Streaming query rows](#streaming-query-rows) -- [Piping results with Streams2](#piping-results-with-streams2) + - [Piping results with Streams](#piping-results-with-streams) - [Multiple statement queries](#multiple-statement-queries) - [Stored procedures](#stored-procedures) - [Joins with overlapping column names](#joins-with-overlapping-column-names) - [Transactions](#transactions) +- [Ping](#ping) - [Timeouts](#timeouts) - [Error handling](#error-handling) - [Exception Safety](#exception-safety) - [Type casting](#type-casting) -- [Connection Flags](#connection-flags) + - [Number](#number) + - [Date](#date) + - [Buffer](#buffer) + - [String](#string) + - [Custom type casting](#custom-type-casting) - [Debugging and reporting problems](#debugging-and-reporting-problems) +- [Security issues](#security-issues) - [Contributing](#contributing) - [Running tests](#running-tests) + - [Running unit tests](#running-unit-tests) + - [Running integration tests](#running-integration-tests) - [Todo](#todo) ## Install +This is a [Node.js](https://nodejs.org/en/) module available through the +[npm registry](https://www.npmjs.com/). + +Before installing, [download and install Node.js](https://nodejs.org/en/download/). +Node.js 0.6 or higher is required. + +Installation is done using the +[`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally): + ```sh $ npm install mysql ``` @@ -126,7 +148,7 @@ spend more time on it (ordered by time of contribution): * [Joyent](http://www.joyent.com/) * [pinkbike.com](http://pinkbike.com/) * [Holiday Extras](http://www.holidayextras.co.uk/) (they are [hiring](http://join.holidayextras.co.uk/)) -* [Newscope](http://newscope.com/) (they are [hiring](http://www.newscope.com/stellenangebote)) +* [Newscope](http://newscope.com/) (they are [hiring](https://newscope.com/unternehmen/jobs/)) ## Community @@ -192,7 +214,7 @@ When establishing a connection, you can set the following options: * `charset`: The charset for the connection. This is called "collation" in the SQL-level of MySQL (like `utf8_general_ci`). If a SQL-level charset is specified (like `utf8mb4`) then the default collation for that charset is used. (Default: `'UTF8_GENERAL_CI'`) -* `timezone`: The timezone used to store local dates. (Default: `'local'`) +* `timezone`: The timezone configured on the MySQL server. This is used to type cast server date/time values to JavaScript `Date` object and vice versa. This can be `'local'`, `'Z'`, or an offset in the form `+HH:MM` or `-HH:MM`. (Default: `'local'`) * `connectTimeout`: The milliseconds before a timeout occurs during the initial connection to the MySQL server. (Default: `10000`) * `stringifyObjects`: Stringify objects instead of converting to values. See @@ -210,7 +232,7 @@ issue [#501](https://github.com/mysqljs/mysql/issues/501). (Default: `false`) 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 @@ -218,6 +240,7 @@ issue [#501](https://github.com/mysqljs/mysql/issues/501). (Default: `false`) * `trace`: Generates stack traces on `Error` to include call site of library entrance ("long stack traces"). Slight performance penalty for most calls. (Default: `true`) +* `localInfile`: Allow `LOAD DATA INFILE` to use the `LOCAL` modifier. (Default: `true`) * `multipleStatements`: Allow multiple mysql statements per query. Be careful with this, it could increase the scope of SQL injection attacks. (Default: `false`) * `flags`: List of connection flags to use other than the default ones. It is @@ -246,7 +269,7 @@ it uses one of the predefined SSL profiles included. The following profiles are https://s3.amazonaws.com/rds-downloads/rds-combined-ca-bundle.pem When connecting to other servers, you will need to provide an object of options, in the -same format as [crypto.createCredentials](http://nodejs.org/api/crypto.html#crypto_crypto_createcredentials_details). +same format as [tls.createSecureContext](https://nodejs.org/api/tls.html#tls_tls_createsecurecontext_options). Please note the arguments expect a string of the certificate, not a file name to the certificate. Here is a simple example: @@ -273,6 +296,63 @@ var connection = mysql.createConnection({ }); ``` +### Connection flags + +If, for any reason, you would like to change the default connection flags, you +can use the connection option `flags`. Pass a string with a comma separated list +of items to add to the default flags. If you don't want a default flag to be used +prepend the flag with a minus sign. To add a flag that is not in the default list, +just write the flag name, or prefix it with a plus (case insensitive). + +```js +var connection = mysql.createConnection({ + // disable FOUND_ROWS flag, enable IGNORE_SPACE flag + flags: '-FOUND_ROWS,IGNORE_SPACE' +}); +``` + +The following flags are available: + +- `COMPRESS` - Enable protocol compression. This feature is not currently supported + by the Node.js implementation so cannot be turned on. (Default off) +- `CONNECT_WITH_DB` - Ability to specify the database on connection. (Default on) +- `FOUND_ROWS` - Send the found rows instead of the affected rows as `affectedRows`. + (Default on) +- `IGNORE_SIGPIPE` - Don't issue SIGPIPE if network failures. This flag has no effect + on this Node.js implementation. (Default on) +- `IGNORE_SPACE` - Let the parser ignore spaces before the `(` in queries. (Default on) +- `INTERACTIVE` - Indicates to the MySQL server this is an "interactive" client. This + will use the interactive timeouts on the MySQL server and report as interactive in + the process list. (Default off) +- `LOCAL_FILES` - Can use `LOAD DATA LOCAL`. This flag is controlled by the connection + option `localInfile`. (Default on) +- `LONG_FLAG` - Longer flags in Protocol::ColumnDefinition320. (Default on) +- `LONG_PASSWORD` - Use the improved version of Old Password Authentication. + (Default on) +- `MULTI_RESULTS` - Can handle multiple resultsets for queries. (Default on) +- `MULTI_STATEMENTS` - The client may send multiple statement per query or + statement prepare (separated by `;`). This flag is controlled by the connection + option `multipleStatements`. (Default off) +- `NO_SCHEMA` +- `ODBC` Special handling of ODBC behaviour. This flag has no effect on this Node.js + implementation. (Default on) +- `PLUGIN_AUTH` - Uses the plugin authentication mechanism when connecting to the + MySQL server. This feature is not currently supported by the Node.js implementation + so cannot be turned on. (Default off) +- `PROTOCOL_41` - Uses the 4.1 protocol. (Default on) +- `PS_MULTI_RESULTS` - Can handle multiple resultsets for execute. (Default on) +- `REMEMBER_OPTIONS` - This is specific to the C client, and has no effect on this + Node.js implementation. (Default off) +- `RESERVED` - Old flag for the 4.1 protocol. (Default on) +- `SECURE_CONNECTION` - Support native 4.1 authentication. (Default on) +- `SSL` - Use SSL after handshake to encrypt data in transport. This feature is + controlled though the `ssl` connection option, so the flag has no effect. + (Default off) +- `SSL_VERIFY_SERVER_CERT` - Verify the server certificate during SSL set up. This + feature is controlled though the `ssl.rejectUnauthorized` connection option, so + the flag has no effect. (Default off) +- `TRANSACTIONS` - Asks for the transaction status flags. (Default on) + ## Terminating connections There are two ways to end a connection. Terminating a connection gracefully is @@ -306,7 +386,8 @@ Rather than creating and managing connections one-by-one, this module also provides built-in connection pooling using `mysql.createPool(config)`. [Read more about connection pooling](https://en.wikipedia.org/wiki/Connection_pool). -Use pool directly. +Create a pool and use it directly: + ```js var mysql = require('mysql'); var pool = mysql.createPool({ @@ -319,38 +400,26 @@ var pool = mysql.createPool({ pool.query('SELECT 1 + 1 AS solution', function (error, results, fields) { if (error) throw error; - console.log('The solution is: ', rows[0].solution); -}); -``` - -Connections can be pooled to ease sharing a single connection, or managing -multiple connections. - -```js -var mysql = require('mysql'); -var pool = mysql.createPool({ - host : 'example.org', - user : 'bob', - password : 'secret', - database : 'my_db' -}); - -pool.getConnection(function(err, connection) { - // connected! (unless `err` is set) + console.log('The solution is: ', results[0].solution); }); ``` -When you are done with a connection, just call `connection.release()` and the -connection will return to the pool, ready to be used again by someone else. +This is a shortcut for the `pool.getConnection()` -> `connection.query()` -> +`connection.release()` code flow. Using `pool.getConnection()` is useful to +share connection state for subsequent queries. This is because two calls to +`pool.query()` may use two different connections and run in parallel. This is +the basic structure: ```js var mysql = require('mysql'); var pool = mysql.createPool(...); pool.getConnection(function(err, connection) { + if (err) throw err; // not connected! + // Use the connection connection.query('SELECT something FROM sometable', function (error, results, fields) { - // And done with the connection. + // When done with the connection, release it. connection.release(); // Handle error after the release. @@ -381,7 +450,9 @@ constructor. In addition to those options pools accept a few extras: * `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 @@ -455,12 +526,19 @@ pool.end(function (err) { }); ``` -The `end` method takes an _optional_ callback that you can use to know once -all the connections have ended. The connections end _gracefully_, so all -pending queries will still complete and the time to end the pool will vary. +The `end` method takes an _optional_ callback that you can use to know when +all the connections are ended. -**Once `pool.end()` has been called, `pool.getConnection` and other operations -can no longer be performed** +**Once `pool.end` is called, `pool.getConnection` and other operations +can no longer be performed.** Wait until all connections in the pool are +released before calling `pool.end`. If you use the shortcut method +`pool.query`, in place of `pool.getConnection` → `connection.query` → +`connection.release`, wait until it completes. + +`pool.end` calls `connection.end` on every active connection in the pool. +This queues a `QUIT` packet on the connection and sets a flag to prevent +`pool.getConnection` from creating new connections. All commands / queries +already in progress will complete, but new commands won't execute. ## PoolCluster @@ -572,6 +650,13 @@ terminated, an existing connection object cannot be re-connected by design. With Pool, disconnected connections will be removed from the pool freeing up space for a new connection to be created on the next getConnection call. +With PoolCluster, disconnected connections will count as errors against the +related node, incrementing the error code for that node. Once there are more than +`removeNodeErrorCount` errors on a given node, it is removed from the cluster. +When this occurs, the PoolCluster may emit a `POOL_NONEONLINE` error if there are +no longer any matching nodes for the pattern. The `restoreNodeTimeout` config can +be set to restore offline nodes after a given timeout. + ## Performing queries The most basic way to perform a query is to call the `.query()` method on an object @@ -634,8 +719,28 @@ connection.query({ ); ``` +If the query only has a single replacement character (`?`), and the value is +not `null`, `undefined`, or an array, it can be passed directly as the second +argument to `.query`: + +```js +connection.query( + 'SELECT * FROM `books` WHERE `author` = ?', + 'David', + function (error, results, fields) { + // error will be an Error if one occurred during the query + // results will contain the results of the query + // fields will contain information about the returned results fields (if any) + } +); +``` + ## Escaping query values +**Caution** These methods of escaping values only works when the +[NO_BACKSLASH_ESCAPES](https://dev.mysql.com/doc/refman/5.7/en/sql-mode.html#sqlmode_no_backslash_escapes) +SQL mode is disabled (which is the default state for MySQL servers). + In order to avoid SQL Injection attacks, you should always escape any user provided data before using it inside a SQL query. You can do so using the `mysql.escape()`, `connection.escape()` or `pool.escape()` methods: @@ -686,6 +791,8 @@ Different value types are escaped differently, here is how: * Arrays are turned into list, e.g. `['a', 'b']` turns into `'a', 'b'` * Nested arrays are turned into grouped lists (for bulk inserts), e.g. `[['a', 'b'], ['c', 'd']]` turns into `('a', 'b'), ('c', 'd')` +* Objects that have a `toSqlString` method will have `.toSqlString()` called + and the returned value is used as the raw SQL. * Objects are turned into `key = 'val'` pairs for each enumerable property on the object. If the property's value is a function, it is skipped; if the property's value is an object, toString() is called on it and the returned @@ -695,8 +802,7 @@ Different value types are escaped differently, here is how: to insert them as values will trigger MySQL errors until they implement support. -If you paid attention, you may have noticed that this escaping allows you -to do neat things like this: +This escaping allows you to do neat things like this: ```js var post = {id: 1, title: 'Hello MySQL'}; @@ -705,7 +811,27 @@ var query = connection.query('INSERT INTO posts SET ?', post, function (error, r // Neat! }); console.log(query.sql); // INSERT INTO posts SET `id` = 1, `title` = 'Hello MySQL' +``` + +And the `toSqlString` method allows you to form complex queries with functions: + +```js +var CURRENT_TIMESTAMP = { toSqlString: function() { return 'CURRENT_TIMESTAMP()'; } }; +var sql = mysql.format('UPDATE posts SET modified = ? WHERE id = ?', [CURRENT_TIMESTAMP, 42]); +console.log(sql); // UPDATE posts SET modified = CURRENT_TIMESTAMP() WHERE id = 42 +``` +To generate objects with a `toSqlString` method, the `mysql.raw()` method can +be used. This creates an object that will be left un-touched when using in a `?` +placeholder, useful for using functions as dynamic values: + +**Caution** The string provided to `mysql.raw()` will skip all escaping +functions when used, so be careful when passing in unvalidated input. + +```js +var CURRENT_TIMESTAMP = mysql.raw('CURRENT_TIMESTAMP()'); +var sql = mysql.format('UPDATE posts SET modified = ? WHERE id = ?', [CURRENT_TIMESTAMP, 42]); +console.log(sql); // UPDATE posts SET modified = CURRENT_TIMESTAMP() WHERE id = 42 ``` If you feel the need to escape queries by yourself, you can also use the escaping @@ -806,7 +932,7 @@ can retrieve the insert id like this: ```js connection.query('INSERT INTO posts SET ?', {title: 'test'}, function (error, results, fields) { if (error) throw error; - console.log(result.insertId); + console.log(results.insertId); }); ``` @@ -824,7 +950,7 @@ You can get the number of affected rows from an insert, update or delete stateme ```js connection.query('DELETE FROM posts WHERE title = "wrong"', function (error, results, fields) { if (error) throw error; - console.log('deleted ' + result.affectedRows + ' rows'); + console.log('deleted ' + results.affectedRows + ' rows'); }) ``` @@ -838,7 +964,7 @@ whose values were not changed. ```js connection.query('UPDATE posts SET ...', function (error, results, fields) { if (error) throw error; - console.log('changed ' + result.changedRows + ' rows'); + console.log('changed ' + results.changedRows + ' rows'); }) ``` @@ -908,14 +1034,13 @@ stream individual row columns, they will always be buffered up entirely. If you have a good use case for streaming large fields to and from MySQL, I'd love to get your thoughts and contributions on this. -### Piping results with Streams2 +### Piping results with Streams The query object provides a convenience method `.stream([options])` that wraps -query events into a [Readable](http://nodejs.org/api/stream.html#stream_class_stream_readable) -[Streams2](http://blog.nodejs.org/2012/12/20/streams2/) object. This -stream can easily be piped downstream and provides automatic pause/resume, -based on downstream congestion and the optional `highWaterMark`. The -`objectMode` parameter of the stream is set to `true` and cannot be changed +query events into a [Readable Stream](http://nodejs.org/api/stream.html#stream_class_stream_readable) +object. This stream can easily be piped downstream and provides automatic +pause/resume, based on downstream congestion and the optional `highWaterMark`. +The `objectMode` parameter of the stream is set to `true` and cannot be changed (if you need a byte stream, you will need to use a transform stream, like [objstream](https://www.npmjs.com/package/objstream) for example). @@ -1039,7 +1164,7 @@ connection.beginTransaction(function(err) { }); } - var log = 'Post ' + result.insertId + ' added'; + var log = 'Post ' + results.insertId + ' added'; connection.query('INSERT INTO log SET data=?', log, function (error, results, fields) { if (error) { @@ -1096,7 +1221,7 @@ connection.query({sql: 'SELECT COUNT(*) AS count FROM big_table', timeout: 60000 throw error; } - console.log(rows[0].count + ' rows'); + console.log(results[0].count + ' rows'); }); ``` @@ -1108,15 +1233,24 @@ review carefully in order to write solid applications. 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 + the queries. +* `err.sqlState`: String, contains the five-character SQLSTATE value. Only populated from [MySQL server error][]. +* `err.sqlMessage`: String, contains the message string that provides a + 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 @@ -1250,94 +1384,58 @@ var query = connection.query(options, function (error, results, fields) { }); ``` +### 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. -```js -connection.query({ - sql: '...', - typeCast: function (field, next) { - if (field.type == 'TINY' && field.length == 1) { - return (field.string() == '1'); // 1 = true, 0 = false - } - 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)__ +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. -``` -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)__ +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. -## Connection Flags +The `next` argument is a `function` that, when called, will return the default +type conversion for the given field. -If, for any reason, you would like to change the default connection flags, you -can use the connection option `flags`. Pass a string with a comma separated list -of items to add to the default flags. If you don't want a default flag to be used -prepend the flag with a minus sign. To add a flag that is not in the default list, -just write the flag name, or prefix it with a plus (case insensitive). +When getting the field data, the following helper methods are present on the +`field` object: -**Please note that some available flags that are not supported (e.g.: Compression), -are still not allowed to be specified.** + * `.string()` - parse the field into a string. + * `.buffer()` - parse the field into a `Buffer`. + * `.geometry()` - parse the field as a geometry value. -### Example +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`). -The next example blacklists FOUND_ROWS flag from default connection flags. +Here's an example of converting `TINYINT(1)` to boolean: ```js -var connection = mysql.createConnection("mysql://localhost/test?flags=-FOUND_ROWS"); +connection = mysql.createConnection({ + typeCast: function (field, next) { + if (field.type === 'TINY' && field.length === 1) { + return (field.string() === '1'); // 1 = true, 0 = false + } else { + return next(); + } + } +}); ``` -### Default Flags - -The following flags are sent by default on a new connection: - -- `CONNECT_WITH_DB` - Ability to specify the database on connection. -- `FOUND_ROWS` - Send the found rows instead of the affected rows as `affectedRows`. -- `IGNORE_SIGPIPE` - Old; no effect. -- `IGNORE_SPACE` - Let the parser ignore spaces before the `(` in queries. -- `LOCAL_FILES` - Can use `LOAD DATA LOCAL`. -- `LONG_FLAG` -- `LONG_PASSWORD` - Use the improved version of Old Password Authentication. -- `MULTI_RESULTS` - Can handle multiple resultsets for COM_QUERY. -- `ODBC` Old; no effect. -- `PROTOCOL_41` - Uses the 4.1 protocol. -- `PS_MULTI_RESULTS` - Can handle multiple resultsets for COM_STMT_EXECUTE. -- `RESERVED` - Old flag for the 4.1 protocol. -- `SECURE_CONNECTION` - Support native 4.1 authentication. -- `TRANSACTIONS` - Asks for the transaction status flags. - -In addition, the following flag will be sent if the option `multipleStatements` -is set to `true`: - -- `MULTI_STATEMENTS` - The client may send multiple statement per query or - statement prepare. - -### Other Available Flags - -There are other flags available. They may or may not function, but are still -available to specify. - -- COMPRESS -- INTERACTIVE -- NO_SCHEMA -- PLUGIN_AUTH -- REMEMBER_OPTIONS -- SSL -- SSL_VERIFY_SERVER_CERT +__WARNING: YOU MUST INVOKE the parser using one of these three field functions +in your custom typeCast callback. They can only be called once.__ ## Debugging and reporting problems @@ -1364,6 +1462,22 @@ will have: * As much debugging output and information about your environment (mysql version, node version, os, etc.) as you can gather. +## Security issues + +Security issues should not be first reported through GitHub or another public +forum, but kept private in order for the collaborators to assess the report +and either (a) devise a fix and plan a release date or (b) assert that it is +not a security issue (in which case it can be posted in a public forum, like +a GitHub issue). + +The primary private forum is email, either by emailing the module's author or +opening a GitHub issue simply asking to whom a security issues should be +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 accompanying proof of concept +("PoC") for collaborators to work against and validate potentional fixes against. + ## Contributing This project welcomes contributions from the community. Contributions are @@ -1376,7 +1490,7 @@ For a good pull request, we ask you provide the following: 1. Try to include a clear description of your pull request in the description. It should include the basic "what" and "why"s for the request. 2. The tests should pass as best as you can. See the [Running tests](#running-tests) - section on hwo to run the different tests. GitHub will automatically run + section on how to run the different tests. GitHub will automatically run the tests as well, to act as a safety net. 3. The pull request should include tests for the change. A new feature should have tests for the new feature and bug fixes should include a test that fails @@ -1421,15 +1535,14 @@ $ MYSQL_HOST=localhost MYSQL_PORT=3306 MYSQL_DATABASE=node_mysql_test MYSQL_USER * 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 --git a/appveyor.yml b/appveyor.yml index efcbd9e11..7e2cbb4e5 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -4,6 +4,7 @@ environment: MYSQL_USER: root MYSQL_PASSWORD: Password12! MYSQL_PATH: C:\Program Files\MySQL\MySQL Server 5.7 + MYSQL_PORT: 3306 matrix: - nodejs_version: "0.8" @@ -12,10 +13,16 @@ environment: - nodejs_version: "1.8" - nodejs_version: "2.5" - nodejs_version: "3.3" - - nodejs_version: "4.7" + - nodejs_version: "4.9" - nodejs_version: "5.12" - - nodejs_version: "6.9" - - nodejs_version: "7.4" + - nodejs_version: "6.17" + - nodejs_version: "7.10" + - nodejs_version: "8.17" + - nodejs_version: "9.11" + - nodejs_version: "10.18" + - nodejs_version: "11.15" + - nodejs_version: "12.14" + - nodejs_version: "13.6" services: - mysql @@ -24,9 +31,12 @@ cache: - node_modules install: - - ps: Install-Product node $env:nodejs_version - - if "%nodejs_version%" equ "0.8" npm rm --save-dev istanbul - - npm rm --save-dev eslint + - 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 config set strict-ssl false + - npm rm --silent --save-dev eslint - if exist node_modules npm prune - if exist node_modules npm rebuild - npm install @@ -35,14 +45,13 @@ build: off 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 istanbul') do set npm_test_command=test-ci - - npm run %npm_test_command% + - npm test version: "{build}" diff --git a/benchmark/analyze.js b/benchmark/analyze.js index 951bb445e..439a2531e 100644 --- a/benchmark/analyze.js +++ b/benchmark/analyze.js @@ -81,7 +81,9 @@ function sdev() { } function variance() { - var t = 0, squares = 0, len = numbers.length; + var t = 0; + var squares = 0; + var len = numbers.length; for (var i = 0; i < len; i++) { var obs = numbers[i]; diff --git a/benchmark/parse-100k-blog-rows.js b/benchmark/parse-100k-blog-rows.js index 23e1c2d49..71dd1de61 100644 --- a/benchmark/parse-100k-blog-rows.js +++ b/benchmark/parse-100k-blog-rows.js @@ -1,15 +1,17 @@ var lib = __dirname + '/../lib'; +var Buffer = require('safe-buffer').Buffer; var Protocol = require(lib + '/protocol/protocol'); var Packets = require(lib + '/protocol/packets'); var PacketWriter = require(lib + '/protocol/PacketWriter'); var Parser = require(lib + '/protocol/Parser'); -var buffers = createBuffers(); var options = { rows : 100000, bufferSize : 64 * 1024 }; +var buffers = createBuffers(); + console.error('Config:', options); run(); @@ -63,7 +65,7 @@ function createRowDataPacketBuffer(parser) { } function mergeBuffers(buffers) { - var mergeBuffer = new Buffer(options.bufferSize); + var mergeBuffer = Buffer.alloc(options.bufferSize); var mergeBuffers = []; var offset = 0; @@ -78,7 +80,7 @@ function mergeBuffers(buffers) { buffer.copy(mergeBuffer, offset, 0, bytesRemaining); mergeBuffers.push(mergeBuffer); - mergeBuffer = new Buffer(options.bufferSize); + mergeBuffer = Buffer.alloc(options.bufferSize); buffer.copy(mergeBuffer, 0, bytesRemaining); offset = buffer.length - bytesRemaining; } diff --git a/index.js b/index.js index ed4496d56..72624076b 100644 --- a/index.js +++ b/index.js @@ -94,6 +94,18 @@ exports.format = function format(sql, values, stringifyObjects, timeZone) { return SqlString.format(sql, values, stringifyObjects, timeZone); }; +/** + * Wrap raw SQL strings from escape overriding. + * @param {string} sql The raw SQL + * @return {object} Wrapped object + * @public + */ +exports.raw = function raw(sql) { + var SqlString = loadClass('SqlString'); + + return SqlString.raw(sql); +}; + /** * The type constants. * @public diff --git a/lib/Connection.js b/lib/Connection.js index ea452757e..6802255dd 100644 --- a/lib/Connection.js +++ b/lib/Connection.js @@ -22,55 +22,40 @@ function Connection(options) { this.threadId = null; } -function bindToCurrentDomain(callback) { - if (!callback) { - return undefined; - } - - var domain = process.domain; - - return domain - ? domain.bind(callback) - : callback; -} - Connection.createQuery = function createQuery(sql, values, callback) { if (sql instanceof Query) { return sql; } - var cb = bindToCurrentDomain(callback); + var cb = callback; var options = {}; if (typeof sql === 'function') { - cb = bindToCurrentDomain(sql); - return new Query(options, cb); - } + cb = sql; + } else if (typeof sql === 'object') { + options = Object.create(sql); - if (typeof sql === 'object') { - for (var prop in sql) { - options[prop] = sql[prop]; + if (typeof values === 'function') { + cb = values; + } else if (values !== undefined) { + Object.defineProperty(options, 'values', { value: values }); } + } else { + options.sql = sql; if (typeof values === 'function') { - cb = bindToCurrentDomain(values); + cb = values; } else if (values !== undefined) { options.values = values; } - - return new Query(options, cb); } - options.sql = sql; - options.values = values; + if (cb !== undefined) { + cb = wrapCallbackInDomain(null, cb); - if (typeof values === 'function') { - cb = bindToCurrentDomain(values); - options.values = undefined; - } - - if (cb === undefined && callback !== undefined) { - throw new TypeError('argument callback must be a function when provided'); + if (cb === undefined) { + throw new TypeError('argument callback must be a function when provided'); + } } return new Query(options, cb); @@ -99,19 +84,20 @@ Connection.prototype.connect = function connect(options, callback) { this._protocol.on('data', function(data) { connection._socket.write(data); }); - this._socket.on('data', function(data) { + this._socket.on('data', wrapToDomain(connection, function (data) { connection._protocol.write(data); - }); + })); this._protocol.on('end', function() { connection._socket.end(); }); - this._socket.on('end', function() { + this._socket.on('end', wrapToDomain(connection, function () { connection._protocol.end(); - }); + })); 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)); @@ -127,7 +113,7 @@ Connection.prototype.connect = function connect(options, callback) { } } - this._protocol.handshake(options, bindToCurrentDomain(callback)); + this._protocol.handshake(options, wrapCallbackInDomain(this, callback)); }; Connection.prototype.changeUser = function changeUser(options, callback) { @@ -149,7 +135,7 @@ Connection.prototype.changeUser = function changeUser(options, callback) { timeout : options.timeout, charsetNumber : charsetNumber, currentConfig : this.config - }, bindToCurrentDomain(callback)); + }, wrapCallbackInDomain(this, callback)); }; Connection.prototype.beginTransaction = function beginTransaction(options, callback) { @@ -203,6 +189,10 @@ Connection.prototype.query = function query(sql, values, cb) { query.sql = this.format(query.sql, query.values); } + if (query._callback) { + query._callback = wrapCallbackInDomain(this, query._callback); + } + this._implyConnect(); return this._protocol._enqueue(query); @@ -215,7 +205,7 @@ Connection.prototype.ping = function ping(options, callback) { } this._implyConnect(); - this._protocol.ping(options, bindToCurrentDomain(callback)); + this._protocol.ping(options, wrapCallbackInDomain(this, callback)); }; Connection.prototype.statistics = function statistics(options, callback) { @@ -225,7 +215,7 @@ Connection.prototype.statistics = function statistics(options, callback) { } this._implyConnect(); - this._protocol.stats(options, bindToCurrentDomain(callback)); + this._protocol.stats(options, wrapCallbackInDomain(this, callback)); }; Connection.prototype.end = function end(options, callback) { @@ -246,7 +236,7 @@ Connection.prototype.end = function end(options, callback) { } this._implyConnect(); - this._protocol.quit(opts, bindToCurrentDomain(cb)); + this._protocol.quit(opts, wrapCallbackInDomain(this, cb)); }; Connection.prototype.destroy = function() { @@ -284,52 +274,52 @@ Connection.prototype.format = function(sql, values) { 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'); - - // 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 - }); + var connection = this; - // 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); + }); + + secureSocket.on('secure', function() { + secureEstablished = true; - // start TLS communications - secureSocket._start(); + onSecure(rejectUnauthorized ? this.ssl.verifyError() : null); + }); + + // start TLS communications + secureSocket._start(); + }); }; } else { // pre-0.11 environment @@ -442,8 +432,11 @@ Connection.prototype._handleProtocolConnect = function() { 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; }; @@ -461,3 +454,76 @@ Connection.prototype._implyConnect = function() { this.connect(); } }; + +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 = []; + var ret; + + while (process.domain) { + domains.shift(process.domain); + process.domain.exit(); + } + + try { + ret = fn.apply(this, arguments); + } finally { + for (var i = 0; i < domains.length; i++) { + domains[i].enter(); + } + } + + return ret; + }; +} + +function wrapCallbackInDomain(ee, fn) { + if (typeof fn !== 'function') { + return undefined; + } + + if (fn.domain) { + return fn; + } + + var domain = process.domain; + + if (domain) { + return domain.bind(fn); + } else if (ee) { + return unwrapFromDomain(wrapToDomain(ee, fn)); + } else { + return fn; + } +} + +function wrapToDomain(ee, fn) { + return function () { + if (Events.usingDomains && ee.domain) { + ee.domain.enter(); + fn.apply(this, arguments); + ee.domain.exit(); + } else { + fn.apply(this, arguments); + } + }; +} diff --git a/lib/ConnectionConfig.js b/lib/ConnectionConfig.js index 147aa0abb..06f4399c5 100644 --- a/lib/ConnectionConfig.js +++ b/lib/ConnectionConfig.js @@ -33,6 +33,9 @@ function ConnectionConfig(options) { this.ssl = (typeof options.ssl === 'string') ? ConnectionConfig.getSSLProfile(options.ssl) : (options.ssl || false); + this.localInfile = (options.localInfile === undefined) + ? true + : options.localInfile; this.multipleStatements = options.multipleStatements || false; this.typeCast = (options.typeCast === undefined) ? true @@ -114,6 +117,11 @@ ConnectionConfig.getDefaultFlags = function getDefaultFlags(options) { '+TRANSACTIONS' // Expects status flags ]; + if (options && options.localInfile !== undefined && !options.localInfile) { + // Disable LOCAL modifier for LOAD DATA INFILE + defaultFlags.push('-LOCAL_FILES'); + } + if (options && options.multipleStatements) { // May send multiple statements per COM_QUERY and COM_STMT_PREPARE defaultFlags.push('+MULTI_STATEMENTS'); diff --git a/lib/PoolConnection.js b/lib/PoolConnection.js index d29581804..064c99d32 100644 --- a/lib/PoolConnection.js +++ b/lib/PoolConnection.js @@ -39,11 +39,12 @@ PoolConnection.prototype.release = function release() { PoolConnection.prototype._realEnd = Connection.prototype.end; PoolConnection.prototype.end = function () { - console.warn( 'Calling conn.end() to release a pooled connection is ' - + 'deprecated. In next version calling conn.end() will be ' - + 'restored to default conn.end() behavior. Use ' - + 'conn.release() instead.' - ); + console.warn( + 'Calling conn.end() to release a pooled connection is ' + + 'deprecated. In next version calling conn.end() will be ' + + 'restored to default conn.end() behavior. Use ' + + 'conn.release() instead.' + ); this.release(); }; diff --git a/lib/protocol/Auth.js b/lib/protocol/Auth.js index 8ecc6344a..a1033d1b9 100644 --- a/lib/protocol/Auth.js +++ b/lib/protocol/Auth.js @@ -1,7 +1,19 @@ -var Buffer = require('buffer').Buffer; +var Buffer = require('safe-buffer').Buffer; 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'); @@ -10,9 +22,9 @@ function sha1(msg) { Auth.sha1 = sha1; function xor(a, b) { - a = new Buffer(a, 'binary'); - b = new Buffer(b, 'binary'); - var result = new Buffer(a.length); + a = Buffer.from(a, 'binary'); + b = Buffer.from(b, 'binary'); + var result = Buffer.allocUnsafe(a.length); for (var i = 0; i < a.length; i++) { result[i] = (a[i] ^ b[i]); } @@ -22,11 +34,11 @@ Auth.xor = xor; Auth.token = function(password, scramble) { if (!password) { - return new Buffer(0); + return Buffer.alloc(0); } // password must be in binary format, not utf8 - var stage1 = sha1((new Buffer(password, 'utf8')).toString('binary')); + var stage1 = sha1((Buffer.from(password, 'utf8')).toString('binary')); var stage2 = sha1(stage1); var stage3 = sha1(scramble.toString('binary') + stage2); return xor(stage3, stage1); @@ -35,13 +47,13 @@ Auth.token = function(password, scramble) { // This is a port of sql/password.c:hash_password which needs to be used for // pre-4.1 passwords. Auth.hashPassword = function(password) { - var nr = [0x5030, 0x5735], - add = 7, - nr2 = [0x1234, 0x5671], - result = new Buffer(8); + var nr = [0x5030, 0x5735]; + var add = 7; + var nr2 = [0x1234, 0x5671]; + var result = Buffer.alloc(8); if (typeof password === 'string'){ - password = new Buffer(password); + password = Buffer.from(password); } for (var i = 0; i < password.length; i++) { @@ -53,7 +65,7 @@ Auth.hashPassword = function(password) { // nr^= (((nr & 63)+add)*c)+ (nr << 8); // nr = xor(nr, add(mul(add(and(nr, 63), add), c), shl(nr, 8))) - nr = this.xor32(nr, this.add32(this.mul32(this.add32(this.and32(nr, [0,63]), [0,add]), [0,c]), this.shl32(nr, 8))); + nr = this.xor32(nr, this.add32(this.mul32(this.add32(this.and32(nr, [0, 63]), [0, add]), [0, c]), this.shl32(nr, 8))); // nr2+=(nr2 << 8) ^ nr; // nr2 = add(nr2, xor(shl(nr2, 8), nr)) @@ -86,12 +98,16 @@ Auth.myRnd = function(r){ }; Auth.scramble323 = function(message, password) { - var to = new Buffer(8), - hashPass = this.hashPassword(password), - hashMessage = this.hashPassword(message.slice(0, 8)), - seed1 = this.int32Read(hashPass, 0) ^ this.int32Read(hashMessage, 0), - seed2 = this.int32Read(hashPass, 4) ^ this.int32Read(hashMessage, 4), - r = this.randomInit(seed1, seed2); + if (!password) { + return Buffer.alloc(0); + } + + var to = Buffer.allocUnsafe(8); + var hashPass = this.hashPassword(password); + var hashMessage = this.hashPassword(message.slice(0, 8)); + var seed1 = this.int32Read(hashPass, 0) ^ this.int32Read(hashMessage, 0); + var seed2 = this.int32Read(hashPass, 4) ^ this.int32Read(hashMessage, 4); + var r = this.randomInit(seed1, seed2); for (var i = 0; i < 8; i++){ to[i] = Math.floor(this.myRnd(r) * 31) + 64; @@ -105,34 +121,34 @@ Auth.scramble323 = function(message, password) { return to; }; -Auth.xor32 = function(a,b){ +Auth.xor32 = function(a, b){ return [a[0] ^ b[0], a[1] ^ b[1]]; }; -Auth.add32 = function(a,b){ - var w1 = a[1] + b[1], - w2 = a[0] + b[0] + ((w1 & 0xFFFF0000) >> 16); +Auth.add32 = function(a, b){ + var w1 = a[1] + b[1]; + var w2 = a[0] + b[0] + ((w1 & 0xFFFF0000) >> 16); return [w2 & 0xFFFF, w1 & 0xFFFF]; }; -Auth.mul32 = function(a,b){ +Auth.mul32 = function(a, b){ // based on this example of multiplying 32b ints using 16b // http://www.dsprelated.com/showmessage/89790/1.php - var w1 = a[1] * b[1], - w2 = (((a[1] * b[1]) >> 16) & 0xFFFF) + ((a[0] * b[1]) & 0xFFFF) + (a[1] * b[0] & 0xFFFF); + var w1 = a[1] * b[1]; + var w2 = (((a[1] * b[1]) >> 16) & 0xFFFF) + ((a[0] * b[1]) & 0xFFFF) + (a[1] * b[0] & 0xFFFF); return [w2 & 0xFFFF, w1 & 0xFFFF]; }; -Auth.and32 = function(a,b){ +Auth.and32 = function(a, b){ return [a[0] & b[0], a[1] & b[1]]; }; -Auth.shl32 = function(a,b){ +Auth.shl32 = function(a, b){ // assume b is 16 or less - var w1 = a[1] << b, - w2 = (a[0] << b) | ((w1 & 0xFFFF0000) >> 16); + var w1 = a[1] << b; + var w2 = (a[0] << b) | ((w1 & 0xFFFF0000) >> 16); return [w2 & 0xFFFF, w1 & 0xFFFF]; }; diff --git a/lib/protocol/PacketWriter.js b/lib/protocol/PacketWriter.js index 3e2de5178..4d0afd2af 100644 --- a/lib/protocol/PacketWriter.js +++ b/lib/protocol/PacketWriter.js @@ -5,6 +5,7 @@ var BUFFER_ALLOC_SIZE = Math.pow(2, 8); // Don't panic: Good enough to represent byte values up to 8192 TB var IEEE_754_BINARY_64_PRECISION = Math.pow(2, 53); var MAX_PACKET_LENGTH = Math.pow(2, 24) - 1; +var Buffer = require('safe-buffer').Buffer; module.exports = PacketWriter; function PacketWriter() { @@ -14,7 +15,7 @@ function PacketWriter() { PacketWriter.prototype.toBuffer = function toBuffer(parser) { if (!this._buffer) { - this._buffer = new Buffer(0); + this._buffer = Buffer.alloc(0); this._offset = 0; } @@ -22,7 +23,7 @@ PacketWriter.prototype.toBuffer = function toBuffer(parser) { var length = this._offset; var packets = Math.floor(length / MAX_PACKET_LENGTH) + 1; - this._buffer = new Buffer(length + packets * 4); + this._buffer = Buffer.allocUnsafe(length + packets * 4); this._offset = 0; for (var packet = 0; packet < packets; packet++) { @@ -192,7 +193,7 @@ PacketWriter.prototype.writeLengthCodedString = function(value) { PacketWriter.prototype._allocate = function _allocate(bytes) { if (!this._buffer) { - this._buffer = new Buffer(Math.max(BUFFER_ALLOC_SIZE, bytes)); + this._buffer = Buffer.alloc(Math.max(BUFFER_ALLOC_SIZE, bytes)); this._offset = 0; return; } @@ -205,6 +206,6 @@ PacketWriter.prototype._allocate = function _allocate(bytes) { var newSize = this._buffer.length + Math.max(BUFFER_ALLOC_SIZE, bytes); var oldBuffer = this._buffer; - this._buffer = new Buffer(newSize); + this._buffer = Buffer.alloc(newSize); oldBuffer.copy(this._buffer); }; diff --git a/lib/protocol/Parser.js b/lib/protocol/Parser.js index 38e004f23..e72555f2e 100644 --- a/lib/protocol/Parser.js +++ b/lib/protocol/Parser.js @@ -1,15 +1,18 @@ -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 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) { options = options || {}; this._supportBigNumbers = options.config && options.config.supportBigNumbers; - this._buffer = new Buffer(0); + this._buffer = Buffer.alloc(0); this._nextBuffers = new BufferList(); this._longPacketBuffers = new BufferList(); this._offset = 0; @@ -27,71 +30,17 @@ Parser.prototype.write = function write(chunk) { 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; - - this._onError(err); - } + var packetHeader = this._tryReadPacketHeader(); - 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); } }; @@ -119,7 +68,7 @@ Parser.prototype.append = function append(chunk) { if (sliceLength !== 0) { // Create a new Buffer - buffer = new Buffer(sliceLength + length); + buffer = Buffer.allocUnsafe(sliceLength + length); offset = 0; // Copy data slice @@ -131,7 +80,7 @@ Parser.prototype.append = function append(chunk) { } } else if (chunks.length > 1) { // Create a new Buffer - buffer = new Buffer(length); + buffer = Buffer.allocUnsafe(length); offset = 0; // Copy chunks @@ -166,8 +115,8 @@ Parser.prototype.resume = function() { process.nextTick(this.write.bind(this)); }; -Parser.prototype.peak = function() { - return this._buffer[this._offset]; +Parser.prototype.peak = function peak(offset) { + return this._buffer[this._offset + (offset >>> 0)]; }; Parser.prototype.parseUnsignedNumber = function parseUnsignedNumber(bytes) { @@ -251,7 +200,7 @@ Parser.prototype.parseLengthCodedNumber = function parseLengthCodedNumber() { 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; @@ -308,13 +257,18 @@ Parser.prototype._nullByteOffset = function() { return offset; }; +Parser.prototype.parsePacketTerminatedBuffer = function parsePacketTerminatedBuffer() { + var length = this._packetEnd - this._offset; + return this.parseBuffer(length); +}; + Parser.prototype.parsePacketTerminatedString = function() { var length = this._packetEnd - this._offset; return this.parseString(length); }; Parser.prototype.parseBuffer = function(length) { - var response = new Buffer(length); + var response = Buffer.alloc(length); this._buffer.copy(response, 0, this._offset, this._offset + length); this._offset += length; @@ -342,7 +296,7 @@ Parser.prototype.parseGeometryValue = function() { var result = null; var byteOrder = buffer.readUInt8(offset); offset += 1; var wkbType = byteOrder ? buffer.readUInt32LE(offset) : buffer.readUInt32BE(offset); offset += 4; - switch(wkbType) { + switch (wkbType) { case 1: // WKBPoint var x = byteOrder ? buffer.readDoubleLE(offset) : buffer.readDoubleBE(offset); offset += 8; var y = byteOrder ? buffer.readDoubleLE(offset) : buffer.readDoubleBE(offset); offset += 8; @@ -351,7 +305,7 @@ Parser.prototype.parseGeometryValue = function() { case 2: // WKBLineString var numPoints = byteOrder ? buffer.readUInt32LE(offset) : buffer.readUInt32BE(offset); offset += 4; result = []; - for(var i = numPoints; i > 0; i--) { + for (var i = numPoints; i > 0; i--) { var x = byteOrder ? buffer.readDoubleLE(offset) : buffer.readDoubleBE(offset); offset += 8; var y = byteOrder ? buffer.readDoubleLE(offset) : buffer.readDoubleBE(offset); offset += 8; result.push({x: x, y: y}); @@ -360,10 +314,10 @@ Parser.prototype.parseGeometryValue = function() { case 3: // WKBPolygon var numRings = byteOrder ? buffer.readUInt32LE(offset) : buffer.readUInt32BE(offset); offset += 4; result = []; - for(var i = numRings; i > 0; i--) { + for (var i = numRings; i > 0; i--) { var numPoints = byteOrder ? buffer.readUInt32LE(offset) : buffer.readUInt32BE(offset); offset += 4; var line = []; - for(var j = numPoints; j > 0; j--) { + for (var j = numPoints; j > 0; j--) { var x = byteOrder ? buffer.readDoubleLE(offset) : buffer.readDoubleBE(offset); offset += 8; var y = byteOrder ? buffer.readDoubleLE(offset) : buffer.readDoubleBE(offset); offset += 8; line.push({x: x, y: y}); @@ -377,7 +331,7 @@ Parser.prototype.parseGeometryValue = function() { case 7: // WKBGeometryCollection var num = byteOrder ? buffer.readUInt32LE(offset) : buffer.readUInt32BE(offset); offset += 4; var result = []; - for(var i = num; i > 0; i--) { + for (var i = num; i > 0; i--) { result.push(parseGeometry()); } break; @@ -445,7 +399,7 @@ Parser.prototype._combineLongPacketBuffers = function _combineLongPacketBuffers( // Create buffer var buf = null; - var buffer = new Buffer(remainingBytes + this._longPacketBuffers.size); + var buffer = Buffer.allocUnsafe(remainingBytes + this._longPacketBuffers.size); var offset = 0; // Copy long buffers @@ -462,6 +416,73 @@ Parser.prototype._combineLongPacketBuffers = function _combineLongPacketBuffers( 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 --git a/lib/protocol/Protocol.js b/lib/protocol/Protocol.js index 99869b235..ab371059b 100644 --- a/lib/protocol/Protocol.js +++ b/lib/protocol/Protocol.js @@ -1,7 +1,6 @@ var Parser = require('./Parser'); var Sequences = require('./sequences'); var Packets = require('./packets'); -var Timers = require('timers'); var Stream = require('stream').Stream; var Util = require('util'); var PacketWriter = require('./PacketWriter'); @@ -21,7 +20,7 @@ function Protocol(options) { this._callback = null; this._fatalError = null; this._quitSequence = null; - this._handshakeSequence = null; + this._handshake = false; this._handshaked = false; this._ended = false; this._destroyed = false; @@ -49,7 +48,11 @@ Protocol.prototype.handshake = function handshake(options, callback) { options = options || {}; options.config = this._config; - return this._handshakeSequence = this._enqueue(new Sequences.Handshake(options, callback)); + var sequence = this._enqueue(new Sequences.Handshake(options, callback)); + + this._handshake = true; + + return sequence; }; Protocol.prototype.query = function query(options, callback) { @@ -95,7 +98,7 @@ Protocol.prototype.quit = function quit(options, callback) { }; Protocol.prototype.end = function() { - if(this._ended) { + if (this._ended) { return; } this._ended = true; @@ -150,12 +153,9 @@ Protocol.prototype._enqueue = function(sequence) { self._delegateError(err, sequence); }) .on('packet', function(packet) { - Timers.active(sequence); + sequence._timer.active(); self._emitPacket(packet); }) - .on('end', function() { - self._dequeue(sequence); - }) .on('timeout', function() { var err = new Error(sequence.constructor.name + ' inactivity timeout'); @@ -164,9 +164,11 @@ Protocol.prototype._enqueue = function(sequence) { err.timeout = sequence._timeout; self._delegateError(err, sequence); - }) - .on('start-tls', function() { - Timers.active(sequence); + }); + + if (sequence.constructor === Sequences.Handshake) { + sequence.on('start-tls', function () { + sequence._timer.active(); self._connection._startTLS(function(err) { if (err) { // SSL negotiation error are fatal @@ -176,11 +178,24 @@ Protocol.prototype._enqueue = function(sequence) { return; } - Timers.active(sequence); + sequence._timer.active(); sequence._tlsUpgradeCompleteHandler(); }); }); + 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); @@ -192,24 +207,19 @@ Protocol.prototype._enqueue = function(sequence) { Protocol.prototype._validateEnqueue = function _validateEnqueue(sequence) { var err; var prefix = 'Cannot enqueue ' + sequence.constructor.name; - var prefixBefore = prefix + ' before '; - var prefixAfter = prefix + ' after '; if (this._fatalError) { - err = new Error(prefixAfter + 'fatal error.'); + err = new Error(prefix + ' after fatal error.'); err.code = 'PROTOCOL_ENQUEUE_AFTER_FATAL_ERROR'; } else if (this._quitSequence) { - err = new Error(prefixAfter + 'invoking quit.'); + err = new Error(prefix + ' after invoking quit.'); err.code = 'PROTOCOL_ENQUEUE_AFTER_QUIT'; } else if (this._destroyed) { - err = new Error(prefixAfter + 'being destroyed.'); + err = new Error(prefix + ' after being destroyed.'); err.code = 'PROTOCOL_ENQUEUE_AFTER_DESTROY'; - } else if (this._handshakeSequence && sequence.constructor === Sequences.Handshake) { - err = new Error(prefixAfter + 'already enqueuing a Handshake.'); + } else if ((this._handshake || this._handshaked) && sequence.constructor === Sequences.Handshake) { + err = new Error(prefix + ' after already enqueuing a Handshake.'); err.code = 'PROTOCOL_ENQUEUE_HANDSHAKE_TWICE'; - } else if (!this._handshakeSequence && sequence.constructor === Sequences.ChangeUser) { - err = new Error(prefixBefore + 'a Handshake.'); - err.code = 'PROTOCOL_ENQUEUE_BEFORE_HANDSHAKE'; } else { return true; } @@ -264,9 +274,10 @@ Protocol.prototype._parsePacket = function() { if (Packet === Packets.HandshakeInitializationPacket) { this._handshakeInitializationPacket = packet; + this.emit('initialize', packet); } - Timers.active(sequence); + sequence._timer.active(); if (!sequence[packetName]) { var err = new Error('Received packet in the wrong sequence.'); @@ -309,12 +320,7 @@ Protocol.prototype._determinePacket = function(sequence) { } 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; } @@ -323,7 +329,7 @@ Protocol.prototype._determinePacket = function(sequence) { }; Protocol.prototype._dequeue = function(sequence) { - Timers.unenroll(sequence); + sequence._timer.stop(); // No point in advancing the queue, we are dead if (this._fatalError) { @@ -345,8 +351,7 @@ Protocol.prototype._dequeue = function(sequence) { Protocol.prototype._startSequence = function(sequence) { if (sequence._timeout > 0 && isFinite(sequence._timeout)) { - Timers.enroll(sequence, sequence._timeout); - Timers.active(sequence); + sequence._timer.start(sequence._timeout); } if (sequence.constructor === Sequences.ChangeUser) { @@ -431,25 +436,28 @@ Protocol.prototype.destroy = function() { this._parser.pause(); if (this._connection.state !== 'disconnected') { - if(!this._ended) { + if (!this._ended) { this.end(); } } }; Protocol.prototype._debugPacket = function(incoming, packet) { - var headline = (incoming) - ? '<-- ' - : '--> '; - - headline = headline + packet.constructor.name; + var connection = this._connection; + 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 --git a/lib/protocol/Timer.js b/lib/protocol/Timer.js new file mode 100644 index 000000000..45ed0292f --- /dev/null +++ b/lib/protocol/Timer.js @@ -0,0 +1,33 @@ +var Timers = require('timers'); + +module.exports = Timer; +function Timer(object) { + this._object = object; + this._timeout = null; +} + +Timer.prototype.active = function active() { + if (this._timeout) { + if (this._timeout.refresh) { + this._timeout.refresh(); + } else { + Timers.active(this._timeout); + } + } +}; + +Timer.prototype.start = function start(msecs) { + this.stop(); + this._timeout = Timers.setTimeout(this._onTimeout.bind(this), msecs); +}; + +Timer.prototype.stop = function stop() { + if (this._timeout) { + Timers.clearTimeout(this._timeout); + this._timeout = null; + } +}; + +Timer.prototype._onTimeout = function _onTimeout() { + return this._object._onTimeout(); +}; diff --git a/lib/protocol/constants/errors.js b/lib/protocol/constants/errors.js index c16014595..e75774183 100644 --- a/lib/protocol/constants/errors.js +++ b/lib/protocol/constants/errors.js @@ -1,7 +1,7 @@ /** * MySQL error constants * - * Extracted from version 5.7.17 + * Extracted from version 5.7.29 * * !! Generated by generate-error-constants.js, do not modify by hand !! */ @@ -1005,201 +1005,240 @@ exports.ER_AES_INVALID_IV exports.ER_PLUGIN_CANNOT_BE_UNINSTALLED = 1883; exports.ER_GTID_UNSAFE_BINLOG_SPLITTABLE_STATEMENT_AND_GTID_GROUP = 1884; exports.ER_SLAVE_HAS_MORE_GTIDS_THAN_MASTER = 1885; -exports.ER_FILE_CORRUPT = 1886; -exports.ER_ERROR_ON_MASTER = 1887; -exports.ER_INCONSISTENT_ERROR = 1888; -exports.ER_STORAGE_ENGINE_NOT_LOADED = 1889; -exports.ER_GET_STACKED_DA_WITHOUT_ACTIVE_HANDLER = 1890; -exports.ER_WARN_LEGACY_SYNTAX_CONVERTED = 1891; -exports.ER_BINLOG_UNSAFE_FULLTEXT_PLUGIN = 1892; -exports.ER_CANNOT_DISCARD_TEMPORARY_TABLE = 1893; -exports.ER_FK_DEPTH_EXCEEDED = 1894; -exports.ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE_V2 = 1895; -exports.ER_WARN_TRIGGER_DOESNT_HAVE_CREATED = 1896; -exports.ER_REFERENCED_TRG_DOES_NOT_EXIST = 1897; -exports.ER_EXPLAIN_NOT_SUPPORTED = 1898; -exports.ER_INVALID_FIELD_SIZE = 1899; -exports.ER_MISSING_HA_CREATE_OPTION = 1900; -exports.ER_ENGINE_OUT_OF_MEMORY = 1901; -exports.ER_PASSWORD_EXPIRE_ANONYMOUS_USER = 1902; -exports.ER_SLAVE_SQL_THREAD_MUST_STOP = 1903; -exports.ER_NO_FT_MATERIALIZED_SUBQUERY = 1904; -exports.ER_INNODB_UNDO_LOG_FULL = 1905; -exports.ER_INVALID_ARGUMENT_FOR_LOGARITHM = 1906; -exports.ER_SLAVE_CHANNEL_IO_THREAD_MUST_STOP = 1907; -exports.ER_WARN_OPEN_TEMP_TABLES_MUST_BE_ZERO = 1908; -exports.ER_WARN_ONLY_MASTER_LOG_FILE_NO_POS = 1909; -exports.ER_QUERY_TIMEOUT = 1910; -exports.ER_NON_RO_SELECT_DISABLE_TIMER = 1911; -exports.ER_DUP_LIST_ENTRY = 1912; -exports.ER_SQL_MODE_NO_EFFECT = 1913; -exports.ER_AGGREGATE_ORDER_FOR_UNION = 1914; -exports.ER_AGGREGATE_ORDER_NON_AGG_QUERY = 1915; -exports.ER_SLAVE_WORKER_STOPPED_PREVIOUS_THD_ERROR = 1916; -exports.ER_DONT_SUPPORT_SLAVE_PRESERVE_COMMIT_ORDER = 1917; -exports.ER_SERVER_OFFLINE_MODE = 1918; -exports.ER_GIS_DIFFERENT_SRIDS = 1919; -exports.ER_GIS_UNSUPPORTED_ARGUMENT = 1920; -exports.ER_GIS_UNKNOWN_ERROR = 1921; -exports.ER_GIS_UNKNOWN_EXCEPTION = 1922; -exports.ER_GIS_INVALID_DATA = 1923; -exports.ER_BOOST_GEOMETRY_EMPTY_INPUT_EXCEPTION = 1924; -exports.ER_BOOST_GEOMETRY_CENTROID_EXCEPTION = 1925; -exports.ER_BOOST_GEOMETRY_OVERLAY_INVALID_INPUT_EXCEPTION = 1926; -exports.ER_BOOST_GEOMETRY_TURN_INFO_EXCEPTION = 1927; -exports.ER_BOOST_GEOMETRY_SELF_INTERSECTION_POINT_EXCEPTION = 1928; -exports.ER_BOOST_GEOMETRY_UNKNOWN_EXCEPTION = 1929; -exports.ER_STD_BAD_ALLOC_ERROR = 1930; -exports.ER_STD_DOMAIN_ERROR = 1931; -exports.ER_STD_LENGTH_ERROR = 1932; -exports.ER_STD_INVALID_ARGUMENT = 1933; -exports.ER_STD_OUT_OF_RANGE_ERROR = 1934; -exports.ER_STD_OVERFLOW_ERROR = 1935; -exports.ER_STD_RANGE_ERROR = 1936; -exports.ER_STD_UNDERFLOW_ERROR = 1937; -exports.ER_STD_LOGIC_ERROR = 1938; -exports.ER_STD_RUNTIME_ERROR = 1939; -exports.ER_STD_UNKNOWN_EXCEPTION = 1940; -exports.ER_GIS_DATA_WRONG_ENDIANESS = 1941; -exports.ER_CHANGE_MASTER_PASSWORD_LENGTH = 1942; -exports.ER_USER_LOCK_WRONG_NAME = 1943; -exports.ER_USER_LOCK_DEADLOCK = 1944; -exports.ER_REPLACE_INACCESSIBLE_ROWS = 1945; -exports.ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_GIS = 1946; -exports.ER_ILLEGAL_USER_VAR = 1947; -exports.ER_GTID_MODE_OFF = 1948; -exports.ER_UNSUPPORTED_BY_REPLICATION_THREAD = 1949; -exports.ER_INCORRECT_TYPE = 1950; -exports.ER_FIELD_IN_ORDER_NOT_SELECT = 1951; -exports.ER_AGGREGATE_IN_ORDER_NOT_SELECT = 1952; -exports.ER_INVALID_RPL_WILD_TABLE_FILTER_PATTERN = 1953; -exports.ER_NET_OK_PACKET_TOO_LARGE = 1954; -exports.ER_INVALID_JSON_DATA = 1955; -exports.ER_INVALID_GEOJSON_MISSING_MEMBER = 1956; -exports.ER_INVALID_GEOJSON_WRONG_TYPE = 1957; -exports.ER_INVALID_GEOJSON_UNSPECIFIED = 1958; -exports.ER_DIMENSION_UNSUPPORTED = 1959; -exports.ER_SLAVE_CHANNEL_DOES_NOT_EXIST = 1960; -exports.ER_SLAVE_MULTIPLE_CHANNELS_HOST_PORT = 1961; -exports.ER_SLAVE_CHANNEL_NAME_INVALID_OR_TOO_LONG = 1962; -exports.ER_SLAVE_NEW_CHANNEL_WRONG_REPOSITORY = 1963; -exports.ER_SLAVE_CHANNEL_DELETE = 1964; -exports.ER_SLAVE_MULTIPLE_CHANNELS_CMD = 1965; -exports.ER_SLAVE_MAX_CHANNELS_EXCEEDED = 1966; -exports.ER_SLAVE_CHANNEL_MUST_STOP = 1967; -exports.ER_SLAVE_CHANNEL_NOT_RUNNING = 1968; -exports.ER_SLAVE_CHANNEL_WAS_RUNNING = 1969; -exports.ER_SLAVE_CHANNEL_WAS_NOT_RUNNING = 1970; -exports.ER_SLAVE_CHANNEL_SQL_THREAD_MUST_STOP = 1971; -exports.ER_SLAVE_CHANNEL_SQL_SKIP_COUNTER = 1972; -exports.ER_WRONG_FIELD_WITH_GROUP_V2 = 1973; -exports.ER_MIX_OF_GROUP_FUNC_AND_FIELDS_V2 = 1974; -exports.ER_WARN_DEPRECATED_SYSVAR_UPDATE = 1975; -exports.ER_WARN_DEPRECATED_SQLMODE = 1976; -exports.ER_CANNOT_LOG_PARTIAL_DROP_DATABASE_WITH_GTID = 1977; -exports.ER_GROUP_REPLICATION_CONFIGURATION = 1978; -exports.ER_GROUP_REPLICATION_RUNNING = 1979; -exports.ER_GROUP_REPLICATION_APPLIER_INIT_ERROR = 1980; -exports.ER_GROUP_REPLICATION_STOP_APPLIER_THREAD_TIMEOUT = 1981; -exports.ER_GROUP_REPLICATION_COMMUNICATION_LAYER_SESSION_ERROR = 1982; -exports.ER_GROUP_REPLICATION_COMMUNICATION_LAYER_JOIN_ERROR = 1983; -exports.ER_BEFORE_DML_VALIDATION_ERROR = 1984; -exports.ER_PREVENTS_VARIABLE_WITHOUT_RBR = 1985; -exports.ER_RUN_HOOK_ERROR = 1986; -exports.ER_TRANSACTION_ROLLBACK_DURING_COMMIT = 1987; -exports.ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED = 1988; -exports.ER_UNSUPPORTED_ALTER_INPLACE_ON_VIRTUAL_COLUMN = 1989; -exports.ER_WRONG_FK_OPTION_FOR_GENERATED_COLUMN = 1990; -exports.ER_NON_DEFAULT_VALUE_FOR_GENERATED_COLUMN = 1991; -exports.ER_UNSUPPORTED_ACTION_ON_GENERATED_COLUMN = 1992; -exports.ER_GENERATED_COLUMN_NON_PRIOR = 1993; -exports.ER_DEPENDENT_BY_GENERATED_COLUMN = 1994; -exports.ER_GENERATED_COLUMN_REF_AUTO_INC = 1995; -exports.ER_FEATURE_NOT_AVAILABLE = 1996; -exports.ER_CANT_SET_GTID_MODE = 1997; -exports.ER_CANT_USE_AUTO_POSITION_WITH_GTID_MODE_OFF = 1998; -exports.ER_CANT_REPLICATE_ANONYMOUS_WITH_AUTO_POSITION = 1999; -exports.ER_CANT_REPLICATE_ANONYMOUS_WITH_GTID_MODE_ON = 2000; -exports.ER_CANT_REPLICATE_GTID_WITH_GTID_MODE_OFF = 2001; -exports.ER_CANT_SET_ENFORCE_GTID_CONSISTENCY_ON_WITH_ONGOING_GTID_VIOLATING_TRANSACTIONS = 2002; -exports.ER_SET_ENFORCE_GTID_CONSISTENCY_WARN_WITH_ONGOING_GTID_VIOLATING_TRANSACTIONS = 2003; -exports.ER_ACCOUNT_HAS_BEEN_LOCKED = 2004; -exports.ER_WRONG_TABLESPACE_NAME = 2005; -exports.ER_TABLESPACE_IS_NOT_EMPTY = 2006; -exports.ER_WRONG_FILE_NAME = 2007; -exports.ER_BOOST_GEOMETRY_INCONSISTENT_TURNS_EXCEPTION = 2008; -exports.ER_WARN_OPTIMIZER_HINT_SYNTAX_ERROR = 2009; -exports.ER_WARN_BAD_MAX_EXECUTION_TIME = 2010; -exports.ER_WARN_UNSUPPORTED_MAX_EXECUTION_TIME = 2011; -exports.ER_WARN_CONFLICTING_HINT = 2012; -exports.ER_WARN_UNKNOWN_QB_NAME = 2013; -exports.ER_UNRESOLVED_HINT_NAME = 2014; -exports.ER_WARN_ON_MODIFYING_GTID_EXECUTED_TABLE = 2015; -exports.ER_PLUGGABLE_PROTOCOL_COMMAND_NOT_SUPPORTED = 2016; -exports.ER_LOCKING_SERVICE_WRONG_NAME = 2017; -exports.ER_LOCKING_SERVICE_DEADLOCK = 2018; -exports.ER_LOCKING_SERVICE_TIMEOUT = 2019; -exports.ER_GIS_MAX_POINTS_IN_GEOMETRY_OVERFLOWED = 2020; -exports.ER_SQL_MODE_MERGED = 2021; -exports.ER_VTOKEN_PLUGIN_TOKEN_MISMATCH = 2022; -exports.ER_VTOKEN_PLUGIN_TOKEN_NOT_FOUND = 2023; -exports.ER_CANT_SET_VARIABLE_WHEN_OWNING_GTID = 2024; -exports.ER_SLAVE_CHANNEL_OPERATION_NOT_ALLOWED = 2025; -exports.ER_INVALID_JSON_TEXT = 2026; -exports.ER_INVALID_JSON_TEXT_IN_PARAM = 2027; -exports.ER_INVALID_JSON_BINARY_DATA = 2028; -exports.ER_INVALID_JSON_PATH = 2029; -exports.ER_INVALID_JSON_CHARSET = 2030; -exports.ER_INVALID_JSON_CHARSET_IN_FUNCTION = 2031; -exports.ER_INVALID_TYPE_FOR_JSON = 2032; -exports.ER_INVALID_CAST_TO_JSON = 2033; -exports.ER_INVALID_JSON_PATH_CHARSET = 2034; -exports.ER_INVALID_JSON_PATH_WILDCARD = 2035; -exports.ER_JSON_VALUE_TOO_BIG = 2036; -exports.ER_JSON_KEY_TOO_BIG = 2037; -exports.ER_JSON_USED_AS_KEY = 2038; -exports.ER_JSON_VACUOUS_PATH = 2039; -exports.ER_JSON_BAD_ONE_OR_ALL_ARG = 2040; -exports.ER_NUMERIC_JSON_VALUE_OUT_OF_RANGE = 2041; -exports.ER_INVALID_JSON_VALUE_FOR_CAST = 2042; -exports.ER_JSON_DOCUMENT_TOO_DEEP = 2043; -exports.ER_JSON_DOCUMENT_NULL_KEY = 2044; -exports.ER_SECURE_TRANSPORT_REQUIRED = 2045; -exports.ER_NO_SECURE_TRANSPORTS_CONFIGURED = 2046; -exports.ER_DISABLED_STORAGE_ENGINE = 2047; -exports.ER_USER_DOES_NOT_EXIST = 2048; -exports.ER_USER_ALREADY_EXISTS = 2049; -exports.ER_AUDIT_API_ABORT = 2050; -exports.ER_INVALID_JSON_PATH_ARRAY_CELL = 2051; -exports.ER_BUFPOOL_RESIZE_INPROGRESS = 2052; -exports.ER_FEATURE_DISABLED_SEE_DOC = 2053; -exports.ER_SERVER_ISNT_AVAILABLE = 2054; -exports.ER_SESSION_WAS_KILLED = 2055; -exports.ER_CAPACITY_EXCEEDED = 2056; -exports.ER_CAPACITY_EXCEEDED_IN_RANGE_OPTIMIZER = 2057; -exports.ER_TABLE_NEEDS_UPG_PART = 2058; -exports.ER_CANT_WAIT_FOR_EXECUTED_GTID_SET_WHILE_OWNING_A_GTID = 2059; -exports.ER_CANNOT_ADD_FOREIGN_BASE_COL_VIRTUAL = 2060; -exports.ER_CANNOT_CREATE_VIRTUAL_INDEX_CONSTRAINT = 2061; -exports.ER_ERROR_ON_MODIFYING_GTID_EXECUTED_TABLE = 2062; -exports.ER_LOCK_REFUSED_BY_ENGINE = 2063; -exports.ER_UNSUPPORTED_ALTER_ONLINE_ON_VIRTUAL_COLUMN = 2064; -exports.ER_MASTER_KEY_ROTATION_NOT_SUPPORTED_BY_SE = 2065; -exports.ER_MASTER_KEY_ROTATION_ERROR_BY_SE = 2066; -exports.ER_MASTER_KEY_ROTATION_BINLOG_FAILED = 2067; -exports.ER_MASTER_KEY_ROTATION_SE_UNAVAILABLE = 2068; -exports.ER_TABLESPACE_CANNOT_ENCRYPT = 2069; -exports.ER_INVALID_ENCRYPTION_OPTION = 2070; -exports.ER_CANNOT_FIND_KEY_IN_KEYRING = 2071; -exports.ER_CAPACITY_EXCEEDED_IN_PARSER = 2072; -exports.ER_UNSUPPORTED_ALTER_ENCRYPTION_INPLACE = 2073; -exports.ER_KEYRING_UDF_KEYRING_SERVICE_ERROR = 2074; -exports.ER_USER_COLUMN_OLD_LENGTH = 2075; -exports.ER_CANT_RESET_MASTER = 2076; -exports.ER_GROUP_REPLICATION_MAX_GROUP_SIZE = 2077; -exports.ER_CANNOT_ADD_FOREIGN_BASE_COL_STORED = 2078; -exports.ER_TABLE_REFERENCED = 2079; -exports.ER_PARTITION_ENGINE_DEPRECATED_FOR_TABLE = 2080; +exports.ER_MISSING_KEY = 1886; +exports.WARN_NAMED_PIPE_ACCESS_EVERYONE = 1887; +exports.ER_FOUND_MISSING_GTIDS = 1888; +exports.ER_FILE_CORRUPT = 3000; +exports.ER_ERROR_ON_MASTER = 3001; +exports.ER_INCONSISTENT_ERROR = 3002; +exports.ER_STORAGE_ENGINE_NOT_LOADED = 3003; +exports.ER_GET_STACKED_DA_WITHOUT_ACTIVE_HANDLER = 3004; +exports.ER_WARN_LEGACY_SYNTAX_CONVERTED = 3005; +exports.ER_BINLOG_UNSAFE_FULLTEXT_PLUGIN = 3006; +exports.ER_CANNOT_DISCARD_TEMPORARY_TABLE = 3007; +exports.ER_FK_DEPTH_EXCEEDED = 3008; +exports.ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE_V2 = 3009; +exports.ER_WARN_TRIGGER_DOESNT_HAVE_CREATED = 3010; +exports.ER_REFERENCED_TRG_DOES_NOT_EXIST = 3011; +exports.ER_EXPLAIN_NOT_SUPPORTED = 3012; +exports.ER_INVALID_FIELD_SIZE = 3013; +exports.ER_MISSING_HA_CREATE_OPTION = 3014; +exports.ER_ENGINE_OUT_OF_MEMORY = 3015; +exports.ER_PASSWORD_EXPIRE_ANONYMOUS_USER = 3016; +exports.ER_SLAVE_SQL_THREAD_MUST_STOP = 3017; +exports.ER_NO_FT_MATERIALIZED_SUBQUERY = 3018; +exports.ER_INNODB_UNDO_LOG_FULL = 3019; +exports.ER_INVALID_ARGUMENT_FOR_LOGARITHM = 3020; +exports.ER_SLAVE_CHANNEL_IO_THREAD_MUST_STOP = 3021; +exports.ER_WARN_OPEN_TEMP_TABLES_MUST_BE_ZERO = 3022; +exports.ER_WARN_ONLY_MASTER_LOG_FILE_NO_POS = 3023; +exports.ER_QUERY_TIMEOUT = 3024; +exports.ER_NON_RO_SELECT_DISABLE_TIMER = 3025; +exports.ER_DUP_LIST_ENTRY = 3026; +exports.ER_SQL_MODE_NO_EFFECT = 3027; +exports.ER_AGGREGATE_ORDER_FOR_UNION = 3028; +exports.ER_AGGREGATE_ORDER_NON_AGG_QUERY = 3029; +exports.ER_SLAVE_WORKER_STOPPED_PREVIOUS_THD_ERROR = 3030; +exports.ER_DONT_SUPPORT_SLAVE_PRESERVE_COMMIT_ORDER = 3031; +exports.ER_SERVER_OFFLINE_MODE = 3032; +exports.ER_GIS_DIFFERENT_SRIDS = 3033; +exports.ER_GIS_UNSUPPORTED_ARGUMENT = 3034; +exports.ER_GIS_UNKNOWN_ERROR = 3035; +exports.ER_GIS_UNKNOWN_EXCEPTION = 3036; +exports.ER_GIS_INVALID_DATA = 3037; +exports.ER_BOOST_GEOMETRY_EMPTY_INPUT_EXCEPTION = 3038; +exports.ER_BOOST_GEOMETRY_CENTROID_EXCEPTION = 3039; +exports.ER_BOOST_GEOMETRY_OVERLAY_INVALID_INPUT_EXCEPTION = 3040; +exports.ER_BOOST_GEOMETRY_TURN_INFO_EXCEPTION = 3041; +exports.ER_BOOST_GEOMETRY_SELF_INTERSECTION_POINT_EXCEPTION = 3042; +exports.ER_BOOST_GEOMETRY_UNKNOWN_EXCEPTION = 3043; +exports.ER_STD_BAD_ALLOC_ERROR = 3044; +exports.ER_STD_DOMAIN_ERROR = 3045; +exports.ER_STD_LENGTH_ERROR = 3046; +exports.ER_STD_INVALID_ARGUMENT = 3047; +exports.ER_STD_OUT_OF_RANGE_ERROR = 3048; +exports.ER_STD_OVERFLOW_ERROR = 3049; +exports.ER_STD_RANGE_ERROR = 3050; +exports.ER_STD_UNDERFLOW_ERROR = 3051; +exports.ER_STD_LOGIC_ERROR = 3052; +exports.ER_STD_RUNTIME_ERROR = 3053; +exports.ER_STD_UNKNOWN_EXCEPTION = 3054; +exports.ER_GIS_DATA_WRONG_ENDIANESS = 3055; +exports.ER_CHANGE_MASTER_PASSWORD_LENGTH = 3056; +exports.ER_USER_LOCK_WRONG_NAME = 3057; +exports.ER_USER_LOCK_DEADLOCK = 3058; +exports.ER_REPLACE_INACCESSIBLE_ROWS = 3059; +exports.ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_GIS = 3060; +exports.ER_ILLEGAL_USER_VAR = 3061; +exports.ER_GTID_MODE_OFF = 3062; +exports.ER_UNSUPPORTED_BY_REPLICATION_THREAD = 3063; +exports.ER_INCORRECT_TYPE = 3064; +exports.ER_FIELD_IN_ORDER_NOT_SELECT = 3065; +exports.ER_AGGREGATE_IN_ORDER_NOT_SELECT = 3066; +exports.ER_INVALID_RPL_WILD_TABLE_FILTER_PATTERN = 3067; +exports.ER_NET_OK_PACKET_TOO_LARGE = 3068; +exports.ER_INVALID_JSON_DATA = 3069; +exports.ER_INVALID_GEOJSON_MISSING_MEMBER = 3070; +exports.ER_INVALID_GEOJSON_WRONG_TYPE = 3071; +exports.ER_INVALID_GEOJSON_UNSPECIFIED = 3072; +exports.ER_DIMENSION_UNSUPPORTED = 3073; +exports.ER_SLAVE_CHANNEL_DOES_NOT_EXIST = 3074; +exports.ER_SLAVE_MULTIPLE_CHANNELS_HOST_PORT = 3075; +exports.ER_SLAVE_CHANNEL_NAME_INVALID_OR_TOO_LONG = 3076; +exports.ER_SLAVE_NEW_CHANNEL_WRONG_REPOSITORY = 3077; +exports.ER_SLAVE_CHANNEL_DELETE = 3078; +exports.ER_SLAVE_MULTIPLE_CHANNELS_CMD = 3079; +exports.ER_SLAVE_MAX_CHANNELS_EXCEEDED = 3080; +exports.ER_SLAVE_CHANNEL_MUST_STOP = 3081; +exports.ER_SLAVE_CHANNEL_NOT_RUNNING = 3082; +exports.ER_SLAVE_CHANNEL_WAS_RUNNING = 3083; +exports.ER_SLAVE_CHANNEL_WAS_NOT_RUNNING = 3084; +exports.ER_SLAVE_CHANNEL_SQL_THREAD_MUST_STOP = 3085; +exports.ER_SLAVE_CHANNEL_SQL_SKIP_COUNTER = 3086; +exports.ER_WRONG_FIELD_WITH_GROUP_V2 = 3087; +exports.ER_MIX_OF_GROUP_FUNC_AND_FIELDS_V2 = 3088; +exports.ER_WARN_DEPRECATED_SYSVAR_UPDATE = 3089; +exports.ER_WARN_DEPRECATED_SQLMODE = 3090; +exports.ER_CANNOT_LOG_PARTIAL_DROP_DATABASE_WITH_GTID = 3091; +exports.ER_GROUP_REPLICATION_CONFIGURATION = 3092; +exports.ER_GROUP_REPLICATION_RUNNING = 3093; +exports.ER_GROUP_REPLICATION_APPLIER_INIT_ERROR = 3094; +exports.ER_GROUP_REPLICATION_STOP_APPLIER_THREAD_TIMEOUT = 3095; +exports.ER_GROUP_REPLICATION_COMMUNICATION_LAYER_SESSION_ERROR = 3096; +exports.ER_GROUP_REPLICATION_COMMUNICATION_LAYER_JOIN_ERROR = 3097; +exports.ER_BEFORE_DML_VALIDATION_ERROR = 3098; +exports.ER_PREVENTS_VARIABLE_WITHOUT_RBR = 3099; +exports.ER_RUN_HOOK_ERROR = 3100; +exports.ER_TRANSACTION_ROLLBACK_DURING_COMMIT = 3101; +exports.ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED = 3102; +exports.ER_UNSUPPORTED_ALTER_INPLACE_ON_VIRTUAL_COLUMN = 3103; +exports.ER_WRONG_FK_OPTION_FOR_GENERATED_COLUMN = 3104; +exports.ER_NON_DEFAULT_VALUE_FOR_GENERATED_COLUMN = 3105; +exports.ER_UNSUPPORTED_ACTION_ON_GENERATED_COLUMN = 3106; +exports.ER_GENERATED_COLUMN_NON_PRIOR = 3107; +exports.ER_DEPENDENT_BY_GENERATED_COLUMN = 3108; +exports.ER_GENERATED_COLUMN_REF_AUTO_INC = 3109; +exports.ER_FEATURE_NOT_AVAILABLE = 3110; +exports.ER_CANT_SET_GTID_MODE = 3111; +exports.ER_CANT_USE_AUTO_POSITION_WITH_GTID_MODE_OFF = 3112; +exports.ER_CANT_REPLICATE_ANONYMOUS_WITH_AUTO_POSITION = 3113; +exports.ER_CANT_REPLICATE_ANONYMOUS_WITH_GTID_MODE_ON = 3114; +exports.ER_CANT_REPLICATE_GTID_WITH_GTID_MODE_OFF = 3115; +exports.ER_CANT_SET_ENFORCE_GTID_CONSISTENCY_ON_WITH_ONGOING_GTID_VIOLATING_TRANSACTIONS = 3116; +exports.ER_SET_ENFORCE_GTID_CONSISTENCY_WARN_WITH_ONGOING_GTID_VIOLATING_TRANSACTIONS = 3117; +exports.ER_ACCOUNT_HAS_BEEN_LOCKED = 3118; +exports.ER_WRONG_TABLESPACE_NAME = 3119; +exports.ER_TABLESPACE_IS_NOT_EMPTY = 3120; +exports.ER_WRONG_FILE_NAME = 3121; +exports.ER_BOOST_GEOMETRY_INCONSISTENT_TURNS_EXCEPTION = 3122; +exports.ER_WARN_OPTIMIZER_HINT_SYNTAX_ERROR = 3123; +exports.ER_WARN_BAD_MAX_EXECUTION_TIME = 3124; +exports.ER_WARN_UNSUPPORTED_MAX_EXECUTION_TIME = 3125; +exports.ER_WARN_CONFLICTING_HINT = 3126; +exports.ER_WARN_UNKNOWN_QB_NAME = 3127; +exports.ER_UNRESOLVED_HINT_NAME = 3128; +exports.ER_WARN_ON_MODIFYING_GTID_EXECUTED_TABLE = 3129; +exports.ER_PLUGGABLE_PROTOCOL_COMMAND_NOT_SUPPORTED = 3130; +exports.ER_LOCKING_SERVICE_WRONG_NAME = 3131; +exports.ER_LOCKING_SERVICE_DEADLOCK = 3132; +exports.ER_LOCKING_SERVICE_TIMEOUT = 3133; +exports.ER_GIS_MAX_POINTS_IN_GEOMETRY_OVERFLOWED = 3134; +exports.ER_SQL_MODE_MERGED = 3135; +exports.ER_VTOKEN_PLUGIN_TOKEN_MISMATCH = 3136; +exports.ER_VTOKEN_PLUGIN_TOKEN_NOT_FOUND = 3137; +exports.ER_CANT_SET_VARIABLE_WHEN_OWNING_GTID = 3138; +exports.ER_SLAVE_CHANNEL_OPERATION_NOT_ALLOWED = 3139; +exports.ER_INVALID_JSON_TEXT = 3140; +exports.ER_INVALID_JSON_TEXT_IN_PARAM = 3141; +exports.ER_INVALID_JSON_BINARY_DATA = 3142; +exports.ER_INVALID_JSON_PATH = 3143; +exports.ER_INVALID_JSON_CHARSET = 3144; +exports.ER_INVALID_JSON_CHARSET_IN_FUNCTION = 3145; +exports.ER_INVALID_TYPE_FOR_JSON = 3146; +exports.ER_INVALID_CAST_TO_JSON = 3147; +exports.ER_INVALID_JSON_PATH_CHARSET = 3148; +exports.ER_INVALID_JSON_PATH_WILDCARD = 3149; +exports.ER_JSON_VALUE_TOO_BIG = 3150; +exports.ER_JSON_KEY_TOO_BIG = 3151; +exports.ER_JSON_USED_AS_KEY = 3152; +exports.ER_JSON_VACUOUS_PATH = 3153; +exports.ER_JSON_BAD_ONE_OR_ALL_ARG = 3154; +exports.ER_NUMERIC_JSON_VALUE_OUT_OF_RANGE = 3155; +exports.ER_INVALID_JSON_VALUE_FOR_CAST = 3156; +exports.ER_JSON_DOCUMENT_TOO_DEEP = 3157; +exports.ER_JSON_DOCUMENT_NULL_KEY = 3158; +exports.ER_SECURE_TRANSPORT_REQUIRED = 3159; +exports.ER_NO_SECURE_TRANSPORTS_CONFIGURED = 3160; +exports.ER_DISABLED_STORAGE_ENGINE = 3161; +exports.ER_USER_DOES_NOT_EXIST = 3162; +exports.ER_USER_ALREADY_EXISTS = 3163; +exports.ER_AUDIT_API_ABORT = 3164; +exports.ER_INVALID_JSON_PATH_ARRAY_CELL = 3165; +exports.ER_BUFPOOL_RESIZE_INPROGRESS = 3166; +exports.ER_FEATURE_DISABLED_SEE_DOC = 3167; +exports.ER_SERVER_ISNT_AVAILABLE = 3168; +exports.ER_SESSION_WAS_KILLED = 3169; +exports.ER_CAPACITY_EXCEEDED = 3170; +exports.ER_CAPACITY_EXCEEDED_IN_RANGE_OPTIMIZER = 3171; +exports.ER_TABLE_NEEDS_UPG_PART = 3172; +exports.ER_CANT_WAIT_FOR_EXECUTED_GTID_SET_WHILE_OWNING_A_GTID = 3173; +exports.ER_CANNOT_ADD_FOREIGN_BASE_COL_VIRTUAL = 3174; +exports.ER_CANNOT_CREATE_VIRTUAL_INDEX_CONSTRAINT = 3175; +exports.ER_ERROR_ON_MODIFYING_GTID_EXECUTED_TABLE = 3176; +exports.ER_LOCK_REFUSED_BY_ENGINE = 3177; +exports.ER_UNSUPPORTED_ALTER_ONLINE_ON_VIRTUAL_COLUMN = 3178; +exports.ER_MASTER_KEY_ROTATION_NOT_SUPPORTED_BY_SE = 3179; +exports.ER_MASTER_KEY_ROTATION_ERROR_BY_SE = 3180; +exports.ER_MASTER_KEY_ROTATION_BINLOG_FAILED = 3181; +exports.ER_MASTER_KEY_ROTATION_SE_UNAVAILABLE = 3182; +exports.ER_TABLESPACE_CANNOT_ENCRYPT = 3183; +exports.ER_INVALID_ENCRYPTION_OPTION = 3184; +exports.ER_CANNOT_FIND_KEY_IN_KEYRING = 3185; +exports.ER_CAPACITY_EXCEEDED_IN_PARSER = 3186; +exports.ER_UNSUPPORTED_ALTER_ENCRYPTION_INPLACE = 3187; +exports.ER_KEYRING_UDF_KEYRING_SERVICE_ERROR = 3188; +exports.ER_USER_COLUMN_OLD_LENGTH = 3189; +exports.ER_CANT_RESET_MASTER = 3190; +exports.ER_GROUP_REPLICATION_MAX_GROUP_SIZE = 3191; +exports.ER_CANNOT_ADD_FOREIGN_BASE_COL_STORED = 3192; +exports.ER_TABLE_REFERENCED = 3193; +exports.ER_PARTITION_ENGINE_DEPRECATED_FOR_TABLE = 3194; +exports.ER_WARN_USING_GEOMFROMWKB_TO_SET_SRID_ZERO = 3195; +exports.ER_WARN_USING_GEOMFROMWKB_TO_SET_SRID = 3196; +exports.ER_XA_RETRY = 3197; +exports.ER_KEYRING_AWS_UDF_AWS_KMS_ERROR = 3198; +exports.ER_BINLOG_UNSAFE_XA = 3199; +exports.ER_UDF_ERROR = 3200; +exports.ER_KEYRING_MIGRATION_FAILURE = 3201; +exports.ER_KEYRING_ACCESS_DENIED_ERROR = 3202; +exports.ER_KEYRING_MIGRATION_STATUS = 3203; +exports.ER_PLUGIN_FAILED_TO_OPEN_TABLES = 3204; +exports.ER_PLUGIN_FAILED_TO_OPEN_TABLE = 3205; +exports.ER_AUDIT_LOG_NO_KEYRING_PLUGIN_INSTALLED = 3206; +exports.ER_AUDIT_LOG_ENCRYPTION_PASSWORD_HAS_NOT_BEEN_SET = 3207; +exports.ER_AUDIT_LOG_COULD_NOT_CREATE_AES_KEY = 3208; +exports.ER_AUDIT_LOG_ENCRYPTION_PASSWORD_CANNOT_BE_FETCHED = 3209; +exports.ER_AUDIT_LOG_JSON_FILTERING_NOT_ENABLED = 3210; +exports.ER_AUDIT_LOG_UDF_INSUFFICIENT_PRIVILEGE = 3211; +exports.ER_AUDIT_LOG_SUPER_PRIVILEGE_REQUIRED = 3212; +exports.ER_COULD_NOT_REINITIALIZE_AUDIT_LOG_FILTERS = 3213; +exports.ER_AUDIT_LOG_UDF_INVALID_ARGUMENT_TYPE = 3214; +exports.ER_AUDIT_LOG_UDF_INVALID_ARGUMENT_COUNT = 3215; +exports.ER_AUDIT_LOG_HAS_NOT_BEEN_INSTALLED = 3216; +exports.ER_AUDIT_LOG_UDF_READ_INVALID_MAX_ARRAY_LENGTH_ARG_TYPE = 3217; +exports.ER_AUDIT_LOG_UDF_READ_INVALID_MAX_ARRAY_LENGTH_ARG_VALUE = 3218; +exports.ER_AUDIT_LOG_JSON_FILTER_PARSING_ERROR = 3219; +exports.ER_AUDIT_LOG_JSON_FILTER_NAME_CANNOT_BE_EMPTY = 3220; +exports.ER_AUDIT_LOG_JSON_USER_NAME_CANNOT_BE_EMPTY = 3221; +exports.ER_AUDIT_LOG_JSON_FILTER_DOES_NOT_EXISTS = 3222; +exports.ER_AUDIT_LOG_USER_FIRST_CHARACTER_MUST_BE_ALPHANUMERIC = 3223; +exports.ER_AUDIT_LOG_USER_NAME_INVALID_CHARACTER = 3224; +exports.ER_AUDIT_LOG_HOST_NAME_INVALID_CHARACTER = 3225; +exports.WARN_DEPRECATED_MAXDB_SQL_MODE_FOR_TIMESTAMP = 3226; +exports.ER_XA_REPLICATION_FILTERS = 3227; +exports.ER_CANT_OPEN_ERROR_LOG = 3228; +exports.ER_GROUPING_ON_TIMESTAMP_IN_DST = 3229; +exports.ER_CANT_START_SERVER_NAMED_PIPE = 3230; // Lookup-by-number table exports[1] = 'EE_CANTCREATEFILE'; @@ -2201,198 +2240,237 @@ exports[1882] = 'ER_AES_INVALID_IV'; exports[1883] = 'ER_PLUGIN_CANNOT_BE_UNINSTALLED'; exports[1884] = 'ER_GTID_UNSAFE_BINLOG_SPLITTABLE_STATEMENT_AND_GTID_GROUP'; exports[1885] = 'ER_SLAVE_HAS_MORE_GTIDS_THAN_MASTER'; -exports[1886] = 'ER_FILE_CORRUPT'; -exports[1887] = 'ER_ERROR_ON_MASTER'; -exports[1888] = 'ER_INCONSISTENT_ERROR'; -exports[1889] = 'ER_STORAGE_ENGINE_NOT_LOADED'; -exports[1890] = 'ER_GET_STACKED_DA_WITHOUT_ACTIVE_HANDLER'; -exports[1891] = 'ER_WARN_LEGACY_SYNTAX_CONVERTED'; -exports[1892] = 'ER_BINLOG_UNSAFE_FULLTEXT_PLUGIN'; -exports[1893] = 'ER_CANNOT_DISCARD_TEMPORARY_TABLE'; -exports[1894] = 'ER_FK_DEPTH_EXCEEDED'; -exports[1895] = 'ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE_V2'; -exports[1896] = 'ER_WARN_TRIGGER_DOESNT_HAVE_CREATED'; -exports[1897] = 'ER_REFERENCED_TRG_DOES_NOT_EXIST'; -exports[1898] = 'ER_EXPLAIN_NOT_SUPPORTED'; -exports[1899] = 'ER_INVALID_FIELD_SIZE'; -exports[1900] = 'ER_MISSING_HA_CREATE_OPTION'; -exports[1901] = 'ER_ENGINE_OUT_OF_MEMORY'; -exports[1902] = 'ER_PASSWORD_EXPIRE_ANONYMOUS_USER'; -exports[1903] = 'ER_SLAVE_SQL_THREAD_MUST_STOP'; -exports[1904] = 'ER_NO_FT_MATERIALIZED_SUBQUERY'; -exports[1905] = 'ER_INNODB_UNDO_LOG_FULL'; -exports[1906] = 'ER_INVALID_ARGUMENT_FOR_LOGARITHM'; -exports[1907] = 'ER_SLAVE_CHANNEL_IO_THREAD_MUST_STOP'; -exports[1908] = 'ER_WARN_OPEN_TEMP_TABLES_MUST_BE_ZERO'; -exports[1909] = 'ER_WARN_ONLY_MASTER_LOG_FILE_NO_POS'; -exports[1910] = 'ER_QUERY_TIMEOUT'; -exports[1911] = 'ER_NON_RO_SELECT_DISABLE_TIMER'; -exports[1912] = 'ER_DUP_LIST_ENTRY'; -exports[1913] = 'ER_SQL_MODE_NO_EFFECT'; -exports[1914] = 'ER_AGGREGATE_ORDER_FOR_UNION'; -exports[1915] = 'ER_AGGREGATE_ORDER_NON_AGG_QUERY'; -exports[1916] = 'ER_SLAVE_WORKER_STOPPED_PREVIOUS_THD_ERROR'; -exports[1917] = 'ER_DONT_SUPPORT_SLAVE_PRESERVE_COMMIT_ORDER'; -exports[1918] = 'ER_SERVER_OFFLINE_MODE'; -exports[1919] = 'ER_GIS_DIFFERENT_SRIDS'; -exports[1920] = 'ER_GIS_UNSUPPORTED_ARGUMENT'; -exports[1921] = 'ER_GIS_UNKNOWN_ERROR'; -exports[1922] = 'ER_GIS_UNKNOWN_EXCEPTION'; -exports[1923] = 'ER_GIS_INVALID_DATA'; -exports[1924] = 'ER_BOOST_GEOMETRY_EMPTY_INPUT_EXCEPTION'; -exports[1925] = 'ER_BOOST_GEOMETRY_CENTROID_EXCEPTION'; -exports[1926] = 'ER_BOOST_GEOMETRY_OVERLAY_INVALID_INPUT_EXCEPTION'; -exports[1927] = 'ER_BOOST_GEOMETRY_TURN_INFO_EXCEPTION'; -exports[1928] = 'ER_BOOST_GEOMETRY_SELF_INTERSECTION_POINT_EXCEPTION'; -exports[1929] = 'ER_BOOST_GEOMETRY_UNKNOWN_EXCEPTION'; -exports[1930] = 'ER_STD_BAD_ALLOC_ERROR'; -exports[1931] = 'ER_STD_DOMAIN_ERROR'; -exports[1932] = 'ER_STD_LENGTH_ERROR'; -exports[1933] = 'ER_STD_INVALID_ARGUMENT'; -exports[1934] = 'ER_STD_OUT_OF_RANGE_ERROR'; -exports[1935] = 'ER_STD_OVERFLOW_ERROR'; -exports[1936] = 'ER_STD_RANGE_ERROR'; -exports[1937] = 'ER_STD_UNDERFLOW_ERROR'; -exports[1938] = 'ER_STD_LOGIC_ERROR'; -exports[1939] = 'ER_STD_RUNTIME_ERROR'; -exports[1940] = 'ER_STD_UNKNOWN_EXCEPTION'; -exports[1941] = 'ER_GIS_DATA_WRONG_ENDIANESS'; -exports[1942] = 'ER_CHANGE_MASTER_PASSWORD_LENGTH'; -exports[1943] = 'ER_USER_LOCK_WRONG_NAME'; -exports[1944] = 'ER_USER_LOCK_DEADLOCK'; -exports[1945] = 'ER_REPLACE_INACCESSIBLE_ROWS'; -exports[1946] = 'ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_GIS'; -exports[1947] = 'ER_ILLEGAL_USER_VAR'; -exports[1948] = 'ER_GTID_MODE_OFF'; -exports[1949] = 'ER_UNSUPPORTED_BY_REPLICATION_THREAD'; -exports[1950] = 'ER_INCORRECT_TYPE'; -exports[1951] = 'ER_FIELD_IN_ORDER_NOT_SELECT'; -exports[1952] = 'ER_AGGREGATE_IN_ORDER_NOT_SELECT'; -exports[1953] = 'ER_INVALID_RPL_WILD_TABLE_FILTER_PATTERN'; -exports[1954] = 'ER_NET_OK_PACKET_TOO_LARGE'; -exports[1955] = 'ER_INVALID_JSON_DATA'; -exports[1956] = 'ER_INVALID_GEOJSON_MISSING_MEMBER'; -exports[1957] = 'ER_INVALID_GEOJSON_WRONG_TYPE'; -exports[1958] = 'ER_INVALID_GEOJSON_UNSPECIFIED'; -exports[1959] = 'ER_DIMENSION_UNSUPPORTED'; -exports[1960] = 'ER_SLAVE_CHANNEL_DOES_NOT_EXIST'; -exports[1961] = 'ER_SLAVE_MULTIPLE_CHANNELS_HOST_PORT'; -exports[1962] = 'ER_SLAVE_CHANNEL_NAME_INVALID_OR_TOO_LONG'; -exports[1963] = 'ER_SLAVE_NEW_CHANNEL_WRONG_REPOSITORY'; -exports[1964] = 'ER_SLAVE_CHANNEL_DELETE'; -exports[1965] = 'ER_SLAVE_MULTIPLE_CHANNELS_CMD'; -exports[1966] = 'ER_SLAVE_MAX_CHANNELS_EXCEEDED'; -exports[1967] = 'ER_SLAVE_CHANNEL_MUST_STOP'; -exports[1968] = 'ER_SLAVE_CHANNEL_NOT_RUNNING'; -exports[1969] = 'ER_SLAVE_CHANNEL_WAS_RUNNING'; -exports[1970] = 'ER_SLAVE_CHANNEL_WAS_NOT_RUNNING'; -exports[1971] = 'ER_SLAVE_CHANNEL_SQL_THREAD_MUST_STOP'; -exports[1972] = 'ER_SLAVE_CHANNEL_SQL_SKIP_COUNTER'; -exports[1973] = 'ER_WRONG_FIELD_WITH_GROUP_V2'; -exports[1974] = 'ER_MIX_OF_GROUP_FUNC_AND_FIELDS_V2'; -exports[1975] = 'ER_WARN_DEPRECATED_SYSVAR_UPDATE'; -exports[1976] = 'ER_WARN_DEPRECATED_SQLMODE'; -exports[1977] = 'ER_CANNOT_LOG_PARTIAL_DROP_DATABASE_WITH_GTID'; -exports[1978] = 'ER_GROUP_REPLICATION_CONFIGURATION'; -exports[1979] = 'ER_GROUP_REPLICATION_RUNNING'; -exports[1980] = 'ER_GROUP_REPLICATION_APPLIER_INIT_ERROR'; -exports[1981] = 'ER_GROUP_REPLICATION_STOP_APPLIER_THREAD_TIMEOUT'; -exports[1982] = 'ER_GROUP_REPLICATION_COMMUNICATION_LAYER_SESSION_ERROR'; -exports[1983] = 'ER_GROUP_REPLICATION_COMMUNICATION_LAYER_JOIN_ERROR'; -exports[1984] = 'ER_BEFORE_DML_VALIDATION_ERROR'; -exports[1985] = 'ER_PREVENTS_VARIABLE_WITHOUT_RBR'; -exports[1986] = 'ER_RUN_HOOK_ERROR'; -exports[1987] = 'ER_TRANSACTION_ROLLBACK_DURING_COMMIT'; -exports[1988] = 'ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED'; -exports[1989] = 'ER_UNSUPPORTED_ALTER_INPLACE_ON_VIRTUAL_COLUMN'; -exports[1990] = 'ER_WRONG_FK_OPTION_FOR_GENERATED_COLUMN'; -exports[1991] = 'ER_NON_DEFAULT_VALUE_FOR_GENERATED_COLUMN'; -exports[1992] = 'ER_UNSUPPORTED_ACTION_ON_GENERATED_COLUMN'; -exports[1993] = 'ER_GENERATED_COLUMN_NON_PRIOR'; -exports[1994] = 'ER_DEPENDENT_BY_GENERATED_COLUMN'; -exports[1995] = 'ER_GENERATED_COLUMN_REF_AUTO_INC'; -exports[1996] = 'ER_FEATURE_NOT_AVAILABLE'; -exports[1997] = 'ER_CANT_SET_GTID_MODE'; -exports[1998] = 'ER_CANT_USE_AUTO_POSITION_WITH_GTID_MODE_OFF'; -exports[1999] = 'ER_CANT_REPLICATE_ANONYMOUS_WITH_AUTO_POSITION'; -exports[2000] = 'ER_CANT_REPLICATE_ANONYMOUS_WITH_GTID_MODE_ON'; -exports[2001] = 'ER_CANT_REPLICATE_GTID_WITH_GTID_MODE_OFF'; -exports[2002] = 'ER_CANT_SET_ENFORCE_GTID_CONSISTENCY_ON_WITH_ONGOING_GTID_VIOLATING_TRANSACTIONS'; -exports[2003] = 'ER_SET_ENFORCE_GTID_CONSISTENCY_WARN_WITH_ONGOING_GTID_VIOLATING_TRANSACTIONS'; -exports[2004] = 'ER_ACCOUNT_HAS_BEEN_LOCKED'; -exports[2005] = 'ER_WRONG_TABLESPACE_NAME'; -exports[2006] = 'ER_TABLESPACE_IS_NOT_EMPTY'; -exports[2007] = 'ER_WRONG_FILE_NAME'; -exports[2008] = 'ER_BOOST_GEOMETRY_INCONSISTENT_TURNS_EXCEPTION'; -exports[2009] = 'ER_WARN_OPTIMIZER_HINT_SYNTAX_ERROR'; -exports[2010] = 'ER_WARN_BAD_MAX_EXECUTION_TIME'; -exports[2011] = 'ER_WARN_UNSUPPORTED_MAX_EXECUTION_TIME'; -exports[2012] = 'ER_WARN_CONFLICTING_HINT'; -exports[2013] = 'ER_WARN_UNKNOWN_QB_NAME'; -exports[2014] = 'ER_UNRESOLVED_HINT_NAME'; -exports[2015] = 'ER_WARN_ON_MODIFYING_GTID_EXECUTED_TABLE'; -exports[2016] = 'ER_PLUGGABLE_PROTOCOL_COMMAND_NOT_SUPPORTED'; -exports[2017] = 'ER_LOCKING_SERVICE_WRONG_NAME'; -exports[2018] = 'ER_LOCKING_SERVICE_DEADLOCK'; -exports[2019] = 'ER_LOCKING_SERVICE_TIMEOUT'; -exports[2020] = 'ER_GIS_MAX_POINTS_IN_GEOMETRY_OVERFLOWED'; -exports[2021] = 'ER_SQL_MODE_MERGED'; -exports[2022] = 'ER_VTOKEN_PLUGIN_TOKEN_MISMATCH'; -exports[2023] = 'ER_VTOKEN_PLUGIN_TOKEN_NOT_FOUND'; -exports[2024] = 'ER_CANT_SET_VARIABLE_WHEN_OWNING_GTID'; -exports[2025] = 'ER_SLAVE_CHANNEL_OPERATION_NOT_ALLOWED'; -exports[2026] = 'ER_INVALID_JSON_TEXT'; -exports[2027] = 'ER_INVALID_JSON_TEXT_IN_PARAM'; -exports[2028] = 'ER_INVALID_JSON_BINARY_DATA'; -exports[2029] = 'ER_INVALID_JSON_PATH'; -exports[2030] = 'ER_INVALID_JSON_CHARSET'; -exports[2031] = 'ER_INVALID_JSON_CHARSET_IN_FUNCTION'; -exports[2032] = 'ER_INVALID_TYPE_FOR_JSON'; -exports[2033] = 'ER_INVALID_CAST_TO_JSON'; -exports[2034] = 'ER_INVALID_JSON_PATH_CHARSET'; -exports[2035] = 'ER_INVALID_JSON_PATH_WILDCARD'; -exports[2036] = 'ER_JSON_VALUE_TOO_BIG'; -exports[2037] = 'ER_JSON_KEY_TOO_BIG'; -exports[2038] = 'ER_JSON_USED_AS_KEY'; -exports[2039] = 'ER_JSON_VACUOUS_PATH'; -exports[2040] = 'ER_JSON_BAD_ONE_OR_ALL_ARG'; -exports[2041] = 'ER_NUMERIC_JSON_VALUE_OUT_OF_RANGE'; -exports[2042] = 'ER_INVALID_JSON_VALUE_FOR_CAST'; -exports[2043] = 'ER_JSON_DOCUMENT_TOO_DEEP'; -exports[2044] = 'ER_JSON_DOCUMENT_NULL_KEY'; -exports[2045] = 'ER_SECURE_TRANSPORT_REQUIRED'; -exports[2046] = 'ER_NO_SECURE_TRANSPORTS_CONFIGURED'; -exports[2047] = 'ER_DISABLED_STORAGE_ENGINE'; -exports[2048] = 'ER_USER_DOES_NOT_EXIST'; -exports[2049] = 'ER_USER_ALREADY_EXISTS'; -exports[2050] = 'ER_AUDIT_API_ABORT'; -exports[2051] = 'ER_INVALID_JSON_PATH_ARRAY_CELL'; -exports[2052] = 'ER_BUFPOOL_RESIZE_INPROGRESS'; -exports[2053] = 'ER_FEATURE_DISABLED_SEE_DOC'; -exports[2054] = 'ER_SERVER_ISNT_AVAILABLE'; -exports[2055] = 'ER_SESSION_WAS_KILLED'; -exports[2056] = 'ER_CAPACITY_EXCEEDED'; -exports[2057] = 'ER_CAPACITY_EXCEEDED_IN_RANGE_OPTIMIZER'; -exports[2058] = 'ER_TABLE_NEEDS_UPG_PART'; -exports[2059] = 'ER_CANT_WAIT_FOR_EXECUTED_GTID_SET_WHILE_OWNING_A_GTID'; -exports[2060] = 'ER_CANNOT_ADD_FOREIGN_BASE_COL_VIRTUAL'; -exports[2061] = 'ER_CANNOT_CREATE_VIRTUAL_INDEX_CONSTRAINT'; -exports[2062] = 'ER_ERROR_ON_MODIFYING_GTID_EXECUTED_TABLE'; -exports[2063] = 'ER_LOCK_REFUSED_BY_ENGINE'; -exports[2064] = 'ER_UNSUPPORTED_ALTER_ONLINE_ON_VIRTUAL_COLUMN'; -exports[2065] = 'ER_MASTER_KEY_ROTATION_NOT_SUPPORTED_BY_SE'; -exports[2066] = 'ER_MASTER_KEY_ROTATION_ERROR_BY_SE'; -exports[2067] = 'ER_MASTER_KEY_ROTATION_BINLOG_FAILED'; -exports[2068] = 'ER_MASTER_KEY_ROTATION_SE_UNAVAILABLE'; -exports[2069] = 'ER_TABLESPACE_CANNOT_ENCRYPT'; -exports[2070] = 'ER_INVALID_ENCRYPTION_OPTION'; -exports[2071] = 'ER_CANNOT_FIND_KEY_IN_KEYRING'; -exports[2072] = 'ER_CAPACITY_EXCEEDED_IN_PARSER'; -exports[2073] = 'ER_UNSUPPORTED_ALTER_ENCRYPTION_INPLACE'; -exports[2074] = 'ER_KEYRING_UDF_KEYRING_SERVICE_ERROR'; -exports[2075] = 'ER_USER_COLUMN_OLD_LENGTH'; -exports[2076] = 'ER_CANT_RESET_MASTER'; -exports[2077] = 'ER_GROUP_REPLICATION_MAX_GROUP_SIZE'; -exports[2078] = 'ER_CANNOT_ADD_FOREIGN_BASE_COL_STORED'; -exports[2079] = 'ER_TABLE_REFERENCED'; -exports[2080] = 'ER_PARTITION_ENGINE_DEPRECATED_FOR_TABLE'; +exports[1886] = 'ER_MISSING_KEY'; +exports[1887] = 'WARN_NAMED_PIPE_ACCESS_EVERYONE'; +exports[1888] = 'ER_FOUND_MISSING_GTIDS'; +exports[3000] = 'ER_FILE_CORRUPT'; +exports[3001] = 'ER_ERROR_ON_MASTER'; +exports[3002] = 'ER_INCONSISTENT_ERROR'; +exports[3003] = 'ER_STORAGE_ENGINE_NOT_LOADED'; +exports[3004] = 'ER_GET_STACKED_DA_WITHOUT_ACTIVE_HANDLER'; +exports[3005] = 'ER_WARN_LEGACY_SYNTAX_CONVERTED'; +exports[3006] = 'ER_BINLOG_UNSAFE_FULLTEXT_PLUGIN'; +exports[3007] = 'ER_CANNOT_DISCARD_TEMPORARY_TABLE'; +exports[3008] = 'ER_FK_DEPTH_EXCEEDED'; +exports[3009] = 'ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE_V2'; +exports[3010] = 'ER_WARN_TRIGGER_DOESNT_HAVE_CREATED'; +exports[3011] = 'ER_REFERENCED_TRG_DOES_NOT_EXIST'; +exports[3012] = 'ER_EXPLAIN_NOT_SUPPORTED'; +exports[3013] = 'ER_INVALID_FIELD_SIZE'; +exports[3014] = 'ER_MISSING_HA_CREATE_OPTION'; +exports[3015] = 'ER_ENGINE_OUT_OF_MEMORY'; +exports[3016] = 'ER_PASSWORD_EXPIRE_ANONYMOUS_USER'; +exports[3017] = 'ER_SLAVE_SQL_THREAD_MUST_STOP'; +exports[3018] = 'ER_NO_FT_MATERIALIZED_SUBQUERY'; +exports[3019] = 'ER_INNODB_UNDO_LOG_FULL'; +exports[3020] = 'ER_INVALID_ARGUMENT_FOR_LOGARITHM'; +exports[3021] = 'ER_SLAVE_CHANNEL_IO_THREAD_MUST_STOP'; +exports[3022] = 'ER_WARN_OPEN_TEMP_TABLES_MUST_BE_ZERO'; +exports[3023] = 'ER_WARN_ONLY_MASTER_LOG_FILE_NO_POS'; +exports[3024] = 'ER_QUERY_TIMEOUT'; +exports[3025] = 'ER_NON_RO_SELECT_DISABLE_TIMER'; +exports[3026] = 'ER_DUP_LIST_ENTRY'; +exports[3027] = 'ER_SQL_MODE_NO_EFFECT'; +exports[3028] = 'ER_AGGREGATE_ORDER_FOR_UNION'; +exports[3029] = 'ER_AGGREGATE_ORDER_NON_AGG_QUERY'; +exports[3030] = 'ER_SLAVE_WORKER_STOPPED_PREVIOUS_THD_ERROR'; +exports[3031] = 'ER_DONT_SUPPORT_SLAVE_PRESERVE_COMMIT_ORDER'; +exports[3032] = 'ER_SERVER_OFFLINE_MODE'; +exports[3033] = 'ER_GIS_DIFFERENT_SRIDS'; +exports[3034] = 'ER_GIS_UNSUPPORTED_ARGUMENT'; +exports[3035] = 'ER_GIS_UNKNOWN_ERROR'; +exports[3036] = 'ER_GIS_UNKNOWN_EXCEPTION'; +exports[3037] = 'ER_GIS_INVALID_DATA'; +exports[3038] = 'ER_BOOST_GEOMETRY_EMPTY_INPUT_EXCEPTION'; +exports[3039] = 'ER_BOOST_GEOMETRY_CENTROID_EXCEPTION'; +exports[3040] = 'ER_BOOST_GEOMETRY_OVERLAY_INVALID_INPUT_EXCEPTION'; +exports[3041] = 'ER_BOOST_GEOMETRY_TURN_INFO_EXCEPTION'; +exports[3042] = 'ER_BOOST_GEOMETRY_SELF_INTERSECTION_POINT_EXCEPTION'; +exports[3043] = 'ER_BOOST_GEOMETRY_UNKNOWN_EXCEPTION'; +exports[3044] = 'ER_STD_BAD_ALLOC_ERROR'; +exports[3045] = 'ER_STD_DOMAIN_ERROR'; +exports[3046] = 'ER_STD_LENGTH_ERROR'; +exports[3047] = 'ER_STD_INVALID_ARGUMENT'; +exports[3048] = 'ER_STD_OUT_OF_RANGE_ERROR'; +exports[3049] = 'ER_STD_OVERFLOW_ERROR'; +exports[3050] = 'ER_STD_RANGE_ERROR'; +exports[3051] = 'ER_STD_UNDERFLOW_ERROR'; +exports[3052] = 'ER_STD_LOGIC_ERROR'; +exports[3053] = 'ER_STD_RUNTIME_ERROR'; +exports[3054] = 'ER_STD_UNKNOWN_EXCEPTION'; +exports[3055] = 'ER_GIS_DATA_WRONG_ENDIANESS'; +exports[3056] = 'ER_CHANGE_MASTER_PASSWORD_LENGTH'; +exports[3057] = 'ER_USER_LOCK_WRONG_NAME'; +exports[3058] = 'ER_USER_LOCK_DEADLOCK'; +exports[3059] = 'ER_REPLACE_INACCESSIBLE_ROWS'; +exports[3060] = 'ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_GIS'; +exports[3061] = 'ER_ILLEGAL_USER_VAR'; +exports[3062] = 'ER_GTID_MODE_OFF'; +exports[3063] = 'ER_UNSUPPORTED_BY_REPLICATION_THREAD'; +exports[3064] = 'ER_INCORRECT_TYPE'; +exports[3065] = 'ER_FIELD_IN_ORDER_NOT_SELECT'; +exports[3066] = 'ER_AGGREGATE_IN_ORDER_NOT_SELECT'; +exports[3067] = 'ER_INVALID_RPL_WILD_TABLE_FILTER_PATTERN'; +exports[3068] = 'ER_NET_OK_PACKET_TOO_LARGE'; +exports[3069] = 'ER_INVALID_JSON_DATA'; +exports[3070] = 'ER_INVALID_GEOJSON_MISSING_MEMBER'; +exports[3071] = 'ER_INVALID_GEOJSON_WRONG_TYPE'; +exports[3072] = 'ER_INVALID_GEOJSON_UNSPECIFIED'; +exports[3073] = 'ER_DIMENSION_UNSUPPORTED'; +exports[3074] = 'ER_SLAVE_CHANNEL_DOES_NOT_EXIST'; +exports[3075] = 'ER_SLAVE_MULTIPLE_CHANNELS_HOST_PORT'; +exports[3076] = 'ER_SLAVE_CHANNEL_NAME_INVALID_OR_TOO_LONG'; +exports[3077] = 'ER_SLAVE_NEW_CHANNEL_WRONG_REPOSITORY'; +exports[3078] = 'ER_SLAVE_CHANNEL_DELETE'; +exports[3079] = 'ER_SLAVE_MULTIPLE_CHANNELS_CMD'; +exports[3080] = 'ER_SLAVE_MAX_CHANNELS_EXCEEDED'; +exports[3081] = 'ER_SLAVE_CHANNEL_MUST_STOP'; +exports[3082] = 'ER_SLAVE_CHANNEL_NOT_RUNNING'; +exports[3083] = 'ER_SLAVE_CHANNEL_WAS_RUNNING'; +exports[3084] = 'ER_SLAVE_CHANNEL_WAS_NOT_RUNNING'; +exports[3085] = 'ER_SLAVE_CHANNEL_SQL_THREAD_MUST_STOP'; +exports[3086] = 'ER_SLAVE_CHANNEL_SQL_SKIP_COUNTER'; +exports[3087] = 'ER_WRONG_FIELD_WITH_GROUP_V2'; +exports[3088] = 'ER_MIX_OF_GROUP_FUNC_AND_FIELDS_V2'; +exports[3089] = 'ER_WARN_DEPRECATED_SYSVAR_UPDATE'; +exports[3090] = 'ER_WARN_DEPRECATED_SQLMODE'; +exports[3091] = 'ER_CANNOT_LOG_PARTIAL_DROP_DATABASE_WITH_GTID'; +exports[3092] = 'ER_GROUP_REPLICATION_CONFIGURATION'; +exports[3093] = 'ER_GROUP_REPLICATION_RUNNING'; +exports[3094] = 'ER_GROUP_REPLICATION_APPLIER_INIT_ERROR'; +exports[3095] = 'ER_GROUP_REPLICATION_STOP_APPLIER_THREAD_TIMEOUT'; +exports[3096] = 'ER_GROUP_REPLICATION_COMMUNICATION_LAYER_SESSION_ERROR'; +exports[3097] = 'ER_GROUP_REPLICATION_COMMUNICATION_LAYER_JOIN_ERROR'; +exports[3098] = 'ER_BEFORE_DML_VALIDATION_ERROR'; +exports[3099] = 'ER_PREVENTS_VARIABLE_WITHOUT_RBR'; +exports[3100] = 'ER_RUN_HOOK_ERROR'; +exports[3101] = 'ER_TRANSACTION_ROLLBACK_DURING_COMMIT'; +exports[3102] = 'ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED'; +exports[3103] = 'ER_UNSUPPORTED_ALTER_INPLACE_ON_VIRTUAL_COLUMN'; +exports[3104] = 'ER_WRONG_FK_OPTION_FOR_GENERATED_COLUMN'; +exports[3105] = 'ER_NON_DEFAULT_VALUE_FOR_GENERATED_COLUMN'; +exports[3106] = 'ER_UNSUPPORTED_ACTION_ON_GENERATED_COLUMN'; +exports[3107] = 'ER_GENERATED_COLUMN_NON_PRIOR'; +exports[3108] = 'ER_DEPENDENT_BY_GENERATED_COLUMN'; +exports[3109] = 'ER_GENERATED_COLUMN_REF_AUTO_INC'; +exports[3110] = 'ER_FEATURE_NOT_AVAILABLE'; +exports[3111] = 'ER_CANT_SET_GTID_MODE'; +exports[3112] = 'ER_CANT_USE_AUTO_POSITION_WITH_GTID_MODE_OFF'; +exports[3113] = 'ER_CANT_REPLICATE_ANONYMOUS_WITH_AUTO_POSITION'; +exports[3114] = 'ER_CANT_REPLICATE_ANONYMOUS_WITH_GTID_MODE_ON'; +exports[3115] = 'ER_CANT_REPLICATE_GTID_WITH_GTID_MODE_OFF'; +exports[3116] = 'ER_CANT_SET_ENFORCE_GTID_CONSISTENCY_ON_WITH_ONGOING_GTID_VIOLATING_TRANSACTIONS'; +exports[3117] = 'ER_SET_ENFORCE_GTID_CONSISTENCY_WARN_WITH_ONGOING_GTID_VIOLATING_TRANSACTIONS'; +exports[3118] = 'ER_ACCOUNT_HAS_BEEN_LOCKED'; +exports[3119] = 'ER_WRONG_TABLESPACE_NAME'; +exports[3120] = 'ER_TABLESPACE_IS_NOT_EMPTY'; +exports[3121] = 'ER_WRONG_FILE_NAME'; +exports[3122] = 'ER_BOOST_GEOMETRY_INCONSISTENT_TURNS_EXCEPTION'; +exports[3123] = 'ER_WARN_OPTIMIZER_HINT_SYNTAX_ERROR'; +exports[3124] = 'ER_WARN_BAD_MAX_EXECUTION_TIME'; +exports[3125] = 'ER_WARN_UNSUPPORTED_MAX_EXECUTION_TIME'; +exports[3126] = 'ER_WARN_CONFLICTING_HINT'; +exports[3127] = 'ER_WARN_UNKNOWN_QB_NAME'; +exports[3128] = 'ER_UNRESOLVED_HINT_NAME'; +exports[3129] = 'ER_WARN_ON_MODIFYING_GTID_EXECUTED_TABLE'; +exports[3130] = 'ER_PLUGGABLE_PROTOCOL_COMMAND_NOT_SUPPORTED'; +exports[3131] = 'ER_LOCKING_SERVICE_WRONG_NAME'; +exports[3132] = 'ER_LOCKING_SERVICE_DEADLOCK'; +exports[3133] = 'ER_LOCKING_SERVICE_TIMEOUT'; +exports[3134] = 'ER_GIS_MAX_POINTS_IN_GEOMETRY_OVERFLOWED'; +exports[3135] = 'ER_SQL_MODE_MERGED'; +exports[3136] = 'ER_VTOKEN_PLUGIN_TOKEN_MISMATCH'; +exports[3137] = 'ER_VTOKEN_PLUGIN_TOKEN_NOT_FOUND'; +exports[3138] = 'ER_CANT_SET_VARIABLE_WHEN_OWNING_GTID'; +exports[3139] = 'ER_SLAVE_CHANNEL_OPERATION_NOT_ALLOWED'; +exports[3140] = 'ER_INVALID_JSON_TEXT'; +exports[3141] = 'ER_INVALID_JSON_TEXT_IN_PARAM'; +exports[3142] = 'ER_INVALID_JSON_BINARY_DATA'; +exports[3143] = 'ER_INVALID_JSON_PATH'; +exports[3144] = 'ER_INVALID_JSON_CHARSET'; +exports[3145] = 'ER_INVALID_JSON_CHARSET_IN_FUNCTION'; +exports[3146] = 'ER_INVALID_TYPE_FOR_JSON'; +exports[3147] = 'ER_INVALID_CAST_TO_JSON'; +exports[3148] = 'ER_INVALID_JSON_PATH_CHARSET'; +exports[3149] = 'ER_INVALID_JSON_PATH_WILDCARD'; +exports[3150] = 'ER_JSON_VALUE_TOO_BIG'; +exports[3151] = 'ER_JSON_KEY_TOO_BIG'; +exports[3152] = 'ER_JSON_USED_AS_KEY'; +exports[3153] = 'ER_JSON_VACUOUS_PATH'; +exports[3154] = 'ER_JSON_BAD_ONE_OR_ALL_ARG'; +exports[3155] = 'ER_NUMERIC_JSON_VALUE_OUT_OF_RANGE'; +exports[3156] = 'ER_INVALID_JSON_VALUE_FOR_CAST'; +exports[3157] = 'ER_JSON_DOCUMENT_TOO_DEEP'; +exports[3158] = 'ER_JSON_DOCUMENT_NULL_KEY'; +exports[3159] = 'ER_SECURE_TRANSPORT_REQUIRED'; +exports[3160] = 'ER_NO_SECURE_TRANSPORTS_CONFIGURED'; +exports[3161] = 'ER_DISABLED_STORAGE_ENGINE'; +exports[3162] = 'ER_USER_DOES_NOT_EXIST'; +exports[3163] = 'ER_USER_ALREADY_EXISTS'; +exports[3164] = 'ER_AUDIT_API_ABORT'; +exports[3165] = 'ER_INVALID_JSON_PATH_ARRAY_CELL'; +exports[3166] = 'ER_BUFPOOL_RESIZE_INPROGRESS'; +exports[3167] = 'ER_FEATURE_DISABLED_SEE_DOC'; +exports[3168] = 'ER_SERVER_ISNT_AVAILABLE'; +exports[3169] = 'ER_SESSION_WAS_KILLED'; +exports[3170] = 'ER_CAPACITY_EXCEEDED'; +exports[3171] = 'ER_CAPACITY_EXCEEDED_IN_RANGE_OPTIMIZER'; +exports[3172] = 'ER_TABLE_NEEDS_UPG_PART'; +exports[3173] = 'ER_CANT_WAIT_FOR_EXECUTED_GTID_SET_WHILE_OWNING_A_GTID'; +exports[3174] = 'ER_CANNOT_ADD_FOREIGN_BASE_COL_VIRTUAL'; +exports[3175] = 'ER_CANNOT_CREATE_VIRTUAL_INDEX_CONSTRAINT'; +exports[3176] = 'ER_ERROR_ON_MODIFYING_GTID_EXECUTED_TABLE'; +exports[3177] = 'ER_LOCK_REFUSED_BY_ENGINE'; +exports[3178] = 'ER_UNSUPPORTED_ALTER_ONLINE_ON_VIRTUAL_COLUMN'; +exports[3179] = 'ER_MASTER_KEY_ROTATION_NOT_SUPPORTED_BY_SE'; +exports[3180] = 'ER_MASTER_KEY_ROTATION_ERROR_BY_SE'; +exports[3181] = 'ER_MASTER_KEY_ROTATION_BINLOG_FAILED'; +exports[3182] = 'ER_MASTER_KEY_ROTATION_SE_UNAVAILABLE'; +exports[3183] = 'ER_TABLESPACE_CANNOT_ENCRYPT'; +exports[3184] = 'ER_INVALID_ENCRYPTION_OPTION'; +exports[3185] = 'ER_CANNOT_FIND_KEY_IN_KEYRING'; +exports[3186] = 'ER_CAPACITY_EXCEEDED_IN_PARSER'; +exports[3187] = 'ER_UNSUPPORTED_ALTER_ENCRYPTION_INPLACE'; +exports[3188] = 'ER_KEYRING_UDF_KEYRING_SERVICE_ERROR'; +exports[3189] = 'ER_USER_COLUMN_OLD_LENGTH'; +exports[3190] = 'ER_CANT_RESET_MASTER'; +exports[3191] = 'ER_GROUP_REPLICATION_MAX_GROUP_SIZE'; +exports[3192] = 'ER_CANNOT_ADD_FOREIGN_BASE_COL_STORED'; +exports[3193] = 'ER_TABLE_REFERENCED'; +exports[3194] = 'ER_PARTITION_ENGINE_DEPRECATED_FOR_TABLE'; +exports[3195] = 'ER_WARN_USING_GEOMFROMWKB_TO_SET_SRID_ZERO'; +exports[3196] = 'ER_WARN_USING_GEOMFROMWKB_TO_SET_SRID'; +exports[3197] = 'ER_XA_RETRY'; +exports[3198] = 'ER_KEYRING_AWS_UDF_AWS_KMS_ERROR'; +exports[3199] = 'ER_BINLOG_UNSAFE_XA'; +exports[3200] = 'ER_UDF_ERROR'; +exports[3201] = 'ER_KEYRING_MIGRATION_FAILURE'; +exports[3202] = 'ER_KEYRING_ACCESS_DENIED_ERROR'; +exports[3203] = 'ER_KEYRING_MIGRATION_STATUS'; +exports[3204] = 'ER_PLUGIN_FAILED_TO_OPEN_TABLES'; +exports[3205] = 'ER_PLUGIN_FAILED_TO_OPEN_TABLE'; +exports[3206] = 'ER_AUDIT_LOG_NO_KEYRING_PLUGIN_INSTALLED'; +exports[3207] = 'ER_AUDIT_LOG_ENCRYPTION_PASSWORD_HAS_NOT_BEEN_SET'; +exports[3208] = 'ER_AUDIT_LOG_COULD_NOT_CREATE_AES_KEY'; +exports[3209] = 'ER_AUDIT_LOG_ENCRYPTION_PASSWORD_CANNOT_BE_FETCHED'; +exports[3210] = 'ER_AUDIT_LOG_JSON_FILTERING_NOT_ENABLED'; +exports[3211] = 'ER_AUDIT_LOG_UDF_INSUFFICIENT_PRIVILEGE'; +exports[3212] = 'ER_AUDIT_LOG_SUPER_PRIVILEGE_REQUIRED'; +exports[3213] = 'ER_COULD_NOT_REINITIALIZE_AUDIT_LOG_FILTERS'; +exports[3214] = 'ER_AUDIT_LOG_UDF_INVALID_ARGUMENT_TYPE'; +exports[3215] = 'ER_AUDIT_LOG_UDF_INVALID_ARGUMENT_COUNT'; +exports[3216] = 'ER_AUDIT_LOG_HAS_NOT_BEEN_INSTALLED'; +exports[3217] = 'ER_AUDIT_LOG_UDF_READ_INVALID_MAX_ARRAY_LENGTH_ARG_TYPE'; +exports[3218] = 'ER_AUDIT_LOG_UDF_READ_INVALID_MAX_ARRAY_LENGTH_ARG_VALUE'; +exports[3219] = 'ER_AUDIT_LOG_JSON_FILTER_PARSING_ERROR'; +exports[3220] = 'ER_AUDIT_LOG_JSON_FILTER_NAME_CANNOT_BE_EMPTY'; +exports[3221] = 'ER_AUDIT_LOG_JSON_USER_NAME_CANNOT_BE_EMPTY'; +exports[3222] = 'ER_AUDIT_LOG_JSON_FILTER_DOES_NOT_EXISTS'; +exports[3223] = 'ER_AUDIT_LOG_USER_FIRST_CHARACTER_MUST_BE_ALPHANUMERIC'; +exports[3224] = 'ER_AUDIT_LOG_USER_NAME_INVALID_CHARACTER'; +exports[3225] = 'ER_AUDIT_LOG_HOST_NAME_INVALID_CHARACTER'; +exports[3226] = 'WARN_DEPRECATED_MAXDB_SQL_MODE_FOR_TIMESTAMP'; +exports[3227] = 'ER_XA_REPLICATION_FILTERS'; +exports[3228] = 'ER_CANT_OPEN_ERROR_LOG'; +exports[3229] = 'ER_GROUPING_ON_TIMESTAMP_IN_DST'; +exports[3230] = 'ER_CANT_START_SERVER_NAMED_PIPE'; diff --git a/lib/protocol/constants/ssl_profiles.js b/lib/protocol/constants/ssl_profiles.js index ce9d9f725..bec1864f3 100644 --- a/lib/protocol/constants/ssl_profiles.js +++ b/lib/protocol/constants/ssl_profiles.js @@ -71,6 +71,43 @@ exports['Amazon RDS'] = { + '/40NawZfTUU=\n' + '-----END CERTIFICATE-----\n', + /** + * Amazon RDS global root CA 2019 to 2024 + * + * CN = Amazon RDS Root 2019 CA + * OU = Amazon RDS + * O = Amazon Web Services, Inc. + * L = Seattle + * ST = Washington + * C = US + * P = 2019-08-22T17:08:50Z/2024-08-22T17:08:50Z + * F = D4:0D:DB:29:E3:75:0D:FF:A6:71:C3:14:0B:BF:5F:47:8D:1C:80:96 + */ + '-----BEGIN CERTIFICATE-----\n' + + 'MIIEBjCCAu6gAwIBAgIJAMc0ZzaSUK51MA0GCSqGSIb3DQEBCwUAMIGPMQswCQYD\n' + + 'VQQGEwJVUzEQMA4GA1UEBwwHU2VhdHRsZTETMBEGA1UECAwKV2FzaGluZ3RvbjEi\n' + + 'MCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywgSW5jLjETMBEGA1UECwwKQW1h\n' + + 'em9uIFJEUzEgMB4GA1UEAwwXQW1hem9uIFJEUyBSb290IDIwMTkgQ0EwHhcNMTkw\n' + + 'ODIyMTcwODUwWhcNMjQwODIyMTcwODUwWjCBjzELMAkGA1UEBhMCVVMxEDAOBgNV\n' + + 'BAcMB1NlYXR0bGUxEzARBgNVBAgMCldhc2hpbmd0b24xIjAgBgNVBAoMGUFtYXpv\n' + + 'biBXZWIgU2VydmljZXMsIEluYy4xEzARBgNVBAsMCkFtYXpvbiBSRFMxIDAeBgNV\n' + + 'BAMMF0FtYXpvbiBSRFMgUm9vdCAyMDE5IENBMIIBIjANBgkqhkiG9w0BAQEFAAOC\n' + + 'AQ8AMIIBCgKCAQEArXnF/E6/Qh+ku3hQTSKPMhQQlCpoWvnIthzX6MK3p5a0eXKZ\n' + + 'oWIjYcNNG6UwJjp4fUXl6glp53Jobn+tWNX88dNH2n8DVbppSwScVE2LpuL+94vY\n' + + '0EYE/XxN7svKea8YvlrqkUBKyxLxTjh+U/KrGOaHxz9v0l6ZNlDbuaZw3qIWdD/I\n' + + '6aNbGeRUVtpM6P+bWIoxVl/caQylQS6CEYUk+CpVyJSkopwJlzXT07tMoDL5WgX9\n' + + 'O08KVgDNz9qP/IGtAcRduRcNioH3E9v981QO1zt/Gpb2f8NqAjUUCUZzOnij6mx9\n' + + 'McZ+9cWX88CRzR0vQODWuZscgI08NvM69Fn2SQIDAQABo2MwYTAOBgNVHQ8BAf8E\n' + + 'BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUc19g2LzLA5j0Kxc0LjZa\n' + + 'pmD/vB8wHwYDVR0jBBgwFoAUc19g2LzLA5j0Kxc0LjZapmD/vB8wDQYJKoZIhvcN\n' + + 'AQELBQADggEBAHAG7WTmyjzPRIM85rVj+fWHsLIvqpw6DObIjMWokpliCeMINZFV\n' + + 'ynfgBKsf1ExwbvJNzYFXW6dihnguDG9VMPpi2up/ctQTN8tm9nDKOy08uNZoofMc\n' + + 'NUZxKCEkVKZv+IL4oHoeayt8egtv3ujJM6V14AstMQ6SwvwvA93EP/Ug2e4WAXHu\n' + + 'cbI1NAbUgVDqp+DRdfvZkgYKryjTWd/0+1fS8X1bBZVWzl7eirNVnHbSH2ZDpNuY\n' + + '0SBd8dj5F6ld3t58ydZbrTHze7JJOd8ijySAp4/kiu9UfZWuTPABzDa/DSdz9Dk/\n' + + 'zPW4CXXvhLmE02TA9/HeCw3KEHIwicNuEfw=\n' + + '-----END CERTIFICATE-----\n', + /** * Amazon RDS ap-northeast-1 certificate CA 2015 to 2020 * @@ -439,6 +476,1005 @@ exports['Amazon RDS'] = { + 'NMb0QME981kGRzc2WhgP71YS2hHd1kXtsoYP1yTu4vThSKsoN4bkiHsaC1cRkLoy\n' + '0fFA4wpB3WloMEvCDaUvvH1LZlBXTNlwi9KtcwD4tDxkkBt4tQczKLGpQ/nF/W9n\n' + '8YDWk3IIc1sd0bkZqoau2Q==\n' + + '-----END CERTIFICATE-----\n', + + /** + * Amazon RDS ap-south-1 certificate CA 2016 to 2020 + * + * CN = Amazon RDS ap-south-1 CA + * OU = Amazon RDS + * O = Amazon Web Services, Inc. + * L = Seattle + * ST = Washington + * C = US + * P = 2016-05-03T21:29:22Z/2020-03-05T21:29:22Z + * F = F3:A3:C2:52:D9:82:20:AC:8C:62:31:2A:8C:AD:5D:7B:1C:31:F1:DD + */ + '-----BEGIN CERTIFICATE-----\n' + + 'MIID/TCCAuWgAwIBAgIBTTANBgkqhkiG9w0BAQsFADCBijELMAkGA1UEBhMCVVMx\n' + + 'EzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUxIjAgBgNVBAoM\n' + + 'GUFtYXpvbiBXZWIgU2VydmljZXMsIEluYy4xEzARBgNVBAsMCkFtYXpvbiBSRFMx\n' + + 'GzAZBgNVBAMMEkFtYXpvbiBSRFMgUm9vdCBDQTAeFw0xNjA1MDMyMTI5MjJaFw0y\n' + + 'MDAzMDUyMTI5MjJaMIGQMQswCQYDVQQGEwJVUzETMBEGA1UECAwKV2FzaGluZ3Rv\n' + + 'bjEQMA4GA1UEBwwHU2VhdHRsZTEiMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNl\n' + + 'cywgSW5jLjETMBEGA1UECwwKQW1hem9uIFJEUzEhMB8GA1UEAwwYQW1hem9uIFJE\n' + + 'UyBhcC1zb3V0aC0xIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA\n' + + '06eWGLE0TeqL9kyWOLkS8q0fXO97z+xyBV3DKSB2lg2GkgBz3B98MkmkeB0SZy3G\n' + + 'Ce4uCpCPbFKiFEdiUclOlhZsrBuCeaimxLM3Ig2wuenElO/7TqgaYHYUbT3d+VQW\n' + + 'GUbLn5GRZJZe1OAClYdOWm7A1CKpuo+cVV1vxbY2nGUQSJPpVn2sT9gnwvjdE60U\n' + + 'JGYU/RLCTm8zmZBvlWaNIeKDnreIc4rKn6gUnJ2cQn1ryCVleEeyc3xjYDSrjgdn\n' + + 'FLYGcp9mphqVT0byeQMOk0c7RHpxrCSA0V5V6/CreFV2LteK50qcDQzDSM18vWP/\n' + + 'p09FoN8O7QrtOeZJzH/lmwIDAQABo2YwZDAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0T\n' + + 'AQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU2i83QHuEl/d0keXF+69HNJph7cMwHwYD\n' + + 'VR0jBBgwFoAUTgLurD72FchM7Sz1BcGPnIQISYMwDQYJKoZIhvcNAQELBQADggEB\n' + + 'ACqnH2VjApoDqoSQOky52QBwsGaj+xWYHW5Gm7EvCqvQuhWMkeBuD6YJmMvNyA9G\n' + + 'I2lh6/o+sUk/RIsbYbxPRdhNPTOgDR9zsNRw6qxaHztq/CEC+mxDCLa3O1hHBaDV\n' + + 'BmB3nCZb93BvO0EQSEk7aytKq/f+sjyxqOcs385gintdHGU9uM7gTZHnU9vByJsm\n' + + '/TL07Miq67X0NlhIoo3jAk+xHaeKJdxdKATQp0448P5cY20q4b8aMk1twcNaMvCP\n' + + 'dG4M5doaoUA8OQ/0ukLLae/LBxLeTw04q1/a2SyFaVUX2Twbb1S3xVWwLA8vsyGr\n' + + 'igXx7B5GgP+IHb6DTjPJAi0=\n' + + '-----END CERTIFICATE-----\n', + + /** + * Amazon RDS us-east-2 certificate CA 2016 to 2020 + * + * CN = Amazon RDS us-east-2 CA + * OU = Amazon RDS + * O = Amazon Web Services, Inc. + * L = Seattle + * ST = Washington + * C = US + * P = 2016-08-11T19:58:45Z/2020-03-05T19:58:45Z + * F = 9B:78:E3:64:7F:74:BC:B2:52:18:CF:13:C3:62:B8:35:9D:3D:5F:B6 + */ + '-----BEGIN CERTIFICATE-----\n' + + 'MIID/DCCAuSgAwIBAgIBTjANBgkqhkiG9w0BAQsFADCBijELMAkGA1UEBhMCVVMx\n' + + 'EzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUxIjAgBgNVBAoM\n' + + 'GUFtYXpvbiBXZWIgU2VydmljZXMsIEluYy4xEzARBgNVBAsMCkFtYXpvbiBSRFMx\n' + + 'GzAZBgNVBAMMEkFtYXpvbiBSRFMgUm9vdCBDQTAeFw0xNjA4MTExOTU4NDVaFw0y\n' + + 'MDAzMDUxOTU4NDVaMIGPMQswCQYDVQQGEwJVUzETMBEGA1UECAwKV2FzaGluZ3Rv\n' + + 'bjEQMA4GA1UEBwwHU2VhdHRsZTEiMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNl\n' + + 'cywgSW5jLjETMBEGA1UECwwKQW1hem9uIFJEUzEgMB4GA1UEAwwXQW1hem9uIFJE\n' + + 'UyB1cy1lYXN0LTIgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCp\n' + + 'WnnUX7wM0zzstccX+4iXKJa9GR0a2PpvB1paEX4QRCgfhEdQWDaSqyrWNgdVCKkt\n' + + '1aQkWu5j6VAC2XIG7kKoonm1ZdBVyBLqW5lXNywlaiU9yhJkwo8BR+/OqgE+PLt/\n' + + 'EO1mlN0PQudja/XkExCXTO29TG2j7F/O7hox6vTyHNHc0H88zS21uPuBE+jivViS\n' + + 'yzj/BkyoQ85hnkues3f9R6gCGdc+J51JbZnmgzUkvXjAEuKhAm9JksVOxcOKUYe5\n' + + 'ERhn0U9zjzpfbAITIkul97VVa5IxskFFTHIPJbvRKHJkiF6wTJww/tc9wm+fSCJ1\n' + + '+DbQTGZgkQ3bJrqRN29/AgMBAAGjZjBkMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMB\n' + + 'Af8ECDAGAQH/AgEAMB0GA1UdDgQWBBSAHQzUYYZbepwKEMvGdHp8wzHnfDAfBgNV\n' + + 'HSMEGDAWgBROAu6sPvYVyEztLPUFwY+chAhJgzANBgkqhkiG9w0BAQsFAAOCAQEA\n' + + 'MbaEzSYZ+aZeTBxf8yi0ta8K4RdwEJsEmP6IhFFQHYUtva2Cynl4Q9tZg3RMsybT\n' + + '9mlnSQQlbN/wqIIXbkrcgFcHoXG9Odm/bDtUwwwDaiEhXVfeQom3G77QHOWMTCGK\n' + + 'qadwuh5msrb17JdXZoXr4PYHDKP7j0ONfAyFNER2+uecblHfRSpVq5UeF3L6ZJb8\n' + + 'fSw/GtAV6an+/0r+Qm+PiI2H5XuZ4GmRJYnGMhqWhBYrY7p3jtVnKcsh39wgfUnW\n' + + 'AvZEZG/yhFyAZW0Essa39LiL5VSq14Y1DOj0wgnhSY/9WHxaAo1HB1T9OeZknYbD\n' + + 'fl/EGSZ0TEvZkENrXcPlVA==\n' + + '-----END CERTIFICATE-----\n', + + /** + * Amazon RDS ca-central-1 certificate CA 2016 to 2020 + * + * CN = Amazon RDS ca-central-1 CA + * OU = Amazon RDS + * O = Amazon Web Services, Inc. + * L = Seattle + * ST = Washington + * C = US + * P = 2016-09-15T00:10:11Z/2020-03-05T00:10:11Z + * F = D7:E0:16:AB:8A:0B:63:9F:67:1F:16:87:42:F4:0A:EE:73:A6:FC:04 + */ + '-----BEGIN CERTIFICATE-----\n' + + 'MIID/zCCAuegAwIBAgIBTzANBgkqhkiG9w0BAQsFADCBijELMAkGA1UEBhMCVVMx\n' + + 'EzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUxIjAgBgNVBAoM\n' + + 'GUFtYXpvbiBXZWIgU2VydmljZXMsIEluYy4xEzARBgNVBAsMCkFtYXpvbiBSRFMx\n' + + 'GzAZBgNVBAMMEkFtYXpvbiBSRFMgUm9vdCBDQTAeFw0xNjA5MTUwMDEwMTFaFw0y\n' + + 'MDAzMDUwMDEwMTFaMIGSMQswCQYDVQQGEwJVUzETMBEGA1UECAwKV2FzaGluZ3Rv\n' + + 'bjEQMA4GA1UEBwwHU2VhdHRsZTEiMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNl\n' + + 'cywgSW5jLjETMBEGA1UECwwKQW1hem9uIFJEUzEjMCEGA1UEAwwaQW1hem9uIFJE\n' + + 'UyBjYS1jZW50cmFsLTEgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB\n' + + 'AQCZYI/iQ6DrS3ny3t1EwX1wAD+3LMgh7Fd01EW5LIuaK2kYIIQpsVKhxLCit/V5\n' + + 'AGc/1qiJS1Qz9ODLTh0Na6bZW6EakRzuHJLe32KJtoFYPC7Z09UqzXrpA/XL+1hM\n' + + 'P0ZmCWsU7Nn/EmvfBp9zX3dZp6P6ATrvDuYaVFr+SA7aT3FXpBroqBS1fyzUPs+W\n' + + 'c6zTR6+yc4zkHX0XQxC5RH6xjgpeRkoOajA/sNo7AQF7KlWmKHbdVF44cvvAhRKZ\n' + + 'XaoVs/C4GjkaAEPTCbopYdhzg+KLx9eB2BQnYLRrIOQZtRfbQI2Nbj7p3VsRuOW1\n' + + 'tlcks2w1Gb0YC6w6SuIMFkl1AgMBAAGjZjBkMA4GA1UdDwEB/wQEAwIBBjASBgNV\n' + + 'HRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBToYWxE1lawl6Ks6NsvpbHQ3GKEtzAf\n' + + 'BgNVHSMEGDAWgBROAu6sPvYVyEztLPUFwY+chAhJgzANBgkqhkiG9w0BAQsFAAOC\n' + + 'AQEAG/8tQ0ooi3hoQpa5EJz0/E5VYBsAz3YxA2HoIonn0jJyG16bzB4yZt4vNQMA\n' + + 'KsNlQ1uwDWYL1nz63axieUUFIxqxl1KmwfhsmLgZ0Hd2mnTPIl2Hw3uj5+wdgGBg\n' + + 'agnAZ0bajsBYgD2VGQbqjdk2Qn7Fjy3LEWIvGZx4KyZ99OJ2QxB7JOPdauURAtWA\n' + + 'DKYkP4LLJxtj07DSzG8kuRWb9B47uqUD+eKDIyjfjbnzGtd9HqqzYFau7EX3HVD9\n' + + '9Qhnjl7bTZ6YfAEZ3nH2t3Vc0z76XfGh47rd0pNRhMV+xpok75asKf/lNh5mcUrr\n' + + 'VKwflyMkQpSbDCmcdJ90N2xEXQ==\n' + + '-----END CERTIFICATE-----\n', + + /** + * Amazon RDS eu-west-2 certificate CA 2016 to 2020 + * + * CN = Amazon RDS eu-west-2 CA + * OU = Amazon RDS + * O = Amazon Web Services, Inc. + * L = Seattle + * ST = Washington + * C = US + * P = 2016-10-10T17:44:42Z/2020-03-05T17:44:42Z + * F = 47:79:51:9F:FF:07:D3:F4:27:D3:AB:64:56:7F:00:45:BB:84:C1:71 + */ + '-----BEGIN CERTIFICATE-----\n' + + 'MIID/DCCAuSgAwIBAgIBUDANBgkqhkiG9w0BAQsFADCBijELMAkGA1UEBhMCVVMx\n' + + 'EzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUxIjAgBgNVBAoM\n' + + 'GUFtYXpvbiBXZWIgU2VydmljZXMsIEluYy4xEzARBgNVBAsMCkFtYXpvbiBSRFMx\n' + + 'GzAZBgNVBAMMEkFtYXpvbiBSRFMgUm9vdCBDQTAeFw0xNjEwMTAxNzQ0NDJaFw0y\n' + + 'MDAzMDUxNzQ0NDJaMIGPMQswCQYDVQQGEwJVUzETMBEGA1UECAwKV2FzaGluZ3Rv\n' + + 'bjEQMA4GA1UEBwwHU2VhdHRsZTEiMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNl\n' + + 'cywgSW5jLjETMBEGA1UECwwKQW1hem9uIFJEUzEgMB4GA1UEAwwXQW1hem9uIFJE\n' + + 'UyBldS13ZXN0LTIgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDO\n' + + 'cttLJfubB4XMMIGWNfJISkIdCMGJyOzLiMJaiWB5GYoXKhEl7YGotpy0qklwW3BQ\n' + + 'a0fmVdcCLX+dIuVQ9iFK+ZcK7zwm7HtdDTCHOCKeOh2IcnU4c/VIokFi6Gn8udM6\n' + + 'N/Zi5M5OGpVwLVALQU7Yctsn3c95el6MdVx6mJiIPVu7tCVZn88Z2koBQ2gq9P4O\n' + + 'Sb249SHFqOb03lYDsaqy1NDsznEOhaRBw7DPJFpvmw1lA3/Y6qrExRI06H2VYR2i\n' + + '7qxwDV50N58fs10n7Ye1IOxTVJsgEA7X6EkRRXqYaM39Z76R894548WHfwXWjUsi\n' + + 'MEX0RS0/t1GmnUQjvevDAgMBAAGjZjBkMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMB\n' + + 'Af8ECDAGAQH/AgEAMB0GA1UdDgQWBBQBxmcuRSxERYCtNnSr5xNfySokHjAfBgNV\n' + + 'HSMEGDAWgBROAu6sPvYVyEztLPUFwY+chAhJgzANBgkqhkiG9w0BAQsFAAOCAQEA\n' + + 'UyCUQjsF3nUAABjfEZmpksTuUo07aT3KGYt+EMMFdejnBQ0+2lJJFGtT+CDAk1SD\n' + + 'RSgfEBon5vvKEtlnTf9a3pv8WXOAkhfxnryr9FH6NiB8obISHNQNPHn0ljT2/T+I\n' + + 'Y6ytfRvKHa0cu3V0NXbJm2B4KEOt4QCDiFxUIX9z6eB4Kditwu05OgQh6KcogOiP\n' + + 'JesWxBMXXGoDC1rIYTFO7szwDyOHlCcVXJDNsTJhc32oDWYdeIbW7o/5I+aQsrXZ\n' + + 'C96HykZcgWzz6sElrQxUaT3IoMw/5nmw4uWKKnZnxgI9bY4fpQwMeBZ96iHfFxvH\n' + + 'mqfEEuC7uUoPofXdBp2ObQ==\n' + + '-----END CERTIFICATE-----\n', + + /** + * Amazon RDS us-gov-west-1 CA 2017 to 2022 + * + * CN = Amazon RDS us-gov-west-1 CA + * OU = Amazon RDS + * O = Amazon Web Services, Inc. + * L = Seattle + * ST = Washington + * C = US + * P = 2017-05-19T22:31:19Z/2022-05-18T12:00:00Z + * F = 77:55:8C:C4:5E:71:1F:1B:57:E3:DA:6E:5B:74:27:12:4E:E8:69:E8 + */ + '-----BEGIN CERTIFICATE-----\n' + + 'MIIECjCCAvKgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwgZMxCzAJBgNVBAYTAlVT\n' + + 'MRAwDgYDVQQHDAdTZWF0dGxlMRMwEQYDVQQIDApXYXNoaW5ndG9uMSIwIAYDVQQK\n' + + 'DBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJbmMuMRMwEQYDVQQLDApBbWF6b24gUkRT\n' + + 'MSQwIgYDVQQDDBtBbWF6b24gUkRTIEdvdkNsb3VkIFJvb3QgQ0EwHhcNMTcwNTE5\n' + + 'MjIzMTE5WhcNMjIwNTE4MTIwMDAwWjCBkzELMAkGA1UEBhMCVVMxEzARBgNVBAgM\n' + + 'Cldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUxIjAgBgNVBAoMGUFtYXpvbiBX\n' + + 'ZWIgU2VydmljZXMsIEluYy4xEzARBgNVBAsMCkFtYXpvbiBSRFMxJDAiBgNVBAMM\n' + + 'G0FtYXpvbiBSRFMgdXMtZ292LXdlc3QtMSBDQTCCASIwDQYJKoZIhvcNAQEBBQAD\n' + + 'ggEPADCCAQoCggEBAM8YZLKAzzOdNnoi7Klih26Zkj+OCpDfwx4ZYB6f8L8UoQi5\n' + + '8z9ZtIwMjiJ/kO08P1yl4gfc7YZcNFvhGruQZNat3YNpxwUpQcr4mszjuffbL4uz\n' + + '+/8FBxALdqCVOJ5Q0EVSfz3d9Bd1pUPL7ARtSpy7bn/tUPyQeI+lODYO906C0TQ3\n' + + 'b9bjOsgAdBKkHfjLdsknsOZYYIzYWOJyFJJa0B11XjDUNBy/3IuC0KvDl6At0V5b\n' + + '8M6cWcKhte2hgjwTYepV+/GTadeube1z5z6mWsN5arOAQUtYDLH6Aztq9mCJzLHm\n' + + 'RccBugnGl3fRLJ2VjioN8PoGoN9l9hFBy5fnFgsCAwEAAaNmMGQwDgYDVR0PAQH/\n' + + 'BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFEG7+br8KkvwPd5g\n' + + '71Rvh2stclJbMB8GA1UdIwQYMBaAFEkQz6S4NS5lOYKcDjBSuCcVpdzjMA0GCSqG\n' + + 'SIb3DQEBCwUAA4IBAQBMA327u5ABmhX+aPxljoIbxnydmAFWxW6wNp5+rZrvPig8\n' + + 'zDRqGQWWr7wWOIjfcWugSElYtf/m9KZHG/Z6+NG7nAoUrdcd1h/IQhb+lFQ2b5g9\n' + + 'sVzQv/H2JNkfZA8fL/Ko/Tm/f9tcqe0zrGCtT+5u0Nvz35Wl8CEUKLloS5xEb3k5\n' + + '7D9IhG3fsE3vHWlWrGCk1cKry3j12wdPG5cUsug0vt34u6rdhP+FsM0tHI15Kjch\n' + + 'RuUCvyQecy2ZFNAa3jmd5ycNdL63RWe8oayRBpQBxPPCbHfILxGZEdJbCH9aJ2D/\n' + + 'l8oHIDnvOLdv7/cBjyYuvmprgPtu3QEkbre5Hln/\n' + + '-----END CERTIFICATE-----\n', + + /** + * Amazon RDS eu-west-3 certificate CA 2017 to 2020 + * + * CN = Amazon RDS eu-west-3 CA + * OU = Amazon RDS + * O = Amazon Web Services, Inc. + * L = Seattle + * ST = Washington + * C = US + * P = 2017-08-25T21:39:26Z/2020-03-05T21:39:26Z + * F = FD:35:A7:84:60:68:98:00:12:54:ED:34:26:8C:66:0F:72:DD:B2:F4 + */ + '-----BEGIN CERTIFICATE-----\n' + + 'MIID/DCCAuSgAwIBAgIBUTANBgkqhkiG9w0BAQsFADCBijELMAkGA1UEBhMCVVMx\n' + + 'EzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUxIjAgBgNVBAoM\n' + + 'GUFtYXpvbiBXZWIgU2VydmljZXMsIEluYy4xEzARBgNVBAsMCkFtYXpvbiBSRFMx\n' + + 'GzAZBgNVBAMMEkFtYXpvbiBSRFMgUm9vdCBDQTAeFw0xNzA4MjUyMTM5MjZaFw0y\n' + + 'MDAzMDUyMTM5MjZaMIGPMQswCQYDVQQGEwJVUzETMBEGA1UECAwKV2FzaGluZ3Rv\n' + + 'bjEQMA4GA1UEBwwHU2VhdHRsZTEiMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNl\n' + + 'cywgSW5jLjETMBEGA1UECwwKQW1hem9uIFJEUzEgMB4GA1UEAwwXQW1hem9uIFJE\n' + + 'UyBldS13ZXN0LTMgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC+\n' + + 'xmlEC/3a4cJH+UPwXCE02lC7Zq5NHd0dn6peMeLN8agb6jW4VfSY0NydjRj2DJZ8\n' + + 'K7wV6sub5NUGT1NuFmvSmdbNR2T59KX0p2dVvxmXHHtIpQ9Y8Aq3ZfhmC5q5Bqgw\n' + + 'tMA1xayDi7HmoPX3R8kk9ktAZQf6lDeksCvok8idjTu9tiSpDiMwds5BjMsWfyjZ\n' + + 'd13PTGGNHYVdP692BSyXzSP1Vj84nJKnciW8tAqwIiadreJt5oXyrCXi8ekUMs80\n' + + 'cUTuGm3aA3Q7PB5ljJMPqz0eVddaiIvmTJ9O3Ez3Du/HpImyMzXjkFaf+oNXf/Hx\n' + + '/EW5jCRR6vEiXJcDRDS7AgMBAAGjZjBkMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMB\n' + + 'Af8ECDAGAQH/AgEAMB0GA1UdDgQWBBRZ9mRtS5fHk3ZKhG20Oack4cAqMTAfBgNV\n' + + 'HSMEGDAWgBROAu6sPvYVyEztLPUFwY+chAhJgzANBgkqhkiG9w0BAQsFAAOCAQEA\n' + + 'F/u/9L6ExQwD73F/bhCw7PWcwwqsK1mypIdrjdIsu0JSgwWwGCXmrIspA3n3Dqxq\n' + + 'sMhAJD88s9Em7337t+naar2VyLO63MGwjj+vA4mtvQRKq8ScIpiEc7xN6g8HUMsd\n' + + 'gPG9lBGfNjuAZsrGJflrko4HyuSM7zHExMjXLH+CXcv/m3lWOZwnIvlVMa4x0Tz0\n' + + 'A4fklaawryngzeEjuW6zOiYCzjZtPlP8Fw0SpzppJ8VpQfrZ751RDo4yudmPqoPK\n' + + '5EUe36L8U+oYBXnC5TlYs9bpVv9o5wJQI5qA9oQE2eFWxF1E0AyZ4V5sgGUBStaX\n' + + 'BjDDWul0wSo7rt1Tq7XpnA==\n' + + '-----END CERTIFICATE-----\n', + + /** + * Amazon RDS ap-northeast-3 certificate CA 2017 to 2020 + * + * CN = Amazon RDS ap-northeast-3 CA + * OU = Amazon RDS + * O = Amazon Web Services, Inc. + * L = Seattle + * ST = Washington + * C = US + * P = 2017-12-01T00:55:42Z/2020-03-05T00:55:42Z + * F = C0:C7:D4:B3:91:40:A0:77:43:28:BF:AF:77:57:DF:FD:98:FB:10:3F + */ + '-----BEGIN CERTIFICATE-----\n' + + 'MIIEATCCAumgAwIBAgIBTjANBgkqhkiG9w0BAQUFADCBijELMAkGA1UEBhMCVVMx\n' + + 'EzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUxIjAgBgNVBAoM\n' + + 'GUFtYXpvbiBXZWIgU2VydmljZXMsIEluYy4xEzARBgNVBAsMCkFtYXpvbiBSRFMx\n' + + 'GzAZBgNVBAMMEkFtYXpvbiBSRFMgUm9vdCBDQTAeFw0xNzEyMDEwMDU1NDJaFw0y\n' + + 'MDAzMDUwMDU1NDJaMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECAwKV2FzaGluZ3Rv\n' + + 'bjEQMA4GA1UEBwwHU2VhdHRsZTEiMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNl\n' + + 'cywgSW5jLjETMBEGA1UECwwKQW1hem9uIFJEUzElMCMGA1UEAwwcQW1hem9uIFJE\n' + + 'UyBhcC1ub3J0aGVhc3QtMyBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC\n' + + 'ggEBAMZtQNnm/XT19mTa10ftHLzg5UhajoI65JHv4TQNdGXdsv+CQdGYU49BJ9Eu\n' + + '3bYgiEtTzR2lQe9zGMvtuJobLhOWuavzp7IixoIQcHkFHN6wJ1CvqrxgvJfBq6Hy\n' + + 'EuCDCiU+PPDLUNA6XM6Qx3IpHd1wrJkjRB80dhmMSpxmRmx849uFafhN+P1QybsM\n' + + 'TI0o48VON2+vj+mNuQTyLMMP8D4odSQHjaoG+zyJfJGZeAyqQyoOUOFEyQaHC3TT\n' + + '3IDSNCQlpxb9LerbCoKu79WFBBq3CS5cYpg8/fsnV2CniRBFFUumBt5z4dhw9RJU\n' + + 'qlUXXO1ZyzpGd+c5v6FtrfXtnIUCAwEAAaNmMGQwDgYDVR0PAQH/BAQDAgEGMBIG\n' + + 'A1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFETv7ELNplYy/xTeIOInl6nzeiHg\n' + + 'MB8GA1UdIwQYMBaAFE4C7qw+9hXITO0s9QXBj5yECEmDMA0GCSqGSIb3DQEBBQUA\n' + + 'A4IBAQCpKxOQcd0tEKb3OtsOY8q/MPwTyustGk2Rt7t9G68idADp8IytB7M0SDRo\n' + + 'wWZqynEq7orQVKdVOanhEWksNDzGp0+FPAf/KpVvdYCd7ru3+iI+V4ZEp2JFdjuZ\n' + + 'Zz0PIjS6AgsZqE5Ri1J+NmfmjGZCPhsHnGZiBaenX6K5VRwwwmLN6xtoqrrfR5zL\n' + + 'QfBeeZNJG6KiM3R/DxJ5rAa6Fz+acrhJ60L7HprhB7SFtj1RCijau3+ZwiGmUOMr\n' + + 'yKlMv+VgmzSw7o4Hbxy1WVrA6zQsTHHSGf+vkQn2PHvnFMUEu/ZLbTDYFNmTLK91\n' + + 'K6o4nMsEvhBKgo4z7H1EqqxXhvN2\n' + + '-----END CERTIFICATE-----\n', + + /** + * Amazon RDS GovCloud Root CA 2017 to 2022 + * + * CN = Amazon RDS GovCloud Root CA + * OU = Amazon RDS + * O = Amazon Web Services, Inc. + * L = Seattle + * ST = Washington + * C = US + * P = 2017-05-19T22:29:11Z/2022-05-18T22:29:11Z + * F = A3:61:F9:C9:A2:5B:91:FE:73:A6:52:E3:59:14:8E:CE:35:12:0F:FD + */ + '-----BEGIN CERTIFICATE-----\n' + + 'MIIEDjCCAvagAwIBAgIJAMM61RQn3/kdMA0GCSqGSIb3DQEBCwUAMIGTMQswCQYD\n' + + 'VQQGEwJVUzEQMA4GA1UEBwwHU2VhdHRsZTETMBEGA1UECAwKV2FzaGluZ3RvbjEi\n' + + 'MCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywgSW5jLjETMBEGA1UECwwKQW1h\n' + + 'em9uIFJEUzEkMCIGA1UEAwwbQW1hem9uIFJEUyBHb3ZDbG91ZCBSb290IENBMB4X\n' + + 'DTE3MDUxOTIyMjkxMVoXDTIyMDUxODIyMjkxMVowgZMxCzAJBgNVBAYTAlVTMRAw\n' + + 'DgYDVQQHDAdTZWF0dGxlMRMwEQYDVQQIDApXYXNoaW5ndG9uMSIwIAYDVQQKDBlB\n' + + 'bWF6b24gV2ViIFNlcnZpY2VzLCBJbmMuMRMwEQYDVQQLDApBbWF6b24gUkRTMSQw\n' + + 'IgYDVQQDDBtBbWF6b24gUkRTIEdvdkNsb3VkIFJvb3QgQ0EwggEiMA0GCSqGSIb3\n' + + 'DQEBAQUAA4IBDwAwggEKAoIBAQDGS9bh1FGiJPT+GRb3C5aKypJVDC1H2gbh6n3u\n' + + 'j8cUiyMXfmm+ak402zdLpSYMaxiQ7oL/B3wEmumIpRDAsQrSp3B/qEeY7ipQGOfh\n' + + 'q2TXjXGIUjiJ/FaoGqkymHRLG+XkNNBtb7MRItsjlMVNELXECwSiMa3nJL2/YyHW\n' + + 'nTr1+11/weeZEKgVbCUrOugFkMXnfZIBSn40j6EnRlO2u/NFU5ksK5ak2+j8raZ7\n' + + 'xW7VXp9S1Tgf1IsWHjGZZZguwCkkh1tHOlHC9gVA3p63WecjrIzcrR/V27atul4m\n' + + 'tn56s5NwFvYPUIx1dbC8IajLUrepVm6XOwdQCfd02DmOyjWJAgMBAAGjYzBhMA4G\n' + + 'A1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRJEM+kuDUu\n' + + 'ZTmCnA4wUrgnFaXc4zAfBgNVHSMEGDAWgBRJEM+kuDUuZTmCnA4wUrgnFaXc4zAN\n' + + 'BgkqhkiG9w0BAQsFAAOCAQEAcfA7uirXsNZyI2j4AJFVtOTKOZlQwqbyNducnmlg\n' + + '/5nug9fAkwM4AgvF5bBOD1Hw6khdsccMwIj+1S7wpL+EYb/nSc8G0qe1p/9lZ/mZ\n' + + 'ff5g4JOa26lLuCrZDqAk4TzYnt6sQKfa5ZXVUUn0BK3okhiXS0i+NloMyaBCL7vk\n' + + 'kDwkHwEqflRKfZ9/oFTcCfoiHPA7AdBtaPVr0/Kj9L7k+ouz122huqG5KqX0Zpo8\n' + + 'S0IGvcd2FZjNSNPttNAK7YuBVsZ0m2nIH1SLp//00v7yAHIgytQwwB17PBcp4NXD\n' + + 'pCfTa27ng9mMMC2YLqWQpW4TkqjDin2ZC+5X/mbrjzTvVg==\n' + + '-----END CERTIFICATE-----\n', + + /** + * Amazon RDS ap-east-1 certificate CA 2019 to 2022 + * + * CN = Amazon RDS ap-east-1 CA + * OU = Amazon RDS + * O = Amazon Web Services, Inc. + * L = Seattle + * ST = Washington + * C = US + * P = 2019-02-17T02:47:00Z/2022-06-01T12:00:00Z + * F = BC:F8:70:75:1F:93:3F:A7:82:86:67:63:A8:86:1F:A4:E8:07:CE:06 + */ + '-----BEGIN CERTIFICATE-----\n' + + 'MIIEBzCCAu+gAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwgZQxCzAJBgNVBAYTAlVT\n' + + 'MRAwDgYDVQQHDAdTZWF0dGxlMRMwEQYDVQQIDApXYXNoaW5ndG9uMSIwIAYDVQQK\n' + + 'DBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJbmMuMRMwEQYDVQQLDApBbWF6b24gUkRT\n' + + 'MSUwIwYDVQQDDBxBbWF6b24gUkRTIGFwLWVhc3QtMSBSb290IENBMB4XDTE5MDIx\n' + + 'NzAyNDcwMFoXDTIyMDYwMTEyMDAwMFowgY8xCzAJBgNVBAYTAlVTMRMwEQYDVQQI\n' + + 'DApXYXNoaW5ndG9uMRAwDgYDVQQHDAdTZWF0dGxlMSIwIAYDVQQKDBlBbWF6b24g\n' + + 'V2ViIFNlcnZpY2VzLCBJbmMuMRMwEQYDVQQLDApBbWF6b24gUkRTMSAwHgYDVQQD\n' + + 'DBdBbWF6b24gUkRTIGFwLWVhc3QtMSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP\n' + + 'ADCCAQoCggEBAOcJAUofyJuBuPr5ISHi/Ha5ed8h3eGdzn4MBp6rytPOg9NVGRQs\n' + + 'O93fNGCIKsUT6gPuk+1f1ncMTV8Y0Fdf4aqGWme+Khm3ZOP3V1IiGnVq0U2xiOmn\n' + + 'SQ4Q7LoeQC4lC6zpoCHVJyDjZ4pAknQQfsXb77Togdt/tK5ahev0D+Q3gCwAoBoO\n' + + 'DHKJ6t820qPi63AeGbJrsfNjLKiXlFPDUj4BGir4dUzjEeH7/hx37na1XG/3EcxP\n' + + '399cT5k7sY/CR9kctMlUyEEUNQOmhi/ly1Lgtihm3QfjL6K9aGLFNwX35Bkh9aL2\n' + + 'F058u+n8DP/dPeKUAcJKiQZUmzuen5n57x8CAwEAAaNmMGQwDgYDVR0PAQH/BAQD\n' + + 'AgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFFlqgF4FQlb9yP6c+Q3E\n' + + 'O3tXv+zOMB8GA1UdIwQYMBaAFK9T6sY/PBZVbnHcNcQXf58P4OuPMA0GCSqGSIb3\n' + + 'DQEBCwUAA4IBAQDeXiS3v1z4jWAo1UvVyKDeHjtrtEH1Rida1eOXauFuEQa5tuOk\n' + + 'E53Os4haZCW4mOlKjigWs4LN+uLIAe1aFXGo92nGIqyJISHJ1L+bopx/JmIbHMCZ\n' + + '0lTNJfR12yBma5VQy7vzeFku/SisKwX0Lov1oHD4MVhJoHbUJYkmAjxorcIHORvh\n' + + 'I3Vj5XrgDWtLDPL8/Id/roul/L+WX5ir+PGScKBfQIIN2lWdZoqdsx8YWqhm/ikL\n' + + 'C6qNieSwcvWL7C03ri0DefTQMY54r5wP33QU5hJ71JoaZI3YTeT0Nf+NRL4hM++w\n' + + 'Q0veeNzBQXg1f/JxfeA39IDIX1kiCf71tGlT\n' + + '-----END CERTIFICATE-----\n', + + /** + * Amazon RDS ap-northeast-1 certificate CA 2019 to 2024 + * + * CN = Amazon RDS ap-northeast-1 2019 CA + * OU = Amazon RDS + * O = Amazon Web Services, Inc. + * L = Seattle + * ST = Washington + * C = US + * P = 2019-09-18T16:56:20Z/2024-08-22T17:08:50Z + * F = 47:A3:F9:20:64:5C:9F:9D:48:8C:7D:E6:0B:86:D6:05:13:00:16:A1 + */ + '-----BEGIN CERTIFICATE-----\n' + + 'MIIEDDCCAvSgAwIBAgICcEUwDQYJKoZIhvcNAQELBQAwgY8xCzAJBgNVBAYTAlVT\n' + + 'MRAwDgYDVQQHDAdTZWF0dGxlMRMwEQYDVQQIDApXYXNoaW5ndG9uMSIwIAYDVQQK\n' + + 'DBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJbmMuMRMwEQYDVQQLDApBbWF6b24gUkRT\n' + + 'MSAwHgYDVQQDDBdBbWF6b24gUkRTIFJvb3QgMjAxOSBDQTAeFw0xOTA5MTgxNjU2\n' + + 'MjBaFw0yNDA4MjIxNzA4NTBaMIGZMQswCQYDVQQGEwJVUzETMBEGA1UECAwKV2Fz\n' + + 'aGluZ3RvbjEQMA4GA1UEBwwHU2VhdHRsZTEiMCAGA1UECgwZQW1hem9uIFdlYiBT\n' + + 'ZXJ2aWNlcywgSW5jLjETMBEGA1UECwwKQW1hem9uIFJEUzEqMCgGA1UEAwwhQW1h\n' + + 'em9uIFJEUyBhcC1ub3J0aGVhc3QtMSAyMDE5IENBMIIBIjANBgkqhkiG9w0BAQEF\n' + + 'AAOCAQ8AMIIBCgKCAQEAndtkldmHtk4TVQAyqhAvtEHSMb6pLhyKrIFved1WO3S7\n' + + '+I+bWwv9b2W/ljJxLq9kdT43bhvzonNtI4a1LAohS6bqyirmk8sFfsWT3akb+4Sx\n' + + '1sjc8Ovc9eqIWJCrUiSvv7+cS7ZTA9AgM1PxvHcsqrcUXiK3Jd/Dax9jdZE1e15s\n' + + 'BEhb2OEPE+tClFZ+soj8h8Pl2Clo5OAppEzYI4LmFKtp1X/BOf62k4jviXuCSst3\n' + + 'UnRJzE/CXtjmN6oZySVWSe0rQYuyqRl6//9nK40cfGKyxVnimB8XrrcxUN743Vud\n' + + 'QQVU0Esm8OVTX013mXWQXJHP2c0aKkog8LOga0vobQIDAQABo2YwZDAOBgNVHQ8B\n' + + 'Af8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQULmoOS1mFSjj+\n' + + 'snUPx4DgS3SkLFYwHwYDVR0jBBgwFoAUc19g2LzLA5j0Kxc0LjZapmD/vB8wDQYJ\n' + + 'KoZIhvcNAQELBQADggEBAAkVL2P1M2/G9GM3DANVAqYOwmX0Xk58YBHQu6iiQg4j\n' + + 'b4Ky/qsZIsgT7YBsZA4AOcPKQFgGTWhe9pvhmXqoN3RYltN8Vn7TbUm/ZVDoMsrM\n' + + 'gwv0+TKxW1/u7s8cXYfHPiTzVSJuOogHx99kBW6b2f99GbP7O1Sv3sLq4j6lVvBX\n' + + 'Fiacf5LAWC925nvlTzLlBgIc3O9xDtFeAGtZcEtxZJ4fnGXiqEnN4539+nqzIyYq\n' + + 'nvlgCzyvcfRAxwltrJHuuRu6Maw5AGcd2Y0saMhqOVq9KYKFKuD/927BTrbd2JVf\n' + + '2sGWyuPZPCk3gq+5pCjbD0c6DkhcMGI6WwxvM5V/zSM=\n' + + '-----END CERTIFICATE-----\n', + + /** + * Amazon RDS ap-northeast-2 certificate CA 2019 to 2024 + * + * CN = Amazon RDS ap-northeast-2 2019 CA + * OU = Amazon RDS + * O = Amazon Web Services, Inc. + * L = Seattle + * ST = Washington + * C = US + * P = 2019-09-10T17:46:21Z/2024-08-22T17:08:50Z + * F = 8E:1C:70:C1:64:BD:FC:F9:93:9B:A2:67:CA:CF:52:F0:E1:F7:B4:F0 + */ + '-----BEGIN CERTIFICATE-----\n' + + 'MIIEDDCCAvSgAwIBAgICOFAwDQYJKoZIhvcNAQELBQAwgY8xCzAJBgNVBAYTAlVT\n' + + 'MRAwDgYDVQQHDAdTZWF0dGxlMRMwEQYDVQQIDApXYXNoaW5ndG9uMSIwIAYDVQQK\n' + + 'DBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJbmMuMRMwEQYDVQQLDApBbWF6b24gUkRT\n' + + 'MSAwHgYDVQQDDBdBbWF6b24gUkRTIFJvb3QgMjAxOSBDQTAeFw0xOTA5MTAxNzQ2\n' + + 'MjFaFw0yNDA4MjIxNzA4NTBaMIGZMQswCQYDVQQGEwJVUzETMBEGA1UECAwKV2Fz\n' + + 'aGluZ3RvbjEQMA4GA1UEBwwHU2VhdHRsZTEiMCAGA1UECgwZQW1hem9uIFdlYiBT\n' + + 'ZXJ2aWNlcywgSW5jLjETMBEGA1UECwwKQW1hem9uIFJEUzEqMCgGA1UEAwwhQW1h\n' + + 'em9uIFJEUyBhcC1ub3J0aGVhc3QtMiAyMDE5IENBMIIBIjANBgkqhkiG9w0BAQEF\n' + + 'AAOCAQ8AMIIBCgKCAQEAzU72e6XbaJbi4HjJoRNjKxzUEuChKQIt7k3CWzNnmjc5\n' + + '8I1MjCpa2W1iw1BYVysXSNSsLOtUsfvBZxi/1uyMn5ZCaf9aeoA9UsSkFSZBjOCN\n' + + 'DpKPCmfV1zcEOvJz26+1m8WDg+8Oa60QV0ou2AU1tYcw98fOQjcAES0JXXB80P2s\n' + + '3UfkNcnDz+l4k7j4SllhFPhH6BQ4lD2NiFAP4HwoG6FeJUn45EPjzrydxjq6v5Fc\n' + + 'cQ8rGuHADVXotDbEhaYhNjIrsPL+puhjWfhJjheEw8c4whRZNp6gJ/b6WEes/ZhZ\n' + + 'h32DwsDsZw0BfRDUMgUn8TdecNexHUw8vQWeC181hwIDAQABo2YwZDAOBgNVHQ8B\n' + + 'Af8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUwW9bWgkWkr0U\n' + + 'lrOsq2kvIdrECDgwHwYDVR0jBBgwFoAUc19g2LzLA5j0Kxc0LjZapmD/vB8wDQYJ\n' + + 'KoZIhvcNAQELBQADggEBAEugF0Gj7HVhX0ehPZoGRYRt3PBuI2YjfrrJRTZ9X5wc\n' + + '9T8oHmw07mHmNy1qqWvooNJg09bDGfB0k5goC2emDiIiGfc/kvMLI7u+eQOoMKj6\n' + + 'mkfCncyRN3ty08Po45vTLBFZGUvtQmjM6yKewc4sXiASSBmQUpsMbiHRCL72M5qV\n' + + 'obcJOjGcIdDTmV1BHdWT+XcjynsGjUqOvQWWhhLPrn4jWe6Xuxll75qlrpn3IrIx\n' + + 'CRBv/5r7qbcQJPOgwQsyK4kv9Ly8g7YT1/vYBlR3cRsYQjccw5ceWUj2DrMVWhJ4\n' + + 'prf+E3Aa4vYmLLOUUvKnDQ1k3RGNu56V0tonsQbfsaM=\n' + + '-----END CERTIFICATE-----\n', + + /** + * Amazon RDS ap-northeast-3 certificate CA 2019 to 2024 + * + * CN = Amazon RDS ap-northeast-3 2019 CA + * OU = Amazon RDS + * O = Amazon Web Services, Inc. + * L = Seattle + * ST = Washington + * C = US + * P = 2019-09-17T20:05:29Z/2024-08-22T17:08:50Z + * F = D1:08:B1:40:6D:6C:80:8E:F4:C1:2C:8A:1F:66:17:01:54:CD:1A:4E + */ + '-----BEGIN CERTIFICATE-----\n' + + 'MIIEDDCCAvSgAwIBAgICOYIwDQYJKoZIhvcNAQELBQAwgY8xCzAJBgNVBAYTAlVT\n' + + 'MRAwDgYDVQQHDAdTZWF0dGxlMRMwEQYDVQQIDApXYXNoaW5ndG9uMSIwIAYDVQQK\n' + + 'DBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJbmMuMRMwEQYDVQQLDApBbWF6b24gUkRT\n' + + 'MSAwHgYDVQQDDBdBbWF6b24gUkRTIFJvb3QgMjAxOSBDQTAeFw0xOTA5MTcyMDA1\n' + + 'MjlaFw0yNDA4MjIxNzA4NTBaMIGZMQswCQYDVQQGEwJVUzETMBEGA1UECAwKV2Fz\n' + + 'aGluZ3RvbjEQMA4GA1UEBwwHU2VhdHRsZTEiMCAGA1UECgwZQW1hem9uIFdlYiBT\n' + + 'ZXJ2aWNlcywgSW5jLjETMBEGA1UECwwKQW1hem9uIFJEUzEqMCgGA1UEAwwhQW1h\n' + + 'em9uIFJEUyBhcC1ub3J0aGVhc3QtMyAyMDE5IENBMIIBIjANBgkqhkiG9w0BAQEF\n' + + 'AAOCAQ8AMIIBCgKCAQEA4dMak8W+XW8y/2F6nRiytFiA4XLwePadqWebGtlIgyCS\n' + + 'kbug8Jv5w7nlMkuxOxoUeD4WhI6A9EkAn3r0REM/2f0aYnd2KPxeqS2MrtdxxHw1\n' + + 'xoOxk2x0piNSlOz6yog1idsKR5Wurf94fvM9FdTrMYPPrDabbGqiBMsZZmoHLvA3\n' + + 'Z+57HEV2tU0Ei3vWeGIqnNjIekS+E06KhASxrkNU5vi611UsnYZlSi0VtJsH4UGV\n' + + 'LhnHl53aZL0YFO5mn/fzuNG/51qgk/6EFMMhaWInXX49Dia9FnnuWXwVwi6uX1Wn\n' + + '7kjoHi5VtmC8ZlGEHroxX2DxEr6bhJTEpcLMnoQMqwIDAQABo2YwZDAOBgNVHQ8B\n' + + 'Af8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUsUI5Cb3SWB8+\n' + + 'gv1YLN/ABPMdxSAwHwYDVR0jBBgwFoAUc19g2LzLA5j0Kxc0LjZapmD/vB8wDQYJ\n' + + 'KoZIhvcNAQELBQADggEBAJAF3E9PM1uzVL8YNdzb6fwJrxxqI2shvaMVmC1mXS+w\n' + + 'G0zh4v2hBZOf91l1EO0rwFD7+fxoI6hzQfMxIczh875T6vUXePKVOCOKI5wCrDad\n' + + 'zQbVqbFbdhsBjF4aUilOdtw2qjjs9JwPuB0VXN4/jY7m21oKEOcnpe36+7OiSPjN\n' + + 'xngYewCXKrSRqoj3mw+0w/+exYj3Wsush7uFssX18av78G+ehKPIVDXptOCP/N7W\n' + + '8iKVNeQ2QGTnu2fzWsGUSvMGyM7yqT+h1ILaT//yQS8er511aHMLc142bD4D9VSy\n' + + 'DgactwPDTShK/PXqhvNey9v/sKXm4XatZvwcc8KYlW4=\n' + + '-----END CERTIFICATE-----\n', + + /** + * Amazon RDS ap-south-1 certificate CA 2019 to 2024 + * + * CN = Amazon RDS ap-south-1 2019 CA + * OU = Amazon RDS + * O = Amazon Web Services, Inc. + * L = Seattle + * ST = Washington + * C = US + * P = 2019-09-04T17:13:04Z/2024-08-22T17:08:50Z + * F = D6:AD:45:A9:54:36:E4:BA:9C:B7:9B:06:8C:0C:CD:CC:1E:81:B5:00 + */ + '-----BEGIN CERTIFICATE-----\n' + + 'MIIECDCCAvCgAwIBAgICVIYwDQYJKoZIhvcNAQELBQAwgY8xCzAJBgNVBAYTAlVT\n' + + 'MRAwDgYDVQQHDAdTZWF0dGxlMRMwEQYDVQQIDApXYXNoaW5ndG9uMSIwIAYDVQQK\n' + + 'DBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJbmMuMRMwEQYDVQQLDApBbWF6b24gUkRT\n' + + 'MSAwHgYDVQQDDBdBbWF6b24gUkRTIFJvb3QgMjAxOSBDQTAeFw0xOTA5MDQxNzEz\n' + + 'MDRaFw0yNDA4MjIxNzA4NTBaMIGVMQswCQYDVQQGEwJVUzETMBEGA1UECAwKV2Fz\n' + + 'aGluZ3RvbjEQMA4GA1UEBwwHU2VhdHRsZTEiMCAGA1UECgwZQW1hem9uIFdlYiBT\n' + + 'ZXJ2aWNlcywgSW5jLjETMBEGA1UECwwKQW1hem9uIFJEUzEmMCQGA1UEAwwdQW1h\n' + + 'em9uIFJEUyBhcC1zb3V0aC0xIDIwMTkgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IB\n' + + 'DwAwggEKAoIBAQDUYOz1hGL42yUCrcsMSOoU8AeD/3KgZ4q7gP+vAz1WnY9K/kim\n' + + 'eWN/2Qqzlo3+mxSFQFyD4MyV3+CnCPnBl9Sh1G/F6kThNiJ7dEWSWBQGAB6HMDbC\n' + + 'BaAsmUc1UIz8sLTL3fO+S9wYhA63Wun0Fbm/Rn2yk/4WnJAaMZcEtYf6e0KNa0LM\n' + + 'p/kN/70/8cD3iz3dDR8zOZFpHoCtf0ek80QqTich0A9n3JLxR6g6tpwoYviVg89e\n' + + 'qCjQ4axxOkWWeusLeTJCcY6CkVyFvDAKvcUl1ytM5AiaUkXblE7zDFXRM4qMMRdt\n' + + 'lPm8d3pFxh0fRYk8bIKnpmtOpz3RIctDrZZxAgMBAAGjZjBkMA4GA1UdDwEB/wQE\n' + + 'AwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBT99wKJftD3jb4sHoHG\n' + + 'i3uGlH6W6TAfBgNVHSMEGDAWgBRzX2DYvMsDmPQrFzQuNlqmYP+8HzANBgkqhkiG\n' + + '9w0BAQsFAAOCAQEAZ17hhr3dII3hUfuHQ1hPWGrpJOX/G9dLzkprEIcCidkmRYl+\n' + + 'hu1Pe3caRMh/17+qsoEErmnVq5jNY9X1GZL04IZH8YbHc7iRHw3HcWAdhN8633+K\n' + + 'jYEB2LbJ3vluCGnCejq9djDb6alOugdLMJzxOkHDhMZ6/gYbECOot+ph1tQuZXzD\n' + + 'tZ7prRsrcuPBChHlPjmGy8M9z8u+kF196iNSUGC4lM8vLkHM7ycc1/ZOwRq9aaTe\n' + + 'iOghbQQyAEe03MWCyDGtSmDfr0qEk+CHN+6hPiaL8qKt4s+V9P7DeK4iW08ny8Ox\n' + + 'AVS7u0OK/5+jKMAMrKwpYrBydOjTUTHScocyNw==\n' + + '-----END CERTIFICATE-----\n', + + /** + * Amazon RDS ap-southeast-1 certificate CA 2019 to 2024 + * + * CN = Amazon RDS ap-southeast-1 2019 CA + * OU = Amazon RDS + * O = Amazon Web Services, Inc. + * L = Seattle + * ST = Washington + * C = US + * P = 2019-09-13T20:11:42Z/2024-08-22T17:08:50Z + * F = 0D:20:FB:91:DE:BE:D2:CF:F3:F8:F8:43:AF:68:C6:03:76:F3:DD:B8 + */ + '-----BEGIN CERTIFICATE-----\n' + + 'MIIEDDCCAvSgAwIBAgICY4kwDQYJKoZIhvcNAQELBQAwgY8xCzAJBgNVBAYTAlVT\n' + + 'MRAwDgYDVQQHDAdTZWF0dGxlMRMwEQYDVQQIDApXYXNoaW5ndG9uMSIwIAYDVQQK\n' + + 'DBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJbmMuMRMwEQYDVQQLDApBbWF6b24gUkRT\n' + + 'MSAwHgYDVQQDDBdBbWF6b24gUkRTIFJvb3QgMjAxOSBDQTAeFw0xOTA5MTMyMDEx\n' + + 'NDJaFw0yNDA4MjIxNzA4NTBaMIGZMQswCQYDVQQGEwJVUzETMBEGA1UECAwKV2Fz\n' + + 'aGluZ3RvbjEQMA4GA1UEBwwHU2VhdHRsZTEiMCAGA1UECgwZQW1hem9uIFdlYiBT\n' + + 'ZXJ2aWNlcywgSW5jLjETMBEGA1UECwwKQW1hem9uIFJEUzEqMCgGA1UEAwwhQW1h\n' + + 'em9uIFJEUyBhcC1zb3V0aGVhc3QtMSAyMDE5IENBMIIBIjANBgkqhkiG9w0BAQEF\n' + + 'AAOCAQ8AMIIBCgKCAQEAr5u9OuLL/OF/fBNUX2kINJLzFl4DnmrhnLuSeSnBPgbb\n' + + 'qddjf5EFFJBfv7IYiIWEFPDbDG5hoBwgMup5bZDbas+ZTJTotnnxVJTQ6wlhTmns\n' + + 'eHECcg2pqGIKGrxZfbQhlj08/4nNAPvyYCTS0bEcmQ1emuDPyvJBYDDLDU6AbCB5\n' + + '6Z7YKFQPTiCBblvvNzchjLWF9IpkqiTsPHiEt21sAdABxj9ityStV3ja/W9BfgxH\n' + + 'wzABSTAQT6FbDwmQMo7dcFOPRX+hewQSic2Rn1XYjmNYzgEHisdUsH7eeXREAcTw\n' + + '61TRvaLH8AiOWBnTEJXPAe6wYfrcSd1pD0MXpoB62wIDAQABo2YwZDAOBgNVHQ8B\n' + + 'Af8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUytwMiomQOgX5\n' + + 'Ichd+2lDWRUhkikwHwYDVR0jBBgwFoAUc19g2LzLA5j0Kxc0LjZapmD/vB8wDQYJ\n' + + 'KoZIhvcNAQELBQADggEBACf6lRDpfCD7BFRqiWM45hqIzffIaysmVfr+Jr+fBTjP\n' + + 'uYe/ba1omSrNGG23bOcT9LJ8hkQJ9d+FxUwYyICQNWOy6ejicm4z0C3VhphbTPqj\n' + + 'yjpt9nG56IAcV8BcRJh4o/2IfLNzC/dVuYJV8wj7XzwlvjysenwdrJCoLadkTr1h\n' + + 'eIdG6Le07sB9IxrGJL9e04afk37h7c8ESGSE4E+oS4JQEi3ATq8ne1B9DQ9SasXi\n' + + 'IRmhNAaISDzOPdyLXi9N9V9Lwe/DHcja7hgLGYx3UqfjhLhOKwp8HtoZORixAmOI\n' + + 'HfILgNmwyugAbuZoCazSKKBhQ0wgO0WZ66ZKTMG8Oho=\n' + + '-----END CERTIFICATE-----\n', + + /** + * Amazon RDS ap-southeast-2 certificate CA 2019 to 2024 + * + * CN = Amazon RDS ap-southeast-2 2019 CA + * OU = Amazon RDS + * O = Amazon Web Services, Inc. + * L = Seattle + * ST = Washington + * C = US + * P = 2019-09-16T19:53:47Z/2024-08-22T17:08:50Z + * F = D5:D4:51:83:D9:A3:AC:47:B0:0A:5A:77:D8:A0:79:A9:6A:3F:6D:96 + */ + '-----BEGIN CERTIFICATE-----\n' + + 'MIIEDDCCAvSgAwIBAgICEkYwDQYJKoZIhvcNAQELBQAwgY8xCzAJBgNVBAYTAlVT\n' + + 'MRAwDgYDVQQHDAdTZWF0dGxlMRMwEQYDVQQIDApXYXNoaW5ndG9uMSIwIAYDVQQK\n' + + 'DBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJbmMuMRMwEQYDVQQLDApBbWF6b24gUkRT\n' + + 'MSAwHgYDVQQDDBdBbWF6b24gUkRTIFJvb3QgMjAxOSBDQTAeFw0xOTA5MTYxOTUz\n' + + 'NDdaFw0yNDA4MjIxNzA4NTBaMIGZMQswCQYDVQQGEwJVUzETMBEGA1UECAwKV2Fz\n' + + 'aGluZ3RvbjEQMA4GA1UEBwwHU2VhdHRsZTEiMCAGA1UECgwZQW1hem9uIFdlYiBT\n' + + 'ZXJ2aWNlcywgSW5jLjETMBEGA1UECwwKQW1hem9uIFJEUzEqMCgGA1UEAwwhQW1h\n' + + 'em9uIFJEUyBhcC1zb3V0aGVhc3QtMiAyMDE5IENBMIIBIjANBgkqhkiG9w0BAQEF\n' + + 'AAOCAQ8AMIIBCgKCAQEAufodI2Flker8q7PXZG0P0vmFSlhQDw907A6eJuF/WeMo\n' + + 'GHnll3b4S6nC3oRS3nGeRMHbyU2KKXDwXNb3Mheu+ox+n5eb/BJ17eoj9HbQR1cd\n' + + 'gEkIciiAltf8gpMMQH4anP7TD+HNFlZnP7ii3geEJB2GGXSxgSWvUzH4etL67Zmn\n' + + 'TpGDWQMB0T8lK2ziLCMF4XAC/8xDELN/buHCNuhDpxpPebhct0T+f6Arzsiswt2j\n' + + '7OeNeLLZwIZvVwAKF7zUFjC6m7/VmTQC8nidVY559D6l0UhhU0Co/txgq3HVsMOH\n' + + 'PbxmQUwJEKAzQXoIi+4uZzHFZrvov/nDTNJUhC6DqwIDAQABo2YwZDAOBgNVHQ8B\n' + + 'Af8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUwaZpaCme+EiV\n' + + 'M5gcjeHZSTgOn4owHwYDVR0jBBgwFoAUc19g2LzLA5j0Kxc0LjZapmD/vB8wDQYJ\n' + + 'KoZIhvcNAQELBQADggEBAAR6a2meCZuXO2TF9bGqKGtZmaah4pH2ETcEVUjkvXVz\n' + + 'sl+ZKbYjrun+VkcMGGKLUjS812e7eDF726ptoku9/PZZIxlJB0isC/0OyixI8N4M\n' + + 'NsEyvp52XN9QundTjkl362bomPnHAApeU0mRbMDRR2JdT70u6yAzGLGsUwMkoNnw\n' + + '1VR4XKhXHYGWo7KMvFrZ1KcjWhubxLHxZWXRulPVtGmyWg/MvE6KF+2XMLhojhUL\n' + + '+9jB3Fpn53s6KMx5tVq1x8PukHmowcZuAF8k+W4gk8Y68wIwynrdZrKRyRv6CVtR\n' + + 'FZ8DeJgoNZT3y/GT254VqMxxfuy2Ccb/RInd16tEvVk=\n' + + '-----END CERTIFICATE-----\n', + + /** + * Amazon RDS ca-central-1 certificate CA 2019 to 2024 + * + * CN = Amazon RDS ca-central-1 2019 CA + * OU = Amazon RDS + * O = Amazon Web Services, Inc. + * L = Seattle + * ST = Washington + * C = US + * P = 2019-09-10T20:52:25Z/2024-08-22T17:08:50Z + * F = A1:03:46:F2:BB:29:BF:4F:EC:04:7E:82:9A:A6:C0:11:4D:AB:82:25 + */ + '-----BEGIN CERTIFICATE-----\n' + + 'MIIECjCCAvKgAwIBAgICEzUwDQYJKoZIhvcNAQELBQAwgY8xCzAJBgNVBAYTAlVT\n' + + 'MRAwDgYDVQQHDAdTZWF0dGxlMRMwEQYDVQQIDApXYXNoaW5ndG9uMSIwIAYDVQQK\n' + + 'DBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJbmMuMRMwEQYDVQQLDApBbWF6b24gUkRT\n' + + 'MSAwHgYDVQQDDBdBbWF6b24gUkRTIFJvb3QgMjAxOSBDQTAeFw0xOTA5MTAyMDUy\n' + + 'MjVaFw0yNDA4MjIxNzA4NTBaMIGXMQswCQYDVQQGEwJVUzETMBEGA1UECAwKV2Fz\n' + + 'aGluZ3RvbjEQMA4GA1UEBwwHU2VhdHRsZTEiMCAGA1UECgwZQW1hem9uIFdlYiBT\n' + + 'ZXJ2aWNlcywgSW5jLjETMBEGA1UECwwKQW1hem9uIFJEUzEoMCYGA1UEAwwfQW1h\n' + + 'em9uIFJEUyBjYS1jZW50cmFsLTEgMjAxOSBDQTCCASIwDQYJKoZIhvcNAQEBBQAD\n' + + 'ggEPADCCAQoCggEBAOxHqdcPSA2uBjsCP4DLSlqSoPuQ/X1kkJLusVRKiQE2zayB\n' + + 'viuCBt4VB9Qsh2rW3iYGM+usDjltGnI1iUWA5KHcvHszSMkWAOYWLiMNKTlg6LCp\n' + + 'XnE89tvj5dIH6U8WlDvXLdjB/h30gW9JEX7S8supsBSci2GxEzb5mRdKaDuuF/0O\n' + + 'qvz4YE04pua3iZ9QwmMFuTAOYzD1M72aOpj+7Ac+YLMM61qOtU+AU6MndnQkKoQi\n' + + 'qmUN2A9IFaqHFzRlSdXwKCKUA4otzmz+/N3vFwjb5F4DSsbsrMfjeHMo6o/nb6Nh\n' + + 'YDb0VJxxPee6TxSuN7CQJ2FxMlFUezcoXqwqXD0CAwEAAaNmMGQwDgYDVR0PAQH/\n' + + 'BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFDGGpon9WfIpsggE\n' + + 'CxHq8hZ7E2ESMB8GA1UdIwQYMBaAFHNfYNi8ywOY9CsXNC42WqZg/7wfMA0GCSqG\n' + + 'SIb3DQEBCwUAA4IBAQAvpeQYEGZvoTVLgV9rd2+StPYykMsmFjWQcyn3dBTZRXC2\n' + + 'lKq7QhQczMAOhEaaN29ZprjQzsA2X/UauKzLR2Uyqc2qOeO9/YOl0H3qauo8C/W9\n' + + 'r8xqPbOCDLEXlOQ19fidXyyEPHEq5WFp8j+fTh+s8WOx2M7IuC0ANEetIZURYhSp\n' + + 'xl9XOPRCJxOhj7JdelhpweX0BJDNHeUFi0ClnFOws8oKQ7sQEv66d5ddxqqZ3NVv\n' + + 'RbCvCtEutQMOUMIuaygDlMn1anSM8N7Wndx8G6+Uy67AnhjGx7jw/0YPPxopEj6x\n' + + 'JXP8j0sJbcT9K/9/fPVLNT25RvQ/93T2+IQL4Ca2\n' + + '-----END CERTIFICATE-----\n', + + /** + * Amazon RDS eu-central-1 certificate CA 2019 to 2024 + * + * CN = Amazon RDS eu-central-1 2019 CA + * OU = Amazon RDS + * O = Amazon Web Services, Inc. + * L = Seattle + * ST = Washington + * C = US + * P = 2019-09-11T19:36:20Z/2024-08-22T17:08:50Z + * F = 53:46:18:4A:42:65:A2:8C:5F:5B:0A:AD:E2:2C:80:E5:E6:8A:6D:2F + */ + '-----BEGIN CERTIFICATE-----\n' + + 'MIIECjCCAvKgAwIBAgICV2YwDQYJKoZIhvcNAQELBQAwgY8xCzAJBgNVBAYTAlVT\n' + + 'MRAwDgYDVQQHDAdTZWF0dGxlMRMwEQYDVQQIDApXYXNoaW5ndG9uMSIwIAYDVQQK\n' + + 'DBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJbmMuMRMwEQYDVQQLDApBbWF6b24gUkRT\n' + + 'MSAwHgYDVQQDDBdBbWF6b24gUkRTIFJvb3QgMjAxOSBDQTAeFw0xOTA5MTExOTM2\n' + + 'MjBaFw0yNDA4MjIxNzA4NTBaMIGXMQswCQYDVQQGEwJVUzETMBEGA1UECAwKV2Fz\n' + + 'aGluZ3RvbjEQMA4GA1UEBwwHU2VhdHRsZTEiMCAGA1UECgwZQW1hem9uIFdlYiBT\n' + + 'ZXJ2aWNlcywgSW5jLjETMBEGA1UECwwKQW1hem9uIFJEUzEoMCYGA1UEAwwfQW1h\n' + + 'em9uIFJEUyBldS1jZW50cmFsLTEgMjAxOSBDQTCCASIwDQYJKoZIhvcNAQEBBQAD\n' + + 'ggEPADCCAQoCggEBAMEx54X2pHVv86APA0RWqxxRNmdkhAyp2R1cFWumKQRofoFv\n' + + 'n+SPXdkpIINpMuEIGJANozdiEz7SPsrAf8WHyD93j/ZxrdQftRcIGH41xasetKGl\n' + + 'I67uans8d+pgJgBKGb/Z+B5m+UsIuEVekpvgpwKtmmaLFC/NCGuSsJoFsRqoa6Gh\n' + + 'm34W6yJoY87UatddCqLY4IIXaBFsgK9Q/wYzYLbnWM6ZZvhJ52VMtdhcdzeTHNW0\n' + + '5LGuXJOF7Ahb4JkEhoo6TS2c0NxB4l4MBfBPgti+O7WjR3FfZHpt18A6Zkq6A2u6\n' + + 'D/oTSL6c9/3sAaFTFgMyL3wHb2YlW0BPiljZIqECAwEAAaNmMGQwDgYDVR0PAQH/\n' + + 'BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFOcAToAc6skWffJa\n' + + 'TnreaswAfrbcMB8GA1UdIwQYMBaAFHNfYNi8ywOY9CsXNC42WqZg/7wfMA0GCSqG\n' + + 'SIb3DQEBCwUAA4IBAQA1d0Whc1QtspK496mFWfFEQNegLh0a9GWYlJm+Htcj5Nxt\n' + + 'DAIGXb+8xrtOZFHmYP7VLCT5Zd2C+XytqseK/+s07iAr0/EPF+O2qcyQWMN5KhgE\n' + + 'cXw2SwuP9FPV3i+YAm11PBVeenrmzuk9NrdHQ7TxU4v7VGhcsd2C++0EisrmquWH\n' + + 'mgIfmVDGxphwoES52cY6t3fbnXmTkvENvR+h3rj+fUiSz0aSo+XZUGHPgvuEKM/W\n' + + 'CBD9Smc9CBoBgvy7BgHRgRUmwtABZHFUIEjHI5rIr7ZvYn+6A0O6sogRfvVYtWFc\n' + + 'qpyrW1YX8mD0VlJ8fGKM3G+aCOsiiPKDV/Uafrm+\n' + + '-----END CERTIFICATE-----\n', + + /** + * Amazon RDS eu-north-1 certificate CA 2019 to 2024 + * + * CN = Amazon RDS eu-north-1 2019 CA + * OU = Amazon RDS + * O = Amazon Web Services, Inc. + * L = Seattle + * ST = Washington + * C = US + * P = 2019-09-12T18:19:44Z/2024-08-22T17:08:50Z + * F = D0:CA:9C:6E:47:4C:4F:DB:85:28:03:4A:60:AC:14:E0:E6:DF:D4:42 + */ + '-----BEGIN CERTIFICATE-----\n' + + 'MIIECDCCAvCgAwIBAgICGAcwDQYJKoZIhvcNAQELBQAwgY8xCzAJBgNVBAYTAlVT\n' + + 'MRAwDgYDVQQHDAdTZWF0dGxlMRMwEQYDVQQIDApXYXNoaW5ndG9uMSIwIAYDVQQK\n' + + 'DBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJbmMuMRMwEQYDVQQLDApBbWF6b24gUkRT\n' + + 'MSAwHgYDVQQDDBdBbWF6b24gUkRTIFJvb3QgMjAxOSBDQTAeFw0xOTA5MTIxODE5\n' + + 'NDRaFw0yNDA4MjIxNzA4NTBaMIGVMQswCQYDVQQGEwJVUzETMBEGA1UECAwKV2Fz\n' + + 'aGluZ3RvbjEQMA4GA1UEBwwHU2VhdHRsZTEiMCAGA1UECgwZQW1hem9uIFdlYiBT\n' + + 'ZXJ2aWNlcywgSW5jLjETMBEGA1UECwwKQW1hem9uIFJEUzEmMCQGA1UEAwwdQW1h\n' + + 'em9uIFJEUyBldS1ub3J0aC0xIDIwMTkgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IB\n' + + 'DwAwggEKAoIBAQCiIYnhe4UNBbdBb/nQxl5giM0XoVHWNrYV5nB0YukA98+TPn9v\n' + + 'Aoj1RGYmtryjhrf01Kuv8SWO+Eom95L3zquoTFcE2gmxCfk7bp6qJJ3eHOJB+QUO\n' + + 'XsNRh76fwDzEF1yTeZWH49oeL2xO13EAx4PbZuZpZBttBM5zAxgZkqu4uWQczFEs\n' + + 'JXfla7z2fvWmGcTagX10O5C18XaFroV0ubvSyIi75ue9ykg/nlFAeB7O0Wxae88e\n' + + 'uhiBEFAuLYdqWnsg3459NfV8Yi1GnaitTym6VI3tHKIFiUvkSiy0DAlAGV2iiyJE\n' + + 'q+DsVEO4/hSINJEtII4TMtysOsYPpINqeEzRAgMBAAGjZjBkMA4GA1UdDwEB/wQE\n' + + 'AwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBRR0UpnbQyjnHChgmOc\n' + + 'hnlc0PogzTAfBgNVHSMEGDAWgBRzX2DYvMsDmPQrFzQuNlqmYP+8HzANBgkqhkiG\n' + + '9w0BAQsFAAOCAQEAKJD4xVzSf4zSGTBJrmamo86jl1NHQxXUApAZuBZEc8tqC6TI\n' + + 'T5CeoSr9CMuVC8grYyBjXblC4OsM5NMvmsrXl/u5C9dEwtBFjo8mm53rOOIm1fxl\n' + + 'I1oYB/9mtO9ANWjkykuLzWeBlqDT/i7ckaKwalhLODsRDO73vRhYNjsIUGloNsKe\n' + + 'pxw3dzHwAZx4upSdEVG4RGCZ1D0LJ4Gw40OfD69hfkDfRVVxKGrbEzqxXRvovmDc\n' + + 'tKLdYZO/6REoca36v4BlgIs1CbUXJGLSXUwtg7YXGLSVBJ/U0+22iGJmBSNcoyUN\n' + + 'cjPFD9JQEhDDIYYKSGzIYpvslvGc4T5ISXFiuQ==\n' + + '-----END CERTIFICATE-----\n', + + /** + * Amazon RDS eu-west-1 certificate CA 2019 to 2024 + * + * CN = Amazon RDS eu-west-1 2019 CA + * OU = Amazon RDS + * O = Amazon Web Services, Inc. + * L = Seattle + * ST = Washington + * C = US + * P = 2019-09-11T17:31:48Z/2024-08-22T17:08:50Z + * F = 2D:1A:A6:3E:0D:EB:D6:26:03:3E:A1:8A:0A:DF:14:80:78:EC:B6:63 + */ + '-----BEGIN CERTIFICATE-----\n' + + 'MIIEBzCCAu+gAwIBAgICYpgwDQYJKoZIhvcNAQELBQAwgY8xCzAJBgNVBAYTAlVT\n' + + 'MRAwDgYDVQQHDAdTZWF0dGxlMRMwEQYDVQQIDApXYXNoaW5ndG9uMSIwIAYDVQQK\n' + + 'DBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJbmMuMRMwEQYDVQQLDApBbWF6b24gUkRT\n' + + 'MSAwHgYDVQQDDBdBbWF6b24gUkRTIFJvb3QgMjAxOSBDQTAeFw0xOTA5MTExNzMx\n' + + 'NDhaFw0yNDA4MjIxNzA4NTBaMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECAwKV2Fz\n' + + 'aGluZ3RvbjEQMA4GA1UEBwwHU2VhdHRsZTEiMCAGA1UECgwZQW1hem9uIFdlYiBT\n' + + 'ZXJ2aWNlcywgSW5jLjETMBEGA1UECwwKQW1hem9uIFJEUzElMCMGA1UEAwwcQW1h\n' + + 'em9uIFJEUyBldS13ZXN0LTEgMjAxOSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP\n' + + 'ADCCAQoCggEBAMk3YdSZ64iAYp6MyyKtYJtNzv7zFSnnNf6vv0FB4VnfITTMmOyZ\n' + + 'LXqKAT2ahZ00hXi34ewqJElgU6eUZT/QlzdIu359TEZyLVPwURflL6SWgdG01Q5X\n' + + 'O++7fSGcBRyIeuQWs9FJNIIqK8daF6qw0Rl5TXfu7P9dBc3zkgDXZm2DHmxGDD69\n' + + '7liQUiXzoE1q2Z9cA8+jirDioJxN9av8hQt12pskLQumhlArsMIhjhHRgF03HOh5\n' + + 'tvi+RCfihVOxELyIRTRpTNiIwAqfZxxTWFTgfn+gijTmd0/1DseAe82aYic8JbuS\n' + + 'EMbrDduAWsqrnJ4GPzxHKLXX0JasCUcWyMECAwEAAaNmMGQwDgYDVR0PAQH/BAQD\n' + + 'AgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFPLtsq1NrwJXO13C9eHt\n' + + 'sLY11AGwMB8GA1UdIwQYMBaAFHNfYNi8ywOY9CsXNC42WqZg/7wfMA0GCSqGSIb3\n' + + 'DQEBCwUAA4IBAQAnWBKj5xV1A1mYd0kIgDdkjCwQkiKF5bjIbGkT3YEFFbXoJlSP\n' + + '0lZZ/hDaOHI8wbLT44SzOvPEEmWF9EE7SJzkvSdQrUAWR9FwDLaU427ALI3ngNHy\n' + + 'lGJ2hse1fvSRNbmg8Sc9GBv8oqNIBPVuw+AJzHTacZ1OkyLZrz1c1QvwvwN2a+Jd\n' + + 'vH0V0YIhv66llKcYDMUQJAQi4+8nbRxXWv6Gq3pvrFoorzsnkr42V3JpbhnYiK+9\n' + + 'nRKd4uWl62KRZjGkfMbmsqZpj2fdSWMY1UGyN1k+kDmCSWYdrTRDP0xjtIocwg+A\n' + + 'J116n4hV/5mbA0BaPiS2krtv17YAeHABZcvz\n' + + '-----END CERTIFICATE-----\n', + + /** + * Amazon RDS eu-west-2 certificate CA 2019 to 2024 + * + * CN = Amazon RDS eu-west-2 2019 CA + * OU = Amazon RDS + * O = Amazon Web Services, Inc. + * L = Seattle + * ST = Washington + * C = US + * P = 2019-09-12T21:32:32Z/2024-08-22T17:08:50Z + * F = 60:65:44:F4:74:6E:2E:29:50:19:38:7C:4B:BE:18:B9:5B:D4:CD:23 + */ + '-----BEGIN CERTIFICATE-----\n' + + 'MIIEBzCCAu+gAwIBAgICZIEwDQYJKoZIhvcNAQELBQAwgY8xCzAJBgNVBAYTAlVT\n' + + 'MRAwDgYDVQQHDAdTZWF0dGxlMRMwEQYDVQQIDApXYXNoaW5ndG9uMSIwIAYDVQQK\n' + + 'DBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJbmMuMRMwEQYDVQQLDApBbWF6b24gUkRT\n' + + 'MSAwHgYDVQQDDBdBbWF6b24gUkRTIFJvb3QgMjAxOSBDQTAeFw0xOTA5MTIyMTMy\n' + + 'MzJaFw0yNDA4MjIxNzA4NTBaMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECAwKV2Fz\n' + + 'aGluZ3RvbjEQMA4GA1UEBwwHU2VhdHRsZTEiMCAGA1UECgwZQW1hem9uIFdlYiBT\n' + + 'ZXJ2aWNlcywgSW5jLjETMBEGA1UECwwKQW1hem9uIFJEUzElMCMGA1UEAwwcQW1h\n' + + 'em9uIFJEUyBldS13ZXN0LTIgMjAxOSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP\n' + + 'ADCCAQoCggEBALGiwqjiF7xIjT0Sx7zB3764K2T2a1DHnAxEOr+/EIftWKxWzT3u\n' + + 'PFwS2eEZcnKqSdRQ+vRzonLBeNLO4z8aLjQnNbkizZMBuXGm4BqRm1Kgq3nlLDQn\n' + + '7YqdijOq54SpShvR/8zsO4sgMDMmHIYAJJOJqBdaus2smRt0NobIKc0liy7759KB\n' + + '6kmQ47Gg+kfIwxrQA5zlvPLeQImxSoPi9LdbRoKvu7Iot7SOa+jGhVBh3VdqndJX\n' + + '7tm/saj4NE375csmMETFLAOXjat7zViMRwVorX4V6AzEg1vkzxXpA9N7qywWIT5Y\n' + + 'fYaq5M8i6vvLg0CzrH9fHORtnkdjdu1y+0MCAwEAAaNmMGQwDgYDVR0PAQH/BAQD\n' + + 'AgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFFOhOx1yt3Z7mvGB9jBv\n' + + '2ymdZwiOMB8GA1UdIwQYMBaAFHNfYNi8ywOY9CsXNC42WqZg/7wfMA0GCSqGSIb3\n' + + 'DQEBCwUAA4IBAQBehqY36UGDvPVU9+vtaYGr38dBbp+LzkjZzHwKT1XJSSUc2wqM\n' + + 'hnCIQKilonrTIvP1vmkQi8qHPvDRtBZKqvz/AErW/ZwQdZzqYNFd+BmOXaeZWV0Q\n' + + 'oHtDzXmcwtP8aUQpxN0e1xkWb1E80qoy+0uuRqb/50b/R4Q5qqSfJhkn6z8nwB10\n' + + '7RjLtJPrK8igxdpr3tGUzfAOyiPrIDncY7UJaL84GFp7WWAkH0WG3H8Y8DRcRXOU\n' + + 'mqDxDLUP3rNuow3jnGxiUY+gGX5OqaZg4f4P6QzOSmeQYs6nLpH0PiN00+oS1BbD\n' + + 'bpWdZEttILPI+vAYkU4QuBKKDjJL6HbSd+cn\n' + + '-----END CERTIFICATE-----\n', + + /** + * Amazon RDS eu-west-3 certificate CA 2019 to 2024 + * + * CN = Amazon RDS eu-west-3 2019 CA + * OU = Amazon RDS + * O = Amazon Web Services, Inc. + * L = Seattle + * ST = Washington + * C = US + * P = 2019-09-18T17:03:15Z/2024-08-22T17:08:50Z + * F = 6F:79:56:B0:74:9C:C6:3E:3B:50:26:C8:51:55:08:F0:BB:7E:32:04 + */ + '-----BEGIN CERTIFICATE-----\n' + + 'MIIEBzCCAu+gAwIBAgICJDQwDQYJKoZIhvcNAQELBQAwgY8xCzAJBgNVBAYTAlVT\n' + + 'MRAwDgYDVQQHDAdTZWF0dGxlMRMwEQYDVQQIDApXYXNoaW5ndG9uMSIwIAYDVQQK\n' + + 'DBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJbmMuMRMwEQYDVQQLDApBbWF6b24gUkRT\n' + + 'MSAwHgYDVQQDDBdBbWF6b24gUkRTIFJvb3QgMjAxOSBDQTAeFw0xOTA5MTgxNzAz\n' + + 'MTVaFw0yNDA4MjIxNzA4NTBaMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECAwKV2Fz\n' + + 'aGluZ3RvbjEQMA4GA1UEBwwHU2VhdHRsZTEiMCAGA1UECgwZQW1hem9uIFdlYiBT\n' + + 'ZXJ2aWNlcywgSW5jLjETMBEGA1UECwwKQW1hem9uIFJEUzElMCMGA1UEAwwcQW1h\n' + + 'em9uIFJEUyBldS13ZXN0LTMgMjAxOSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP\n' + + 'ADCCAQoCggEBAL9bL7KE0n02DLVtlZ2PL+g/BuHpMYFq2JnE2RgompGurDIZdjmh\n' + + '1pxfL3nT+QIVMubuAOy8InRfkRxfpxyjKYdfLJTPJG+jDVL+wDcPpACFVqoV7Prg\n' + + 'pVYEV0lc5aoYw4bSeYFhdzgim6F8iyjoPnObjll9mo4XsHzSoqJLCd0QC+VG9Fw2\n' + + 'q+GDRZrLRmVM2oNGDRbGpGIFg77aRxRapFZa8SnUgs2AqzuzKiprVH5i0S0M6dWr\n' + + 'i+kk5epmTtkiDHceX+dP/0R1NcnkCPoQ9TglyXyPdUdTPPRfKCq12dftqll+u4mV\n' + + 'ARdN6WFjovxax8EAP2OAUTi1afY+1JFMj+sCAwEAAaNmMGQwDgYDVR0PAQH/BAQD\n' + + 'AgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFLfhrbrO5exkCVgxW0x3\n' + + 'Y2mAi8lNMB8GA1UdIwQYMBaAFHNfYNi8ywOY9CsXNC42WqZg/7wfMA0GCSqGSIb3\n' + + 'DQEBCwUAA4IBAQAigQ5VBNGyw+OZFXwxeJEAUYaXVoP/qrhTOJ6mCE2DXUVEoJeV\n' + + 'SxScy/TlFA9tJXqmit8JH8VQ/xDL4ubBfeMFAIAo4WzNWDVoeVMqphVEcDWBHsI1\n' + + 'AETWzfsapRS9yQekOMmxg63d/nV8xewIl8aNVTHdHYXMqhhik47VrmaVEok1UQb3\n' + + 'O971RadLXIEbVd9tjY5bMEHm89JsZDnDEw1hQXBb67Elu64OOxoKaHBgUH8AZn/2\n' + + 'zFsL1ynNUjOhCSAA15pgd1vjwc0YsBbAEBPcHBWYBEyME6NLNarjOzBl4FMtATSF\n' + + 'wWCKRGkvqN8oxYhwR2jf2rR5Mu4DWkK5Q8Ep\n' + + '-----END CERTIFICATE-----\n', + + /** + * Amazon RDS me-south-1 certificate CA 2019 to 2024 + * + * CN = Amazon RDS me-south-1 Root CA + * OU = Amazon RDS + * O = Amazon Web Services, Inc. + * L = Seattle + * ST = Washington + * C = US + * P = 2019-05-10T21:48:27Z/2024-05-08T21:48:27Z + * F = 8A:69:D7:00:FB:5D:62:9C:B0:D1:75:6F:B7:B6:38:AA:76:C4:BD:1F + */ + '-----BEGIN CERTIFICATE-----\n' + + 'MIIEEjCCAvqgAwIBAgIJANew34ehz5l8MA0GCSqGSIb3DQEBCwUAMIGVMQswCQYD\n' + + 'VQQGEwJVUzEQMA4GA1UEBwwHU2VhdHRsZTETMBEGA1UECAwKV2FzaGluZ3RvbjEi\n' + + 'MCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywgSW5jLjETMBEGA1UECwwKQW1h\n' + + 'em9uIFJEUzEmMCQGA1UEAwwdQW1hem9uIFJEUyBtZS1zb3V0aC0xIFJvb3QgQ0Ew\n' + + 'HhcNMTkwNTEwMjE0ODI3WhcNMjQwNTA4MjE0ODI3WjCBlTELMAkGA1UEBhMCVVMx\n' + + 'EDAOBgNVBAcMB1NlYXR0bGUxEzARBgNVBAgMCldhc2hpbmd0b24xIjAgBgNVBAoM\n' + + 'GUFtYXpvbiBXZWIgU2VydmljZXMsIEluYy4xEzARBgNVBAsMCkFtYXpvbiBSRFMx\n' + + 'JjAkBgNVBAMMHUFtYXpvbiBSRFMgbWUtc291dGgtMSBSb290IENBMIIBIjANBgkq\n' + + 'hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp7BYV88MukcY+rq0r79+C8UzkT30fEfT\n' + + 'aPXbx1d6M7uheGN4FMaoYmL+JE1NZPaMRIPTHhFtLSdPccInvenRDIatcXX+jgOk\n' + + 'UA6lnHQ98pwN0pfDUyz/Vph4jBR9LcVkBbe0zdoKKp+HGbMPRU0N2yNrog9gM5O8\n' + + 'gkU/3O2csJ/OFQNnj4c2NQloGMUpEmedwJMOyQQfcUyt9CvZDfIPNnheUS29jGSw\n' + + 'ERpJe/AENu8Pxyc72jaXQuD+FEi2Ck6lBkSlWYQFhTottAeGvVFNCzKszCntrtqd\n' + + 'rdYUwurYsLTXDHv9nW2hfDUQa0mhXf9gNDOBIVAZugR9NqNRNyYLHQIDAQABo2Mw\n' + + 'YTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU54cf\n' + + 'DjgwBx4ycBH8+/r8WXdaiqYwHwYDVR0jBBgwFoAU54cfDjgwBx4ycBH8+/r8WXda\n' + + 'iqYwDQYJKoZIhvcNAQELBQADggEBAIIMTSPx/dR7jlcxggr+O6OyY49Rlap2laKA\n' + + 'eC/XI4ySP3vQkIFlP822U9Kh8a9s46eR0uiwV4AGLabcu0iKYfXjPkIprVCqeXV7\n' + + 'ny9oDtrbflyj7NcGdZLvuzSwgl9SYTJp7PVCZtZutsPYlbJrBPHwFABvAkMvRtDB\n' + + 'hitIg4AESDGPoCl94sYHpfDfjpUDMSrAMDUyO6DyBdZH5ryRMAs3lGtsmkkNUrso\n' + + 'aTW6R05681Z0mvkRdb+cdXtKOSuDZPoe2wJJIaz3IlNQNSrB5TImMYgmt6iAsFhv\n' + + '3vfTSTKrZDNTJn4ybG6pq1zWExoXsktZPylJly6R3RBwV6nwqBM=\n' + + '-----END CERTIFICATE-----\n', + + /** + * Amazon RDS sa-east-1 certificate CA 2019 to 2024 + * + * CN = Amazon RDS sa-east-1 2019 CA + * OU = Amazon RDS + * O = Amazon Web Services, Inc. + * L = Seattle + * ST = Washington + * C = US + * P = 2019-09-05T18:46:29Z/2024-08-22T17:08:50Z + * F = 8C:34:0F:AA:FB:10:80:9C:05:CE:D7:BF:0B:12:4D:07:42:39:74:7A + */ + '-----BEGIN CERTIFICATE-----\n' + + 'MIIEBzCCAu+gAwIBAgICQ2QwDQYJKoZIhvcNAQELBQAwgY8xCzAJBgNVBAYTAlVT\n' + + 'MRAwDgYDVQQHDAdTZWF0dGxlMRMwEQYDVQQIDApXYXNoaW5ndG9uMSIwIAYDVQQK\n' + + 'DBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJbmMuMRMwEQYDVQQLDApBbWF6b24gUkRT\n' + + 'MSAwHgYDVQQDDBdBbWF6b24gUkRTIFJvb3QgMjAxOSBDQTAeFw0xOTA5MDUxODQ2\n' + + 'MjlaFw0yNDA4MjIxNzA4NTBaMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECAwKV2Fz\n' + + 'aGluZ3RvbjEQMA4GA1UEBwwHU2VhdHRsZTEiMCAGA1UECgwZQW1hem9uIFdlYiBT\n' + + 'ZXJ2aWNlcywgSW5jLjETMBEGA1UECwwKQW1hem9uIFJEUzElMCMGA1UEAwwcQW1h\n' + + 'em9uIFJEUyBzYS1lYXN0LTEgMjAxOSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP\n' + + 'ADCCAQoCggEBAMMvR+ReRnOzqJzoaPipNTt1Z2VA968jlN1+SYKUrYM3No+Vpz0H\n' + + 'M6Tn0oYB66ByVsXiGc28ulsqX1HbHsxqDPwvQTKvO7SrmDokoAkjJgLocOLUAeld\n' + + '5AwvUjxGRP6yY90NV7X786MpnYb2Il9DIIaV9HjCmPt+rjy2CZjS0UjPjCKNfB8J\n' + + 'bFjgW6GGscjeyGb/zFwcom5p4j0rLydbNaOr9wOyQrtt3ZQWLYGY9Zees/b8pmcc\n' + + 'Jt+7jstZ2UMV32OO/kIsJ4rMUn2r/uxccPwAc1IDeRSSxOrnFKhW3Cu69iB3bHp7\n' + + 'JbawY12g7zshE4I14sHjv3QoXASoXjx4xgMCAwEAAaNmMGQwDgYDVR0PAQH/BAQD\n' + + 'AgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFI1Fc/Ql2jx+oJPgBVYq\n' + + 'ccgP0pQ8MB8GA1UdIwQYMBaAFHNfYNi8ywOY9CsXNC42WqZg/7wfMA0GCSqGSIb3\n' + + 'DQEBCwUAA4IBAQB4VVVabVp70myuYuZ3vltQIWqSUMhkaTzehMgGcHjMf9iLoZ/I\n' + + '93KiFUSGnek5cRePyS9wcpp0fcBT3FvkjpUdCjVtdttJgZFhBxgTd8y26ImdDDMR\n' + + '4+BUuhI5msvjL08f+Vkkpu1GQcGmyFVPFOy/UY8iefu+QyUuiBUnUuEDd49Hw0Fn\n' + + '/kIPII6Vj82a2mWV/Q8e+rgN8dIRksRjKI03DEoP8lhPlsOkhdwU6Uz9Vu6NOB2Q\n' + + 'Ls1kbcxAc7cFSyRVJEhh12Sz9d0q/CQSTFsVJKOjSNQBQfVnLz1GwO/IieUEAr4C\n' + + 'jkTntH0r1LX5b/GwN4R887LvjAEdTbg1his7\n' + + '-----END CERTIFICATE-----\n', + + /** + * Amazon RDS us-east-1 certificate CA 2019 to 2024 + * + * CN = Amazon RDS us-east-1 2019 CA + * OU = Amazon RDS + * O = Amazon Web Services, Inc. + * L = Seattle + * ST = Washington + * C = US + * P = 2019-09-19T18:16:53Z/2024-08-22T17:08:50Z + * F = F0:ED:82:3E:D1:44:47:BA:B5:57:FD:F3:E4:92:74:66:98:8C:1C:78 + */ + '-----BEGIN CERTIFICATE-----\n' + + 'MIIEBzCCAu+gAwIBAgICJVUwDQYJKoZIhvcNAQELBQAwgY8xCzAJBgNVBAYTAlVT\n' + + 'MRAwDgYDVQQHDAdTZWF0dGxlMRMwEQYDVQQIDApXYXNoaW5ndG9uMSIwIAYDVQQK\n' + + 'DBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJbmMuMRMwEQYDVQQLDApBbWF6b24gUkRT\n' + + 'MSAwHgYDVQQDDBdBbWF6b24gUkRTIFJvb3QgMjAxOSBDQTAeFw0xOTA5MTkxODE2\n' + + 'NTNaFw0yNDA4MjIxNzA4NTBaMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECAwKV2Fz\n' + + 'aGluZ3RvbjEQMA4GA1UEBwwHU2VhdHRsZTEiMCAGA1UECgwZQW1hem9uIFdlYiBT\n' + + 'ZXJ2aWNlcywgSW5jLjETMBEGA1UECwwKQW1hem9uIFJEUzElMCMGA1UEAwwcQW1h\n' + + 'em9uIFJEUyB1cy1lYXN0LTEgMjAxOSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP\n' + + 'ADCCAQoCggEBAM3i/k2u6cqbMdcISGRvh+m+L0yaSIoOXjtpNEoIftAipTUYoMhL\n' + + 'InXGlQBVA4shkekxp1N7HXe1Y/iMaPEyb3n+16pf3vdjKl7kaSkIhjdUz3oVUEYt\n' + + 'i8Z/XeJJ9H2aEGuiZh3kHixQcZczn8cg3dA9aeeyLSEnTkl/npzLf//669Ammyhs\n' + + 'XcAo58yvT0D4E0D/EEHf2N7HRX7j/TlyWvw/39SW0usiCrHPKDLxByLojxLdHzso\n' + + 'QIp/S04m+eWn6rmD+uUiRteN1hI5ncQiA3wo4G37mHnUEKo6TtTUh+sd/ku6a8HK\n' + + 'glMBcgqudDI90s1OpuIAWmuWpY//8xEG2YECAwEAAaNmMGQwDgYDVR0PAQH/BAQD\n' + + 'AgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFPqhoWZcrVY9mU7tuemR\n' + + 'RBnQIj1jMB8GA1UdIwQYMBaAFHNfYNi8ywOY9CsXNC42WqZg/7wfMA0GCSqGSIb3\n' + + 'DQEBCwUAA4IBAQB6zOLZ+YINEs72heHIWlPZ8c6WY8MDU+Be5w1M+BK2kpcVhCUK\n' + + 'PJO4nMXpgamEX8DIiaO7emsunwJzMSvavSPRnxXXTKIc0i/g1EbiDjnYX9d85DkC\n' + + 'E1LaAUCmCZBVi9fIe0H2r9whIh4uLWZA41oMnJx/MOmo3XyMfQoWcqaSFlMqfZM4\n' + + '0rNoB/tdHLNuV4eIdaw2mlHxdWDtF4oH+HFm+2cVBUVC1jXKrFv/euRVtsTT+A6i\n' + + 'h2XBHKxQ1Y4HgAn0jACP2QSPEmuoQEIa57bEKEcZsBR8SDY6ZdTd2HLRIApcCOSF\n' + + 'MRM8CKLeF658I0XgF8D5EsYoKPsA+74Z+jDH\n' + + '-----END CERTIFICATE-----\n', + + /** + * Amazon RDS us-east-2 certificate CA 2019 to 2024 + * + * CN = Amazon RDS us-east-2 2019 CA + * OU = Amazon RDS + * O = Amazon Web Services, Inc. + * L = Seattle + * ST = Washington + * C = US + * P = 2019-09-13T17:06:41Z/2024-08-22T17:08:50Z + * F = E9:FE:27:2A:A0:0F:CE:DF:AD:51:03:A6:94:F7:1F:6F:BD:1E:28:D3 + */ + '-----BEGIN CERTIFICATE-----\n' + + 'MIIECDCCAvCgAwIBAgIDAIVCMA0GCSqGSIb3DQEBCwUAMIGPMQswCQYDVQQGEwJV\n' + + 'UzEQMA4GA1UEBwwHU2VhdHRsZTETMBEGA1UECAwKV2FzaGluZ3RvbjEiMCAGA1UE\n' + + 'CgwZQW1hem9uIFdlYiBTZXJ2aWNlcywgSW5jLjETMBEGA1UECwwKQW1hem9uIFJE\n' + + 'UzEgMB4GA1UEAwwXQW1hem9uIFJEUyBSb290IDIwMTkgQ0EwHhcNMTkwOTEzMTcw\n' + + 'NjQxWhcNMjQwODIyMTcwODUwWjCBlDELMAkGA1UEBhMCVVMxEzARBgNVBAgMCldh\n' + + 'c2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUxIjAgBgNVBAoMGUFtYXpvbiBXZWIg\n' + + 'U2VydmljZXMsIEluYy4xEzARBgNVBAsMCkFtYXpvbiBSRFMxJTAjBgNVBAMMHEFt\n' + + 'YXpvbiBSRFMgdXMtZWFzdC0yIDIwMTkgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IB\n' + + 'DwAwggEKAoIBAQDE+T2xYjUbxOp+pv+gRA3FO24+1zCWgXTDF1DHrh1lsPg5k7ht\n' + + '2KPYzNc+Vg4E+jgPiW0BQnA6jStX5EqVh8BU60zELlxMNvpg4KumniMCZ3krtMUC\n' + + 'au1NF9rM7HBh+O+DYMBLK5eSIVt6lZosOb7bCi3V6wMLA8YqWSWqabkxwN4w0vXI\n' + + '8lu5uXXFRemHnlNf+yA/4YtN4uaAyd0ami9+klwdkZfkrDOaiy59haOeBGL8EB/c\n' + + 'dbJJlguHH5CpCscs3RKtOOjEonXnKXldxarFdkMzi+aIIjQ8GyUOSAXHtQHb3gZ4\n' + + 'nS6Ey0CMlwkB8vUObZU9fnjKJcL5QCQqOfwvAgMBAAGjZjBkMA4GA1UdDwEB/wQE\n' + + 'AwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBQUPuRHohPxx4VjykmH\n' + + '6usGrLL1ETAfBgNVHSMEGDAWgBRzX2DYvMsDmPQrFzQuNlqmYP+8HzANBgkqhkiG\n' + + '9w0BAQsFAAOCAQEAUdR9Vb3y33Yj6X6KGtuthZ08SwjImVQPtknzpajNE5jOJAh8\n' + + 'quvQnU9nlnMO85fVDU1Dz3lLHGJ/YG1pt1Cqq2QQ200JcWCvBRgdvH6MjHoDQpqZ\n' + + 'HvQ3vLgOGqCLNQKFuet9BdpsHzsctKvCVaeBqbGpeCtt3Hh/26tgx0rorPLw90A2\n' + + 'V8QSkZJjlcKkLa58N5CMM8Xz8KLWg3MZeT4DmlUXVCukqK2RGuP2L+aME8dOxqNv\n' + + 'OnOz1zrL5mR2iJoDpk8+VE/eBDmJX40IJk6jBjWoxAO/RXq+vBozuF5YHN1ujE92\n' + + 'tO8HItgTp37XT8bJBAiAnt5mxw+NLSqtxk2QdQ==\n' + + '-----END CERTIFICATE-----\n', + + /** + * Amazon RDS us-west-1 certificate CA 2019 to 2024 + * + * CN = Amazon RDS us-west-1 2019 CA + * OU = Amazon RDS + * O = Amazon Web Services, Inc. + * L = Seattle + * ST = Washington + * C = US + * P = 2019-09-06T17:40:21Z/2024-08-22T17:08:50Z + * F = 1C:9F:DF:84:E6:13:32:F3:91:12:2D:0D:A5:9A:16:5D:AC:DC:E8:93 + */ + '-----BEGIN CERTIFICATE-----\n' + + 'MIIECDCCAvCgAwIBAgIDAIkHMA0GCSqGSIb3DQEBCwUAMIGPMQswCQYDVQQGEwJV\n' + + 'UzEQMA4GA1UEBwwHU2VhdHRsZTETMBEGA1UECAwKV2FzaGluZ3RvbjEiMCAGA1UE\n' + + 'CgwZQW1hem9uIFdlYiBTZXJ2aWNlcywgSW5jLjETMBEGA1UECwwKQW1hem9uIFJE\n' + + 'UzEgMB4GA1UEAwwXQW1hem9uIFJEUyBSb290IDIwMTkgQ0EwHhcNMTkwOTA2MTc0\n' + + 'MDIxWhcNMjQwODIyMTcwODUwWjCBlDELMAkGA1UEBhMCVVMxEzARBgNVBAgMCldh\n' + + 'c2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUxIjAgBgNVBAoMGUFtYXpvbiBXZWIg\n' + + 'U2VydmljZXMsIEluYy4xEzARBgNVBAsMCkFtYXpvbiBSRFMxJTAjBgNVBAMMHEFt\n' + + 'YXpvbiBSRFMgdXMtd2VzdC0xIDIwMTkgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IB\n' + + 'DwAwggEKAoIBAQDD2yzbbAl77OofTghDMEf624OvU0eS9O+lsdO0QlbfUfWa1Kd6\n' + + '0WkgjkLZGfSRxEHMCnrv4UPBSK/Qwn6FTjkDLgemhqBtAnplN4VsoDL+BkRX4Wwq\n' + + '/dSQJE2b+0hm9w9UMVGFDEq1TMotGGTD2B71eh9HEKzKhGzqiNeGsiX4VV+LJzdH\n' + + 'uM23eGisNqmd4iJV0zcAZ+Gbh2zK6fqTOCvXtm7Idccv8vZZnyk1FiWl3NR4WAgK\n' + + 'AkvWTIoFU3Mt7dIXKKClVmvssG8WHCkd3Xcb4FHy/G756UZcq67gMMTX/9fOFM/v\n' + + 'l5C0+CHl33Yig1vIDZd+fXV1KZD84dEJfEvHAgMBAAGjZjBkMA4GA1UdDwEB/wQE\n' + + 'AwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBR+ap20kO/6A7pPxo3+\n' + + 'T3CfqZpQWjAfBgNVHSMEGDAWgBRzX2DYvMsDmPQrFzQuNlqmYP+8HzANBgkqhkiG\n' + + '9w0BAQsFAAOCAQEAHCJky2tPjPttlDM/RIqExupBkNrnSYnOK4kr9xJ3sl8UF2DA\n' + + 'PAnYsjXp3rfcjN/k/FVOhxwzi3cXJF/2Tjj39Bm/OEfYTOJDNYtBwB0VVH4ffa/6\n' + + 'tZl87jaIkrxJcreeeHqYMnIxeN0b/kliyA+a5L2Yb0VPjt9INq34QDc1v74FNZ17\n' + + '4z8nr1nzg4xsOWu0Dbjo966lm4nOYIGBRGOKEkHZRZ4mEiMgr3YLkv8gSmeitx57\n' + + 'Z6dVemNtUic/LVo5Iqw4n3TBS0iF2C1Q1xT/s3h+0SXZlfOWttzSluDvoMv5PvCd\n' + + 'pFjNn+aXLAALoihL1MJSsxydtsLjOBro5eK0Vw==\n' + + '-----END CERTIFICATE-----\n', + + /** + * Amazon RDS us-west-2 certificate CA 2019 to 2024 + * + * CN = Amazon RDS us-west-2 2019 CA + * OU = Amazon RDS + * O = Amazon Web Services, Inc. + * L = Seattle + * ST = Washington + * C = US + * P = 2019-09-16T18:21:15Z/2024-08-22T17:08:50Z + * F = C8:DE:1D:13:AD:35:9B:3D:EA:18:2A:DC:B4:79:6D:22:47:75:3C:4A + */ + '-----BEGIN CERTIFICATE-----\n' + + 'MIIEBzCCAu+gAwIBAgICUYkwDQYJKoZIhvcNAQELBQAwgY8xCzAJBgNVBAYTAlVT\n' + + 'MRAwDgYDVQQHDAdTZWF0dGxlMRMwEQYDVQQIDApXYXNoaW5ndG9uMSIwIAYDVQQK\n' + + 'DBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJbmMuMRMwEQYDVQQLDApBbWF6b24gUkRT\n' + + 'MSAwHgYDVQQDDBdBbWF6b24gUkRTIFJvb3QgMjAxOSBDQTAeFw0xOTA5MTYxODIx\n' + + 'MTVaFw0yNDA4MjIxNzA4NTBaMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECAwKV2Fz\n' + + 'aGluZ3RvbjEQMA4GA1UEBwwHU2VhdHRsZTEiMCAGA1UECgwZQW1hem9uIFdlYiBT\n' + + 'ZXJ2aWNlcywgSW5jLjETMBEGA1UECwwKQW1hem9uIFJEUzElMCMGA1UEAwwcQW1h\n' + + 'em9uIFJEUyB1cy13ZXN0LTIgMjAxOSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP\n' + + 'ADCCAQoCggEBANCEZBZyu6yJQFZBJmSUZfSZd3Ui2gitczMKC4FLr0QzkbxY+cLa\n' + + 'uVONIOrPt4Rwi+3h/UdnUg917xao3S53XDf1TDMFEYp4U8EFPXqCn/GXBIWlU86P\n' + + 'PvBN+gzw3nS+aco7WXb+woTouvFVkk8FGU7J532llW8o/9ydQyDIMtdIkKTuMfho\n' + + 'OiNHSaNc+QXQ32TgvM9A/6q7ksUoNXGCP8hDOkSZ/YOLiI5TcdLh/aWj00ziL5bj\n' + + 'pvytiMZkilnc9dLY9QhRNr0vGqL0xjmWdoEXz9/OwjmCihHqJq+20MJPsvFm7D6a\n' + + '2NKybR9U+ddrjb8/iyLOjURUZnj5O+2+OPcCAwEAAaNmMGQwDgYDVR0PAQH/BAQD\n' + + 'AgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFEBxMBdv81xuzqcK5TVu\n' + + 'pHj+Aor8MB8GA1UdIwQYMBaAFHNfYNi8ywOY9CsXNC42WqZg/7wfMA0GCSqGSIb3\n' + + 'DQEBCwUAA4IBAQBZkfiVqGoJjBI37aTlLOSjLcjI75L5wBrwO39q+B4cwcmpj58P\n' + + '3sivv+jhYfAGEbQnGRzjuFoyPzWnZ1DesRExX+wrmHsLLQbF2kVjLZhEJMHF9eB7\n' + + 'GZlTPdTzHErcnuXkwA/OqyXMpj9aghcQFuhCNguEfnROY9sAoK2PTfnTz9NJHL+Q\n' + + 'UpDLEJEUfc0GZMVWYhahc0x38ZnSY2SKacIPECQrTI0KpqZv/P+ijCEcMD9xmYEb\n' + + 'jL4en+XKS1uJpw5fIU5Sj0MxhdGstH6S84iAE5J3GM3XHklGSFwwqPYvuTXvANH6\n' + + 'uboynxRgSae59jIlAK6Jrr6GWMwQRbgcaAlW\n' + '-----END CERTIFICATE-----\n' ] }; diff --git a/lib/protocol/constants/types.js b/lib/protocol/constants/types.js index 19943e8e5..a33cd502c 100644 --- a/lib/protocol/constants/types.js +++ b/lib/protocol/constants/types.js @@ -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.29 + * + * !! 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 --git a/lib/protocol/packets/AuthSwitchRequestPacket.js b/lib/protocol/packets/AuthSwitchRequestPacket.js new file mode 100644 index 000000000..c74e6ec23 --- /dev/null +++ b/lib/protocol/packets/AuthSwitchRequestPacket.js @@ -0,0 +1,20 @@ +module.exports = AuthSwitchRequestPacket; +function AuthSwitchRequestPacket(options) { + options = options || {}; + + this.status = 0xfe; + this.authMethodName = options.authMethodName; + this.authMethodData = options.authMethodData; +} + +AuthSwitchRequestPacket.prototype.parse = function parse(parser) { + this.status = parser.parseUnsignedNumber(1); + this.authMethodName = parser.parseNullTerminatedString(); + this.authMethodData = parser.parsePacketTerminatedBuffer(); +}; + +AuthSwitchRequestPacket.prototype.write = function write(writer) { + writer.writeUnsignedNumber(1, this.status); + writer.writeNullTerminatedString(this.authMethodName); + writer.writeBuffer(this.authMethodData); +}; diff --git a/lib/protocol/packets/AuthSwitchResponsePacket.js b/lib/protocol/packets/AuthSwitchResponsePacket.js new file mode 100644 index 000000000..488abbd03 --- /dev/null +++ b/lib/protocol/packets/AuthSwitchResponsePacket.js @@ -0,0 +1,14 @@ +module.exports = AuthSwitchResponsePacket; +function AuthSwitchResponsePacket(options) { + options = options || {}; + + this.data = options.data; +} + +AuthSwitchResponsePacket.prototype.parse = function parse(parser) { + this.data = parser.parsePacketTerminatedBuffer(); +}; + +AuthSwitchResponsePacket.prototype.write = function write(writer) { + writer.writeBuffer(this.data); +}; diff --git a/lib/protocol/packets/ClientAuthenticationPacket.js b/lib/protocol/packets/ClientAuthenticationPacket.js index a66d28bbe..595db77a0 100644 --- a/lib/protocol/packets/ClientAuthenticationPacket.js +++ b/lib/protocol/packets/ClientAuthenticationPacket.js @@ -1,3 +1,5 @@ +var Buffer = require('safe-buffer').Buffer; + module.exports = ClientAuthenticationPacket; function ClientAuthenticationPacket(options) { options = options || {}; @@ -46,7 +48,7 @@ ClientAuthenticationPacket.prototype.write = function(writer) { writer.writeBuffer(this.scrambleBuff); if (this.database && this.database.length) { writer.writeFiller(1); - writer.writeBuffer(new Buffer(this.database)); + writer.writeBuffer(Buffer.from(this.database)); } } }; diff --git a/lib/protocol/packets/EmptyPacket.js b/lib/protocol/packets/EmptyPacket.js index 3d3410659..27dd68604 100644 --- a/lib/protocol/packets/EmptyPacket.js +++ b/lib/protocol/packets/EmptyPacket.js @@ -2,5 +2,8 @@ module.exports = EmptyPacket; function EmptyPacket() { } +EmptyPacket.prototype.parse = function parse() { +}; + EmptyPacket.prototype.write = function write() { }; diff --git a/lib/protocol/packets/Field.js b/lib/protocol/packets/Field.js index bb6336c1a..a5d58edb6 100644 --- a/lib/protocol/packets/Field.js +++ b/lib/protocol/packets/Field.js @@ -9,7 +9,7 @@ function Field(options) { 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.buffer = function () { 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 --git a/lib/protocol/packets/HandshakeInitializationPacket.js b/lib/protocol/packets/HandshakeInitializationPacket.js index 48622fc9a..b2510633b 100644 --- a/lib/protocol/packets/HandshakeInitializationPacket.js +++ b/lib/protocol/packets/HandshakeInitializationPacket.js @@ -1,3 +1,4 @@ +var Buffer = require('safe-buffer').Buffer; var Client = require('../constants/client'); module.exports = HandshakeInitializationPacket; @@ -88,11 +89,13 @@ HandshakeInitializationPacket.prototype.write = function(writer) { }; HandshakeInitializationPacket.prototype.scrambleBuff = function() { - var buffer = new Buffer(this.scrambleBuff1.length + - (typeof this.scrambleBuff2 !== 'undefined' ? this.scrambleBuff2.length : 0)); + var buffer = null; - this.scrambleBuff1.copy(buffer); - if (typeof this.scrambleBuff2 !== 'undefined') { + if (typeof this.scrambleBuff2 === 'undefined') { + buffer = Buffer.from(this.scrambleBuff1); + } else { + buffer = Buffer.allocUnsafe(this.scrambleBuff1.length + this.scrambleBuff2.length); + this.scrambleBuff1.copy(buffer, 0); this.scrambleBuff2.copy(buffer, this.scrambleBuff1.length); } diff --git a/lib/protocol/packets/LocalInfileRequestPacket.js b/lib/protocol/packets/LocalInfileRequestPacket.js new file mode 100644 index 000000000..b1f68bab4 --- /dev/null +++ b/lib/protocol/packets/LocalInfileRequestPacket.js @@ -0,0 +1,21 @@ +module.exports = LocalInfileRequestPacket; +function LocalInfileRequestPacket(options) { + options = options || {}; + + this.filename = options.filename; +} + +LocalInfileRequestPacket.prototype.parse = function parse(parser) { + if (parser.parseLengthCodedNumber() !== null) { + var err = new TypeError('Received invalid field length'); + err.code = 'PARSER_INVALID_FIELD_LENGTH'; + throw err; + } + + this.filename = parser.parsePacketTerminatedString(); +}; + +LocalInfileRequestPacket.prototype.write = function write(writer) { + writer.writeLengthCodedNumber(null); + writer.writeString(this.filename); +}; diff --git a/lib/protocol/packets/OkPacket.js b/lib/protocol/packets/OkPacket.js index 0d9a0963a..7caf3b0e7 100644 --- a/lib/protocol/packets/OkPacket.js +++ b/lib/protocol/packets/OkPacket.js @@ -1,3 +1,7 @@ + +// Language-neutral expression to match ER_UPDATE_INFO +var ER_UPDATE_INFO_REGEXP = /^[^:0-9]+: [0-9]+[^:0-9]+: ([0-9]+)[^:0-9]+: [0-9]+[^:0-9]*$/; + module.exports = OkPacket; function OkPacket(options) { options = options || {}; @@ -22,8 +26,7 @@ OkPacket.prototype.parse = function(parser) { this.message = parser.parsePacketTerminatedString(); this.changedRows = 0; - var m = this.message.match(/\schanged:\s*(\d+)/i); - + var m = ER_UPDATE_INFO_REGEXP.exec(this.message); if (m !== null) { this.changedRows = parseInt(m[1], 10); } diff --git a/lib/protocol/packets/OldPasswordPacket.js b/lib/protocol/packets/OldPasswordPacket.js index 1ff78ec1e..a72951021 100644 --- a/lib/protocol/packets/OldPasswordPacket.js +++ b/lib/protocol/packets/OldPasswordPacket.js @@ -6,10 +6,9 @@ function OldPasswordPacket(options) { } 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 --git a/lib/protocol/packets/ResultSetHeaderPacket.js b/lib/protocol/packets/ResultSetHeaderPacket.js index 25b800222..a097ea1f2 100644 --- a/lib/protocol/packets/ResultSetHeaderPacket.js +++ b/lib/protocol/packets/ResultSetHeaderPacket.js @@ -3,23 +3,12 @@ function ResultSetHeaderPacket(options) { options = options || {}; this.fieldCount = options.fieldCount; - this.extra = options.extra; } ResultSetHeaderPacket.prototype.parse = function(parser) { this.fieldCount = parser.parseLengthCodedNumber(); - - if (parser.reachedPacketEnd()) return; - - this.extra = (this.fieldCount === null) - ? parser.parsePacketTerminatedString() - : parser.parseLengthCodedNumber(); }; ResultSetHeaderPacket.prototype.write = function(writer) { writer.writeLengthCodedNumber(this.fieldCount); - - if (this.extra !== undefined) { - writer.writeLengthCodedNumber(this.extra); - } }; diff --git a/lib/protocol/packets/RowDataPacket.js b/lib/protocol/packets/RowDataPacket.js index 8313f87fb..b8ec4b895 100644 --- a/lib/protocol/packets/RowDataPacket.js +++ b/lib/protocol/packets/RowDataPacket.js @@ -123,10 +123,7 @@ function typeCast(field, parser, timeZone, supportBigNumbers, bigNumberStrings, 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 --git a/lib/protocol/packets/index.js b/lib/protocol/packets/index.js index 5c63df53a..5e9352457 100644 --- a/lib/protocol/packets/index.js +++ b/lib/protocol/packets/index.js @@ -1,3 +1,5 @@ +exports.AuthSwitchRequestPacket = require('./AuthSwitchRequestPacket'); +exports.AuthSwitchResponsePacket = require('./AuthSwitchResponsePacket'); exports.ClientAuthenticationPacket = require('./ClientAuthenticationPacket'); exports.ComChangeUserPacket = require('./ComChangeUserPacket'); exports.ComPingPacket = require('./ComPingPacket'); @@ -11,6 +13,7 @@ exports.Field = require('./Field'); exports.FieldPacket = require('./FieldPacket'); exports.HandshakeInitializationPacket = require('./HandshakeInitializationPacket'); exports.LocalDataFilePacket = require('./LocalDataFilePacket'); +exports.LocalInfileRequestPacket = require('./LocalInfileRequestPacket'); exports.OkPacket = require('./OkPacket'); exports.OldPasswordPacket = require('./OldPasswordPacket'); exports.ResultSetHeaderPacket = require('./ResultSetHeaderPacket'); diff --git a/lib/protocol/sequences/ChangeUser.js b/lib/protocol/sequences/ChangeUser.js index 26be6dbbd..e1cc1fbc3 100644 --- a/lib/protocol/sequences/ChangeUser.js +++ b/lib/protocol/sequences/ChangeUser.js @@ -15,6 +15,14 @@ function ChangeUser(options, callback) { 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 @@ ChangeUser.prototype.start = function(handshakeInitializationPacket) { 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 --git a/lib/protocol/sequences/Handshake.js b/lib/protocol/sequences/Handshake.js index 3ce49407b..8fad0fcf3 100644 --- a/lib/protocol/sequences/Handshake.js +++ b/lib/protocol/sequences/Handshake.js @@ -15,7 +15,7 @@ function Handshake(options, callback) { this._handshakeInitializationPacket = null; } -Handshake.prototype.determinePacket = function(firstByte) { +Handshake.prototype.determinePacket = function determinePacket(firstByte, parser) { if (firstByte === 0xff) { return Packets.ErrorPacket; } @@ -25,12 +25,32 @@ Handshake.prototype.determinePacket = function(firstByte) { } if (firstByte === 0xfe) { - return Packets.UseOldPasswordPacket; + return (parser.packetLength() === 1) + ? Packets.UseOldPasswordPacket + : Packets.AuthSwitchRequestPacket; } return undefined; }; +Handshake.prototype['AuthSwitchRequestPacket'] = function (packet) { + 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: 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); + } +}; + Handshake.prototype['HandshakeInitializationPacket'] = function(packet) { this._handshakeInitializationPacket = packet; @@ -75,15 +95,15 @@ Handshake.prototype._sendCredentials = function() { database : this._config.database, protocol41 : packet.protocol41, scrambleBuff : (packet.protocol41) - ? Auth.token(this._config.password, packet.scrambleBuff()) - : Auth.scramble323(packet.scrambleBuff(), this._config.password) + ? Auth.token(this._config.password, packet.scrambleBuff()) + : Auth.scramble323(packet.scrambleBuff(), this._config.password) })); }; Handshake.prototype['UseOldPasswordPacket'] = function() { if (!this._config.insecureAuth) { var err = new Error( - 'MySQL server is requesting the old and insecure pre-4.1 auth mechanism.' + + 'MySQL server is requesting the old and insecure pre-4.1 auth mechanism. ' + 'Upgrade the user password or use the {insecureAuth: true} option.' ); diff --git a/lib/protocol/sequences/Query.js b/lib/protocol/sequences/Query.js index 12eb29860..b7632959b 100644 --- a/lib/protocol/sequences/Query.js +++ b/lib/protocol/sequences/Query.js @@ -1,10 +1,11 @@ -var Sequence = require('./Sequence'); -var Util = require('util'); -var Packets = require('../packets'); -var ResultSet = require('../ResultSet'); -var ServerStatus = require('../constants/server_status'); -var fs = require('fs'); -var Readable = require('readable-stream'); +var ClientConstants = require('../constants/client'); +var fs = require('fs'); +var Packets = require('../packets'); +var ResultSet = require('../ResultSet'); +var Sequence = require('./Sequence'); +var ServerStatus = require('../constants/server_status'); +var Readable = require('readable-stream'); +var Util = require('util'); module.exports = Query; Util.inherits(Query, Sequence); @@ -35,6 +36,7 @@ Query.prototype.determinePacket = function determinePacket(byte, parser) { if (!resultSet) { switch (byte) { case 0x00: return Packets.OkPacket; + case 0xfb: return Packets.LocalInfileRequestPacket; case 0xff: return Packets.ErrorPacket; default: return Packets.ResultSetHeaderPacket; } @@ -85,17 +87,27 @@ Query.prototype['ErrorPacket'] = function(packet) { : undefined; err.index = this._index; + err.sql = this.sql; + this.end(err, results, fields); }; -Query.prototype['ResultSetHeaderPacket'] = function(packet) { - if (packet.fieldCount === null) { - this._sendLocalDataFile(packet.extra); +Query.prototype['LocalInfileRequestPacket'] = function(packet) { + if (this._connection.config.clientFlags & ClientConstants.CLIENT_LOCAL_FILES) { + this._sendLocalDataFile(packet.filename); } else { - this._resultSet = new ResultSet(packet); + this._loadError = new Error('Load local files command is disabled'); + this._loadError.code = 'LOCAL_FILES_DISABLED'; + this._loadError.fatal = false; + + this.emit('packet', new Packets.EmptyPacket()); } }; +Query.prototype['ResultSetHeaderPacket'] = function(packet) { + this._resultSet = new ResultSet(packet); +}; + Query.prototype['FieldPacket'] = function(packet) { this._resultSet.fieldPackets.push(packet); }; @@ -178,12 +190,12 @@ Query.prototype._sendLocalDataFile = function(path) { }; Query.prototype.stream = function(options) { - var self = this, - stream; + var self = this; options = options || {}; options.objectMode = true; - stream = new Readable(options); + + var stream = new Readable(options); stream._read = function() { self._connection && self._connection.resume(); @@ -195,21 +207,21 @@ Query.prototype.stream = function(options) { }); }); - this.on('result',function(row,i) { + this.on('result', function(row, i) { if (!stream.push(row)) self._connection.pause(); - stream.emit('result',row,i); // replicate old emitter + stream.emit('result', row, i); // replicate old emitter }); - this.on('error',function(err) { - stream.emit('error',err); // Pass on any errors + this.on('error', function(err) { + stream.emit('error', err); // Pass on any errors }); this.on('end', function() { stream.push(null); // pushing null, indicating EOF }); - this.on('fields',function(fields,i) { - stream.emit('fields',fields,i); // replicate old emitter + this.on('fields', function(fields, i) { + stream.emit('fields', fields, i); // replicate old emitter }); return stream; diff --git a/lib/protocol/sequences/Quit.js b/lib/protocol/sequences/Quit.js index 04438d125..3c34c5820 100644 --- a/lib/protocol/sequences/Quit.js +++ b/lib/protocol/sequences/Quit.js @@ -11,8 +11,30 @@ function Quit(options, callback) { } Sequence.call(this, options, callback); + + this._started = false; } +Quit.prototype.end = function end(err) { + if (this._ended) { + return; + } + + if (!this._started) { + Sequence.prototype.end.call(this, err); + return; + } + + if (err && err.code === 'ECONNRESET' && err.syscall === 'read') { + // Ignore read errors after packet sent + Sequence.prototype.end.call(this); + return; + } + + Sequence.prototype.end.call(this, err); +}; + Quit.prototype.start = function() { + this._started = true; this.emit('packet', new Packets.ComQuitPacket()); }; diff --git a/lib/protocol/sequences/Sequence.js b/lib/protocol/sequences/Sequence.js index 2c8660768..de82dc270 100644 --- a/lib/protocol/sequences/Sequence.js +++ b/lib/protocol/sequences/Sequence.js @@ -2,6 +2,7 @@ var Util = require('util'); var EventEmitter = require('events').EventEmitter; var Packets = require('../packets'); var ErrorConstants = require('../constants/errors'); +var Timer = require('../Timer'); // istanbul ignore next: Node.js < 0.10 not covered var listenerCount = EventEmitter.listenerCount @@ -25,13 +26,7 @@ function Sequence(options, callback) { this._callSite = null; this._ended = false; this._timeout = options.timeout; - - // For Timers - this._idleNext = null; - this._idlePrev = null; - this._idleStart = null; - this._idleTimeout = -1; - this._repeat = null; + this._timer = new Timer(this); } Sequence.determinePacket = function(byte) { @@ -52,7 +47,9 @@ Sequence.prototype._packetToError = function(packet) { var err = new Error(code + ': ' + packet.message); err.code = code; err.errno = packet.errno; - err.sqlState = packet.sqlState; + + err.sqlMessage = packet.message; + err.sqlState = packet.sqlState; return err; }; diff --git a/package.json b/package.json index d5a80360f..7ed9d55bb 100644 --- a/package.json +++ b/package.json @@ -1,30 +1,28 @@ { "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.13.0", + "version": "2.18.1", "license": "MIT", "author": "Felix Geisendörfer (http://debuggable.com/)", "contributors": [ "Andrey Sidorov ", + "Bradley Grainger ", "Douglas Christopher Wilson ", "Diogo Resende ", "Nathan Woltman " ], "repository": "mysqljs/mysql", "dependencies": { - "bignumber.js": "3.1.2", - "readable-stream": "1.1.14", - "sqlstring": "2.2.0" + "bignumber.js": "9.0.0", + "readable-stream": "2.3.7", + "safe-buffer": "5.1.2", + "sqlstring": "2.3.1" }, "devDependencies": { "after": "0.8.2", - "eslint": "3.13.1", - "istanbul": "0.4.5", - "require-all": "2.1.0", - "rimraf": "2.2.8", - "seedrandom": "2.4.2", - "timezone-mock": "0.0.0", - "mkdirp": "0.5.1", + "eslint": "5.16.0", + "seedrandom": "3.0.5", + "timezone-mock": "0.0.7", "urun": "0.0.8", "utest": "0.0.8" }, @@ -39,9 +37,10 @@ "node": ">= 0.6" }, "scripts": { - "lint": "eslint .", + "lint": "eslint . && node tool/lint-readme.js", "test": "node test/run.js", - "test-ci": "node test/run-cov.js lcovonly", - "test-cov": "node test/run-cov.js" + "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 --git a/test/FakeServer.js b/test/FakeServer.js index 6fc2f5ed9..28f67f257 100644 --- a/test/FakeServer.js +++ b/test/FakeServer.js @@ -1,19 +1,20 @@ // An experimental fake MySQL server for tricky integration tests. Expanded // as needed. -var common = require('./common'); -var Charsets = common.Charsets; -var Crypto = require('crypto'); -var Net = require('net'); -var tls = require('tls'); -var Packets = common.Packets; -var PacketWriter = common.PacketWriter; -var Parser = common.Parser; -var Types = common.Types; -var Auth = require(common.lib + '/protocol/Auth'); -var Errors = common.Errors; -var EventEmitter = require('events').EventEmitter; -var Util = require('util'); +var Buffer = require('safe-buffer').Buffer; +var common = require('./common'); +var Charsets = common.Charsets; +var ClientConstants = common.ClientConstants; +var Crypto = require('crypto'); +var Net = require('net'); +var tls = require('tls'); +var Packets = common.Packets; +var PacketWriter = common.PacketWriter; +var Parser = common.Parser; +var Types = common.Types; +var Errors = common.Errors; +var EventEmitter = require('events').EventEmitter; +var Util = require('util'); module.exports = FakeServer; Util.inherits(FakeServer, EventEmitter); @@ -55,57 +56,85 @@ Util.inherits(FakeConnection, EventEmitter); function FakeConnection(socket) { EventEmitter.call(this); + this.database = null; + this.user = null; + + this._cipher = null; this._socket = socket; - this._ssl = null; this._stream = socket; this._parser = new Parser({onPacket: this._parsePacket.bind(this)}); + this._expectedNextPacket = null; this._handshakeInitializationPacket = null; - this._clientAuthenticationPacket = null; - this._oldPasswordPacket = null; this._handshakeOptions = {}; socket.on('data', this._handleData.bind(this)); } +FakeConnection.prototype.authSwitchRequest = function authSwitchRequest(options) { + this._sendPacket(new Packets.AuthSwitchRequestPacket(options)); +}; + +FakeConnection.prototype.deny = function deny(message, errno) { + message = message || 'Access Denied'; + errno = errno || Errors.ER_ACCESS_DENIED_ERROR; + this.error(message, errno); +}; + +FakeConnection.prototype.error = function deny(message, errno) { + this._sendPacket(new Packets.ErrorPacket({ + message : (message || 'Error'), + errno : (errno || Errors.ER_UNKNOWN_COM_ERROR) + })); + this._parser.resetPacketNumber(); +}; + FakeConnection.prototype.handshake = function(options) { this._handshakeOptions = options || {}; - var packetOpiotns = common.extend({ - scrambleBuff1 : new Buffer('1020304050607080', 'hex'), - scrambleBuff2 : new Buffer('0102030405060708090A0B0C', 'hex'), + var packetOptions = common.extend({ + scrambleBuff1 : Buffer.from('1020304050607080', 'hex'), + scrambleBuff2 : Buffer.from('0102030405060708090A0B0C', 'hex'), serverCapabilities1 : 512, // only 1 flag, PROTOCOL_41 protocol41 : true }, this._handshakeOptions); - this._handshakeInitializationPacket = new Packets.HandshakeInitializationPacket(packetOpiotns); + this._handshakeInitializationPacket = new Packets.HandshakeInitializationPacket(packetOptions); this._sendPacket(this._handshakeInitializationPacket); }; -FakeConnection.prototype.deny = function(message, errno) { - this._sendPacket(new Packets.ErrorPacket({ - message : message, - errno : errno - })); +FakeConnection.prototype.ok = function ok() { + this._sendPacket(new Packets.OkPacket()); + this._parser.resetPacketNumber(); }; -FakeConnection.prototype._sendAuthResponse = function(packet, expected) { - var got = packet.scrambleBuff; - +FakeConnection.prototype._sendAuthResponse = function _sendAuthResponse(got, expected) { if (expected.toString('hex') === got.toString('hex')) { - this._sendPacket(new Packets.OkPacket()); + this.ok(); } else { - this._sendPacket(new Packets.ErrorPacket({ - message : 'expected ' + expected.toString('hex') + ' got ' + got.toString('hex'), - errno : Errors.ER_ACCESS_DENIED_ERROR - })); + this.deny('expected ' + expected.toString('hex') + ' got ' + got.toString('hex')); } this._parser.resetPacketNumber(); }; FakeConnection.prototype._sendPacket = function(packet) { + switch (packet.constructor) { + case Packets.AuthSwitchRequestPacket: + this._expectedNextPacket = Packets.AuthSwitchResponsePacket; + break; + case Packets.HandshakeInitializationPacket: + this._expectedNextPacket = Packets.ClientAuthenticationPacket; + break; + case Packets.UseOldPasswordPacket: + this._expectedNextPacket = Packets.OldPasswordPacket; + break; + default: + this._expectedNextPacket = null; + break; + } + var writer = new PacketWriter(); packet.write(writer); this._stream.write(writer.toBuffer(this._parser)); @@ -163,7 +192,7 @@ FakeConnection.prototype._handleQueryPacket = function _handleQueryPacket(packet this._sendPacket(new Packets.EofPacket()); var writer = new PacketWriter(); - writer.writeLengthCodedString((this._clientAuthenticationPacket.user || '') + '@localhost'); + writer.writeLengthCodedString((this.user || '') + '@localhost'); this._socket.write(writer.toBuffer(this._parser)); this._sendPacket(new Packets.EofPacket()); @@ -232,7 +261,7 @@ FakeConnection.prototype._handleQueryPacket = function _handleQueryPacket(packet var writer = new PacketWriter(); writer.writeLengthCodedString('Ssl_cipher'); - writer.writeLengthCodedString(this._ssl ? this._ssl.getCurrentCipher().name : ''); + writer.writeLengthCodedString(this._cipher ? this._cipher.name : ''); this._stream.write(writer.toBuffer(this._parser)); this._sendPacket(new Packets.EofPacket()); @@ -241,53 +270,36 @@ FakeConnection.prototype._handleQueryPacket = function _handleQueryPacket(packet } if (/INVALID/i.test(sql)) { - this._sendPacket(new Packets.ErrorPacket({ - errno : Errors.ER_PARSE_ERROR, - message : 'Invalid SQL' - })); - this._parser.resetPacketNumber(); + this.error('Invalid SQL', Errors.ER_PARSE_ERROR); return; } - this._sendPacket(new Packets.ErrorPacket({ - errno : Errors.ER_QUERY_INTERRUPTED, - message : 'Interrupted unknown query' - })); - - this._parser.resetPacketNumber(); + this.error('Interrupted unknown query', Errors.ER_QUERY_INTERRUPTED); }; -FakeConnection.prototype._parsePacket = function(header) { - var Packet = this._determinePacket(header); +FakeConnection.prototype._parsePacket = function _parsePacket(packetHeader) { + var Packet = this._determinePacket(packetHeader); var packet = new Packet({protocol41: true}); packet.parse(this._parser); switch (Packet) { + case Packets.AuthSwitchResponsePacket: + if (!this.emit('authSwitchResponse', packet)) { + this.deny('No auth response handler'); + } + break; case Packets.ClientAuthenticationPacket: - this._clientAuthenticationPacket = packet; - if (this._handshakeOptions.oldPassword) { - this._sendPacket(new Packets.UseOldPasswordPacket()); - } else if (this._handshakeOptions.password === 'passwd') { - var expected = new Buffer('3DA0ADA7C9E1BB3A110575DF53306F9D2DE7FD09', 'hex'); - this._sendAuthResponse(packet, expected); - } else if (this._handshakeOptions.user || this._handshakeOptions.password) { - throw new Error('not implemented'); - } else { - this._sendPacket(new Packets.OkPacket()); - this._parser.resetPacketNumber(); + this.database = (packet.database || null); + this.user = (packet.user || null); + + if (!this.emit('clientAuthentication', packet)) { + this.ok(); } break; case Packets.SSLRequestPacket: this._startTLS(); break; - case Packets.OldPasswordPacket: - this._oldPasswordPacket = packet; - - var expected = Auth.scramble323(this._handshakeInitializationPacket.scrambleBuff(), this._handshakeOptions.password); - - this._sendAuthResponse(packet, expected); - break; case Packets.ComQueryPacket: if (!this.emit('query', packet)) { this._handleQueryPacket(packet); @@ -295,39 +307,24 @@ FakeConnection.prototype._parsePacket = function(header) { break; case Packets.ComPingPacket: if (!this.emit('ping', packet)) { - this._sendPacket(new Packets.OkPacket()); - this._parser.resetPacketNumber(); + this.ok(); } break; case Packets.ComChangeUserPacket: - if (packet.user === 'does-not-exist') { - this._sendPacket(new Packets.ErrorPacket({ - errno : Errors.ER_ACCESS_DENIED_ERROR, - message : 'User does not exist' - })); - this._parser.resetPacketNumber(); - break; - } else if (packet.database === 'does-not-exist') { - this._sendPacket(new Packets.ErrorPacket({ - errno : Errors.ER_BAD_DB_ERROR, - message : 'Database does not exist' - })); - this._parser.resetPacketNumber(); - break; + this.database = (packet.database || null); + this.user = (packet.user || null); + + if (!this.emit('changeUser', packet)) { + if (packet.user === 'does-not-exist') { + this.deny('User does not exist'); + break; + } else if (packet.database === 'does-not-exist') { + this.error('Database does not exist', Errors.ER_BAD_DB_ERROR); + break; + } + + this.ok(); } - - this._clientAuthenticationPacket = new Packets.ClientAuthenticationPacket({ - clientFlags : this._clientAuthenticationPacket.clientFlags, - filler : this._clientAuthenticationPacket.filler, - maxPacketSize : this._clientAuthenticationPacket.maxPacketSize, - protocol41 : this._clientAuthenticationPacket.protocol41, - charsetNumber : packet.charsetNumber, - database : packet.database, - scrambleBuff : packet.scrambleBuff, - user : packet.user - }); - this._sendPacket(new Packets.OkPacket()); - this._parser.resetPacketNumber(); break; case Packets.ComQuitPacket: if (!this.emit('quit', packet)) { @@ -335,23 +332,29 @@ FakeConnection.prototype._parsePacket = function(header) { } break; default: - throw new Error('Unexpected packet: ' + Packet.name); + if (!this.emit(packet.constructor.name, packet)) { + throw new Error('Unexpected packet: ' + Packet.name); + } } }; -FakeConnection.prototype._determinePacket = function(header) { - if (!this._clientAuthenticationPacket) { - // first packet phase +FakeConnection.prototype._determinePacket = function _determinePacket(packetHeader) { + if (this._expectedNextPacket) { + var Packet = this._expectedNextPacket; - if (header.length === 32) { - return Packets.SSLRequestPacket; + if (Packet === Packets.ClientAuthenticationPacket) { + return !this._cipher && (this._parser.peak(1) << 8) & ClientConstants.CLIENT_SSL + ? Packets.SSLRequestPacket + : Packets.ClientAuthenticationPacket; } - return Packets.ClientAuthenticationPacket; + this._expectedNextPacket = null; + + return Packet; } - if (this._handshakeOptions.oldPassword && !this._oldPasswordPacket) { - return Packets.OldPasswordPacket; + if (packetHeader.length === 0) { + return Packets.EmptyPacket; } var firstByte = this._parser.peak(); @@ -444,7 +447,7 @@ if (tls.TLSSocket) { var conn = this; secureSocket.on('secure', function () { - conn._ssl = this.ssl; + conn._cipher = this.getCipher(); }); // resume @@ -473,7 +476,7 @@ if (tls.TLSSocket) { var conn = this; securePair.on('secure', function () { - conn._ssl = this.ssl; + conn._cipher = securePair.cleartext.getCipher(); }); // resume diff --git a/test/common.js b/test/common.js index 7d1ef44f6..f0eccbe08 100644 --- a/test/common.js +++ b/test/common.js @@ -1,9 +1,8 @@ var common = exports; var fs = require('fs'); -var mkdirp = require('mkdirp'); var path = require('path'); -common.lib = path.resolve(__dirname, '..', (process.env.TEST_COVERAGE || ''), 'lib'); +common.lib = path.resolve(__dirname, '..', 'lib'); common.fixtures = path.resolve(__dirname, 'fixtures'); // Useful for triggering ECONNREFUSED errors on connect() @@ -19,6 +18,7 @@ common.fakeServerSocket = __dirname + '/fake_server.sock'; common.testDatabase = process.env.MYSQL_DATABASE || 'test'; // Export common modules +common.Auth = require(common.lib + '/protocol/Auth'); common.Charsets = require(common.lib + '/protocol/constants/charsets'); common.ClientConstants = require(common.lib + '/protocol/constants/client'); common.Connection = require(common.lib + '/Connection'); @@ -32,13 +32,6 @@ common.PoolConnection = require(common.lib + '/PoolConnection'); common.SqlString = require(common.lib + '/protocol/SqlString'); common.Types = require(common.lib + '/protocol/constants/types'); -// Setup coverage hook -if (process.env.TEST_COVERAGE) { - process.on('exit', function () { - writeCoverage(global.__coverage__ || {}); - }); -} - var Mysql = require(path.resolve(common.lib, '../index')); var FakeServer = require('./FakeServer'); @@ -149,7 +142,7 @@ common.getSSLConfig = function() { return { ca : fs.readFileSync(path.join(common.fixtures, 'server.crt'), 'ascii'), cert : fs.readFileSync(path.join(common.fixtures, 'server.crt'), 'ascii'), - ciphers : 'ECDHE-RSA-AES128-SHA256:AES128-GCM-SHA256:RC4:HIGH:!MD5:!aNULL:!EDH', + ciphers : 'ECDHE-RSA-AES128-SHA256:AES128-GCM-SHA256:AES128-SHA:HIGH:!MD5:!aNULL:!EDH', key : fs.readFileSync(path.join(common.fixtures, 'server.key'), 'ascii') }; }; @@ -165,14 +158,3 @@ function mergeTestConfig(config) { return config; } - -function writeCoverage(coverage) { - var test = path.relative(__dirname, path.resolve(process.argv[1])); - var ext = path.extname(test); - var cov = test.substr(0, test.length - ext.length) + '.json'; - var out = path.resolve(__dirname, '..', process.env.TEST_COVERAGE, 'test', cov); - - mkdirp.sync(path.dirname(out)); - - fs.writeFileSync(out, JSON.stringify(coverage)); -} diff --git a/test/integration/connection/test-connection-config-flags-affected-rows.js b/test/integration/connection/test-connection-config-flags-affected-rows.js index cd6e725ab..9dc658342 100644 --- a/test/integration/connection/test-connection-config-flags-affected-rows.js +++ b/test/integration/connection/test-connection-config-flags-affected-rows.js @@ -13,7 +13,7 @@ common.getTestConnection({flags: '-FOUND_ROWS'}, function (err, connection) { common.useTestDb(connection); connection.query([ - 'CREATE TABLE ?? (', + 'CREATE TEMPORARY TABLE ?? (', '`a` int(11) unsigned NOT NULL AUTO_INCREMENT,', '`b` int(11),', '`c` int(11),', diff --git a/test/integration/connection/test-error-sqlmessage.js b/test/integration/connection/test-error-sqlmessage.js new file mode 100644 index 000000000..8ee44d5fe --- /dev/null +++ b/test/integration/connection/test-error-sqlmessage.js @@ -0,0 +1,60 @@ +var assert = require('assert'); +var common = require('../../common'); + +var table = 'error_message_test'; +var message = 'Name must not contain b.'; + +common.getTestConnection(function (err, connection) { + assert.ifError(err); + + common.useTestDb(connection); + + createTestTable(function (err3) { + assert.ifError(err3); + + // Violates trigger condition, so it will throw an error on insert + connection.query('INSERT INTO ?? (name) VALUES ?', [table, [['bbbbbbbbbb']]], function (err4) { + // Remove table when insert finishes + connection.query('DROP TABLE IF EXISTS ??', [table], function (err5) { + assert.ifError(err5); + assert.ok(err4); + assert.equal(err4.sqlState, '45000'); + assert.equal(err4.sqlMessage, message, 'error sqlMessage property is the trigger error message'); + connection.end(assert.ifError); + }); + }); + }); + + function createTestTable(cb) { + // Must use real table because temporary tables cannot have triggers + connection.query([ + 'CREATE TABLE ?? (', + '`name` varchar(255)', + ') ENGINE=InnoDB DEFAULT CHARSET=utf8' + ].join('\n'), [table], function (err1) { + if (err1) { + cb(err1); + } else { + // Create a trigger that throws error when name contains the letter "b" + connection.query([ + 'CREATE TRIGGER `validateName`', + 'BEFORE INSERT ON ??', + 'FOR EACH ROW BEGIN', + 'IF (NEW.name like \'%b%\') THEN', + 'SIGNAL SQLSTATE \'45000\' SET MESSAGE_TEXT = ?;', + 'END IF;', + 'END;' + ].join('\n'), [table, message], function (err2) { + if (!err2) { + cb(); + } else { + // Clean up table if create trigger fails + connection.query('DROP TABLE IF EXISTS ??', [table], function () { + cb(err2); + }); + } + }); + } + }); + } +}); diff --git a/test/integration/connection/test-load-data-infile-disable.js b/test/integration/connection/test-load-data-infile-disable.js new file mode 100644 index 000000000..89cdf4aaf --- /dev/null +++ b/test/integration/connection/test-load-data-infile-disable.js @@ -0,0 +1,38 @@ +var assert = require('assert'); +var common = require('../../common'); + +var path = common.fixtures + '/data.csv'; +var table = 'load_data_test'; +var newline = common.detectNewline(path); + +common.getTestConnection({localInfile: false}, function (err, connection) { + assert.ifError(err); + + common.useTestDb(connection); + + connection.query([ + 'CREATE TEMPORARY TABLE ?? (', + '`id` int(11) unsigned NOT NULL AUTO_INCREMENT,', + '`title` varchar(400),', + 'PRIMARY KEY (`id`)', + ') ENGINE=InnoDB DEFAULT CHARSET=utf8' + ].join('\n'), [table], assert.ifError); + + var sql = + 'LOAD DATA LOCAL INFILE ? INTO TABLE ?? CHARACTER SET utf8 ' + + 'FIELDS TERMINATED BY ? ' + + 'LINES TERMINATED BY ? ' + + '(id, title)'; + + connection.query(sql, [path, table, ',', newline], function (err) { + assert.ok(err); + assert.equal(err.code, 'ER_NOT_ALLOWED_COMMAND'); + }); + + connection.query('SELECT * FROM ??', [table], function (err, rows) { + assert.ifError(err); + assert.equal(rows.length, 0); + }); + + connection.end(assert.ifError); +}); diff --git a/test/integration/connection/test-load-data-infile.js b/test/integration/connection/test-load-data-infile.js index 4d5cc4285..ef5a72a3f 100644 --- a/test/integration/connection/test-load-data-infile.js +++ b/test/integration/connection/test-load-data-infile.js @@ -42,9 +42,10 @@ common.getTestConnection(function (err, connection) { assert.equal(rows[4].title, 'this is a long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long string'); }); - connection.query(sql, [badPath, table, ',', newline], function (err) { + connection.query(sql, [badPath, table, ',', newline], function (err, result) { assert.ok(err); assert.equal(err.code, 'ENOENT'); + assert.equal(result.affectedRows, 0); }); connection.end(assert.ifError); diff --git a/test/integration/connection/test-procedure-with-multiple-selects.js b/test/integration/connection/test-procedure-with-multiple-selects.js index 379f5fea3..781cf3a08 100644 --- a/test/integration/connection/test-procedure-with-multiple-selects.js +++ b/test/integration/connection/test-procedure-with-multiple-selects.js @@ -12,7 +12,7 @@ common.getTestConnection(function (err, connection) { var input1 = 1000; connection.query([ - 'CREATE DEFINER=root@localhost PROCEDURE ?? (IN param0 INT, IN param1 INT)', + 'CREATE PROCEDURE ?? (IN param0 INT, IN param1 INT)', 'BEGIN', 'SELECT param0;', 'SELECT param1;', diff --git a/test/integration/connection/test-procedure-with-single-select.js b/test/integration/connection/test-procedure-with-single-select.js index a8327735b..305cb3268 100644 --- a/test/integration/connection/test-procedure-with-single-select.js +++ b/test/integration/connection/test-procedure-with-single-select.js @@ -11,7 +11,7 @@ common.getTestConnection(function (err, connection) { var input = 1; connection.query([ - 'CREATE DEFINER=root@localhost PROCEDURE ?? (IN param INT)', + 'CREATE PROCEDURE ?? (IN param INT)', 'BEGIN', 'SELECT param;', 'END' diff --git a/test/integration/connection/test-query-changed-rows.js b/test/integration/connection/test-query-changed-rows.js new file mode 100644 index 000000000..9507ce927 --- /dev/null +++ b/test/integration/connection/test-query-changed-rows.js @@ -0,0 +1,29 @@ +var assert = require('assert'); +var common = require('../../common'); + +var table = 'changed_rows_test'; + +common.getTestConnection(function (err, connection) { + assert.ifError(err); + + common.useTestDb(connection); + + connection.query( + 'CREATE TEMPORARY TABLE ?? (`col1` int, `col2` int) ENGINE=InnoDB DEFAULT CHARSET=utf8', + [table], assert.ifError); + + connection.query('INSERT INTO ?? VALUES(1,1)', [table], assert.ifError); + + connection.query('UPDATE ?? SET `col1` = 2', [table], function (error, results) { + assert.ifError(error); + assert.strictEqual(results.affectedRows, 1); + assert.strictEqual(results.changedRows, 1); + + connection.query('UPDATE ?? SET `col1` = 2', [table], function (error, results) { + assert.ifError(error); + assert.strictEqual(results.affectedRows, 1); + assert.strictEqual(results.changedRows, 0); + connection.end(assert.ifError); + }); + }); +}); diff --git a/test/integration/connection/test-timezones.js b/test/integration/connection/test-timezones.js index 8c6a9a00a..622b5c82d 100644 --- a/test/integration/connection/test-timezones.js +++ b/test/integration/connection/test-timezones.js @@ -5,7 +5,9 @@ var common = require('../../common'); function registerMock() { timezone_mock.register('US/Pacific'); - assert.ok(new Date().getTimezoneOffset() === 420 || new Date().getTimezoneOffset() === 480); + var date = new Date(Date.now()); + var tzo = date.getTimezoneOffset(); + assert.ok(tzo === 420 || tzo === 480); } var table = 'timezone_test'; diff --git a/test/integration/connection/test-type-casting.js b/test/integration/connection/test-type-casting.js index 8e8fecd25..178056456 100644 --- a/test/integration/connection/test-type-casting.js +++ b/test/integration/connection/test-type-casting.js @@ -1,4 +1,5 @@ var assert = require('assert'); +var Buffer = require('safe-buffer').Buffer; var common = require('../../common'); var tests = [ @@ -23,13 +24,13 @@ var tests = [ {type: 'datetime', insert: new Date('2012-05-12 12:00:23')}, {type: 'date', insert: new Date('2012-05-12 00:00:00')}, {type: 'time', insert: '13:13:23'}, - {type: 'binary(4)', insert: new Buffer([0, 1, 254, 255])}, - {type: 'varbinary(4)', insert: new Buffer([0, 1, 254, 255])}, - {type: 'tinyblob', insert: new Buffer([0, 1, 254, 255])}, - {type: 'mediumblob', insert: new Buffer([0, 1, 254, 255])}, - {type: 'longblob', insert: new Buffer([0, 1, 254, 255])}, - {type: 'blob', insert: new Buffer([0, 1, 254, 255])}, - {type: 'bit(32)', insert: new Buffer([0, 1, 254, 255])}, + {type: 'binary(4)', insert: Buffer.from([0, 1, 254, 255])}, + {type: 'varbinary(4)', insert: Buffer.from([0, 1, 254, 255])}, + {type: 'tinyblob', insert: Buffer.from([0, 1, 254, 255])}, + {type: 'mediumblob', insert: Buffer.from([0, 1, 254, 255])}, + {type: 'longblob', insert: Buffer.from([0, 1, 254, 255])}, + {type: 'blob', insert: Buffer.from([0, 1, 254, 255])}, + {type: 'bit(32)', insert: Buffer.from([0, 1, 254, 255])}, {type: 'char(5)', insert: 'Hello'}, {type: 'varchar(5)', insert: 'Hello'}, {type: 'varchar(3) character set utf8 collate utf8_bin', insert: 'bin'}, @@ -38,15 +39,14 @@ var tests = [ {type: 'longtext', insert: 'Hello World'}, {type: 'text', insert: 'Hello World'}, {type: 'point', insertRaw: 'POINT(1.2,-3.4)', expect: {x: 1.2, y: -3.4}, deep: true}, - {type: 'point', insertRaw: 'GeomFromWKB(X\'010100000066666666666616c0f6285c8fc2752440\')', expect: {x: -5.6, y: 10.23}, deep: true}, {type: 'point', insertRaw: '', insert: null, expect: null}, {type: 'linestring', insertRaw: 'LINESTRING(POINT(1.2,-3.4),POINT(-5.6,10.23),POINT(0.2,0.7))', expect: [{x: 1.2, y: -3.4}, {x: -5.6, y: 10.23}, {x: 0.2, y: 0.7}], deep: true}, - {type: 'polygon', insertRaw: "GeomFromText('POLYGON((0 0,10 0,10 10,0 10,0 0),(5 5,7 5,7 7,5 7, 5 5))')", expect: [[{x: 0,y: 0}, {x: 10, y: 0}, {x: 10, y: 10}, {x: 0, y: 10}, {x: 0, y: 0}], [{x: 5, y: 5}, {x: 7, y: 5}, {x: 7, y: 7}, {x: 5, y: 7}, {x: 5, y: 5}]], deep: true}, + {type: 'polygon', insertRaw: 'POLYGON(LINESTRING(POINT(0,0),POINT(10,0),POINT(10,10),POINT(0,10),POINT(0,0)),LINESTRING(POINT(5,5),POINT(7,5),POINT(7,7),POINT(5,7),POINT(5,5)))', expect: [[{x: 0, y: 0}, {x: 10, y: 0}, {x: 10, y: 10}, {x: 0, y: 10}, {x: 0, y: 0}], [{x: 5, y: 5}, {x: 7, y: 5}, {x: 7, y: 7}, {x: 5, y: 7}, {x: 5, y: 5}]], deep: true}, {type: 'geometry', insertRaw: 'POINT(1.2,-3.4)', expect: {x: 1.2, y: -3.4}, deep: true}, - {type: 'multipoint', insertRaw: "GeomFromText('MULTIPOINT(0 0, 20 20, 60 60)')", expect: [{x: 0, y: 0}, {x: 20, y: 20}, {x: 60, y: 60}], deep: true}, - {type: 'multilinestring', insertRaw: "GeomFromText('MULTILINESTRING((10 10, 20 20), (15 15, 30 15))')", expect: [[{x: 10, y: 10}, {x: 20, y: 20}], [{x: 15, y: 15}, {x: 30, y: 15}]], deep: true}, - {type: 'multipolygon', insertRaw: "GeomFromText('MULTIPOLYGON(((0 0,10 0,10 10,0 10,0 0)),((5 5,7 5,7 7,5 7, 5 5)))')", expect: [[[{x: 0,y: 0}, {x: 10, y: 0}, {x: 10, y: 10}, {x: 0, y: 10}, {x: 0, y: 0}]], [[{x: 5, y: 5}, {x: 7, y: 5}, {x: 7, y: 7}, {x: 5, y: 7}, {x: 5, y: 5}]]], deep: true}, - {type: 'geometrycollection', insertRaw: "GeomFromText('GEOMETRYCOLLECTION(POINT(10 10), POINT(30 30), LINESTRING(15 15, 20 20))')", expect: [{x: 10, y: 10}, {x: 30, y: 30}, [{x: 15, y: 15}, {x: 20,y: 20}]], deep: true} + {type: 'multipoint', insertRaw: 'MULTIPOINT(POINT(0,0),POINT(20,20),POINT(60,60))', expect: [{x: 0, y: 0}, {x: 20, y: 20}, {x: 60, y: 60}], deep: true}, + {type: 'multilinestring', insertRaw: 'MULTILINESTRING(LINESTRING(POINT(10,10),POINT(20,20)),LINESTRING(POINT(15,15),POINT(30,15)))', expect: [[{x: 10, y: 10}, {x: 20, y: 20}], [{x: 15, y: 15}, {x: 30, y: 15}]], deep: true}, + {type: 'multipolygon', insertRaw: 'MULTIPOLYGON(POLYGON(LINESTRING(POINT(0,0),POINT(10,0),POINT(10,10),POINT(0,10),POINT(0,0))),POLYGON(LINESTRING(POINT(5,5),POINT(7,5),POINT(7,7),POINT(5,7),POINT(5,5))))', expect: [[[{x: 0, y: 0}, {x: 10, y: 0}, {x: 10, y: 10}, {x: 0, y: 10}, {x: 0, y: 0}]], [[{x: 5, y: 5}, {x: 7, y: 5}, {x: 7, y: 7}, {x: 5, y: 7}, {x: 5, y: 5}]]], deep: true}, + {type: 'geometrycollection', insertRaw: 'GEOMETRYCOLLECTION(POINT(10,10),POINT(30,30),LINESTRING(POINT(15,15),POINT(20,20)))', expect: [{x: 10, y: 10}, {x: 30, y: 30}, [{x: 15, y: 15}, {x: 20, y: 20}]], deep: true} ]; var table = 'type_casting'; diff --git a/test/run-cov.js b/test/run-cov.js deleted file mode 100644 index 5e4ddec4e..000000000 --- a/test/run-cov.js +++ /dev/null @@ -1,93 +0,0 @@ -var istanbul = require('istanbul'); -var mkdirp = require('mkdirp'); -var path = require('path'); -var rimraf = require('rimraf'); -var spawn = require('child_process').spawn; - -var istanbulcli = path.resolve(__dirname, '../node_modules/istanbul/lib/cli.js'); -var libcov = path.resolve(__dirname, '../lib-cov'); - -rimraf.sync(libcov); -mkdirp.sync(libcov); - -instrument('index.js', function (err) { - if (err) handleError(err); - instrument('lib', function (err) { - if (err) handleError(err); - run(function (err, code) { - if (err) handleError(err); - reportCoverage(collectCoverage(path.resolve(libcov, 'test'))); - rimraf.sync(libcov); - process.exit(code); - }); - }); -}); - -function collectCoverage(dir) { - var collector = new istanbul.Collector(); - var coverage = require('require-all')({ - dirname : dir, - filter : /^(test-.+?)\.json$/i - }); - var obj = null; - var objs = [coverage]; - - while ((obj = objs.shift())) { - for (var key in obj) { - if (/^test-/.test(key)) { - collector.add(obj[key]); - } else { - objs.push(obj[key]); - } - } - } - - return collector; -} - -function handleError(err) { - rimraf.sync(libcov); - throw err; -} - -function instrument(target, callback) { - var args = [istanbulcli, 'instrument', path.resolve(__dirname, '..', target), '-o', path.resolve(libcov, target)]; - var exec = process.argv[0]; - var proc = spawn(exec, args, {stdio: 'ignore'}); - - proc.on('error', callback); - proc.on('exit', function (code) { - callback(code === 0 ? null : new Error('non-zero exit code: ' + code)); - }); -} - -function reportCoverage(collector) { - var reporter = new istanbul.Reporter(null, path.resolve(__dirname, '../coverage')); - var style = process.argv[2]; - - rimraf.sync(reporter.dir); - mkdirp.sync(reporter.dir); - - reporter.add(style || 'lcov'); - reporter.add('text-summary'); - reporter.write(collector, true, function(){}); -} - -function run(callback) { - var args = [path.resolve(__dirname, 'run.js')]; - var env = Object.create(null); - var exec = process.argv[0]; - - for (var key in process.env) { - env[key] = process.env[key]; - } - - env.TEST_COVERAGE = 'lib-cov'; - - var proc = spawn(exec, args, {env: env, stdio: 'inherit'}); - - proc.on('error', callback); - proc.on('exit', function (code) { - callback(null, code); - }); -} diff --git a/test/unit/connection/test-auth-no-old-password.js b/test/unit/connection/test-auth-no-old-password.js new file mode 100644 index 000000000..9af2e8715 --- /dev/null +++ b/test/unit/connection/test-auth-no-old-password.js @@ -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 --git a/test/unit/connection/test-auth-no-password.js b/test/unit/connection/test-auth-no-password.js new file mode 100644 index 000000000..86223ed94 --- /dev/null +++ b/test/unit/connection/test-auth-no-password.js @@ -0,0 +1,31 @@ +var assert = require('assert'); +var common = require('../../common'); +var connection = common.createConnection({ + port : common.fakeServerPort, + password : null, + user : 'root' +}); + +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 (packet) { + if (packet.scrambleBuff.length === 0) { + this.ok(); + } else { + this.deny(); + } + }); + + incomingConnection.handshake(); +}); diff --git a/test/unit/connection/test-auth-old-password.js b/test/unit/connection/test-auth-old-password.js new file mode 100644 index 000000000..d73a076f2 --- /dev/null +++ b/test/unit/connection/test-auth-old-password.js @@ -0,0 +1,41 @@ +var common = require('../../common'); +var connection = common.createConnection({ + port : common.fakeServerPort, + password : 'oldpw', + insecureAuth : true +}); +var assert = require('assert'); +var Auth = require(common.lib + '/protocol/Auth'); +var Crypto = require('crypto'); + +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.connect(function (err) { + assert.ifError(err); + connection.destroy(); + server.destroy(); + }); +}); + +server.on('connection', function(incomingConnection) { + random(8, function (err, scramble) { + assert.ifError(err); + + incomingConnection.on('clientAuthentication', function () { + this._sendPacket(new common.Packets.UseOldPasswordPacket()); + }); + + incomingConnection.on('OldPasswordPacket', function (packet) { + var expected = Auth.scramble323(scramble, 'oldpw'); + this._sendAuthResponse(packet.scrambleBuff, expected); + }); + + incomingConnection.handshake({ + scrambleBuff1: scramble + }); + }); +}); diff --git a/test/unit/connection/test-auth-password.js b/test/unit/connection/test-auth-password.js new file mode 100644 index 000000000..06f2aa48b --- /dev/null +++ b/test/unit/connection/test-auth-password.js @@ -0,0 +1,36 @@ +var common = require('../../common'); +var connection = common.createConnection({ + port : common.fakeServerPort, + password : 'passwd' +}); +var assert = require('assert'); +var Auth = require(common.lib + '/protocol/Auth'); +var Crypto = require('crypto'); + +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.connect(function (err) { + assert.ifError(err); + connection.destroy(); + server.destroy(); + }); +}); + +server.on('connection', function(incomingConnection) { + random(20, function (err, scramble) { + assert.ifError(err); + + incomingConnection.on('clientAuthentication', function (packet) { + this._sendAuthResponse(packet.scrambleBuff, Auth.token('passwd', scramble)); + }); + + incomingConnection.handshake({ + scrambleBuff1 : scramble.slice(0, 8), + scrambleBuff2 : scramble.slice(8, 20) + }); + }); +}); diff --git a/test/unit/connection/test-auth-switch-native.js b/test/unit/connection/test-auth-switch-native.js new file mode 100644 index 000000000..0d31dccb5 --- /dev/null +++ b/test/unit/connection/test-auth-switch-native.js @@ -0,0 +1,47 @@ +var assert = require('assert'); +var Crypto = require('crypto'); +var common = require('../../common'); +var connection = common.createConnection({ + port : common.fakeServerPort, + password : 'authswitch' +}); + +var random = Crypto.pseudoRandomBytes || Crypto.randomBytes; // Depends on node.js version +var server = common.createFakeServer(); + +var connected; +server.listen(common.fakeServerPort, function (err) { + assert.ifError(err); + + connection.connect(function (err, result) { + assert.ifError(err); + + connected = result; + + 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('authswitch', scramble)); + }); + + incomingConnection.on('clientAuthentication', function () { + this.authSwitchRequest({ + authMethodName : 'mysql_native_password', + authMethodData : scramble + }); + }); + + incomingConnection.handshake(); + }); +}); + +process.on('exit', function() { + assert.equal(connected.fieldCount, 0); +}); diff --git a/test/unit/connection/test-auth-switch-unknown.js b/test/unit/connection/test-auth-switch-unknown.js new file mode 100644 index 000000000..059ab912b --- /dev/null +++ b/test/unit/connection/test-auth-switch-unknown.js @@ -0,0 +1,34 @@ +var assert = require('assert'); +var Buffer = require('safe-buffer').Buffer; +var common = require('../../common'); +var connection = common.createConnection({ + port : common.fakeServerPort, + password : 'authswitch' +}); + +var server = common.createFakeServer(); + +server.listen(common.fakeServerPort, function (err) { + assert.ifError(err); + + connection.connect(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('clientAuthentication', function () { + this.authSwitchRequest({ + authMethodName : 'foo_plugin_password', + authMethodData : Buffer.alloc(0) + }); + }); + + incomingConnection.handshake(); +}); diff --git a/test/unit/connection/test-change-user-auth-switch-unknown.js b/test/unit/connection/test-change-user-auth-switch-unknown.js new file mode 100644 index 000000000..dcaa327f1 --- /dev/null +++ b/test/unit/connection/test-change-user-auth-switch-unknown.js @@ -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 --git a/test/unit/connection/test-change-user-auth-switch.js b/test/unit/connection/test-change-user-auth-switch.js new file mode 100644 index 000000000..f3f080549 --- /dev/null +++ b/test/unit/connection/test-change-user-auth-switch.js @@ -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 --git a/test/unit/connection/test-change-user-before-connect.js b/test/unit/connection/test-change-user-before-connect.js new file mode 100644 index 000000000..0549dd8ca --- /dev/null +++ b/test/unit/connection/test-change-user-before-connect.js @@ -0,0 +1,25 @@ +var assert = require('assert'); +var common = require('../../common'); +var connection = common.createConnection({ + port : common.fakeServerPort, + user : 'user_1' +}); + +var server = common.createFakeServer(); + +server.listen(common.fakeServerPort, function(err) { + assert.ifError(err); + assert.equal(connection.state, 'disconnected'); + + connection.changeUser({user: 'user_2'}, function (err) { + assert.ifError(err); + + connection.query('SELECT CURRENT_USER()', function (err, result) { + assert.ifError(err); + assert.strictEqual(result[0]['CURRENT_USER()'], 'user_2@localhost'); + + connection.destroy(); + server.destroy(); + }); + }); +}); diff --git a/test/unit/connection/test-change-user-timeout.js b/test/unit/connection/test-change-user-timeout.js new file mode 100644 index 000000000..ada603fc7 --- /dev/null +++ b/test/unit/connection/test-change-user-timeout.js @@ -0,0 +1,38 @@ +var assert = require('assert'); +var common = require('../../common'); +var connection = common.createConnection({ + port : common.fakeServerPort, + user : 'user_1' +}); + +var timeout = setTimeout(function () { + throw new Error('test timeout'); +}, 5000); + +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', timeout: 1000}, function (err) { + assert.ok(err); + assert.equal(err.code, 'PROTOCOL_SEQUENCE_TIMEOUT'); + assert.equal(err.message, 'ChangeUser inactivity timeout'); + + connection.destroy(); + server.destroy(); + clearTimeout(timeout); + }); + }); +}); + +server.on('connection', function (conn) { + conn.handshake(); + conn.on('changeUser', function () { + // do nothing + }); +}); diff --git a/test/unit/connection/test-connect-error-event.js b/test/unit/connection/test-connect-error-event.js index 53c5d5426..035445227 100644 --- a/test/unit/connection/test-connect-error-event.js +++ b/test/unit/connection/test-connect-error-event.js @@ -18,5 +18,5 @@ server.listen(common.fakeServerPort, function (err) { }); server.on('connection', function (conn) { - conn.deny('You suck.', common.Errors.ER_ACCESS_DENIED_ERROR); + conn.deny(); }); diff --git a/test/unit/connection/test-connection-error.js b/test/unit/connection/test-connection-error.js index 6016bc5f6..c5167de29 100644 --- a/test/unit/connection/test-connection-error.js +++ b/test/unit/connection/test-connection-error.js @@ -50,7 +50,7 @@ function end() { } server.on('connection', function(incomingConnection) { - incomingConnection.deny('You suck.', common.Errors.ER_HOST_NOT_PRIVILEGED); + incomingConnection.deny(); }); process.on('exit', function() { diff --git a/test/unit/connection/test-connection-ssl-ciphers.js b/test/unit/connection/test-connection-ssl-ciphers.js index 2a8f48e68..6a0335f76 100644 --- a/test/unit/connection/test-connection-ssl-ciphers.js +++ b/test/unit/connection/test-connection-ssl-ciphers.js @@ -4,7 +4,7 @@ var connection = common.createConnection({ port : common.fakeServerPort, ssl : { ca : common.getSSLConfig().ca, - ciphers : 'RC4-SHA' + ciphers : 'AES128-SHA' } }); @@ -17,7 +17,7 @@ server.listen(common.fakeServerPort, function (err) { assert.ifError(err); assert.equal(rows.length, 1); assert.equal(rows[0].Variable_name, 'Ssl_cipher'); - assert.equal(rows[0].Value, 'RC4-SHA'); + assert.equal(rows[0].Value, 'AES128-SHA'); connection.destroy(); server.destroy(); diff --git a/test/unit/connection/test-connection-thread-id-error.js b/test/unit/connection/test-connection-thread-id-error.js new file mode 100644 index 000000000..aea5617fc --- /dev/null +++ b/test/unit/connection/test-connection-thread-id-error.js @@ -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 --git a/test/unit/connection/test-debug-exclude.js b/test/unit/connection/test-debug-exclude.js index 72024e3da..406b045fc 100644 --- a/test/unit/connection/test-debug-exclude.js +++ b/test/unit/connection/test-debug-exclude.js @@ -4,7 +4,9 @@ var connection = common.createConnection({ debug : ['OkPacket', 'ComPingPacket'], port : common.fakeServerPort }); +var util = require('util'); +var tid = 0; var server = common.createFakeServer(); server.listen(common.fakeServerPort, function (err) { @@ -12,9 +14,10 @@ server.listen(common.fakeServerPort, function (err) { 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]); } }; @@ -22,12 +25,16 @@ server.listen(common.fakeServerPort, function (err) { assert.ifError(err); assert.equal(messages.length, 3); assert.deepEqual(messages, [ - '<-- OkPacket', - '--> ComPingPacket', - '<-- OkPacket' + '<-- (1) OkPacket', + '--> (1) ComPingPacket', + '<-- (1) OkPacket' ]); connection.destroy(); server.destroy(); }); }); + +server.on('connection', function (conn) { + conn.handshake({ threadId: ++tid }); +}); diff --git a/test/unit/connection/test-debug-parser-error.js b/test/unit/connection/test-debug-parser-error.js index af3d7b8af..cdca8759c 100644 --- a/test/unit/connection/test-debug-parser-error.js +++ b/test/unit/connection/test-debug-parser-error.js @@ -1,7 +1,9 @@ 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(); server.listen(common.fakeServerPort, function (err) { @@ -9,9 +11,10 @@ server.listen(common.fakeServerPort, function (err) { 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]); } }; @@ -20,11 +23,11 @@ server.listen(common.fakeServerPort, function (err) { assert.equal(messages.length, 6); assert.deepEqual(messages, [ '<-- HandshakeInitializationPacket', - '--> ClientAuthenticationPacket', - '<-- OkPacket', - '--> ComQueryPacket', - '<-- ResultSetHeaderPacket', - '<-- FieldPacket' + '--> (1) ClientAuthenticationPacket', + '<-- (1) OkPacket', + '--> (1) ComQueryPacket', + '<-- (1) ResultSetHeaderPacket', + '<-- (1) FieldPacket' ]); connection.destroy(); @@ -33,7 +36,7 @@ server.listen(common.fakeServerPort, function (err) { }); server.on('connection', function(conn) { - conn.handshake(); + conn.handshake({ threadId: ++tid }); conn.on('query', function(packet) { switch (packet.sql) { case 'SELECT value FROM stuff': diff --git a/test/unit/connection/test-debug.js b/test/unit/connection/test-debug.js index 11da5bb94..d6a27467f 100644 --- a/test/unit/connection/test-debug.js +++ b/test/unit/connection/test-debug.js @@ -1,7 +1,9 @@ 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(); server.listen(common.fakeServerPort, function (err) { @@ -9,9 +11,10 @@ server.listen(common.fakeServerPort, function (err) { 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]); } }; @@ -20,13 +23,17 @@ server.listen(common.fakeServerPort, function (err) { assert.equal(messages.length, 5); assert.deepEqual(messages, [ '<-- HandshakeInitializationPacket', - '--> ClientAuthenticationPacket', - '<-- OkPacket', - '--> ComPingPacket', - '<-- OkPacket' + '--> (1) ClientAuthenticationPacket', + '<-- (1) OkPacket', + '--> (1) ComPingPacket', + '<-- (1) OkPacket' ]); connection.destroy(); server.destroy(); }); }); + +server.on('connection', function (conn) { + conn.handshake({ threadId: ++tid }); +}); diff --git a/test/unit/connection/test-double-connect.js b/test/unit/connection/test-double-connect.js index 2aee44955..0ccee399a 100644 --- a/test/unit/connection/test-double-connect.js +++ b/test/unit/connection/test-double-connect.js @@ -1,3 +1,4 @@ +var after = require('after'); var assert = require('assert'); var common = require('../../common'); var connection = common.createConnection({port: common.fakeServerPort}); @@ -7,6 +8,11 @@ var server = common.createFakeServer(); server.listen(common.fakeServerPort, function (err) { assert.ifError(err); + var done = after(2, function () { + connection.destroy(); + server.destroy(); + }); + connection.connect(function (err) { assert.ifError(err); @@ -14,9 +20,14 @@ server.listen(common.fakeServerPort, function (err) { assert.ok(err, 'got error'); assert.equal(err.code, 'PROTOCOL_ENQUEUE_HANDSHAKE_TWICE'); assert.ok(!err.fatal); - - connection.destroy(); - server.destroy(); + done(); }); }); + + connection.connect(function (err) { + assert.ok(err, 'got error'); + assert.equal(err.code, 'PROTOCOL_ENQUEUE_HANDSHAKE_TWICE'); + assert.ok(!err.fatal); + done(); + }); }); diff --git a/test/unit/connection/test-exception-safety.js b/test/unit/connection/test-exception-safety.js index de62c719b..aa1470683 100644 --- a/test/unit/connection/test-exception-safety.js +++ b/test/unit/connection/test-exception-safety.js @@ -30,12 +30,12 @@ server.listen(common.fakeServerPort, function(err) { // Row streaming events connection.query('SELECT 1') - .on('fields', function() { - throw new Error('3'); - }) - .on('result', function() { - throw new Error('4'); - }); + .on('fields', function () { + throw new Error('3'); + }) + .on('result', function () { + throw new Error('4'); + }); // Normal callback with error connection.query('INVALID SQL', function(err) { @@ -45,9 +45,9 @@ server.listen(common.fakeServerPort, function(err) { // Row streaming 'result' event triggered by Ok Packet (special code path) connection.query('USE test') - .on('result', function() { - throw new Error('6'); - }); + .on('result', function () { + throw new Error('6'); + }); // Normal callback (same code path as connect, but in here should that // implementation detail change at some point). @@ -73,15 +73,10 @@ server.on('connection', function (conn) { conn.on('query', function(packet) { switch (packet.sql) { case 'INVALID SQL': - this._sendPacket(new common.Packets.ErrorPacket({ - errno : common.Errors.ER_PARSE_ERROR, - message : 'Parse error' - })); - this._parser.resetPacketNumber(); + this.error('Parse error', common.Errors.ER_PARSE_ERROR); break; case 'USE test': - this._sendPacket(new common.Packets.OkPacket()); - this._parser.resetPacketNumber(); + this.ok(); break; default: this._handleQueryPacket(packet); diff --git a/test/unit/connection/test-fatal-connect-error.js b/test/unit/connection/test-fatal-connect-error.js index 7f954ce11..e39825e8d 100644 --- a/test/unit/connection/test-fatal-connect-error.js +++ b/test/unit/connection/test-fatal-connect-error.js @@ -37,7 +37,7 @@ server.listen(common.fakeServerPort, function (err) { server.on('connection', function (conn) { if (count === 0) { - conn.deny('You suck.', common.Errors.ER_ACCESS_DENIED_ERROR); + conn.deny(); return; } diff --git a/test/unit/connection/test-insecure-auth-error.js b/test/unit/connection/test-insecure-auth-error.js new file mode 100644 index 000000000..b5d999827 --- /dev/null +++ b/test/unit/connection/test-insecure-auth-error.js @@ -0,0 +1,29 @@ +var assert = require('assert'); +var common = require('../../common'); +var connection = common.createConnection({ + port : common.fakeServerPort, + password : 'oldpw' +}); + +var server = common.createFakeServer(); + +server.listen(common.fakeServerPort, function (err) { + assert.ifError(err); + + connection.connect(function (err) { + assert.ok(err); + assert.equal(err.code, 'HANDSHAKE_INSECURE_AUTH'); + assert.equal(err.fatal, true); + + connection.destroy(); + server.destroy(); + }); +}); + +server.on('connection', function(incomingConnection) { + incomingConnection.on('clientAuthentication', function () { + this._sendPacket(new common.Packets.UseOldPasswordPacket()); + }); + + incomingConnection.handshake(); +}); diff --git a/test/unit/connection/test-large-blobs.js b/test/unit/connection/test-large-blobs.js index 2065e5881..fcaee32c1 100644 --- a/test/unit/connection/test-large-blobs.js +++ b/test/unit/connection/test-large-blobs.js @@ -1,4 +1,5 @@ var assert = require('assert'); +var Buffer = require('safe-buffer').Buffer; var common = require('../../common'); var connection = common.createConnection({port: common.fakeServerPort}); var server = common.createFakeServer(); @@ -41,27 +42,27 @@ server.on('connection', function(conn) { this._sendPacket(new common.Packets.EofPacket()); var writer = new common.PacketWriter(); - writer.writeLengthCodedBuffer(new Buffer(0)); + writer.writeLengthCodedBuffer(Buffer.alloc(0)); this._socket.write(writer.toBuffer(this._parser)); var writer = new common.PacketWriter(); - writer.writeLengthCodedBuffer(filledBuffer(8, '.')); + writer.writeLengthCodedBuffer(Buffer.alloc(8, '.')); this._socket.write(writer.toBuffer(this._parser)); var writer = new common.PacketWriter(); - writer.writeLengthCodedBuffer(filledBuffer((Math.pow(2, 16) - 1), '.')); + writer.writeLengthCodedBuffer(Buffer.alloc((Math.pow(2, 16) - 1), '.')); this._socket.write(writer.toBuffer(this._parser)); var writer = new common.PacketWriter(); - writer.writeLengthCodedBuffer(filledBuffer(Math.pow(2, 16), '.')); + writer.writeLengthCodedBuffer(Buffer.alloc(Math.pow(2, 16), '.')); this._socket.write(writer.toBuffer(this._parser)); var writer = new common.PacketWriter(); - writer.writeLengthCodedBuffer(filledBuffer((Math.pow(2, 24) - 1), '.')); + writer.writeLengthCodedBuffer(Buffer.alloc((Math.pow(2, 24) - 1), '.')); this._socket.write(writer.toBuffer(this._parser)); var writer = new common.PacketWriter(); - writer.writeLengthCodedBuffer(filledBuffer(Math.pow(2, 24), '.')); + writer.writeLengthCodedBuffer(Buffer.alloc(Math.pow(2, 24), '.')); this._socket.write(writer.toBuffer(this._parser)); this._sendPacket(new common.Packets.EofPacket()); @@ -73,13 +74,3 @@ server.on('connection', function(conn) { } }); }); - -function filledBuffer(size, fill) { - if (Buffer.alloc) { - return Buffer.alloc(size, fill); - } - - var buf = new Buffer(size); - buf.fill(fill); - return buf; -} diff --git a/test/unit/connection/test-load-data-infile-disable.js b/test/unit/connection/test-load-data-infile-disable.js new file mode 100644 index 000000000..03d2be114 --- /dev/null +++ b/test/unit/connection/test-load-data-infile-disable.js @@ -0,0 +1,41 @@ +var assert = require('assert'); +var common = require('../../common'); +var connection = common.createConnection({port: common.fakeServerPort, localInfile: false}); +var server = common.createFakeServer(); + +server.listen(common.fakeServerPort, function (err) { + assert.ifError(err); + + connection.query('LOAD DATA LOCAL INFILE ? INTO TABLE ??', ['data.csv', 'foo'], function (err, result) { + assert.ok(err); + assert.equal(err.code, 'LOCAL_FILES_DISABLED'); + assert.ok(!err.fatal); + assert.equal(result.affectedRows, 0); + + connection.destroy(); + server.destroy(); + }); +}); + +server.on('connection', function(conn) { + conn.on('clientAuthentication', function (packet) { + if (packet.clientFlags & common.ClientConstants.LOCAL_FILES) { + conn.deny(); + } else { + conn.ok(); + } + }); + conn.on('query', function (packet) { + if (packet.sql.indexOf('LOAD DATA LOCAL INFILE') === 0) { + conn.once('EmptyPacket', function () { + conn.ok(); + }); + this._sendPacket(new common.Packets.LocalInfileRequestPacket({ + filename: common.fixtures + '/data.csv' + })); + } else { + this._handleQueryPacket(packet); + } + }); + conn.handshake(); +}); diff --git a/test/unit/connection/test-old-password.js b/test/unit/connection/test-old-password.js deleted file mode 100644 index d9845c25c..000000000 --- a/test/unit/connection/test-old-password.js +++ /dev/null @@ -1,35 +0,0 @@ -var common = require('../../common'); -var connection = common.createConnection({ - port : common.fakeServerPort, - password : 'oldpw', - insecureAuth : true -}); -var assert = require('assert'); - -var server = common.createFakeServer(); - -var connected; -server.listen(common.fakeServerPort, function(err) { - if (err) throw err; - - connection.connect(function(err, result) { - if (err) throw err; - - connected = result; - - connection.destroy(); - server.destroy(); - }); -}); - -server.on('connection', function(incomingConnection) { - incomingConnection.handshake({ - user : connection.config.user, - password : connection.config.password, - oldPassword : true - }); -}); - -process.on('exit', function() { - assert.equal(connected.fieldCount, 0); -}); diff --git a/test/unit/connection/test-packet-out-of-order.js b/test/unit/connection/test-packet-out-of-order.js index 3d0eb10ea..c20e366bd 100644 --- a/test/unit/connection/test-packet-out-of-order.js +++ b/test/unit/connection/test-packet-out-of-order.js @@ -10,8 +10,7 @@ server.listen(common.fakeServerPort, function(err) { connection.connect(function(err) { assert.ifError(err); - serverConn._sendPacket(new common.Packets.OkPacket()); - serverConn._parser.resetPacketNumber(); + serverConn.ok(); connection.end(function(err) { assert.ok(err); diff --git a/test/unit/connection/test-password.js b/test/unit/connection/test-password.js deleted file mode 100644 index 5d92e2876..000000000 --- a/test/unit/connection/test-password.js +++ /dev/null @@ -1,33 +0,0 @@ -var common = require('../../common'); -var connection = common.createConnection({ - port : common.fakeServerPort, - password : 'passwd' -}); -var assert = require('assert'); - -var server = common.createFakeServer(); - -var connected; -server.listen(common.fakeServerPort, function(err) { - if (err) throw err; - - connection.connect(function(err, result) { - if (err) throw err; - - connected = result; - - connection.destroy(); - server.destroy(); - }); -}); - -server.on('connection', function(incomingConnection) { - incomingConnection.handshake({ - user : connection.config.user, - password : connection.config.password - }); -}); - -process.on('exit', function() { - assert.equal(connected.fieldCount, 0); -}); diff --git a/test/unit/connection/test-quit-ok-packet.js b/test/unit/connection/test-quit-ok-packet.js index 0996221d6..5781a5b81 100644 --- a/test/unit/connection/test-quit-ok-packet.js +++ b/test/unit/connection/test-quit-ok-packet.js @@ -16,7 +16,6 @@ server.listen(common.fakeServerPort, function (err) { server.on('connection', function (conn) { conn.handshake(); conn.on('quit', function () { - conn._sendPacket(new common.Packets.OkPacket()); - conn._parser.resetPacketNumber(); + conn.ok(); }); }); diff --git a/test/unit/pool-cluster/test-connection-error.js b/test/unit/pool-cluster/test-connection-error.js index 9968f93de..e9b548360 100644 --- a/test/unit/pool-cluster/test-connection-error.js +++ b/test/unit/pool-cluster/test-connection-error.js @@ -15,7 +15,7 @@ server.listen(common.fakeServerPort, function(err) { cluster.getConnection('MASTER', function (err) { assert.ok(err); - assert.equal(err.code, 'ER_HOST_NOT_PRIVILEGED'); + assert.equal(err.code, 'ER_ACCESS_DENIED_ERROR'); assert.equal(err.fatal, true); assert.equal(connCount, 5); @@ -28,5 +28,5 @@ server.listen(common.fakeServerPort, function(err) { server.on('connection', function(incomingConnection) { connCount += 1; - incomingConnection.deny('You suck.', common.Errors.ER_HOST_NOT_PRIVILEGED); + incomingConnection.deny(); }); diff --git a/test/unit/pool-cluster/test-connection-no-retry.js b/test/unit/pool-cluster/test-connection-no-retry.js index f33ac6c1b..3c3387922 100644 --- a/test/unit/pool-cluster/test-connection-no-retry.js +++ b/test/unit/pool-cluster/test-connection-no-retry.js @@ -12,7 +12,7 @@ server.listen(common.fakeServerPort, function(err) { cluster.getConnection('MASTER', function (err) { assert.ok(err); - assert.equal(err.code, 'ER_HOST_NOT_PRIVILEGED'); + assert.equal(err.code, 'ER_ACCESS_DENIED_ERROR'); assert.equal(err.fatal, true); assert.equal(connCount, 1); @@ -25,5 +25,5 @@ server.listen(common.fakeServerPort, function(err) { server.on('connection', function (conn) { connCount += 1; - conn.deny('You suck.', common.Errors.ER_HOST_NOT_PRIVILEGED); + conn.deny(); }); diff --git a/test/unit/pool-cluster/test-connection-order-fatal.js b/test/unit/pool-cluster/test-connection-order-fatal.js index e2a86abd0..6dfe718ed 100644 --- a/test/unit/pool-cluster/test-connection-order-fatal.js +++ b/test/unit/pool-cluster/test-connection-order-fatal.js @@ -24,16 +24,12 @@ server.listen(common.fakeServerPort, function(err) { pool.getConnection(function (err, connection) { assert.ifError(err); assert.strictEqual(connection._clusterId, 'SLAVE2'); - - conn1 = connection; done(); }); pool.getConnection(function (err, connection) { assert.ifError(err); assert.strictEqual(connection._clusterId, 'SLAVE2'); - - conn2 = connection; done(); }); }); diff --git a/test/unit/pool-cluster/test-connection-rr.js b/test/unit/pool-cluster/test-connection-rr.js index 905349d35..5c6b8dad4 100644 --- a/test/unit/pool-cluster/test-connection-rr.js +++ b/test/unit/pool-cluster/test-connection-rr.js @@ -29,12 +29,16 @@ server.listen(common.fakeServerPort, function(err) { var pool = cluster.of('SLAVE*', 'RR'); - for (var i = 0; i < count; i++) { + function getConnection(i) { pool.getConnection(function (err, conn) { assert.ifError(err); - order.push(conn._clusterId); + order[i] = conn._clusterId; conn.release(); done(); }); } + + for (var i = 0; i < count; i++) { + getConnection(i); + } }); diff --git a/test/unit/pool-cluster/test-pattern.js b/test/unit/pool-cluster/test-pattern.js index 262c0d17c..8e2941b60 100644 --- a/test/unit/pool-cluster/test-pattern.js +++ b/test/unit/pool-cluster/test-pattern.js @@ -5,7 +5,7 @@ var server = common.createFakeServer(); var poolConfig = common.getTestConfig({port: common.fakeServerPort}); cluster.add('MASTER', poolConfig); -cluster.add('SLAVE' , poolConfig); +cluster.add('SLAVE', poolConfig); cluster.add('SLAVE1', poolConfig); cluster.add('SLAVE2', poolConfig); diff --git a/test/unit/pool-cluster/test-query-connection-error.js b/test/unit/pool-cluster/test-query-connection-error.js index 3011ad2f4..c01be16ae 100644 --- a/test/unit/pool-cluster/test-query-connection-error.js +++ b/test/unit/pool-cluster/test-query-connection-error.js @@ -15,11 +15,11 @@ server.listen(common.fakeServerPort, function (err) { pool.query('SELECT 1', function (err) { assert.ok(err, 'got error'); - assert.equal(err.code, 'ER_HOST_NOT_PRIVILEGED'); + assert.equal(err.code, 'ER_ACCESS_DENIED_ERROR'); server.destroy(); }); }); server.on('connection', function (conn) { - conn.deny('You suck.', common.Errors.ER_HOST_NOT_PRIVILEGED); + conn.deny(); }); diff --git a/test/unit/pool/test-acquire-timeout-existing.js b/test/unit/pool/test-acquire-timeout-existing.js index ffdb41603..aa0f74316 100644 --- a/test/unit/pool/test-acquire-timeout-existing.js +++ b/test/unit/pool/test-acquire-timeout-existing.js @@ -43,14 +43,12 @@ server.listen(common.fakeServerPort, function (err) { }); server.on('connection', function(incomingConnection) { - serverConn = incomingConnection; incomingConnection.handshake({ threadId: ++tid }); incomingConnection.on('ping', function() { if (!fail) { - this._sendPacket(new common.Packets.OkPacket()); - this._parser.resetPacketNumber(); + this.ok(); } fail = false; diff --git a/test/unit/pool/test-connection-bad.js b/test/unit/pool/test-connection-bad.js index e9b6dbac4..c96f51f9c 100644 --- a/test/unit/pool/test-connection-bad.js +++ b/test/unit/pool/test-connection-bad.js @@ -42,7 +42,6 @@ server.listen(common.fakeServerPort, function(err){ }); server.on('connection', function(incomingConnection) { - serverConn = incomingConnection; incomingConnection.handshake({ threadId: ++tid }); @@ -50,8 +49,7 @@ server.on('connection', function(incomingConnection) { if (fail) { setTimeout(this.destroy.bind(this), 100); } else { - this._sendPacket(new common.Packets.OkPacket()); - this._parser.resetPacketNumber(); + this.ok(); } fail = false; diff --git a/test/unit/pool/test-debug.js b/test/unit/pool/test-debug.js new file mode 100644 index 000000000..e9953cd1a --- /dev/null +++ b/test/unit/pool/test-debug.js @@ -0,0 +1,67 @@ +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(); + +server.listen(common.fakeServerPort, function (err) { + assert.ifError(err); + + var messages = []; + + console.log = function () { + var msg = util.format.apply(this, arguments); + if (String(msg).indexOf('--') !== -1) { + messages.push(msg.split(' {')[0]); + } + }; + + pool.getConnection(function (err, conn1) { + assert.ifError(err); + conn1.query('SELECT 1', function (err) { + assert.ifError(err); + pool.getConnection(function (err, conn2) { + assert.ifError(err); + conn2.query('SELECT 1', function (err) { + assert.ifError(err); + conn1.release(); + conn2.release(); + pool.end(function (err) { + assert.ifError(err); + assert.equal(messages.length, 20); + assert.deepEqual(messages, [ + '<-- HandshakeInitializationPacket', + '--> (1) ClientAuthenticationPacket', + '<-- (1) OkPacket', + '--> (1) ComQueryPacket', + '<-- (1) ResultSetHeaderPacket', + '<-- (1) FieldPacket', + '<-- (1) EofPacket', + '<-- (1) RowDataPacket', + '<-- (1) EofPacket', + '<-- HandshakeInitializationPacket', + '--> (2) ClientAuthenticationPacket', + '<-- (2) OkPacket', + '--> (2) ComQueryPacket', + '<-- (2) ResultSetHeaderPacket', + '<-- (2) FieldPacket', + '<-- (2) EofPacket', + '<-- (2) RowDataPacket', + '<-- (2) EofPacket', + '--> (1) ComQuitPacket', + '--> (2) ComQuitPacket' + ]); + + server.destroy(); + }); + }); + }); + }); + }); +}); + +server.on('connection', function (conn) { + conn.handshake({ threadId: ++tid }); +}); diff --git a/test/unit/pool/test-end-ping.js b/test/unit/pool/test-end-ping.js index acf57d690..eb27edcb9 100644 --- a/test/unit/pool/test-end-ping.js +++ b/test/unit/pool/test-end-ping.js @@ -33,8 +33,7 @@ server.on('connection', function (conn) { conn.handshake(); conn.on('ping', function () { setTimeout(function () { - conn._sendPacket(new common.Packets.OkPacket()); - conn._parser.resetPacketNumber(); + conn.ok(); }, 100); }); }); diff --git a/test/unit/pool/test-protocol-stray-packet.js b/test/unit/pool/test-protocol-stray-packet.js index d4d96ec44..c87e31504 100644 --- a/test/unit/pool/test-protocol-stray-packet.js +++ b/test/unit/pool/test-protocol-stray-packet.js @@ -3,7 +3,8 @@ var common = require('../../common'); var pool = common.createPool({port: common.fakeServerPort}); var server = common.createFakeServer(); -var connCount = 0; +var connCount = 0; +var connection = null; server.listen(common.fakeServerPort, function (err) { assert.ifError(err); @@ -18,10 +19,12 @@ server.listen(common.fakeServerPort, function (err) { pool.query('SELECT 1', function (err) { assert.ifError(err); - pool.getConnection(function (err) { + pool.getConnection(function (err, conn) { assert.ifError(err); assert.equal(connCount, 2); + connection = conn; + pool.end(function (err) { assert.ifError(err); server.destroy(); diff --git a/test/unit/pool/test-query-connection-error.js b/test/unit/pool/test-query-connection-error.js index 48fe5f6eb..d1c8f7c43 100644 --- a/test/unit/pool/test-query-connection-error.js +++ b/test/unit/pool/test-query-connection-error.js @@ -8,12 +8,12 @@ server.listen(common.fakeServerPort, function (err) { pool.query('SELECT 1', function (err) { assert.ok(err, 'got error'); - assert.equal(err.code, 'ER_HOST_NOT_PRIVILEGED'); + assert.equal(err.code, 'ER_ACCESS_DENIED_ERROR'); assert.equal(err.fatal, true); server.destroy(); }); }); server.on('connection', function (conn) { - conn.deny('You suck.', common.Errors.ER_HOST_NOT_PRIVILEGED); + conn.deny(); }); diff --git a/test/unit/pool/test-query-stream-connection-error.js b/test/unit/pool/test-query-stream-connection-error.js index 402fd4431..bb57e43fe 100644 --- a/test/unit/pool/test-query-stream-connection-error.js +++ b/test/unit/pool/test-query-stream-connection-error.js @@ -10,12 +10,12 @@ server.listen(common.fakeServerPort, function (err) { query.on('error', function (err) { assert.ok(err, 'got error'); - assert.equal(err.code, 'ER_HOST_NOT_PRIVILEGED'); + assert.equal(err.code, 'ER_ACCESS_DENIED_ERROR'); assert.equal(err.fatal, true); server.destroy(); }); }); server.on('connection', function (conn) { - conn.deny('You suck.', common.Errors.ER_HOST_NOT_PRIVILEGED); + conn.deny(); }); diff --git a/test/unit/protocol/test-Parser.js b/test/unit/protocol/test-Parser.js index 032bf7b81..112aebed2 100644 --- a/test/unit/protocol/test-Parser.js +++ b/test/unit/protocol/test-Parser.js @@ -1,10 +1,11 @@ +var Buffer = require('safe-buffer').Buffer; var common = require('../../common'); var test = require('utest'); var assert = require('assert'); var Parser = common.Parser; function packet(bytes) { - var buffer = new Buffer(bytes); + var buffer = Buffer.from(bytes); var parser = new Parser(); parser.append(buffer); @@ -14,17 +15,16 @@ function packet(bytes) { test('Parser', { "parseBuffer: buffer won\'t change after appending another one": function() { - var startBuffer = new Buffer(5); - startBuffer.fill('a'); + var startBuffer = Buffer.alloc(5, 'a'); + var parser = new Parser(); - var parser = new Parser(); parser.append(startBuffer); var value = parser.parseBuffer(4); assert.equal(value.toString(), 'aaaa'); - parser.append(new Buffer('b')); + parser.append(Buffer.from('b')); assert.equal(value.toString(), 'aaaa'); }, diff --git a/test/unit/protocol/test-SqlString.js b/test/unit/protocol/test-SqlString.js index dabbf378f..63fdb54eb 100644 --- a/test/unit/protocol/test-SqlString.js +++ b/test/unit/protocol/test-SqlString.js @@ -1,3 +1,4 @@ +var Buffer = require('safe-buffer').Buffer; var common = require('../../common'); var test = require('utest'); var assert = require('assert'); @@ -63,7 +64,7 @@ test('SqlString.escape', { }, 'nested arrays are turned into grouped lists': function() { - assert.equal(SqlString.escape([[1,2,3], [4,5,6], ['a', 'b', {nested: true}]]), "(1, 2, 3), (4, 5, 6), ('a', 'b', '[object Object]')"); + assert.equal(SqlString.escape([[1, 2, 3], [4, 5, 6], ['a', 'b', {nested: true}]]), "(1, 2, 3), (4, 5, 6), ('a', 'b', '[object Object]')"); }, 'nested objects inside arrays are cast to strings': function() { @@ -128,7 +129,7 @@ test('SqlString.escape', { }, 'buffers are converted to hex': function() { - var buffer = new Buffer([0, 1, 254, 255]); + var buffer = Buffer.from([0, 1, 254, 255]); var string = SqlString.escape(buffer); assert.strictEqual(string, "X'0001feff'"); diff --git a/test/unit/query/test-args-query-bad-callback.js b/test/unit/query/test-args-query-bad-callback.js new file mode 100644 index 000000000..5f531fc79 --- /dev/null +++ b/test/unit/query/test-args-query-bad-callback.js @@ -0,0 +1,20 @@ +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.throws(function () { + connection.query('SELECT ?', [1], 'oops'); + }, /TypeError: argument callback must be a function when provided/); + + assert.throws(function () { + connection.query({ sql: 'SELECT ?' }, [1], 'oops'); + }, /TypeError: argument callback must be a function when provided/); + + connection.destroy(); + server.destroy(); +}); diff --git a/test/unit/query/test-args-query-like-object-values.js b/test/unit/query/test-args-query-like-object-values.js new file mode 100644 index 000000000..28a7368b0 --- /dev/null +++ b/test/unit/query/test-args-query-like-object-values.js @@ -0,0 +1,29 @@ +var assert = require('assert'); +var common = require('../../common'); +var connection = common.createConnection({port: common.fakeServerPort}); + +var server = common.createFakeServer(); +var sqlQuery = Object.create(null, { + sql: { + enumerable : false, + value : 'SELECT ?', + writable : false + }, + values: { + enumerable : false, + value : [42], + writable : false + } +}); + +server.listen(common.fakeServerPort, function (err) { + assert.ifError(err); + + connection.query(sqlQuery, [99], function (err, rows) { + assert.ifError(err); + assert.strictEqual(rows.length, 1); + assert.strictEqual(rows[0]['99'], 99); + connection.destroy(); + server.destroy(); + }); +}); diff --git a/test/unit/query/test-args-query-like-object.js b/test/unit/query/test-args-query-like-object.js new file mode 100644 index 000000000..9b98025bf --- /dev/null +++ b/test/unit/query/test-args-query-like-object.js @@ -0,0 +1,29 @@ +var assert = require('assert'); +var common = require('../../common'); +var connection = common.createConnection({port: common.fakeServerPort}); + +var server = common.createFakeServer(); +var sqlQuery = Object.create(null, { + sql: { + enumerable : false, + value : 'SELECT ?', + writable : false + }, + values: { + enumerable : false, + value : [42], + writable : false + } +}); + +server.listen(common.fakeServerPort, function (err) { + assert.ifError(err); + + connection.query(sqlQuery, function (err, rows) { + assert.ifError(err); + assert.strictEqual(rows.length, 1); + assert.strictEqual(rows[0]['42'], 42); + connection.destroy(); + server.destroy(); + }); +}); diff --git a/test/unit/query/test-error-event.js b/test/unit/query/test-error-event.js index fdd11687a..be0d7dae2 100644 --- a/test/unit/query/test-error-event.js +++ b/test/unit/query/test-error-event.js @@ -12,6 +12,7 @@ server.listen(common.fakeServerPort, function (err) { query.on('error', function (err) { assert.ok(err, 'got error'); assert.equal(err.code, 'ER_PARSE_ERROR'); + assert.equal(err.sql, 'INVALID SQL'); assert.ok(!err.fatal); connection.destroy(); server.destroy(); diff --git a/test/unit/test-ConnectionConfig.js b/test/unit/test-ConnectionConfig.js index b3db4932f..67e573468 100644 --- a/test/unit/test-ConnectionConfig.js +++ b/test/unit/test-ConnectionConfig.js @@ -1,4 +1,5 @@ var common = require('../common'); +var Crypto = require('crypto'); var test = require('utest'); var assert = require('assert'); var ConnectionConfig = common.ConnectionConfig; @@ -56,7 +57,7 @@ test('ConnectionConfig#Constructor', { }, 'ignores empty client flags': function() { - var config = new ConnectionConfig({ flags: '-FOUND_ROWS,,+IGNORE_SPACE' }); + var config = new ConnectionConfig({ flags: ',-FOUND_ROWS,,+IGNORE_SPACE' }); assert.equal(config.clientFlags & common.ClientConstants.CLIENT_FOUND_ROWS, 0); assert.notEqual(config.clientFlags & common.ClientConstants.CLIENT_IGNORE_SPACE, 0); }, @@ -168,13 +169,24 @@ test('ConnectionConfig#Constructor.ssl', { assert.equal(config.ssl, false); }, - 'string loads pre-defined profile': function() { + 'string "Amazon RDS" loads valid profile': function() { var config = new ConnectionConfig({ ssl: 'Amazon RDS' }); assert.ok(config.ssl); - assert.ok(/-----BEGIN CERTIFICATE-----/.test(config.ssl.ca)); + assert.ok(Array.isArray(config.ssl.ca)); + + config.ssl.ca.forEach(function (ca) { + assert.equal(typeof ca, 'string', 'ca is a string'); + + if (Crypto.createPublicKey) { + var key = null; + + assert.doesNotThrow(function () { key = Crypto.createPublicKey(ca); }); + assert.equal(key.type, 'public'); + } + }); }, 'throws on unknown profile name': function() { diff --git a/test/unit/test-Mysql.js b/test/unit/test-Mysql.js index 8cc627c75..c12f15699 100644 --- a/test/unit/test-Mysql.js +++ b/test/unit/test-Mysql.js @@ -20,6 +20,16 @@ test('Mysql.format', { } }); +test('Mysql.raw', { + 'generate object format will not escape': function() { + var now = Mysql.raw('NOW()'); + assert.equal( + Mysql.format('SELECT * FROM ?? WHERE ?? >= ?', ['table', 'property', now]), + 'SELECT * FROM `table` WHERE `property` >= NOW()' + ); + } +}); + test('Mysql.Types', { 'exported object of types': function() { assert.equal(typeof Mysql.Types, 'object'); @@ -27,12 +37,24 @@ test('Mysql.Types', { 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) { + 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) { - assert.ok(/^[A-Z_]+/.test(type)); - assert.equal(typeof Mysql.Types[type], 'number'); + if (/^[0-9]+$/.test(type)) { + assert.equal(typeof Mysql.Types[type], 'string'); + } }); } }); diff --git a/tool/free-port.js b/tool/free-port.js new file mode 100644 index 000000000..a624b9bc4 --- /dev/null +++ b/tool/free-port.js @@ -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 --git a/tool/generate-error-constants.js b/tool/generate-error-constants.js index 38fb91ae4..cf4354cfd 100755 --- a/tool/generate-error-constants.js +++ b/tool/generate-error-constants.js @@ -107,13 +107,15 @@ function appendDatabseErrorCodes(srcDir, codes) { function appendSqlErrorCodes(srcDir, codes) { var errorFile = path.join(srcDir, 'sql', 'share', 'errmsg-utf8.txt'); var contents = fs.readFileSync(errorFile, 'utf-8'); - var offset = Number(contents.match(/start-error-number (\d+)/)[1]); - var names = contents.match(/^([A-Z0-9_]+)/mg).map(fixupCode); - var num = 0; + var sections = contents.split(/^start-error-number (\d+)$/m); - for (var i = 0; i < names.length; i++) { - num = offset + i; - codes[num] = names[i]; + for (var i = 1; i < sections.length; i += 2) { + var offset = Number(sections[i]); + var names = sections[i + 1].match(/^([A-Z0-9_]+)/mg).map(fixupCode); + + for (var j = 0; j < names.length; j++) { + codes[offset + j] = names[j]; + } } return codes; @@ -138,10 +140,10 @@ function extractMySqlVersion(srcDir) { function fixupCode(code) { return code - // remove obsolete markers - .replace('ER_OBSOLETE_', 'ER_') - // remove unused markers - .replace(/(?:_OLD)?_+UNUSED$/, ''); + // remove obsolete markers + .replace('ER_OBSOLETE_', 'ER_') + // remove unused markers + .replace(/(?:_OLD)?_+UNUSED$/, ''); } function keepUnusedCodes(previousCodes, currentCodes) { diff --git a/tool/generate-type-constants.js b/tool/generate-type-constants.js new file mode 100755 index 000000000..8275c8715 --- /dev/null +++ b/tool/generate-type-constants.js @@ -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 --git a/tool/install-nyc.js b/tool/install-nyc.js new file mode 100644 index 000000000..1c9800950 --- /dev/null +++ b/tool/install-nyc.js @@ -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 --git a/tool/lint-readme.js b/tool/lint-readme.js new file mode 100644 index 000000000..b6ef74c86 --- /dev/null +++ b/tool/lint-readme.js @@ -0,0 +1,75 @@ +var fs = require('fs'); +var path = require('path'); +var util = require('util'); + +var MARKDOWN_SECTION_REGEXP = /^(#+) (.+)$/; +var NEWLINE_REGEXP = /\r?\n/; +var README_PATH = path.join(__dirname, '..', 'Readme.md'); +var README_CONTENTS = fs.readFileSync(README_PATH, 'utf-8'); +var TOC_SECTION_NAME = 'Table of Contents'; + +var currentSectionLevel = null; +var currentSectionName = null; +var currentToc = []; +var expectedToc = []; +var tocOffset = 0; + +README_CONTENTS.split(NEWLINE_REGEXP).forEach(function (line, index) { + var match = MARKDOWN_SECTION_REGEXP.exec(line); + + if (match) { + currentSectionLevel = match[1].length; + currentSectionName = match[2]; + + if (currentSectionName === TOC_SECTION_NAME) { + tocOffset = index; + } + + if (currentSectionLevel > 1 && currentSectionName !== TOC_SECTION_NAME) { + expectedToc.push(util.format('%s- [%s](%s)', + repeat(' ', (currentSectionLevel - 2)), currentSectionName, toAnchor(currentSectionName))); + } + } else if (currentSectionName === TOC_SECTION_NAME) { + currentToc.push(line); + } +}); + +var index = 0; + +if (currentToc[index++].length !== 0) { + expect((tocOffset + index), 'blank line', currentToc[index - 1]); +} + +expectedToc.forEach(function (expectedLine) { + var currentLine = currentToc[index++] || ''; + + if (expectedLine !== currentLine) { + var currentIndex = currentToc.indexOf(expectedLine); + + expect((tocOffset + index), ('"' + expectedLine + '"'), currentLine); + + if (currentIndex !== -1) { + index = currentIndex + 1; + } + } +}); + +function expect (lineidx, message, line) { + console.log('Expected %s on line %d', message, (lineidx + 1)); + console.log(' Got: %s', line); + process.exitCode = 1; +} + +function repeat (str, num) { + var s = ''; + + for (var i = 0; i < num; i++) { + s += str; + } + + return s; +} + +function toAnchor (section) { + return '#' + section.toLowerCase().replace(/ /g, '-'); +} diff --git a/tool/mysql-version.js b/tool/mysql-version.js new file mode 100644 index 000000000..06f14fe29 --- /dev/null +++ b/tool/mysql-version.js @@ -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 --git a/tool/version-changes.js b/tool/version-changes.js new file mode 100755 index 000000000..b46df25f5 --- /dev/null +++ b/tool/version-changes.js @@ -0,0 +1,35 @@ +#!/usr/bin/env node +var fs = require('fs'); +var path = require('path'); + +var changesFilePath = path.join(__dirname, '..', 'Changes.md'); +var changesFileContents = fs.readFileSync(changesFilePath, 'utf-8'); +var changesHeadRegexp = /^## HEAD$/m; +var date = getLocaleDate(); +var version = process.env.npm_package_version; + +if (!changesHeadRegexp.test(changesFileContents)) { + console.error('Changes.md missing version marker.'); + process.exit(1); +} + +fs.writeFileSync(changesFilePath, + changesFileContents.replace(changesHeadRegexp, '## v' + version + ' (' + date + ')')); + +function getLocaleDate() { + var now = new Date(); + + return zeroPad(now.getFullYear(), 4) + '-' + + zeroPad(now.getMonth() + 1, 2) + '-' + + zeroPad(now.getDate(), 2); +} + +function zeroPad(number, length) { + number = number.toString(); + + while (number.length < length) { + number = '0' + number; + } + + return number; +} diff --git a/tool/wait-mysql.js b/tool/wait-mysql.js new file mode 100644 index 000000000..df11174d7 --- /dev/null +++ b/tool/wait-mysql.js @@ -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(); +}