mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Merge pull request #9207 from dylanahsmith/mysql-quote-numeric
active_record: Quote numeric values compared to string columns.
This commit is contained in:
commit
408227d9c5
8 changed files with 60 additions and 14 deletions
|
@ -1,5 +1,15 @@
|
|||
## Rails 4.0.0 (unreleased) ##
|
||||
|
||||
* Quote numeric values being compared to non-numeric columns. Otherwise,
|
||||
in some database, the string column values will be coerced to a numeric
|
||||
allowing 0, 0.0 or false to match any string starting with a non-digit.
|
||||
|
||||
Example:
|
||||
|
||||
App.where(apikey: 0) # => SELECT * FROM users WHERE apikey = '0'
|
||||
|
||||
*Dylan Smith*
|
||||
|
||||
* Schema dumper supports dumping the enabled database extensions to `schema.rb`
|
||||
(currently only supported by postgresql).
|
||||
|
||||
|
|
|
@ -25,13 +25,19 @@ module ActiveRecord
|
|||
when true, false
|
||||
if column && column.type == :integer
|
||||
value ? '1' : '0'
|
||||
elsif column && [:text, :string, :binary].include?(column.type)
|
||||
value ? "'1'" : "'0'"
|
||||
else
|
||||
value ? quoted_true : quoted_false
|
||||
end
|
||||
# BigDecimals need to be put in a non-normalized form and quoted.
|
||||
when nil then "NULL"
|
||||
when BigDecimal then value.to_s('F')
|
||||
when Numeric, ActiveSupport::Duration then value.to_s
|
||||
when Numeric, ActiveSupport::Duration
|
||||
value = BigDecimal === value ? value.to_s('F') : value.to_s
|
||||
if column && ![:integer, :float, :decimal].include?(column.type)
|
||||
value = "'#{value}'"
|
||||
end
|
||||
value
|
||||
when Date, Time then "'#{quoted_date(value)}'"
|
||||
when Symbol then "'#{quote_string(value.to_s)}'"
|
||||
when Class then "'#{value.to_s}'"
|
||||
|
|
|
@ -212,8 +212,6 @@ module ActiveRecord
|
|||
if value.kind_of?(String) && column && column.type == :binary && column.class.respond_to?(:string_to_binary)
|
||||
s = column.class.string_to_binary(value).unpack("H*")[0]
|
||||
"x'#{s}'"
|
||||
elsif value.kind_of?(BigDecimal)
|
||||
value.to_s("F")
|
||||
else
|
||||
super
|
||||
end
|
||||
|
|
|
@ -98,6 +98,11 @@ module ActiveRecord
|
|||
when Class
|
||||
# FIXME: I think we need to deprecate this behavior
|
||||
attribute.eq(value.name)
|
||||
when Integer, ActiveSupport::Duration
|
||||
# Arel treats integers as literals, but they should be quoted when compared with strings
|
||||
table = attribute.relation
|
||||
column = table.engine.connection.schema_cache.columns_hash(table.name)[attribute.name.to_s]
|
||||
attribute.eq(Arel::Nodes::SqlLiteral.new(table.engine.connection.quote(value, column)))
|
||||
else
|
||||
attribute.eq(value)
|
||||
end
|
||||
|
|
|
@ -122,35 +122,35 @@ module ActiveRecord
|
|||
def test_quote_float
|
||||
float = 1.2
|
||||
assert_equal float.to_s, @quoter.quote(float, nil)
|
||||
assert_equal float.to_s, @quoter.quote(float, Object.new)
|
||||
assert_equal float.to_s, @quoter.quote(float, FakeColumn.new(:float))
|
||||
end
|
||||
|
||||
def test_quote_fixnum
|
||||
fixnum = 1
|
||||
assert_equal fixnum.to_s, @quoter.quote(fixnum, nil)
|
||||
assert_equal fixnum.to_s, @quoter.quote(fixnum, Object.new)
|
||||
assert_equal fixnum.to_s, @quoter.quote(fixnum, FakeColumn.new(:integer))
|
||||
end
|
||||
|
||||
def test_quote_bignum
|
||||
bignum = 1 << 100
|
||||
assert_equal bignum.to_s, @quoter.quote(bignum, nil)
|
||||
assert_equal bignum.to_s, @quoter.quote(bignum, Object.new)
|
||||
assert_equal bignum.to_s, @quoter.quote(bignum, FakeColumn.new(:integer))
|
||||
end
|
||||
|
||||
def test_quote_bigdecimal
|
||||
bigdec = BigDecimal.new((1 << 100).to_s)
|
||||
assert_equal bigdec.to_s('F'), @quoter.quote(bigdec, nil)
|
||||
assert_equal bigdec.to_s('F'), @quoter.quote(bigdec, Object.new)
|
||||
assert_equal bigdec.to_s('F'), @quoter.quote(bigdec, FakeColumn.new(:decimal))
|
||||
end
|
||||
|
||||
def test_dates_and_times
|
||||
@quoter.extend(Module.new { def quoted_date(value) 'lol' end })
|
||||
assert_equal "'lol'", @quoter.quote(Date.today, nil)
|
||||
assert_equal "'lol'", @quoter.quote(Date.today, Object.new)
|
||||
assert_equal "'lol'", @quoter.quote(Date.today, FakeColumn.new(:date))
|
||||
assert_equal "'lol'", @quoter.quote(Time.now, nil)
|
||||
assert_equal "'lol'", @quoter.quote(Time.now, Object.new)
|
||||
assert_equal "'lol'", @quoter.quote(Time.now, FakeColumn.new(:time))
|
||||
assert_equal "'lol'", @quoter.quote(DateTime.now, nil)
|
||||
assert_equal "'lol'", @quoter.quote(DateTime.now, Object.new)
|
||||
assert_equal "'lol'", @quoter.quote(DateTime.now, FakeColumn.new(:datetime))
|
||||
end
|
||||
|
||||
def test_crazy_object
|
||||
|
|
|
@ -108,5 +108,30 @@ module ActiveRecord
|
|||
assert_equal 4, Edge.where(blank).order("sink_id").to_a.size
|
||||
end
|
||||
end
|
||||
|
||||
def test_where_with_integer_for_string_column
|
||||
count = Post.where(:title => 0).count
|
||||
assert_equal 0, count
|
||||
end
|
||||
|
||||
def test_where_with_float_for_string_column
|
||||
count = Post.where(:title => 0.0).count
|
||||
assert_equal 0, count
|
||||
end
|
||||
|
||||
def test_where_with_boolean_for_string_column
|
||||
count = Post.where(:title => false).count
|
||||
assert_equal 0, count
|
||||
end
|
||||
|
||||
def test_where_with_decimal_for_string_column
|
||||
count = Post.where(:title => BigDecimal.new(0)).count
|
||||
assert_equal 0, count
|
||||
end
|
||||
|
||||
def test_where_with_duration_for_string_column
|
||||
count = Post.where(:title => 0.seconds).count
|
||||
assert_equal 0, count
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -391,19 +391,19 @@ class DefaultScopingTest < ActiveRecord::TestCase
|
|||
def test_default_scope_with_inheritance
|
||||
wheres = InheritedPoorDeveloperCalledJamis.all.where_values_hash
|
||||
assert_equal "Jamis", wheres[:name]
|
||||
assert_equal 50000, wheres[:salary]
|
||||
assert_equal Arel.sql("50000"), wheres[:salary]
|
||||
end
|
||||
|
||||
def test_default_scope_with_module_includes
|
||||
wheres = ModuleIncludedPoorDeveloperCalledJamis.all.where_values_hash
|
||||
assert_equal "Jamis", wheres[:name]
|
||||
assert_equal 50000, wheres[:salary]
|
||||
assert_equal Arel.sql("50000"), wheres[:salary]
|
||||
end
|
||||
|
||||
def test_default_scope_with_multiple_calls
|
||||
wheres = MultiplePoorDeveloperCalledJamis.all.where_values_hash
|
||||
assert_equal "Jamis", wheres[:name]
|
||||
assert_equal 50000, wheres[:salary]
|
||||
assert_equal Arel.sql("50000"), wheres[:salary]
|
||||
end
|
||||
|
||||
def test_scope_overwrites_default
|
||||
|
|
|
@ -540,6 +540,8 @@ ActiveRecord::Schema.define do
|
|||
create_table :price_estimates, :force => true do |t|
|
||||
t.string :estimate_of_type
|
||||
t.integer :estimate_of_id
|
||||
t.string :thing_type
|
||||
t.integer :thing_id
|
||||
t.integer :price
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in a new issue