From 638c2f6740fc471f4611fde15d5c0fa68057e539 Mon Sep 17 00:00:00 2001 From: Philip Molares Date: Sun, 6 Nov 2022 20:37:49 +0100 Subject: [PATCH] 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 --- lib/models/index.js | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/lib/models/index.js b/lib/models/index.js index f40079f55..74fb8682b 100644 --- a/lib/models/index.js +++ b/lib/models/index.js @@ -9,6 +9,7 @@ const Umzug = require('umzug') // core const config = require('../config') const logger = require('../logger') +const {isSQLite} = require("../utils"); const dbconfig = cloneDeep(config.db) dbconfig.logging = config.debug @@ -80,14 +81,38 @@ const umzug = new Umzug({ db.runMigrations = async function runMigrations () { // checks migrations and run them if they are not already applied // 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(`Database migration failed. 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. Exiting…`) process.exit(1) - }) + } finally { + if (isSQLite(sequelize)) { + await sequelize.query('PRAGMA foreign_keys = ON;') + } + } logger.info('All migrations performed successfully') }