Skip to content

Commit

Permalink
Add support/test around handling of float/real column types
Browse files Browse the repository at this point in the history
  • Loading branch information
Lucas Maxwell committed Aug 24, 2011
1 parent f333b9f commit f2d928e
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 61 deletions.
2 changes: 2 additions & 0 deletions lib/active_record/connection_adapters/sqlserver_adapter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1332,6 +1332,8 @@ def column_definitions(table_name)
ci[:type]
when /^numeric|decimal$/i
"#{ci[:type]}(#{ci[:numeric_precision]},#{ci[:numeric_scale]})"
when /^float|real$/i
"#{ci[:type]}(#{ci[:numeric_precision]})"
when /^char|nchar|varchar|nvarchar|varbinary|bigint|int|smallint$/
ci[:length].to_i == -1 ? "#{ci[:type]}(max)" : "#{ci[:type]}(#{ci[:length]})"
else
Expand Down
8 changes: 8 additions & 0 deletions test/cases/adapter_test_sqlserver.rb
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,14 @@ def setup
assert_equal 'bigint', @connection.type_to_sql(:integer, 7)
assert_equal 'bigint', @connection.type_to_sql(:integer, 8)
end

should 'create floats when no limit supplied' do
assert_equal 'float(8)', @connection.type_to_sql(:float)
end

should 'create floats when limit is supplied' do
assert_equal 'float(27)', @connection.type_to_sql(:float, 27)
end

end

Expand Down
139 changes: 93 additions & 46 deletions test/cases/column_test_sqlserver.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,23 @@
class SqlServerEdgeSchema < ActiveRecord::Base; end;

class ColumnTestSqlserver < ActiveRecord::TestCase

def setup
@connection = ActiveRecord::Base.connection
@column_klass = ActiveRecord::ConnectionAdapters::SQLServerColumn
end

should 'return real_number as float' do
assert_equal :float, TableWithRealColumn.columns_hash["real_number"].type
end

should 'know its #table_name and #table_klass' do
Topic.columns.each do |column|
assert_equal 'topics', column.table_name, "This column #{column.inspect} did not know it's #table_name"
assert_equal Topic, column.table_klass, "This column #{column.inspect} did not know it's #table_klass"
end
end

should 'return correct null, limit, and default for Topic' do
tch = Topic.columns_hash
assert_equal false, tch['id'].null
Expand All @@ -29,33 +29,33 @@ def setup
assert_equal true, tch['approved'].default
assert_equal 0, tch['replies_count'].default
end

context 'For binary columns' do

setup do
@binary_string = "GIF89a\001\000\001\000\200\000\000\377\377\377\000\000\000!\371\004\000\000\000\000\000,\000\000\000\000\001\000\001\000\000\002\002D\001\000;"
@saved_bdata = Binary.create!(:data => @binary_string)
end

should 'read and write binary data equally' do
assert_equal @binary_string, Binary.find(@saved_bdata).data
end

should 'have correct attributes' do
column = Binary.columns_hash['data']
assert_equal :binary, column.type
assert_equal @connection.native_binary_database_type, column.sql_type
assert_equal nil, column.limit
end

should 'quote data for sqlserver with literal 0x prefix' do
# See the output of the stored procedure: 'exec sp_datatype_info'
sqlserver_encoded_bdata = "0x47494638396101000100800000ffffff00000021f90400000000002c00000000010001000002024401003b"
assert_equal sqlserver_encoded_bdata, @column_klass.string_to_binary(@binary_string)
assert_equal sqlserver_encoded_bdata, @column_klass.string_to_binary(@binary_string)
end

end

context 'For string columns' do

setup do
Expand All @@ -73,7 +73,7 @@ def setup
assert_equal :text, @varcharmax10.type, @varcharmax10.inspect
end
end

should 'have correct #sql_type per schema definition' do
assert_equal 'char(1)', @char.sql_type, 'Specifing a char type with no limit is 1 by SQL Server standards.'
assert_equal 'char(10)', @char10.sql_type, @char10.inspect
Expand All @@ -82,7 +82,7 @@ def setup
assert_equal 'varchar(max)', @varcharmax10.sql_type, 'A -1 limit should be converted to max (max) type.'
end
end

