This question already has answers here:
A table name as a variable
(10 answers)
Closed 1 year ago.
I am building a sql query string like this:
var sqlDailyDataForOption = #"select underlying_symbol, quote_date
FROM [#val6]
Later I add the command line parameters thus:
command.Parameters.AddWithValue("#val6", o.underlying_symbol + "_1545");
I get an exception when I try to execute the query string:
using (SqlDataReader reader = command.ExecuteReader())
{
- $exception {"Invalid object name '#val6'."} System.Data.SqlClient.SqlException
However, if I hardwire the value o.underlying_symbol + "_1545" it works fine.
Is it that command-parameters can't be dynamically created in a FROM ?
You would have to use dynamic SQL and safely inject the value of the dynamic object into the statement. I'm not a C# developer, but I suspect it'll look something like this:
var sqlDailyDataForOption = #"DECLARE #SQL nvarchar(MAX) = N'SELECT underlying_symbol, quote_date FROM dbo.' + QUOTENAME(#var6) + N';'; EXEC sys.sp_executesql #SQL;"
command.Parameters.Add("#Var6", SqlDbType.NVarChar, 128).Value = o.underlying_symbol + "_1545"
try this
var val16=o.underlying_symbol + "_1545";
var sqlDailyDataForOption = $"select underlying_symbol, quote_date FROM [{val16}]";
but please remember about possibility sql script injection attack in this case and check val16 for malicious words like delete.
Related
This question already has answers here:
Sanitize table/column name in Dynamic SQL in .NET? (Prevent SQL injection attacks)
(3 answers)
Closed 5 months ago.
Edit: I marked that the linked question was useful, but I didn't intend to mean that it completely answered my question here, which after reviewing others' comments and answers here, I realize I need two different escaped versions of table, one as a safe single-quoted identifier, and one as a safe single-bracketed identifier.
I need to drop a SQL server table from C# with the table name as a parameter.
This is my code:
private static void DropSqlTableIfExists(string connectionString, string table)
{
string query = "if object_id (#table, 'U') is not null begin drop table #table; end";
using SqlConnection conn = new(connectionString);
using SqlCommand command = new(query, conn);
command.Parameters.AddWithValue("#table", table);
conn.Open();
command.ExecuteNonQuery();
}
The above code gives me an error, Incorrect syntax near '#table'.
I could of course put the table name directly into the query string, but that would allow code injection, which I need to avoid.
What is the best way to go about this?
EDIT 2:
Based on feedback, I updated the code to look like this:
private static void DropSqlTableIfExists(string connectionString, string table)
{
string tableSafeQuoted = $"'{table.Replace("'", "''")}'";
string tableSafeBracketed = $"[{table.Replace("]", "]]").Replace(".", "].[")}]";
string query = $"if object_id ({tableSafeQuoted}, 'U') is not null begin drop table {tableSafeBracketed}; end";
using SqlConnection conn = new(connectionString);
using SqlCommand command = new(query, conn);
conn.Open();
command.ExecuteNonQuery();
}
tbh, I'm not sure if it's 100% safe, due to the oddity of the . replacement.. but I think unless someone gives me a good reason not to, I will leave it like this..
You'll need to escape/encode the table name as an identifier. In SQL Server, this is typically done by replacing any closing brackets (]) in the name with two consecutive brackets (]]), and then surrounding the result with brackets ([...]).
You can either write a simple method to do this yourself, or take on a dependency like ScriptDom, which allows you to do this:
var escapedTableName = Identifier.EncodeIdentifier(tableName);
If your SQL Server database is set to use double-quoted identifiers, do something similar, but with double-quotes instead of brackets. Or, with ScriptDom:
var escapedTableName = Identifier.EncodeIdentifier(tableName, QuoteType.DoubleQuote);
Note that encoding the table name makes any .s act as if they're part of the table name itself. If your table name is supposed to have qualifiers (database, schema), each of those must be escaped individually, so you'll probably want to have them passed in as a separate argument, or create a separate type to represent the combination of these names.
There is probably a more elegant way to do this, but here's one possible way:
declare #dynamicsql nvarchar(max)
set #dynamicsql = 'DROP TABLE dbo.' + QUOTENAME(#table) + '';
if object_id (#table, 'U') is not null
begin
EXEC sp_executesql #dynamicsql;
end
so in your specific case it will be:
private static void DropSqlTableIfExists(string connectionString, string table)
{
string query = #"
declare #dynamicsql nvarchar(max)
set #dynamicsql = 'DROP TABLE dbo.' + QUOTENAME(#table) + '';
if object_id (#table, 'U') is not null
begin
EXEC sp_executesql #dynamicsql;
end
";
using SqlConnection conn = new(connectionString);
using SqlCommand command = new(query, conn);
command.Parameters.AddWithValue("#table", table);
conn.Open();
command.ExecuteNonQuery();
}
I hope it helps!
This question already has answers here:
Call a stored procedure with parameter in c#
(7 answers)
Closed 5 years ago.
I've got a stored procedure that runs just fine if I execute it on my server and if I build an execute statement with my parameters (e.g. string sql = "Exec Get_Data '" + St + " ' ...". However, as soon as I try:
string strQS = "Exec Get_Data #param1,#param2,#param3,#param4..."
using (SqlConnection conSQL = new SqlConnection(connectionString))
{
using (SqlCommand cmdSQL = new SqlCommand(strQS, conSQL))
{
conSQL.Open();
cmdSQL.Parameters.AddWithValue("#param1", SqlDbType.VarChar).Value = St;
cmdSQL.Parameters.AddWithValue("#param2", SqlDbType.VarChar).Value = Loc;
...
I get the following error:
Column name or number of supplied values does not match table definition.
Obviously if I can run it before I use a parametrized query I don't have anything wrong with my column names, but something with how my values are being treated. All my variables are of type string and the SQL Server is expecting all parameters to by of type varchar...Any ideas?
You need to change your command type to StoredProcedure.
And then drop the EXEC and all the parameters from your string.
cmdSQL.CommandType = CommandType.StoredProcedure;
string strQS = "Get_Data"
This question already has answers here:
SqlCommand with Parameters
(3 answers)
Closed 8 years ago.
Hi this is my query
SELECT StraightDist FROM StraightLineDistances
WHERE (FirstCity='007' AND SecondCity='017');
How can I pass this in to sql statement?
I want to replace the city numbers '007' and '017' with variables
string destcity;
string tempcityholder1;
What I tried is this
SqlCommand mybtncmd2 = new SqlCommand("SELECT StraightDist FROM StraightLineDistances WHERE (FirstCity='" + tempcityholder1 + "' AND SecondCity='" + destcity + "');", mybtnconn2);
it didn't give me the expected output.
But when i tried with the original sql as given below it worked.
SqlCommand mybtncmd2 = new SqlCommand("SELECT StraightDist FROM StraightLineDistances WHERE (FirstCity='007' AND SecondCity='017');", mybtnconn2);
Can anyone point me the error here?
or a better solution.
This is for a personal application, security is not a must, so no need of parametrized queries. And I don't know how to implement parametrized queries with multiple parameters. If anyone can explain how to use a parametrized query it's great and I would really appreciate that. But just for the time being I need to correct this.
Any help would be great..
OK if with parametrized query
MY Work looks like this
SqlConnection mybtnconn2 = null;
SqlDataReader mybtnreader2 = null;
mybtnconn2 = new SqlConnection("");
mybtnconn2.Open();
SqlCommand mybtncmd2 = new SqlCommand("SELECT StraightDist FROM StraightLineDistances WHERE (FirstCity='007' AND SecondCity='017');", mybtnconn2);
mybtnreader2 = mybtncmd2.ExecuteReader();
while (mybtnreader2.Read())
{
MessageBox.Show(mybtnreader2.GetValue(0) + "My btn readre 2 value");
}
Can anyone give me a solution which doesn't complicate this structure.
If I use a parametrized query how can I edit
mybtnreader2 = mybtncmd2.ExecuteReader();
This statement?
This is the way to use parametrized queries:
string sqlQuery="SELECT StraightDist FROM StraightLineDistances WHERE (FirstCity= #tempcityholder1 AND SecondCity=#destcity);"
SqlCommand mybtncmd2 = new SqlCommand(sqlQuery, mybtnconn2);
mybtncmd2.Parameters.AddWithValue("tempcityholder1", tempcityholder1 );
mybtncmd2.Parameters.AddWithValue("destcity", destcity);
It's always good practice to use parameters, for both speed and security. A slight change to the code is all you need:
var mybtncmd2 = new SqlCommand("SELECT StraightDist FROM StraightLineDistances WHERE FirstCity=#City1 AND SecondCity=#City2;", mybtnconn2);
mybtncmd2.Parameters.AddWithValue("#City1", "007");
mybtncmd2.Parameters.AddWithValue("#City2", "017");
Use prepared statements: it's both easy and secure.
command.CommandText =
"INSERT INTO Region (RegionID, RegionDescription) " +
"VALUES (#id, #desc)";
SqlParameter idParam = new SqlParameter("#id", SqlDbType.Int, 0);
SqlParameter descParam =
new SqlParameter("#desc", SqlDbType.Text, 100);
You really won't do this, because this is an open door to SQL injection.
Instead you should use Stored Procedures for that approach.
In case your not familiar with SQL injection, let's make it clear:
Assume that you have a database with a table called 'T_USER' with 10 records in it.
A user object has an Id, a Name and a Firstname.
Now, let's write a query that select a user based on it's name.
SELECT * FROM T_USER WHERE Name= 'Name 1'
If we take that value from C#, this can really take unexpected behaviour.
So, in C# code we will have a query:
string queryVal;
var command = "SELECT * FROM T_USER WHERE Name = '" + queryVal + "'";
As long as the user is nice to your application, there's not a problem.
But there's an easy way to retrieve all records in this table.
If our user passes the following string in QueryVal:
demo' OR 'a' = 'a
Then our query would become:
SELECT * FROM T_USER WHERE Name = 'demo' OR 'a' = 'a'
Since the second condition is always true, all the records are retrieved from this table.
But we can even go further:
If the same user uses the following value in queryVal:
demo'; DELETE FROM T_USER--
The full query becomes:
SELECT * FROM T_USER WHERE Name = 'demo'; DELETE FROM T_USER--'
And all our records our gone.
And we can even go further by dropping the table:
queryVal needs to be:
demo'; DROP TABLE T_USER--
I think you get it. For more information google on Sql Injection:
This question already has answers here:
Avoiding SQL injection without parameters
(21 answers)
Closed 9 years ago.
If I change my select from
String insSQL2
= "select * from Produtos where nome = '" + txtBuscaNome.Text + "'"
To
String insSQL2
= "select * from Produtos where nome = ''" + txtBuscaNome.Text + "''"
Will it prevent sql injection?
No.
SQL injection isn't about creatively using quote characters. It's about treating input as data instead of as code. Take a look at a classic SQL injection vulnerability:
"SELECT * FROM Users WHERE Id = " + someValue;
It may intuitively look like you're using someValue as a data value, but you're actually using it as actual SQL code. The SQL engine doesn't see this as a value parameter, it sees it as part of the command being executed. That code should just be a value, but it can be anything. And you'd be executing whatever code is supplied.
Thinking of it in this way, it becomes clear that you should never execute user-supplied code in your application.
The alternative is to treat the user input as values in pre-defined code. That way you control the complete scope of the code and users are only supplying values. Which would look more like this:
"SELECT * FROM Users WHERE Id = #id";
Now the SQL engine sees that parameter (#id) and expects you to supply a value for that parameter. In ADO.NET it might look something like:
someCommand.Parameters.AddWithValue("#id", someValue);
Now the SQL engine knows that this is a data value and not code, so it treats it as data instead of executing it.
No, it won't prevent sql injection.
Use parameterized sql:
var insSQL2 = "select * from Produtos where nome = #nome";
var connection = new SqlConnection(/* connection info */);
var command = new SqlCommand(insSQL2, connection);
command.Parameters.AddWithValue("#nome", txtBuscaNome.Text);
This question already has answers here:
How to use a variable for the database name in T-SQL?
(4 answers)
Closed 10 years ago.
I can't change the database file size with a C# query. For some reason I get an exception: "Incorrect syntax near '#databaseName'.
This is the code that executed the query:
command = connection.CreateCommand();
command.CommandText = #"
ALTER DATABASE #databaseName
MODIFY FILE
(NAME = #databaseFile, SIZE = #newSize)
";
dbParam = command.CreateParameter();
dbParam.ParameterName = "databaseFile";
dbParam.Value = dbFileName;
command.Parameters.Add(dbParam);
dbParam = command.CreateParameter();
dbParam.ParameterName = "newSize";
dbParam.Value = newSize;
command.Parameters.Add(dbParam);
dbParam = command.CreateParameter();
dbParam.ParameterName = "databaseName";
dbParam.Value = databaseName;
command.Parameters.Add(dbParam);
command.ExecuteNonQuery();
Now there might be several problems. Firstly the database is on a different machine so wouldn't the db file path be different?
Some things cannot be parameterized. That includes things like table and column names in DML, but includes most of DDL. It is not expecting, and cannot process, parameters in this scenario.
To check this; just run it in SSMS, declaring the variables ahead of time and giving them values. You will find the error message is the same. If it doesn't work in SSMS it is very unlikely to work from ADO.NET.