Подтвердить что ты не робот

Android Lollipop - измененное поведение SQLite

При тестировании одного из моих приложений для совместимости с Android 5.0 я обнаружил, что one два моих SQL-запроса не работают больше не работают на Lollipop. Обе мои проблемы привели к значительно большим результатам на Lollipop по сравнению со старыми версиями Android.

Ниже я расскажу о тех проблемах и их решениях более глубоко, если у вас возникнут аналогичные проблемы.

Мой главный вопрос довольно прост: не документированы ли какие-либо несоответствующие изменения?

Проблема номер один: MATCH

Кажется, что следующий запрос больше не работает на Lollipop:


SELECT title FROM ents JOIN ctt ON ctt.docid = ents.cttId WHERE (ctt MATCH '*ads*');

Он больше не возвращает никаких результатов, на pre-Lollipop (с той же базой данных и теми же данными, конечно).

Как описано в этом вопросе, например, MATCH соответствует только строковым префиксам. Это действительно так, "*" перед поисковым термином просто игнорировался на Android < 5.0.

Lollipop SQLite, однако, не нравится первый '*' и ничего не возвращает для этого запроса. Мне пришлось изменить запрос на следующий, чтобы он снова работал:


SELECT title FROM ents JOIN ctt ON ctt.docid = ents.cttId WHERE (ctt MATCH 'ads*');

(Я использую FTS3 для полнотекстового поиска.)

Проблема номер два: COLLATE LOCALIZED

Краткая история: GROUPING В столбце с псевдонимом, на который ссылается исходное имя в сочетании с ORDER BY, с использованием специфичного для Android "COLLATE LOCALIZED", выдает ошибку на Lollipop, но работает в предыдущих версиях. WTF!?: -)

Длинная история:

История началась с довольно большого автоматически сгенерированного запроса, поэтому я модифицировал, упрощал и сокращал его до тех частей, которые вызывают проблемы. Я знаю, что запрос не имеет особого смысла, как показано ниже, но он демонстрирует проблему.


SELECT 
    inner.title AS title, 
    ltrim(inner.title, '*') AS title2
FROM 
    (SELECT types.text AS title FROM types) AS inner
GROUP BY inner.title 

UNION SELECT 
    inner.title AS title, 
    ltrim(inner.title, '*') AS title2
FROM 
    (SELECT types.text AS title FROM types) AS inner
GROUP BY inner.title 

ORDER BY title2 COLLATE LOCALIZED ASC

Запрос выше работает на Andriod < 5.0, но приводит к ошибке в Lollipop:

Error: no such column: inner.title

ОК, я сгладил "inner.title" с "title", поэтому я попытался изменить "GROUP BY inner.title" на "GROUP BY title", который действительно является решением для Lollipop SQLite:


SELECT 
    inner.title AS title, 
    ltrim(inner.title, '*') AS title2
FROM 
    (SELECT types.text AS title FROM types) AS inner
GROUP BY title 

UNION SELECT 
    inner.title AS title, 
    ltrim(inner.title, '*') AS title2
FROM 
    (SELECT types.text AS title FROM types) AS inner
GROUP BY title 

ORDER BY title2 COLLATE LOCALIZED ASC

(btw, этот ответ, вы можете найти отличный обзор используемых версий SQLite в Android)

Теперь идет интересная часть: Если конкретный Android "COLLATE LOCALIZED" удаляется в предложении ORDER BY, все начинает работать, даже с "GROUP BY inner.title":


SELECT 
    inner.title AS title, 
    ltrim(inner.title, '*') AS title2
FROM 
    (SELECT indsntyps.text AS title FROM indsntyps) AS inner
GROUP BY inner.title 

UNION SELECT 
    inner.title AS title, 
    ltrim(inner.title, '*') AS title2
FROM 
    (SELECT indsntyps.text AS title FROM indsntyps) AS inner
GROUP BY inner.title 

ORDER BY title2 ASC

Мой опыт Lollipop основан на тестах в эмуляторе SDK с использованием образа системы ARM Android 5.0 - API уровня 21.

Эта проблема secon выглядит как ошибка SQLite, специфичная для Android. Или может кто-нибудь объяснить мне это (на мой взгляд) странное поведение? Или, опять же, это даже где-то документировано?: -)

Спасибо заранее!

4b9b3361

Ответ 1

Я не эксперт по SQLite, и я предполагаю, что вы решили, что этот вопрос будет в значительной степени риторическим, но позвольте мне предложить некоторые мысли.

MATCH

Как вы уже указали, MATCH учитывает только префиксные термины. Неудивительно, что неожиданное и непредсказуемое поведение возникло бы из-за префикса префикса (если хотите) со звездочкой.

COLLATE LOCALIZED с псевдонимом

Это кажется интересной ошибкой. Вы можете попробовать и использовать EXPLAIN QUERY PLAN, чтобы попробовать и диагностировать его.

Документация

Очевидно, я не сказал вам ничего, чего вы еще не знаете. Однако ваш "вопрос" касался документации. Во-первых, примечания о выпуске SQLite можно найти здесь. Обычно они довольно подробно описывают изменения между релизами.

Ваша первая проблема - это действительно ошибка программирования. Документация уже существует о том, как использовать префиксы FTS. Вы не получите объяснение, почему ваш синтаксис перестает работать. Вероятно, с ним никогда не следовало начинать.

Проблема LOCALIZED, вероятно, является ошибкой, поэтому ее отсутствие "документации" (я рекомендую вам сообщить об этом Google, хотя). Также помните, что SQLite является частью ядра Android и имеет не только настройки (например, LOCALIZED), но и собственные привязки Java. Как основная реализация ядра SQLite, так и привязки потенциально изменяются с каждой версией. Это подводит меня к моей основной точке:

Рассмотрите возможность развертывания приложения с помощью частной реализации SQLite. Инструкции для этого можно найти здесь. Это позволит вам контролировать версию SQLite, используемую вашим приложением, и дать вам прекрасный контроль над тем, как и когда его обновлять. Однако это связано с ценой, поскольку вы теряете ключевое слово LOCALIZED, например, и привязки поддерживают API API 15 или выше. Я полагаю.

Ответ 2

Наблюдаемые изменения связаны с тем, что Lollipop поставляется с SQLite 3.8 (Android 4.x поставляется с 3.7.11). Вот список изменений http://www.sqlite.org/releaselog/3_8_0.html

Например, ошибка без такого столбца для "GROUP BY inner.title" обусловлена ​​тем, что "Идентификаторы в предложениях GROUP BY всегда предпочитают имена столбцов вывода".

Ответ 3

Я вижу пару проблем с OP.

  • FTS использует проценты не звездочки в качестве дикой карты.

  • FTS ищет границы слов, поэтому, имея ведущую дикую карту, никогда не работал с FTS, она передала бы ее sqlite, чтобы прочитать всю таблицу ужасно медленно, но OP заставляет нас полагать, что она работала в мимо. Следовательно, этот запрос в прошлом бы работал медленнее, если он вообще выполнялся.

  • Запросы союзников всегда чрезмерны в количестве ресурсов, которые они используют, особенно в сочетании с некоторой группой. Следовательно, этот запрос не имеет места в масштабируемом бизнес-приложении.