I have a long SQL query, it does some inserts, updates, then deletes. Each query uses the same 2 parameters. If I pass them in as SQL parameters from C#, it times out, after 20 mins. I just put the parameters into the command text, and it works. When I use it with the parameters it doesn't even show up in the profiler till it times out. Am I missing something?
SqlCommand comm = new SqlCommand(cmdText, conn);
comm.CommandTimeout = 5 * 60;
SqlParameter p = new SqlParameter("#key1", SqlDbType.Int);
p.Value = key1;
comm.Parameters.Add(p);
p = new SqlParameter("#key2", SqlDbType.Int);
p.Value = 1000000;
comm.Parameters.Add(p);
comm.ExecuteNonQuery();
If you take the parameter code out, and just to a replace on cmdText before executing the query it works. The query itself is a 300 lines or so. Each parameter gets used 51 times.
You may be missing the comm.Prepare() call before ExecuteNonQuery().
The key is in the SQL command, instead of saying "cmdText" post your SQL command.
EDIT: You are also not specifying a parameter direction in the code, it might be important.
Did you set the command type?
var command = new SqlCommand() { CommandType = CommandType.StoredProcedure };
Related
I am trying to modify a table data using a SQL statement
foreach (Words words in Words_DB.Records)
{
string _IPAUS = words.IPAUS;
string _IPAUK = words.IPAUK;
query = "UPDATE Words SET IPAUK='" + _IPAUK + "',IPAUS='" + _IPAUS + "' WHERE WORD='" + words.Word + "'";
command.Parameters.Clear();
command.CommandText = query;
//command.Parameters.AddWithValue("#IPAUK", _IPAUK);
//command.Parameters.AddWithValue("#IPAUS", _IPAUS);
//command.Parameters.AddWithValue("#WORD", words.Word);
int a = command.ExecuteNonQuery();
}
A example of query is UPDATE Words SET IPAUK='ɑːd.vɑːk',IPAUS='ɑːrd.vɑːrk' WHERE WORD='aardvark'
The problem is when a read the database data I receive :
But, when I use the MySql Tools to execute the Query the result is right.
What I am doing wrong?
Regards
The question concatenates raw input to generate a SQL query which exposes to SQL injection and bugs like this one. If _IPAUK contained '; -- all the data in that column would be lost.
In this case it seems the code is trying to pass Unicode data using ASCII syntax, resulting in mangled data.
The solution to both SQL injection and conversion issues is to use parameterized queries. In a parameterized query, the actual parameter values never become part of the query itself. The server compiles the SQL query into an execution plan and executes that using the parameter values.
await using var connection = new MySqlConnection(connString);
await connection.OpenAsync();
// Insert some data
using (var cmd = new MySqlCommand())
{
cmd.Connection = connection;
cmd.CommandText = "UPDATE Words SET IPAUK=#IPAUK,IPAUS=#IPAUS WHERE WORD=#Word";
cmd.Parameters.AddWithValue("IPAUK", words.IPAUK);
cmd.Parameters.AddWithValue("IPAUS", words.IPAUS);
cmd.Parameters.AddWithValue("Word", words.Word);
await cmd.ExecuteNonQueryAsync();
}
The example uses the open source MySQLConnector ADO.NET Driver instead of Oracle's somewhat ... buggy driver.
The code can be simplified even more by using Dapper to construct the command, parameters and handle the connection automagically. Assuming words only has the IPAUK, IPAUS and Word properties, the code can be reduced to three lines :
var sql="UPDATE Words SET IPAUK=#IPAUK,IPAUS=#IPAUS WHERE WORD=#Word";
await using var connection = new MySqlConnection(connString);
await connection.ExecuteAsync(sql,words);
Dapper will construct a MySqlCommand, add parameters based on the properties of the parameter object (words), open the connection, execute the command and then close the connection
Thanks a lot for your helps.
This is my final code working properly.
string query = "UPDATE Words SET IPAUK=#IPAUK,IPAUS=#IPAUS WHERE WORD=#WORD";
var command = DatabaseConnection.MySql_Connection.CreateCommand();
try
{
foreach (Words words in Words_DB.Records)
{
MySqlParameter IPAUSp = new MySqlParameter("#IPAUS", MySqlDbType.VarChar, 60);
MySqlParameter IPAUKp = new MySqlParameter("#IPAUK", MySqlDbType.VarChar, 60);
MySqlParameter WORD = new MySqlParameter("#WORD", MySqlDbType.VarChar, 50);
command.Parameters.Clear();
command.CommandText = query;
command.Parameters.AddWithValue(IPAUKp.ToString(), words.IPAUK);
command.Parameters.AddWithValue(IPAUSp.ToString(), words.IPAUS);
command.Parameters.AddWithValue(WORD.ToString(), words.Word);
int a = command.ExecuteNonQuery();
}
}
Try it like this:
command.CommandText = "UPDATE Words SET IPAUK= #IPAUK, IPAUS= #IPAUS WHERE WORD= #Word;";
// Match these to the column type and length in the DB
command.Parameters.Add("#IPAUK", MySQlDbType.VarChar, 30);
command.Parameters.Add("#IPAUS", MySQlDbType.VarChar, 30);
command.Parameters.Add("#Word", MySQlDbType.VarChar, 30);
foreach (Words words in Words_DB.Records)
{
command.Parameters["#IPAUK"].Value = words.IPAUK;
command.Parameters["#IPAUS"].Value = words.IPAUS;
command.Parameters["#Word"].Value = words.Word;
command.ExecuteNonQuery();
}
Notice how the above minimizes the work done in the loop, which should improve performance, while also fixing the HUGE GAPING SECURITY ISSUE in the question from using string concatenation to build the query.
Separately, I have the impression Words_DB.Records is the result of a prior query. It's highly likely you could eliminate this entire section completely by updating the prior query to also do the update in one operation on the server. Not only would that greatly reduce your code, it will likely improve performance here by multiple orders of magnitude.
I am setting CommandTimeout to 1 second and no TimeoutException is being thrown as expected. The query I am running takes about 7-8 seconds. The timeout does work however when I use ExecuteReader to execute a query rather than trying to fill a DataTable. I have tried setting CommandTimeout when after creating the command and also after creating the DataAdapter.
using(SqlConnection con = new SqlConnection("data source=*****;user id==*****;password==*****;initial catalog==*****;"))
{
string query = "select * from *****";
SqlCommand command = new SqlCommand(query, con);
//command.CommandTimeout = 1;
CostingDataSet cds = new CostingDataSet();
SqlDataAdapter da = new SqlDataAdapter(command);
da.SelectCommand.CommandTimeout = 1;
Stopwatch stopwatch = Stopwatch.StartNew();
da.Fill(cds.CostingData);
stopwatch.Stop();
Console.WriteLine(stopwatch.ElapsedMilliseconds);
}
The cause is the magic that occurs in the SQLDataAdapter, which is frankly, why they are a bad idea.
My guess is they are using async to perform the fill, which will always ignore command timeouts.
My suggestion: run away from the adapter, and never look back. They aren't that valuable and make everything messier.
If that isn't possible, set your connection timeout in your connection string and it should apply regardless of how the db is accessed.
Queries like "select * from" are a bad idea.
What is the reason not to use select *?
That said, maybe you could restric the amount of data to return, by paging or similar way. Reducing the amount of returned data will make it work
I am a newbie in DB2 world and am using:
- DB2 Data Provider for .NET (IBM.Data.DB2.dll version 9.7.4.4)
- C# VS2010 with .NET Framework 4.0
I have problem with query that uses parameter.
My code snippet:
DB2Command cmd = new DB2Command();
cmd.CommandText = "SELECT COUNT(*) FROM CUSTOMERS t0 WHERE (t0.\"CITY\" < :p0)";
cmd.Connection = Db2Connection;
DB2Parameter param = cmd.CreateParameter();
param.DB2Type = DB2Type.VarChar;
param.ParameterName = ":p0";
param.Value = "Seattle";
var p = cmd.Parameters.Add(param);
var execResult = cmd.ExecuteScalar();
I get following error on cmd.ExecuteScalar():
The number of variables in the EXECUTE statement, the number of
variables in the OPEN statement, or the number of arguments in an OPEN
statement for a parameterized cursor is not equal to the number of
values required. SQLSTATE=07004
Please help how to fix the problem. Thank you in advance.
Additional information:
1. I just tried to use IBM Data Studio to verify the DB2 command using query editor. It doesn't recognize the prefix "#" for parameter. So I use oracle-liked prefix ":" for it. It works. But my C# code still raises the error [07004] SQL0313N
2. If I don't use any prefix for parameter on my C# code, I get ERROR [42703] [IBM][DB2/NT64] SQL0206N \"P0\" is not valid in this context.
Finally I find out 2 ways to fix the problem.
Using unnamed parameter "?" instead of parameter name ":p0".
DB2Command cmd = new DB2Command();
cmd.CommandText = "SELECT COUNT(*) FROM CUSTOMERS t0 WHERE (t0.\"CITY\" < ?)";
cmd.Connection = Db2Connection;
DB2Parameter param = cmd.CreateParameter();
param.DB2Type = DB2Type.VarChar;
param.ParameterName = "param1";
param.Value = "Seattle";
var p = cmd.Parameters.Add(param);
var execResult = cmd.ExecuteScalar();
Activate HostVarParameters property of class DB2ConnectionStringBuilder and the original code remains unchanged (keeping using named parameters).
My 2 cents,
Mag
The following code results in a System.Data.SqlClient.SqlException: Timeout expired.
const string sqlStmt = #"SELECT *
FROM CUSTOMER_INFO
WHERE CUSTOMER_NO = #CUSTOMER_NO;";
SqlCommand command = new SqlCommand(sqlStmt, connection);
command.Parameters.AddWithValue("#CUSTOMER_NO", txtAccountNo.Text.Trim().ToUpper());
but this does not time out...
const string sqlStmt = #"SELECT *
FROM CUSTOMER_INFO
WHERE CUSTOMER_NO = #CUSTOMER_NO;";
SqlCommand command = new SqlCommand(sqlStmt, connection);
command.Parameters.Add("#CUSTOMER_NO", SqlDbType.VarChar, 25).Value = txtAccountNo.Text.Trim().ToUpper();
I don't understand why, can anyone enlighten me?
Can you get a look at the SQL statement that gets executed by the database ?
You'll probably see a difference in the type that is used by the parameter. I believe that the AddParamWithValue method will not use the correct type for the parameter.
Then, it is possible that the DBMS will have to convert the value back to the correct type. Some DBMS'es will not be able to use an index-lookup in that case, which will result in a longer running query, hence the timeout.
I have an Informix database which exposes some stored procedures, I have an abstracted data accessor that handles communicating with them but I have a problem with a null value.
Directly you can call:
execute procedure some_stored_procedure(1,2,NULL,3)
and get back correct results, I would rather there not be this nullable field, but it is out of my hands. Anyway I was originally trying to call it like so:
var command = connection.CreateCommand();
command.CommandType = CommandTypes.StoredProcedure
command.CommandText = "some_stored_procedure"
// Pass in the parameters
However doing that causes Informix to throw a syntax error, so instead I have been forced to go with the:
var command = connection.CreateCommand();
command.CommandText = "execute procedure some_stored_procedure(?,?,?,?)";
// Pass in parameters
Which works but never passes back correct results, and if I try and make parameter 3 null it gives another syntax error. Am I missing something or is there a better way to call these stored procedures?
try parameterizing the parameters (you can use OdbcParameters if working with the odbcdriver) and then pass DbNull.Value where Null is required.
Try this:
var command = connection.CreateCommand();
command.CommandType = CommandTypes.Text;
command.CommandText = "call some_stored_procedure(?,?,?,?)";
command.Parameters.Add(param); //add all your parameters.
Format the query as follow:
strQuery = string.Format("EXECUTE PROCEDURE Cronos_UpdateStateLegacyProduct ({0})", oValidityProducts.PurchaseId);
OdbcConnection oConnection = new OdbcConnection(this.strConnectionString);
OdbcCommand oCommand = new OdbcCommand();
oCommand.CommandType = CommandType.StoredProcedure;
oCommand.CommandText = strQuery;
oCommand.Connection = oConnection;
oConnection.Open();
intResult = oCommand.ExecuteNonQuery();
Best Regards
In case you are using an ODBC connection, when using CommandType.StoredProcedure you must use a diferent syntax for the procedure's name. In your case:
CommandText = "{ CALL some_stored_procedure(?,?,?,?)}"
Check this link for more information: https://support.microsoft.com/en-us/kb/310130