From 07ff21d04531f8b163aa019a6887e5fd2c828baf Mon Sep 17 00:00:00 2001 From: Gerhard Schlager Date: Tue, 22 Oct 2024 23:13:01 +0900 Subject: [PATCH] FIX: Restoring backup could fail due to missing `discourse_functions` (#29332) Database dumps sometimes reference functions in the `discourse_functions` schema. It's possible that some of these functions have been dropped in a newer version of Discourse. In that case, restoring an older backup will fail with a `ERROR: function discourse_functions.something_something() does not exist` error. The restore functionality contains a workaround for that problem, but it didn't work with functions created in plugin migrations. This commit adds support for temporarily creating missing `discourse_functions` from plugins. And it adds a simple check if the DB migration file even contains the required `DROPPED_TABLES` or `DROPPED_COLUMNS` constant. We don't need to create an instance of the DB migration class unless one of those constants is used. This makes the restore slightly faster and works around a problem with migrations that execute without `up` or `down` methods (e.g. `BackfillChatChannelAndThreadLastMessageIdsPostMigrate`). --- lib/backup_restore/database_restorer.rb | 11 ++++++++--- spec/lib/backup_restore/database_restorer_spec.rb | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/lib/backup_restore/database_restorer.rb b/lib/backup_restore/database_restorer.rb index e913ba99324..d8ce2dfb1ec 100644 --- a/lib/backup_restore/database_restorer.rb +++ b/lib/backup_restore/database_restorer.rb @@ -49,9 +49,11 @@ module BackupRestore ActiveRecord::Base.connection.drop_schema(BACKUP_SCHEMA) if backup_schema_dropable? end - def self.core_migration_files + def self.all_migration_files Dir[Rails.root.join(Migration::SafeMigrate.post_migration_path, "**/*.rb")] + - Dir[Rails.root.join("db/migrate/*.rb")] + Dir[Rails.root.join("db/migrate/*.rb")] + + Dir[Rails.root.join("plugins/**", Migration::SafeMigrate.post_migration_path, "**/*.rb")] + + Dir[Rails.root.join("plugins/**", "db/migrate/*.rb")] end protected @@ -162,7 +164,10 @@ module BackupRestore @created_functions_for_table_columns = [] all_readonly_table_columns = [] - DatabaseRestorer.core_migration_files.each do |path| + DatabaseRestorer.all_migration_files.each do |path| + file_content = File.read(path) + next if file_content.exclude?("DROPPED_TABLES") && file_content.exclude?("DROPPED_COLUMNS") + require path class_name = File.basename(path, ".rb").sub(/\A\d+_/, "").camelize migration_class = class_name.constantize diff --git a/spec/lib/backup_restore/database_restorer_spec.rb b/spec/lib/backup_restore/database_restorer_spec.rb index 7c04e6cb25f..50ccf3f8d18 100644 --- a/spec/lib/backup_restore/database_restorer_spec.rb +++ b/spec/lib/backup_restore/database_restorer_spec.rb @@ -157,7 +157,7 @@ RSpec.describe BackupRestore::DatabaseRestorer do describe "readonly functions" do before do - BackupRestore::DatabaseRestorer.stubs(:core_migration_files).returns( + BackupRestore::DatabaseRestorer.stubs(:all_migration_files).returns( Dir[Rails.root.join("spec/fixtures/db/post_migrate/drop_column/**/*.rb")], ) end