should 'have correct #limit per schema definition' do
assert_equal 1, @char.limit
assert_equal 10, @char10.limit
Expand All @@ -93,10 +93,10 @@ def setup
end

end


context 'For all national/unicode columns' do

setup do
@nchar = SqlServerUnicode.columns_hash['nchar']
@nvarchar = SqlServerUnicode.columns_hash['nvarchar']
Expand All @@ -107,13 +107,13 @@ def setup
@nvarcharmax = SqlServerUnicode.columns_hash['nvarchar_max']
@nvarcharmax10 = SqlServerUnicode.columns_hash['nvarchar_max_10']
end

should 'all respond true to #is_utf8?' do
SqlServerUnicode.columns_hash.except('id').values.each do |column|
assert column.is_utf8?, "This column #{column.inspect} should have been a unicode column."
end
end

should 'have correct simplified types' do
assert_equal :string, @nchar.type
assert_equal :string, @nvarchar.type
Expand All @@ -126,7 +126,7 @@ def setup
assert_equal :text, @nvarcharmax10.type, @nvarcharmax10.inspect
end
end

should 'have correct #sql_type per schema definition' do
assert_equal 'nchar(1)', @nchar.sql_type, 'Specifing a nchar type with no limit is 1 by SQL Server standards.'
assert_equal 'nvarchar(255)', @nvarchar.sql_type, 'Default nvarchar limit is 255.'
Expand All @@ -139,7 +139,7 @@ def setup
assert_equal 'nvarchar(max)', @nvarcharmax10.sql_type, 'A -1 limit should be converted to max (max) type.'
end
end

should 'have correct #limit per schema definition' do
assert_equal 1, @nchar.limit
assert_equal 255, @nvarchar.limit
Expand All @@ -151,9 +151,9 @@ def setup
assert_equal nil, @nvarcharmax10.limit, 'Limits on max types are moot and we should let rails know that.'
end
end

end

context 'For datetime columns' do

setup do
Expand All @@ -168,7 +168,7 @@ def setup
should 'have correct simplified type for uncast datetime' do
assert_equal :datetime, @datetime.type
end

should 'use correct #sql_type for different sql server versions' do
assert_equal 'datetime', @datetime.sql_type
if sqlserver_2000? || sqlserver_2005?
Expand All @@ -179,116 +179,163 @@ def setup
assert_equal 'time', @time.sql_type
end
end

should 'all be have nil #limit' do
assert_equal nil, @date.limit
assert_equal nil, @time.limit
assert_equal nil, @datetime.limit
end

context 'with timestamps' do

should 'use datetime sql type when using :timestamp in schema statements' do
assert_equal :datetime, @timestamp.type
assert_equal 'datetime', @timestamp.sql_type
end

should 'be able to use real sql server timestamp if you really want to' do
assert_equal :binary, @ss_timestamp.type
assert_equal 'timestamp', @ss_timestamp.sql_type
end

should 'return :timestamp as a binaryish string' do
chronic = SqlServerChronic.create!.reload
assert_match %r|\000|, chronic.ss_timestamp
end

end

context 'For smalldatetime types' do

should 'have created that type using rails migrations' do
assert_equal 'smalldatetime', @smalldatetime.sql_type
end

should 'be able to insert column without truncation warnings or the like' do
SqlServerChronic.create! :smalldatetime => Time.now
end

should 'be able to update column without truncation warnings or the like' do
ssc = SqlServerChronic.create! :smalldatetime => 2.days.ago
ssc.update_attributes! :smalldatetime => Time.now
end

end

context 'which have coerced types' do

setup do
christmas_08 = "2008-12-25".to_time
christmas_08_afternoon = "2008-12-25 12:00".to_time
@chronic_date = SqlServerChronic.create!(:date => christmas_08).reload
@chronic_time = SqlServerChronic.create!(:time => christmas_08_afternoon).reload
end

should 'have an inheritable attribute ' do
assert SqlServerChronic.coerced_sqlserver_date_columns.include?('date') unless sqlserver_2008?
end

should 'have column and objects cast to date' do
assert_equal :date, @date.type, "This column: \n#{@date.inspect}"
klass = sqlserver_2008? ? Date : (connection_mode_dblib? ? Time : Date)
assert_instance_of klass, @chronic_date.date
end

