Android Lollipop - 改变了SQLite的行为

时间:2014-11-08 11:22:44

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

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

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

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

问题一:MATCH

似乎以下查询在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进行全文搜索。)

问题二:COLLATE LOCALIZED

短篇小说:使用特定于Android的“COLLATE LOCALIZED”将原始名称引用的别名列与ORDER BY结合使用会在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

(顺便说一句,在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体验基于SDK模拟器中使用Android 5.0 - API Level 21 ARM系统映像的测试。

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

提前致谢!

3 个答案:

答案 0 :(得分:8)

我从来都不是SQLite专家,而且我认为你打算让这个问题主要是修辞,但请允许我提出一些想法。

MATCH

正如您已经指出的那样,MATCH only considers prefix terms。将前缀(如果愿意)加上星号前缀会产生意外和不可预测的行为,这并不奇怪。

使用别名

收集LOCALIZED

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

文档

显然,我还没有告诉你任何你不知道的事情。你的问题"然而,是关于文档。首先,SQLite release notes can be found here。它们通常非常详细地说明版本之间的变化。

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

LOCALIZED问题可能是一个错误因此缺少"文档" (我鼓励您向Google报告)。还要记住,SQLite是Android核心的一部分,它不仅具有自定义(如LOCALIZED),还具有本机Java绑定。基础SQLite核心实现和绑定都可能随每个版本而变化。这让我想到了我的主要观点:

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

答案 1 :(得分:4)

观察到的变化是因为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子句中的标识符总是更喜欢输出列名”。

答案 2 :(得分:0)

我发现OP有几个问题。

  1. FTS使用百分比而非星号作为外卡。

  2. FTS搜索单词边界,因此拥有一张领先的外卡从未使用过FTS,它会将它传递给sqlite来读取整个表格的速度非常慢但是OP让我们相信它确实有效在过去。因此,如果该查询确实运行,那么该查询在过去会运行缓慢。

  3. 联盟查询在使用的资源量方面总是过多,尤其是与某些组合使用时。因此,此查询在可伸缩业务应用程序中没有位置。