fix(migrations): don't run with foreign keys activated

This PR deactivates and reactivates the foreign_keys in the DB for the duration of all migrations.
This prevents a cascade of deletion, when table columns are changed and tables get recreated by sequelize.

Fixes #2809

Signed-off-by: Philip Molares <philip.molares@udo.edu>
This commit is contained in:
Philip Molares 2022-11-06 20:37:49 +01:00
parent 912bea3e23
commit 638c2f6740

View file

@ -9,6 +9,7 @@ const Umzug = require('umzug')
// core // core
const config = require('../config') const config = require('../config')
const logger = require('../logger') const logger = require('../logger')
const {isSQLite} = require("../utils");
const dbconfig = cloneDeep(config.db) const dbconfig = cloneDeep(config.db)
dbconfig.logging = config.debug dbconfig.logging = config.debug
@ -80,14 +81,38 @@ const umzug = new Umzug({
db.runMigrations = async function runMigrations () { db.runMigrations = async function runMigrations () {
// checks migrations and run them if they are not already applied // checks migrations and run them if they are not already applied
// exit in case of unsuccessful migrations // exit in case of unsuccessful migrations
await umzug.up().catch(error => { const savepointName = 'migration';
try {
if (isSQLite(sequelize)) {
// Deactivate foreign_keys for sqlite, so that sequelize does not accidentally delete data when recreating tables via cascading delete.
// See https://github.com/hedgedoc/hedgedoc/issues/2809
await sequelize.query('PRAGMA foreign_keys = OFF;')
await this.sequelize.query(`SAVEPOINT ${savepointName};`);
}
await umzug.up()
if (isSQLite(sequelize)) {
// Run a foreign keys integrity check
const foreignKeyCheckResult = await sequelize.query('PRAGMA foreign_key_check;')
if (foreignKeyCheckResult.length > 0) {
throw Error(`Foreign key violations detected: ${JSON.stringify(foreignKeyCheckResult, null, 2)}`);
}
await this.sequelize.query(`RELEASE ${savepointName};`, options);
}
} catch(error) {
if (isSQLite(sequelize)) {
await this.sequelize.query(`ROLLBACK TO ${savepointName};`)
}
logger.error(error) logger.error(error)
logger.error(`Database migration failed. logger.error(`Database migration failed.
This can be the result of upgrading from quite old versions and requires manual database intervention. This can be the result of upgrading from quite old versions and requires manual database intervention.
See https://docs.hedgedoc.org/guides/migration-troubleshooting/ for help. See https://docs.hedgedoc.org/guides/migration-troubleshooting/ for help.
Exiting`) Exiting`)
process.exit(1) process.exit(1)
}) } finally {
if (isSQLite(sequelize)) {
await sequelize.query('PRAGMA foreign_keys = ON;')
}
}
logger.info('All migrations performed successfully') logger.info('All migrations performed successfully')
} }