should 'have column objects cast to time' do
assert_equal :time, @time.type, "This column: \n#{@time.inspect}"
assert_instance_of Time, @chronic_time.time
end

end

end

context 'For decimal and numeric columns' do

setup do
@bank_balance = NumericData.columns_hash['bank_balance']
@big_bank_balance = NumericData.columns_hash['big_bank_balance']
@world_population = NumericData.columns_hash['world_population']
@my_house_population = NumericData.columns_hash['my_house_population']
end

should 'have correct simplified types' do
assert_equal :decimal, @bank_balance.type
assert_equal :decimal, @big_bank_balance.type
assert_equal :integer, @world_population.type, 'Since #extract_scale == 0'
assert_equal :integer, @my_house_population.type, 'Since #extract_scale == 0'
end

should 'have correct #sql_type' do
assert_equal 'decimal(10,2)', @bank_balance.sql_type
assert_equal 'decimal(15,2)', @big_bank_balance.sql_type
assert_equal 'decimal(10,0)', @world_population.sql_type
assert_equal 'decimal(2,0)', @my_house_population.sql_type
end

should 'have correct #limit' do
assert_equal nil, @bank_balance.limit
assert_equal nil, @big_bank_balance.limit
assert_equal nil, @world_population.limit
assert_equal nil, @my_house_population.limit
end

should 'return correct precisions and scales' do
assert_equal [10,2], [@bank_balance.precision, @bank_balance.scale]
assert_equal [15,2], [@big_bank_balance.precision, @big_bank_balance.scale]
assert_equal [10,0], [@world_population.precision, @world_population.scale]
assert_equal [2,0], [@my_house_population.precision, @my_house_population.scale]
end

end


context 'For float columns' do
# NOTE: float limits are adjusted to 24 or 53 by the database as per
# http://msdn.microsoft.com/en-us/library/ms173773.aspx
# NOTE: floats with a limit of <= 24 are reduced to reals by sqlserver on creation

setup do
@temperature = FloatData.columns_hash['temperature']
@freezing = FloatData.columns_hash['temperature_8']
@mild = FloatData.columns_hash['temperature_24']
@beach = FloatData.columns_hash['temperature_32']
@desert = FloatData.columns_hash['temperature_53']
end

should 'have correct simplified types' do
assert_equal :float, @temperature.type
assert_equal :float, @freezing.type
assert_equal :float, @mild.type
assert_equal :float, @beach.type
assert_equal :float, @desert.type
end

should 'have correct #sql_type' do
assert_equal 'real(24)', @temperature.sql_type
assert_equal 'real(24)', @freezing.sql_type
assert_equal 'real(24)', @mild.sql_type
assert_equal 'float(53)', @beach.sql_type
assert_equal 'float(53)', @desert.sql_type
end

should 'have correct #limit' do
assert_equal 24, @temperature.limit
assert_equal 24, @freezing.limit
assert_equal 24, @mild.limit
assert_equal 53, @beach.limit
assert_equal 53, @desert.limit
end

should 'return nil precisions and scales' do
assert_equal [nil,nil], [@temperature.precision, @temperature.scale]
assert_equal [nil,nil], [@freezing.precision, @freezing.scale]
assert_equal [nil,nil], [@mild.precision, @mild.scale]
assert_equal [nil,nil], [@beach.precision, @beach.scale]
assert_equal [nil,nil], [@desert.precision, @desert.scale]
end

end

context 'For tinyint columns' do

setup do
Expand All @@ -302,6 +349,6 @@ def setup
end

end


end
1 change: 1 addition & 0 deletions test/cases/sqlserver_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class TableWithRealColumn < ActiveRecord::Base; end
class FkTestHasFk < ActiveRecord::Base ; end
class FkTestHasPk < ActiveRecord::Base ; end
class NumericData < ActiveRecord::Base ; self.table_name = 'numeric_data' ; end
class FloatData < ActiveRecord::Base ; self.table_name = 'float_data' ; end
class CustomersView < ActiveRecord::Base ; self.table_name = 'customers_view' ; end
class StringDefaultsView < ActiveRecord::Base ; self.table_name = 'string_defaults_view' ; end
class StringDefaultsBigView < ActiveRecord::Base ; self.table_name = 'string_defaults_big_view' ; end
Expand Down
Loading

0 comments on commit f2d928e

Please sign in to comment.