nivel - Lollipop de Android-comportamiento cambiado de SQLite
que es el nivel de api en android (3)
Al probar una de mis aplicaciones para la compatibilidad con Android 5.0, encontré que uno dos de mis consultas SQL no hace No trabajes como se espera en Lollipop. Mis dos problemas llevaron a resultados significativamente diferentes en Lollipop en comparación con versiones anteriores de Android.
A continuación, describiré esos problemas y sus soluciones con mayor profundidad en caso de que tenga problemas similares.
Mi pregunta principal es bastante simple: ¿Están documentados esos cambios no compatibles con versiones anteriores?
Problema número uno: MATCH
Parece que la siguiente consulta ya no funciona en Lollipop:
SELECT title FROM ents JOIN ctt ON ctt.docid = ents.cttId WHERE (ctt MATCH ''*ads*'');
Ya no devuelve ningún resultado, en pre-Lollipop lo hizo (con la misma base de datos y los mismos datos, por supuesto).
Como se describe en esta pregunta , por ejemplo, MATCH solo coincide con los prefijos de cadena. Eso es realmente cierto, el ''*'' delante del término de búsqueda se ignoró en Android <5.0.
El SQLite de Lollipop, sin embargo, no le gusta el primer ''*'' y no devuelve nada para esta consulta. Tuve que cambiar la consulta a la siguiente para que funcione de nuevo:
SELECT title FROM ents JOIN ctt ON ctt.docid = ents.cttId WHERE (ctt MATCH ''ads*'');
(Estoy usando FTS3 para la búsqueda de texto completo).
Problema número dos: COLLAR LOCALIZADO
Historia corta: Agrupar POR una columna con alias referenciada por el nombre original junto con un ORDEN POR usar el "COLLATE LOCALIZED" específico de Android, produce un error en Lollipop, pero funciona en versiones anteriores. ¿WTF? :-)
Larga historia:
La historia comenzó con una consulta generada automáticamente bastante grande, así que la modifiqué, simplifiqué y acorté a las partes que causan los problemas. Soy consciente del hecho de que la consulta no tiene mucho sentido como se muestra a continuación, pero demuestra el problema.
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
La consulta anterior funciona en Andriod <5.0, pero produce un error en Lollipop:
Error: no such column: inner.title
De acuerdo, alias "inner.title" con "title", así que intenté cambiar "GROUP BY inner.title" por "GROUP BY title", que realmente es la solución para el SQLite de Lollipop:
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
(Por cierto, en esta respuesta puede encontrar una gran descripción general de las versiones de SQLite utilizadas en Android)
Ahora viene la parte interesante: si el "COLLATE LOCALIZED" específico de Android se elimina en la cláusula ORDER BY, todo comienza a funcionar también, incluso con "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
Las experiencias de My Lollipop se basan en pruebas en el emulador del SDK utilizando la imagen del sistema Android 5.0 - API Level 21 ARM.
Este problema de la segunda me parece un error de SQLite específico para Android. ¿O puede alguien explicarme esto (a mis ojos) comportamiento extraño? O, de nuevo, ¿es esto incluso documentado? :-)
¡Gracias por adelantado!
Estoy viendo un par de problemas con el OP.
FTS usa el porcentaje no asterisco como comodín.
FTS realiza búsquedas en los límites de las palabras, por lo que tener un comodín principal nunca ha funcionado con FTS, lo habría pasado a sqlite para leer toda la tabla terriblemente lenta, pero el OP nos hace creer que funcionó en el pasado. Por lo tanto, esta consulta habría sido lenta en el pasado si se hubiera ejecutado.
Las consultas sindicales siempre son excesivas en la cantidad de recursos que utilizan, especialmente cuando se combinan con algún grupo por. Por lo tanto, esta consulta no tiene lugar en la aplicación empresarial escalable.
Los cambios observados se deben a que Lollipop se envía con SQLite 3.8 (Android 4.x se incluye con 3.7.11). Aquí está la lista de cambios http://www.sqlite.org/releaselog/3_8_0.html
Por ejemplo, el error que no tiene tal columna para "GROUP BY inner.title" se debe a esto: "Los identificadores en las cláusulas GROUP BY siempre prefieren los nombres de las columnas de salida".
No soy un experto en SQLite de ninguna manera, y asumo que pretendía que esta pregunta fuera retórica en gran medida, pero permítame ofrecer algunas ideas.
PARTIDO
Como ya ha indicado, MATCH
solo considera los términos de los prefijos . No es sorprendente que surjan comportamientos inesperados e impredecibles al prefijar el prefijo (si lo desea) con un asterisco.
COLLATE LOCALIZADO con un alias
Esto parece ser un error interesante. Sin embargo, puede probar y usar EXPLAIN QUERY PLAN
para intentar diagnosticarlo.
Documentación
Obviamente, no te he dicho nada que no sepas ya. Su "pregunta" fue acerca de la documentación, sin embargo. Para empezar, las notas de la versión de SQLite se pueden encontrar aquí . Por lo general, son bastante detallados sobre los cambios entre lanzamientos.
Tu primer problema es realmente un error de programación. La documentación ya está allí sobre cómo usar los prefijos FTS. No recibirá una explicación de por qué su sintaxis en particular dejó de funcionar. Podría decirse que, para empezar, nunca debería haber funcionado.
El problema LOCALIZED
es probablemente un error, por lo tanto, su falta de "documentación" (aunque le recomiendo que lo informe a Google). También recuerde que SQLite es parte del núcleo de Android, y que no solo tiene personalizaciones (como LOCALIZED
) sino también enlaces Java nativos. Tanto la implementación del núcleo SQLite subyacente como los enlaces están cambiando potencialmente con cada versión. Lo que me lleva a mi punto principal:
Considere implementar su aplicación con una implementación privada de SQLite. Las instrucciones para hacerlo se pueden encontrar aquí . Esto le permitirá controlar la versión de SQLite que usa su aplicación y le dará un control preciso sobre cómo y cuándo actualizarla. Sin embargo, esto tiene un costo, ya que pierde la palabra clave LOCALIZED
, por ejemplo, y los enlaces solo admiten API 15 o superior, creo.