I'm trying to add a new column to a table in my CE database using C# code.
This SQL works in SSMS to add to a standard SQL database table:
IF NOT EXISTS(SELECT * FROM sys.columns WHERE Name = N'sent' AND Object_ID = Object_ID(N'QAReports')) BEGIN
ALTER TABLE QAReports ADD [Sent] bit NULL;
END
But when I try to run the same sql in C# I get an error:
There was an error parsing the query. [ Token line number = 1,Token line offset = 1,Token in error = IF ]
My code that I'm using to execute the SQL above is:
bool retVal = true;
try
{
using (var connection = new SqlCeConnection(ConnString))
{
connection.Open();
using (var command = connection.CreateCommand())
{
command.CommandText = sql;
command.CommandType = CommandType.Text;
command.ExecuteNonQuery();
}
connection.Close();
}
}
catch (Exception ex)
{
retVal = false;
}
return retVal;
Is there a way to do what I want to do.
Is there a better way. I'm trying to upgrade a database on an end-users installation if they need it. I check a value in the database that tells me what app version was last used on it. Then I want to run the SQL to add the required fields and then update the value in the database for the app version.
Related
An SQL query that I'm executing from my application is returning different results than SQL Management Studio, specifically missing entire rows of data.
I've tried stripping the query way down to just "SELECT *" from the relevant table with a single WHERE clause, this achieved the same result of the C# version missing the same row each time.
A stripped down SQL query (that still has the issue) looks like this
SELECT Token, Last_update, repeatno, Maxrepeatno, Dispwindowstart
FROM v_eps_prescriptions
WHERE Token='F69F4D-C82043-70379I'
The C# version is
SqlCommand command = new SqlCommand(
$#"SELECT Token, Last_update, messages, repeatno, Maxrepeatno
FROM v_eps_prescriptions
WHERE Token='{UUID}'",
conn);
The SQL version for this query will return 2 rows, C# will only return 1 row.
I've been putting the data into a dataGridView to debug which is where I'm seeing just the single row.
Edit:
As requested the full chunk of C# that performs the query and what outputs to a datagrid (which is temporary for debugging)
try
{
conn.ConnectionString = $"Data Source=[source];Initial Catalog=[Cat];Integrated Security=True";
conn.Open();
foreach (string UUID in ValidUUIDList)
{
try
{
DateTime dt = DateTime.Now.AddDays(1);
DateTime dtpast = dt.AddMonths(-6);
SqlCommand command = new SqlCommand(string.Format($#"SELECT Token, Last_update, messages, repeatno, Maxrepeatno
FROM [Table]
WHERE Token='{UUID}'
AND Dispwindowstart
BETWEEN '{dtpast.ToString("yyyy - MM - dd")} 00:00:00.000'
AND '{dt.ToString("yyyy-MM-dd")} 00:00:00.000'
OR Token='{UUID}'
AND Dispwindowstart IS NULL"),
conn);
using (SqlDataReader dataReader = command.ExecuteReader())
{
if (dataReader.Read())
{
DataTable dataTable = new DataTable();
dataTable.Load(dataReader);
dataGridView1.DataSource = dataTable;
}
}
}
catch (Exception err)
{
MessageBox.Show($"An error occured while processing UUID {UUID}. \n\n{err.Message}");
}
}
}
catch (Exception err)
{
MessageBox.Show($"An error occured while connecting to the Nexphase database. \n\n{err.Message}");
}
I am executing a dynamically generated MySQL query using C# code. An exception gets thrown:
CREATE TABLE dump ("#employee_OID" VARCHAR(50));
"{"You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '\"#employee_OID\" VARCHAR(50))' at line 1"}"
I cannot skip the '#' symbol from the Column Name.
Manually, using MySQL Workbench, I can get it executed after executing the following query.
SET sql_mode='ANSI_QUOTES';
Following is the code I am able to produce:
MySqlConnection conn = null;
MySqlCommand cmd = null;
string mySQLConnectionString = ConfigurationManager.AppSettings["MySQLAutomationServerConnectionString"];
//Dynamically getting generated using some other code
string sqlQueryString = "CREATE TABLE dump ("#employee_OID" VARCHAR(50));";
try
{
conn = new MySqlConnection(mySQLConnectionString);
conn.Open();
cmd = new MySqlCommand(sqlQueryString, conn);
executionResultStatus = cmd.ExecuteNonQuery();
}
catch (MySqlException ex)
{
Console.WriteLine("MySQL Exception: " + ex.Message.ToString());
}
I have tried to execute the "SET sql_mode='ANSI_QUOTES';" query before this gets executed using the code right before executing this code, its not working. What shall I do?
Change your command to
string sqlQueryString = "CREATE TABLE dump (`#employee_OID` VARCHAR(50));";
Notice how there are two backticks before and after the problematic name (ALT+096)
This will allow your engine to ignore the character # used to identify parameters
I have created an ASP.Net C# application to run the SQL server (MSSQL) queries.
The application reads all the user input queries in the text box provided and using the TSql110Parser, it will break down to individual SQL statements.
Its running fine in almost all the cases except when the SQL statements are like the below
DECLARE #user VARCHAR(50)
SET #user = 'ABC'
PRINT #user
SELECT * FROM user_table WHERE username = #user
The execution stops at line 2 and error from SQL server saying that
Must declare the scalar variable "#user"
even though its defined in the first line.
Then I figured out the below way to run. Adding a BEGIN and END statements.
BEGIN
DECLARE #user VARCHAR(50)
SET #user = 'ABC'
PRINT #user
SELECT * FROM user_table WHERE username = #user
END
But still, then there is a limitation that we won't be able to return the results from the SELECT query.
C# code snippet is below
protected void btnQuery_Click(object sender, EventArgs e)
{
if (qry.Length > 0)
{
using (sqlCon = new SqlConnection())
{
dbConnString = dbConnString + "database=" + ddlDBNames.SelectedValue + ";";
sqlCon.ConnectionString = dbConnString;
sqlCon.Open();
cmd = new SqlCommand();
cmd.Connection = sqlCon;
IList<ParseError> Errors;
var parser = new TSql110Parser(false);
var script = parser.Parse(new StringReader(qry), out Errors) as TSqlScript;
if (Errors.Count > 0)
{
lblErrorMessage.Text = "***** Error: No statements executed *****";
}
else
{
foreach (var ts in script.Batches)
{
foreach (var st in ts.Statements)
{
q = qry.Substring(st.StartOffset, st.FragmentLength);
ExecStatement(st, q);
}
}
}
}
}
}
protected void ExecStatement(TSqlStatement statement, string qry)
{
cmd.CommandText = qry;
if (statement is SelectStatement)
{
SqlDataReader dr = cmd.ExecuteReader();
//code to populate the tabular result
}
else
{
cmd.ExecuteNonQuery();
//code to show the non query execution result
}
}
Is there any possible way i can run the SQL queries with persistent connection to DB server so that the declaration in the first line will be able to use through out the queries?
The application screenshot below.
Use CONTEXT_INFO. It is the connection specific global variable.
Its usage is not simple since it is just a 128 bit value. To set it, run the following code (N = the int you want to store connectionwise)
DECLARE #BinVar binary(128);
SET #BinVar = cast(N as binary(128));
set context_info #BinVar
You can get the N in subsequent queries by calling the context_info() function. You should convert it with something like this.
convert(int, context_info())
Why do I get an exception when trying to truncate a MySQL table (using MySQL Connector/Net)? I am trying to give the table name with a parameter.
This is the code I'm executing:
var connectionString = "Server="+_server+";Uid="+_user+";Pwd="+_password+";Database="+_database+";";
try
{
using (var conn = new MySqlConnection(connectionString))
{
conn.Open();
const string sql = "TRUNCATE TABLE #tablename"; // also tried with TRUNCATE #tablename
var cmd = new MySqlCommand(sql, conn);
cmd.Parameters.AddWithValue("#tablename", "test");
cmd.ExecuteNonQuery();
conn.Close();
}
}
catch (MySqlException ex)
{
Console.WriteLine(ex.ToString());
}
And this is the execption:
MySql.Data.MySqlClient.MySqlException (0x80004005): You have an error
in your SQ L syntax; check the manual that corresponds to your MySQL
server version for the right syntax to use near ''test'' at line 1
When I try a select query, for example, then I don't have any problems. This runs fine and returns correct data:
conn.Open();
const string sql = "SELECT body FROM test WHERE id=#pid";
var cmd = new MySqlCommand(sql, conn);
cmd.Parameters.AddWithValue("#pid", 1);
cmd.ExecuteScalar();
conn.Close();
Parameters are used for query values, not object names like tables.
So this will not work for sure.
You need to set the table name in the command string by using string concatenation. You can avoid sql injection attacks by manually checking for weird characters in the table name (spaces, dashes, semicolons, etc..)
I've been playing around with this for a while now, and i can't seem to get it to work either. I can't find any documentation online, so i'm starting to think you may not be able to truncate with a parameter like you've tried.
However, is there really a need to prevent SQL injection on this command? Does the user enter the name of the table they want to truncate, and if so, they're just going to truncate a table which...is essentially what the command does anyway?
Background: I am rewriting my ASP.NET application - currently it uses MS SQL database but I need to support also MySQL (both in the same time!).
Most of work is done - I used MySQL Connector/Net for work with MySQL database from C# (Visual Studio 2010) - but I have troubles with certain SQL queries. This is SQL query I need to execute:
"SELECT #username=username FROM t_Users WHERE id=#id"
Here is my code:
public static int ExecuteSqlNonQuery(string i_szQuery)
{
bool bConnectionWasOpen = false;
AbstractConnection dbConnection = CMSSQLInstanceCreator.CreateConnection();
if(dbConnection.IsMySQL())
{
MySqlConnection aSqlConnection = dbConnection.GetMysConnection();
try
{
if (aSqlConnection.State == System.Data.ConnectionState.Closed)
aSqlConnection.Open();
else
if (aSqlConnection.State == System.Data.ConnectionState.Open)
bConnectionWasOpen = true;
else
throw new ApplicationException("Connection not available!");
List<MySqlParameter> aParameters1 = new List<MySqlParameter>();
aParameters1.Add(new MySqlParameter("#username", MySqlDbType.VarString, 128));
aParameters1.Add(new MySqlParameter("#id", MySqlDbType.Int32));
aParameters1[0].Direction = System.Data.ParameterDirection.Output;
aParameters1[1].Direction = System.Data.ParameterDirection.Input;
aParameters1[1].Value = (int)1;
MySqlCommand aSqlCommand = new MySqlCommand(i_szQuery, aSqlConnection);
aSqlCommand.CommandType = System.Data.CommandType.Text;
aSqlCommand.CommandTimeout = 0;
aSqlCommand.Parameters.Clear();
aSqlCommand.Parameters.AddRange(aParameters1.ToArray());
int iResult = aSqlCommand.ExecuteNonQuery();
if(iResult <= 0)
Debug.WriteLine("aResult <= 0: " + i_szQuery);
return iResult;
}
catch (Exception ex)
{
throw new ApplicationException("Cannot execute query!\nReason: '" + ex.Message + "'", ex);
}
finally
{
if (!bConnectionWasOpen && aSqlConnection.State == System.Data.ConnectionState.Open)
aSqlConnection.Close();
}
}
else
{
//... almost the same for MS SQL
}
}
The problem is that the Output parameter #username (System.Data.ParameterDirection.Output;) is not filled with the value from query.
If I use other query - e.g.
UPDATE t_Users SET password=#new_password WHERE (password=#old_password AND id=#user)
Everything is fine.
I cannot return scalar as there are many other queries like
SELECT #username=username, #is_blocked=is_blocked, #full_name=full_name, #must_change_pwd=must_change_pwd ...
returning many values and I do not want to rewrite most of code.
It looks like there is problem only in MySQL because the same code works with MS SQL fine.
What should I use to force MySqlParameter to load the value from query?
You should be able to read the value of the output like this
aSqlCommand.Parameters["#username"].Value
It apparently is a shortcoming in the MySql .Net connector, see #75267. Tested it with connector v6.9.7 and MySql server 5.5.45. It is still broken and the bug report - of december 2014 - is still open. Output parameters work for stored procedures, with a command type StoredProcedure, and do not work for a SELECT statement that assigns output parameters as part of the select; command type Text.
2023-02-16 Update. A couple of weeks ago it is fixed in version 8.0.32. I tested it by updating Connector/NET to 8.0.32, and by using NuGet package MySql.Data 8.0.32.
A command of type text, an output parameter and an ExecuteNonQuery now works for the following case:
SET #valNum:=(SELECT ValueNumber FROM `sky.application` WHERE Name='Agents')
Value #valNum can then be retrieved through the output parameter.
Note that retrieving two values does not work as follows, despite it does the job in the Workbench:
SELECT #valNum:=ValueNumber, #instNum:=InstanceNumber FROM `sky.application` WHERE Name='Agents'
Error: Parameter 'valNum:=ValueNumber' not found in the collection.
Same error if retrieving one value.
Fortunately the following syntax works:
SELECT ValueNumber, InstanceNumber INTO #valNum, #instNum FROM `sky.application` WHERE Name='Agents'