我有一个活动记录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。
任何想法发生了什么?
答案 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 :(得分:0)
感谢@gazler和@basgys的帮助,我能够找到问题所在:
实际上是由Digest :: Sha2 #hexdigest函数引起的编码问题。它返回一个编码为ASCII-8BIT的字符串。当它存储在数据库中时,它似乎会自动转换为UTF-8字符串(我通过运行select hex(songhash) from songs
查询来检查)。但是,在查询中使用字符串时,它似乎不会执行该转换。
内部ruby似乎自动处理不同的编码转换。这就是"abc"=="abc"
的原因,尽管它们可能有不同的编码。
我确信这不是预期的行为,但我不知道它是否是一个错误 - 如果它是一个错误,它是否在ActiveRecord,SQLite驱动程序或SQLite本身的某个地方。
我的解决方案现在是在摘要函数的结果中添加.encode("UTF-8")
。