I am getting a Fatal Error on using a ExecuteNonQuery(). I'm new to working with sql and as such im not sure why this SET
command is causing a problem.
I'm using MySql 5.5.17, and I'm using C# .Net Framework 3.5 in the VS2010 IDE.
Exception Message = Fatal error encountered during command execution. The Error Line = SET @oldguid = 250006;
the content from the sql file im using is as follows minus the "comments" that i removed:
DELETE FROM `disables` WHERE `sourceType`=0 AND `entry`=61904;
INSERT INTO `disables` (`sourceType`, `entry`, `flags`, `comment`) VALUES(0, 61904, 8, 'Magma Totem TEST - can crash client by spawning too many totems');
SET @oldguid = 250006;
SET @newguid = 202602;
UPDATE `creature` SET `guid`=@newguid WHERE `guid`=@oldguid;
UPDATE `creature_addon` SET `guid`=@newguid, `path_id`=@newguid*100 WHERE `guid`=@oldguid;
UPDATE `waypoint_data` SET `id`=@newguid*100 WHERE `id`=@oldguid*100;
UPDATE `areatrigger_teleport` SET `target_orientation`=2.255664 WHERE `id`=4386;
UPDATE `gameobject` SET `spawnMask`=3 WHERE `guid`=22674;
the guid
column is a unsigned int(10)
the C# code I am using to process this .sql file is as follows:
filename = lstBox_SqlFiles.SelectedItem.ToString();
mysql = new MySqlConnection(connection + Database);
string line;
OpenDatabase();
using (StreamReader reader = new StreamReader(filename))
{
StringBuilder parsedLine = new StringBuilder();
int count = 0;
while ((line = reader.ReadLine()) != null)
{
if (line.Length > 0 && !line.StartsWith("--"))
{
if (line.EndsWith(";"))
{
if (parsedLine.Length > 0)
line = parsedLine.ToString() + line;
try
{
count++;
lbl_LineQuery.Text = line;
lbl_QueryCount.Text = String.Format("Count: {0}", count);
MySqlCommand cmd = new MySqlCommand(line, mysql);
cmd.ExecuteNonQuery();
}
catch (MySqlException ex)
{
string msg = String.Format("Source FileName: SqlUpdater.cs\nSql FileName: {0}\nError Line: {1}\nException Message: {2}\n", filename, line, ex.Message);
MessageBox.Show("cmd.ExecuteNonQuery() Error!\n" + msg, "MySql Error", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
return;
}
sbClear(parsedLine);
}
else
{
parsedLine.Append(line);
continue;
}
}
else
continue;
}
}
Can anyone see a problem with my code? Is there some special manipulation of the "SET @var" string that I need to do?
Any Help is appreciated Thanks in advance
roadmaster
This is a problem I discovered when upgrading MySql.Data.dll from 1.0 to 6.9. For example:
MYSQL:
SET @foo = 'foo'
Message: Fatal error encountered during command execution.
I suspect the MySql.Data is trying to interperate the @foo as a prepared statement variable, and wants me to populate it. On pain of death. The solution therefore seem to be to tell MySql.Data that this is a literal '@' and not a token.
There may be other ways, but the pragmatic solution I have found is to quote the variable name in back-quotes:
SET @`foo` = 'foo'
SELECT @`foo`
I hope this helps.
添加;Allow User Variables=True
到连接字符串。
Андрей's suggestion worked for me.
I have a rather complex procedure in my MySQL database which I dont want to include in my C# code. Here is how I do it:
//Open connection
string conString = "server=myserver; Uid=myusername; database=myscheme; Pwd=mypwd";
MySqlConnection con = new MySqlConnection(conString);
try
{
//Set first variable, @START
string sql = "SET @START = '" + date1 + "'";
MySqlScript cmd = new MySqlScript(con, sql);
cmd.Connection.Open();
cmd.Execute();
//Set second variable, @END
sql = "SET @END = '" + date2 + "'";
cmd = new MySqlScript(con, sql);
cmd.Execute();
//Send procedure call
MySqlDataAdapter MyDA = new MySqlDataAdapter();
sql = "call MY_DB_PROCEDURE";
MyDA.SelectCommand = new MySqlCommand(sql, con);
//From here you can process the DB response as you want
//For instance, display the results in a datagridview
DataTable table = new DataTable();
MyDA.Fill(table);
BindingSource bSource = new BindingSource();
bSource.DataSource = table;
//"dataGridView1" is already placed in the active form
dataGridView1.DataSource = bSource;
dataGridView1.Visible = true;
}
catch (Exception e)
{
//Error handling procedure
}
finally
{
if (con.State == ConnectionState.Open)
{
con.Dispose(); // return connection to the pool
}
}
A more elegant solution is to add "Allow User Variables=True" to the connection string. Example as follows:
//Open connection
string conString = "server=myserver; Uid=myusername; database=myscheme; Pwd=mypwd; Allow User Variables=True";
MySqlConnection con = new MySqlConnection(conString);
try
{
//Open connection
con.Open();
//Set first variable, @START
//Set second variable, @END
//Send procedure call
string sql = "SET @START = '" + date1 + "';" +
"SET @END = '" + date2 + "';" +
"CALL MY_DB_PROCEDURE";
MySqlDataAdapter MyDA = new MySqlDataAdapter();
MyDA.SelectCommand = new MySqlCommand(sql, con);
//From here you can process the DB response as you like
//...
}
catch (Exception e)
{
//Error handling procedure
}
finally
{
if (con.State == ConnectionState.Open)
{
con.Dispose(); // return connection to the pool
}
}
Actually, I don't think that you can pass this line SET @oldguid = 250006;
into a mysqlcommand object (actually I don't know). What you should do is have your program put these values in a local variable, and then replace the parameter in your update queries.
Find a way to mix your code and this one:
// This line should be outside the While loop
Dictionary<string, string> variables = new Dictionary<string, string>();
if (line.Trim().ToUpper().StartsWith("SET"))
{
List<string> commandLine;
commandLine = line.Trim(' ',';').Split().Distinct().ToList();
commandLine.Remove(string.Empty);
// After next line, the 'variables' dictionary contains the name
// of the variable you want to set, and its value
variables[commandLine[1]] = commandLine[3];
// ...
// Do something here (try catch, chatever, but NO MySqlCommand)
// ...
}
else
{
// If the line contains any of the variables you previously set,
// i will be the index of this variable, -1 otherwise
int i = line.ContainsAnyOfAt(variables.Keys);
while(i>=0)
{
// Here we replace the parameter by its value, for example:
// UPDATE `creature` SET `guid`=@newguid WHERE `guid`=@oldguid;
// becomes (after all loops):
// UPDATE `creature` SET `guid`=202602 WHERE `guid`=250006;
line = line.Replace(variables.Keys.ElementAt(i), variables.Values.ElementAt(i));
i = line.ContainsAnyOfAt(variables.Keys,i+1);
}
// ...
// This is where you should put the code of MySqlCommand
// ...
}
And here is the extension method ContainsAnyOfAt :
public static int ContainsAnyOfAt<T>(this global::System.String source, IEnumerable<T> values, int startIndex = 0)
{
if (source == null) throw new ArgumentNullException("source");
for (int i = startIndex ; i < values.Count(); i++)
{
if (source.Contains(values.ElementAt(i).ToString()))
{
return i;
}
}
return -1;
}
Please give it a try and give feedback. Greetings
The code basically does this:
MySqlCommand
(thereby creating its own scope!) @oldguid
hasn't been declared. If you want to be able to use variables, use one MySqlCommand object, and call ExecNonQuery()
once.
Your best bet is to create a stored procedure. Perhaps it'll need 2 parameters for your "guid"/integer values.
The reason it works in SQLYog is that all those statements are running in the same context, rather than in different sessions.
Wrote procedures containing variables (@ name_var). An exception was thrown. Helped change the class MySqlCommand class MySqlScript
add connection string ; Allow User Variables=True
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.