views:

1630

answers:

6

For some integration tests I want to connect to the database and run a .sql file that has the schema needed for the tests to actually run, including GO statements. How can I execute the .sql file? (or is this totally the wrong way to go?)

I've found a post in the MSDN forum showing this code:

using System.Data.SqlClient;
using System.IO;
using Microsoft.SqlServer.Management.Common;
using Microsoft.SqlServer.Management.Smo;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            string sqlConnectionString = "Data Source=(local);Initial Catalog=AdventureWorks;Integrated Security=True";
            FileInfo file = new FileInfo("C:\\myscript.sql");
            string script = file.OpenText().ReadToEnd();
            SqlConnection conn = new SqlConnection(sqlConnectionString);
            Server server = new Server(new ServerConnection(conn));
            server.ConnectionContext.ExecuteNonQuery(script);
        }
    }
}

but on the last line I'm getting this error:

System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.TypeInitializationException: The type initializer for '' threw an exception. ---> .ModuleLoadException: The C++ module failed to load during appdomain initialization. ---> System.DllNotFoundException: Unable to load DLL 'MSVCR80.dll': The specified module could not be found. (Exception from HRESULT: 0x8007007E).

I was told to go and download that DLL from somewhere, but that sounds very hacky. Is there a cleaner way to? Is there another way to do it? What am I doing wrong?

I'm doing this with Visual Studio 2008, SQL Server 2008, .Net 3.5SP1 and C# 3.0.

A: 

Have you tried running this with a very, very basic script in the .sql file? Maybe something that just inserts one row or creates an arbitrary table? Something that is very easy to verify? Essentially, this code is like hard coding the sql, except you're reading it from a file. If you can get it to work with a very simple file, then I would say that there is likely something wrong with the file structure itself. The post alluded to the fact that there are some stipulations regarding what can and cannot be in the file. If nothing else, it's a good place to start troubleshooting.

Chris Thompson
The file was an export from SQL Server itself, nothing generated manually, so it should be valid. The post said that if the file had a go statement, this was the only way to run it, and that's why I'm doing it. I've replaced the content of the file with select(1 + 1) and I get exactly the same error. I don't think that's a SQL error.
J. Pablo Fernández
+2  A: 

MSVCR80 is the Visual C++ 2005 runtime. You may need to install the runtime package. See http://www.microsoft.com/downloads/details.aspx?FamilyID=200b2fd9-ae1a-4a14-984d-389c36f85647&displaylang=en for more details.

In addition to resolving the DLL issue and Matt Brunell's answer (which I feel is more appropriate for what you're trying to do), you can use the SQLCMD command line tool (from the SQL Client tools installation) to execute these SQL scripts. Just be sure it's on your path so you don't struggle with path locations.

This would play out like so:

Actual command:

SQLCMD -S myServer -D myDatabase -U myUser -P myPassword -i myfile.sql

Parameters (case matters):

S: server
d: database
U: User name, only necessary if you don't want to use Windows authentication
P: Password, only necessary if you don't want to use Windows authentication
i: File to run

Code to execute SQL files:

var startInfo = new ProcessStartInfo();
startInfo.FileName = "SQLCMD.EXE";
startInfo.Arguments = String.Format("-S {0} -d {1}, -U {2} -P {3} -i {4}",
                                    server,
                                    database,
                                    user,
                                    password,
                                    file);
Process.Start(startInfo);

See http://msdn.microsoft.com/en-us/library/ms162773.aspx for more information on the SQLCMD tool.

David Andres
Is there a way to run a sql file without requiring to install the run time of an old Visual C++?
J. Pablo Fernández
Yep...use SQLCMD. I'll edit my post.
David Andres
@J. Pablo Fernandez: Please see my updates.
David Andres
+7  A: 
using Microsoft.SqlServer.Management.Common;
using Microsoft.SqlServer.Management.Smo;

You shouldn't need SMO to execute queries. Try using the SqlCommand object instead. Remove these using statements. Use this code to execute the query:

 SqlConnection conn = new SqlConnection(sqlConnectionString);
 SqlCommand cmd = new SqlCommand(script, conn);
 cmd.ExecuteNonQuery();

Also, remove the project reference to SMO. Note: you will want to clean up resources properly.

Update:

The ADO.NET libraries do not support the 'GO' keyword. It looks like your options are:

  1. Parse the script. Remove the 'GO' keywords and split the script into separate batches. Execute each batch as its own SqlCommand.
  2. Send the script to SQLCMD in the shell (David Andres's answer).
  3. Use SMO like the code from the blog post.

Actually, in this case, I think that SMO may be the best option, but you will need to track down why the dll wasn't found.

Matt Brunell
Matt, pretty solid. On a project I'm working on now, we have code that uses Smo in exactly the same way described in the OP. I can't figure out why it wasn't already obvious that SqlCommand was a better fit...that is until I read your answer.
David Andres
Does that work if the SQL file contain "GO" statement? My understanding was that it didn't.
J. Pablo Fernández
I haven't tested that. I believe it does.
Matt Brunell
It doesn't. There are many things in a schema as exported from SQL server that fail with this approach:Test method IsItScienceFiction.Tests.UserTest.TestMethod1 threw exception: System.Data.SqlClient.SqlException: Incorrect syntax near 'GO'. Incorrect syntax near the keyword 'SET'. Incorrect syntax near the keyword 'ALTER'.
J. Pablo Fernández
GO is not a SQL Command. GO is a keyword used in SQL Server stored procedures that tells the server to execute the SQL that you gave it. You don't need to "GO" when you are executing SQL using SQLCommand; you just need to Execute() it.
Robert Harvey
I'm removing the GOs on the string and that seems to work.
J. Pablo Fernández
Not "stored procedures" that use GO but .sql scripts to denote when to execute a chunk of the script. Its unique to SSMS.
Will
A: 

You may be interested in this: http://geekswithblogs.net/thomasweller/archive/2009/09/08/automating-database-script-execution.aspx

It presents a general-purpose 'test fixture' to automatically execute sql-scripts. There is also sample code available, and there are no dependencies to any unusual assemblies whatsoever...

Thomas Weller
A: 

If you add following references in your project, then original code will work fine.

I use SQL 2008 Express.

Path: C:\Program Files (x86)\Microsoft SQL Server\100\SDK\Assemblies\

Files: microsoft.sqlserver.smo.dll, microsoft.sqlserver.connectioninfo.dll and Microsoft.SqlServer.Management.Sdk.Sfc.dll

Miguel Paiva
A: 

Why not try a semi-colon instead of the "GO" keyword?

charles