Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Ticket #8886: sqlserver_improved_column_schema_reflection.diff

File sqlserver_improved_column_schema_reflection.diff, 7.7 kB (added by tomafro, 10 months ago)
  • activerecord/test/defaults_test.rb

    old new  
    22require 'fixtures/default' 
    33require 'fixtures/entrant' 
    44 
     5 
     6 
    57class DefaultTest < Test::Unit::TestCase 
    68  def test_nil_defaults_for_not_null_columns 
    79    column_defaults = 
     
    5759      assert_equal BigDecimal.new("2.78"), default.decimal_number 
    5860    end 
    5961  end 
     62   
     63  if current_adapter?(:SQLServerAdapter) 
     64    class SQLServerDefault < ActiveRecord::Base; end; 
     65     
     66    def test_sqlserver_default_strings 
     67      default = SQLServerDefault.new 
     68      assert_equal nil, default.string_with_null_default 
     69      assert_equal 'null', default.string_with_pretend_null_one 
     70      assert_equal '(null)', default.string_with_pretend_null_two  
     71      assert_equal 'NULL', default.string_with_pretend_null_three 
     72      assert_equal '(NULL)', default.string_with_pretend_null_four 
     73    end 
     74  end 
    6075end 
  • activerecord/test/fixtures/db_definitions/schema.rb

    old new  
    7474    create_table :table_with_real_columns, :force => true do |t| 
    7575      t.column :real_number, :real 
    7676    end 
     77     
     78    create_table :sql_server_defaults, :force => true do |t| 
     79      t.column :string_with_null_default, :string, :default => nil 
     80      t.column :string_with_pretend_null_one, :string, :default => 'null' 
     81      t.column :string_with_pretend_null_two, :string, :default => '(null)' 
     82      t.column :string_with_pretend_null_three, :string, :default => 'NULL' 
     83      t.column :string_with_pretend_null_four, :string, :default => '(NULL)' 
     84    end 
    7785  end 
    7886end 
  • activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb

    old new  
    5353    class SQLServerColumn < Column# :nodoc: 
    5454      attr_reader :identity, :is_special 
    5555 
    56       def initialize(name, default, sql_type = nil, identity = false, null = true) # TODO: check ok to remove scale_value = 0 
    57         super(name, default, sql_type, null) 
    58         @identity = identity 
    59         @is_special = sql_type =~ /text|ntext|image/i 
     56      def initialize(info) 
     57        if info[:type] =~ /numeric|decimal/i 
     58          type = "#{info[:type]}(#{info[:numeric_precision]},#{info[:numeric_scale]})" 
     59        else 
     60          type = "#{info[:type]}(#{info[:length]})" 
     61        end 
     62        super(info[:name], info[:default_value], type, info[:is_nullable]) 
     63        @identity = info[:is_identity] 
     64        @is_special = ["text", "ntext", "image"].include?(info[:type]) 
    6065        # TODO: check ok to remove @scale = scale_value 
    6166        # SQL Server only supports limits on *char and float types 
    6267        @limit = nil unless @type == :float or @type == :string 
     
    255260      def disconnect! 
    256261        @connection.disconnect rescue nil 
    257262      end 
    258  
     263       
    259264      def columns(table_name, name = nil) 
    260265        return [] if table_name.blank? 
    261         table_name = table_name.to_s if table_name.is_a?(Symbol) 
    262         table_name = table_name.split('.')[-1] unless table_name.nil? 
     266        table_name = table_name.to_s.split('.')[-1] 
    263267        table_name = table_name.gsub(/[\[\]]/, '') 
    264         sql = %Q
     268        sql = %
    265269          SELECT  
    266             cols.COLUMN_NAME as ColName,   
    267             cols.COLUMN_DEFAULT as DefaultValue, 
    268             cols.NUMERIC_SCALE as numeric_scale, 
    269             cols.NUMERIC_PRECISION as numeric_precision,  
    270             cols.DATA_TYPE as ColType,  
    271             cols.IS_NULLABLE As IsNullable,   
    272             COL_LENGTH(cols.TABLE_NAME, cols.COLUMN_NAME) as Length,   
    273             COLUMNPROPERTY(OBJECT_ID(cols.TABLE_NAME), cols.COLUMN_NAME, 'IsIdentity') as IsIdentity,   
    274             cols.NUMERIC_SCALE as Scale  
    275           FROM INFORMATION_SCHEMA.COLUMNS cols  
    276           WHERE cols.TABLE_NAME = '#{table_name}'    
     270          columns.COLUMN_NAME as name, 
     271          columns.DATA_TYPE as type,   
     272          CASE 
     273            WHEN columns.COLUMN_DEFAULT = '(null)' OR columns.COLUMN_DEFAULT = '(NULL)' THEN NULL 
     274            ELSE columns.COLUMN_DEFAULT 
     275          END default_value, 
     276          columns.NUMERIC_SCALE as numeric_scale, 
     277          columns.NUMERIC_PRECISION as numeric_precision,   
     278          COL_LENGTH(columns.TABLE_NAME, columns.COLUMN_NAME) as length,   
     279          CASE 
     280            WHEN constraint_column_usage.constraint_name IS NULL THEN NULL 
     281            ELSE 1 
     282          END is_primary_key, 
     283          CASE 
     284            WHEN columns.IS_NULLABLE = 'YES' THEN 1 
     285            ELSE NULL 
     286          end is_nullable, 
     287          CASE 
     288            WHEN COLUMNPROPERTY(OBJECT_ID(columns.TABLE_NAME), columns.COLUMN_NAME, 'IsIdentity') = 0 THEN NULL 
     289            ELSE 1 
     290          END is_identity 
     291          FROM INFORMATION_SCHEMA.COLUMNS columns 
     292          LEFT OUTER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS primary_key_constraints ON ( 
     293            primary_key_constraints.table_name = columns.table_name  
     294            AND primary_key_constraints.constraint_type = 'PRIMARY KEY' 
     295          ) 
     296          LEFT OUTER JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE constraint_column_usage ON ( 
     297            constraint_column_usage.table_name = primary_key_constraints.table_name  
     298            AND constraint_column_usage.column_name = columns.column_name 
     299          ) 
     300          WHERE columns.TABLE_NAME = '#{table_name}' 
    277301        } 
    278         # Comment out if you want to have the Columns select statment logged. 
    279         # Personally, I think it adds unnecessary bloat to the log.  
    280         # If you do comment it out, make sure to un-comment the "result" line that follows 
    281         result = log(sql, name) { @connection.select_all(sql) } 
    282         #result = @connection.select_all(sql) 
    283         columns = [] 
    284         result.each do |field| 
    285           default = field[:DefaultValue].to_s.gsub!(/[()\']/,"") =~ /null/ ? nil : field[:DefaultValue] 
    286           if field[:ColType] =~ /numeric|decimal/i 
    287             type = "#{field[:ColType]}(#{field[:numeric_precision]},#{field[:numeric_scale]})" 
    288           else 
    289             type = "#{field[:ColType]}(#{field[:Length]})" 
    290           end 
    291           is_identity = field[:IsIdentity] == 1 
    292           is_nullable = field[:IsNullable] == 'YES' 
    293           columns << SQLServerColumn.new(field[:ColName], default, type, is_identity, is_nullable) 
     302 
     303        result = select(sql, name, true) 
     304        result.collect do |column_info| 
     305          # Remove brackets and outer quotes (if quoted) of default value returned by db, i.e: 
     306          #   "(1)" => "1", "('1')" => "1", "((-1))" => "-1", "('(-1)')" => "(-1)" 
     307          column_info.symbolize_keys! 
     308          column_info[:default_value] = column_info[:default_value].match(/\A\(+'?(.*?)'?\)+\Z/)[1] if column_info[:default_value] 
     309          SQLServerColumn.new(column_info) 
    294310        end 
    295         columns 
    296311      end 
    297312 
     313 
    298314      def insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) 
    299315        execute(sql, name) 
    300316        id_value || select_one("SELECT @@IDENTITY AS Ident")["Ident"] 
     
    510526      end 
    511527 
    512528      private  
    513         def select(sql, name = nil
    514           repair_special_columns(sql) 
     529        def select(sql, name = nil, ignore_special_columns = false
     530          repair_special_columns(sql) unless ignore_special_columns 
    515531 
    516532          result = []           
    517533          execute(sql) do |handle|