Python smartsql编译插入语句
Python smartsql compile insert statement
我想使用 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
条语句没有问题。
更新:
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()
已修改答案
来自 python doc for sqlite3 APIs:
Usually your SQL operations will need to use values from Python
variables. You shouldn’t assemble your query using Python’s string
operations because doing so is insecure; it makes your program
vulnerable to an SQL injection attack (see https://xkcd.com/327/ for
humorous example of what can go wrong).
Instead, use the DB-API’s parameter substitution. Put ? as a
placeholder wherever you want to use a value, and then provide a tuple
of values as the second argument to the cursor’s execute() method.
(Other database modules may use a different placeholder, such as %s or
:1.) For example:
# Never do this -- insecure!
symbol = 'RHAT' c.execute("SELECT * FROM stocks WHERE symbol = '%s'" % symbol)
# Do this instead
t = ('RHAT',) c.execute('SELECT * FROM stocks WHERE symbol=?', t)
insert` `('(?, (?, ?))', ['INSERT INTO "temp" ("i", "t") VALUES (%s, %s)', 1, 'text'])
的 returned 值表示 sqlbuilder
正在尝试采纳此建议。剩下的就是如何进行字符串插值以将其放入有效的 sqlite 语法中。事实证明 result
构造函数的 Q
参数将做到这一点。
insert = Q(T.temp,result=Result(compile=compile)).insert({T.temp.t: 'text', T.temp.i: 1})
将 return 是 "SQL ready" 的元组,即:('INSERT INTO `temp` (`i`, `t`) VALUES (?, ?)', [1, 'text'])
。现在您看到“%s”已被替换为“?”。不要忘记导入 Result
。
我想使用 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
条语句没有问题。
更新:
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()
已修改答案
来自 python doc for sqlite3 APIs:
Usually your SQL operations will need to use values from Python variables. You shouldn’t assemble your query using Python’s string operations because doing so is insecure; it makes your program vulnerable to an SQL injection attack (see https://xkcd.com/327/ for humorous example of what can go wrong).
Instead, use the DB-API’s parameter substitution. Put ? as a placeholder wherever you want to use a value, and then provide a tuple of values as the second argument to the cursor’s execute() method. (Other database modules may use a different placeholder, such as %s or :1.) For example:
# Never do this -- insecure!
symbol = 'RHAT' c.execute("SELECT * FROM stocks WHERE symbol = '%s'" % symbol)
# Do this instead
t = ('RHAT',) c.execute('SELECT * FROM stocks WHERE symbol=?', t)
insert` `('(?, (?, ?))', ['INSERT INTO "temp" ("i", "t") VALUES (%s, %s)', 1, 'text'])
的 returned 值表示 sqlbuilder
正在尝试采纳此建议。剩下的就是如何进行字符串插值以将其放入有效的 sqlite 语法中。事实证明 result
构造函数的 Q
参数将做到这一点。
insert = Q(T.temp,result=Result(compile=compile)).insert({T.temp.t: 'text', T.temp.i: 1})
将 return 是 "SQL ready" 的元组,即:('INSERT INTO `temp` (`i`, `t`) VALUES (?, ?)', [1, 'text'])
。现在您看到“%s”已被替换为“?”。不要忘记导入 Result
。