changed CHANGELOG.md
 
@@ -1,5 +1,11 @@
1
1
# Changelog
2
2
3
+ ## v0.6.4 (2023-12-04)
4
+
5
+ * Let DBConnection rollback for failed commit or disconnect failed begin/rollback
6
+ * Trap exits from connect callback
7
+ * Handle duplicate column names in Table.Reader implementation
8
+
3
9
## v0.6.3 (2022-09-22)
4
10
5
11
* Print query statement in error log
changed hex_metadata.config
 
@@ -1,7 +1,36 @@
1
- {<<"app">>,<<"myxql">>}.
2
- {<<"build_tools">>,[<<"mix">>]}.
1
+ {<<"links">>,[{<<"GitHub">>,<<"https://github.com/elixir-ecto/myxql">>}]}.
2
+ {<<"name">>,<<"myxql">>}.
3
+ {<<"version">>,<<"0.6.4">>}.
3
4
{<<"description">>,<<"MySQL 5.5+ driver for Elixir">>}.
4
5
{<<"elixir">>,<<"~> 1.7">>}.
6
+ {<<"app">>,<<"myxql">>}.
7
+ {<<"licenses">>,[<<"Apache-2.0">>]}.
8
+ {<<"requirements">>,
9
+ [[{<<"name">>,<<"db_connection">>},
10
+ {<<"app">>,<<"db_connection">>},
11
+ {<<"optional">>,false},
12
+ {<<"requirement">>,<<"~> 2.4.1 or ~> 2.5">>},
13
+ {<<"repository">>,<<"hexpm">>}],
14
+ [{<<"name">>,<<"decimal">>},
15
+ {<<"app">>,<<"decimal">>},
16
+ {<<"optional">>,false},
17
+ {<<"requirement">>,<<"~> 1.6 or ~> 2.0">>},
18
+ {<<"repository">>,<<"hexpm">>}],
19
+ [{<<"name">>,<<"jason">>},
20
+ {<<"app">>,<<"jason">>},
21
+ {<<"optional">>,true},
22
+ {<<"requirement">>,<<"~> 1.0">>},
23
+ {<<"repository">>,<<"hexpm">>}],
24
+ [{<<"name">>,<<"geo">>},
25
+ {<<"app">>,<<"geo">>},
26
+ {<<"optional">>,true},
27
+ {<<"requirement">>,<<"~> 3.4">>},
28
+ {<<"repository">>,<<"hexpm">>}],
29
+ [{<<"name">>,<<"table">>},
30
+ {<<"app">>,<<"table">>},
31
+ {<<"optional">>,true},
32
+ {<<"requirement">>,<<"~> 0.1.0">>},
33
+ {<<"repository">>,<<"hexpm">>}]]}.
5
34
{<<"files">>,
6
35
[<<"lib">>,<<"lib/myxql">>,<<"lib/myxql/client.ex">>,
7
36
<<"lib/myxql/protocol.ex">>,<<"lib/myxql/error.ex">>,
 
@@ -13,33 +42,4 @@
13
42
<<"lib/myxql/connection.ex">>,<<"lib/myxql/text_query.ex">>,
14
43
<<"lib/myxql.ex">>,<<".formatter.exs">>,<<"mix.exs">>,<<"README.md">>,
15
44
<<"LICENSE.md">>,<<"CHANGELOG.md">>]}.
16
- {<<"licenses">>,[<<"Apache-2.0">>]}.
17
- {<<"links">>,[{<<"GitHub">>,<<"https://github.com/elixir-ecto/myxql">>}]}.
18
- {<<"name">>,<<"myxql">>}.
19
- {<<"requirements">>,
20
- [[{<<"app">>,<<"db_connection">>},
21
- {<<"name">>,<<"db_connection">>},
22
- {<<"optional">>,false},
23
- {<<"repository">>,<<"hexpm">>},
24
- {<<"requirement">>,<<"~> 2.4.1 or ~> 2.5">>}],
25
- [{<<"app">>,<<"decimal">>},
26
- {<<"name">>,<<"decimal">>},
27
- {<<"optional">>,false},
28
- {<<"repository">>,<<"hexpm">>},
29
- {<<"requirement">>,<<"~> 1.6 or ~> 2.0">>}],
30
- [{<<"app">>,<<"jason">>},
31
- {<<"name">>,<<"jason">>},
32
- {<<"optional">>,true},
33
- {<<"repository">>,<<"hexpm">>},
34
- {<<"requirement">>,<<"~> 1.0">>}],
35
- [{<<"app">>,<<"geo">>},
36
- {<<"name">>,<<"geo">>},
37
- {<<"optional">>,true},
38
- {<<"repository">>,<<"hexpm">>},
39
- {<<"requirement">>,<<"~> 3.4">>}],
40
- [{<<"app">>,<<"table">>},
41
- {<<"name">>,<<"table">>},
42
- {<<"optional">>,true},
43
- {<<"repository">>,<<"hexpm">>},
44
- {<<"requirement">>,<<"~> 0.1.0">>}]]}.
45
- {<<"version">>,<<"0.6.3">>}.
45
+ {<<"build_tools">>,[<<"mix">>]}.
changed lib/myxql/connection.ex
 
