Skip to content

Inconsistent type handling for real columns in PostgreSQL schema dumps and loads #52742

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
krororo opened this issue Aug 29, 2024 · 0 comments · Fixed by #53107
Closed

Inconsistent type handling for real columns in PostgreSQL schema dumps and loads #52742

krororo opened this issue Aug 29, 2024 · 0 comments · Fixed by #53107

Comments

@krororo
Copy link
Contributor

krororo commented Aug 29, 2024

Steps to reproduce

When dumping a PostgreSQL schema that includes a real column (defined as float(24)), the column is represented as float in the generated schema dump. However, when loading this schema, the real column is converted to double precision.

# frozen_string_literal: true

require "bundler/inline"

gemfile(true) do
  source "https://rubygems.org"

  gem "rails", "7.1.4"
  gem "pg"
end

require "active_record"
require "minitest/autorun"
require "logger"

dbconfig = {
  adapter: "postgresql",
  username: "postgres",
  password: "postgres",
  host: "localhost",
  database: "migration_test"
}
ActiveRecord::Base.establish_connection(dbconfig.merge(database: "postgres"))
ActiveRecord::Base.connection.drop_database("migration_test")
ActiveRecord::Base.connection.create_database("migration_test")
ActiveRecord::Base.establish_connection(dbconfig)

ActiveRecord::Base.logger = Logger.new(STDOUT)

class CreatePaymentWithFloatColumn < ActiveRecord::Migration::Current
  def change
    create_table :payments do |t|
      t.float :amount, limit: 24
    end
  end
end

class Payment < ActiveRecord::Base
end

class BugTest < Minitest::Test
  def test_migration_up
    CreatePaymentWithFloatColumn.migrate(:up)
    Payment.reset_column_information

    assert_equal "real", Payment.columns_hash["amount"].sql_type

    io = StringIO.new
    ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, io)
    assert_includes('t.float "amount", limit: 24', io.string)
  end
end

result:

Run options: --seed 55169

# Running:

==  CreatePaymentWithFloatColumn: migrating ===================================
-- create_table(:payments)
D, [2024-08-29T17:34:22.146929 #38268] DEBUG -- :    (2.8ms)  CREATE TABLE "payments" ("id" bigserial primary key, "amount" float(24))
   -> 0.0187s
==  CreatePaymentWithFloatColumn: migrated (0.0187s) ==========================

F

Finished in 0.036045s, 27.7431 runs/s, 83.2293 assertions/s.

  1) Failure:
BugTest#test_migration_up [migration_test.rb:50]:
Expected "t.float \"amount\", limit: 24" to include "# This file is auto-generated from the current state of the database. Instead\n# of editing this file, please use the migrations feature of Active Record to\n# incrementally modify your database, and then regenerate this schema definition.\n#\n# This file is the source Rails uses to define your schema when running `bin/rails\n# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to\n# be faster and is potentially less error prone than running all of your\n# migrations from scratch. Old migrations may fail to apply correctly if those\n# migrations use external dependencies or application code.\n#\n# It's strongly recommended that you check this file into your version control system.\n\nActiveRecord::Schema[7.2].define(version: 0) do\n  # These are extensions that must be enabled in order to support this database\n  enable_extension \"plpgsql\"\n\n  create_table \"payments\", force: :cascade do |t|\n    t.float \"amount\"\n  end\nend\n".

1 runs, 3 assertions, 1 failures, 0 errors, 0 skips

Expected behavior

A real column defined in a PostgreSQL schema should be preserved as a real column when dumped and loaded.

see: https://www.postgresql.org/docs/14/datatype-numeric.html#DATATYPE-FLOAT

PostgreSQL also supports the SQL-standard notations float and float(p) for specifying inexact numeric types. Here, p specifies the minimum acceptable precision in binary digits. PostgreSQL accepts float(1) to float(24) as selecting the real type, while float(25) to float(53) select double precision. Values of p outside the allowed range draw an error. float with no precision specified is taken to mean double precision.

Actual behavior

The current behavior results in a conversion from real to double precision during the dump and load process.

System configuration

Rails version: 7.1.4

Ruby version: 3.3.4

PostgreSQL version: 14.7

tnagatomi added a commit to tnagatomi/rails that referenced this issue Sep 30, 2024

Verified

This commit was signed with the committer’s verified signature.
tnagatomi Takayuki Nagatomi
Fixes rails#52742

Co-authored-by: Ryota Kitazawa <krororo.07@gmail.com>
tnagatomi added a commit to tnagatomi/rails that referenced this issue Sep 30, 2024

Verified

This commit was signed with the committer’s verified signature.
tnagatomi Takayuki Nagatomi
Fixes rails#52742

Co-authored-by: Ryota Kitazawa <krororo.07@gmail.com>
tnagatomi added a commit to tnagatomi/rails that referenced this issue Sep 30, 2024

Verified

This commit was signed with the committer’s verified signature.
tnagatomi Takayuki Nagatomi
Fixes rails#52742

Co-authored-by: Ryota Kitazawa <krororo.07@gmail.com>
DanielaVelasquez pushed a commit to DanielaVelasquez/rails that referenced this issue Oct 3, 2024
Fixes rails#52742

Co-authored-by: Ryota Kitazawa <krororo.07@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants