Почему мой простой пример Ruby SQLite3 не работает? - PullRequest
2 голосов
/ 23 ноября 2010

Пытаясь выучить Ruby, я читал Мистер. Смиренная маленькая рубиновая книжка соседей .

За большинством примеров было очень легко следовать, давая мне хорошее представление о Ruby, однако я не могу легко запускать примеры, связанные с БД.

Я пытаюсь запустить этот код: (слегка измененный по сравнению с примером, приведенным в книге)

#!/usr/bin/ruby
require 'rubygems'
require 'dbi'

DBI.connect('DBI:SQLite3:testdb', 'ruby', 'ruby') do | dbh |
  dbh.do('CREATE TABLE slugs(name varchar(20), age int);') rescue puts "TABLE slugs already exists."

  sql = "INSERT INTO slugs (name, age) VALUES (?, ?)"

  dbh.prepare(sql) do |st|
    1.upto(20) do |i|
      st.execute("slug #{i}", "#{i}")
    end
  end

end

При запуске он вставляет одну строку в базу данных, а затем выдает следующую ошибку:

/var/lib/gems/1.8/gems/sqlite3-ruby-1.3.2/lib/sqlite3/statement.rb:41:in `bind_param': library routine called out of sequence (SQLite3::MisuseException)
    from /var/lib/gems/1.8/gems/sqlite3-ruby-1.3.2/lib/sqlite3/statement.rb:41:in `bind_params'
    from /var/lib/gems/1.8/gems/sqlite3-ruby-1.3.2/lib/sqlite3/statement.rb:37:in `each'
    from /var/lib/gems/1.8/gems/sqlite3-ruby-1.3.2/lib/sqlite3/statement.rb:37:in `bind_params'
    from /var/lib/gems/1.8/gems/dbd-sqlite3-1.2.5/lib/dbd/sqlite3/statement.rb:71:in `bind_params'
    from /var/lib/gems/1.8/gems/dbi-0.4.5/lib/dbi/handles/statement.rb:115:in `execute'
    from /media/dev/ruby-prax/moi.rb:12
    from /media/dev/ruby-prax/moi.rb:11:in `upto'
    from /media/dev/ruby-prax/moi.rb:11
    from /var/lib/gems/1.8/gems/dbi-0.4.5/lib/dbi/handles/database.rb:61:in `prepare'
    from /media/dev/ruby-prax/moi.rb:10
    from /var/lib/gems/1.8/gems/dbi-0.4.5/lib/dbi/handles/driver.rb:41:in `connect'
    from /var/lib/gems/1.8/gems/dbi-0.4.5/lib/dbi.rb:148:in `connect'
    from /media/dev/ruby-prax/moi.rb:5
TABLE slugs already exists.

Я сейчас на Ubuntu 10.04. Информация о версии:

tlee@tim-ubuntu:/media/dev/ruby-prax$ ruby -v
ruby 1.8.7 (2010-01-10 patchlevel 249) [x86_64-linux]
tlee@tim-ubuntu:/media/dev/ruby-prax$ gem list

*** LOCAL GEMS ***

abstract (1.0.0)
daemons (1.1.0)
dbd-mysql (0.4.4)
dbd-odbc (0.2.5)
dbd-sqlite3 (1.2.5)
dbi (0.4.5)
deprecated (3.0.0, 2.0.1)
erubis (2.6.6)
eventmachine (0.12.10)
extlib (0.9.15)
json_pure (1.4.6)
mysql (2.8.1)
rack (1.2.1)
sqlite3-ruby (1.3.2)
thin (1.2.7)
thor (0.14.1)
tlee@tim-ubuntu:/media/dev/ruby-prax$ sqlite3 --version
3.6.22
tlee@tim-ubuntu:/media/dev/ruby-prax$ 

Что я делаю не так?

Ответы [ 3 ]

3 голосов
/ 02 января 2011

У меня возникла такая же проблема. На github существует проблема , связанная с ошибкой драйвера SQLite для DBD, когда вы используете подготовленный оператор INSERT более одного раза. Лично я принял рекомендацию в ответе там на переход к RDBI , поскольку Ruby / DBI, по-видимому, больше не поддерживается. Переход на RDBI потребовал минимальных изменений кода.

1 голос
/ 23 ноября 2010

Ваше определение таблицы:

slugs(name varchar(20), age int);

но вы пытаетесь вставить:

st.execute("slug #{i}", "#{i}")

Обратите внимание, что "#{i}" это не целое число, это строка. Измените его на i, как в этом примере:

st.execute("slug #{i}", i) 

Тогда посмотри, что произойдет.

0 голосов
/ 09 июня 2015

Мне почему-то кажется, что в некоторых библиотеках sqlite3 на Ruby отсутствуют методы сброса и очистки для класса операторов.

Когда один и тот же оператор SQL выполняется неоднократно, оператор готовится один раз и выполняется с новым набором значений. Но после выполнения оператора и перед его повторным связыванием его необходимо сбросить (и часто очищать). Дело в том, что быстрее сбрасывать используемый оператор, чем «компилировать и оптимизировать» один и тот же SQL снова и снова. Большинство из вас, вероятно, знают все это ... но вот ссылка на документацию SQLite соответствующей части:

https://www.sqlite.org/c3ref/stmt.html

Я не вижу методов сброса и очистки в классе SQLite3 :: Statement, поэтому их можно как-то упустить из этой реализации, или есть какой-то другой механизм для автоматического сброса / сброса при повторном использовании, но этот механизм почему-то не срабатывает , Тем не менее, он даже не упоминается в документации ... по крайней мере, я не смог его найти.

Я думаю, что clear_bindings и методы сброса отсутствуют в классе SQLite3 :: Statement.

https://github.com/sparklemotion/sqlite3-ruby/issues/158

...