Repository: rails/rails
File: activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb (Ruby)

Code before:
            RangeError.new(message, sql: sql, binds: binds, connection_pool: @pool)
          when NOT_NULL_VIOLATION
            NotNullViolation.new(message, sql: sql, binds: binds, connection_pool: @pool)
          when SERIALIZATION_FAILURE
            SerializationFailure.new(message, sql: sql, binds: binds, connection_pool: @pool)
          when DEADLOCK_DETECTED
            Deadlocked.new(message, sql: sql, binds: binds, connection_pool: @pool)
          when DUPLICATE_DATABASE
            DatabaseAlreadyExists.new(message, sql: sql, binds: binds, connection_pool: @pool)
          when LOCK_NOT_AVAILABLE
            LockWaitTimeout.new(message, sql: sql, binds: binds, connection_pool: @pool)
          when QUERY_CANCELED
            QueryCanceled.new(message, sql: sql, binds: binds, connection_pool: @pool)
          else
            super
          end
        end

        def retryable_query_error?(exception)
          # We cannot retry anything if we're inside a broken transaction; we need to at
          # least raise until the innermost savepoint is rolled back
          @raw_connection&.transaction_status != ::PG::PQTRANS_INERROR &&
            super
        # If the connection is closed, defer to super
        rescue PG::ConnectionBad
          super
        end

        def get_oid_type(oid, fmod, column_name, sql_type = "")
          if !type_map.key?(oid)
            load_additional_types([oid])
          end

          type_map.fetch(oid, fmod, sql_type) {
            warn "unknown OID #{oid}: failed to recognize type of '#{column_name}'. It will be treated as String."
            Type.default_value.tap do |cast_type|
              type_map.register_type(oid, cast_type)
            end
          }
        end

        def load_additional_types(oids = nil)
          initializer = OID::TypeMapInitializer.new(type_map)
          load_types_queries(initializer, oids) do |query|
            records = internal_execute(query, "SCHEMA", [], allow_retry: true, materialize_transactions: false)
            initializer.run(records)
          end
        end

        def load_types_queries(initializer, oids)
          query = <<~SQL

Review comment (bug):
```suggestion
          in_transaction = begin
            @raw_connection&.transaction_status == ::PG::PQTRANS_INERROR
          rescue PG::ConnectionBad
            false
          end
          !in_transaction && super
```

We should scope the `rescue` to `transaction_status` specifically. Because we don't know what super does, so if somehow it raises `rescue PG::ConnectionBad` that will end up in a catastrophic infinite loop.

Code after:
            RangeError.new(message, sql: sql, binds: binds, connection_pool: @pool)
          when NOT_NULL_VIOLATION
            NotNullViolation.new(message, sql: sql, binds: binds, connection_pool: @pool)
          when SERIALIZATION_FAILURE
            SerializationFailure.new(message, sql: sql, binds: binds, connection_pool: @pool)
          when DEADLOCK_DETECTED
            Deadlocked.new(message, sql: sql, binds: binds, connection_pool: @pool)
          when DUPLICATE_DATABASE
            DatabaseAlreadyExists.new(message, sql: sql, binds: binds, connection_pool: @pool)
          when LOCK_NOT_AVAILABLE
            LockWaitTimeout.new(message, sql: sql, binds: binds, connection_pool: @pool)
          when QUERY_CANCELED
            QueryCanceled.new(message, sql: sql, binds: binds, connection_pool: @pool)
          else
            super
          end
        end

        def retryable_query_error?(exception)
          # We cannot retry anything if we're inside a broken transaction; we need to at
          # least raise until the innermost savepoint is rolled back
          in_transaction = begin
            @raw_connection&.transaction_status == ::PG::PQTRANS_INERROR
          rescue PG::ConnectionBad
            false
          end
          !in_transaction && super
        end

        def get_oid_type(oid, fmod, column_name, sql_type = "")
          if !type_map.key?(oid)
            load_additional_types([oid])
          end

          type_map.fetch(oid, fmod, sql_type) {
            warn "unknown OID #{oid}: failed to recognize type of '#{column_name}'. It will be treated as String."
            Type.default_value.tap do |cast_type|
              type_map.register_type(oid, cast_type)
            end
          }
        end

        def load_additional_types(oids = nil)
          initializer = OID::TypeMapInitializer.new(type_map)
          load_types_queries(initializer, oids) do |query|
            records = internal_execute(query, "SCHEMA", [], allow_retry: true, materialize_transactions: false)
            initializer.run(records)
          end
        end

        def load_types_queries(initializer, oids)