views:

6205

answers:

8

I have an international company that has recently been added, which is named "BLA "BLAHBLAH" Ltd. (The double quotes are part of the name. )

Whenever a user tries to search for this company, by entering "Blah, or something to that affect, the search fails with a syntax error in SQL server.

How can I escape this so the search will not fail?

Sample SQL:

SELECT c.companyID, c.companyName, c.dateAdded, count(cm.maxID) as NumDirect
    FROM RussoundGeneral.dbo.Company c  
         LEFT JOIN RussoundGeneral.dbo.CompanyMax cm
                ON (cm.companyId = c.companyId and cm.maxID is not null)  
    WHERE CONTAINS ( companyName,  '"BLAH*' )
    GROUP BY c.companyID, c.companyName, c.dateAdded  
    ORDER BY c.companyName ASC
+3  A: 

I strongly suspect you're building the SQL dynamically - e.g.

// Bad code, do not use!
string sql = "SELECT * FROM Foo WHERE X LIKE '" + input + "%'";

That's a really, really bad idea for many reasons - most notably SQL injection attacks. Use parameterised SQL statements instead, where you specify the parameters separately.

Look at various answers to questions with the sql-injection tag for examples of how to do this properly.

Jon Skeet
Sorry, but no. concatinated sql will get you verbaly beaten around here..... by me. I won't tollerate them.
Russ
+5  A: 

Use a parameterized query and all your quoting woes will be gone.

Edit: If you're not letting them enter more than one word in the CONTAINS, sanitize the parameter by removing the quotes. Sanitizing the input by removing the quotes may work anyhow, regardless of the multi-word search.

Robert C. Barth
+2  A: 

Unfortunately, double-quotes have special meaning inside FTI, so even if you parameterize it, the FTI engine treats it as a phrase delimiter. I am not sure there is an easy way to include double-quotes in an FTI search. Brackets are also a special character, but can be encased in quotes to treat as a query term - but not AFAIK double-quotes.

Update

A bit of searching suggests that doubling the quote to "" may fix it - worth a try. Personally, I'd do this inside the DB, since this is a TSQL implementation detail.

Likewise, ' needs to be doubled to '' before passing to FTI (completely separate to TSQL escaping),

Marc Gravell
String operations in T-SQL are unbelievably slow. If the query gets called a lot, he's better off fixing the quotes outside the database, right before the call.
Robert C. Barth
Doubling the quote ("") doesn't work.
Richard Davies
A: 

have you tried substituting the character with it's ASCII code?

HLGEM
A: 

Try Using the escape keyword:

SELECT c.companyID, c.companyName, c.dateAdded, count(cm.maxID) as NumDirect 
FROM RussoundGeneral.dbo.Company c          
LEFT JOIN RussoundGeneral.dbo.CompanyMax cm 
ON (cm.companyId = c.companyId and cm.maxID is not null )  
WHERE CONTAINS ( companyName,  '\"BLAH*' ) escape '\'
group by c.companyID, c.companyName, c.dateAdded  ORDER BY c.companyName ASC
A: 

should be something like

string sqlCommand = "SELECT c.companyID, c.companyName, c.dateAdded, count(cm.maxID) as NumDirect FROM RussoundGeneral.dbo.Company c LEFT JOIN RussoundGeneral.dbo.CompanyMax cm ON (cm.companyId = c.companyId and cm.maxID is not null ) WHERE CONTAINS ( companyName,  '@strVal' ) group by c.companyID, c.companyName, c.dateAdded ORDER BY c.companyName ASC"
SqlCommand command = new SqlCommand(strSQLCommand, conn); 
SqlCommand.Parameters.AddWithValue("@strval", SearchTextBox.Text); 
Russ Bradberry
+1  A: 

This is a bit of a theoretical answer, but maybe it will help. The short version is "use parameters in the query", but it helps to understand the full details.

In standard SQL, strings are enclosed in single quotes, and embedded single quotes are represented by two single quotes in a row:

SELECT * FROM SomeWhere
    WHERE SomeThing = 'He said, "Don''t do it!"';

In some dialects of SQL, you can instead close strings in double quotes; you then need to double the double quotes to embed a single instance of a double quote:

SELECT * FROM SomeWhere
    WHERE SomeThing = "He said, ""Don't do it!""';

It isn't clear from the question whether the company name includes the outer double quotes as well as the middle one, or if it just contains the middle one. However, in principle, the rules are the same. Assuming all three double quotes are required, and using single quotes in the SQL - much easier in this context:

SELECT c.companyID, c.companyName, c.dateAdded, count(cm.maxID) as NumDirect
    FROM RussoundGeneral.dbo.Company c  
         LEFT JOIN RussoundGeneral.dbo.CompanyMax cm
                ON (cm.companyId = c.companyId and cm.maxID is not null)  
    WHERE CONTAINS ( companyName,  '"BLAH "BLAHBLAH" Ltd.' )
    GROUP BY c.companyID, c.companyName, c.dateAdded  
    ORDER BY c.companyName ASC;

Using double quotes:

SELECT c.companyID, c.companyName, c.dateAdded, count(cm.maxID) as NumDirect
    FROM RussoundGeneral.dbo.Company c  
         LEFT JOIN RussoundGeneral.dbo.CompanyMax cm
                ON (cm.companyId = c.companyId and cm.maxID is not null)  
    WHERE CONTAINS ( companyName,  """BLAH ""BLAHBLAH"" Ltd." )
    GROUP BY c.companyID, c.companyName, c.dateAdded  
    ORDER BY c.companyName ASC;

If you are building strings in a programming language, then you have to worry about getting these quotes past whatever evaluates strings in your programming language. For example, if you were building a string literal in C, you'd have to escape the double quotes with backslashes:

static const char sql_stmt[] =
"SELECT c.companyID, c.companyName, c.dateAdded,\n"
"       COUNT(cm.maxID) AS NumDirect\n"
"    FROM RussoundGeneral.dbo.Company c\n"
"         LEFT JOIN RussoundGeneral.dbo.CompanyMax cm\n"
"                ON (cm.companyId = c.companyId AND cm.maxID IS NOT NULL)\n"  
"    WHERE CONTAINS(companyName,  \"\"\"BLAH \"\"BLAHBLAH\"\" Ltd.\")\n"
"    GROUP BY c.companyID, c.companyName, c.dateAdded\n"
"    ORDER BY c.companyName ASC";

On the other hand, if you read the data from the user - such as the company name, then you simply have to ensure what is read is correctly quoted.

Those who said "use parameters" are right - it is much easier and more reliable and less vulnerable to SQL injection attacks (see XKCD if you haven't already see it). But if you understand the fundamentals, you can adapt to the actual requirements of your system.

Final note: in standard SQL, double quotes enclose 'delimited identifiers'. That is, the double quotes surround a name which must be treated as the name of something in the database, not as a string literal. In MS SQL Server, the [square brackets] serve the same purpose; what is between the brackets is the name of a column or whatever inside the database. Many systems are more flexible than that; not all systems are the same in how they deviate from the standard.

Jonathan Leffler
A: 

You will finally have to extract data from your database and have it displayed on screen or printed on reports. Manipulating double quotes or any extra character can then become very confusing.

By converting your strings to HTML before INSERTS or UPDATES, you are avoiding all the confusion linked to quotes management. At SELECT time, it will be easy to convert back from HTML. At reporting time (as reporting tools (such as Crystal Reports) propose an HTML formatting option), you will not even have to do anything to display data in a correct way.

By the way, do not forget to hang the guy that invented this company name.

Philippe Grondier