Найти тему

Параметризованные SQL-запросы

Делюсь с вами задачей, которую недавно встретила. Есть у нас вот такой простой запрос:

Выполняем мы его через db.rawQuery(query, null) и получаем в ответ android.database.sqlite.SQLiteException: near "Artagnan": syntax error (code 1 SQLITE_ERROR): , while compiling: SELECT * FROM cats WHERE name = 'D'Artagnan';

Тут проблема в том, что catName содержит одинарную кавычку ('), которая не экранируется автоматически и конфликтует с кавычками, используемыми в самом запросе. Но почему это происходит, если я обернула весь запрос в тройные кавычки? Оказывается, SQLite ничего не знает о тройных кавычках, поэтому у нас появляется синтаксическая ошибка.

Напомню, что экранирование символов — это такой метод обработки специальных символов в строках, чтобы они воспринимались буквально, а не как часть всей конструкции.

Теперь попробуем немного изменённый вариант запроса, и он работает без проблем:

-2

И появляются вопросы, ведь в новом запросе тоже одинарная кавычка, которая должна конфликтовать. Однако здесь есть очень важный момент: мы используем catName не напрямую, а внутри arrayOf. Этот способ называется параметризированным запросом и считается безопасным.

В таком запросе параметры (?) заменяются безопасными значениями, которые экранируют специальные символы и формируются безопасным образом для использования в SQL-запросах. Это решает все проблемы с кавычками.

Посмотрим, как это работает:

  1. Когда мы пишем параметризованный запрос, мы создаем SQL-команду с вопросительными знаками для значений, которые будут подставлены позже. Этот запрос передается в SQLite в качестве шаблона, где он компилируется.
  2. Параметры, которые мы передаем (имя котика), не вставляются сразу в SQL-команду как часть строки. Вместо этого они обрабатываются отдельно.
  3. SQLite автоматически обрабатывает все специальные символы в параметрах, такие как кавычки, знаки препинания и т.д., чтобы гарантировать, что они не будут восприняты как часть SQL-кода. (Ну не красота ли, что всё сделают за нас?)
  4. Данные "привязываются" к запросу в безопасной форме. Это означает, что значения (имя котика) передаются отдельно и не объединяются с основным текстом запроса до момента его выполнения.
  5. Когда все параметры привязаны, SQLite выполняет запрос. Поскольку параметры были обработаны правильно, запрос выполняется именно так, как мы и хотели, без риска неожиданного поведения из-за кривого SQL-кода.

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

-3

Дубль статей в телеграмме — https://t.me/android_junior

Мои заметки в телеграмме — https://t.me/android_junior_notes