HOWTO: Handle Quotes and Pipes in Concatenated SQL Literals

Last reviewed: December 16, 1997
Article ID: Q178070
The information in this article applies to:
  • Microsoft Visual Basic Learning, Professional, and Enterprise Editions for Windows, version 5.0
  • Microsoft Visual Basic Standard, Professional, and Enterprise Editions for Windows, version 4.0
  • Microsoft Access versions 1.0, 1.1, 2.0, 7.0, 97
  • Microsoft Visual Basic Standard and Professional Editions for Windows, version 3.0

SUMMARY

Building concatenated SQL statements based on user-typed text values can result in invalid SQL statements. This article provides a solution to the problem of building concatenated SQL.

MORE INFORMATION

When building concatenated SQL statements, you can run into the following problems based on incorporating user-typed text into the SQL statement:

User Types the Delimiter Character

If the user types the same character you use to delimit the text field, such as:

   LName contains: O'Brien

   SQL = "SELECT * FROM Employees WHERE LastName='" & LName & "'"

   SQL now contains:
   SELECT * FROM Employees WHERE LastName='O'Brien'

this can result in the following error messages when you execute the SQL statement:

   Run-time error 3075
   Syntax error in query expression '...'

One solution is to replace the apostrophe delimiter with quotes ("), such as:

   SQL = "SELECT * FROM Employees WHERE LastName=""" & LName & """"

However, the user could easily type O"Brien by mistake (forgetting to release the SHIFT key when typing the apostrophe) and the problem reappears. In addition, SQL Server uses " to delimit table and field names. If the user-supplied value exceeds the maximum length of an identifier name, SQL Server will return a syntax error.

The solution is to replace the apostrophe in the variable with two apostrophes so that SQL contains:

   SELECT * FROM Employees WHERE LastName='O''Brien'

User Types the Pipe Symbol

If the user types the pipe symbol (|), such as:

   Password contains: A2|45

   SQL = "SELECT * FROM SecurityLevel WHERE UID='" & UserID & "'"
   SQL = SQL & " AND PWD='" & Password & "'"

   SQL now contains:
   SELECT * FROM SecurityLevel WHERE UID='JohnDoe'
   AND PWD='A2|45'

and you are querying a Jet database, it can cause either the "Syntax Error" given above or the following error:

   Run-time error 3061
   Too few parameters. Expected n.

The pipe symbol causes problems because Jet uses pipe symbols to delimit field or parameter names embedded in a literal string, such as:

   SELECT "|LastName|, |FirstName|" FROM Employees

This was considered easier for beginner users to learn than concatenation when building ad hoc queries through the Access Query designer. However, when used inadvertently in building a SQL statement, it can result in an error.

The solution is to replace the pipe symbol with a concatenated expression so that SQL contains:

   SELECT * FROM SecurityLevel WHERE UID='JohnDoe'
   AND PWD='A2' & chr(124) & '45'

Implementing the Solution

The solution to both these problems can be addressed via substring replacement. The sample functions, ReplaceStr, SQLFixup and JetSQLFixup, are provided below to illustrate the technique.

WARNING: Microsoft provides code examples for illustration only, without warranty either expressed or implied, including but not limited to the implied warranties of merchantability and/or fitness for a particular purpose. This code is provided 'as is' and Microsoft does not guarantee that the following code can be used in all situations. Microsoft does not support modifications of the code to suit customer requirements for a particular purpose.

NOTE: In the following sample code, an underscore (_) at the end of a line is used as a line-continuation character. For product versions that don't not support the line-continuation character, remove the underscore and combine that line with the next lines as a single statement when re- creating this code.

   Function ReplaceStr (TextIn, ByVal SearchStr As String, _
                        ByVal Replacement As String, _
                        ByVal CompMode As Integer)
   Dim WorkText As String, Pointer As Integer
     If IsNull(TextIn) Then
       ReplaceStr = Null
     Else
       WorkText = TextIn
       Pointer = InStr(1, WorkText, SearchStr, CompMode)
       Do While Pointer > 0
         WorkText = Left(WorkText, Pointer - 1) & Replacement & _
                    Mid(WorkText, Pointer + Len(SearchStr))
         Pointer = InStr(Pointer + Len(Replacement), WorkText, _
                         SearchStr, CompMode)
       Loop
       ReplaceStr = WorkText
     End If
   End Function

   Function SQLFixup(TextIn)
     SQLFixup = ReplaceStr(TextIn, "'", "''", 0)
   End Function

   Function JetSQLFixup(TextIn)
   Dim Temp
     Temp = ReplaceStr(TextIn, "'", "''", 0)
     SQLFixup = ReplaceStr(Temp, "|", "' & chr(124) & '", 0)
   End Function

SQLFixup should be used if your SQL statement is going to be used with Jet SQL pass-through queries or with ODBCDirect, RDO, or ADO to a non-Jet back- end database:

   LName contains: O'Brien

   SQL = "SELECT * FROM Employees WHERE LastName='" & _
         SQLFixup(LName) & "'"

   SQL now contains:
   SELECT * FROM Employees WHERE LastName='O''Brien'

JetSQLFixup should be used if Jet is your database back-end, or if doing a non-Pass-through query to an ODBC datasource:

   UserID cntains: JohnDoe
   Password contains: A2|4'5

   SQL = "SELECT * FROM SecurityLevel WHERE UID='" & _
         JetSQLFixup(UserID) & "' AND PWD='" & JetSQLFixup(Password) & "'"

   SQL now contains:
   SELECT * FROM SecurityLevel WHERE UID='JohnDoe'
   AND PWD='A2' & chr(124) & '4''5'

REFERENCES

Microsoft Jet Database Engine Programmer's Guide

Visual Basic Help topic: InStr

For additional information, please see the following article in the Microsoft Knowledge Base:

   ARTICLE-ID: Q147687
   TITLE     : HOWTO: Query for Literal Special Characters in a Where
               Clause

Microsoft Corporation 1997, All Rights Reserved. Contributions by Malcolm Stewart, Microsoft Corporation
Keywords          : VB4WIN vb5all vb5howto
Version           : WINDOWS:1.0,1.1,2.0,3.0,4.0,5.0,7.0,97
Platform          : WINDOWS
Issue type        : kbhowto


================================================================================


THE INFORMATION PROVIDED IN THE MICROSOFT KNOWLEDGE BASE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. MICROSOFT DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES SO THE FOREGOING LIMITATION MAY NOT APPLY.

Last reviewed: December 16, 1997
© 1998 Microsoft Corporation. All rights reserved. Terms of Use.