Android Lollipop - 改变 SQLite 的行为

标签 android sqlite backwards-compatibility android-5.0-lollipop

在测试我的一个应用程序的 Android 5.0 兼容性时,我发现 一个 我的两个 SQL 查询 在 Lollipop 上不再按预期工作。与旧的 Android 版本相比,我的两个问题导致 Lollipop 的结果明显不同。

下面,我将更深入地描述这些问题及其解决方案,以防您遇到类似问题。

我的主要问题很简单:这些不向后兼容的更改是否记录在案?

问题一:匹配

以下查询似乎不再适用于 Lollipop:


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

它不再返回任何结果,在 Lollipop 之前它确实返回了(当然,使用相同的数据库和相同的数据)。

this question 中所述,例如, MATCH 仅匹配字符串前缀。确实如此,搜索词前面的“*”在 Android < 5.0 上被忽略了。

然而,Lollipop 的 SQLite 不喜欢第一个 '*' 并且不为此查询返回任何内容。我不得不将查询更改为以下内容以使其再次工作:


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

(我正在使用 FTS3 进行全文搜索。)

问题二:整理本地化

简短的故事: GROUPing BY 原始名称引用的别名列与使用 Android 特定的“COLLATE LOCALIZED”的 ORDER BY 结合会在 Lollipop 上引发错误,但适用于以前的版本。哇!? :-)

长篇大论:

故事从一个相当大的自动生成查询开始,所以我对其进行了修改、简化和缩短到导致问题的部分。我知道查询没有多大意义,如下所示,但它说明了问题。


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

上面的查询适用于 < 5.0 的 Andriod,但在 Lollipop 中会出错:

Error: no such column: inner.title

OK, I aliased "inner.title" with "title", so I tried changing the "GROUP BY inner.title" to "GROUP BY title" which really is the solution for Lollipop's 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

(顺便说一句,在 this answer 中,您可以找到 Android 中使用的 SQLite 版本的概览)

现在有趣的部分来了:如果在 ORDER BY 子句中删除了 Android 特定的“COLLATE LOCALIZED”,那么一切都会开始工作,即使是“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 体验基于使用 Android 5.0 - API Level 21 ARM 系统镜像的 SDK 模拟器中的测试。

对我来说,这个问题似乎是 Android 特有的 SQLite 错误。或者有人可以向我解释这个(在我看来)奇怪的行为吗?或者,再一次,这甚至在某个地方有记录吗? :-)

提前致谢!

最佳答案

无论如何,我都不是 SQLite 专家,我假设您打算让这个问题在很大程度上是修辞,但请允许我提供一些想法。

比赛

正如你已经指出的,MATCH only considers prefix terms .使用星号作为前缀(如果您愿意的话)会导致意外和不可预知的行为,这并不奇怪。

用别名整理本地化

这似乎是一个有趣的错误。不过,您可以尝试使用 EXPLAIN QUERY PLAN 来尝试诊断它。

文档

显然,我没有告诉你任何你不知道的事情。但是,您的“问题”是关于文档的。对于初学者,SQLite release notes can be found here .它们通常非常详细地说明版本之间的变化。

您的第一个问题实际上是编程错误。有关如何使用 FTS 前缀的文档已经存在。你不会得到关于为什么你的特定语法停止工作的解释。可以说,它从一开始就不应该起作用。

LOCALIZED 问题可能是一个错误,因此它缺乏“文档”(不过,我鼓励您将其报告给 Google)。还要记住,SQLite 是 Android 核心的一部分,它不仅有自定义(如 LOCALIZED),还有原生 Java 绑定(bind)。底层 SQLite 核心实现和绑定(bind)都可能随着每个版本而改变。这让我想到了我的主要观点:

考虑使用私有(private) SQLite 实现来部署您的应用。这样做的说明can be found here .这将使您能够控制您的应用程序使用的 SQLite 版本,并让您可以很好地控制如何以及何时升级它。但是,这确实是有代价的,因为您丢失了 LOCALIZED 关键字,我相信绑定(bind)只支持 API 15 或更高版本。

关于Android Lollipop - 改变 SQLite 的行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26816561/

相关文章:

android - 第一次在 ViewPager 中加载时出现黑色 fragment

java - Java servlet 中 Firebase 管理 key 的路径

android - 通过webview或数据库在android中创建表?

java - 动态添加 TextView 到布局

java - 尝试创建一个 Adapter 类来根据固件版本选择 .Java 文件

android - Android Robolectric Library类支持。如何从应用程序项目加载库类R引用

android - 将向所有类(class)播放的游戏应用程序的背景音乐

android - "table doesn' t 存在“sqlite 错误

soap - SOAP/WSDL 中的 API 能否轻松保持向后兼容?

python - BeautifulSoup - 类型错误 : 'NoneType' object is not callable