Ошибка при поиске контакта с символом апостроф (')

Приложение для отправки смс. Можно выбрать контакт из телефонной книги и отправить смс. Но если в поле поиска контакта ввести апостроф, то приложение падает с ошибкой android.database.sqlite.SQLiteException: near "'%'": syntax error (code 1). Буду благодарен всем за помощь. Вот данный метод:

void requestDatabase(String s) {

    String selection = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " like'%" + s + "%' " +
            " or " + ContactsContract.CommonDataKinds.Phone.NORMALIZED_NUMBER + " like'%" + s + "%'";
    String[] projection = new String[]{ContactsContract.CommonDataKinds.Phone.NAME_RAW_CONTACT_ID,
            ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME_PRIMARY,
            ContactsContract.CommonDataKinds.Phone.NUMBER, ContactsContract.CommonDataKinds.Phone.PHOTO_THUMBNAIL_URI};
    Cursor cursor = getApplicationContext().getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, projection, selection, null, ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME_PRIMARY);
    if (cursor != null) {
        List<ContactHintItem> list = new ArrayList<>();
        while (cursor.moveToNext()) {
            list.add(new ContactHintItem(cursor));
        }
        if (isStringDigit(s))
            list.add(new ContactHintItem(null, s, s, null));
        cursor.close();
        adapter.update(list);
    }
}

Ответы (3 шт):

Автор решения: S.H.

У вас одинарный апостроф воспринимается как окончание строки в поисковом запросе. То есть, надо как то поменять апостроф на то, что не разрывает строку. Это называется экранированием.

Экранирование апострофов при вставке или в select-запросе в sqlite делается дублированием этих апострофов: ссылка

→ Ссылка
Автор решения: Alexey R.

API андройда предлагает использовать DatabaseUtils.sqlEscapeString(String value) для того чтобы заескейпить все символы, которые необходимо эскейпить в запросах.

→ Ссылка
Автор решения: Максим Шимко

Данная проблема была решена! Можно использовать:

if (s.contains("'")) {
   s = s.replaceAll("'", "''");
}

Но я не хотел использовать костыль, и искал как правильно параметризировать запрос. Вот работающий метод с параметрами в запросе:

void requestDatabase(String s) {
                String selection = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " like ?" + " or " + ContactsContract.CommonDataKinds.Phone.NORMALIZED_NUMBER + " like ?";
                String[] projection = new String[]{ContactsContract.CommonDataKinds.Phone.NAME_RAW_CONTACT_ID,
                        ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME_PRIMARY,
                        ContactsContract.CommonDataKinds.Phone.NUMBER, ContactsContract.CommonDataKinds.Phone.PHOTO_THUMBNAIL_URI};
                Cursor cursor = getApplicationContext().getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, projection, selection, new String[]{"%"+s+"%", "%"+s+"%"}, ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME_PRIMARY);
        
                ...
            }
→ Ссылка