As there appears to be no elegant solution to the problem, I bit the bullet and implemented something that seems to work - for now. Although this is not a real answer to my question, I thought someone else might benefit from the following thoughts.
Here is a rough outline of my implementation (tested on SQL Server 2012):
- Create a temporary database
bar
- Get the real logical and physical file names from the system table with
SELECT * FROM sys.master_files WHERE database_id = DB_ID('bar')
- Drop the temporary database
bar
- Get the backup logical and physical file names from the backup with
RESTORE FILELISTONLY FROM DISK = '\path\to\database.bak'
- Make sure that for each file in the backup (obtained in step 4) we have corresponding real logical/physical file names (obtained in step 2)
- Restore the database with
RESTORE DATABASE [bar] FROM DISK = '\path\to\database.bak'
. Add oneMOVE
statement for each file in the backup where the logical file name from the backup is mapped to the real physical file name (obtained in step 2). - The restored database still has the wrong logical names from the backup, so fix these as well with
ALTER DATABASE [bar] MODIFY FILE (name = 'backup_logical_filename', newname = 'real_logical_filename')
. Repeat for each database file.
The approach of creating a temporary database to obtain "real" information about database files (steps 1-3) allows to delegate at least a few things to the DBMS:
- Filesystem locations are correct as per the DBA's server configuration (e.g. separate locations for data files and transaction logs)
- Mapping of database name to file name filesystem name (e.g. if the database name contains characters that are not valid in file names, such as the ":" character)
When matching up real file names and backup file names (e.g. in step 5), the file types in sys.master_files
and in the backup are not the same:
- The file types in
sys.master_files
are "ROWS" and "LOG" (or 0 and 1 if you prefer the numerical file type) - The file types in the backup are "D" and "L"