Есть ли причина, которую я выбираю строковыми столбцами, которые содержат SHA1 hexdigests?

У меня есть таблица приглашений, которая выглядит так:

sqlite> .schema invitations CREATE TABLE "invitations" ( "id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL , "sender_id" integer , "recipient_email" varchar(255) , "token" varchar(255) , "sent_at" datetime , "team_id" integer , "created_at" datetime , "updated_at" datetime ); CREATE UNIQUE INDEX "index_invitations_on_recipient_email_and_team_id" ON "invitations" ("recipient_email", "team_id"); CREATE INDEX "index_invitations_on_sender_id" ON "invitations" ("sender_id"); CREATE INDEX "index_invitations_on_team_id" ON "invitations" ("team_id"); 

В столбце токена хранятся шестнадцатеричные, которые генерируются на записи, создаются так (Ruby):

 self.token = Digest::SHA1.hexdigest([Time.now, rand].join) 

Когда я вставляю приглашение в базу данных, я могу получить его с помощью

 SELECT * FROM "invitations" where "invitations"."recipient_email" = "an email" 

но

 SELECT * FROM "invitations" where "invitations"."token" = "an token" 

возвращает примечание, даже если я копирую / вставляю точный токен из инструкции insert?

редактировать
Оказывается, что

 SELECT * FROM "invitations" where "invitations"."token" LIKE "an token" 

вернет запись правильно.

Почему «LIKE» работает, но «=» нет? Я попытался снять шестерку перед вставкой и сделать выбор без учета регистра. Ничего не сработало.

Изменить 2 Кажется, я могу реплицировать эту проблему, используя только rubygem «sqlite3» и командную строку. Это без Rails и т. Д.

Вот этот процесс:

 stuff $ gem install sqlite3 Fetching: sqlite3-1.3.3.gem (100%) Building native extensions. This could take a while... Successfully installed sqlite3-1.3.3 1 gem installed Installing ri documentation for sqlite3-1.3.3... Installing RDoc documentation for sqlite3-1.3.3... stuff $ irb ruby-1.9.2-head :001 > require "sqlite3" ruby-1.9.2-head :017 > rows = db.execute <<-SQL ruby-1.9.2-head :018"> create table invitations ( ruby-1.9.2-head :019"> token varchar(40) ruby-1.9.2-head :020"> ); ruby-1.9.2-head :021"> SQL # with normal strings for comparison ruby-1.9.2-head :022 > ['4535435', 'jfeu833'].each {|hash| db.execute "insert into 'invitations' ('token') values (?)", hash } => ["4535435", "jfeu833"] ruby-1.9.2-head :023 > db.execute("select * from invitations where invitations.token = '4535435'") {|row| p row } # it finds the row successfully ["4535435"] => #<SQLite3::Statement:0x000001011741c8> ruby-1.9.2-head :028 > require "digest/sha1" => true # now to try it with a hash ruby-1.9.2-head :029 > [Digest::SHA1.hexdigest("banana")].each {|hash| db.execute "insert into 'invitations' ('token') values (?)", hash } => ["250e77f12a5ab6972a0895d290c4792f0a326ea8"] ruby-1.9.2-head :031 > db.execute("select * from invitations where invitations.token = '250e77f12a5ab6972a0895d290c4792f0a326ea8'") {|row| p row } # notice that no record is printed => #<SQLite3::Statement:0x0000010107c630> 

    Я обсуждал это с duckyfuzz (OP) в чате, и мы обнаружили, что хэш хранится как BLOB в sqlite:

     sqlite> select typeof(token) from invitations; blob blob 

    Поэтому по какой-то причине, хотя Ruby говорит, что то, что вставляется, является строкой:

     irb(main):002:0> (Digest::SHA1.hexdigest("banana")).class() => String 

    он заканчивается в sqlite как BLOB.

    Интерполяция значения или вставка в качестве литерала вместо вставки с использованием параметров заставляет проблему уйти (как проверено OP):

     oh ok got it ruby-1.9.2-head :010 > db.execute("insert into invitations (token) VALUES ('#{the_hash}')") => [] ok now the dump.. INSERT INTO "invitations" VALUES('bda04628ea94f26cac0793eac103258eb515c505'); much better! 

    Проблема связана с тем, что двоичные строки будут храниться как blobs с помощью sqlite3 rubygem. Способ предотвращения этого заключается в том, чтобы кодировать хэш как UTF-8 перед вставкой.

     hash = Digest::SHA1.hexdigest("banana").encode("UTF-8") db.execute("insert into invitations (token) values (?)", hash) 

    Как только вы это сделаете, хеш будет сохранен как текст.

    Изменение token от varchar(255) до char(40) может помочь.


    Еще одна вещь, которая меня беспокоит, заключается в том, что вы используете двойные кавычки:

    Я всегда думал, что

     select * from "invitations" where "invitations"."token" = "e8c6ab9d5d1df98c906952c58e1be4d640d3c5ae" 

    отличается от:

     select * from 'invitations' where 'invitations'.'token' = 'e8c6ab9d5d1df98c906952c58e1be4d640d3c5ae' 

    и отличается от:

     select * from `invitations` where `invitations`.token` = `e8c6ab9d5d1df98c906952c58e1be4d640d3c5ae` 

    Совсем не уверен, как ведут себя Rails и SQLite по этому вопросу. Я всегда использую (в MySQL и SQL-Server):

     select * from invitations where invitations.token = 'e8c6ab9d5d1df98c906952c58e1be4d640d3c5ae'