0

我想使用 sqlbuilder ( https://sqlbuilder.readthedocs.io/en/latest/ ) 库来构建对 sqlite 的本机查询。有我插入数据的代码:

import sqlite3
from sqlbuilder.smartsql import Q, T
from sqlbuilder.smartsql.dialects.sqlite import compile


if __name__ == '__main__':
    connection = sqlite3.connect(':memory:')

    with connection:
        connection.execute('CREATE TABLE temp (t TEXT, i INTEGER)')

        insert = compile(Q(T.temp).insert({T.temp.t: 'text', T.temp.i: 1}))
        sql, params = insert

        connection.execute(
            sql, params
        )

    connection.close()

此代码不起作用,因为compile为 sqlite: 生成了不正确的 sql 和参数 ('(?, (?, ?))', ['INSERT INTO "temp" ("i", "t") VALUES (%s, %s)', 1, 'text']),并且我收到了错误:sqlite3.OperationalError: near "(": syntax error

select有趣的是,编译和执行语句没有问题。

更新:

选择语句的代码及其工作:

import sqlite3
from sqlbuilder.smartsql import Q, T
from sqlbuilder.smartsql.dialects.sqlite import compile

if __name__ == '__main__':
    connection = sqlite3.connect(':memory:')

    with connection:
        connection.execute('CREATE TABLE temp (t TEXT, i INTEGER)')

        select = compile(Q(T.temp).fields('*'))
        print(select)  # ('SELECT * FROM `temp`', [])
        sql, params = select

        connection.execute(
            sql, params
        )

    connection.close()
4

1 回答 1

1

答案已修改

来自 sqlite3 API 的python 文档

通常,您的 SQL 操作将需要使用 Python 变量中的值。你不应该使用 Python 的字符串操作来组装你的查询,因为这样做是不安全的;它使您的程序容易受到 SQL 注入攻击(有关可能出错的幽默示例,请参见https://xkcd.com/327/ )。

相反,使用 DB-API 的参数替换。放 ?作为一个占位符,无论你想在哪里使用一个值,然后提供一个值的元组作为游标的 execute() 方法的第二个参数。(其他数据库模块可能使用不同的占位符,例如 %s 或 :1。)例如:

# 永远不要这样做——不安全!
symbol = 'RHAT' c.execute("SELECT * FROM stocks WHERE symbol = '%s'" % symbol)

# 改为这样做
t = ('RHAT',) c.execute('SELECT * FROM stocks WHERE symbol=?', t)

insert` `('(?, (?, ?))', ['INSERT INTO "temp" ("i", "t") VALUES (%s, %s)', 1, 'text'])指示的返回值sqlbuilder正在尝试接受此建议。剩下的就是如何进行字符串插值以将其放入有效的 sqlite 语法中。原来构造函数的result参数就是Q这样做的。

insert = Q(T.temp,result=Result(compile=compile)).insert({T.temp.t: 'text', T.temp.i: 1})将返回一个“SQL 就绪”的元组,即:('INSERT INTO `temp` (`i`, `t`) VALUES (?, ?)', [1, 'text']). 现在您看到 '%s' 已被替换为 '?'。不要忘记导入Result.

于 2018-09-10T18:12:07.750 回答