Integer out of range in PostgreSQL database - ruby-on-rails

I'm trying to save a number representing the length of a file (4825733517). The column is set to type integer. I don't have any validations or restrictions set.
RangeError: 4825733517 is out of range for ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Integer with limit 4
Should I be using some other column type for this value? (on rails 4.2.4)

For columns of type integer, the :limit value is the maximum column length in bytes (documentation).
With 4 byte length, the largest signed integer you can store is 2,147,483,647, way smaller than your value of 4,825,733,517. You can increase the byte limit, for example to 8 bytes to be a long integer (a bigint PostgreSQL type), this will allow you to store signed values up to 9,223,372,036,854,775,807.
You can do this with a migration create it with something like rails generate migration change_integer_limit_in_your_table, and the following code:
class ChangeIntegerLimitInYourTable < ActiveRecord::Migration
def change
change_column :your_table, :your_column, :integer, limit: 8
end
end

According to the PostgreSQL documentation an integer have a range from -2147483648 to +2147483647. So your number is to big for this type.
Update your column and use the parameter limit to indicate that you want to have a bigint.
change_column :table, :column, :integer, limit: 8

You should change the length of the column in your database with a migration :
update_column :my_table, :my_column, :integer, limit: 12
It will allow you to store bigger integers.

Related

How do i change column type from integer to decimal, with a letter after the decimal?

I just realized my column type needs to be decimal instead of integer
Can i make the change directly in my seeds.rb or there's something else i should do?
Also how do i do this if i intend to add a letter after the decimal?
Example: 2.0L, 2.5L, 5.7L, etc.
If you want to store a letter in your DB, that column type can't be a decimal or integer. A string field would be more appropriate for your case. I'll assume your main question is regarding decimals though.
If you do want to change a column type in the DB, you're supposed to do it using Migrations. From terminal, in your app directory, run: bin/rails g migration changeFieldNameFromIntegerToDecimal.
This will generate a migration file with a timestamp in the filename, in which there is a change method telling rails how you want to change the database. In that change method, put:
def change
change_column :table_name, :column_name, :decimal, precision: :8, scale: :2
end
the precision and scale options do the follwing (from the above link):
precision: Defines the precision for the decimal fields, representing the total number of digits in the number.
scale: Defines the scale for the decimal fields, representing the number of digits after the decimal point.
If you want to convert it to a string, then the migration file would contain:
def change
change_column :table_name, :column_name, :string
end
Finally run bin/rails db:migrate from the terminal in your app directory to execute the migration.
This will change the column type to decimal. To know about the scale and precision check out this Stackoverflow question https://stackoverflow.com/a/2377176/12297707 or the docs https://edgeguides.rubyonrails.org/active_record_migrations.html#column-modifiers
change_column :table_name, :column_name, :decimal, :precision => 8, :scale => 2, :default => 0

How to specify the size of an integer in the migration script

We have two columns which require to be declared as t.integer size(1) and size(2).
i.e. a max size of 1 (i.e upto 9) and max size of 2 (i.e upto 99). How should I declare this in my migration script.
Do you mean that the value in that column should be restricted to the range 1-99?
Having created an integer column you could add ActiveRecord validation to the model:
validates_numericality_of :field_name, :in => 1..99
You should be able to set a :limit on your migration record. Check the documentation here -- http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/TableDefinition.html#method-i-column
Ex:
add_column :my_tbl, :myint, :integer, :limit => 9
This will set a column length -- in other words, it will only allow integers up to 9 digits long.
If you want to restrict the data input for this column, you'll need to do validations in your model. Have a look at http://guides.rubyonrails.org/active_record_validations_callbacks.html#length

Rails Very Large Table

Rails likes to use autoincrement 32bit ints as primary keys on tables. What do people do when they get close to the limits of 32bit int # of rows in a table?
You could change the key to a bigint? That is an 8-byte (64-bit) integer. It gives you up to 9 quantillion instead of 4 billion. There isn't a native migration though, you'd have to do something like:
execute("ALTER TABLE massive_table CHANGE id id BIGINT")
EDIT Apparently specifying a limit on the field as Alex suggested does allow for bigints in both PostgreSQL and mySQL.
You could use 8-byte id fields. Rails doesn't provide types to create long integer or double precision columns, however it can be done using the :limit parameter:
create_table :my_table do |t|
t.integer :long_int_column, :limit => 8
t.float :double_column, :limit => 53
end
8 and 53 are magic numbers. This works for PostgreSQL and MySQL databases, but I haven't tried any others.
If you're altering a table, then you can write
change_column :my_table, :my_col, :integer, :limit => 8
The alternative to 8-byte id fields is to handle id rollover in some way. That would depend on the specifics of your data and application.

Is using column limit options worth it?

Is there any point to specifying a limit option on string in migrations...
class CreateAccounts < ActiveRecord::Migration
def self.up
create_table :accounts do |t|
t.string :name, :limit => 64
end
end
end
Should this be applied to all strings in the DB? What's the significance?
Strings are usually 255 characters length but not all databases treat the string field in the same way. For instance, PostgreSQL can create string column of different sizes.
There are at least 2 very good reasons to specify the value of the string field:
cross-database compatibility
database performance
If you need a string column to store the country code that is 2 chr length, why you want the database to reserve additional 253 characters for... nothing?
Also note you should always validate the length of the field value in your model.
If you try to create a record with a name that exceeds your maximum length:
SQLIte3 will silently trim the value
MySQL will silently trim the value
PostgreSQL will raise an exception
So, always validates_length_of your attribute.
The first thing that comes to mind - when you have millions of accounts, that limit will actually affect the size of your DB a lot.

Integer out of range on Postgres DB

Simple rails app using Postgres DB, getting 'integer out of range' error when trying to insert 2176968859. Should be an easy fix to the migrations, but I'm not sure. Right now I've got...
create_table :targets do |t|
t.integer :tid
...
end
Here's the magic incantation in your migration when you declare the column:
create_table :example do |t|
t.integer :field, :limit => 8
end
The :limit => 8 is the magic in this case as postgres only does signed 4-byte integers when you just say integer. This uses 8-byte signed integers.
What's the question? You are overflowing. Use a bigint if you need numbers that big.
http://www.postgresql.org/docs/8.3/interactive/datatype-numeric.html
In Rails 4. In your migration file, you could define the column as:
t.column :foobar, :bigint
As noted in previous answers, limit: 8 will also achieve the same thing
PostgreSQL integers are signed, there is no unsigned datatype - I bet that's your problem.
If you need larger values, use bigint. If bigint also isn't enough, use numeric - but use bigint rather than numeric unless you need the larger size or decimals, since it's much faster.
Note the range of allowed values for the integer type in http://www.postgresql.org/docs/8.3/interactive/datatype-numeric.html. I think you are going to have to use a bigint, decimal, or double precision.

Resources