Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge pull request #14078 from gsamokovarov/hstore_arrays_fix_4_0

Backport #13512 to 4.0 stable
  • Loading branch information...
commit ad84512f89b4da69d787f2574a3a5e93945005b5 2 parents 0ea8e5f + d96d7e8
@guilleiguaran guilleiguaran authored
View
6 activerecord/CHANGELOG.md
@@ -1,3 +1,9 @@
+* Perform necessary deeper encoding when hstore is inside an array.
+
+ Fixes #11135.
+
+ *Josh Goodall*, *Genadi Samokovarov*
+
* Properly detect if a connection is still active before using it
in multi-threaded environments.
View
12 activerecord/lib/active_record/connection_adapters/postgresql/cast.rb
@@ -35,11 +35,11 @@ def string_to_bit(value)
end
end
- def hstore_to_string(object)
+ def hstore_to_string(object, array_member = false)
if Hash === object
- object.map { |k,v|
- "#{escape_hstore(k)}=>#{escape_hstore(v)}"
- }.join ','
+ string = object.map { |k, v| "#{escape_hstore(k)}=>#{escape_hstore(v)}" }.join(',')
+ string = escape_hstore(string) if array_member
+ string
else
object
end
@@ -49,10 +49,10 @@ def string_to_hstore(string)
if string.nil?
nil
elsif String === string
- Hash[string.scan(HstorePair).map { |k,v|
+ Hash[string.scan(HstorePair).map { |k, v|
v = v.upcase == 'NULL' ? nil : v.gsub(/\A"(.*)"\Z/m,'\1').gsub(/\\(.)/, '\1')
k = k.gsub(/\A"(.*)"\Z/m,'\1').gsub(/\\(.)/, '\1')
- [k,v]
+ [k, v]
}]
else
string
View
2  activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb
@@ -109,7 +109,7 @@ def type_cast(value, column, array_member = false)
{ :value => value, :format => 1 }
when Hash
case column.sql_type
- when 'hstore' then PostgreSQLColumn.hstore_to_string(value)
+ when 'hstore' then PostgreSQLColumn.hstore_to_string(value, array_member)
when 'json' then PostgreSQLColumn.json_to_string(value)
else super(value, column)
end
View
67 activerecord/test/cases/adapters/postgresql/hstore_test.rb
@@ -26,6 +26,7 @@ def setup
@connection.transaction do
@connection.create_table('hstores') do |t|
t.hstore 'tags', :default => ''
+ t.hstore 'payload', array: true
end
end
@column = Hstore.columns.find { |c| c.name == 'tags' }
@@ -152,13 +153,36 @@ def test_rewrite
assert x.save!
end
-
def test_select
@connection.execute "insert into hstores (tags) VALUES ('1=>2')"
x = Hstore.first
assert_equal({'1' => '2'}, x.tags)
end
+ def test_array_cycle
+ assert_array_cycle([{"AA" => "BB", "CC" => "DD"}, {"AA" => nil}])
+ end
+
+ def test_array_strings_with_quotes
+ assert_array_cycle([{'this has' => 'some "s that need to be escaped"'}])
+ end
+
+ def test_array_strings_with_commas
+ assert_array_cycle([{'this,has' => 'many,values'}])
+ end
+
+ def test_array_strings_with_array_delimiters
+ assert_array_cycle(['{' => '}'])
+ end
+
+ def test_array_strings_with_null_strings
+ assert_array_cycle([{'NULL' => 'NULL'}])
+ end
+
+ def test_contains_nils
+ assert_array_cycle([{'NULL' => nil}])
+ end
+
def test_select_multikey
@connection.execute "insert into hstores (tags) VALUES ('1=>2,2=>3')"
x = Hstore.first
@@ -212,17 +236,32 @@ def test_update_all
end
private
- def assert_cycle hash
- # test creation
- x = Hstore.create!(:tags => hash)
- x.reload
- assert_equal(hash, x.tags)
-
- # test updating
- x = Hstore.create!(:tags => {})
- x.tags = hash
- x.save!
- x.reload
- assert_equal(hash, x.tags)
- end
+
+ def assert_array_cycle(array)
+ # test creation
+ x = Hstore.create!(payload: array)
+ x.reload
+ assert_equal(array, x.payload)
+
+ # test updating
+ x = Hstore.create!(payload: [])
+ x.payload = array
+ x.save!
+ x.reload
+ assert_equal(array, x.payload)
+ end
+
+ def assert_cycle(hash)
+ # test creation
+ x = Hstore.create!(:tags => hash)
+ x.reload
+ assert_equal(hash, x.tags)
+
+ # test updating
+ x = Hstore.create!(:tags => {})
+ x.tags = hash
+ x.save!
+ x.reload
+ assert_equal(hash, x.tags)
+ end
end
Please sign in to comment.
Something went wrong with that request. Please try again.