mysql.erl 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. %% MySQL/OTP – MySQL client library for Erlang/OTP
  2. %% Copyright (C) 2014 Viktor Söderqvist
  3. %%
  4. %% This file is part of MySQL/OTP.
  5. %%
  6. %% MySQL/OTP is free software: you can redistribute it and/or modify it under
  7. %% the terms of the GNU Lesser General Public License as published by the Free
  8. %% Software Foundation, either version 3 of the License, or (at your option)
  9. %% any later version.
  10. %%
  11. %% This program is distributed in the hope that it will be useful, but WITHOUT
  12. %% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13. %% FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  14. %% more details.
  15. %%
  16. %% You should have received a copy of the GNU Lesser General Public License
  17. %% along with this program. If not, see <https://www.gnu.org/licenses/>.
  18. %% @doc MySQL/OTP. FIXME: Documentation of value representation, examples
  19. %% and more.
  20. %%
  21. %% This documentation is written with `edoc' as part of the source code and thus
  22. %% is covered by GPL 3 or later. See the LICENSE file or find GPL 3 on
  23. %% <a href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
  24. -module(mysql).
  25. -export([start_link/1, query/2, execute/3, prepare/2, warning_count/1,
  26. affected_rows/1, insert_id/1, transaction/2, transaction/3]).
  27. %% MySQL error with the codes and message returned from the server.
  28. -type reason() :: {Code :: integer(), SQLState :: binary(),
  29. Message :: binary()}.
  30. %% @doc Starts a connection process and connects to a database. To disconnect
  31. %% do `exit(Pid, normal)'.
  32. %%
  33. %% This is just a wrapper for `gen_server:start_link(mysql_connection, Options,
  34. %% [])'. If you need to specify gen_server options, use gen_server:start_link/3
  35. %% directly.
  36. -spec start_link(Options) -> {ok, pid()} | ignore | {error, term()}
  37. when Options :: [Option],
  38. Option :: {host, iodata()} | {port, integer()} | {user, iodata()} |
  39. {password, iodata()} | {database, iodata()}.
  40. start_link(Opts) ->
  41. gen_server:start_link(mysql_connection, Opts, []).
  42. -spec query(Conn, Query) -> ok | {ok, Fields, Rows} | {error, Reason}
  43. when Conn :: pid(),
  44. Query :: iodata(),
  45. Fields :: [binary()],
  46. Rows :: [[term()]],
  47. Reason :: reason().
  48. query(Conn, Query) ->
  49. gen_server:call(Conn, {query, Query}).
  50. %% @doc Executes a prepared statement.
  51. execute(Conn, StatementId, Args) ->
  52. gen_server:call(Conn, {execute, StatementId, Args}).
  53. -spec prepare(Conn :: pid(), Query :: iodata()) ->
  54. {ok, StatementId :: integer()} | {error, Reason :: reason()}.
  55. prepare(Conn, Query) ->
  56. gen_server:call(Conn, {prepare, Query}).
  57. -spec warning_count(pid()) -> integer().
  58. warning_count(Conn) ->
  59. gen_server:call(Conn, warning_count).
  60. -spec affected_rows(pid()) -> integer().
  61. affected_rows(Conn) ->
  62. gen_server:call(Conn, affected_rows).
  63. -spec insert_id(pid()) -> integer().
  64. insert_id(Conn) ->
  65. gen_server:call(Conn, insert_id).
  66. %% @doc This function executes the functional object Fun as a transaction.
  67. %% @see transaction/2
  68. -spec transaction(pid(), fun()) -> {atomic, term()} | {aborted, term()}.
  69. transaction(Conn, Fun) ->
  70. transaction(Conn, Fun, []).
  71. %% @doc This function executes the functional object Fun with arguments Args as
  72. %% a transaction.
  73. %%
  74. %% The semantics are the sames as for mnesia's transactions.
  75. %%
  76. %% The Fun must be a function and Args must be a list with the same length
  77. %% as the arity of Fun.
  78. %%
  79. %% Current limitations:
  80. %%
  81. %% <ul>
  82. %% <li>Transactions cannot be nested</li>
  83. %% <li>They are not automatically restarted when deadlocks are detected.</li>
  84. %% </ul>
  85. %%
  86. %% TODO: Implement nested transactions
  87. %% TODO: Automatic restart on deadlocks
  88. -spec transaction(pid(), fun(), list()) -> {atomic, term()} | {aborted, term()}.
  89. transaction(Conn, Fun, Args) when is_list(Args),
  90. is_function(Fun, length(Args)) ->
  91. %% The guard makes sure that we can apply Fun to Args. Any error we catch
  92. %% in the try-catch are actual errors that occurred in Fun.
  93. ok = query(Conn, <<"BEGIN">>),
  94. try apply(Fun, Args) of
  95. ResultOfFun ->
  96. %% We must be able to rollback. Otherwise let's go mad.
  97. ok = query(Conn, <<"COMMIT">>),
  98. {atomic, ResultOfFun}
  99. catch
  100. Class:Reason ->
  101. %% We must be able to rollback. Otherwise let's go mad.
  102. ok = query(Conn, <<"ROLLBACK">>),
  103. %% These forms for throw, error and exit mirror Mnesia's behaviour.
  104. Aborted = case Class of
  105. throw -> {throw, Reason};
  106. error -> {Reason, erlang:get_stacktrace()};
  107. exit -> Reason
  108. end,
  109. {aborted, Aborted}
  110. end.