Viktor Söderqvist 10 лет назад
Родитель
Сommit
9de8240132
2 измененных файлов с 39 добавлено и 17 удалено
  1. 19 8
      src/mysql_connection.erl
  2. 20 9
      src/mysql_protocol.erl

+ 19 - 8
src/mysql_connection.erl

@@ -64,6 +64,8 @@ init(Opts) ->
         #ok{} = OK ->
             State = #state{socket = Socket, timeout = Timeout},
             State1 = update_state(State, OK),
+            %% Trap exit so that we can properly disconnect when we die.
+            process_flag(trap_exit, true),
             {ok, State1};
         #error{} = E ->
             {stop, error_to_reason(E)}
@@ -163,18 +165,27 @@ handle_call(autocommit, _From, State) ->
     {reply, State#state.status band ?SERVER_STATUS_AUTOCOMMIT /= 0, State};
 handle_call(in_transaction, _From, State) ->
     {reply, State#state.status band ?SERVER_STATUS_IN_TRANS /= 0, State};
-handle_call(get_state, _From, State) ->
-    %% *** FOR DEBUGGING ***
-    %% TODO: Delete this.
-    {reply, State, State}.
+%handle_call(get_state, _From, State) ->
+%    %% *** FOR DEBUGGING ***
+%    {reply, State, State}.
+handle_call(_Msg, _From, State) ->
+    {reply, {error, invalid_message}, State}.
 
-handle_cast(_, _) -> todo.
+handle_cast(_Msg, State) ->
+    {noreply, State}.
 
-handle_info(_, _) -> todo.
+handle_info(_Info, State) ->
+    {noreply, State}.
 
-terminate(_, _) -> todo.
+terminate(_Reason, State) ->
+    %% Send the goodbye message for politeness.
+    #state{socket = Socket, timeout = Timeout} = State,
+    SendFun = fun (Data) -> gen_tcp:send(Socket, Data) end,
+    RecvFun = fun (Size) -> gen_tcp:recv(Socket, Size, Timeout) end,
+    mysql_protocol:quit(SendFun, RecvFun).
 
-code_change(_, _, _) -> todo.
+code_change(_OldVsn, State, _Extra) ->
+    {ok, State}.
 
 %% --- Helpers ---
 

+ 20 - 9
src/mysql_protocol.erl

@@ -25,7 +25,7 @@
 %% take funs for data communitaction as parameters.
 -module(mysql_protocol).
 
--export([handshake/5,
+-export([handshake/5, quit/2,
          query/3,
          prepare/3, unprepare/3, execute/4]).
 
@@ -63,6 +63,13 @@ handshake(Username, Password, Database, SendFun, RecvFun) ->
     {ok, ConfirmPacket, _SeqNum3} = recv_packet(RecvFun, SeqNum2),
     parse_handshake_confirm(ConfirmPacket).
 
+quit(SendFun, RecvFun) ->
+    {ok, SeqNum1} = send_packet(SendFun, <<?COM_QUIT>>, 0),
+    case recv_packet(RecvFun, SeqNum1) of
+        {error, closed} -> ok;
+        {ok, ?ok_pattern, _SeqNum2} -> ok
+    end.
+
 -spec query(Query :: iodata(), sendfun(), recvfun()) ->
     #ok{} | #error{} | #resultset{}.
 query(Query, SendFun, RecvFun) ->
@@ -746,14 +753,18 @@ recv_packet(RecvFun, SeqNum) ->
                   Acc :: binary()) ->
     {ok, Data :: binary(), NextSeqNum :: integer()}.
 recv_packet(RecvFun, ExpectSeqNum, Acc) ->
-    {ok, Header} = RecvFun(4),
-    {Size, ExpectSeqNum, More} = parse_packet_header(Header),
-    {ok, Body} = RecvFun(Size),
-    Acc1 = <<Acc/binary, Body/binary>>,
-    NextSeqNum = (ExpectSeqNum + 1) band 16#ff,
-    case More of
-        false -> {ok, Acc1, NextSeqNum};
-        true  -> recv_packet(RecvFun, NextSeqNum, Acc1)
+    case RecvFun(4) of
+        {ok, Header} ->
+            {Size, ExpectSeqNum, More} = parse_packet_header(Header),
+            {ok, Body} = RecvFun(Size),
+            Acc1 = <<Acc/binary, Body/binary>>,
+            NextSeqNum = (ExpectSeqNum + 1) band 16#ff,
+            case More of
+                false -> {ok, Acc1, NextSeqNum};
+                true  -> recv_packet(RecvFun, NextSeqNum, Acc1)
+            end;
+        {error, closed} ->
+            {error, closed}
     end.
 
 %% @doc Parses a packet header (32 bits) and returns a tuple.