Из школьного курса арифметики всем известно что минус на минус дает плюс. Ваш покорный слуга также всю свою жизнь был уверен в этой, казалось бы незыблемой, аксиоме. Но на днях, произошло событие, перевернувшее мировоззрение, и заставившее посмотреть новым взглядом на привычные вещи.
В процессе разработки административных инструментов для клуба трельяж понадобилась функция ануллирования всех результатов конкретной игры. Казалось бы, что может быть проще. Меняем статус игры, откатываем денормализационные данные со статистикой игроков, инвалидируем оперативные кеши, затрагивающие эти данные, и дело в шляпе. Но у связки PostgreSQL и psycopg2 на этот счет оказалось собственное мнение, не совпадающее с мнением редакции.
Упрощенно проблемный запрос выглядел приблизительно так:
То есть нам нужно декрементировать общее количество игр и ануллировать рейтинг игрока, набранный в этой игре. Запрос параметризован. Экранируется штатными средствами psycopg2. Здесь кажется просто негде ошибиться. Но на деле, при отрицательном значени rating этот запрос превратится в:
То есть происходит ВЗРЫВ, БАЗУ РАЗРЫВАЕТ В КИШКИ, и далее по тексту. Другими словами, база радостно восприняла два, подряд идущих минуса как комментарий, и побила данные в капусту. А драйвер psycopg2 всю эту радость пропустил без единого возгласа. Хотя, наверное, мог бы определить что в запросе есть комментарий и количество экранируемых параметров не соответствует действительности.
Лечится это довольно просто. Достаточно вместо rating=rating-%s сказать например rating=rating-(%s) и все заработает как надо, Но сам факт безоговорочного доверия к обработке параметризированных запросов драйверами баз данных нужно ставить под сомнение.
Следите за собой, будьте осторожны, и да пребудет с вами сила.
В процессе разработки административных инструментов для клуба трельяж понадобилась функция ануллирования всех результатов конкретной игры. Казалось бы, что может быть проще. Меняем статус игры, откатываем денормализационные данные со статистикой игроков, инвалидируем оперативные кеши, затрагивающие эти данные, и дело в шляпе. Но у связки PostgreSQL и psycopg2 на этот счет оказалось собственное мнение, не совпадающее с мнением редакции.
Упрощенно проблемный запрос выглядел приблизительно так:
cursor.execute("update pref_player set games=games-1, rating=rating-%s where player_id=%s", (rating, player_id))
То есть нам нужно декрементировать общее количество игр и ануллировать рейтинг игрока, набранный в этой игре. Запрос параметризован. Экранируется штатными средствами psycopg2. Здесь кажется просто негде ошибиться. Но на деле, при отрицательном значени rating этот запрос превратится в:
update pref_player set games=games-1, rating=rating
То есть происходит ВЗРЫВ, БАЗУ РАЗРЫВАЕТ В КИШКИ, и далее по тексту. Другими словами, база радостно восприняла два, подряд идущих минуса как комментарий, и побила данные в капусту. А драйвер psycopg2 всю эту радость пропустил без единого возгласа. Хотя, наверное, мог бы определить что в запросе есть комментарий и количество экранируемых параметров не соответствует действительности.
Лечится это довольно просто. Достаточно вместо rating=rating-%s сказать например rating=rating-(%s) и все заработает как надо, Но сам факт безоговорочного доверия к обработке параметризированных запросов драйверами баз данных нужно ставить под сомнение.
Следите за собой, будьте осторожны, и да пребудет с вами сила.