Don't skip some columns in column_types on Postgres

Fixes https://github.com/rails/rails/issues/41651, by partially reverting https://github.com/rails/rails/pull/39097

I ran the same benchmark as https://github.com/rails/rails/pull/39097 and it seems like this change does not cause a perf regression.

```ruby

require "bundler/inline"

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

  git_source(:github) { |repo| "https://github.com/#{repo}.git" }

  gem "rails", path: "/Users/alex/code/rails" # github: "rails/rails", branch: "main"
  gem "sqlite3"
  gem "benchmark-ips"
end

require "active_record"

ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")

ActiveRecord::Schema.define do
  create_table :active_storage_blobs do |t|
    t.string   :key,          null: false
    t.string   :filename,     null: false
    t.string   :content_type
    t.text     :metadata
    t.string   :service_name, null: false
    t.bigint   :byte_size,    null: false
    t.string   :checksum,     null: false
    t.datetime :created_at,   null: false

    t.index [ :key ], unique: true
  end
end

class ActiveStorageBlob < ActiveRecord::Base
end

Benchmark.ips do |x|
  x.report("find_by") { ActiveStorageBlob.find_by(id: 1) }
end
```

This branch:

```
Warming up --------------------------------------
             find_by     1.940k i/100ms
Calculating -------------------------------------
             find_by     17.928k (± 4.8%) i/s -     91.180k in   5.098301s
```

Main:

```
Warming up --------------------------------------
             find_by     1.912k i/100ms
Calculating -------------------------------------
             find_by     17.961k (± 4.8%) i/s -     89.864k in   5.015252s
```
This commit is contained in:
Alex Ghiculescu 2021-08-02 18:30:51 -05:00
parent 0b5c7210af
commit 587522e696
3 changed files with 26 additions and 10 deletions

@ -55,11 +55,7 @@ def exec_query(sql, name = "SQL", binds = [], prepare: false, async: false) # :n
fields.each_with_index do |fname, i|
ftype = result.ftype i
fmod = result.fmod i
case type = get_oid_type(ftype, fmod, fname)
when Type::Integer, Type::Float, OID::Decimal, Type::String, Type::DateTime, Type::Boolean
# skip if a column has already been type casted by pg decoders
else types[fname] = type
end
types[fname] = get_oid_type(ftype, fmod, fname)
end
build_result(columns: fields, rows: result.values, column_types: types)
end

@ -1442,6 +1442,13 @@ def cast(value)
assert_equal "t.lo", topic.author_name
end
if current_adapter?(:PostgreSQLAdapter)
def test_column_types_on_queries_on_postgresql
result = ActiveRecord::Base.connection.exec_query("SELECT 1 AS test")
assert_equal ActiveModel::Type::Integer, result.column_types["test"].class
end
end
def test_typecasting_aliases
assert_equal 10, Topic.select("10 as tenderlove").first.tenderlove
end

@ -993,11 +993,24 @@ def test_pluck_functions_with_alias
end
def test_pluck_functions_without_alias
assert_equal [
[1, "The First Topic"], [2, "The Second Topic of the day"],
[3, "The Third Topic of the day"], [4, "The Fourth Topic of the day"],
[5, "The Fifth Topic of the day"]
], Topic.order(:id).pluck(
expected = if current_adapter?(:PostgreSQLAdapter)
# Postgres returns the same name for each column in the given query, so each column is named "coalesce"
# As a result Rails cannot accurately type cast each value.
# To work around this, you should use aliases in your select statement (see test_pluck_functions_with_alias).
[
["1", "The First Topic"], ["2", "The Second Topic of the day"],
["3", "The Third Topic of the day"], ["4", "The Fourth Topic of the day"],
["5", "The Fifth Topic of the day"]
]
else
[
[1, "The First Topic"], [2, "The Second Topic of the day"],
[3, "The Third Topic of the day"], [4, "The Fourth Topic of the day"],
[5, "The Fifth Topic of the day"]
]
end
assert_equal expected, Topic.order(:id).pluck(
Arel.sql("COALESCE(id, 0)"),
Arel.sql("COALESCE(title, 'untitled')")
)