Предположим, name
содержит одиночную кавычку, за которой следует t
, как в
name = "don't look now"
sql = "update foo set is_processed=1 where bar='"+name+"'"
Тогда sql
будет равно
In [156]: sql
Out[156]: "update foo set is_processed=1 where bar='don't look now'"
, а sqlite3 будет считать условное условиеравен where bar='don'
с последующей синтаксической ошибкой t look now'
.sqlite3
затем поднимает
sqlite3.OperationalError: near "t": syntax error
Это пример того, почему вы должны всегда использовать параметризованный SQL .Чтобы избежать этой проблемы (и защитить ваш код от атак с использованием SQL-инъекций), используйте параметризованный SQL и передайте последовательность (или, в зависимости от параметра стиля, сопоставление) значений в качестве второго аргумента cursor.execute
:
sql = "update foo set is_processed=1 where bar=?"
cursor.execute(sql, [name])
Когда вы передаете аргументы (например, [name]
) в качестве второго аргумента cursor.execute
, sqlite3 будет экранировать одинарную кавычку для вас.
В соответствии с API базы данных Python , когда вы передаете parameters
в качестве второго аргумента cursor.execute
(мой акцент):
Модуль будет использовать __getitem__
метод параметровобъект для сопоставления либо позиций (целые числа), либо имен (строки) со значениями параметров.Это позволяет использовать в качестве входных данных как последовательности, так и сопоставления.
Термин привязка относится к процессу привязки входного значения к буферу выполнения базы данных. На практике это означает, что входное значение непосредственно используется в качестве значения в операции.От клиента не требуется «экранировать» значение, чтобы его можно было использовать - значение должно быть равно фактическому значению базы данных
Вот пример работающей игрушкичтобы помочь увидеть проблему и как ее избежать с помощью параметризованного SQL:
import sqlite3
with sqlite3.connect(':memory:') as conn:
cursor = conn.cursor()
cursor.execute('''CREATE TABLE foo
(id INTEGER PRIMARY KEY AUTOINCREMENT,
bar TEXT,
is_processed BOOL)''')
name = "don't look now"
sql = "update foo set is_processed=1 where bar='"+name+"'"
print(sql)
cursor.execute(sql)
# comment out `cursor.execute(sql)` above and compare with
# sql = "update foo set is_processed=1 where bar=?"
# cursor.execute(sql, [name])