Browse Source

Comments and errors

Viktor Söderqvist 10 years ago
parent
commit
f2c4e0dadb
1 changed files with 24 additions and 25 deletions
  1. 24 25
      src/mysql_protocol.erl

+ 24 - 25
src/mysql_protocol.erl

@@ -3,18 +3,14 @@
 %% The protocol is described in the document "MySQL Internals" which can be
 %% found under "MySQL Documentation: Expert Guides" on http://dev.mysql.com/
 %%
-%% TCP communication is not handled in this module.
+%% TCP communication is not handled in this module. Most of the public functions
+%% take funs for data communitaction as parameters.
 -module(mysql_protocol).
 
--export([
-         %parse_packet_header/1, add_packet_headers/2,
-         %parse_handshake/1, build_handshake_response/3,
-         %parse_handshake_confirm/1,
-         handshake/5,
-         query_tcp/3, query/3]).
+-export([handshake/5,
+         query/3]).
 
--include("records.hrl").
--include("protocol.hrl").
+-export_type([sendfun/0, recvfun/0]).
 
 -type sendfun() :: fun((binary()) -> ok).
 -type recvfun() :: fun((integer()) -> {ok, binary()}).
@@ -22,6 +18,9 @@
 %% How much data do we want to send at most?
 -define(MAX_BYTES_PER_PACKET, 50000000).
 
+-include("records.hrl").
+-include("protocol.hrl").
+
 %% Macros for pattern matching on packets.
 -define(ok_pattern, <<?OK, _/binary>>).
 -define(error_pattern, <<?ERROR, _/binary>>).
@@ -58,7 +57,8 @@ add_packet_headers(PacketBody, SeqNum) ->
     end.
 
 %% @doc Performs a handshake using the supplied functions for communication.
-%% Returns an ok or an error record.
+%% Returns an ok or an error record. Raises errors when various unimplemented
+%% features are requested.
 %%
 %% TODO: Implement setting the database in the handshake. Currently an error
 %% occurs if Database is anything other than undefined.
@@ -66,7 +66,7 @@ add_packet_headers(PacketBody, SeqNum) ->
                 recvfun()) -> #ok{} | #error{}.
 handshake(Username, Password, Database, SendFun, RecvFun) ->
     SeqNum0 = 0,
-    Database == undefined orelse error(database_in_handshake_not_implemented),
+    Database == undefined orelse error(database_in_handshake),
     {ok, HandshakePacket, SeqNum1} = recv_packet(RecvFun, SeqNum0),
     Handshake = parse_handshake(HandshakePacket),
     Response = build_handshake_response(Handshake, Username, Password),
@@ -75,7 +75,7 @@ handshake(Username, Password, Database, SendFun, RecvFun) ->
     parse_handshake_confirm(ConfirmPacket).
 
 %% @doc Parses a handshake. This is the first thing that comes from the server
-%% when connecting. If an unsupported version of variant of the protocol is used
+%% when connecting. If an unsupported version or variant of the protocol is used
 %% an error is raised.
 -spec parse_handshake(binary()) -> #handshake{}.
 parse_handshake(<<10, Rest/binary>>) ->
@@ -125,7 +125,7 @@ build_handshake_response(Handshake, Username, Password) ->
                       ?CLIENT_TRANSACTIONS bor
                       ?CLIENT_SECURE_CONNECTION,
     Handshake#handshake.capabilities band CapabilityFlags == CapabilityFlags
-        orelse error({not_implemented, old_server_version}),
+        orelse error(old_server_version),
     Hash = hash_password(Password,
                          Handshake#handshake.auth_plugin_name,
                          Handshake#handshake.auth_plugin_data),
@@ -158,20 +158,14 @@ parse_handshake_confirm(Packet) ->
             %% single 0xfe byte. It is sent by server to request client to
             %% switch to Old Password Authentication if CLIENT_PLUGIN_AUTH
             %% capability is not supported (by either the client or the server)"
-            error({not_implemented, old_auth});
+            error(old_auth);
         <<?EOF, _/binary>> ->
             %% "Authentication Method Switch Request Packet. If both server and
             %% client support CLIENT_PLUGIN_AUTH capability, server can send
             %% this packet to ask client to use another authentication method."
-            error({not_implemented, auth_method_switch})
+            error(auth_method_switch)
     end.
 
-%% @doc Query on a tcp socket.
-query_tcp(Query, Socket, Timeout) ->
-    SendFun = fun (Data) -> gen_tcp:send(Socket, Data) end,
-    RecvFun = fun (Size) -> gen_tcp:recv(Socket, Size, Timeout) end,
-    query(Query, SendFun, RecvFun).
-
 %% @doc Normally fun gen_tcp:send/2 and fun gen_tcp:recv/3 are used, except in
 %% unit testing.
 query(Query, SendFun, RecvFun) ->
@@ -190,6 +184,11 @@ query(Query, SendFun, RecvFun) ->
             fetch_resultset(RecvFun, FieldCount, SeqNum2)
     end.
 
+prepare(Query, SendFun, RecvFun) ->
+    Req = <<?COM_STMT_PREPARE, (iolist_to_binary(Query))/binary>>,
+    {ok, SeqNum1} = send_packet(SendFun, Req, 0),
+    {ok, Resp, SeqNum2} = recv_packet(RecvFun, SeqNum1),
+
 -spec fetch_resultset(recvfun(), integer(), integer()) ->
     #text_resultset{} | #error{}.
 fetch_resultset(RecvFun, FieldCount, SeqNum) ->
@@ -304,8 +303,8 @@ parse_ok_packet(<<?OK:8, Rest/binary>>) ->
     {AffectedRows, Rest1} = lenenc_int(Rest),
     {InsertId, Rest2} = lenenc_int(Rest1),
     <<StatusFlags:16/little, WarningCount:16/little, Msg/binary>> = Rest2,
-    %% We have enabled CLIENT_PROTOCOL_41 but not CLIENT_SESSION_TRACK in the
-    %% conditional protocol:
+    %% We have CLIENT_PROTOCOL_41 but not CLIENT_SESSION_TRACK enabled. The
+    %% protocol is conditional. This is from the protocol documentation:
     %%
     %% if capabilities & CLIENT_PROTOCOL_41 {
     %%   int<2> status_flags
@@ -343,7 +342,7 @@ parse_eof_packet(<<?EOF:8, NumWarnings:16/little, StatusFlags:16/little>>) ->
 -spec hash_password(Password :: iodata(), AuthPluginName :: binary(),
                     AuthPluginData :: binary()) -> binary().
 hash_password(_Password, <<"mysql_old_password">>, _Salt) ->
-    error({incompatible, <<"Old auth method not implemented">>});
+    error(old_auth);
 hash_password(Password, <<"mysql_native_password">>, AuthData) ->
     %% From the "MySQL Internals" manual:
     %% SHA1( password ) XOR SHA1( "20-bytes random data from server" <concat>
@@ -363,7 +362,7 @@ hash_password(Password, <<"mysql_native_password">>, AuthData) ->
     <<Hash3Num:160>> = crypto:hash(sha, <<Salt/binary, Hash2/binary>>),
     <<(Hash1Num bxor Hash3Num):160>>;
 hash_password(_, AuthPlugin, _) ->
-    error({unsupported_auth_method, AuthPlugin}).
+    error({auth_method, AuthPlugin}).
 
 %% lenenc_int/1 decodes length-encoded-integer values
 -spec lenenc_int(Input :: binary()) -> {Value :: integer(), Rest :: binary()}.