Skip to content

Commit 6bfa2af

Browse files
committed
lib: Always drop keys not created by mysql-plus during migrations
This fixes a bug where mysql-plus would crash when attempting to drop a key it didn't create.
1 parent 1da7a2a commit 6bfa2af

File tree

2 files changed

+99
-3
lines changed

2 files changed

+99
-3
lines changed

lib/TableDefinition.js

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ class TableDefinition {
9696
this._getMigrateKeysOperations(oldSchema, KEY_TYPES.UNIQUE, 'uniqueKeys'),
9797
this._getMigrateKeysOperations(oldSchema, KEY_TYPES.INDEX, 'indexes'),
9898
this._getMigrateKeysOperations(oldSchema, KEY_TYPES.SPATIAL, 'spatialIndexes'),
99+
this._getDropUnknownKeysOperations(oldSchema),
99100
this._getMigrateTableOptionsOperations(oldSchema)
100101
);
101102
const operations = this._getMigrateForeignKeysOperations(oldSchema, alterOperations);
@@ -217,6 +218,21 @@ class TableDefinition {
217218
return operations;
218219
}
219220

221+
_getDropUnknownKeysOperations(oldSchema) {
222+
const operations = [];
223+
const unknownKeys = oldSchema.$unknownKeys;
224+
225+
for (var i = 0; i < unknownKeys.length; i++) {
226+
operations.push(Operation.create(
227+
Operation.Types.DROP_KEY,
228+
'DROP KEY ' + this._pool.escapeId(unknownKeys[i].name),
229+
unknownKeys[i].columns
230+
));
231+
}
232+
233+
return operations;
234+
}
235+
220236
_getMigrateForeignKeysOperations(oldSchema, otherOperations) {
221237
const operations = [];
222238
const oldForeignKeys = oldSchema.foreignKeys;
@@ -582,6 +598,7 @@ function sqlToSchema(sql) {
582598
indexes: generateKeysSchema(createDefinitions, KEY_TYPES.INDEX),
583599
spatialIndexes: generateKeysSchema(createDefinitions, KEY_TYPES.SPATIAL),
584600
foreignKeys: generateForegnKeysSchema(createDefinitions),
601+
$unknownKeys: getUnknownKeys(createDefinitions),
585602
};
586603

587604
let match = /ENGINE=(\w+)/.exec(tableOptions);
@@ -712,13 +729,13 @@ function generateKeysSchema(createDefinitions, keyType) {
712729

713730
switch (keyType) {
714731
case KEY_TYPES.UNIQUE:
715-
rgxKey = /^\s*UNIQUE KEY `\w+` \((.*?)\)/;
732+
rgxKey = /^\s*UNIQUE KEY `unique_\w+` \((.*?)\)/;
716733
break;
717734
case KEY_TYPES.INDEX:
718-
rgxKey = /^\s*(?:INDEX|KEY) `\w+` \((.*?)\)/;
735+
rgxKey = /^\s*KEY `index_\w+` \((.*?)\)/;
719736
break;
720737
case KEY_TYPES.SPATIAL:
721-
rgxKey = /^\s*SPATIAL (?:INDEX|KEY) `\w+` \((.*?)\)/;
738+
rgxKey = /^\s*SPATIAL KEY `spatial_\w+` \((.*?)\)/;
722739
break;
723740
}
724741

@@ -732,6 +749,24 @@ function generateKeysSchema(createDefinitions, keyType) {
732749
return keys.length ? keys : null;
733750
}
734751

752+
function getUnknownKeys(createDefinitions) {
753+
const keys = [];
754+
const rgxKey =
755+
/^\s*(?:UNIQUE KEY `((?!unique_)\w+)`|KEY `((?!index_)\w+)`|SPATIAL KEY `((?!spatial_)\w+)`) \((.*?)\)/;
756+
757+
for (var i = 0; i < createDefinitions.length; i++) {
758+
const keyMatch = rgxKey.exec(createDefinitions[i]);
759+
if (keyMatch) {
760+
keys.push({
761+
name: keyMatch[1] || keyMatch[2] || keyMatch[3],
762+
columns: columnsSQLToSchema(keyMatch[4]),
763+
});
764+
}
765+
}
766+
767+
return keys;
768+
}
769+
735770
function generateForegnKeysSchema(createDefinitions) {
736771
const foreignKeys = {};
737772
const rgxForeignKey =
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
'use strict';
2+
3+
const MySQLPlus = require('../../lib/MySQLPlus');
4+
5+
const config = require('../config');
6+
7+
const ColTypes = MySQLPlus.ColTypes;
8+
9+
describe('when migrating a table with keys not created by mysql-plus', function() {
10+
11+
const pool = MySQLPlus.createPool(config);
12+
13+
pool.defineTable('unknown_keys', {
14+
columns: {
15+
id: ColTypes.int(),
16+
p: ColTypes.point().notNull(),
17+
},
18+
indexes: ['id'],
19+
});
20+
21+
before(done => {
22+
pool.query(
23+
'CREATE TABLE `unknown_keys` (' +
24+
'`id` int, ' +
25+
'`p` point NOT NULL, ' +
26+
'UNIQUE KEY `unknown_unique_key` (`id`),' +
27+
'INDEX `unknown_index` (`id`),' +
28+
'KEY `fk_unknown_keys_id` (`id`),' +
29+
'SPATIAL KEY `unknown_spatial_key` (`p`))',
30+
done
31+
);
32+
});
33+
34+
after(done => {
35+
pool.end(done);
36+
});
37+
38+
it('should remove the unknown keys', done => {
39+
pool.sync(err => {
40+
if (err) {
41+
throw err;
42+
}
43+
44+
pool.query('SHOW CREATE TABLE `unknown_keys`', (err, rows) => {
45+
if (err) {
46+
throw err;
47+
}
48+
49+
rows[0]['Create Table'].should.equal(
50+
'CREATE TABLE `unknown_keys` (\n' +
51+
' `id` int(11) DEFAULT NULL,\n' +
52+
' `p` point NOT NULL,\n' +
53+
' KEY `index_unknown_keys_id` (`id`)\n' +
54+
') ENGINE=InnoDB DEFAULT CHARSET=utf8'
55+
);
56+
done();
57+
});
58+
});
59+
});
60+
61+
});

0 commit comments

Comments
 (0)