I'm currently connecting to and working with a MS Access database. I can do a generic select * query fine, so I am connected to the db, but when I try to select using parameters it throws a missing operator exception.
string selectStatement = "Select ID from pages where page_title = ? limit 1";
string title = Request.QueryString["pagetitle"];
OleDbCommand selectCommand = new OleDbCommand(selectStatement, conn);
selectCommand.Parameters.Add("#p1",OleDbType.VarChar);
selectCommand.Parameters["#p1"].Value = System.Web.HttpUtility.UrlDecode(title);
OleDbDataReader selectResult = selectCommand.ExecuteReader();
The error I get is on the ExecuteReader line:
Exception Details: System.Data.OleDb.OleDbException: Syntax error (missing operator) in query expression 'page_title = ? limit 1'.
I've tried using #p1 inside the query, as well as the current ?. I've tried adding the parameters different ways, including removing the # in the parameter name. Nothing seems to work. Can someone point me in the right direction?
AFAIK, there is no LIMIT clause in MS Access.
And, parameters should be named, #p1 in your case, instead of ?
I haven't worked with Access for years, so I might be wrong, but instead of LIMIT, try this:
Select TOP 1 ID from pages where page_title = #p1
Also, if appropriate, consider this advice:
MS Access isn't quite the right DBMS to handle websites (I suspect in your case it's a website). For an alternative file-based database management systems, check SQLite and FirebirdSQL. Both have a lot of tools you can use for GUI, like SQLite Maestro, and respectively IBExpert.
Queries are more flexible in those DBMS.
Related
I am trying to create a database using this code:
var createDatabaseQuery = "exec ('CREATE DATABASE ' + #db)";
var sqlCommand = new SqlCommand(createDatabaseQuery, sqlConnection);
sqlCommand.Parameters.Add("#db", SqlDbType.Text);
sqlCommand.Parameters["#db"].Value = "DbName";
sqlCommand.ExecuteNonQuery();
The above works perfectly but I try to do concatenation as follows, it throws an exception:
var sqlCommand = new SqlCommand(createDatabaseQuery, sqlConnection);
sqlCommand.Parameters.Add("#db", SqlDbType.Text);
sqlCommand.Parameters["#db"].Value = "DbName" + CustomId; //Doing the concatenation here
Exception:
System.Data.SqlClient.SqlException (0x80131904): Incorrect syntax near '-'
I know, there could be better ways to do it. But is there any way that I can make the above work?
Time to learn the real intricate sides of SQL.
The way you wan t to write it - is incorrect in multiple ways. DEBUG THE SQL. Do not care about the C# code, look at the SQL...
In your case - naming conversions.
Tables, databases etc. can not contains a "-" - OR they must be marked.
CREATE DATABASE my-database -> Error
CREATE DATABASE [my-database] -> correct, the [] brackets names and thus... no processing of the "-" is tried.
This is quite clear in the SQL documentation, but a part many people overlook (mostly because in most cases it does not matter). They likely wonder why generators bracket every item name (Database, schema, table, COLUMN). Well, that is the reason. What do you think "-1" means? Minus one, processing, or part of a name - the server has no way to determine this. Help him.
You need to make sure you are quoting the name correctly using QUOTENAME, because it contains characters that need escaping.
var createDatabaseQuery = "exec ('CREATE DATABASE ' + QUOTENAME(#db))";
Also, the parameter type should be nvarchar(128)
sqlCommand.Parameters.Add("#db", SqlDbType.NVarChar, 128).Value = "DbName" + CustomId;
I'm using C# with TSQL and SQL Server 2005
I'm trying to use PetaPoco to return a dataset as a list of objects. this is the code I'm using just now
var s = PetaPoco.Sql.Builder.Append("USE [BI] EXEC [dbo].[TestProcedure2];");
var result = db.Query<dynamic>(s);
var result2 = db.Query<dynamic>("USE [BI] EXEC [dbo].[TestProcedure2];");
I think the error message is a generic sql error for when petaPoco fails.
At first I was using a stored procedure with paramaters and the # character was causing a problem, once that was fixed with ## i started getting this error so I made a stored procedure with a simple select statement. The procedure executes completely fine in Management Studio.
Using PetaPoco with select statements is fine and the data is mapped both to a dynamic or an object model completely fine. I created a garbage SQL string and it returned the same error which is where I'm getting the generic error idea from.
This is the select I'm using which works fine
var dynTest =
db.Query<dynamic>(
"SELECT TOP 10 * FROM [BI].[dbo].[Managers] ORDER BY [ConsecutiveDays] desc");
Its trying to append the select clause in front of it.
If you put a ";" at the start of your query it won't try to append it.
PetaPoco assumes that you want to perform a SELECT and will infer one if you don't include one.
To avoid doing the automatic SELECT you should use:
db.EnableAutoSelect = false;
Prior to your query.
I am working with C#. I need to write a select inline query.
The table name should be taken from config. I cannot write a stored procedure.
SqlCommand myCommand= new SqlCommand();
myCommand.CommandText = "Select * from " + tableName;
myCommand.CommandType = CommandType.Text;
myCommand.Connection = connString;
How to avoid sql injection ?
Just create a query with a real param and check for the existence of the tablename - somthing like:
SELECT COUNT(*) FROM SYS.TABLES WHERE NAME = #pYOURTABLENAME
IF that returns 1 then you know that the table exists and thus can use it in the SELECT you showed in the question...
However I strongly recommend to try anything to get rid of the need for any code prone to SQL injection!
I would ensure table name contains only these characters:
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz[]. -_0123456789
E.g.,
Regex regex = new Regex(#"^[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\[\]. -_0123456789]{1,128}$");
if (!regex.IsMatch(tableName)) throw new ApplicationException("Invalid table name");
To do a more comprehensive job including non-English languages see this reference on what a valid table names:
http://msdn.microsoft.com/en-us/library/ms175874.aspx
You need to verify that tableName is appropriate. After some sanity checking (making sure it has no spaces, or other disallowed characters for table names, etc), I would then first query the database for the names of all tables, and programmatically verify that it is one of those table names. Then proceed to run the query you show.
I'd look at moving the SQL to a stored proc and review this article by Erland Sommarskog as it has some great ideas for using dynamic SQL within stored procs. I'd certainly look into it. It discusses a lot of the issues around SQL injection and possible alternatives to dynamic SQL.
He also has another great article on ways to use arrays in stored procs. I know you didn't ask for that, but I often refer to these two articles as I think they are quite insightful and provide you with some useful ideas with regards to writing your procedures.
In addition to some of the suggestions linked above, I still have some basic parameter sanitisation mechanisms that I use if I am ever using dynamic SQL. An example of this is as follows;
IF LEN(#TableName) < 5 OR LEN(#TableDisplayName) < 5
BEGIN
RAISERROR('Please ensure table name and display name are at least 5 characters long', 16, 1)
END
IF NOT (#TableName not like '%[^A-Z]%')
BEGIN
RAISERROR('The TableName can only contain letters', 16, 1)
END
IF NOT (#TableDisplayName not like '%[^0-9A-Z ]%')
BEGIN
RAISERROR('The TableDisplayName can only contain letters, numbers or spaces', 16, 1)
END
This combined with using parameters within your dynamic sql and then executing using sp_executesql certainly help to minimise the possibility of a SQL injection attack.
Is there a way to see final query which is passed to SQL Server database from my C# app ?
For ex I got query:
SELECT * FROM mytable WHERE x = #yyyy;
This creates and SQLCommand object
SqlCommand cmd = new SqlCommand("SELECT * FROM mytable WHERE x = #yyyy");
Plus I need to pass parameter:
cmd.Parameters.Add("#yyyy","MyValue");
What I want to see (in debug in C# or somewhere in SQL Server Management Studio) is this:
SELECT * FROM mytable WHERE x = MyValue
Where can I find such query ?!
Best regards
Where can I find such query ?!
You can't. Such a query never exists. The values are not substituted into the SQL.
I think actually sp_executesql is called, and this function accepts the parameters separately from the SQL. You can check this using SQL Profiler to see the actual SQL.
Update:
ORDER BY #descOrAsc
Your problem is that parameters can only be used in certain places where expressions are allowed. DESC is not an expression - it is a reserved word. You cannot use a parameter containing the string "DESC" instead of writing the keyword DESC in the query.
Also, you haven't specified which column to order by.
You can run the SQL Server Profiler and see all the queries that get executed, to see whats happening (and copy paste these into the Sql Server Management Studio to do tests etc)
I would expect the query to be passed to SQL Server with the parameters. There should be no need for anything to ever create a full SQL-only query. It makes no sense to do so, as it just means more conversions for either the client, the server or both. On the server side, the query processor is going to want to parse the query into clauses with values - if the command can pass those values directly, where's the advantage on converting them into the SQL statement, only to have the server parse them into separate values again?
1.You can use SQL Profiler. (here you can see all process)
2.You can write all your queries to SQL Server table. And then you can always get queries from this table.
I have a problem when I try to read rows from SQL Server 2005 from code in C#
The idea:
In my database (SQL Server 2005 Express) there is a table with a column (of datatype ntext) containing HTML code.
In my C# application user can enter a sentence (HTML code) and search the rows with contains this sentence.
The query generated from my app is:
USE test
SELECT
al.aal_Id As ID,
al.aal_Description As Opis,
au.au_Title As Tytul_szablonu,
au.au_Note As Nazwa_szablonu
FROM dbo.au_Allegro al
LEFT OUTER JOIN dbo.au__Auction au ON (al.aal_AuctionId = au.au_Id)
WHERE
au.au_Type = 11
AND al.aal_Description COLLATE SQL_Latin1_General_CP1_CS_AS LIKE '%%' ESCAPE '\'
In my App I'm converting special characters (e.g. ',) and adding escape character.
User tries to search for very long sentence (about 7000+ chars), when he tries to do this the sqlserver.exe process consumes all of his RAM memory and search time is about 30+ minutes (he has about 1000+ rows in this table).
The query returns 0 rows.
When he tries to run (this same) query in SQL Server Management Studio the database shows results in few seconds (with rows).
In my app I use SqlDataAdapter:
System.Data.DataTable dt = new System.Data.DataTable();
System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand();
cmd.CommandTimeout = 0;
cmd.Connection = conn;
System.Data.SqlClient.SqlDataAdapter da = new System.Data.SqlClient.SqlDataAdapter(kwerenda, conn);
try
{
da.Fill(dt);
}
I tried SqlDataReader:
dr = cmd.ExecuteReader();
while (dr.Read())
{
string id = dr["ID"].ToString();
string opis = dr["Opis"].ToString();
string tytul = dr["Tytul_szablonu"].ToString();
string nazwa = dr["Nazwa_szablonu"].ToString();
dt.Rows.Add(id, opis, tytul, nazwa);
}
When I tried to simulate this in my test database I don't have any problems with search (this same) sentences.
Have you got any tips for me ?
I can't do any changes in user datatable, i can't go to him and check what happens.
Is the SQL command executing a stored procedure? If so you might be getting different query plans, which may explain the timing difference between the apps. Your ADO.Net call might be affected by something known as parameter sniffing, which can cause radically different query execution times.
There are a couple of things you can do to avoid this problem and yield consistent results.
Convert parameters to local variables inside of the stored procedure.
Disable the feature on the SQL server altogether.
Also your syntax looks suspect as John pointed out. It would be better to use a NVARCHAR(MAX) datatype for that column if possible NTEXT should be avoided as its been deprecated.
A better alternative to doing like searches on a non-indexed column like this is to utilize the SQL's Full Text Search which is optimized for these types of queries.
http://msdn.microsoft.com/en-us/library/ms142571.aspx
http://www.developer.com/article.php/3446891
A couple of things you might want to do.
First, don't use nText. SQL 2005 has a datatype called nvarchar(max). It's MUCH better for storing large amounts of text. Further, ntext was deprecated so save yourself some trouble and convert it now. See this link on how to successfully do this.
Second, the query you posted is unusual. You have a left outer join, but you have a where clause on the outer joined table. Because of the where clause it's being converted (hopefully) into an inner join. You should just write it that way OR move the au.au_type = 11 to be part of the join construct. I doubt you want the latter.
Third, when the client runs the query the first time through your app it is generating a query plan based on those parameters. Running the exact same query shortly thereafter in Management Studio is going to reuse that plan and cached data. Therefore the second pass will be fast so no surprise there.
Fourth, I don't think you posted the actual query that was run. I suspect there is some data in the parameter you are comparing which either isn't escaping properly OR is using one of the reserved characters such as '[', ']', ^, etc.