SQLite插入-如何在使用参数化值避免语法错误的同时插入任何文本

时间:2019-03-05 21:17:24

标签: sql vb.net sqlite

我很想知道一种正确的方法,可以将文本字符串插入数据库中,而不管字符串中包含什么字符。我的意思是,如果我有一个字符串,例如包含单引号或保留为“特殊” SQL字符的任何其他字符。

我要处理的具体问题是,我无法控制可能插入到数据库中的“文本”,因为文本是由应用程序生成的。

当错误消息恰好包含单引号时,我的应用程序无法正确插入的一个示例。 SQL语句当然会使用单引号插入文本,因此我无法插入也包含单引号的文本(除了使用ascii值char(##)函数外)。我要解决的问题是,我将应用程序的输出设置为字符串变量,然后将其插入数据库中,以便可以记录活动(无论是标准输出还是捕获错误)。

如何在避免所有SQL特殊字符的同时简单地插入字符串变量中包含的内容?

我是否需要手动说明所有SQL特殊字符并在插入之前将其替换为字符串?听起来像是命中注定,但我希望已经有一些东西可以适应这种情况。

通过示例伪代码来说明要点:

比方说,应用内发生了错误,需要将其记录下来。错误字符串可能是:

  

错误字符串:“函数calculateStats()参数'pBoolStatCheck'中的错误为空”

现在,我在应用程序中分配给我的字符串变量,并建立SQL插入字符串。

var insertString = "Error in function calculateStats() parameter 'pBoolStatCheck' is Null"


INSERT INTO outputLog(outputLogText) 
VALUES ('insertString');   --This will Fail

--Fails due to the variable 'insertString' containing single quotes.
INSERT INTO outputLog(outputLogText) 
VALUES ('Error in function calculateStats() parameter 'pBoolStatCheck' is Null');

最后-由于我无法控制应用程序可能创建的文本,因此我该如何考虑所有可能破坏插入的字符?

我当前的应用程序遇到此问题的代码是用Visual Basic编写的。我正在使用的数据库是SQLite。

基于此帖子收到的答案的最终解决方案:

Public Sub saveOutputLog(pTextOutput, pTextColor, pNumNewLines, plogType, pMethodSub)

    Dim strTableName As String = "outputLog"
    Dim sqlInsert As String = "INSERT INTO " & strTableName & "(" &
                              "outputLog, logColor, numNewLines, logType, method" &
                              ") VALUES (@outputLog, @logColor, @numNewLines, @logType, @method);"

    Try
        'Open the Database
        outputLogDBConn.Open()

        'Create/Use a command object via the connection object to insert data into the outputLog table
        Using cmd = outputLogDBConn.CreateCommand() 
            cmd.CommandType = CommandType.Text
            cmd.CommandText = sqlInsert
            cmd.Parameters.AddWithValue("@outputLog", pTextOutput)
            cmd.Parameters.AddWithValue("@logColor", pTextColor)
            cmd.Parameters.AddWithValue("@numNewLines", pNumNewLines)
            cmd.Parameters.AddWithValue("@logType", plogType)
            cmd.Parameters.AddWithValue("@method", pMethodSub)

            'Execute the command using above Insert and added Parameters.
            cmd.ExecuteNonQuery()

        End Using 'Using outputLogDBComm

        outputLogDBConn.Close()

    Catch ex As Exception

        outputLogDBConn.Close()

    End Try

End Sub

2 个答案:

答案 0 :(得分:2)

此问题与防止代码中的SQL注入漏洞的问题非常相似。查询非常容易中断,尽管您的中断以无害且烦人的方式中断,但是可以将这些查询带到某些输入可以完全破坏数据库的水平!

解决此问题的最佳方法之一是使用参数化查询。这种方法非常简单。您首先使用“占位符”编写查询,以获取要发送的参数。准备好程序后,可以将这些参数“绑定”到占位符。

类似于以下内容:

Dim command = New SqlCommand("INSERT INTO outputLog(outputLogText) VALUES  (@stringToInsert)", connection);
.
.
.
code
.
.
.
command.Parameters.AddWithValue("@stringToInsert", errorMessage)
.
.
.
execute query

在上面,您看到@stringToInsert是占位符,仅在以后绑定。变量errorMessage所包含的内容无关紧要,因为它不会导致查询以输入导致其潜在中断的方式起作用。

关于此的资源很多:

https://docs.microsoft.com/en-us/dotnet/api/system.data.sqlclient.sqlcommand.prepare?view=netframework-4.7.2

答案 1 :(得分:1)

诸如连接之类的数据库对象不仅需要关闭,而且还需要处置。 using块将确保即使发生错误也将发生这种情况。

由于多种原因,.Add.AddWithValue更好。参见https://blogs.msmvps.com/jcoehoorn/blog/2014/05/12/can-we-stop-using-addwithvalue-already/http://www.dbdelta.com/addwithvalue-is-evil/
.Add的参数是参数的名称,数据库中的数据类型以及字段的大小(可选)。您将需要检查数据库中的最后2个。

在执行之前的最后一分钟打开连接。

如果将OleDb与Access一起使用,则需要确保以与sql语句中出现的顺序相同的顺序添加参数。

    Using cn As New SqlConnection("Your connection string")
        Using cmd As New SqlCommand("INSERT INTO outputLog(outputLogText) VALUES (@outputLogText);", cn)
            cmd.Parameters.Add("@outputLogText", SqlDbType.VarChar, 100).Value = TextBox1.Text
            cn.Open()
            cmd.ExecuteNonQuery()
        End Using
    End Using