无法在ActiveRecord中查询长字符串

时间:2012-01-15 20:43:19

标签: ruby-on-rails sqlite activerecord ruby-on-rails-3.1

我有一个活动记录Song模型,其中songhash字段(字符串(255))包含Sha2哈希。当我尝试通过以下代码查找歌曲时,不会返回任何内容:

song = Song.all.first
song2 = Song.where(songhash: song.songhash).first
# song is a valid object with a songhash set, but song2 is nil!

如果我使用“喜欢”查询做同样的事情,它可以工作:

song = Song.all.first
song2 = Song.where("songhash like ?", song.songhash).first
# song2 is a valid object now
song2.songhash == song.songhash
# the equation is true

我担心它与字符串编码有关,但我不知道为什么这个字符串可能会出现编码问题:61a9761b9ebd543b72c5ccf2ab6db198b067f7cf7f8412ee6e9c14b19611bc80

我正在使用带有sqlite db的rails 3.1。

任何想法发生了什么?

2 个答案:

答案 0 :(得分:0)

<强>摘要

生成的SQL语句

 # With = / It doesn't work
 SELECT "songs".* FROM "songs" WHERE "songs"."type" 
 IN ('PlaylistSong') AND "songs"."songhash" =
 '61a9761b9ebd543b72c5ccf2ab6db198b067f7cf7f8412ee6e9c14b19611bc80'

 # With like / It works
 SELECT "songs".* FROM "songs" WHERE "songs"."type" 
 IN ('PlaylistSong') AND (songhash like 
 '61a9761b9ebd543b72c5ccf2ab6db198b067f7cf7f8412ee6e9c14b19611bc80')

 # With upper / It works
 SELECT "songs".* FROM "songs" WHERE "songs"."type" 
 IN ('PlaylistSong') AND (UPPER(songhash) = 
 '61A9761B9EBD543B72C5CCF2AB6DB198B067F7CF7F8412EE6E9C14B19611BC80')

以下陈述有效:

 Song.where(['UPPER(songhash) = ?', song.songhash.upcase]).first
 Song.where(['songhash like ?', song.songhash]).first

UPPER LIKE 都不区分大小写

SQLite文档

  

LIKE运算符执行模式匹配比较。 (一个错误:默认情况下,SQLite只能理解ASCII字符的大写/小写。对于超出 ASCII范围的unicode字符,LIKE运算符默认区分大小写。例如,表达式'a'喜欢'A'是正确的但'æ'喜欢'Æ'是假的。)See more

调查

  1. Charset等于? (Rails - SQLite)
  2. 字符串存储可能脏(回车,...)

答案 1 :(得分:0)

感谢@gazler和@basgys的帮助,我能够找到问题所在:

实际上是由Digest :: Sha2 #hexdigest函数引起的编码问题。它返回一个编码为ASCII-8BIT的字符串。当它存储在数据库中时,它似乎会自动转换为UTF-8字符串(我通过运行select hex(songhash) from songs查询来检查)。但是,在查询中使用字符串时,它似乎不会执行该转换。

内部ruby似乎自动处理不同的编码转换。这就是"abc"=="abc"的原因,尽管它们可能有不同的编码。

我确信这不是预期的行为,但我不知道它是否是一个错误 - 如果它是一个错误,它是否在ActiveRecord,SQLite驱动程序或SQLite本身的某个地方。

我的解决方案现在是在摘要函数的结果中添加.encode("UTF-8")