2 одинаково выглядящих варианта «обновления» работают по-разному - PullRequest
0 голосов
/ 26 мая 2011

Вот снимок № 1:

strr = "UPDATE fileinfo SET file_name = ? WHERE md5sum = ?"
cr.execute(strr, ( rec[0], rec[1]) )

и № 2:

strr = "UPDATE fileinfo SET file_name = {0} WHERE md5sum = {1}".format(rec[0], rec[1])
cr.execute(strr)

Первый работает нормально, а второй отказывает.Он выдает

sqlite3.OperationalError: нераспознанный токен: (некоторый токен в rec [0], зависит от входных данных, может быть "@" или "!" Или любой строкой, которую вы передаете на вход)

python 3.2, win7

Спасибо.

Ответы [ 2 ]

1 голос
/ 26 мая 2011

Внимание! Следует плохой код!

Проблема заключается в том, что в вашем втором примере вы предоставляете строки не в виде строк SQL, а в виде литеральных значений. Это вряд ли сработает! Вместо этого вы должны сделать это:

strr = "UPDATE fileinfo SET file_name = '{0}' WHERE md5sum = '{1}'".format(rec[0], rec[1])
cr.execute(strr)

Обратите внимание на дополнительные одинарные кавычки? Это синтаксис строки SQL.

Но не делай этого!

Проблема в том, что в замещаемых строках есть символы, которые под синтаксическим анализатором SQL понимаются как что-либо, кроме литерального символа внутри строкового контекста. Наиболее очевидный пример - ' (символ одинарной кавычки). Хотя вы можете быть достаточно безопасны для параметра md5sum, в именах файлов возникают странные вещи (особенно когда речь идет о нетехнических пользователях!), Поэтому лучше быть осторожным в начале.

Можно справиться с этим, добавив дополнительные магические кавычки к значениям во время подстановки, но легко ошибиться (проблема в огромном количестве программ PHP даже до сегодняшнего дня), и это делает это неправильно , учитывая, что у нас есть лучшее, более простое решение в использовании подготовленного утверждения.

Это тоже медленно. Использование подготовленного оператора (т. Е. Ваш первый пример) быстрее, потому что механизм SQL может анализировать код один раз вместо каждого раза, а значения, которые нужно ввести, можно обработать, эффективно разместив их в нужном слоте. сгенерированного байт-кода. Нет необходимости пересчитывать план запроса (то есть небольшую программу, которую SQLite создает внутри себя), а сами значения никогда не суетятся; они просто верно используются правильно.

1 голос
/ 26 мая 2011

Два варианта, которые вы показываете, очень разные. Во-первых, вы используете API базы данных для заполнения параметров - значения правильно экранируются.

Во втором варианте вы просто используете форматирование строки питонов для добавления переменных в строку SQL - значения не экранируются, и в зависимости от содержимого rec[0] и rec[1] у вас будет некорректный SQL.

Обратите внимание, что это путь к уязвимости SQL-инъекций!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...