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:
Related
Using mysql, I am trying to get/set data using parameterized queries, but some of them are returning null, though they working without using parameterized queries. Here are the two I have I had issues with:
This one returns nothing frm the database:
// csvFolder looks ridiculous but this is actually way it needs to look like to work
string csvFolder = "C:\\\\\\\\Users\\\\\\\\fakename\\\\\\\\Desktop\\\\\\\\csvScanner\\\\\\\\testeappfolder"
MySqlCommand deleteCheck = new MySqlCommand("SELECT * FROM email_list WHERE filepath LIKE '%#csvfolder%' AND expired IS NULL", conn);
deleteCheck.Parameters.AddWithValue("#csvfolder", csvFolder);
MySqlDataReader deleteRdr = deleteCheck.ExecuteReader();
But, concatenating the value in will work:
MySqlCommand deleteCheck = new MySqlCommand("SELECT * FROM email_list WHERE filepath LIKE '%" + csvFolder + "%' AND expired IS NULL", conn);
MySqlDataReader deleteRdr = deleteCheck.ExecuteReader();
This one returns null from the ExecuteScalar.
MySqlCommand getId = new MySqlCommand("SELECT * FROM email_list WHERE filepath = '#filepath' ORDER BY expired DESC LIMIT 1", conn);
getId.Parameters.AddWithValue("#filepath", deletedPath.Replace(#"\", "\\\\"));
int id = int.Parse(getId.ExecuteScalar().ToString());
But also works fine when concatenating.
I believe it has to be something with what I am passing (paths with \'s that cause various weirdness), but I cannot see exactly what it is. I have many other parameterized queries for paths that work correctly, but these two do not work. Anyone see something like this before
Because your parameter was within a quoted part of your query, it doesn't get treated like a parameter, It is treated as a literal string that you are searching for. You need to concatenate it like this...
MySqlCommand deleteCheck = new MySqlCommand(
"SELECT * FROM email_list WHERE filepath LIKE '%'+#csvfolder+'%' AND expired IS NULL", conn);
Similar in the ExecuteScalar example:
MySqlCommand getId = new MySqlCommand(
"SELECT * FROM email_list WHERE filepath = #filepath ORDER BY expired DESC LIMIT 1", conn);
Other tips:
MySqlCommand and MySqlDataReader are both IDisposable so each should be in a using block.
You can use literal string to make the string a little easier to follow: string csvFolder = #"C:\\\\Users\\\\fakename\\\\Desktop\\\\csvScanner\\\\testeappfolder" (this still doesn't look right, but it's equivalent to the value you've given).
You may want to read can we stop using AddWithValue.
SELECT * with ExecuteScalar (which only used the first value from the first row) is at risk of breaking in future: safer to select the particular column you are intending to work with.
You're using LIKE to look for a value containing your parameter when the value would appear to be a rooted path. If the value will start with that value, drop the initial wildcard.
I'm having problems with some code I'm trying to write. I'm doing something for suppliers orders, so I have a table which is named "encomendas_fornecedores" with a autoincrement field before the key that is the code of sale which consists in a EF before the number(which is a text field).
Here is the code:
connection.Open();
OleDbCommand comando1 = new OleDbCommand();
OleDbCommand comando2 = new OleDbCommand();
OleDbCommand comando3 = new OleDbCommand();
comando1.Connection = connection;
comando2.Connection = connection;
comando3.Connection = connection;
comando1.CommandText = "INSERT INTO encomendas_fornecedores (cod_encomenda_forn, cod_metodo, cod_forn, total_pagar_forn) VALUES('FO', '" + txtcodmetodo.Text + "', '" + txtcodforn.Text + "', '" + lbltotalapagar.Text + "'); ";// insert into table the values with a FO to cod
comando1.ExecuteNonQuery();
comando2.CommandText = "Select MAX(num_encomenda) From encomendas_fornecedores;";// selecting maximum num encomenda so I can isolate it and add to a text before(btw I do this in php/sql no problems
int numero = Convert.ToInt32(comando2.ExecuteScalar());//max num_encomenda
string codencomendaforn= "EF"+Convert.ToString(numero);// sales code completed
comando3.CommandText = "UPDATE encomendas_fornecedores SET cod_encomenda_forn = '"+codencomendaforn+"' WHERE num_encomenda = '"+ numero +"';";//query that is giving me the problems, it says something like "type of data incorrect in data expression"
comando3.ExecuteScalar();//giving me error this line
connection.Close();
But now here's the catch the cod_encomenda_forn is text and the num_encomenda auto increment as it is in the sql, and I tried to show the query in a textbox to see if its anything is wrong but nothing seems wrong.
"UPDATE encomendas_fornecedores SET cod_encomenda_forn = '"+codencomendaforn+"' WHERE num_encomenda = **'**"+ **numero** +"**'**;";//query that is giving me the problems,it says something like "type of data incorrect in data expression"
You are passing a string numero to a where statement that seems like it is expecting a number. As long as it is numeric it should work, but definitely not gauranteed to work. Second you are passing anothercodencomendaforn string to encomenda what is encomenda 's data type?
It appears that you are not handling potential datatype differences between your c# code and your SQL query. In addition single quoting '' around a value in a SQL statement tells the database engines that it is a string even if that is '1234'. While SQL will automatically convert some values it doesn't always. In addition c# .net library also looks for some conversion etc. before sending the SQL statement. To fix appropriately use parameters that are data typed to the database type in the SQL table. To fix it simply in the statement figure out your data types and fix the '' single quotes appropriately.
PS the people trying to help you in the comments were being nice and telling you the professional way of keeping your job in the future when you graduate after fixing this issue.
I have posted this question already because I had problems with the "LIKE" statement but now I realized there are problems with parameterized statements at all. Here is my code:
for example when I write:
sqlCmd = new SqlCommand(#"SELECT #cusId,#cusName FROM " + form1.getTable() + " WHERE #cusId LIKE #filter", connection);
sqlCmd.Parameters.AddWithValue("cusId", form1.cusId.Text);
sqlCmd.Parameters.AddWithValue("cusName", form1.cusName.Text);
sqlCmd.Parameters.AddWithValue("filter", form1.filterType().Trim() + "%");
sqlDatAdapter = new SqlDataAdapter(sqlCmd.CommandText, connection);
sqlDatAdapter.Fill(datTable);
form1.setDataGrid = datTable;
Somehow I always get
"Must declare the scalar variable #..."
for each variable when I fill the data table. I tried that already with
sqlCmd.ExecuteNonQuery();
and it seems to work in this case (when I update a database it works fine) but I need to bind the values to my DataGridView.
EDIT: Even when I just try to write something like:
... WHERE cusId.Text = #cusId
I get the same error
As noted, you aren't working with parameters quite right. Your SqlCommand should be something more like this:
SqlCommand sqlcmd = new SqlCommand(#"SELECT cusId,cusName FROM " + form1.getTable() + " WHERE cusId LIKE #filter", connection);
Note how the columns you are trying to select aren't parameters (so don't include '#' symbol).
When you add parameters you DO need to add the '#' symbol. Something like this:
sqlCmd.Parameters.AddWithValue("#cusId", form1.cusId.Text);
You can't parameterize your table and column names . You can only parameterize your values.
If you really wanna get your table and column names dynamically, you can use dynamic SQL but which is a bad idea.
Best way to get your column names dynamically is creating a strong validation for your column names or creating a black list for them.
Using ExecuteNonQuery doesn't effect anything since it's because just execute your query, does not return any data. Also use using statement to dispose your connections, commands and adapter.
Here an example;
string str = string.Format("SELECT {0}, {1} FROM {2} WHERE {0} LIKE #filter",
form1.cusId.Text,
form1.cusName.Text,
form1.getTable());
sqlCmd = new SqlCommand(str, connection);
sqlCmd.Parameters.AddWithValue("#filter", form1.filterType().Trim() + "%");
sqlDatAdapter = new SqlDataAdapter(sqlCmd);
sqlDatAdapter.Fill(datTable);
But I have to say again, you really need strong validation or black list for your column and table name when you try get them outside of your program.
I used AddWithValue in this example but this method might be dangerous in some cases. Using .Add() overloads to specify it's db type and parameter size implicitly would be better.
Finally solved it! I tried:
using (sqlDatAdapter = new SqlDataAdapter(sqlCmd.CommandText, connection))
{
sqlDatAdapter.SelectCommand.Parameters.Add("#filter", SqlDbType.Int, 25).Value = CusIdEnter;
sqlDatAdapter.Fill(datTable);
form1.setDataGrid = datTable;
}
and now it works! One had to bind the parameters to the Adapter
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);
Every time i get a value from a response from a odbcconnection by datareader, i made a connection to the database (if i have a query that return 9 fields, i have 9 connection to db), and i want to do only 1 connection and retrieve all information. it's possible with datareader ? I need to use other method of connection ?
Best Regards.
Code:
string strSql = "SELECT G.COMPANY_ID, U.USER_ID, U.GROUP_ID, U.NAME, U.DISPLAY_NAME, U.EMAIL, U.IS_CORPORATE, U.CALL_PARK, U.CALL_PICKUP, U.PCHUNTING, U.OUT_OF_OFFICE, U.DND, U.HOTLINE, U.PIN, U.FORCE_PIN_CHECKED, U.PCHUNTING_TYPE, U.DND_END_TIMESTAMP, U.DND_CONTACT, U.OUT_OF_OFFICE_TYPE, U.LANGUAGE, U.AVAILABLE_TIMESTAMP, U.LAST_DIALLED_NUMBER, U.LAST_INCOMING_CALL, U.LAST_MISSED_CALL, U.CALL_PICKUP_GROUP_ID, U.HOTLINE_NUMBER, U.PORTAL_PASSWORD, U.PROFILE, U.MAIN_NUMBER, U.DUAL_OUTGOING_CTRANSFER, U.MY_CALL_PICKUP, U.VM_RECONNECT_NOTIFY, U.SPARE_STRING1, U.INSERT_DATE, U.INSERT_USER, U.UPDATE_DATE, U.UPDATE_USER " +
"FROM {0}_TT_USER U LEFT OUTER JOIN {0}_TT_GROUP G ON U.GROUP_ID = G.GROUP_ID " +
"WHERE USER_ID = :USER_ID ";
conn = new OdbcConnection(GetIpCntrxTimestenConnString(opCode));
cmd = new OdbcCommand(
string.Format(strSql
, config.GetIpCntrxEsmViewName(opCode))
, conn);
cmd.Parameters.AddWithValue(":USER_ID", user_id);
cmd.CommandType = CommandType.Text;
conn.Open();
dataReader = cmd.ExecuteReader();
object[] meta = new object[dataReader.FieldCount];
int NumberOfColums = dataReader.GetValues(meta);
No, you need another way to query.
Instead of one query per field, SELECT all 9 at once and close the connection right away.
Another problem with this approach is that there's no layering whatsoever. I wouldn't like mingling UI and database code together. There's no abstraction your way.
Try using a StringBuilder and AppendLine your select queries. Loop through your dbReader and store in an List thats the best i can come up with. I do understand you want one call with 9 different queries but either way there is going to be overhead on your sql machine or program machine.