C# Parameterized Oracle Update fails on ExecuteNonQuery - c#

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.

Related

MySQL SELECT INTO Variable, Getting 'Fatal Error encountered during command execution.'

I have tried MANY suggested solutions from here but nothing seems to work for this problem. I just keep getting this error message when it hits the 'mdr = command.ExecuteReader();' line. Any thoughts please?
try
{
MySqlConnection connection = new MySqlConnection("SERVER=" + server + ";" + "DATABASE=" + database + ";" + "UID=" + uid + ";" + "PASSWORD=" + password + ";");
MySqlCommand command;
MySqlDataReader mdr;
connection.Open();
string ThePID = tbPID.Text;
string TheRound = tbRound.Text;
string CurrentPage = tbCurrentPage.Text;
// SELECT #myvar:= myvalue
string query = "SELECT ImageURL, ProofingText " +
"INTO #ImageURL, #ProofingText " +
"FROM Rounds " +
"WHERE ProjectID = " + ThePID + " " +
"AND CurrentRound = " + TheRound + " " +
"AND Page = " + CurrentPage + ";";
command = new MySqlCommand(query, connection);
mdr = command.ExecuteReader();
mdr.Read();
rtProofing.Text = mdr.GetString("#PRoofingText");
tbURL.Text = mdr.GetString("#ImageURL");
tbImagePage.Text = Path.GetFileName(tbURL.Text);
PageBox.Image = Image.FromFile(tbURL.Text);
connection.Close();
connection.Dispose();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
If you use MySqlConnector, you will get a helpful exception message that explains the problem:
Parameter '#ImageURL' must be defined. To use this as a variable, set 'Allow User Variables=true' in the connection string.
By default, MySQL queries (executed from .NET) can't use user-defined variables. You can relax this limitation by adding Allow User Variables=true to your connection string.
However, this won't fix your underlying problem, which is that this isn't the right way to select data from MySQL.
Firstly, your query is susceptible to SQL injection; you should rewrite it to use parameters as follows:
using (var command = connection.CreateCommand())
{
command.CommandText = #"SELECT ImageURL, ProofingText
FROM Rounds
WHERE ProjectID = #ThePID
AND CurrentRound = #TheRound
AND Page = #CurrentPage;";
commands.Parameters.AddWithValue("#ThePID", ThePID);
commands.Parameters.AddWithValue("#TheRound", TheRound);
commands.Parameters.AddWithValue("#CurrentPage", CurrentPage);
Then, you can retrieve the values with a slight variation on your current code. You must retrieve the values by their column names, which do not have a leading #. You should also check that a row was retrieved by examining the return value of Read():
if (mdr.Read())
{
rtProofing.Text = mdr.GetString("ProofingText");
tbURL.Text = mdr.GetString("ImageURL");
}
Finally, string concatenation is also not the right way to build a connection string. The MySqlConnectionStringBuilder class exists for this purpose; use it.
var builder = new MySqlConnectionStringBuilder
{
Server = server,
Database = database,
UserID = uid,
Password = password,
};
using var connection = new MySqlConnection(csb.ConnectionString);

Using Subquery as Parameter Value [duplicate]

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.

Read Data from .dbf File with OdbcConnection

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"];

How do i assign the return data from MySql to a C# variable?

I am trying to acquire the count of a column in my database.
string cmdstr = "select count(" + col + ") from " + tbname + " where \"" +
col + "\" =\"" + val + "\"";
However, I do not know how to assign the count value to an int.
var myVariable = new MySqlCommand("SELECT 3 FROM table WHERE id = 1",
databaseCon);
int id = (int)myVariable.ExecuteScalar();
Cast your teturn value and assign it to Int type variable
If you want more help inform me
Perhaps this is able to help you:
var result = Cmd.ExecuteNonQuery();
This was suggested to me on one of my SQL questions, when I asked as to why doing it like this rather then just typing Cmd.ExecuteNonQuery();. He explained to me that this way you get a variable saying how many rows were affected.
There is two way, ExecuteScalar to get the value or you can get DataSet
ExecuteScalar
int result = Convert.ToInt32(sqlCommand.ExecuteScalar().ToString());
DataSet
MySqlDataAdapter mySqlDataAdapter = new MySqlDataAdapter(sqlCommand);
DataSet dataSet = new DataSet();
mySqlDataAdapter.Fill(dataSet);
int result = Convert.ToInt32(DataSet.Tables[0].Rows[0]["YourFieldName"].Tostring());

How can i select from table where tablename is specified as SqlParameter?

I am trying to perform dynamic sql select where I am selecting from a table using a parameter.
SELECT null FROM #TableName
However I am getting error must declare table variable #TableName. I suspect this is because I am selecting from a table using a variable. I have not needed to do this before.
List<SqlParameter> sqlParams = new List<SqlParameter>()
{
new SqlParameter("TableName", "testtable"),
new SqlParameter("FieldName", "testfield"),
new SqlParameter("Find", "testfind"),
};
string sqlSelect = "SELECT null FROM #TableName
WHERE #FieldName LIKE '%' + #Find + '%' ";
DataTable dtSelect = SqlHelper.ExecuteDataset(sqlConn, CommandType.Text,
sqlSelect, 30, sqlParams.ToArray()).Tables[0];
//30 = timeout
How can I perform the above using dynamic sql? (no stored procedures please)
You cannot use parameters for things like table and column names. For those you could have a whitelist of possible values and then use string concatenation when building the SQL query.
You can't use parameters like that, so you have to build the query as a string. You could do that in SQL, but you can also just create the string in the C# code.
Make sure that the table name and field name are safe and trusted values, and doesn't come directly from an unsafe source like a web request.
string tableName = "testtable";
string fieldName = "testfield";
List<SqlParameter> sqlParams = new List<SqlParameter>() {
new SqlParameter("Find", "testfind"),
};
string sqlSelect =
"SELECT null " +
"FROM " + tableName + " " +
"WHERE " + fieldName + " LIKE '%' + #Find + '%' ";
private DataTable ExecuteDynamic(string TableName,string FieldName, string Find)
{
string sqlSelect = "SELECT * FROM " + TableName +
" WHERE " + FieldName + " LIKE '%'" + Find + "'%' ";
using (connection = new SqlConnection(Strcon))
connection.Open();
{
using (cmd = new SqlCommand(sqlSelect, connection))
{
cmd.CommandType = CommandType.Text;
cmd.CommandTimeout = 60;
adpt = new SqlDataAdapter(cmd);
dt = new DataTable();
adpt.Fill(dt);
return (dt);
}
}
}

Categories