Bit of fun this week with something that a colleague of mine noticed when playing around with SQL Server on linux.
The first thing you do when playing with a new technology is see how you can break it right? Always good fun 🙂
So I’m going to break a database in a SQL Server instance that’s running on linux. I’m not going to go through the install process as there’s a whole bunch of resources out there that detail how to do it. See here
Once you have your instance up and running, connect it to as normal in SSMS and create a database with one table:-
CREATE DATABASE [GoingToBreak]; GO USE [GoingToBreak]; GO CREATE TABLE dbo.Test (PKID INT IDENTITY(1,1) PRIMARY KEY, ColA VARCHAR(10), ColB VARCHAR(10), DateCreated DATETIME); GO
Then insert some data: –
INSERT INTO dbo.Test (ColA, ColB, DateCreated) VALUES (REPLICATE('A',10),REPLICATE('B',10),GETUTCDATE()); GO 1000
What we’re going to do is delete the database files whilst the instance is up and running. Something you can’t do to a database running in an instance of SQL on windows as the files are locked.
First, find where the files are located: –
USE [GoingToBreak]; GO EXEC sp_helpfile; GO
Then jump into your favourite terminal client (I’m using bash on windows) and connect to the linux server.
Then run: –
cd /var/opt/mssql/data/ ls
Ok, so now to delete the files we can run: –
rm GoingToBreak.mdf GoingToBreak_log.ldf
And the files are gone! That database is deader than dead!
But….wait a minute. Let’s have a look back in SSSMS.
Run the following: –
USE [GoingToBreak]; GO SELECT * FROM dbo.Test;
Hmm, data’s returned! Ok, it could just be in the buffer pool. Let’s write some data: –
USE [GoingToBreak]; GO INSERT INTO dbo.Test (ColA, ColB, DateCreated) VALUES (REPLICATE('A',10),REPLICATE('B',10),GETUTCDATE()); GO 1000
What? It completed successfully??? Err, ok. Let’s run that select statement one more time…
SELECT * FROM dbo.Test;
Ok, that returned 2000 rows right? Hmm, what happens if we run CHECKPOINT?
Errr, ok. That worked as well.
Alright, enough of this. Let’s break it for sure. Back in your terminal session run: –
sudo systemctl restart mssql-server
Once that’s complete, jump back into SSMS and refresh the connection: –
Ha ha! Now it’s dead. That’s pretty weird behaviour though eh? I expect there’s a linux person out there who can explain why that happened ‘cos I’m really not sure.
EDIT – Anthony Nocentino (b|t) has come back to me and said that the files when deleted get unlinked from the directory so we can no longer see them but the SQL process will still have them open; hence being able to execute queries. Once the instance is restarted the file handle will be released, the underlying blocks and inodes get deallocated; hence the database going into recovery pending. Thanks Anthony!
One thing I do know is that SQL databases on linux will continue to allow queries to be executed against them after their underlying files have been deleted. Pretty worrying imho, you could have a problem and not even know about it until your next server restart!