Экранирование строк для вставки в Ruby SQLite - PullRequest
6 голосов
/ 08 марта 2012

Я создаю сценарий Ruby для импорта текстового файла с разделителями табуляции длиной около 150 тыс. Строк в SQLite. Вот оно пока:

require 'sqlite3'

file = File.new("/Users/michael/catalog.txt")
string = []

# Escape single quotes, remove newline, split on tabs, 
# wrap each item in quotes, and join with commas
def prepare_for_insert(s)
  s.gsub(/'/,"\\\\'").chomp.split(/\t/).map {|str| "'#{str}'"}.join(", ")
end

file.each_line do |line|
  string << prepare_for_insert(line)
end

database = SQLite3::Database.new("/Users/michael/catalog.db")

# Insert each string into the database
string.each do |str|
  database.execute( "INSERT INTO CATALOG VALUES (#{str})")
end

Ошибка сценария в первой строке, содержащая одинарную кавычку, несмотря на gsub для экранирования одинарных кавычек в моем методе prepare_for_insert:

/Users/michael/.rvm/gems/ruby-1.9.3-p0/gems/sqlite3-1.3.5/lib/sqlite3/database.rb:91:
in `initialize': near "s": syntax error (SQLite3::SQLException)

Это ошибка в строке 15. Если я проверяю эту строку с puts string[14], я вижу, где она показывает ошибку рядом с "s". Это выглядит так: 'Touch the Top of the World: A Blind Man\'s Journey to Climb Farther Than the Eye Can See'

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

1 Ответ

12 голосов
/ 08 марта 2012

Не делайте так, интерполяция строк и SQL имеют тенденцию быть плохой комбинацией.Вместо этого используйте подготовленный оператор и позвольте драйверу иметь дело с цитированием и экранированием:

# Ditch the gsub in prepare_for_insert and...
db  = SQLite3::Database.new('/Users/michael/catalog.db')
ins = db.prepare('insert into catalog (column_name) values (?)')
string.each { |s| ins.execute(s) }

Вы должны заменить column_name реальным именем столбца, конечно;вам не нужно указывать имена столбцов в INSERT, но вы всегда должны делать это в любом случае.Если вам нужно вставить больше столбцов, то добавьте больше заполнителей и аргументов в ins.execute.

. Использование prepare и execute должно быть быстрее, безопаснее,проще, и это не заставит вас чувствовать, что вы пишете PHP в 1999 году.

Кроме того, вы должны использовать стандартный синтаксический анализатор CSV 1017 * для анализа файлов, разделенных табуляцией, в форматах XSVне очень весело иметь дело (на самом деле это просто зло), и у вас есть дела поважнее, чем разбираться с их глупостями и крайними случаями, а что нет.

...