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

Code before:
        NOT_NULL_VIOLATION    = "23502"
        FOREIGN_KEY_VIOLATION = "23503"
        UNIQUE_VIOLATION      = "23505"
        SERIALIZATION_FAILURE = "40001"
        DEADLOCK_DETECTED     = "40P01"
        DUPLICATE_DATABASE    = "42P04"
        LOCK_NOT_AVAILABLE    = "55P03"
        QUERY_CANCELED        = "57014"

        def translate_exception(exception, message:, sql:, binds:)
          return exception unless exception.respond_to?(:result)

          case exception.result.try(:error_field, PG::PG_DIAG_SQLSTATE)
          when nil
            if exception.message.match?(/connection is closed/i) || exception.message.match?(/no connection to the server/i)
              ConnectionNotEstablished.new(exception, connection_pool: @pool)
            elsif exception.is_a?(PG::ConnectionBad)
              # libpq message style always ends with a newline; the pg gem's internal
              # errors do not. We separate these cases because a pg-internal
              # ConnectionBad means it failed before it managed to send the query,
              # whereas a libpq failure could have occurred at any time (meaning the
              # server may have already executed part or all of the query).
              if exception.message.end_with?("\n")
                ConnectionFailed.new(exception, connection_pool: @pool)
              else
                message = if exception.message.match?(/can't get server version/i)
                  "Could not determine PostgreSQL version"
                else
                  exception.message
                end
                ConnectionNotEstablished.new(message, connection_pool: @pool)
              end
            else
              super
            end
          when UNIQUE_VIOLATION
            RecordNotUnique.new(message, sql: sql, binds: binds, connection_pool: @pool)
          when FOREIGN_KEY_VIOLATION
            InvalidForeignKey.new(message, sql: sql, binds: binds, connection_pool: @pool)
          when VALUE_LIMIT_VIOLATION
            ValueTooLong.new(message, sql: sql, binds: binds, connection_pool: @pool)
          when NUMERIC_VALUE_OUT_OF_RANGE
            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)

Review comment (suggestion):
I really don't think we should be rewriting error messages here, the original message is fine

Code after:
        NOT_NULL_VIOLATION    = "23502"
        FOREIGN_KEY_VIOLATION = "23503"
        UNIQUE_VIOLATION      = "23505"
        SERIALIZATION_FAILURE = "40001"
        DEADLOCK_DETECTED     = "40P01"
        DUPLICATE_DATABASE    = "42P04"
        LOCK_NOT_AVAILABLE    = "55P03"
        QUERY_CANCELED        = "57014"

        def translate_exception(exception, message:, sql:, binds:)
          return exception unless exception.respond_to?(:result)

          case exception.result.try(:error_field, PG::PG_DIAG_SQLSTATE)
          when nil
            if exception.message.match?(/connection is closed/i) || exception.message.match?(/no connection to the server/i)
              ConnectionNotEstablished.new(exception, connection_pool: @pool)
            elsif exception.is_a?(PG::ConnectionBad)
              # libpq message style always ends with a newline; the pg gem's internal
              # errors do not. We separate these cases because a pg-internal
              # ConnectionBad means it failed before it managed to send the query,
              # whereas a libpq failure could have occurred at any time (meaning the
              # server may have already executed part or all of the query).
              if exception.message.end_with?("\n")
                ConnectionFailed.new(exception, connection_pool: @pool)
              else
                ConnectionNotEstablished.new(exception, connection_pool: @pool)
              end
            else
              super
            end
          when UNIQUE_VIOLATION
            RecordNotUnique.new(message, sql: sql, binds: binds, connection_pool: @pool)
          when FOREIGN_KEY_VIOLATION
            InvalidForeignKey.new(message, sql: sql, binds: binds, connection_pool: @pool)
          when VALUE_LIMIT_VIOLATION
            ValueTooLong.new(message, sql: sql, binds: binds, connection_pool: @pool)
          when NUMERIC_VALUE_OUT_OF_RANGE
            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