Skip to content

Commit 802914d

Browse files
Allow MyXQL to specify :prepare per operation. (#650)
1 parent 6345716 commit 802914d

File tree

2 files changed

+62
-0
lines changed

2 files changed

+62
-0
lines changed
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
defmodule Ecto.Integration.PrepareTest do
2+
use Ecto.Integration.Case, async: false
3+
4+
import Ecto.Query, only: [from: 2]
5+
6+
alias Ecto.Integration.TestRepo
7+
alias Ecto.Integration.Post
8+
9+
test "prepare option" do
10+
TestRepo.insert!(%Post{title: "one"})
11+
12+
query = from p in Post, select: fragment("'mxql test prepare option'")
13+
stmt_count_query = "SHOW GLOBAL STATUS LIKE '%prepared_stmt_count%'"
14+
15+
%{rows: [[_, orig_count]]} = TestRepo.query!(stmt_count_query, [])
16+
orig_count = String.to_integer(orig_count)
17+
18+
# Uncached
19+
assert TestRepo.all(query, prepare: :unnamed) == ["mxql test prepare option"]
20+
%{rows: [[_, new_count]]} = TestRepo.query!(stmt_count_query, [])
21+
assert String.to_integer(new_count) == orig_count
22+
23+
assert TestRepo.all(query, prepare: :named) == ["mxql test prepare option"]
24+
assert %{rows: [[_, new_count]]} = TestRepo.query!(stmt_count_query, [])
25+
assert String.to_integer(new_count) == orig_count + 1
26+
27+
# Cached
28+
assert TestRepo.all(query, prepare: :unnamed) == ["mxql test prepare option"]
29+
assert %{rows: [[_, new_count]]} = TestRepo.query!(stmt_count_query, [])
30+
assert String.to_integer(new_count) == orig_count + 1
31+
32+
assert TestRepo.all(query, prepare: :named) == ["mxql test prepare option"]
33+
assert %{rows: [[_, new_count]]} = TestRepo.query!(stmt_count_query, [])
34+
assert String.to_integer(new_count) == orig_count + 1
35+
end
36+
end

lib/ecto/adapters/myxql.ex

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,13 @@ defmodule Ecto.Adapters.MyXQL do
1010
below. All options can be given via the repository
1111
configuration:
1212
13+
config :your_app, YourApp.Repo,
14+
...
15+
16+
The `:prepare` option may be specified per operation:
17+
18+
YourApp.Repo.all(Queryable, prepare: :unnamed)
19+
1320
### Connection options
1421
1522
* `:protocol` - Set to `:socket` for using UNIX domain socket, or `:tcp` for TCP
@@ -147,6 +154,8 @@ defmodule Ecto.Adapters.MyXQL do
147154
@behaviour Ecto.Adapter.Storage
148155
@behaviour Ecto.Adapter.Structure
149156

157+
@default_prepare_opt :named
158+
150159
## Custom MySQL types
151160

152161
@impl true
@@ -171,6 +180,23 @@ defmodule Ecto.Adapters.MyXQL do
171180
defp json_decode(x) when is_binary(x), do: {:ok, MyXQL.json_library().decode!(x)}
172181
defp json_decode(x), do: {:ok, x}
173182

183+
## Query API
184+
185+
@impl Ecto.Adapter.Queryable
186+
def execute(adapter_meta, query_meta, query, params, opts) do
187+
prepare = Keyword.get(opts, :prepare, @default_prepare_opt)
188+
189+
unless valid_prepare?(prepare) do
190+
raise ArgumentError,
191+
"expected option `:prepare` to be either `:named` or `:unnamed`, got: #{inspect(prepare)}"
192+
end
193+
194+
Ecto.Adapters.SQL.execute(prepare, adapter_meta, query_meta, query, params, opts)
195+
end
196+
197+
defp valid_prepare?(prepare) when prepare in [:named, :unnamed], do: true
198+
defp valid_prepare?(_), do: false
199+
174200
## Storage API
175201

176202
@impl true

0 commit comments

Comments
 (0)