Search code examples
sql-serverdelphidevart

T-SQL code for restoring a database doesn't work inside a Delphi query, but it works in SSMS


I am trying to restore a database which I use in a Delphi program.

When I try to do the restore, it doesn't show any errors and the T-SQL code passes, but there is no change in the database that I am trying to restore to a previous state. On the other hand, if I run the same code in SSMS 18, it works as expected.

Here is the code in Delphi:

Query.SQL.Text := 'USE master RESTORE DATABASE [' + DBName +
  '] FROM DISK = ' + QuotedStr(RestorePath) +
  ' WITH REPLACE, RECOVERY, STATS = 1 USE [' + DBName + ']';

Here is the SQL value inside the query before it's execution:

USE master RESTORE DATABASE [DBName] 
FROM DISK = ''RestorePath'' WITH REPLACE, RECOVERY, STATS = 1 USE [DBName]'#$D#$A

For DBName and RestorePath, I pass the correct values, but I thought it's not relevant, so I changed it in the example here to DBName and RestorePath, since they were very long and made the code hard to read (especially the RestorePath). I did the same with the next block of code.

Finally, here is the code that works in SSMS:

USE master 

RESTORE DATABASE [DBName] FROM DISK = 'RestorePath'
WITH REPLACE, RECOVERY, STATS = 1 

USE [DBName]

I don't know if this is relevant but the restore is being done in a different thread and a backup works fine. So, can anybody help me find out why does it work in SSMS and it doesn't with the Delphi code and how to make the restore with Delphi in a way that it works?

Since a comment asked here is more info about how I execute it. I create a query and a connection. I don't think that the problem is in the values I give to them, since I do the same with the backup and it works, so I'm not going to copy and paste the values, just the way I use the query. After I create it and give it the needed values(just like with the connection and data source) I give the query the SQL code like this

Query.SQL.Text := 'USE master RESTORE DATABASE [' + DBName +
      '] FROM DISK = ' + QuotedStr(RestorePath) +
      ' WITH REPLACE, RECOVERY, STATS = 1 USE [' + DBName + ']';

and then execute it like this:

Query.Execute;

After that I free the connection, query and datasource.


Solution

  • I managed to find a way to make it work. After I added Synchronize() and called a method, with which I refresh the grids I use to show the data from the database, at the end of the TThread(after I free the connection and query) it worked correctly. Here is the final outcome:

    Query.SQL.Text := 'USE master ALTER DATABASE [' + DBName + ']' + 
          ' SET OFFLINE WITH ROLLBACK IMMEDIATE ' + 'RESTORE DATABASE [' + DBName +
          '] FROM DISK = ' + QuotedStr(RestorePath) +
          ' WITH REPLACE, RECOVERY, STATS = 1 ' +
          'ALTER DATABASE [' + DBName + '] SET ONLINE ' + 'USE [' + DBName + ']';
    
    Query.Execute;
    
    DataSource.Free;
    Query.Free;
    Connection.Free;
    
    Synchronize(frmMain.MultiRefresh);
    

    I used to call that function (frmMain.MultiRefresh) right after I executed the query without using Synchronize. After I used Synchronize to call the function the restore worked but it gave me an error that said "failed attempt to login in using user" or something like that. I think that happened because I was still using the database with the credentials in the query and the connection, so after I moved the Synchronize right after I freed the connection, query and dataSource, it worked well.