Im trying to perform a parameterized query in SQLite from C#, and the method im using is along the lines of creating a static command with
SQLiteCommand cmd = new SQLiteCommand(
"SELECT [ID]" +
",[email]" +
",[serializedata]" +
",[restrictions]" +
" FROM " + UserTable +
" WHERE #search = #searchparam", SQLConnection);
cmd.Parameters.Add(new SQLiteParameter("#searchparam"));
cmd.Parameters.Add(new SQLiteParameter("#search"));
and calling it like this:
Command.Parameters["#searchparam"].Value = searchdata;
Command.Parameters["#search"].Value = search;
SQLiteDataAdapter slda = new SQLiteDataAdapter(UserSelectUsernameCommand);
DataSet ds = new DataSet();
slda.Fill(ds);
User[] array = new User[ds.Tables[0].Rows.Count];
int index = 0;
foreach (DataRow row in ds.Tables[0].Rows)
{
array[index] = new User(this, row);
index++;
}
return array;
but im getting an error along the line of " '#search' is not a correct column name " or something like that. if i use a constant column name, and only use the data for parameters it works, but i dont want to create 10 different commands for when i need to search by different column names.
What is the issue here?
Generally things like column names (or table names) can not be parameterised - and the fact that there are different indices means that it will have to be a different plan internally. So you will have to use concatenation - but be careful to white-list the known column names to prevent sql injection:
SQLiteCommand cmd = new SQLiteCommand(#"
SELECT [ID],[email],[serializedata],[restrictions]
FROM " + whiteListedUserTable + #"
WHERE [" + whiteListedColumnName + #"] = #searchparam", SQLConnection);
cmd.Parameters.Add(new SQLiteParameter("#searchparam"));
...
Command.Parameters["#searchparam"].Value = searchdata;
You cannot use a query parameter in that fashion -- to indicate a column name. You can only use it to supply values.
Consider something like this instead:
SQLiteCommand cmd = new SQLiteCommand(
"SELECT [ID]" +
",[email]" +
",[serializedata]" +
",[restrictions]" +
" FROM " + UserTable +
" WHERE [" + search + "] = #searchparam", SQLConnection);
cmd.Parameters.Add(new SQLiteParameter("#searchparam"));
If you control all of the input to this function and none if it can be supplied by someone other than you, this should be safe. But if search comes from an untrusted third party, be sure to make the appropriate security checks on the value.
Related
How to correct send parameters to oledb query?
MyCode is
cmd.CommandText = "UPDATE #target SET [#columnname] = Replace([#columnname], Chr(10), '');";
cmd.Parameters.Add(new OleDbParameter("#target", OleDbType.VarChar)).Value = tb_tablename.Text.Trim();
cmd.Parameters.Add(new OleDbParameter("#columnname", OleDbType.VarChar)).Value = column.ColumnName;
And it's not working). I need to add in query #target ( table name ) and #columnname ( column name ).
Modified to code with ?
cmd.CommandText = "UPDATE ? SET [?] = Replace([?], Chr(10), '');";
cmd.Parameters.Add(new OleDbParameter("#target", OleDbType.VarChar)).Value = tb_tablename.Text.Trim();
cmd.Parameters.Add(new OleDbParameter("#columnname", OleDbType.VarChar)).Value = column.ColumnName;
cmd.Parameters.Add(new OleDbParameter("#columnname", OleDbType.VarChar)).Value = column.ColumnName;
Got error:
syntax error in update statement
Concatenation style got error
string query = "UPDATE " + tb_tablename.Text.Trim() + " SET [" + column.ColumnName + "] = Replace([" + column.ColumnName + "], Chr(10), '');";
data type mismatch in criteria expression
Full code:
DataTable dt = new DataTable();
using (OleDbDataAdapter adapter = new OleDbDataAdapter("SELECT * FROM " + tb_tablename.Text, conn))
{
adapter.Fill(dt);
}
foreach (DataColumn column in dt.Columns)
{
if (column.DataType == typeof(String))
{
if (column.ColumnName != "ID1" && column.ColumnName != "ID" && column.ColumnName != "Geometry" && column.ColumnName != "Geometry_SK")
{
string query = "UPDATE " + tb_tablename.Text.Trim() + " SET [" + column.ColumnName + "] = Replace([" + column.ColumnName + "], Chr(10), '');";
using (OleDbCommand cmd = new OleDbCommand(query, conn))
{
cmd.ExecuteNonQuery();
}
}
}
}
Whats helped: string query = "UPDATE " + tb_tablename.Text.Trim() + " SET " + column.ColumnName + " = Replace(" + column.ColumnName + ", Chr(10), \"\") WHERE " + column.ColumnName + " <> \"\";";
Blank data + reserved column name brokes all. ColumnNames Date,Type,Note brokes all - exclude it from cycle.
You're getting a syntax error because cannot make a SQL identifier (table name, column name etc) a parameter. Only values can be parameterized
Your query would hence have to look like:
cmd.CommandText = "UPDATE "+tb_tablename.Text+" SET ["+...+"] = Replace(["+...+"], Chr(10), '');";
Never concatenate values supplied by the user, into an SQL. Because you're forced in this instance to concat take and column names in you should absolutely make sure that only safe values are provided. Ideally you should take the value provided for the the table name and column name and have a lot of all table and column names (you can query the db for this) and only permit the sql to build if the values provided are in that list
This is a very unusual requirement- almost no one here seeks to parameterize table names etc. If you're trying to write some sort of mini library to make your data access life easier, I would recommend you use one that already exists like Dapper
You indicated in a comment that you're trying to run a replace on all columns in a db with minimal effort. For this you can consider the following:
use the GetSchema method of your DbConnection object to get a list of the tables in the db
loop Over it, concatenate a string sql of the table name into "SELECT * FROM "+tablename+" WHERE 1=0" and run this sql using a DataAdapter to return an empty datatable with all the columns of the target table
loop over the datatable.Columns collection returned from the above select, running your REPLACE sql, subbing the table and column names in via string concat (it's safe and non hackable because you retrieved the list and are not concatting values provided by a user
if you have non string columns (dates,ints) then examine the datatype of the DataColumn and only run th replace if it's a string/varchar or similar
Helpful links:
https://learn.microsoft.com/en-us/dotnet/framework/data/adonet/getschema-and-schema-collections
https://sizious.com/2015/05/11/how-to-load-an-access-database-into-a-dataset-object-in-c/ - goes part way- add a where clause to this guy's code so that no rows are returned (you only want the columns)
You cannot substitute table and column names with parameters.
Parameters can only be applied as follows:
UPDATE SomeTable SET SomeColumn = ?
It is best to allow the user to choose the names of tables and columns from Comboboxes/ListBoxes with ready-made values. Something like this:
var table = tablesComboBox.SelectedItem;
var column = columnsComboBox.SelectedItem;
var query = "UPDATE " + table + " SET " + column +
" = Replace(" + column + ", Chr(10), '''');";
Note that you must escape single quote characters.
How to update bool in a database a sql query
below is the code i have but i am unsure of how to implement the checkbox.
Thank you for any help.
i have updated the code to remove the sql injection problems.
con.Open();
OleDbCommand cmd = new OleDbCommand(String.Concat("Select * From ", comboBox1.Text), con);
cmd.CommandType = CommandType.Text;
string tableName = comboBox1.Text.ToString();
cmd.CommandText = #"UPDATE [" + tableName + "] SET"
+"People_Call_Status = #People_Call_Status,"
+"Research_Date=#Research_Date,"
+ "tblCompanies_Area_Dialling_Code = #tblCompanies_Area_Dialling_Code,"
+ "Work_Number = #Work_Number,"
+ "building_Address = #building_Address,"
+ "[Street Address] = #[Street Address],"
+ "suburb = #suburb,"
+ "city = #city,"
+ "res_Code = #res_Code,"
+ "industry_Vertical_ID = #industry_Vertical_ID,"
+ "pO_Box = #pO_Box,"
+ "post_Office = #post_Office,"
+ "postal_Code = #postal_Code,"
+ "country_ID = #country_ID,"
+ "province_ID = #province_ID," //this line
+ "prospect = #prospect"
+ "WHERE Company_ID = #Company_ID ";
cmd.Parameters.AddWithValue("#People_Call_Status", Status_textBox1.Text);
cmd.Parameters.AddWithValue("#Research_Date", Date_textBox.Text);
cmd.Parameters.AddWithValue("#Company_Name", company_NameTextBox.Text);
cmd.Parameters.AddWithValue("#tblCompanies_Area_Dialling_Code", tblCompanies_Area_Dialling_CodeTextBox.Text);
cmd.Parameters.AddWithValue("#Work_Number", work_NumberTextBox.Text);
cmd.Parameters.AddWithValue("#building_Address", building_AddressTextBox.Text);
cmd.Parameters.AddWithValue("#[Street Address]", street_AddressTextBox.Text);
cmd.Parameters.AddWithValue("#suburb", suburbTextBox.Text);
cmd.Parameters.AddWithValue("#city", cityTextBox.Text);
cmd.Parameters.AddWithValue("#res_Code", res_CodeTextBox.Text);
cmd.Parameters.AddWithValue("#industry_Vertical_ID", industry_Vertical_IDTextBox.Text);
cmd.Parameters.AddWithValue("#pO_Box", pO_BoxTextBox.Text);
cmd.Parameters.AddWithValue("#post_Office", post_OfficeTextBox.Text);
cmd.Parameters.AddWithValue("#postal_Code", postal_CodeTextBox.Text);
cmd.Parameters.AddWithValue("#country_ID", country_IDTextBox.Text);
cmd.Parameters.AddWithValue("#province_ID", province_IDTextBox.Text);
cmd.Parameters.AddWithValue("#prospect", prospectCheckBox.Checked);
cmd.Parameters.AddWithValue("#Company_ID", company_IDTextBox.Text);
cmd.ExecuteNonQuery();
{
MessageBox.Show("Update Success!");
con.Close();
}
In SQL Server, bool is mapped as a bit datatype with 0 and 1 values.
So what you need to do is:
"', prospect = '" + prospectCheckBox.Checked ? 1 : 0
Side-Note:
Don't concatenate strings to build up your query from user data input, this is vulnerable to SQL injection. Instead, use parameterized queries or stored procedures.
What DBMS platform are you using, and can you show the DDL for the table?
I can't guarantee this will work, but instead of using AddWithValue try using the Add method with explicit types declared:
cmd.Parameters.Add(new OleDbParameter("#People_Call_Status", OleDbType.VarChar));
cmd.Parameters.Add(new OleDbParameter("#Research_Date", OleDbType.VarChar));
...
cmd.Parameters.Add(new OleDbParameter("#prospect", OleDbType.Boolean));
cmd.Parameters.Add(new OleDbParameter("#Company_ID", OleDbType.VarChar));
cmd.Parameters[0].Value = Status_textBox1.Text;
cmd.Parameters[1].Value = Date_textBox.Text;
...
cmd.Parameters[16].Value = prospectCheckBox.Checked;
cmd.Parameters[17].Value = company_IDTextBox.Text;
Also, with regards to SQL Injection, you still have a theoretical vulnerability:
cmd.CommandText = #"UPDATE [" + tableName + "] SET"
+ "People_Call_Status = #People_Call_Status,"
+ "Research_Date=#Research_Date,"
...
+ "prospect = #prospect"
+ "WHERE Company_ID = #Company_ID ";
I realize it's an obscure possibility, but if the tableName variable were to contain this string or something like it:
Table1 set foo = 'bar';
truncate table ba2;
update table3
You could see how it would compile, execute and do something other than what you had in mind. Again, I realize this is reaching, and your input does come from a combo box, but it's still a theoretical risk.
I'm creating an Inventory System which can add multiple items in a single click. how could I do this? I can already save data but for just a single textbox.
//Add new Data if Item Code is not exit;
{
OleDbCommand cmdInsert = new OleDbCommand(#"insert into TblInventory (ItemCode,ProductName,Quantity,DateAndTime) values ('" + txtItem.Text + "','" + txtProduct.Text + "','" + txtQuantity.Text + "','" + time + "')");
cmdInsert.Connection = con;
cmdInsert.ExecuteNonQuery();
MessageBox.Show("You added New " + txtQuantity.Text + " " + txtProduct.Text + " in the list", "New Item");
}
con.Close();
assuming that I have another textBoxes which are txtItem2, txtProduct2 and txtQuantity2. where can I locate those on my insert into statement?
First, use parameters instead of string concatenation, like below:
OleDbCommand cmdInsert = new OleDbCommand(
#"insert into TblInventory (ItemCode,ProductName,Quantity,DateAndTime) values (#ItemCode,#ProductName,#Quantity,#DateAndTime)");
cmdInsert.Parameters.AddWithValue("ItemCode", txtItem.Text);
cmdInsert.Parameters.AddWithValue("ProductName", txtProduct.Text);
cmdInsert.Parameters.AddWithValue("Quantity", txtQuantity.Text);
cmdInsert.Parameters.AddWithValue("DateAndTime", time);
Second, if you need many inserts, use loop. Or, wrap your insert code in function with four parameters ItemCode,ProductName,Quantity,DateAndTime. Use them instead of direct references to txtSomething.Text values, i.e. (pseudocode):
InsertRecord(txtItem.Text, txtProduct.Text, ...);
InsertRecord(txtItem2.Text, txtProduduct2.Text, ...);
For loop you can write like below:
var rows = new[]
{
new {Item = "item1" /*value from txtItem1*/, Product = "product1", Quantity = "Quantity1" /*should be int?*/},
new {Item = "item2" /*value from txtItem2*/, Product = "product2", Quantity = "Quantity2"}
};
foreach (var row in rows)
{
OleDbCommand cmdInsert = new OleDbCommand(
#"insert into TblInventory (ItemCode,ProductName,Quantity,DateAndTime) values (#ItemCode,#ProductName,#Quantity,#DateAndTime)");
cmdInsert.Parameters.AddWithValue("ItemCode", row.Item);
cmdInsert.Parameters.AddWithValue("ProductName", row.Product);
cmdInsert.Parameters.AddWithValue("Quantity", row.Quantity);
cmdInsert.Parameters.AddWithValue("DateAndTime", DateTime.Now);
cmdInsert.Connection = conn;
cmdInsert.ExecuteNonQuery();
}
You could create a stored procedure accepting xml as input parameter, and then in the stored procedure ypu will parse the xml and insert the data to the table,
I am using visual studio 2010 on Win 7. I want to read a .dbf file and get the minimum value of a selected column.
Here is what I have:
System.Data.Odbc.OdbcConnection oConn = new System.Data.Odbc.OdbcConnection();
oConn.ConnectionString = #"Driver={Microsoft dBase Driver (*.dbf)};SourceType=DBF;SourceDB=" + ImportDirPath + ";Exclusive=No; Collate=Machine;NULL=NO;DELETED=NO;BACKGROUNDFETCH=NO;";
oConn.Open();
// Update time
string nowTime = DateTime.Now.ToString("HHmmss");
oCmd.CommandText = #"UPDATE " + tableName + " SET HQCJBS = " + nowTime + " WHERE HQZQDM = ?";
oCmd.Parameters.AddWithValue("row2", "000000");
oCmd.ExecuteNonQuery();
string query = "SELECT MIN(" + colName + ") FROM " + tableName + " WHERE HQZQDM <> 000000";
OdbcDataAdapter da = new OdbcDataAdapter(query, oConn);
DataSet ds = new DataSet();
da.Fill(ds);
Suppose colName and tableName are correct. I have two question.
Two Questions:
When the code da.Fill(ds); is hit, I got an error data type mismatch in criteria expression access, What is wrong?
After I get the minimum value from the database, how can I input it into the memory as a double, for example double min = ds.Tables[0];
Your update command should apply TWO parameters... one for the set, another for the where clause. Use the "?" place-holder for each respectively and add the parameters in the same order as they appear in the query.
string nowTime = DateTime.Now.ToString("HHmmss");
oCmd.CommandText = #"UPDATE " + tableName + " SET HQCJBS = ? WHERE HQZQDM = ?";
oCmd.Parameters.AddWithValue("setParm", nowTime );
oCmd.Parameters.AddWithValue("whereParm, "000000");
oCmd.ExecuteNonQuery();
For your select MIN() query, it appears your WHERE criteria column is a string and by having the literal numbers without quotes is applying it as a numeric... Again, stick with "?" parameters
OdbcCommand getMinCmd = new OdbcCommand("", oConn);
getMinCmd.CommandText = "SELECT MIN(" + colName
+ ") FROM " + tableName + " WHERE HQZQDM <> ?";
getMinCmd.Parameters.AddWithValue("whereParm, "000000");
OdbcDataAdapter da = new OdbcDataAdapter(getMinCmd);
DataSet ds = new DataSet();
da.Fill(ds);
Finally, to get the value OUT of the retrieved query into memory, you need to get the row of the table (only 1 record result set, zero-based index) and column-0 too. Since you did not assign a column name, you don't know the column and just go with 0-index...
int lowestValue = (int)ds.Tables[0].Rows[0][0];
Think of the above as the hierarchy...
ds
tables[0]
rows[0]
[column 0]
rows[1] -- but your query would only have one row anyhow
[column 0]
tables[1] -- if your query had multiple queries, this might be available
but at least it shows where the pieces are.
Now, if you change your query slightly to something like
select MIN( colName ) as MyMinValue ...
then your reference would be where you explicitly name the column from the row retrieved
int lowestValue = (int)ds.Tables[0].Rows[0]["MyMinValue"];
I am attempting to dynamically update a set of database tables. I have two variables;
table_name & field_name. These are populated by a foreach loop, that loops through a DataTable. Everytime we hit a new row in the DataTable the names change respectively. Within this loop I create a new Oracle Connection and attempt to write an update with the current table_name/field_name. But Oracle keeps giving me an error on my ExcecuteNonQuery command.
Any help is greatly appreciated!!
EDIT: I have reformatted to include parameters, still does not work does anyone have any ideas on what I am doing wrong?
foreach (DataRow fieldtable in setofTables.Tables[0].Rows)
{
//do work
table_name = fieldtable["table_name"].ToString().Trim();
field_name = fieldtable["field_name"].ToString().Trim();
MessageBox.Show(table_name + field_name);
//create parameters
OracleParameter fieldParamater = new OracleParameter("field_name", OracleDbType.Varchar2);
OracleParameter diffParameter = new OracleParameter("mark_diff_oracle", OracleDbType.BinaryFloat);
OracleParameter wellIdParameter = new OracleParameter("id", OracleDbType.Char);
//wellIdParameter.Size = 10;
//create oracle connection and open
OracleConnection OrclCon2 = new OracleConnection("Data Source=" + dbname + "; User Id=" + userid + ";Password=" + password1 + ";");
OrclCon2.Open();
//prepare sql to be passed to oracle
string UpdateOraSQL = "UPDATE " +table_name+ " set :field_name = :field_name - (:mark_diff_oracle) where id = ':id' and :field_name is not null;";
MessageBox.Show(UpdateOraSQL);
//create dommand
OracleCommand UpdateDB = new OracleCommand(UpdateOraSQL, OrclCon2);
UpdateDB.CommandType = CommandType.Text;
//add parameters
UpdateDB.Parameters.Clear();
UpdateDB.Prepare();
UpdateDB.Parameters.Add(fieldParamater).Value = field_name;
UpdateDB.Parameters.Add(diffParameter).Value = mark_diff_oracle;
UpdateDB.Parameters.Add(wellIdParameter).Value = id;
Remove the semicolon from the end of the sql statement. Change the following code
string UpdateOraSQL = "UPDATE " +table_name+ " set :field_name = :field_name - (:mark_diff_oracle) where id = ':id' and :field_name is not null;";
to
string UpdateOraSQL = "UPDATE " +table_name+ " set :field_name = :field_name - (:mark_diff_oracle) where id = ':id' and :field_name is not null";
See the following link for more information
why the semicolon couldn't place in the CommandText of a OracleCommand when C#
If the problem is still not resolved, it might be helpful if you post the entire exception message also.
AFAIK, you cannot use parameters to define the column that you're updating.
AFAIK, you can only use parameters for the values that you'd want to set.
So, you'll have to create the query using string concat:
string sql = "UPDATE " + tableName + " SET " + fieldName + " = :p_Value WHERE id = :p_Id";
OracleCommand UpdateDB = new OracleCommand(sql, OrclCon2);
UpdateDB.Parameters.Add ("p_Value", ... ).Value = "foo";
UpdateDB.Parameters.Add ("p_Id", ...).Value = 4;
Offcourse, you should make sure that the variables you're adding to the string do not contain any harmfull statements. You should do sanity checks on them.
Perhaps, you can even verify if the tableName or the fieldName that has been passed, is a valid / existing tableName/columnname.
In SQL, one does not say COLUMN <> NULL. The proper syntax is COLUMN IS NOT NULL.