I am converting a winforms application from MS Access to SQLServer Express.
I have some code which is used throughout the application for updating the database, I pass in the table name, ID for the entry the fields to update and the values in an array... works ok with access
The code generates an SQL statememnt, which is passed as a query along with the values as parameters... an example output is
UPDATE userVersion SET lastUpdated=?, userId=?, userName=?, version=? WHERE userId = 1299
if I try run this on sqlserver, the system crashes with this error
System.Data.SqlClient.SqlException: 'Incorrect syntax near '?'.
Incorrect syntax near '?'.'
What is the correct format for sql server?
Based on the error you are using SQLClient to execute the query, but the structure of the query looks like it may be closer to ODBC's command.
In case it helps, System.Data.ODBC.ODBCCommand uses the "?" symbol as a place holder for parameters. The order of the parameters is important in this case.
https://msdn.microsoft.com/en-us/library/system.data.odbc.odbccommand.parameters(v=vs.110).aspx
The System.Data.SQLClient.SQLCommand uses named variables (for example #MyVariable) to specify variables. In this case, order is not important as long as the names are specified correctly.
https://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlcommand.parameters(v=vs.110).aspx
ODBCCommand would look like:
UPDATE Sales.Store SET Demographics = #demographics WHERE CustomerID = ?;
While SQLCommand would look like:
UPDATE Sales.Store SET Demographics = #demographics WHERE CustomerID = #ID;
Related
This question already has answers here:
When should I use prepared statements?
(4 answers)
Closed 1 year ago.
I have code that inputs data into db using OLEDB. Let's say it looks like this
var commandText = $"INSERT into {tableName}
({columnName1}, {columnName2})
VALUES ({value1, value2});"
var command = new OleDbCommand(commandText, connection);
command.ExecuteNonQuery();
Suggestion is to use OLEDB parameters, something like this
var commandText = $"INSERT into {tableName}
([{columnName1}], [{columnName2}])
VALUES (?, ?);"
var command = new OleDbCommand(commandText, connection);
command.Parameters.Add(new OleDbParameter(columnName1, value1));
command.Parameters.Add(new OleDbParameter(columnName2, value2));
command.ExecuteNonQuery();
What are the benefits of using parameters here?
Does it really improve security if the values are validated before?
With this code, no amount of parameters can help you.
The fact that you're concatenating the table name and the columns names makes your query vulnerable to SQL Injection attacks, which is the primary (but not only) reason to use parameters.
The way SQL injection works is by replacing parts of the string sent to the database with sql code. Parameters prevent that from happening because the database treats them as placeholders for data, which means it will not run any sql code that was passed through them.
However, since your table name and column names are also c# variables, they can be replaced with SQL code that the database will try to run.
Suppose the following code:
var tableName = "table (Col1) VALUES (null);DROP TABLE table;--";
// declare and populate columnName1, columnName2 with whatever values you want here, even just nulls
var commandText = $"INSERT into {tableName}
([{columnName1}], [{columnName2}])
VALUES (?, ?);"
// run SQL command here
This will insert a single record into table, and then drop the table from the database.
For more information, read my blog post entitled Back to basics: SQL Injection
Actually, yes. We all make mistakes and the extra safety added by the parameter object is like a second set of eyes.
Also, if you always use the parameter object, you run less of a risk in introducing errors down the line.
I have the following parameterized SQL query, which inserts data into a table, gets the (automatically incremented) Id value of the new row, and then inserts that new value into another table:
DECLARE #engId_newtable TABLE(engId INT);
DECLARE #engId_new INT;
INSERT INTO eng (locationTypeId, engNumb, projectId, engTypeId, capacity, cylNo, employeeId, bore, stroke, crankOffset, rodLength, cr, crankThrow, pinOffset, engDesc)
OUTPUT INSERTED.engId INTO #engId_newtable
SELECT a.locationTypeId, #engNumb, b.projectId, c.engTypeId, #capacity, #cylNo, d.employeeId, #bore, #stroke, #crankOffset, #rodLength, #cr, #crankThrow, #pinOffset, #engDesc
FROM dbo.locationType AS a,dbo.project AS b,dbo.engType AS c,dbo.employees AS d
WHERE a.locationType = #locationType AND b.projectCode = #projectCode AND b.engineType = #engineType AND c.engType = #engType AND d.userName = #userName ;
SELECT #engId_new = engId FROM #engId_newtable;
INSERT INTO oil (engId, oilQuantity, oilTypeId)
SELECT #engId_new, #oilQuantity, a.oilTypeId
FROM dbo.oilType AS a
WHERE a.oilManufacturer = #oilManufacturer AND a.oilRange = #oilRange AND a.oilGrade = #oilGrade ;
The query works perfectly when executed in SQL Server Management Studio (SSMS), but when I try to run it using my ASP.NET Core C# (Razor Pages) project, it fails with the following error:
System.Data.SqlClient.SqlException: 'Cannot insert the value NULL into
column 'engId', table 'TestEng.dbo.oil'; column does not allow nulls.
INSERT fails. The statement has been terminated.'
So it appears that the OUTPUT INSERTED command is not working. I have also tried using SELECT #engId_new = SCOPE_IDENTITY(), and even ##IDENTITY, but they also return null and give the same error.
I have similar queries (using OUTPUT INSERTED) in other areas of my project, which work fine. This query was also working correctly until earlier today, when we changed the server the SQL database is running on - maybe I need to change some database/table settings?
Any help is much appreciated, I'm really at a loss here. Thanks.
EDIT: Showing how the query is executed
Query is built programatically - I know the query building functions work as all my other queries work fine - the query I'm trying to execute is exactly as shown here (it is returned by the query builder as a single string):
"DECLARE #engId_newtable TABLE(engId INT); DECLARE #engId_new INT; INSERT INTO eng (locationTypeId, engNumb, projectId, engTypeId, capacity, cylNo, employeeId, bore, stroke, crankOffset, rodLength, cr, crankThrow, pinOffset, engDesc) OUTPUT INSERTED.engId INTO #engId_newtable SELECT a.locationTypeId, #engNumb, b.projectId, c.engTypeId, #capacity, #cylNo, d.employeeId, #bore, #stroke, #crankOffset, #rodLength, #cr, #crankThrow, #pinOffset, #engDesc FROM dbo.locationType AS a,dbo.project AS b,dbo.engType AS c,dbo.employees AS d WHERE a.locationType = #locationType AND b.projectCode = #projectCode AND b.engineType = #engineType AND c.engType = #engType AND d.userName = #userName ;SELECT #engId_new = engId FROM #engId_newtable; INSERT INTO oil (engId, oilTypeId) SELECT #engId_new, a.oilTypeId FROM dbo.oilType AS a WHERE a.oilManufacturer = #oilManufacturer AND a.oilRange = #oilRange AND a.oilGrade = #oilGrade ;"
Query Execution function, called from razor page model, query and connection passed as parameters:
public void ExecuteVoid(SqlConnection con, string query, List<SqlColumn> columns, List<SqlFilter> filters)
{
SqlCommand cmd = new SqlCommand(query, con);
Parameterize(cmd, columns, filters);
con.Open();
cmd.ExecuteNonQuery();
con.Close();
}
The Parameterize function just adds all the relevant parameters to the query. Again, like the query builder function, I know it works because all my other queries execute as expected.
EDIT 2: SQL Server Profiler
Shown below is an image showing all the events relevant to this query that I can see in SQL Server Profiler:
All parts of the query are written out as expected, all parameters are present, but the query still fails.
I found the problem! I was using HttpContext.Session.GetString to get the value of a WHERE clause in my first query (to the eng table). I had changed the name of the string elsewhere in my code, and forgotten to change it in the query. So, the problem had nothing to do with SQL at all, really.
I can say that SQL server profiler was crucial in finding this error, so if you're having trouble with parameterized sql queries Visual C#, look over your queries there and you may highlight some unseen issues.
I have the following code:
string strTruncateTable = "TRUNCATE TABLE #TableNameTruncate";
SqlCommand truncateTable = new SqlCommand(strTruncateTable, myConnection);
truncateTable.Parameters.AddWithValue("TableNameTruncate", tbTableName.Text);
truncateTable.ExecuteNonQuery();
Whenever I run the application, I get the following error:
Incorrect syntax near '#TableNameTruncate'
How can I fix the issue?
How can I fix the issue?
By specifying the table name as part of the SQL. Table and column names can't be parameterized in most database SQL dialects, including SQL Server.
You should either perform very stringent validation on the table name before putting it into the SQL, or have a whitelisted set of valid table names, in order to avoid SQL injection attacks in the normal way.
You can only parameterized your values, not your column names or table names no matter you use DML statements or DDL statements.
And by the way, parameters are supported for Data manipulation language operations not Data Manipulation language operations.
Data manipulation language =
SELECT ... FROM ... WHERE ...
INSERT INTO ... VALUES ...
UPDATE ... SET ... WHERE ...
DELETE FROM ... WHERE ...
TRUNCATE TABLE is a Data Definition Language statement. That's why you can't use TRUNCATE TABLE with parameters even only if you try to parameter a value. You need to specify it as a part of SQL query.
You might need to take a look at the term called Dynamic SQL
As mentioned by Jon Skeet, table name cannot be parametrized for truncate operation.
To fix this issue, fully qualified query needed to be written.
So you can put a conditional check by the parameter value #TableNameTruncate and using if or switch case statement create fully qualified query then execute it.
or simply
string strTruncateTable = "TRUNCATE TABLE " + TableNameTruncate.Value;
SqlCommand truncateTable = new SqlCommand(strTruncateTable, myConnection);
truncateTable.Parameters.AddWithValue("TableNameTruncate", tbTableName.Text);
truncateTable.ExecuteNonQuery();
Does anyone know how to store a single backslash into PostgreSQL Database?
I am using C# and Nqgsql to access PostgreSQL, and my case is I want to store "1\\0\\0\\0\\1\\0" into the database, and the expected string in DB field will be "1\0\0\0\1\0", that is I only need one backslash in the db field, thus when I get the data from db, it will still be "1\\0\\0\\0\\1\\0" in memory. But my problem is when the memory string is "1\\0\\0\\0\\1\\0", the string stored into db field is also "1\\0\\0\\0\\1\\0", then when I get the data from db, the memory string will be "1\\\\0\\\\0\\\\0\\\\1\\\\0".
The variables I used in c# code is set as the following format:
var a = "1\\0\\0\\0\\1\\0";
var b = #"1\0\0\0\1\0";
when store into db, it seems that the backslashes in both variables have been doubled. How to deal with this issue?
You should avoid this entirely by using parametrized queries. Consult an example in Npgsql: User's Manual in Using parameters in a query section.
But if you really want to construct a literal query then you can use E'' syntax, like this:
var sql = #"insert into table_name (column_name) values (E'1\\0\\0\\0\\1\\0')";
This syntax is independent of server or connection configuration like standard_conforming_strings. But it is Postgres specific.
If you want your code be portable between different database engines the you can issue set standard_conforming_strings=on just after connecting. Then this works:
var sql = #"insert into table_name (column_name) values ('1\0\0\0\1\0')";
This option is turned on by default since PostgreSQL 9.1 and available since 8.2.
I had this problem as well. I was able to solve it by going in the database's config and changing "standard_conforming_strings" to OFF.
i have a problem where i can't apparently find a solution even after hours of debugging.
I have a simple SQL command where i want to update a row with some value(the value is a text of about ~5mb), after executing the SQL Command, the 'ExecuteNonQuery()' on the C# code side, returns '1' and no exception but the changes are sometime reflected in the Database row and sometime not.
I tried debugging to see if the values that will replace the old one are correct and they are. I am using MySQL 5.5.11.
Could it be a MySQL setting or something?
Losing my mind on this problem, if you have any idea it would be greatly appreciated.
EDIT, include code:
The code is as simple as this:
cmd.CommandText = "UPDATE user SET data = #data WHERE id = #id";
then i add params to the DBCommand object for the SQL Query. The 'data' is about ~5mb big.
this command always returns '1' even if the changes are not reflected in the database(sometime it works, sometime it doesnt):
cmd.ExecuteNonQuery();
Thanks in advance!
I don't know if the mysql provider uses autocommit? If not then you have to call commit on the Transaction object you can get with BeginTransaction on the connection object.
http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlcommand.parameters.aspx
The Microsoft .NET Framework Data Provider for SQL Server does not support the question mark (?) placeholder for passing parameters to a SQL Statement or a stored procedure called by a command of CommandType.Text. In this case, named parameters must be used.
For example:
SELECT * FROM Customers WHERE CustomerID = #CustomerID
Edit:
Just noticed this was MySQL, and while i can't find anything simliar about it quickly, i would suggest you use named parameters anyways
I had this problem and it was related to autocommit.
Problem: earlier in the app lifespan autocommit was set to 0 by another process in the app, and failed. The connection with autocommit turned off is then reused by the connection pool.
That will lead to this type of error at unpredictable times.