This repository was archived by the owner on Apr 3, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 21
feat(mysql): Add config option for REQUIRED_SQL_MODES. #334
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -72,18 +72,16 @@ module.exports = function (log, error) { | |
| options.master.charset = options.charset | ||
| options.slave.charset = options.charset | ||
|
|
||
| var mode = REQUIRED_SQL_MODES.join(',') | ||
| if (options.sql_mode && options.sql_mode !== mode) { | ||
| log.error('createPoolCluster.invalidSqlMode', { sql_mode: options.sql_mode }) | ||
| throw new Error(`You cannot use any sql mode other than ${mode}`) | ||
| } else { | ||
| options.sql_mode = REQUIRED_SQL_MODES.join(',') | ||
| this.requiredModes = REQUIRED_SQL_MODES | ||
| if (options.requiredSQLModes) { | ||
| this.requiredModes = options.requiredSQLModes.split(',') | ||
| this.requiredModes.forEach(mode => { | ||
| if (! /^[A-Z0-9_]+$/.test(mode)) { | ||
| throw new Error('Invalid SQL mode: ' + mode) | ||
| } | ||
| }) | ||
| } | ||
|
|
||
| options.master.sql_mode = options.sql_mode | ||
| options.slave.sql_mode = options.sql_mode | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The MySQL module docs don't mention this |
||
|
|
||
|
|
||
| // Use separate pools for master and slave connections. | ||
| this.poolCluster.add('MASTER', options.master) | ||
| this.poolCluster.add('SLAVE', options.slave) | ||
|
|
@@ -1155,22 +1153,37 @@ module.exports = function (log, error) { | |
| return resolve(connection) | ||
| } | ||
|
|
||
| var mode = REQUIRED_SQL_MODES.join(',') | ||
| connection.query(`SET SESSION sql_mode = '${mode}';`, (err) => { | ||
| // Enforce sane defaults on every new connection. | ||
| // These *should* be set by the database by default, but it's nice | ||
| // to have an additional layer of protection here. | ||
| connection.query('SELECT @@sql_mode AS mode;', (err, rows) => { | ||
| if (err) { | ||
| return reject(err) | ||
| } | ||
|
|
||
| connection.query('SET NAMES utf8mb4 COLLATE utf8mb4_bin;', (err) => { | ||
| const currentModes = rows[0]['mode'].split(',') | ||
| this.requiredModes.forEach(requiredMode => { | ||
| if (currentModes.indexOf(requiredMode) === -1) { | ||
| currentModes.push(requiredMode) | ||
| } | ||
| }) | ||
|
|
||
| const newMode = currentModes.join(',') | ||
| connection.query(`SET SESSION sql_mode = '${newMode}';`, (err) => { | ||
| if (err) { | ||
| return reject(err) | ||
| } | ||
|
|
||
| connection._fxa_initialized = true | ||
| resolve(connection) | ||
| connection.query('SET NAMES utf8mb4 COLLATE utf8mb4_bin;', (err) => { | ||
| if (err) { | ||
| return reject(err) | ||
| } | ||
|
|
||
| connection._fxa_initialized = true | ||
| resolve(connection) | ||
| }) | ||
| }) | ||
| }) | ||
|
|
||
| }) | ||
| }) | ||
| } | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -26,7 +26,7 @@ describe('MySQL', () => { | |
| }) | ||
|
|
||
| it( | ||
| 'forces REQUIRED_CHARSET for connections', | ||
| 'validates REQUIRED_CHARSET for connections', | ||
| () => { | ||
| const configCharset = Object.assign({}, config) | ||
| configCharset.charset = 'wat' | ||
|
|
@@ -42,20 +42,51 @@ describe('MySQL', () => { | |
| ) | ||
|
|
||
| it( | ||
| 'forces REQUIRED_SQL_MODES for connections', | ||
| 'accepts REQUIRED_SQL_MODES from config', | ||
| () => { | ||
| const configSqlMode = Object.assign({}, config) | ||
| const REQUIRED_SQL_MODES = [ | ||
| 'STRICT_ALL_TABLES', | ||
| 'NO_ENGINE_SUBSTITUTION', | ||
| ] | ||
| var mode = REQUIRED_SQL_MODES.join(',') | ||
| configSqlMode.sql_mode = 'xyz' | ||
| return DB.connect(configSqlMode) | ||
| const configModes = Object.assign({}, config) | ||
| configModes.requiredSQLModes = 'STRICT_TRANS_TABLES,NO_ZERO_DATE' | ||
|
|
||
| return DB.connect(configModes) | ||
| .then( | ||
| db => { | ||
| assert.deepEqual(db.requiredModes, [ | ||
| 'STRICT_TRANS_TABLES', | ||
| 'NO_ZERO_DATE' | ||
| ]) | ||
| }, | ||
| assert.fail | ||
| ) | ||
| } | ||
| ) | ||
|
|
||
| it( | ||
| 'rejects unrecognized REQUIRED_SQL_MODES values from config', | ||
| () => { | ||
| const configModes = Object.assign({}, config) | ||
| configModes.requiredSQLModes = 'UNRECOGNIZED_SQL_MODE_NONSENSE' | ||
|
|
||
| return DB.connect(configModes) | ||
| .then( | ||
| assert.fail, | ||
| err => { | ||
| assert.equal(err.message, 'ER_WRONG_VALUE_FOR_VAR') | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The fact that MySQL rejects this value, is a useful test that we are actually attempting to call |
||
| } | ||
| ) | ||
| } | ||
| ) | ||
|
|
||
| it( | ||
| 'rejects badly-formed REQUIRED_SQL_MODES from config, for safety', | ||
| () => { | ||
| const configModes = Object.assign({}, config) | ||
| configModes.requiredSQLModes = 'TEST,MODE,\'; DROP TABLE users;' | ||
|
|
||
| return DB.connect(configModes) | ||
| .then( | ||
| assert.fail, | ||
| err => { | ||
| assert.equal(err.message, `You cannot use any sql mode other than ${mode}`) | ||
| assert.ok(err.message.indexOf('Invalid SQL mode') === 0) | ||
| } | ||
| ) | ||
| } | ||
|
|
||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good, let's just not forget to actually set this at some point :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you leave it unset, it should use the hard-coded defaults from
const REQUIRED_SQL_MODES; perhaps the config doc here could have made that clearer.