如果我的 SQL 语句只计算一次,那我为什么要使用 sqlite3_bind()?

If my SQL statement is only evaluated once, then why would I use sqlite3_bind()?

例如, on the question 说 "Don't use stringWithFormat to build your query. Do it properly with sqlite3_bind_xxx statements." 我已经看到(在 Stack Overflow 及以后)许多 comments/answers 无条件地建议使用参数而不是文字。

但是,我在 SQLite website. I do see that section "6. Binding Parameters and Reusing Prepared Statements" in "An Introduction To The SQLite C/C++ Interface" says that "SQLite allows the same prepared statement to be evaluated multiple times" by using sqlite3_bind() 上没有看到任何类似的建议。

因此,如果我只对 SQL 语句求值一次,那么为什么我要使用参数而不是仅使用文字(并且在必要时转义用户输入的文本或自己将数据转换为 BLOB 文字)?我在这里错过了什么吗?我明白 "reusing prepared statements",因此 "avoiding calls to sqlite3_prepare() can give a significant performance improvement",但我想暂时让我的代码尽可能简单,并可能在以后提高性能。

"必要时"是这里的关键。如此开放,这种方法将不可避免地导致 SQL 注入。什么是用户输入的文本?界面的一部分是用户输入的吗?您从数据库中获得的文本是用户输入的吗?你能保证任何使用代码库的人都会得到正确的答案吗?

SQL 的数据处理应该是统一且可预测的。准备好的陈述恰恰提供了这一点。

此外,"escaping"也不是为了保护。在给你一种虚假的安全感的同时,它会在第一时间背叛你。尝试使用字符串转义来保护字段名称并查看。与转义不同,使用准备好的语句可以在适用时保证保护。

I'd like to keep my code as simple as possible

一方面,现在您的 编码过程 不必要地复杂,让您自己在每次执行查询时都在思考,"is it necessary escaping user-inputted text or not?"

最后,为了简化重复性任务,用户定义的函数 可以解决这个问题。只需编写一个将 prepare/bind/execute 组合在单个调用中的函数,然后使用它使您的应用程序代码尽可能简单和有意义。

总是使用 sql_bind() 的原因:

  • 它允许您插入更多数据,因为 SQLite 限制了 SQL 语句的长度
  • 对于大字符串来说速度更快,因为它不会 "need to be parsed or copied as much"
  • 由于将数据转换为 BLOB 字面值需要时间,而且十六进制字符串比它们所代表的数据占用更多内存,因此对于大型 BLOB 速度更快且使用的内存更少
  • 建议在“Limits in SQLite" under "3. Maximum Length Of An SQL Statement

    If an SQL statement is limited to be a million bytes in length, then obviously you will not be able to insert multi-million byte strings by embedding them as literals inside of INSERT statements. But you should not do that anyway. Use host parameters for your data. Prepare short SQL statements like this:

            INSERT INTO tab1 VALUES(?,?,?);

    Then use the sqlite3_bind_XXXX() functions to bind your large string values to the SQL statement. The use of binding obviates the need to escape quote characters in the string, reducing the risk of SQL injection attacks. It is [sic] also runs faster since the large string does not need to be parsed or copied as much.

注意:我发现 "the use of binding obviates the need to escape quote characters in the string" 本身不足的原因是这样做很容易,只需使用我的应用程序的编程语言或使用 SQLite's Formatted String Printing Functions with either the %q or %Q substitution types 之一来明确地做。