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
Related
Ok been starring at this for a good while and i can not under stand why it is not updating my database..... I do not get an error messages it runs just fine. Code below
if (e.KeyCode == Keys.Enter)
{
// #WORK
string searchtext = txtAssetScanned.Text;
string searchcmd = "UPDATE " + lstCompCode.SelectedItem.ToString() + " SET " + lstCompCode.SelectedItem.ToString() + ".[Inventory Status]= \"FOUND\" WHERE [Inventory number] like '*" + searchtext + "';";
MessageBox.Show(searchcmd);
myConnection.Open();
OleDbCommand search = new OleDbCommand();
search.Connection = myConnection;
search.CommandText = searchcmd;
search.ExecuteNonQuery();
myConnection.Close();
}
There are a few things that pop out here :
Use Parameterized Queries. You should be using parameterized queries, concatenating in the manner you currently are can cause syntax issues and leave you vulnerable to SQL Injection.
Consider Using Single Quotes for Values. When setting string values in SQL, you should use single quotes 'value' as opposed to double quotes (i.e. "value").
SelectedValue over SelectedItem. Consider using the SelectedValue property as opposed to SelectedItem.ToString() to ensure you use the proper value.
Table Names as Parameters May Not Be Allowed. If you are using a table name as a parameter, which in many cases may be flat out rejected (as they are generally reserved for values), so fair warning.
Double-check for Typos. Finally, ensure the properties that you are targeting are correct and do not contain any typos (i.e. Foo.[Inventory number], etc.)
You can apply these changes as follows :
using(var connection = new OleDbConnection("{your-connection-string}"))
{
// Build your query with parameters
var query = "UPDATE ? SET [Inventory Status] = 'FOUND' WHERE [Inventory number] LIKE ?";
using(var command = new OleDbCommand(query, connection))
{
connection.Open();
// Add your parameters
command.Parameters.AddWithValue("#table",lstCompCode.SelectedValue);
command.Parameters.AddWithValue("#search", "*" + txtAssetScanned.Text);
// Now that your queries are added, perform your update
command.ExecuteNonQuery();
}
}
The Likely Issue
As I mentioned, some databases will not allow you to pass in table names as parameters without resorting to stored procedures, dynamic SQL, etc. You may be better off simply defining the table that you want to use directly :
var query = "UPDATE [YourTableName] SET [Inventory Status] = 'FOUND' WHERE [Inventory number] LIKE ?";
Since you cannot pass this through via parameters, you might consider adding some logic to determine which to use and hard-code it along with some sanitation to avoid possible nefarious behavior.
I have a Project table with two columns -- ProjectId and ProjectName -- and am writing a function that constructs and executes a SqlCommand to query the database for the ids of a Project with a given name. This command works, but is vulnerable to SQL Injection:
string sqlCommand = String.Format("SELECT {0} FROM {1} WHERE {2} = {3}",
attributeParam, tableParam, idParam, surroundWithSingleQuotes(idValue));
SqlCommand command = new SqlCommand(sqlCommand, sqlDbConnection);
using (SqlDataAdapter adapter = new SqlDataAdapter(command))
{
DataTable attributes = new DataTable();
adapter.Fill(attributes);
...
}
attributeParam, tableParam, idParam, and idValue are all strings. For example, they might be "ProjectId", "Project", "ProjectName", and "MyFirstProject", respectively. surroundWithSingleQuotes surrounds a string with '', so surroundWithSingleQuotes(idValue) == "'MyFirstProject'". I am trying to write this function as general as possible since I might want to get all of a given attribute from a table in the future.
Although the above String.Format works, this doesn't:
string sqlCommand = String.Format("SELECT #attributeparam FROM {0} WHERE " +
"#idparam = #idvalue", tableParam);
command.Parameters.Add(new SqlParameter("#attributeparam", attributeParam));
command.Parameters.Add(new SqlParameter("#idparam", idParam));
command.Parameters.Add(new SqlParameter("#idvalue",
surroundWithSingleQuotes(idValue)));
SqlCommand command = new SqlCommand(sqlCommand, sqlDbConnection);
using (SqlDataAdapter adapter = new SqlDataAdapter(command))
{
DataTable attributes = new DataTable();
adapter.Fill(attributes);
...
}
I'm not sure why. I get no error message, but when I fill my DataTable using a SqlDataAdapter, the DataTable contains nothing. Here are various approaches I've taken, to no avail:
Following this answer and Microsoft's documentation, using AddWithValue or using Parameters.Add and SqlParameter.Value.
Selectively replacing {0}, {1}, {2}, and {3}in String.Format with either the actual value or the parameter string.
In other places in my code, I've used parametrized queries (although with just one parameter) no problem.
Basically parameters in SQL only work for values - not identifiers of columns or tables. In your example, only the final parameter represents a value.
If you need to be dynamic in terms of your column and table names, you'll need to build that part of the SQL yourself. Be very careful for all the normal reasons associated with SQL injection attacks. Ideally, only allow a known whitelist of table and column values. If you need to be more general, I'd suggest performing very restrictive validation, and quote the identifiers to avoid conflicts with keywords (or prohibit those entirely, ideally).
Keep using SQL parameters for values, of course.
This is a valid statement:
SELECT * FROM SomeTable WHERE SomeColumn=#param
Whereas this is not:
SELECT * FROM #param
This means that you can use parameters for values and not for table names, view names, column names etc.
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:
I have the following code in asp.net:
using (OleDbCommand command = dbConnW.CreateCommand())
{
string CreateTableK = null;
CreateTableK += "Create Table DSKKAR00 (DSK_ID c(10),DSK_KIND N(1),MON_PYM C(3))";
OleDbCommand cmdCreateTable = new OleDbCommand(CreateTableK, dbConnW);
cmdCreateTable.ExecuteNonQuery();
System.Text.StringBuilder sb = new System.Text.StringBuilder();
sb.Append(WorkRoomNo + ",");
sb.Append("1,");
sb.Append(",");
OleDbCommand cmd3 = new OleDbCommand("Insert into DSKKAR00 (DSK_ID,DSK_KIND,MON_PYM) Values (" + sb.ToString() + ")", dbConnW);
cmd3.ExecuteNonQuery();
But I have the following error:
Syntax error
In addition to what Chris has offered, you are starting your CREATE TABLE with a NULL string variable, then doing a += to it. From what I remember, a NULL += "anystring" will remain a null value... You might be crashing right there too.
Although VFP is not really suceptible to SQL Injection like other SQL engines, its good habit to do parameterizing. When you do, use "?" as a place-holder for the value you want to insert, and add parameters in the same order sequence as the "?" represent.
string CreateTableK =
"Create Table DSKKAR00 (DSK_ID c(10),DSK_KIND N(1),MON_PYM C(3))";
OleDbCommand cmdCreateTable = new OleDbCommand(CreateTableK, dbConnW);
cmdCreateTable.ExecuteNonQuery();
string MyInsert =
"insert into DSKKAR00 ( dsk_id, dsk_kind, mon_pym ) values ( ?, ?, ? )";
OleDbCommand cmd3 = new OleDbCommand( MyInsert, dbConnW);
cmd3.Parameters.AddWithValue( "parmSlot1", WorkRoomNo );
cmd3.Parameters.AddWithValue( "parmSlot2", 1);
cmd3.Parameters.AddWithValue( "parmSlot3", 'tst' ); // or whatever variable to put
cmd3.ExecuteNonQuery();
First off, any time you have an error it's usually best to post the entire error message you get.
Also, when trying to debug a query problem, you should emit the actual query being sent to your server/database and inspect it. This way you can find various problems like too many commas.
Speaking of which, looking at your code, you are concatenating a String and it really looks like you have way too many commas.
The emitted query looks like it will be:
insert into DSKKAR00(DSK_ID, DSK_KIND, MON_PYM) VALUES( X,1, ,)
where X is the value of your WorkRoomNo variable.
Obviously, that isn't valid syntax and would result in the error you've seen. The commas indicate there are 4 values being passed, but the insert query only identifies 3 columns.
The next issue has to do with the column definitions themselves. The first column of that table is a c(10); the third is a c(3). I'm a little rusty, but aren't those character fields?
If so then you need to adjust your string builder to add the appropriate quotes around the values...
Which leads us to the final problem: Don't use String concatentation to build queries. Use Parameterized queries
well, the question is clear i hope, the code is this:
string sql = "delete from #tabelnaam";
SqlCommand sc = new SqlCommand();
sc.Connection = getConnection();
sc.CommandType = CommandType.Text;
sc.CommandText = sql;
SqlParameter param = new SqlParameter();
param.Direction = ParameterDirection.Input;
param.ParameterName = "#tabelnaam";
param.Value = tableName;
sc.Parameters.Add(param);
OpenConnection(sc);
sc.ExecuteScalar();
tableName is supplied to this function.
I get the exception:
Must declare the table variable #tabelnaam
IIRC, you cant use a substitute the table name for a parameter.
Rather build the SQL string containing the correct table name.
Make to changes
rather than using paramter use this
string sql = string.format( "delete from {0}",tableName);
make use of executenonquery intead of ExecuteScalar
sc.ExecuteNonQuery();
As mentioned by others, you can't parameterise the table name.
However, as you rightly mention in comments on other answers, using simple string manipulation potentialy introduces a SQL injection risk:
If your table name input is fro an untrusted source, such as user input, then using this:
string sql = string.format( "DELETE FROM {0}",tableName);
leaves you open to the table name "myTable; DROP DATABASE MyDb" being inserted, to give you:
DELETE FROM myDb; DROP DATABASE MyDB
The way round this is to delimit the table name doing something such as this:
string sql = string.format("DELETE FROM dbo.[{0}]", tableName);
in combination with checking that the input does not contain either '[' or ']'; you should probably check it also doesn't contain any other characters that can't be used as a table name, such as period and quotes.
I dont think you can parameterize the table name. From what I have read you can do it via Dynamic sql and calling sp_ExecuteSQL.
Your SQL is incorrect, you are deleting from a table variable yet you haven't defined that variable.
Update: as someone has pointed out, you are trying to dynamically build a query string but have inadvertantly used SQL parameters (these do not act as place holders for string literals).
More here:
Parameterise table name in .NET/SQL?
You cannot parameterise the table name, you have to inject it into the command text.
What you can and should do is protect yourself against SQL injection by delimiting the name thus:
public static string Delimit(string name) {
return "[" + name.Replace("]", "]]") + "]";
}
// Construct the command...
sc.CommandType = CommandType.Text;
sc.CommandText = "delete from " + Delimit(tableName);
sc.ExecuteNonQuery();
See here and here for more background info.