Dav*_*ite 3 sql sqlite sqlite3-ruby
我有一个看起来像这样的邀请表
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");
Run Code Online (Sandbox Code Playgroud)
令牌列存储在记录创建时生成的hexdigests(Ruby):
self.token = Digest::SHA1.hexdigest([Time.now, rand].join)
Run Code Online (Sandbox Code Playgroud)
当我将邀请插入数据库时,我可以使用它来检索它
SELECT * FROM "invitations" where "invitations"."recipient_email" = "an email"
Run Code Online (Sandbox Code Playgroud)
但
SELECT * FROM "invitations" where "invitations"."token" = "an token"
Run Code Online (Sandbox Code Playgroud)
即使我从insert语句中复制/粘贴确切的标记,也会注意到?
编辑
事实证明
SELECT * FROM "invitations" where "invitations"."token" LIKE "an token"
Run Code Online (Sandbox Code Playgroud)
将正确地检索记录.
为什么"喜欢"工作,但"="不工作?我已尝试在插入之前剥离十六进制并执行不区分大小写的选择.都没有奏效.
编辑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>
Run Code Online (Sandbox Code Playgroud)
小智 5
我在聊天中与duckyfuzz(OP)讨论过这个问题,我们发现哈希在sqlite中存储为BLOB:
sqlite> select typeof(token) from invitations;
blob
blob
Run Code Online (Sandbox Code Playgroud)
所以出于某种原因,尽管ruby说插入的是一个字符串:
irb(main):002:0> (Digest::SHA1.hexdigest("banana")).class()
=> String
Run Code Online (Sandbox Code Playgroud)
它最终在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!
Run Code Online (Sandbox Code Playgroud)
问题是由二进制字符串将由 sqlite3 rubygem 存储为blob的事实引起的.防止这种情况的方法是在插入之前将散列编码为UTF-8.
hash = Digest::SHA1.hexdigest("banana").encode("UTF-8")
db.execute("insert into invitations (token) values (?)", hash)
Run Code Online (Sandbox Code Playgroud)
完成后,哈希将存储为文本.
| 归档时间: |
|
| 查看次数: |
423 次 |
| 最近记录: |