Skip to content

Commit 24bd53f

Browse files
add rollback option to explain
1 parent cf5080c commit 24bd53f

File tree

3 files changed

+42
-4
lines changed

3 files changed

+42
-4
lines changed

integration_test/myxql/explain_test.exs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,5 +42,19 @@ defmodule Ecto.Integration.ExplainTest do
4242
assert Enum.member?(keys, "select_id")
4343
assert Enum.member?(keys, "table")
4444
end
45+
46+
test "explain without rolling back" do
47+
TestRepo.insert!(%Post{})
48+
assert [%Post{}] = TestRepo.all(Post)
49+
50+
{:ok, {:ok, explain}} =
51+
TestRepo.transaction(fn ->
52+
TestRepo.explain(:delete_all, Post, analyze: true, rollback: false, timeout: 20000)
53+
end)
54+
55+
assert explain =~ "DELETE"
56+
assert explain =~ "p0"
57+
assert TestRepo.all(Post) == []
58+
end
4559
end
4660
end

integration_test/pg/explain_test.exs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,4 +81,18 @@ defmodule Ecto.Integration.ExplainTest do
8181
assert explain =~ ~r/Node Type:/
8282
assert explain =~ ~r/Relation Name:/
8383
end
84+
85+
test "explain without rolling back" do
86+
TestRepo.insert!(%Post{})
87+
assert [%Post{}] = TestRepo.all(Post)
88+
89+
{:ok, {:ok, explain}} =
90+
TestRepo.transaction(fn ->
91+
TestRepo.explain(:delete_all, Post, analyze: true, rollback: false, timeout: 20000)
92+
end)
93+
94+
assert explain =~ "Delete on posts p0"
95+
assert explain =~ "cost="
96+
assert TestRepo.all(Post) == []
97+
end
8498
end

lib/ecto/adapters/sql.ex

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -434,8 +434,8 @@ defmodule Ecto.Adapters.SQL do
434434
435435
Adapter | Supported opts
436436
---------------- | --------------
437-
Postgrex | `analyze`, `verbose`, `costs`, `settings`, `buffers`, `timing`, `summary`, `format`, `plan`
438-
MyXQL | `format`
437+
Postgrex | `analyze`, `verbose`, `costs`, `settings`, `buffers`, `timing`, `summary`, `format`, `plan`, `rollback`
438+
MyXQL | `format`, `rollback`
439439
440440
All options except `format` are boolean valued and default to `false`.
441441
@@ -447,6 +447,10 @@ defmodule Ecto.Adapters.SQL do
447447
* Postgrex: `:map`, `:yaml` and `:text`
448448
* MyXQL: `:map` and `:text`
449449
450+
The `rollback` option is a boolean that controls whether the command is run inside of a transaction
451+
that is rolled back. This is useful when, for example, you'd like to use `analyze: true` on an update
452+
or delete query without modifying data. Defaults to `true`.
453+
450454
The `:plan` option in Postgrex can take the values `:custom` or `:fallback_generic`. When `:custom`
451455
is specified, the explain plan generated will consider the specific values of the query parameters
452456
that are supplied. When using `:fallback_generic`, the specific values of the query parameters will
@@ -508,10 +512,11 @@ defmodule Ecto.Adapters.SQL do
508512
def explain(repo, operation, queryable, opts \\ [])
509513

510514
def explain(repo, operation, queryable, opts) when is_atom(repo) or is_pid(repo) do
511-
explain(Ecto.Adapter.lookup_meta(repo), operation, queryable, opts)
515+
rollback? = Keyword.get(opts, :rollback, true)
516+
explain(Ecto.Adapter.lookup_meta(repo), operation, queryable, rollback?, opts)
512517
end
513518

514-
def explain(%{repo: repo} = adapter_meta, operation, queryable, opts) do
519+
def explain(%{repo: repo} = adapter_meta, operation, queryable, true, opts) do
515520
Ecto.Multi.new()
516521
|> Ecto.Multi.run(:explain, fn _, _ ->
517522
{prepared, prepared_params} = to_sql(operation, repo, queryable)
@@ -528,6 +533,11 @@ defmodule Ecto.Adapters.SQL do
528533
end
529534
end
530535

536+
def explain(%{repo: repo} = adapter_meta, operation, queryable, false, opts) do
537+
{prepared, prepared_params} = to_sql(operation, repo, queryable)
538+
sql_call(adapter_meta, :explain_query, [prepared], prepared_params, opts)
539+
end
540+
531541
@doc @disconnect_all_doc
532542
@spec disconnect_all(
533543
pid | Ecto.Repo.t() | Ecto.Adapter.adapter_meta(),

0 commit comments

Comments
 (0)