I am building a C# console application that restores a SQL Server database with pre defined parameters that can be modified in a switch menu. The focus of this application is simplicity. It's designed for anyone to be able to restore a SQL Server database at the press of a button. Yes, there should be someone who can perform this task competently, but there's a lot of ways things should be done... Regardless I've built the logic to loop through the backup directories and pick out the correct backup files based on a point in time. Everything works except the actual restore part.
From other questions I've read, I fear that it isn't possible to run SQL from C# that modifies the server in this way. I am reluctant to use SMO objects, because that involves extra complexities that I want to avoid, but if it is the only way I can do this, then that's what I'll do.
Whenever I try and run this code it complains that the #dbName value is invalid.
public static void RestoreDatabase(string Server_Name, string Instance_Name, string DB_Name, FileInfo BakFile, FileInfo DiffFile, FileInfo TrnFile, DateTime Point_In_Time)
{
SqlConnection conn = new SqlConnection();
conn.ConnectionString = "Data Source=" + Server_Name + "\\" + Instance_Name + ";Initial Catalog=master;Integrated Security=True";
string SqlQuery = #"ALTER DATABASE #dbName
SET SINGLE_USER
WITH ROLLBACK IMMEDIATE;
RESTORE DATABASE #dbName
FROM DISK = #BakFilePath
WITH NORECOVERY, REPLACE;
RESTORE DATABASE #dbName
FROM DISK = #DiffFilePath
WITH NORECOVERY;
RESTORE DATABASE #dbName
FROM DISK = #TrnFilePath
WITH RECOVERY, STOPAT = #RecoveryTime;
ALTER DATABASE #dbName
SET MULTI_USER;";
SqlCommand cmd = new SqlCommand();
cmd.CommandType = System.Data.CommandType.Text;
cmd.Connection = conn;
cmd.CommandText = SqlQuery;
try
{
cmd.Parameters.Add(new SqlParameter("#dbName", SqlDbType.NVarChar, 30));
cmd.Parameters.Add(new SqlParameter("#BakFilePath", SqlDbType.NVarChar, 255));
cmd.Parameters.Add(new SqlParameter("#DiffFilePath", SqlDbType.NVarChar, 255));
cmd.Parameters.Add(new SqlParameter("#TrnFilePath", SqlDbType.NVarChar, 255));
cmd.Parameters.Add(new SqlParameter("#RecoveryTime", SqlDbType.DateTime));
cmd.Parameters["#dbName"].Value = DB_Name;
cmd.Parameters["#BakFilePath"].Value = BakFile.FullName;
cmd.Parameters["#DiffFilePath"].Value = DiffFile.FullName;
cmd.Parameters["#TrnFilePath"].Value = TrnFile.FullName;
cmd.Parameters["#RecoveryTime"].Value = Point_In_Time;
}
catch (Exception ex)
{
Console.WriteLine(ex);
Console.ReadLine();
}
try
{
Console.WriteLine("Restoring {0}...", DB_Name);
cmd.Connection.Open();
cmd.ExecuteNonQuery();
cmd.Connection.Close();
Console.WriteLine("Restore Complete!");
Console.ReadLine();
}
catch (SqlException ex)
{
Console.WriteLine("Connection could not open. Error: {0}", ex);
Console.ReadLine();
}
}
8/15/2016 10:38
Based on some of the answers, you guys are recommending dynamic SQL. I was worried about SQL injection, but only admins will have access to this program. Regardless I'll still add stricter validation because who doesn't love putting garbage input in for kicks.
I had attempted dynamic SQL. This was my code, however I did not spend much time checking for errors, so I'll go that route again and try and clean up any mistakes.
string SqlQuery = string.Format(#"DECLARE #dbName NVARCHAR(MAX), #strSQL NVarchar(MAX)=N'';
SET #dbName = {0};
SELECT
#strSQL += 'DECLARE #BakFilePath nvarchar(255) = N''{1}'','
+ N' #DiffFilePath nvarchar(255) = N''{2}'','
+ N' #TrnFilePath nvarchar(255) = N''{3}'','
+ N' #RecoveryTime DateTime = N''{4}'''
+ N' ALTER DATABASE '+ #dbName
+ N' SET SINGLE_USER'
+ N' WITH ROLLBACK IMMEDIATE;'
+ N' RESTORE DATABASE ' + #dbName
+ N' FROM DISK = #BakFilePath'
+ N' WITH NORECOVERY, REPLACE;'
+ N' RESTORE DATABASE ' + #dbName
+ N' FROM DISK = #DiffFilePath'
+ N' WITH NORECOVERY;'
+ N' RESTORE DATABASE ' + #dbName
+ N' FROM DISK = #TrnFilePath'
+ N' WITH RECOVERY, STOPAT = #RecoveryTime;'
+ N' ALTER DATABASE ' + #dbName
+ N' SET MULTI_USER;
'
EXEC sp_executesql #strSQL",DB_Name, BakFile.FullName, DiffFile.FullName, TrnFile.FullName, Point_In_Time);
unfortunately there is an issue with the way your SQL is written. I provided an answer to a question that had a similar underlying issue, you can find it here:
DROP PROCEDURE throws syntax error
sql-server will complain about the usage of:
Restore Database #dbName
Because it is being passed as a literal string. You would need to write something like this to execute your code.
declare #sql varchar(64);
set #sql = 'RESTORE DATABASE ' + #dbName;
exec(#sql);
Update
As per Scott's comment, using:
set #sql = 'RESTORE DATABASE ' + QUOTENAME(#dbName);
Will escape the string to create a valid SQL Server delimited identifier:
https://msdn.microsoft.com/en-us/library/ms176114.aspx
#dbName is invalid.
when passing a parameter you have to respect the rules of where variables are allowed to be used in sql syntax. When using a SELECT statement you can use a variable in the column definition or where clause but it cannot be used to reference a specific database object. The same holds true for ALTER DATABASE, ATLER TABLE, CREATE TABLE, etc.....
So basically the parameter cannot take place of the object name unless you then use dynamic sql such as building the sql string from the parameters as the other answer suggests. Dynamic SQL in this manner can be very open to SQL Injection attacks so you should make sure your source(s) are trusted.
Lastly you ask if it is possible and the answer is yes it is very possible to run backup/alter database commands etc. from c# as long as you user has permissions and your sql statement is correct it will execute.
You can't parameterize everything in SQL.
SELECT * FROM myTable WHERE customerID = #custID
is valid.
SELECT * FROM #tablename
is not. Neither is using ALTER DATABASE or RESTORE DATABASE with a parameter.
This is by design. The fix is to do the replacement in the string before you send it to SQL, but then of course you'll have to scrub the incoming parameters for bad things.
Thank you for everyone's answers, they lead me in the direction to choose dynamic SQL. The code below was the SQL solution that worked for me. I'll explain what's going on because holy cow does it get complicated (at least for me).
My C# application calls a function and I pass five parameters:
The database name
Full backup file path
Differential backup file path
Transactional backup file path
point in time to restore to
These values are then used in the SQL String's variable definitions. Once the variables are set in the SQL string, it then becomes regular dynamic SQL. Dynamic SQL is still a huge pain; figuring out all the single quotes caused me a lot of grief. Once the dynamic SQL is formatted correctly, it's just like any other SQL statement that is executed with C#.
UPDATE: Modified solution to include parameters for input values upon Scott Chamberlains request, and included the entire function as solution.
public static void RestoreDatabase(string Server_Name, string Instance_Name, string DB_Name,
FileInfo BakFile, FileInfo DiffFile, FileInfo TrnFile, DateTime Point_In_Time)
{
SqlConnection conn = new SqlConnection();
conn.ConnectionString = "Data Source=" + Server_Name + "\\" + Instance_Name + ";Initial Catalog=master;Integrated Security=True";
string SqlQuery = string.Format(#"DECLARE #strSQL NVARCHAR(MAX) =''
SELECT
#strSQL += N'ALTER DATABASE ' + QUOTENAME(#dbName)
+ N' SET SINGLE_USER'
+ N' WITH ROLLBACK IMMEDIATE;'
+ N' RESTORE DATABASE ' + QUOTENAME(#dbName)
+ N' FROM DISK = N''' + #BakFilePath + ''''
+ N' WITH NORECOVERY, REPLACE;'
+ N' RESTORE DATABASE ' + QUOTENAME(#dbName) +
+ N' FROM DISK = N''' + #DiffFilePath + ''''
+ N' WITH NORECOVERY;'
+ N' RESTORE DATABASE ' + QUOTENAME(#dbName)
+ N' FROM DISK = N''' + #TrnFilePath + ''''
+ N' WITH NORECOVERY, STOPAT = N''' + #RecoveryTime + ''';'
+ N' RESTORE DATABASE ' + QUOTENAME(#dbName)
+ N' WITH RECOVERY;'
+ N' ALTER DATABASE ' + QUOTENAME(#dbName)
+ N' SET MULTI_USER;
'
EXEC sp_executesql #strSQL");
SqlCommand cmd = new SqlCommand();
cmd.CommandType = System.Data.CommandType.Text;
cmd.Connection = conn;
cmd.CommandText = SqlQuery;
try
{
cmd.Parameters.Add(new SqlParameter("#dbName", SqlDbType.NVarChar, 30));
cmd.Parameters.Add(new SqlParameter("#BakFilePath", SqlDbType.NVarChar, 255));
cmd.Parameters.Add(new SqlParameter("#DiffFilePath", SqlDbType.NVarChar, 255));
cmd.Parameters.Add(new SqlParameter("#TrnFilePath", SqlDbType.NVarChar, 255));
cmd.Parameters.Add(new SqlParameter("#RecoveryTime", SqlDbType.NVarChar,30));
cmd.Parameters["#dbName"].Value = DB_Name;
cmd.Parameters["#BakFilePath"].Value = BakFile.FullName;
cmd.Parameters["#DiffFilePath"].Value = DiffFile.FullName;
cmd.Parameters["#TrnFilePath"].Value = TrnFile.FullName;
cmd.Parameters["#RecoveryTime"].Value = Point_In_Time.ToString();
}
catch (Exception ex)
{
Console.WriteLine(ex);
Console.WriteLine("Press any key to exit");
Console.ReadLine();
}
try
{
Console.WriteLine("Restoring {0}...", DB_Name);
cmd.Connection.Open();
cmd.ExecuteNonQuery();
cmd.Connection.Close();
Console.WriteLine("Restore Complete!");
Console.WriteLine("Press any key to exit");
Console.ReadLine();
}
catch (SqlException ex)
{
Console.WriteLine("Connection could not open. Error: {0}", ex);
Console.ReadLine();
}
}
Related
I'm using a a multiple query with insert and update statement together.
The problem is that if query will not be completed(for some reason e.x bad internet connection) my SQL Server table keeps rubbish.
Example of query:
SqlCommand cmd = new SqlCommand("INSERT INTO CustomerTrans (TableName, UserID, UserName, SumQuantity, SumPrice, SumRealPrice, SumExtrasPrice, SumTotal, SumDiscountTotal, DateTime) SELECT " + Connection.TableName + ",' " + Connection.UserID + "', '" + Connection.Username + "',Sum(Quantity),Sum(Price),Sum(RealPrice),Sum(ExtrasPrice), Sum(Quantity * Price),Sum(Quantity * DiscountPrice),'" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "' from InventoryTransTemp where active=1 and TableName=" + Connection.TableName + ";update InventorytransTemp set TrnDocumentID=(select max(TrnDocumentID) from CustomerTrans where UserID='" + Connection.UserID + "'),Active=0 where TableName=" + Connection.TableName + " and Active=1", con);
cmd.ExecuteNonQuery();
Take a photo from a query which has not be completed properly look query 2989 it has NULL values. I want to avoid inserting something if query is not be completed properly.
Sorry for my previous Question it was Unclear
Try it like this:
string sql =
"INSERT INTO CustomerTrans" +
" (TableName, UserID, UserName, SumQuantity, SumPrice, SumRealPrice, SumExtrasPrice, SumTotal, SumDiscountTotal, DateTime)" +
" SELECT #TableName, #UserID, #Username, Sum(Quantity), Sum(Price), Sum(RealPrice), Sum(ExtrasPrice), Sum(Quantity * Price), Sum(Quantity * DiscountPrice), current_timestamp" +
" FROM InventoryTransTemp" +
" WHERE active=1 and TableName= #TableName;\n" +
"SELECT #TranID = scope_identity;\n"
"UPDATE InventorytransTemp" +
" SET TrnDocumentID=#TranID ,Active=0" +
" WHERE TableName= #Tablename and Active=1;";
using (var con = new SqlConnection("connection string here"))
using (var cmd = new SqlCommand(sql, con))
{
//I'm guessing at exact column types/lengths here.
// You should update this to use your exact column types and lengths.
// Don't let ADO.Net try to guess this for you.
cmd.Parameters.Add("#TableName", SqlDbType.NVarChar, 20).Value = Connection.TableName;
cmd.Parameters.Add("#UserID", SqlDbType.Int).Value = Connection.UserID;
cmd.Parameters.Add("#Username", SqlDbType.NVarChar, 20).Value = Connection.Username;
cmd.Parameters.Add("#TranID", SqlDbType.Int).Value = 0; //placeholder only
con.Open();
cmd.ExecuteNonQuery();
}
Note the improved formatting of the query, the use of scope_identity() to get the new identity value rather than a nested select statement that might not be atomic, that I avoided ALL uses of string concatenation to substitute data into the query, that I avoided the AddWithValue() method entirely in favor of an option that doesn't try to guess at your parameter types, and the use of using blocks to be sure the SqlClient objects are disposed properly.
The only thing I'm still concerned about is if your INSERT/SELECT operation might create more than one new record. In that case, you'll need to handle this a different way that probably involves explicit BEGIN TRANSACTION/COMMIT statements, because this code only gets one #TranID value. But in that case, the original code was broken, too.
I developed a good application with backup and restore feature. It works fine. every time I added new features to its SQL Server 2008 R2 database, for example add a new stored procedure or user-defined table type to upgrade my software.
My backup function is this:
protected int BackUpDataBase(string dbName, string address)
{
try
{
using (_con)
{
string command = "Backup database " + dbName + " to disk='" + address + "'";
SqlCommand cmd = new SqlCommand(command, _con);
cmd.CommandType = CommandType.Text;
connect();
cmd.ExecuteNonQuery();
return 1;
}
}
catch (SqlException ex)
{
return ex.Number * (-1);
}
}
and my restore function is here:
protected int RecoverDataBase(string dbName, string address)
{
try
{
SqlConnection temp = new SqlConnection(_addressMaster);
string Restore = "USE master" + Environment.NewLine;
if (CheckDatabaseExists(dbName))
{
Restore += #"ALTER DATABASE [" + dbName + "]" + Environment.NewLine;
Restore += #"SET OFFLINE WITH ROLLBACK IMMEDIATE" + Environment.NewLine;
Restore += #"ALTER DATABASE [" + dbName + "] SET ONLINE" + Environment.NewLine;
}
Restore += #"RESTORE DATABASE [" + dbName + "] FROM DISK = N'" + address + #"' WITH FILE = 1, NOUNLOAD, REPLACE, STATS = 10" + Environment.NewLine;
Restore += #"ALTER DATABASE [" + dbName + "] SET Single_User WITH Rollback Immediate" + Environment.NewLine;
Restore += #"ALTER DATABASE [" + dbName + "] SET Multi_User" + Environment.NewLine;
using (temp)
{
using (SqlCommand cmd = new SqlCommand(Restore, temp))
{
cmd.CommandText = Restore;
cmd.CommandType = CommandType.Text;
temp.Open();
cmd.ExecuteNonQuery();
temp.Close();
return 1;
}
}
}
catch (SqlException ex)
{
return ex.Number * (-1);
}
}
Everything is ok BUT! The problem is here: I developed my upgraded Windows App with new stored procedures and etc, then install it to a new computer and wants to restore the old backup to my upgraded app, all new stored procedures and feature will back to Old because I restored entire old backup not only its data.
So how can I restore only tables data from a backup file using C# and SQL query?
You cannot restore just the data, but you can script all your objects-modules (you can do it in some mouse click using SSMS) before you restore your backup and then drop all the modules and launch the script that re-creates all the modules.
Update:
if you cannot use SSMS, you can script your modules using
select definition from sys.sql_modules
as CREATE statements.
The only caveat here is your objects must not be ever renamed because the definition in sys.sql_modules is not updated when you rename a module.
Other options are:
script the database with the data as INSERT statements (for small
data sizes)
or import/export data using bcp utility. This does not script
any object so you should truncate your tables before importing data
or recreate the tables if their structure is different from what your
backup contains
Restore to another environment
Restore your database on another database (a copy or an existing dev/test environment).
RESTORE statement
Then pick only the required data and copy them to the production environment.
The way to pick the data and insert them back will entirely depend on what data has to be transfered, and if there are any constraints to add them (indexes, keys, etc...)
Restore Stored Procedures
For example here you can get all the STORED PROCEDURE names to drop them.
SELECT 'DROP PROCEDURE ' + objects.name FROM sys.sql_modules
INNER JOIN sys.objects
ON objects.object_id = sql_modules.object_id
WHERE objects.type_desc = 'SQL_STORED_PROCEDURE'
Then you can recover create scripts with the following query
SELECT sql_modules.definition FROM sys.sql_modules
INNER JOIN sys.objects
ON objects.object_id = sql_modules.object_id
WHERE objects.type_desc = 'SQL_STORED_PROCEDURE'
DROP Procedure
Just put those in an EXEC and make sure it is executed on the Production Database and data is selected from the Copy Database.
Restore data (without indexes and keys)
DROP TABLE [prodDB].[mySchema].[myTable]
SELECT * INTO [prodDB].[mySchema].[myTable] FROM [copyDB].[mySchema].[myTable]
Also you can get table definitions from sys.objects table again.
SELECT schemas.name + '.' + objects.name FROM sys.objects
INNER JOIN sys.schemas
ON objects.schema_id = schemas.schema_id
WHERE type_desc = 'USER_TABLE'
Restore data (with indexes and keys)
TRUNCATE TABLE [prodDB].[mySchema].[myTable]
INSERT INTO [prodDB].[mySchema].[myTable] SELECT * FROM [copyDB].[mySchema].[myTable]
Also consider reading this post if you have any foreign keys referencing the restored tables : https://stackoverflow.com/a/253858/3635715
If you need to get keys definitions you can get them from [sys].[key_constraints]
I'm trying to create stored procedures from a c# program. It typically reads the sproc definition from a text file, and then run it against the chosen database.
My SQL script file looks like this:
DROP PROCEDURE IF EXISTS MySproc;
DELIMITER //
CREATE PROCEDURE MySproc(
IN Id BIGINT,
IN Reference VARCHAR(255),
IN Bla VARCHAR(255)
)
BEGIN
INSERT INTO TableA(`Id`, `Reference`) VALUES(Id, Reference);
INSERT INTO TableB(`Id`, `Bla`) VALUES(Id, Bla);
END
//
DELIMITER ;
and this works fine in the workbench.
I then execute it with this type of c# code:
using (MySqlCommand sqlCommand = _mySqlConnection.CreateCommand())
{
sqlCommand.Connection = _mySqlConnection;
sqlCommand.CommandText = scriptfile;
sqlCommand.CommandType = CommandType.Text;
sqlCommand.ExecuteNonQuery();
}
And it errors with:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'DELIMITER //
CREATE PROCEDURE MySproc( IN Id BIGINT
' at line 1
If I remove the DELIMITER // stuff, then it still parses the semi colons between BEGIN and END as a delimiter for the outer statement, and it errors with:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'END' at line 31
Any idea how I can set either the Command or the something int he script so that it works? Not even sure if the error actually comes from MySQL itself, or from the MySqlCommand library (MySql.Data.6.9.9). And MySQL server is 5.6.25, InnoDB tables.
Can you try replacing the DELIMITER // with something like delimiter $$
Pointless question, sorry, it's embarrassing. This morning, I created a unit test following the top part of this page: https://dev.mysql.com/doc/connector-net/en/connector-net-programming-stored-using.html
and it works fine:
[TestMethod]
public void TestSprocCreationFromMySqlDoc()
{
// from https://dev.mysql.com/doc/connector-net/en/connector-net-programming-stored-using.html
MySqlConnection conn = new MySqlConnection();
conn.ConnectionString = "server=localhost;user=root;database=test;port=3306;password=;";
MySqlCommand cmd = new MySqlCommand();
try
{
Console.WriteLine("Connecting to MySQL...");
conn.Open();
cmd.Connection = conn;
cmd.CommandText = "DROP PROCEDURE IF EXISTS add_emp";
cmd.ExecuteNonQuery();
cmd.CommandText = "DROP TABLE IF EXISTS emp";
cmd.ExecuteNonQuery();
cmd.CommandText = "CREATE TABLE emp (empno INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, first_name VARCHAR(20), last_name VARCHAR(20), birthdate DATE)";
cmd.ExecuteNonQuery();
cmd.CommandText = "CREATE PROCEDURE add_emp(" +
"IN fname VARCHAR(20), IN lname VARCHAR(20), IN bday DATETIME, OUT empno INT)" +
"BEGIN INSERT INTO emp(first_name, last_name, birthdate) " +
"VALUES(fname, lname, DATE(bday)); SET empno = LAST_INSERT_ID(); END";
cmd.ExecuteNonQuery();
}
finally
{
conn.Close();
}
}
Then, I did another test with my own statements (trying to replicate file read from disk, with crlf) and it works too!
cmd.CommandText =
"DROP PROCEDURE IF EXISTS MySproc; " + Environment.NewLine +
"CREATE PROCEDURE MySproc(" + Environment.NewLine +
"IN Id BIGINT," + Environment.NewLine +
"IN Reference VARCHAR(255)," + Environment.NewLine +
"IN Bla VARCHAR(255))" + Environment.NewLine +
"BEGIN " + Environment.NewLine +
"INSERT INTO TableA(`Id`, `Reference`) VALUES(Id, Reference); " + Environment.NewLine +
"INSERT INTO TableB(`Id`, `Bla`) VALUES(Id, Bla); " + Environment.NewLine +
"END";
cmd.ExecuteNonQuery();
And then I ran my original application (that read scripts from files) and it runs ok as well! So I can't explain it. I'm wondering if I did something to the MySql server that affected all connections, or did something in one connection that stayed on, affecting all connections, until a reboot.
I have been trying to add a column programmatically in ASP.NET to modify the tables in SQL Server.
Please see the following code:
string suppliernotxt = supplieridlist[1].ToString();
//SqlCommand cmd2 = new SqlCommand("ALTER TABLE [ProductNormalDB] ADD suppliernotxt nvarchar(20) NULL", con);
SqlCommand cmd2 = new SqlCommand("ALTER TABLE ProductNormalDB ADD #supplierlist nvarchar(20) NULL", con);
cmd2.Parameters.AddWithValue("#supplierlist", suppliernotxt);
//cmd2.Parameters.AddWithValue("#supplierlist", suppliernotxt.ToString());
//cmd2.Parameters["#supplierlist"].Value = supplieridlist[x];
cmd2.ExecuteNonQuery();
supplieridlist is an array that acquires all the column names to add into the SQL Server database. For some reason the parametrized method is not working and shows the following error:
Incorrect syntax near '#supplierlist'.
The basic idea is to have a user select from a check box the name of the suppliers, based on the selected number of suppliers the array will create the supplier names for ex. if we selected 3 suppliers, the array will save "Supplier1", "Supplier2", "Supplier3" and then the SqlCommand is supposed to alter the table and add the new columns.
You cannot use parameters to express the name of columns.
Parameters could only be used to express values for WHERE clause or for INSERT or UPDATE statements.
You could use string concatenation for your query text, passing the string value to a stored procedure or use some form of dynamic sql.
Please be very carefull with these kind of approaches because if you don't keep absolute control on the values passed to your code you will be exposed to Sql Injection.
Adding as an example of Dynamic SQL execution, but still vulnerable to SQL Injection
string suppliernotxt = supplieridlist[1].ToString();
string execSQL = "DECLARE #sup nvarchar(15); " +
"SET #sup = '" + suppliernotxt + "'; " +
"EXEC ('ALTER TABLE ProductNormalDB ADD ' + #sup + ' nvarchar(20) NULL')"
SqlCommand cmd2 = new SqlCommand(execSQL, con);
cmd2.ExecuteNonQuery();
As you can see, even with Dynamic SQL there is nothing that prevent an SQL Injection attack passing via the suppliernotxt variable
EDIT As explained in the comments below from #RBarryYoung, a good improvement on the SQL Injection problem for this case of dynamic sql could be the usage of the QUOTENAME function to obtain an Unicode string with the required delimiters around the input string
string execSQL = "DECLARE #sup nvarchar(15); " +
"SET #sup = QUOTENAME('" + suppliernotxt + "'); " +
"EXEC ('ALTER TABLE ProductNormalDB ADD ' + #sup + ' nvarchar(20) NULL')"
I have the following code block
SQLiteConnection cnn = new SQLiteConnection("Data Source=" + getDBPath());
cnn.Open();
SQLiteCommand mycommand = new SQLiteCommand(cnn);
string values = "'" + this.section + "','" + this.exception + "','" + this.dateTimeString + "'";
string sql = #"INSERT INTO Emails_Pending (Section,Message,Date_Time) values (" + values + ")";
mycommand.CommandText = sql;
mycommand.ExecuteNonQuery();
cnn.Close();
When I execute it , nothing happens, no errors are produced, but nothing gets inserted, what am I doing wrong?
Path to DB is correct!
Insert statement works, tried it in a SQLLite GUI (no problems there)
Here is the SQL Snippet:
"INSERT INTO Emails_Pending (Section,Message,Date_Time) values ('Downloading Received Messages','Object reference not set to an instance of an object.','04.12.2009 11:09:49');"
How about adding Commit before Close
mycommand.Transaction.Commit();
You should always use transactions and parameterized statements when using sqlite, else the performance will be very slow.
Read here: Improve INSERT-per-second performance of SQLite?
Your approach is vulnerable to sql injection too. A message in an email can have a piece of sql in its body and your code will execute this piece of sql. You can also run into problems when the message in your string values contains a " or a ' .