@@ -18,6 +18,9 @@ defmodule MyXQL.Connection do
18
18
19
19
@impl true
20
20
def connect(opts) do
21
+ # Trap exits so that DBConnection calls `disconnect` on unexpected shutdowns
22
+ Process.flag(:trap_exit, true)
23
+
21
24
prepare = Keyword.get(opts, :prepare, :named)
22
25
ping_timeout = Keyword.get(opts, :ping_timeout, 15_000)
23
26
config = Client.Config.new(opts)
 
@@ -413,7 +416,7 @@ defmodule MyXQL.Connection do
413
416
414
417
defp format_reason(reason) do
415
418
case :ssl.format_error(reason) do
416
- 'Unexpected error' ++ _ ->
419
+ ~c"Unexpected error" ++ _ ->
417
420
inspect(reason)
418
421
419
422
message ->
 
@@ -438,7 +441,12 @@ defmodule MyXQL.Connection do
438
441
{:ok, result, state}
439
442
440
443
other ->
441
- result(other, statement, state)
444
+ # We convert {:error, exception, state} to {:error, state}
445
+ # so that DBConnection will disconnect during handle_begin/handle_rollback
446
+ # and will attempt to rollback during handle_commit
447
+ with {:error, _exception, state} <- result(other, statement, state) do
448
+ {:error, state}
449
+ end
442
450
end
443
451
end
changed lib/myxql/protocol/server_error_codes.ex
 
@@ -1,7 +1,15 @@
1
1
defmodule MyXQL.Protocol.ServerErrorCodes do
2
2
@moduledoc false
3
3
4
- codes = [
4
+ # TODO: remove when we require Elixir v1.10+
5
+ codes_from_config =
6
+ if Version.match?(System.version(), ">= 1.10.0") do
7
+ Application.compile_env(:myxql, :extra_error_codes, [])
8
+ else
9
+ apply(Application, :get_env, [:myxql, :extra_error_codes, []])
10
+ end
11
+
12
+ default_codes = [
5
13
{1005, :ER_CANT_CREATE_TABLE},
6
14
{1006, :ER_CANT_CREATE_DB},
7
15
{1007, :ER_DB_CREATE_EXISTS},
 
@@ -23,8 +31,7 @@ defmodule MyXQL.Protocol.ServerErrorCodes do
23
31
{1836, :ER_READ_ONLY_MODE}
24
32
]
25
33
26
- # TODO: use Application.compile_env/3 when we require Elixir v1.10
27
- codes = codes ++ Application.get_env(:myxql, :extra_error_codes, [])
34
+ codes = default_codes ++ codes_from_config
28
35
29
36
for {code, name} <- Enum.uniq(codes) do
30
37
def name_to_code(unquote(name)), do: unquote(code)
changed lib/myxql/result.ex
 
@@ -48,7 +48,17 @@ if Code.ensure_loaded?(Table.Reader) do
48
48
end
49
49
50
50
def init(result) do
51
- {:rows, %{columns: result.columns, count: result.num_rows}, result.rows}
51
+ {columns, _} =
52
+ Enum.map_reduce(result.columns, %{}, fn column, counts ->
53
+ counts = Map.update(counts, column, 1, &(&1 + 1))
54
+
55
+ case counts[column] do
56
+ 1 -> {column, counts}
57
+ n -> {"#{column}_#{n}", counts}
58
+ end
59
+ end)
60
+
61
+ {:rows, %{columns: columns, count: result.num_rows}, result.rows}
52
62
end
53
63
end
54
64
end
changed mix.exs
 
@@ -1,7 +1,7 @@
1
1
defmodule MyXQL.MixProject do
2
2
use Mix.Project
3
3
4
- @version "0.6.3"
4
+ @version "0.6.4"
5
5
@source_url "https://github.com/elixir-ecto/myxql"
6
6
7
7
def project() do