Revert "Quote binary strings in Arel"

This commit is contained in:
Matthew Draper 2023-03-15 19:50:50 +10:30 committed by GitHub
parent 335733b858
commit bb7f3be138
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 11 additions and 87 deletions

View File

@ -46,7 +46,6 @@ module ActiveModel
def serialize(value) def serialize(value)
case value case value
when ::Numeric, ::Symbol, ActiveSupport::Duration then value.to_s when ::Numeric, ::Symbol, ActiveSupport::Duration then value.to_s
when ::String then serialize_cast_value(value)
when true then @true when true then @true
when false then @false when false then @false
else super else super
@ -54,12 +53,6 @@ module ActiveModel
end end
def serialize_cast_value(value) # :nodoc: def serialize_cast_value(value) # :nodoc:
if value&.encoding == Encoding::BINARY
# If we can treat the bytes as UTF-8 without changing them, then use UTF-8 as encoding
new_value = value.dup.force_encoding(Encoding::UTF_8)
return new_value if new_value.valid_encoding?
end
value value
end end

View File

@ -17,26 +17,6 @@ module ActiveModel
assert_same s, type.cast(s) assert_same s, type.cast(s)
assert_same s, type.deserialize(s) assert_same s, type.deserialize(s)
end end
test "leaves validly encoded strings untouched" do
s = "string with àccénts".encode(Encoding::ISO_8859_1)
type = Type::ImmutableString.new
assert_same s, type.serialize(s)
end
test "serializes valid, binary-encoded strings to UTF-8" do
s = "string with àccénts".b
type = Type::ImmutableString.new
serialized = type.serialize(s)
assert_equal Encoding::UTF_8, serialized.encoding
assert_equal s.bytes, serialized.bytes
end
test "leaves true binary data untouched" do
binary_data = "\xEE\x49\xC7".b
type = Type::ImmutableString.new
assert_same binary_data, type.serialize(binary_data)
end
end end
end end
end end

View File

@ -16,10 +16,7 @@ module ActiveRecord
when false then quoted_false when false then quoted_false
when nil then "NULL" when nil then "NULL"
# BigDecimals need to be put in a non-normalized form and quoted. # BigDecimals need to be put in a non-normalized form and quoted.
# Additionally, for Ruby 2.7, the string returned by `to_s` is ASCII-8BIT. when BigDecimal then value.to_s("F")
# We want to avoid that, as that will cause the string to be quoted as
# binary. It is safe to force the encoding to US-ASCII.
when BigDecimal then value.to_s("F").force_encoding(Encoding::US_ASCII)
when Numeric then value.to_s when Numeric then value.to_s
when Type::Binary::Data then quoted_binary(value) when Type::Binary::Data then quoted_binary(value)
when Type::Time::Value then "'#{quoted_time(value)}'" when Type::Time::Value then "'#{quoted_time(value)}'"

View File

@ -6,30 +6,14 @@ module ActiveRecord
module ConnectionAdapters module ConnectionAdapters
module MySQL module MySQL
module Quoting # :nodoc: module Quoting # :nodoc:
def quote(value)
case value
when String
if value.encoding == Encoding::BINARY
quoted_binary(value)
else
"'#{quote_string(value.to_s)}'"
end
else
super
end
end
def cast_bound_value(value) def cast_bound_value(value)
case value case value
when Rational when Rational
value.to_f.to_s value.to_f.to_s
when BigDecimal
# For Ruby 2.7, the string returned by `to_s` is ASCII-8BIT.
# We want to avoid that, as that will cause the string to be quoted as
# binary. It is safe to force the encoding to US-ASCII.
value.to_s("F").force_encoding(Encoding::US_ASCII)
when Numeric when Numeric
value.to_s value.to_s
when BigDecimal
value.to_s("F")
when true when true
"1" "1"
when false when false
@ -67,11 +51,7 @@ module ActiveRecord
end end
def quoted_binary(value) def quoted_binary(value)
if value.is_a? String "x'#{value.hex}'"
"x'#{value.unpack1("H*")}'"
else
"x'#{value.hex}'"
end
end end
def unquote_identifier(identifier) def unquote_identifier(identifier)

View File

@ -4,19 +4,6 @@ module ActiveRecord
module ConnectionAdapters module ConnectionAdapters
module SQLite3 module SQLite3
module Quoting # :nodoc: module Quoting # :nodoc:
def quote(value)
case value
when String
if value.encoding == Encoding::BINARY
quoted_binary(value)
else
"'#{quote_string(value.to_s)}'"
end
else
super
end
end
def quote_string(s) def quote_string(s)
::SQLite3::Database.quote(s) ::SQLite3::Database.quote(s)
end end
@ -39,11 +26,7 @@ module ActiveRecord
end end
def quoted_binary(value) def quoted_binary(value)
if value.is_a? String "x'#{value.hex}'"
"x'#{value.unpack1("H*")}'"
else
"x'#{value.hex}'"
end
end end
def quoted_true def quoted_true
@ -79,6 +62,12 @@ module ActiveRecord
case value case value
when BigDecimal when BigDecimal
value.to_f value.to_f
when String
if value.encoding == Encoding::ASCII_8BIT
super(value.encode(Encoding::UTF_8))
else
super
end
else else
super super
end end

View File

@ -37,19 +37,4 @@ class BinaryTest < ActiveRecord::TestCase
assert_equal data, bin.reload.data, "Reloaded data differs from original" assert_equal data, bin.reload.data, "Reloaded data differs from original"
end end
end end
unless current_adapter?(:PostgreSQLAdapter)
def test_does_not_cause_database_warnings
original_db_warnings_action = ActiveRecord.db_warnings_action
ActiveRecord.db_warnings_action = :raise
Binary.delete_all
binary_data = "\xEE\x49\xC7".b
Binary.connection.insert(Arel.sql("INSERT INTO binaries(data) VALUES(?)", binary_data))
binary = Binary.first
assert_equal binary_data, binary.data
ensure
ActiveRecord.db_warnings_action = original_db_warnings_action || :ignore
end
end
end end