草庐IT

Android Lollipop - 改变 SQLite 的行为

coder 2023-06-07 原文

在测试我的一个应用程序的 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 Lollipop - 改变 SQLite 的行为的更多相关文章

  1. ruby - 如何根据特征实现 FactoryGirl 的条件行为 - 2

    我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden

  2. ruby - Ruby gsub 替换中的行为不一致? - 2

    两个gsub产生不同的结果。谁能解释一下为什么?代码也可在https://gist.github.com/franklsf95/6c0f8938f28706b5644d获得.ver=9999str="\tCFBundleDevelopmentRegion\n\ten\n\tCFBundleVersion\n\t0.1.190\n\tAppID\n\t000000000000000"putsstr.gsub/(CFBundleVersion\n\t.*\.).*()/,"#{$1}#{ver}#{$2}"puts'--------'putsstr.gsub/(CFBundleVersio

  3. ruby-on-rails - Ruby 中意外的大小写行为 - 2

    我在一段非常简单的代码(如我所想)中得到了一个错误的值:org=4caseorgwhenorg=4val='H'endputsval=>nil请不要生气,我希望我错过了一些非常明显的东西,但我真的想不通。谢谢。 最佳答案 这是典型的Ruby错误。case有两种被调用的方法,一种是你传递一个东西作为分支的基础,另一种是你不传递的东西。如果您确实在case中指定了一个表达式语句然后评估所有其他条件并与===进行比较.在这种情况下org评估为false和org===false显然不是真的。所有其他情况也是如此,它们要么是真的,要么是假的。

  4. ruby - 使对象的行为类似于 ruby​​ 中并行分配的数组 - 2

    假设您在Ruby中执行此操作:ar=[1,2]x,y=ar然后,x==1和y==2。是否有一种方法可以在我自己的类中定义,从而产生相同的效果?例如rb=AllYourCode.newx,y=rb到目前为止,对于这样的赋值,我所能做的就是使x==rb和y=nil。Python有这样一个特性:>>>classFoo:...def__iter__(self):...returniter([1,2])...>>>x,y=Foo()>>>x1>>>y2 最佳答案 是的。定义#to_ary。这将使您的对象被视为要分配的数组。irb>o=Obje

  5. ruby - 改变替换的大小写 - 2

    我有以下内容:text.gsub(/(lower)(upper)/,'\1\2')我可以将\2替换为大写吗?类似于:sed-e's/\(abc\)/\U\1/'这在Ruby中可行吗? 最佳答案 查看gsub文档:str.gsub(模式){|匹配|block}→new_str在block形式中,当前匹配字符串作为参数传入,$1、$2、$`、$&、$'等变量将被适当设置。block返回的值将替换为每次调用的匹配项。"alowerupperb".gsub(/(lower)(upper)/){|s|$1+""+$2.upcase}

  6. ruby - 了解在 Ruby 中与 lambda 一起使用的 inject 行为 - 2

    我经常将预配置的lambda插入可枚举的方法中,例如“map”、“select”等。但是“注入(inject)”的行为似乎有所不同。例如与mult4=lambda{|item|item*4}然后(5..10).map&mult4给我[20,24,28,32,36,40]但是,如果我制作一个2参数lambda用于像这样的注入(inject),multL=lambda{|product,n|product*n}我想说(5..10).inject(2)&multL因为“inject”有一个可选的单个初始值参数,但这给了我......irb(main):027:0>(5..10).inject

  7. ruby - Sinatra + Heroku + Datamapper 使用 dm-sqlite-adapter 部署问题 - 2

    出于某种原因,heroku尝试要求dm-sqlite-adapter,即使它应该在这里使用Postgres。请注意,这发生在我打开任何URL时-而不是在gitpush本身期间。我构建了一个默认的Facebook应用程序。gem文件:source:gemcuttergem"foreman"gem"sinatra"gem"mogli"gem"json"gem"httparty"gem"thin"gem"data_mapper"gem"heroku"group:productiondogem"pg"gem"dm-postgres-adapter"endgroup:development,:t

  8. ruby - 奇怪的 ruby​​ for 循环行为(为什么这样做有效) - 2

    defreverse(ary)result=[]forresult[0,0]inaryendresultendassert_equal["baz","bar","foo"],reverse(["foo","bar","baz"])这行得通,我想了解原因。有什么解释吗? 最佳答案 如果我使用each而不是for/in重写它,它看起来像这样:defreverse(ary)result=[]#forresult[0,0]inaryary.eachdo|item|result[0,0]=itemendresultendforainb基本上就

  9. ruby - 比较 rspec 中的 float 时的奇怪行为 - 2

    以下测试中的第3个失败:specify{(0.6*2).shouldeql(1.2)}specify{(0.3*3).shouldeql(0.3*3)}specify{(0.3*3).shouldeql(0.9)}#thisonefails这是为什么呢?这是浮点问题还是ruby​​或rspec问题? 最佳答案 从rspec-2.1开始specify{(0.6*2).shouldbe_within(0.01).of(1.2)}在那之前:specify{(0.6*2).shouldbe_close(1.2,0.01)}

  10. ruby - 为什么 `Symbol#match` 的行为与 `String#match` 和 `Regexp#match` 不同? - 2

    String#match和Regexp#match在匹配成功时返回一个MatchData:"".match(//)#=>#//.match("")#=>#//.match(:"")#=>#但是Symbol#match返回匹配位置(如String#=~)::"".match(//)#=>0为什么Symbol#match表现不同?有用例吗? 最佳答案 我将其报告为Ruby核心中的错误:https://bugs.ruby-lang.org/issues/11991.让我们看看他们会怎么说。更新被质疑的行为似乎是一个错误。似乎从Ruby2.

随机推荐