rails icon indicating copy to clipboard operation
rails copied to clipboard

`ConnectionNotEstablished` when accessing column data with `check_schema_cache_dump_version = false` on postgres

Open Earlopain opened this issue 6 months ago • 5 comments

Steps to reproduce

I started looking into the schema cache functionality that Rails offers. When loading the cache and setting check_schema_cache_dump_version to false, accessing column information still queries the database somewhere.

This is not the case on main anymore. Perhaps because of #49378, #49415 or similar work that has been done in that regard.

# frozen_string_literal: true

require "bundler/inline"

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

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

  # Activate the gem you are reporting the issue against.
  gem "rails", github: "rails/rails", branch: "main"
  gem "pg"
end

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

class TestApp < Rails::Application
  config.load_defaults 7.1
  config.eager_load = false
  config.root = __dir__

  config.logger = Logger.new($stdout)
  Rails.logger  = config.logger

  config.active_record.check_schema_cache_dump_version = false
end

schema_yml = <<~YML
  --- !ruby/object:ActiveRecord::ConnectionAdapters::SchemaCache
  columns:
    ar_internal_metadata:
    - !ruby/object:ActiveRecord::ConnectionAdapters::PostgreSQL::Column
      serial:
      generated: ''
      name: key
      sql_type_metadata: &1 !ruby/object:ActiveRecord::ConnectionAdapters::PostgreSQL::TypeMetadata
        delegate_dc_obj: !ruby/object:ActiveRecord::ConnectionAdapters::SqlTypeMetadata
          sql_type: character varying
          type: :string
          limit:
          precision:
          scale:
        oid: 1043
        fmod: -1
      'null': false
      default:
      default_function:
      collation:
      comment:
    - !ruby/object:ActiveRecord::ConnectionAdapters::PostgreSQL::Column
      serial:
      generated: ''
      name: value
      sql_type_metadata: *1
      'null': true
      default:
      default_function:
      collation:
      comment:
    - !ruby/object:ActiveRecord::ConnectionAdapters::PostgreSQL::Column
      serial:
      generated: ''
      name: created_at
      sql_type_metadata: &2 !ruby/object:ActiveRecord::ConnectionAdapters::PostgreSQL::TypeMetadata
        delegate_dc_obj: !ruby/object:ActiveRecord::ConnectionAdapters::SqlTypeMetadata
          sql_type: timestamp(6) with time zone
          type: :datetime
          limit:
          precision: 6
          scale:
        oid: 1184
        fmod: 6
      'null': false
      default:
      default_function:
      collation:
      comment:
    - !ruby/object:ActiveRecord::ConnectionAdapters::PostgreSQL::Column
      serial:
      generated: ''
      name: updated_at
      sql_type_metadata: *2
      'null': false
      default:
      default_function:
      collation:
      comment:
    posts:
    - !ruby/object:ActiveRecord::ConnectionAdapters::PostgreSQL::Column
      serial: true
      generated: ''
      name: id
      sql_type_metadata: !ruby/object:ActiveRecord::ConnectionAdapters::PostgreSQL::TypeMetadata
        delegate_dc_obj: !ruby/object:ActiveRecord::ConnectionAdapters::SqlTypeMetadata
          sql_type: bigint
          type: :integer
          limit: 8
          precision:
          scale:
        oid: 20
        fmod: -1
      'null': false
      default:
      default_function: nextval('posts_id_seq'::regclass)
      collation:
      comment:
    schema_migrations:
    - !ruby/object:ActiveRecord::ConnectionAdapters::PostgreSQL::Column
      serial:
      generated: ''
      name: version
      sql_type_metadata: *1
      'null': false
      default:
      default_function:
      collation:
      comment:
  primary_keys:
    ar_internal_metadata: key
    posts: id
    schema_migrations: version
  data_sources:
    ar_internal_metadata: true
    posts: true
    schema_migrations: true
  indexes:
    ar_internal_metadata: []
    posts: []
    schema_migrations: []
  version: 20230922142507
  database_version: 150004
YML

file = Tempfile.new(["schema" ".yml"])
file.write(schema_yml)
file.rewind

ENV["DATABASE_URL"] = "postgresql://localhost:5432/doesnt_exist"
Rails.application.initialize!

class Post < ActiveRecord::Base
end

cache = ActiveRecord::ConnectionAdapters::SchemaCache._load_from(file.path)
ActiveRecord::Base.connection_pool.schema_reflection.instance_variable_set(:@cache, cache)

require "active_record/testing/query_assertions"

class BugTest < ActiveSupport::TestCase
  include ActiveRecord::Assertions::QueryAssertions

  def test_accessing_column_names_with_loaded_query_cache_makes_no_queries
    assert_nothing_raised do
      assert_no_queries do
        assert_equal(["id"], Post.column_names)
      end
    end
  end

  def test_accessing_default_attributes_with_loaded_query_cache_makes_no_queries
    assert_nothing_raised do
      assert_no_queries do
        assert_equal(["id"], Post._default_attributes.keys)
      end
    end
  end

  def test_instantiating_activerecord_class_with_loaded_query_cache_makes_no_queries
    assert_nothing_raised do
      assert_no_queries do
        assert_nil Post.new
      end
    end
  end
end

Expected behavior

No attempted connection to the database.

Actual behavior

Attempted connection to the database.

System configuration

Rails version: 7.1.1

Ruby version: 3.2.2

Earlopain avatar Oct 17 '23 14:10 Earlopain