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

Ticket #6868 (closed defect: fixed)

Opened 2 years ago

Last modified 2 months ago

[PATCH] add_column doesn't honor :precision and :scale with PostgreSQL

Reported by: ricardo Assigned to: core
Priority: high Milestone: 1.2.7
Component: ActiveRecord Version: edge
Severity: major Keywords: migrations add_column postgresql decimal precision scale tiny
Cc: nzkoz

Description

Hello everyone.

I'm a Rails newbie, and I have a question about migrations with PostgreSQL.

I'm using the svn version of Rails, in this way:

~ $ rails depot
~ $ cd depot
~/depot $ rake rails:freeze:edge

The application will use a PostgreSQL database, so I configure my app accordingly editing the config/database.yml file.

Now I create a model for the items table:

~/depot $ ruby script/generate model item

It creates the file db/migrate/001_create_items.rb, which I modify until I get the following contents:

class CreateItems < ActiveRecord::Migration
  def self.up
    create_table :items do |t|
      t.column :descr, :string
      t.column :price, :decimal, :precision => 5, :scale => 2
    end
  end

  def self.down
    drop_table :items
  end
end

Finally, I do:

~/depot $ rake db:migrate

which creates the items table correctly:

depot_development=# \d items
                                    Table "public.items"
   Column     |          Type          | Modifiers
--------------+------------------------+--------------------------------------------------------
 id           | integer                | not null default
nextval('items_id_seq'::regclass)
 descr        | character varying(255) |
 price        | numeric(5,2)           |
Indexes:
    "items_pkey" PRIMARY KEY, btree (id)

Now it comes the problem:

I want to add a new column, so therefore I create a new migration:

~/depot $ ruby script/generate migration add_cost

I modify the file db/migrate/002_add_cost.rb, which I modify so it looks like this:

class AddCost < ActiveRecord::Migration
  def self.up
    add_column :items, :cost, :decimal, :precision => 6, :scale => 2
  end

  def self.down
    remove_column :items, :cost
  end
end

Then I do:

~/depot $ rake db:migrate

which creates the new column, BUT WITHOUT PRECISION NOR SCALE:

depot_development=# \d items
                                    Table "public.items"
   Column     |          Type          | Modifiers
--------------+------------------------+--------------------------------------------------------
 id           | integer                | not null default nextval('items_id_seq'::regclass)
 descr        | character varying(255) |
 price        | numeric(5,2)           |
 cost         | numeric                |
Indexes:
    "articulos_pkey" PRIMARY KEY, btree (id)

Look at the difference between price and cost columns. "price" has precision (5) and scale (2), but cost is only "numeric", without precision or scale. However, I specify {:precision => 6, :scale => 2} in the add_column command.

It looks like an add_column bug. What do you think?

Attachments

make_postgres_honor_scale_and_precision.diff (1.8 kB) - added by manfred on 01/14/07 14:46:08.
make_postgres_honor_scale_and_precision_with_documentation.diff (3.0 kB) - added by manfred on 06/27/07 16:48:37.
New version of the patch, now with documentation.
postgresql_add_decimal_column_with_scale_and_precision_patch.diff (2.0 kB) - added by w.piekutowski on 10/01/07 00:22:17.
fix_8647.diff (1.0 kB) - added by isak on 01/16/08 10:03:52.

Change History

12/20/06 19:28:08 changed by eventualbuddha

  • status changed from new to closed.
  • resolution set to untested.

You might try sorting this out on IRC or the mailing list first. If you still cannot fix the problem, please reopen this ticket with a failing test.

12/20/06 22:50:55 changed by ricardo

  • status changed from closed to reopened.
  • resolution deleted.

This is a test case I made to illustrate the problem. Create a file called "decimal_test.rb" into depot/test/unit directory, with the following content:

require File.dirname(__FILE__) + '/../test_helper'

class DecimalTest < Test::Unit::TestCase
  self.use_transactional_fixtures = false

  class Item < ActiveRecord::Base; end

  def test_decimal
    Item.connection.create_table :items do |t|
      t.column :descr, :string
      t.column :price, :decimal, :precision => 5, :scale => 2
    end

    assert_raise(ActiveRecord::StatementInvalid) do
      Item.create :descr => 'sample item', :price => 1280
    end

    Item.connection.remove_column(:items, :descr)
    Item.connection.remove_column(:items, :price)
    Item.reset_column_information

    Item.connection.add_column :items, :descr, :string
    Item.connection.add_column :items, :price, :decimal, :precision => 5, :scale => 2

    assert_raise(ActiveRecord::StatementInvalid) do
      Item.create :descr => 'another sample item', :price => 1280
    end
  end
end

In this test case, I create a table with a decimal column, and then I try to create a new row with a very large price value: 1280, which is large than 999.99 (the largest possible value for price, because of its precision and scale).

Obviously, the first try fails, and assert_raise is ok.

