<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -1,5 +1,7 @@
 *Edge*
 
+* change_column_default preserves the not-null constraint.  #617 [Tarmo T&#228;nav]
+
 * Fixed that create database statements would always include &quot;DEFAULT NULL&quot; (Nick Sieger) [#334]
 
 * Add :accessible option to associations for allowing (opt-in) mass assignment. #474. [David Dollar] Example :</diff>
      <filename>activerecord/CHANGELOG</filename>
    </modified>
    <modified>
      <diff>@@ -437,18 +437,29 @@ module ActiveRecord
       end
 
       def change_column_default(table_name, column_name, default) #:nodoc:
-        current_type = select_one(&quot;SHOW COLUMNS FROM #{quote_table_name(table_name)} LIKE '#{column_name}'&quot;)[&quot;Type&quot;]
+        column = column_for(table_name, column_name)
+        change_column table_name, column_name, column.sql_type, :default =&gt; default
+      end
+
+      def change_column_null(table_name, column_name, null, default = nil)
+        column = column_for(table_name, column_name)
+
+        unless null || default.nil?
+          execute(&quot;UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL&quot;)
+        end
 
-        execute(&quot;ALTER TABLE #{quote_table_name(table_name)} CHANGE #{quote_column_name(column_name)} #{quote_column_name(column_name)} #{current_type} DEFAULT #{quote(default)}&quot;)
+        change_column table_name, column_name, column.sql_type, :null =&gt; null
       end
 
       def change_column(table_name, column_name, type, options = {}) #:nodoc:
+        column = column_for(table_name, column_name)
+
         unless options_include_default?(options)
-          if column = columns(table_name).find { |c| c.name == column_name.to_s }
-            options[:default] = column.default
-          else
-            raise &quot;No such column: #{table_name}.#{column_name}&quot;
-          end
+          options[:default] = column.default
+        end
+
+        unless options.has_key?(:null)
+          options[:null] = column.null
         end
 
         change_column_sql = &quot;ALTER TABLE #{quote_table_name(table_name)} CHANGE #{quote_column_name(column_name)} #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}&quot;
@@ -460,6 +471,7 @@ module ActiveRecord
         options = {}
         if column = columns(table_name).find { |c| c.name == column_name.to_s }
           options[:default] = column.default
+          options[:null] = column.null
         else
           raise ActiveRecordError, &quot;No such column: #{table_name}.#{column_name}&quot;
         end
@@ -536,6 +548,13 @@ module ActiveRecord
         def version
           @version ||= @connection.server_info.scan(/^(\d+)\.(\d+)\.(\d+)/).flatten.map { |v| v.to_i }
         end
+
+        def column_for(table_name, column_name)
+          unless column = columns(table_name).find { |c| c.name == column_name.to_s }
+            raise &quot;No such column: #{table_name}.#{column_name}&quot;
+          end
+          column
+        end
     end
   end
 end</diff>
      <filename>activerecord/lib/active_record/connection_adapters/mysql_adapter.rb</filename>
    </modified>
    <modified>
      <diff>@@ -238,6 +238,15 @@ module ActiveRecord
         end
       end
 
+      def change_column_null(table_name, column_name, null, default = nil)
+        unless null || default.nil?
+          execute(&quot;UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL&quot;)
+        end
+        alter_table(table_name) do |definition|
+          definition[column_name].null = null
+        end
+      end
+
       def change_column(table_name, column_name, type, options = {}) #:nodoc:
         alter_table(table_name) do |definition|
           include_default = options_include_default?(options)</diff>
      <filename>activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb</filename>
    </modified>
    <modified>
      <diff>@@ -703,6 +703,55 @@ if ActiveRecord::Base.connection.supports_migrations?
       Person.connection.drop_table :testings rescue nil
     end
 
+    def test_keeping_default_and_notnull_constaint_on_change
+      Person.connection.create_table :testings do |t|
+        t.column :title, :string
+      end
+      person_klass = Class.new(Person)
+      person_klass.set_table_name 'testings'
+
+      person_klass.connection.add_column &quot;testings&quot;, &quot;wealth&quot;, :integer, :null =&gt; false, :default =&gt; 99
+      person_klass.reset_column_information
+      assert_equal 99, person_klass.columns_hash[&quot;wealth&quot;].default
+      assert_equal false, person_klass.columns_hash[&quot;wealth&quot;].null
+      assert_nothing_raised {person_klass.connection.execute(&quot;insert into testings (title) values ('tester')&quot;)}
+
+      # change column default to see that column doesn't lose its not null definition
+      person_klass.connection.change_column_default &quot;testings&quot;, &quot;wealth&quot;, 100
+      person_klass.reset_column_information
+      assert_equal 100, person_klass.columns_hash[&quot;wealth&quot;].default
+      assert_equal false, person_klass.columns_hash[&quot;wealth&quot;].null
+
+      # rename column to see that column doesn't lose its not null and/or default definition
+      person_klass.connection.rename_column &quot;testings&quot;, &quot;wealth&quot;, &quot;money&quot;
+      person_klass.reset_column_information
+      assert_nil person_klass.columns_hash[&quot;wealth&quot;]
+      assert_equal 100, person_klass.columns_hash[&quot;money&quot;].default
+      assert_equal false, person_klass.columns_hash[&quot;money&quot;].null
+
+      # change column
+      person_klass.connection.change_column &quot;testings&quot;, &quot;money&quot;, :integer, :null =&gt; false, :default =&gt; 1000
+      person_klass.reset_column_information
+      assert_equal 1000, person_klass.columns_hash[&quot;money&quot;].default
+      assert_equal false, person_klass.columns_hash[&quot;money&quot;].null
+
+      # change column, make it nullable and clear default
+      person_klass.connection.change_column &quot;testings&quot;, &quot;money&quot;, :integer, :null =&gt; true, :default =&gt; nil
+      person_klass.reset_column_information
+      assert_nil person_klass.columns_hash[&quot;money&quot;].default
+      assert_equal true, person_klass.columns_hash[&quot;money&quot;].null
+
+      # change_column_null, make it not nullable and set null values to a default value
+      person_klass.connection.execute('UPDATE testings SET money = NULL')
+      person_klass.connection.change_column_null &quot;testings&quot;, &quot;money&quot;, false, 2000
+      person_klass.reset_column_information
+      assert_nil person_klass.columns_hash[&quot;money&quot;].default
+      assert_equal false, person_klass.columns_hash[&quot;money&quot;].null
+      assert_equal [2000], Person.connection.select_values(&quot;SELECT money FROM testings&quot;).map { |s| s.to_i }.sort
+    ensure
+      Person.connection.drop_table :testings rescue nil
+    end
+
     def test_change_column_default_to_null
       Person.connection.change_column_default &quot;people&quot;, &quot;first_name&quot;, nil
       Person.reset_column_information</diff>
      <filename>activerecord/test/cases/migration_test.rb</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>8f72bc92e20b1242272714f253e23b256761ec1a</id>
    </parent>
  </parents>
  <author>
    <name>Tarmo T&#228;nav</name>
    <email>tarmo@itech.ee</email>
  </author>
  <url>http://github.com/rails/rails/commit/07578ac85585d3c64d4d38d4892fd31582c7c473</url>
  <id>07578ac85585d3c64d4d38d4892fd31582c7c473</id>
  <committed-date>2008-07-14T12:42:01-07:00</committed-date>
  <authored-date>2008-07-13T23:42:20-07:00</authored-date>
  <message>Fixed mysql change_column_default to not make the column always nullable.

Also added change_column_null to both mysql and sqlite to keep the api features closer to postgresql.

[#617 state:resolved]</message>
  <tree>b1a3bfc9964f22609ade326af1303af3b8a46ded</tree>
  <committer>
    <name>Jeremy Kemper</name>
    <email>jeremy@bitsweat.net</email>
  </committer>
</commit>
