pair_match = HSTORE_PAIR_RE.match(hstore_str)
while pair_match is not None:
- key = pair_match.group('key')
+ key = pair_match.group('key').replace(r'\"', '"').replace("\\\\", "\\")
if pair_match.group('value_null'):
value = None
else:
- value = pair_match.group('value').replace(r'\"', '"')
+ value = pair_match.group('value').replace(r'\"', '"').replace("\\\\", "\\")
result[key] = value
pos += pair_match.end()
if position == 'value' and s is None:
return 'NULL'
elif isinstance(s, basestring):
- return '"%s"' % s.replace('"', r'\"')
+ return '"%s"' % s.replace("\\", "\\\\").replace('"', r'\"')
else:
raise ValueError("%r in %s position is not a string." %
(s, position))
'"key1"=>"value1", "key2"=>"value2"'
)
+ def test_bind_serialize_with_slashes_and_quotes(self):
+ from sqlalchemy.engine import default
+
+ dialect = default.DefaultDialect()
+ proc = self.test_table.c.hash.type._cached_bind_processor(dialect)
+ eq_(
+ proc({'\\"a': '\\"1'}),
+ '"\\\\\\"a"=>"\\\\\\"1"'
+ )
+
def test_parse_error(self):
from sqlalchemy.engine import default
{"key1": "value1", "key2": "value2"}
)
+ def test_result_deserialize_with_slashes_and_quotes(self):
+ from sqlalchemy.engine import default
+
+ dialect = default.DefaultDialect()
+ proc = self.test_table.c.hash.type._cached_result_processor(
+ dialect, None)
+ eq_(
+ proc('"\\\\\\"a"=>"\\\\\\"1"'),
+ {'\\"a': '\\"1'}
+ )
+
def test_bind_serialize_psycopg2(self):
from sqlalchemy.dialects.postgresql import psycopg2
engine = testing.db
self._test_unicode_round_trip(engine)
+ def test_escaped_quotes_round_trip_python(self):
+ engine = self._non_native_engine()
+ self._test_escaped_quotes_round_trip(engine)
+
+ @testing.only_on("postgresql+psycopg2")
+ def test_escaped_quotes_round_trip_native(self):
+ engine = testing.db
+ self._test_escaped_quotes_round_trip(engine)
+
+ def _test_escaped_quotes_round_trip(self, engine):
+ engine.execute(
+ self.tables.data_table.insert(),
+ {'name': 'r1', 'data': {r'key \"foo\"': r'value \"bar"\ xyz'}}
+ )
+ self._assert_data([{r'key \"foo\"': r'value \"bar"\ xyz'}])
+
class _RangeTypeMixin(object):
__requires__ = 'range_types',
__dialect__ = 'postgresql+psycopg2'