Как переписать SQL-запрос DELETE на UPDATE с добавлением текста в начало

    При работе с декомпилированными Android-приложениями часто возникает задача изменить логику удаления сообщений на их модификацию. Вместо выполнения DELETE требуется выполнить UPDATE, добавив в начало поля text символ, например, цифру 1. Рассмотрим корректный синтаксис для SQLite, который используется в Android.

    Проблема исходных запросов

    Исходные запросы удаляют строки из таблицы messages по условиям:

    • DELETE FROM messages WHERE chat_id = ? AND delayed_attrs_time_to_fire >= ? AND delayed_attrs_time_to_fire <= ? AND id NOT IN (...)
    • DELETE FROM messages WHERE chat_id = ? AND time >= ? AND time <= ? AND id NOT IN (...)
    • DELETE FROM messages WHERE chat_id = ? AND id in (...)

    Задача - заменить удаление на обновление, добавив в начало содержимого поля text цифру 1.

    Правильный синтаксис UPDATE с конкатенацией

    В SQLite для добавления текста в начало строки используется оператор || (конкатенация) или функция CONCAT. Однако функция CONCAT доступна только в SQLite версии 3.44.0 и выше. Для совместимости с Android (SQLite 3.19-3.28) лучше использовать оператор ||.

    Правильный запрос:

    UPDATE messages SET text = '1' || COALESCE(text, '') WHERE chat_id = ? AND time >= ? AND time <= ? AND id NOT IN (...)

    Почему ваши варианты не работали

    Вы перечислили несколько попыток. Разберём ошибки:

    1. Использование CONCAT

    UPDATE messages SET text=CONCAT('1', COALESCE(text,'')) WHERE ... - синтаксически верно, но CONCAT может отсутствовать в старой версии SQLite. В Android 7+ используется SQLite 3.19, где CONCAT не поддерживается. Запрос завершится ошибкой.

    2. Ошибка в названии функции CONALESCE

    CONALESCE - это несуществующая функция. В SQLite нет такой функции, поэтому запрос не выполнится.

    3. Неправильные имена столбцов

    В исходном запросе столбец называется chat_id, а вы написали chatid (без подчёркивания). Это приводит к ошибке «no such column».

    4. Использование ifnull вместо COALESCE

    UPDATE messages SET text='1 ' || ifnull(text, '') WHERE ... - синтаксис верный, но ifnull принимает только два аргумента. В вашем примере он использован корректно, однако если поле text содержит NULL, то ifnull заменит его на пустую строку. Проблема может быть в версии SQLite или в том, что вы не экранировали кавычки.

    Итоговые корректные запросы

    Вот три переписанных запроса для ваших исходных условий:

    • Первый запрос (delayed_attrs_time_to_fire): UPDATE messages SET text = '1' || COALESCE(text, '') WHERE chat_id = ? AND delayed_attrs_time_to_fire >= ? AND delayed_attrs_time_to_fire <= ? AND id NOT IN (...)
    • Второй запрос (time): UPDATE messages SET text = '1' || COALESCE(text, '') WHERE chat_id = ? AND time >= ? AND time <= ? AND id NOT IN (...)
    • Третий запрос (id in): UPDATE messages SET text = '1' || COALESCE(text, '') WHERE chat_id = ? AND id IN (...)

    Обратите внимание: если вы хотите добавить пробел после единицы, используйте '1 ' ||. Если без пробела - '1' ||.

    Дополнительные рекомендации

    При внедрении изменений в декомпилированное приложение:

    • Убедитесь, что в smali-коде правильно экранированы кавычки (используйте \" внутри строки).
    • Проверьте версию SQLite на устройстве. Для Android 10+ (SQLite 3.28) CONCAT может работать, но || гарантированно поддерживается.
    • Если нужно добавить символ не в начало, а в конец - используйте SET text = text || '1'.

    Теперь вы можете уверенно заменить DELETE на UPDATE и добавить нужный префикс к тексту сообщения.

    Часто задаваемые вопросы