Then I remove the two columns and recreate them, but using add_column. When I try to create a row with price = 1280, PostgreSQL allows it, and the assert_raise command fails because no exception is thrown:

/depot$ rake test
(in /home/ricardo/depot)
/usr/bin/ruby1.8 -Ilib:test "/var/lib/gems/1.8/gems/rake-0.7.1/lib/rake/rake_test_loader.rb" "test/unit/decimal_test.rb" 
Loaded suite /var/lib/gems/1.8/gems/rake-0.7.1/lib/rake/rake_test_loader
Started
NOTICE:  CREATE TABLE will create implicit sequence "items_id_seq" for serial column "items.id"
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "items_pkey" for table "items"
F
Finished in 0.125663 seconds.

  1) Failure:
test_decimal(DecimalTest) [./test/unit/decimal_test.rb:25]:
<ActiveRecord::StatementInvalid> exception expected but none was thrown.

1 tests, 2 assertions, 1 failures, 0 errors
/usr/bin/ruby1.8 -Ilib:test "/var/lib/gems/1.8/gems/rake-0.7.1/lib/rake/rake_test_loader.rb" "test/functional/admin_controller_test.rb" 
Loaded suite /var/lib/gems/1.8/gems/rake-0.7.1/lib/rake/rake_test_loader
Started
.
Finished in 0.045193 seconds.

1 tests, 1 assertions, 0 failures, 0 errors
/usr/bin/ruby1.8 -Ilib:test "/var/lib/gems/1.8/gems/rake-0.7.1/lib/rake/rake_test_loader.rb"  
rake aborted!
Test failures

(See full trace by running task with --trace)

Obviously, this fails because the add_column creates a decimal column without precision & scale, so it has an "infinite" precision.

01/14/07 14:45:33 changed by manfred

  • summary changed from Problem with add_column in migrations with PostgreSQL to [PATCH] add_column doesn't honor :precision and :scale with PostgreSQL.
  • milestone changed from 1.x to 1.2.

01/14/07 14:46:08 changed by manfred

  • attachment make_postgres_honor_scale_and_precision.diff added.

01/20/07 15:31:33 changed by ricardo

  • keywords changed from migrations add_column postgresql decimal precision scale to migrations add_column postgresql decimal precision scale verified.

06/23/07 17:16:37 changed by david

  • keywords changed from migrations add_column postgresql decimal precision scale verified to migrations add_column postgresql decimal precision scale undocumented.

Looks good, but needs documentation.

06/27/07 16:48:37 changed by manfred

  • attachment make_postgres_honor_scale_and_precision_with_documentation.diff added.

New version of the patch, now with documentation.

10/01/07 00:21:39 changed by w.piekutowski

  • keywords changed from migrations add_column postgresql decimal precision scale undocumented to migrations add_column postgresql decimal precision scale.

I've improved this patch.

  • documentation for add_column is copied from schema_statements.rb to be consistent with other database adapters
  • previous add_column change had a potential bug - there was no column name quoting
  • precision and scale values in unit test more likely aren't defaults in any supported database

10/01/07 00:22:17 changed by w.piekutowski

  • attachment postgresql_add_decimal_column_with_scale_and_precision_patch.diff added.

10/01/07 00:30:09 changed by w.piekutowski

  • version changed from edge to 1.2.3.

10/01/07 20:03:05 changed by w.piekutowski

  • keywords changed from migrations add_column postgresql decimal precision scale to migrations add_column postgresql decimal precision scale tiny.
  • version changed from 1.2.3 to edge.

Patch is against egde, but bug exists in 1.2.3 too.

01/16/08 03:54:19 changed by nzkoz

  • status changed from reopened to closed.
  • resolution set to fixed.

(In [8647]) Don't ignore :precision and :scale when adding columns on postgresql. Closes #6868 [w.piekutowski]

01/16/08 10:02:20 changed by isak

  • cc set to nzkoz.
  • priority changed from normal to high.
  • status changed from closed to reopened.
  • resolution deleted.
  • severity changed from normal to major.

[8647] breaks add_column in the postgresql_adapter. Patch attached.

01/16/08 10:03:52 changed by isak

  • attachment fix_8647.diff added.

01/16/08 21:56:48 changed by nzkoz

  • status changed from reopened to closed.
  • resolution set to fixed.

(In [8650]) Correct fix for [8647], Closes #6868. [isak]

(in reply to: ↑ description ; follow-up: ↓ 13 ) 04/21/08 20:12:26 changed by linforcer

I would just like to add that the same problem seems to affect change_column (at least in Rails 2.0.2) I'm just a newbie, so I don't know if this affects the fix at all, but just thought I'd mention it.

(in reply to: ↑ 12 ) 04/22/08 06:33:47 changed by linforcer

Sorry, some more tests showed I was wrong. change_column seems to work after all.

Replying to linforcer:

I would just like to add that the same problem seems to affect change_column (at least in Rails 2.0.2) I'm just a newbie, so I don't know if this affects the fix at all, but just thought I'd mention it.