From 089ef42520968c7852c97faf07e5101685885150 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Sun, 2 Jan 2005 15:09:03 +0000 Subject: [PATCH] Fixed handling of binary content in blobs and similar fields for Ruby/MySQL and SQLite #409 [xal] git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@309 5ecf4fe2-1ee6-0310-87b1-e25e094e27de --- activerecord/CHANGELOG | 2 ++ .../connection_adapters/abstract_adapter.rb | 23 +++++++++++++++--- .../connection_adapters/sqlite_adapter.rb | 24 ++++++++++++++++++- 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG index 4234e4cb1d..59bcb3e712 100644 --- a/activerecord/CHANGELOG +++ b/activerecord/CHANGELOG @@ -1,5 +1,7 @@ *SVN* +* Fixed handling of binary content in blobs and similar fields for Ruby/MySQL and SQLite #409 [xal] + * Added dynamic attribute-based finders as a cleaner way of getting objects by simple queries without turning to SQL. They work by appending the name of an attribute to find_by_, so you get finders like Person.find_by_user_name, Payment.find_by_transaction_id. So instead of writing Person.find_first(["user_name = ?", user_name]), you just do diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb index 454fe98e7f..547c98911a 100755 --- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb @@ -184,6 +184,7 @@ module ActiveRecord when :timestamp then Time when :time then Time when :text, :string then String + when :binary then String when :boolean then Object end end @@ -199,6 +200,7 @@ module ActiveRecord when :timestamp then string_to_time(value) when :time then string_to_dummy_time(value) when :date then string_to_date(value) + when :binary then binary_to_string(value) when :boolean then (value == "t" or value == true ? true : false) else value end @@ -207,6 +209,14 @@ module ActiveRecord def human_name Base.human_attribute_name(@name) end + + def string_to_binary(value) + value + end + + def binary_to_string(value) + value + end private def string_to_date(string) @@ -229,7 +239,7 @@ module ActiveRecord # pad the resulting array with dummy date information time_array[0] = 2000; time_array[1] = 1; time_array[2] = 1; Time.send(Base.default_timezone, *time_array) rescue nil - end + end def extract_limit(sql_type) $1.to_i if sql_type =~ /\((.*)\)/ @@ -249,8 +259,10 @@ module ActiveRecord :time when /date/i :date - when /(c|b)lob/i, /text/i + when /clob/i, /text/i :text + when /blob/i, /binary/i + :binary when /char/i, /string/i :string when /boolean/i @@ -323,7 +335,12 @@ module ActiveRecord def quote(value, column = nil) case value - when String then "'#{quote_string(value)}'" # ' (for ruby-mode) + when String + if column && column.type == :binary + "'#{quote_string(column.string_to_binary(value))}'" # ' (for ruby-mode) + else + "'#{quote_string(value)}'" # ' (for ruby-mode) + end when NilClass then "NULL" when TrueClass then (column && column.type == :boolean ? "'t'" : "1") when FalseClass then (column && column.type == :boolean ? "'f'" : "0") diff --git a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb index 604fc960aa..4dc8d634b3 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb @@ -25,6 +25,28 @@ module ActiveRecord end module ConnectionAdapters + + class SQLiteColumn < Column + + def string_to_binary(value) + value.gsub(/(\0|\%)/) do + case $1 + when "\0" then "%00" + when "%" then "%25" + end + end + end + + def binary_to_string(value) + value.gsub(/(%00|%25)/) do + case $1 + when "%00" then "\0" + when "%25" then "%" + end + end + end + + end class SQLiteAdapter < AbstractAdapter # :nodoc: def select_all(sql, name = nil) select(sql, name) @@ -37,7 +59,7 @@ module ActiveRecord def columns(table_name, name = nil) table_structure(table_name).inject([]) do |columns, field| - columns << Column.new(field['name'], field['dflt_value'], field['type']) + columns << SQLiteColumn.new(field['name'], field['dflt_value'], field['type']) columns end end