Browse Source

Merge branch 'log-warnings'

Viktor Söderqvist 10 years ago
parent
commit
f54b91523a
1 changed files with 31 additions and 7 deletions
  1. 31 7
      src/mysql.erl

+ 31 - 7
src/mysql.erl

@@ -79,6 +79,9 @@
 %%       using the query `USE <database>'.</dd>
 %%   <dt>`{connect_timeout, Timeout}'</dt>
 %%   <dd>The maximum time to spend for start_link/1.</dd>
+%%   <dt>`{log_warnings, boolean()}'</dt>
+%%   <dd>Whether to fetch warnings and log them using error_logger; default
+%%       true.</dd>
 %%   <dt>`{query_timeout, Timeout}'</dt>
 %%   <dd>The default time to wait for a response when executing a query or a
 %%       prepared statement. This can be given per query using `query/3,4' and
@@ -93,6 +96,7 @@
                    {user, iodata()} | {password, iodata()} |
                    {database, iodata()} |
                    {connect_timeout, timeout()} |
+                   {log_warnings, boolean()} |
                    {query_timeout, timeout()} |
                    {query_cache_time, non_neg_integer()},
          ServerName :: {local, Name :: atom()} |
@@ -328,7 +332,7 @@ transaction(Conn, Fun, Args) when is_list(Args),
 
 %% Gen_server state
 -record(state, {server_version, connection_id, socket,
-                host, port, user, password,
+                host, port, user, password, log_warnings,
                 query_timeout, query_cache_time,
                 affected_rows = 0, status = 0, warning_count = 0, insert_id = 0,
                 transaction_level = 0,
@@ -342,6 +346,7 @@ init(Opts) ->
     User     = proplists:get_value(user,          Opts, ?default_user),
     Password = proplists:get_value(password,      Opts, ?default_password),
     Database = proplists:get_value(database,      Opts, undefined),
+    LogWarn  = proplists:get_value(log_warnings,  Opts, true),
     Timeout  = proplists:get_value(query_timeout, Opts, ?default_query_timeout),
     QueryCacheTime = proplists:get_value(query_cache_time, Opts,
                                          ?default_query_cache_time),
@@ -360,6 +365,7 @@ init(Opts) ->
                            socket = Socket,
                            host = Host, port = Port, user = User,
                            password = Password, status = Status,
+                           log_warnings = LogWarn,
                            query_timeout = Timeout,
                            query_cache_time = QueryCacheTime},
             %% Trap exit so that we can properly disconnect when we die.
@@ -386,6 +392,8 @@ handle_call({query, Query, Timeout}, _From, State) ->
             QueryResult
     end,
     State1 = update_state(State, Rec),
+    State1#state.warning_count > 0 andalso State1#state.log_warnings
+        andalso log_warnings(State1, Query),
     case Rec of
         #ok{} ->
             {reply, ok, State1};
@@ -426,7 +434,10 @@ handle_call({param_query, Query, Params, Timeout}, _From, State) ->
     case StmtResult of
         {ok, StmtRec} ->
             State1 = State#state{query_cache = Cache1},
-            execute_stmt(StmtRec, Params, Timeout, State1);
+            {Reply, State2} = execute_stmt(StmtRec, Params, Timeout, State1),
+            State2#state.warning_count > 0 andalso State2#state.log_warnings
+                andalso log_warnings(State2, Query),
+            {reply, Reply, State2};
         PrepareError ->
             {reply, PrepareError, State}
     end;
@@ -435,7 +446,12 @@ handle_call({execute, Stmt, Args}, From, State) ->
 handle_call({execute, Stmt, Args, Timeout}, _From, State) ->
     case dict:find(Stmt, State#state.stmts) of
         {ok, StmtRec} ->
-            execute_stmt(StmtRec, Args, Timeout, State);
+            {Reply, State1} = execute_stmt(StmtRec, Args, Timeout, State),
+            State1#state.warning_count > 0 andalso State1#state.log_warnings
+                andalso log_warnings(State1,
+                                     io_lib:format("prepared statement ~p",
+                                                   [Stmt])),
+            {reply, Reply, State1};
         error ->
             {reply, {error, not_prepared}, State}
     end;
@@ -568,7 +584,7 @@ code_change(_OldVsn, _State, _Extra) ->
 
 %% --- Helpers ---
 
-%% @doc Returns a tuple on the the same form as handle_call/3.
+%% @doc Executes a prepared statement and returns {Reply, NextState}.
 execute_stmt(Stmt, Args, Timeout, State = #state{socket = Socket}) ->
     Rec = case mysql_protocol:execute(Stmt, Args, gen_tcp, Socket, Timeout) of
         {error, timeout} when State#state.server_version >= [5, 0, 0] ->
@@ -584,12 +600,12 @@ execute_stmt(Stmt, Args, Timeout, State = #state{socket = Socket}) ->
     State1 = update_state(State, Rec),
     case Rec of
         #ok{} ->
-            {reply, ok, State1};
+            {ok, State1};
         #error{} = E ->
-            {reply, {error, error_to_reason(E)}, State1};
+            {{error, error_to_reason(E)}, State1};
         #resultset{cols = ColDefs, rows = Rows} ->
             Names = [Def#col.name || Def <- ColDefs],
-            {reply, {ok, Names, Rows}, State1}
+            {{ok, Names, Rows}, State1}
     end.
 
 %% @doc Produces a tuple to return as an error reason.
@@ -612,6 +628,14 @@ update_state(State, _Other) ->
     %% Reset warnings, etc. (Note: We don't reset status and insert_id.)
     State#state{warning_count = 0, affected_rows = 0}.
 
+%% @doc Fetches and logs warnings. Query is the query that gave the warnings.
+log_warnings(#state{socket = Socket}, Query) ->
+    #resultset{rows = Rows} =
+        mysql_protocol:query(<<"SHOW WARNINGS">>, gen_tcp, Socket, infinity),
+    Lines = [[Level, " ", integer_to_binary(Code), ": ", Message, "\n"]
+             || [Level, Code, Message] <- Rows],
+    error_logger:warning_msg("~s in ~s~n", [Lines, Query]).
+
 %% @doc Makes a separate connection and execute KILL QUERY. We do this to get
 %% our main connection back to normal. KILL QUERY appeared in MySQL 5.0.0.
 kill_query(#state{connection_id = ConnId, host = Host, port = Port,