views:

647

answers:

4

I'm trying to parameterise a search query that uses the LIKE keyword with a wildcard. The original sql has dynamic sql like this:

"AND JOB_POSTCODE LIKE '" + isPostCode + "%' "

So I've tried this instead, but I get a FormatException:

"AND JOB_POSTCODE LIKE @postcode + '%' "

Edit: I guess the FormatException isn't going to be coming from Sql Server CE, so as requested, here is how I set the parameter in my C# code. The parameter is set in code like this:

command.Parameters.Add("@postcode", SqlDbType.NVarChar).Value = isPostCode;

I also tried:

"AND JOB_POSTCODE LIKE @postcode"

with

command.Parameters.Add("@postcode", SqlDbType.NVarChar).Value = isPostCode + "%";

but that doesn't return any results. Can anyone advise how to use parameters in this search sql?

+1  A: 

Using:

"AND JOB_POSTCODE LIKE '" + isPostCode + "%' "

...means that the string is constructed before being tacked onto the dynamic SQL. This is so that you don't have to specify the parameter in the parameter list for sp_executesql/EXEC, while this:

"AND JOB_POSTCODE LIKE @postcode + '%' "

...does. Please post more of the query.

OMG Ponies
The dynamic sql works but I want to use a parameter to protect against sql injection, and I can't get that to work
Colin
+1  A: 

Please post your complete example (including the outer client code where you are assembling your call). Both your second and third options should work if you are passing the parameter correctly. Are you calling this in a stored procedure or inline parameterized SQL?

I assume no SPs since I just see you are using CE...

I think you need to add a length to your .Add call since it's an nvarchar.

Cade Roux
You're right, no SP's. It's inline parameterized sql. I've edited the question to add the line where I add the parameter to the command. Could the SqlDbType.NVarChar be the problem?
Colin
Cade, I tried adding length and found it made no difference, but during more testing I found that the third option WAS working. My apologies. Please see the answer I posted for all the details. I'm curious about why the second option didn't work.........
Colin
+2  A: 

This returns appropriate results in SQL Server 05 (also works wrapped in a SP), so it seems like the last thing you tried should have worked. But I don't have a test bed for Compact Edition, so maybe that makes a difference (I'd be curious to see if that's so, and why).

declare @p1 nvarchar(50)
set @p1 = 'f'         -- initial value passed from your app
set @p1 = @p1 + '%'   -- edit value for use with LIKE
select * from JOB
where JOB_POSTCODE like @p1

EDIT:

What version of SQLCE are you using? Can you tell if your parameter values are actually being passed from your code to the DB? I skimmed through this MSDN tutorial and was able to get the results you're looking for, at least from the Visual Studio Query Designer. (only difference is that I'm using VS 2008 and SQL Server Compact 3.5). See the section titled "Creating a new query"; I mocked up a table with some data and this query worked as you intend.

SELECT     JobID, PostCode, OtherValue
FROM         Job
WHERE     (PostCode LIKE @p1 + '%')

Like I said, I didn't write any code to call the query, but it worked from within the designer. In other words, "it works on my machine".

Matt
Sql Server CE doesn't permit named parameters, and the declare keyword doesn't exist, so I can't use your sql. I don't know how to assign an unnamed parameter in Management Studio. I was trying this:SELECT * FROM JOB WHERE JOB_POSTCODE LIKE ? + '%', 'G20'but the syntax is incorrect
Colin
@Colin, I think I learned more from your comment than you did from my answer ;) - maybe the edit helps?
Matt
Matt,Thanks for the link, now I'll be able to test parameterised queries outside my code (I've been trying to do it in Management Studio rather than Server Explorer). I don't think the error is coming from SqlServerCE, I think it's coming from the .NET Compact Framework Data Provider - see the answer I've posted for the error text. For the record I'm using VS2005 and Sql Server Compact 3.5
Colin
+1  A: 

I went back and stripped my code down to the essentials so that I could post it here, and while doing that I discovered that the last method I tried in my original question does actually work. Must have been something wrong in my testing. So here's a summary, with full code that's been run:

Original dynamic sql, vulnerable to sql injection:

//Dynamic sql works, returns 2 results as expected, but I want to use parameters to protect against sql injection

string postCode = "G20";
sqlCommand.CommandText = "SELECT * FROM JOB WHERE JOB_POSTCODE LIKE '" + postCode + "%'";
return Database.fGetDataSet(sqlCommand, iiStartRecord, iiMaxRecords, "JOBVISIT");

First attempt to use parameter gives an error:

//This syntax with a parameter gives me an error (note that I've added the NVarChar length as suggested:
//System.FormatException : @postcode : G20 - Input string was not in a correct format.
//at System.Data.SqlServerCe.SqlCeCommand.FillParameterDataBindings()
//at System.Data.SqlServerCe.SqlCeCommand.ExecuteCommandText(IntPtr& pCursor, Boolean& isBaseTableCursor)

string postCode = "G20";
sqlCommand.CommandText = "SELECT * FROM JOB WHERE JOB_POSTCODE LIKE @postcode + '%'";
sqlCommand.Parameters.Add("@postcode", SqlDbType.NVarChar, 10).Value = postCode;
return Database.fGetDataSet(sqlCommand, iiStartRecord, iiMaxRecords, "JOBVISIT");

Second technique does actually work:

///This syntax with a parameter works, returns 2 results as expected
string postCode = "G20";
sqlCommand.CommandText = "SELECT * FROM JOB WHERE JOB_POSTCODE LIKE @postcode";
sqlCommand.Parameters.Add("@postcode", SqlDbType.NVarChar).Value = postCode + "%";
return Database.fGetDataSet(sqlCommand, iiStartRecord, iiMaxRecords, "JOBVISIT");

Thanks for all the input, and sorry about the original misleading question...

Colin
SQLCE (or, more likely, the provider) must have a problem with the inline expression - that might be why the provider throws the error. I don't have a testbed for SQLCE and didn't even notice this was really a SQL CE question until I had already posted my first answer :-(
Cade Roux
Cade, Thank-you for your input. It helped me persevere with my code and testing, and helped me move towards the code rather than the sql.
Colin