I'm running into a problem related to the way
binary fields are handled. Let's say I have a binary field set to the
value 0x00. Rails (namely the SQL Server adapter) converts it to the
string "00". But when I try to save I get an exception, because the
adapter does not perform the reverse conversion.
Here is an example. If we have a table created like this in SQL Server:
CREATE TABLE [dbo].[binary_tests] (
[id] [int] IDENTITY (1, 1) NOT FOR REPLICATION NOT NULL ,
[binary_field] [binary] (1) NULL ,
) ON [PRIMARY];
And we insert a record like this:
INSERT INTO binary_tests (binary_field) VALUES (0x00);
Here is what we get at the Rails level:
./script/console
Loading development environment.
>> record = BinaryTest.find(:first)
=> #<BinaryTest:0xb687b0d4 @attributes={"id"=>1, "binary_field"=>"00"}>
>> record.binary_field
=> "00"
>> record.save
ActiveRecord::StatementInvalid: DBI::DatabaseError: (260)
[unixODBC][FreeTDS][SQL Server]Disallowed implicit conversion from data
type varchar to data type binary, table
'foo_development.dbo.binary_tests', column 'binary_field'. Use the
CONVERT function to run this query.: UPDATE dbo.binary_tests SET
[binary_field] = '00' WHERE id = 1
from
./script/../config/../config/../lib/active_record/connection_adapters/abstract_adapter.rb:122:in
`log'
from
./script/../config/../config/../lib/active_record/connection_adapters/sqlserver_adapter.rb:317:in
`execute'
from
./script/../config/../config/../lib/active_record/connection_adapters/sqlserver_adapter.rb:300:in
`update'
from
./script/../config/../config/../vendor/rails/activerecord/lib/active_record/base.rb:1723:in
`update_without_lock'
from
./script/../config/../config/../vendor/rails/activerecord/lib/active_record/locking.rb:33:in
`update_without_callbacks'
from
./script/../config/../config/../vendor/rails/activerecord/lib/active_record/callbacks.rb:278:in
`update_without_timestamps'
from
./script/../config/../config/../vendor/rails/activerecord/lib/active_record/timestamp.rb:39:in
`update'
from
./script/../config/../config/../vendor/rails/activerecord/lib/active_record/base.rb:1718:in
`create_or_update_without_callbacks'
from
./script/../config/../config/../vendor/rails/activerecord/lib/active_record/callbacks.rb:253:in
`create_or_update'
from
./script/../config/../config/../vendor/rails/activerecord/lib/active_record/base.rb:1392:in
`save_without_validation'
from
./script/../config/../config/../vendor/rails/activerecord/lib/active_record/validations.rb:736:in
`save_without_transactions'
from
./script/../config/../config/../vendor/rails/activerecord/lib/active_record/transactions.rb:126:in
`save'
from
./script/../config/../config/../lib/active_record/connection_adapters/abstract/database_statements.rb:59:in
`transaction'
from
./script/../config/../config/../vendor/rails/activerecord/lib/active_record/transactions.rb:91:in
`transaction'
from
./script/../config/../config/../vendor/rails/activerecord/lib/active_record/transactions.rb:118:in
`transaction'
from
./script/../config/../config/../vendor/rails/activerecord/lib/active_record/transactions.rb:126:in
`save'
from (irb):3>>
Now let's try to insert values likely to be accepted as binary:
>> record.binary_field = 1
=> 1
>> record.binary_field
NoMethodError: private method `gsub' called for 1:Fixnum
from
./script/../config/../config/../lib/active_record/connection_adapters/sqlserver_adapter.rb:136:in
`binary_to_string'
from
./script/../config/../config/../lib/active_record/connection_adapters/abstract/schema_definitions.rb:64:in
`type_cast'
from
./script/../config/../config/../lib/active_record/connection_adapters/sqlserver_adapter.rb:83:in
`type_cast'
from
./script/../config/../config/../vendor/rails/activerecord/lib/active_record/base.rb:1805:in
`read_attribute'
from
./script/../config/../config/../vendor/rails/activerecord/lib/active_record/base.rb:1776:in
`method_missing'
from (irb):3
>> record.binary_field = 0x01
=> 1
>> record.binary_field
NoMethodError: private method `gsub' called for 1:Fixnum
from
./script/../config/../config/../lib/active_record/connection_adapters/sqlserver_adapter.rb:136:in
`binary_to_string'
from (eval):1:in `binary_field'
from (irb):5