I am trying to create a database using this code:
var createDatabaseQuery = "exec ('CREATE DATABASE ' + #db)";
var sqlCommand = new SqlCommand(createDatabaseQuery, sqlConnection);
sqlCommand.Parameters.Add("#db", SqlDbType.Text);
sqlCommand.Parameters["#db"].Value = "DbName";
sqlCommand.ExecuteNonQuery();
The above works perfectly but I try to do concatenation as follows, it throws an exception:
var sqlCommand = new SqlCommand(createDatabaseQuery, sqlConnection);
sqlCommand.Parameters.Add("#db", SqlDbType.Text);
sqlCommand.Parameters["#db"].Value = "DbName" + CustomId; //Doing the concatenation here
Exception:
System.Data.SqlClient.SqlException (0x80131904): Incorrect syntax near '-'
I know, there could be better ways to do it. But is there any way that I can make the above work?
Time to learn the real intricate sides of SQL.
The way you wan t to write it - is incorrect in multiple ways. DEBUG THE SQL. Do not care about the C# code, look at the SQL...
In your case - naming conversions.
Tables, databases etc. can not contains a "-" - OR they must be marked.
CREATE DATABASE my-database -> Error
CREATE DATABASE [my-database] -> correct, the [] brackets names and thus... no processing of the "-" is tried.
This is quite clear in the SQL documentation, but a part many people overlook (mostly because in most cases it does not matter). They likely wonder why generators bracket every item name (Database, schema, table, COLUMN). Well, that is the reason. What do you think "-1" means? Minus one, processing, or part of a name - the server has no way to determine this. Help him.
You need to make sure you are quoting the name correctly using QUOTENAME, because it contains characters that need escaping.
var createDatabaseQuery = "exec ('CREATE DATABASE ' + QUOTENAME(#db))";
Also, the parameter type should be nvarchar(128)
sqlCommand.Parameters.Add("#db", SqlDbType.NVarChar, 128).Value = "DbName" + CustomId;
Related
I have a dynamic SQL for searching records in Oracle, and VS2017 code analysis reports warning about using parameterized SQL query for this line (1st line, this code works):
string SQL = "SELECT " + string.Join(",", my_columns.ToArray()) + " FROM MyTable ";
string where_condition = " WHERE ";
//the rest of code follows as this...
if (!string.IsNullOrEmpty(textbox1.Text))
{
SQL = string.Concat(SQL, where_condition, " Name like :name");
cmd.Parameters.Add(new OracleParameter("name", string.Concat("%", textbox1.Text, "%")));
where_condition = " AND ";
} //...
So, I tried to put column names as parameters because of warning, but then I get ORA-01036- illegal variable name/number error:
string SQL = "SELECT :columns FROM MyTable ";
cmd.Parameters.Add(new OracleParameter("columns", string.Join(",",
my_columns.ToArray())));
string where_condition = " WHERE ";
What is wrong, maybe column names cannot be passed as parameters ? Or is there any other way to avoid warning in VS code analysis ?
You're right - column names can't be passed as parameters. That part has to be done dynamically, unless you want to change your database structure very significantly. (You could have one column with a value which is the logical column name, and one column for the value. I'm not recommending this - it's very much not how databases are intended to be used.)
The warning you're getting is there to avoid SQL injection attacks. When building the query dynamically, you have to do that differently. You basically need to make sure you have a whitelist of column names, and only build up SQL including those names.
You may well still get a code analysis warning at that point, but you should disable that just for this piece of code, with a comment explaining that you understand the warning, and what you've done to remove the risk of SQL injection attacks.
I want to insert multiple rows into my database, I tried to use parameters but I did something wrong.
In debug mode, the parameters do have values, but once the insert is done, I still have #compte, #mo, #userimp in my database instead of their values.
string INSERTDELAMORTPart2 = "'123'," + "'#compte'" + "," + "'#mo'" + "," + "'ubs'" + "," + "'2'" + "," + "'#userimp'" + "," + "'22.10.17'" + ",'";
OdbcCommand Query = new OdbcCommand(INSERTDELAMORTPart2, InfoConnexion);
Query.Parameters.AddWithValue("#compte", _cb_Compte.SelectedItem);
Query.Parameters.AddWithValue("#mo", MondantResultat);
Query.Parameters.AddWithValue("#userimp", UserImp);
Query.ExecuteNonQuery();
I have tried Parameters.Add, and also Parameters["#name"].Value, but the result stays the same.
What am I doing wrong ?
EDIT :
I have an Oracle database and I need the single quote to insert my values.
I have tried to pass my whole INSERT string into a parameter but it doesn't work.
I'm about to give up and just replace the ' by '' even if it's a bad idea.
A few things.
If you are using Oracle, I highly recommend you use ODP.net or managed ODP.net, not ODBC. ODBC should work, but the native drivers will work more efficiently and will avoid any oddities you might with with the abstraction layer ODBC provides. Managed ODP.net has the additional advantage of not requiring an Oracle client be installed on the target machine
SQL Server (and other databases) use the "#" as a parameter, but Oracle uses the colon ":" instead. Some databases (like PostgreSQL) will take either. While the parameter in your SQL requires the colon, when you use assign the parameter in .NET you need to omit it. Again, this is an Oracle thing you won't find in other databases.
Your SQL doesn't appear to have any command in it... only values. Where is your "insert into?"
Especially with Oracle, you want to be explicit about your datatypes... so use Add instead of AddWithValue (which is actually an overload of Add in ODP.net). Alternatively, you can set the datatype later.
The converted code would look something like this:
string insert = "insert into my_table values (:COMPTE, :MO, :USERIMP)";
using (OracleCommand cmd = new OracleCommand(insert, Connection))
{
// no ":" in the parameter declarations
cmd.Parameters.Add(new OracleParameter("COMPTE", OracleDbType.Int32));
cmd.Parameters.Add(new OracleParameter("MO", OracleDbType.Varchar2));
cmd.Parameters.Add(new OracleParameter("USERIMP", OracleDbType.Varchar2));
cmd.Parameters[0].Value = 123;
cmd.Parameters[1].Value = "ubs";
cmd.Parameters[2].Value = "22.10.17";
cmd.ExecuteNonQuery();
}
I guessed at your datatypes -- make sure they match your DDL when you actually implement this, and if these aren't the only three columns, update your insert command appropriately.
If for some reason I misunderstood, and this is not Oracle, I still recommend use of the native driver rather than ODBC. When you use ODBC, you assume a lot about the target machine -- assumptions that may not turn out to be true.
The command should look something like this:
insert into t(compte, mo, userimp) -- of course the table and columns should be the right names
values (#compte, #mo, #userimp);
No single quotes are needed.
I would recommend against using AddWithValue(). Instead, be explicit about the types.
You have this:
string INSERTDELAMORTPart2 = "'123'," + "'#compte'" ...
Note the single quotes around the parameter names. They should not be there. You want this instead:
string INSERTDELAMORTPart2 = "'123'," + "#compte"
I have the following Code in C# ( Sql server (LocalDB)\v11.0)
If Definition property has no special character , the Insert executed. but
some times it has an unknown special character in it , and i recive the Error.
for()
{
if(){
DB.Docommand("INSERT INTO Test5(P_Def) VALUES('"+ pro.Definition + "')");
}
}
in database the data type is nvarchar(Max)
but i receive the following error:
incorrect syntax near .....
I want to insert my property with special characters.
What can id do?
Thanks
Parameterize your insert. In addition to gaining an ability to insert strings with any characters that are valid inside nvarchar, you will also fix a major security problem by avoiding a potential sql injection attack:
var cmd = new SqlCommand("INSERT INTO Test5(P_Def) VALUES(#Def)", con);
cmd.Parameters.AddWithValue("#Def", pro.Definition);
I am working on a C# windows form which is connected to MySQL and updates strings within the form. I have everything working properly except for a small issue.
Say you want to update the "notes" field to read "The dog's bone", that apostrophe is causing the SQL query to end and cause an error. How can I get around this please?
UPDATE `database`
SET `notes` = 'The dog's bone'
WHERE `Pet` = 'Dog';
Thanks!
You can escape ' character in MySQL with doubling it like ''.
Other than that, if you use parameterized queries, you will not need this at all. Just pass your The dog's bone string directly to your parameterized query and you will be fine.
Also I strongly suspect you try to use UPDATE instead of SELECT statement. In MySQL, SELECT syntax doesn't have any SET part.
And using a reserved keyword as a column name is a bad idea. As a best practice, change your database column name to non-reserved word.
using(var con = new MySqlConnection(conString))
using(var cmd = con.CreateCommand())
{
cmd.CommandText = #"UPDATE `database` SET notes = #notes
WHERE Pet = #pet";
cmd.Parameters.AddWithValue("#notes", "The dog's bone");
cmd.Parameters.AddWithValue("#pet", "Dog");
con.Open();
cmd.ExecuteNonQuery();
}
I used AddWithValue method as an example in my code since I didn't know your column types but you don't use it. This method may generate unexpected and surprising results sometimes. Use Add method overloads to specify your parameter type and it's size.
Escape it with another single quote ':
SELECT `database`
SET `notes` = 'The dog''s bone'
WHERE `Pet` = 'Dog';
I am working with C#. I need to write a select inline query.
The table name should be taken from config. I cannot write a stored procedure.
SqlCommand myCommand= new SqlCommand();
myCommand.CommandText = "Select * from " + tableName;
myCommand.CommandType = CommandType.Text;
myCommand.Connection = connString;
How to avoid sql injection ?
Just create a query with a real param and check for the existence of the tablename - somthing like:
SELECT COUNT(*) FROM SYS.TABLES WHERE NAME = #pYOURTABLENAME
IF that returns 1 then you know that the table exists and thus can use it in the SELECT you showed in the question...
However I strongly recommend to try anything to get rid of the need for any code prone to SQL injection!
I would ensure table name contains only these characters:
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz[]. -_0123456789
E.g.,
Regex regex = new Regex(#"^[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\[\]. -_0123456789]{1,128}$");
if (!regex.IsMatch(tableName)) throw new ApplicationException("Invalid table name");
To do a more comprehensive job including non-English languages see this reference on what a valid table names:
http://msdn.microsoft.com/en-us/library/ms175874.aspx
You need to verify that tableName is appropriate. After some sanity checking (making sure it has no spaces, or other disallowed characters for table names, etc), I would then first query the database for the names of all tables, and programmatically verify that it is one of those table names. Then proceed to run the query you show.
I'd look at moving the SQL to a stored proc and review this article by Erland Sommarskog as it has some great ideas for using dynamic SQL within stored procs. I'd certainly look into it. It discusses a lot of the issues around SQL injection and possible alternatives to dynamic SQL.
He also has another great article on ways to use arrays in stored procs. I know you didn't ask for that, but I often refer to these two articles as I think they are quite insightful and provide you with some useful ideas with regards to writing your procedures.
In addition to some of the suggestions linked above, I still have some basic parameter sanitisation mechanisms that I use if I am ever using dynamic SQL. An example of this is as follows;
IF LEN(#TableName) < 5 OR LEN(#TableDisplayName) < 5
BEGIN
RAISERROR('Please ensure table name and display name are at least 5 characters long', 16, 1)
END
IF NOT (#TableName not like '%[^A-Z]%')
BEGIN
RAISERROR('The TableName can only contain letters', 16, 1)
END
IF NOT (#TableDisplayName not like '%[^0-9A-Z ]%')
BEGIN
RAISERROR('The TableDisplayName can only contain letters, numbers or spaces', 16, 1)
END
This combined with using parameters within your dynamic sql and then executing using sp_executesql certainly help to minimise the possibility of a SQL injection attack.