Skip to content

Commit 86ec289

Browse files
authored
Fix Postgres JSON literal escaping (#740)
1 parent 04191cb commit 86ec289

2 files changed

Lines changed: 24 additions & 6 deletions

File tree

lib/ecto/adapters/postgres/connection.ex

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2023,12 +2023,10 @@ if Code.ensure_loaded?(Postgrex) do
20232023
end
20242024

20252025
defp escape_json(value) when is_binary(value) do
2026-
escaped =
2027-
value
2028-
|> escape_string()
2029-
|> :binary.replace("\"", "\\\"", [:global])
2030-
2031-
[?", escaped, ?"]
2026+
value
2027+
|> json_library().encode_to_iodata!()
2028+
|> IO.iodata_to_binary()
2029+
|> escape_string()
20322030
end
20332031

20342032
defp escape_json(value) when is_integer(value) do
@@ -2038,6 +2036,10 @@ if Code.ensure_loaded?(Postgrex) do
20382036
defp escape_json(true), do: ["true"]
20392037
defp escape_json(false), do: ["false"]
20402038

2039+
defp json_library do
2040+
Application.get_env(:postgrex, :json_library, Jason)
2041+
end
2042+
20412043
# To allow columns in json paths, we use the array[...] syntax
20422044
# which requires special handling for strings and column references.
20432045
# We still keep the escape_json/1 variant for strings because it is

test/ecto/adapters/postgres_test.exs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1011,6 +1011,22 @@ defmodule Ecto.Adapters.PostgresTest do
10111011
query = Schema |> where([s], s.meta["id"] == "123") |> select(true) |> plan()
10121012
assert all(query) == ~s|SELECT TRUE FROM "schema" AS s0 WHERE ((s0."meta"@>'{"id": "123"}'))|
10131013

1014+
query = Schema |> where([s], s.meta["k"] == "a\\b") |> select(true) |> plan()
1015+
assert all(query) == ~S|SELECT TRUE FROM "schema" AS s0 WHERE ((s0."meta"@>'{"k": "a\\b"}'))|
1016+
1017+
query = Schema |> where([s], s.meta["k"] == "l1\nl2") |> select(true) |> plan()
1018+
1019+
assert all(query) ==
1020+
~S|SELECT TRUE FROM "schema" AS s0 WHERE ((s0."meta"@>'{"k": "l1\nl2"}'))|
1021+
1022+
query = Schema |> where([s], s.meta["k"] == "a\\q") |> select(true) |> plan()
1023+
assert all(query) == ~S|SELECT TRUE FROM "schema" AS s0 WHERE ((s0."meta"@>'{"k": "a\\q"}'))|
1024+
1025+
query = Schema |> where([s], s.meta["a\\b"] == "value") |> select(true) |> plan()
1026+
1027+
assert all(query) ==
1028+
~S|SELECT TRUE FROM "schema" AS s0 WHERE ((s0."meta"@>'{"a\\b": "value"}'))|
1029+
10141030
query = Schema |> where([s], s.meta["tags"][0]["name"] == "123") |> select(true) |> plan()
10151031

10161032
assert all(query) ==

0 commit comments

Comments
 (0)