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

Ticket #4353 (new enhancement)

Opened 2 years ago

Last modified 2 years ago

[PATCH] Bigint Support for Migrations (MySQL and SQLite Engines)

Reported by: shammond@northpub.com Assigned to: David
Priority: normal Milestone:
Component: ActiveRecord Version: 1.1.1
Severity: minor Keywords: migration mysql sqlite bigint
Cc: tom@popdog.net

Description

This patch provides bigint support for migrations. The :biginteger type can be used for column definitions and the :use_big_id option can be set to use a bigint as the primary key in a table.

Here is an example migration.

class GameDslMigration < ActiveRecord::Migration

  def self.up
    create_table :random_numbers, :use_big_id => true, :force => true do |t|
      t.column "randnum", :biginteger, :null=> false
    end
  end

  def self.down
    drop_table :random_numbers
  end
end

NOTES 1. I struggled with the name for the type. I started with :bignum, but thought that might be misleading because it isn't unlimited in size like the ruby type. :bigint seemed to tied to MySQL, other databases might support it. So I settled for :biginteger

1. SQLite and SQLite3 engines are supported; they simply treat :biginteger the same as :integer. If you check the type of a :biginteger column it will be reported as :integer. SQLite doesn't distinguish.

1. I think that all that needs to be done to support other engines is to define :biginteger and :big_primary_key in the adapter.

1. I'm pretty sure the tests won't pass for the other engines. I assumed that they would get implemented and didn't put a lot of adapter type checks in the tests. That should make it easier to implement the other adapters. I can go back and add the checks if necessary.

Attachments

bigint_support_in_migrations.diff (13.5 kB) - added by shammond@northpub.com on 03/22/06 13:17:51.
Subversion diff
bigint_support_in_migrations.2.diff (11.6 kB) - added by shammond@northpub.com on 04/03/06 10:39:04.
Second implementation using :limit =>
bigint_support_in_migrations.3.diff (11.9 kB) - added by shammond@northpub.com on 07/07/06 10:15:57.
Improved implementation that doesn't break other adapters.

Change History

03/22/06 13:17:51 changed by shammond@northpub.com

  • attachment bigint_support_in_migrations.diff added.

Subversion diff

03/22/06 13:20:01 changed by shammond@northpub.com

Sorry for the formatting. I clicked sumit instead of preview.

Thanks, Steve

03/22/06 19:21:38 changed by david

  • keywords changed from migration mysql bigint to migration mysql bigint unverified.

Please make this dependent on the size instead. So you use a bigint when the size of the column is declared to be larger than what can fit in int. I actually think that MySQL does this automatically. They do for blob/text. (remove the unverified keyword when done).

03/23/06 12:55:42 changed by shammond@northpub.com

MySQL doesn't automatically do that for integer types. In fact when you specify the "size" in MySQL (i.e. int(11)) you are really specifying the number of characters that will padded when the value is returned by the database. int(1) and int(11) both take 4 bytes. I thought about using this approach but the meaning of :limit became kind of ambiguous. See this ticket for more information.

If I use the :limit option I'm changing its meaning in MySQL from characters displayed. I could strictly interpret it as bytes so and :limit greater than 4 yields a bigint or interpret it as characters, any :limit greater than 11 is a bigint? Given the ambiguity, neither approach seemed particularly elegant.

If we want to go with :limit as bytes, I would say that we should explitly redefine it so that the result is the smallest type for the database engine that is large enough to hold the desired number of bytes. Thus :integer :limit => 1 would be a byte, :limit => 4 would be a int and limit => 7 would be bigint in MySQL. They would all be int in SQLite. What would :limit => 20 be?

Let me know how you want this to go.

03/25/06 01:09:54 changed by anonymous

  • keywords changed from migration mysql bigint unverified to migration mysql bigint.

03/26/06 21:45:35 changed by david

  • keywords changed from migration mysql bigint to migration mysql bigint unverified.

It would just pick the biggest field type it could at the high end. This sounds like a good approach. Remove unverified when complete.

04/03/06 10:38:07 changed by shammond@northpub.com

  • keywords changed from migration mysql bigint unverified to migration mysql bigint.

Ok, this has been implemented as :limit, overriding the default behavior in mysql. Also, it translates the column type into the correct Rails column type (i.e. bigint is :integer with :limit => 8. Alterint tables and changing limits works as well. Finally, you can :use_big_id on a table and get the largest supported integer type as the primary_key column. All tests for MySQL, SQLite adn SQLite3 pass. I believe that all other db tests should pass without change, though they won't be able to take advantage of the new functionality without some minor changes to the adapter.

04/03/06 10:39:04 changed by shammond@northpub.com

  • attachment bigint_support_in_migrations.2.diff added.

Second implementation using :limit =>

04/06/06 15:28:20 changed by anonymous

  • keywords changed from migration mysql bigint to migration mysql sqlite bigint.
  • version changed from 1.0.0 to 1.1.0.

05/30/06 11:00:17 changed by tomafro

  • cc set to tom@popdog.net.

07/07/06 10:15:57 changed by shammond@northpub.com

  • attachment bigint_support_in_migrations.3.diff added.

Improved implementation that doesn't break other adapters.

07/07/06 10:20:15 changed by shammond@northpub.com

  • version changed from 1.1.0 to 1.1.1.

In the process of packaging this patch as a plugin I realized it was fairly simple to fix this so that it doesn't break other adapters who don't know, or care, about integer types. I have attached the new diff file above.

See the wiki plugins page for more details on the plugin version of this.