Lars Strojny commited on 2007-03-18 16:27:18
Zeige 8 geänderte Dateien mit 0 Einfügungen und 1701 Löschungen.
... | ... |
@@ -1,31 +0,0 @@ |
1 |
-AUX mysql-5/mysql.erl 26950 RMD160 1e7f78cfc3165270f49e5f9a5b0991abfcd19750 SHA1 a45d087613aa0556cddffcec6ebc97547415eec8 SHA256 56da9d145b8d8fc08bbec5569aaa6ac58c852f2bb163ead1b448cb263edf290c size 26950 |
|
2 |
-MD5 6468ce139782e5afdc174814ef79e3dc files/mysql-5/mysql.erl 26950 |
|
3 |
-RMD160 1e7f78cfc3165270f49e5f9a5b0991abfcd19750 files/mysql-5/mysql.erl 26950 |
|
4 |
-SHA256 56da9d145b8d8fc08bbec5569aaa6ac58c852f2bb163ead1b448cb263edf290c files/mysql-5/mysql.erl 26950 |
|
5 |
-AUX mysql-5/mysql.hrl 105 RMD160 e87df112cee2b8cd8e40f48ebd33cc9ad5824c85 SHA1 5756564c95b85c6913917b715b682f01cf1ae652 SHA256 7913a92afb56c909cef29f9ee57f8483c7acc2de484909c3165dd7abb8951996 size 105 |
|
6 |
-MD5 2a911311bafd83b0b7837de8046b4035 files/mysql-5/mysql.hrl 105 |
|
7 |
-RMD160 e87df112cee2b8cd8e40f48ebd33cc9ad5824c85 files/mysql-5/mysql.hrl 105 |
|
8 |
-SHA256 7913a92afb56c909cef29f9ee57f8483c7acc2de484909c3165dd7abb8951996 files/mysql-5/mysql.hrl 105 |
|
9 |
-AUX mysql-5/mysql_auth.erl 6578 RMD160 91ab61b647c0e671fc47432f66340e262ef42b23 SHA1 3b4094be6995f9438246c204dabecaa8cf82d667 SHA256 ca13c4177a4acb13d4e4eb3fb31e132996477a4a526aa50fc42851fac2288d85 size 6578 |
|
10 |
-MD5 b12048d5b64c0249173d8a0d690dbdd3 files/mysql-5/mysql_auth.erl 6578 |
|
11 |
-RMD160 91ab61b647c0e671fc47432f66340e262ef42b23 files/mysql-5/mysql_auth.erl 6578 |
|
12 |
-SHA256 ca13c4177a4acb13d4e4eb3fb31e132996477a4a526aa50fc42851fac2288d85 files/mysql-5/mysql_auth.erl 6578 |
|
13 |
-AUX mysql-5/mysql_conn.erl 24318 RMD160 5bd5c430553245285b45a8f33bc8a438b2b75f03 SHA1 9ac62dea95ff209dbc27b54c74a74df4868c04c5 SHA256 93b8d6029682e1f9dd5343b78639c209201513ad4da0e6a4e010680c545a027f size 24318 |
|
14 |
-MD5 d62886a6d354e54867c2fa925ecfbf5b files/mysql-5/mysql_conn.erl 24318 |
|
15 |
-RMD160 5bd5c430553245285b45a8f33bc8a438b2b75f03 files/mysql-5/mysql_conn.erl 24318 |
|
16 |
-SHA256 93b8d6029682e1f9dd5343b78639c209201513ad4da0e6a4e010680c545a027f files/mysql-5/mysql_conn.erl 24318 |
|
17 |
-AUX mysql-5/mysql_recv.erl 5969 RMD160 55e05e77eea577cd97f646dbbaa4a59d6170b90d SHA1 b00e10ec0aa0f6686e86a0a33e24fff6e543b5a8 SHA256 22069257ff8230bb2b8f26c7e065a5d6f6c0b5f4f2bf5d505830ffe2b75ce783 size 5969 |
|
18 |
-MD5 c4e1b577553658ec96e1a867a7091d14 files/mysql-5/mysql_recv.erl 5969 |
|
19 |
-RMD160 55e05e77eea577cd97f646dbbaa4a59d6170b90d files/mysql-5/mysql_recv.erl 5969 |
|
20 |
-SHA256 22069257ff8230bb2b8f26c7e065a5d6f6c0b5f4f2bf5d505830ffe2b75ce783 files/mysql-5/mysql_recv.erl 5969 |
|
21 |
-EBUILD mysql-5.ebuild 677 RMD160 4a3c3ef182ed4104587fbbbf0f2f438efac02eee SHA1 e0f02ae13504ebff9ff76818ed15776a742e1d6b SHA256 bcfc02741dad9bab768b61f63399e333bcc5bc28944b9e8a6da6c5411cc86cc4 size 677 |
|
22 |
-MD5 6ac678b1fdfdb88c7d89dca2204019d0 mysql-5.ebuild 677 |
|
23 |
-RMD160 4a3c3ef182ed4104587fbbbf0f2f438efac02eee mysql-5.ebuild 677 |
|
24 |
-SHA256 bcfc02741dad9bab768b61f63399e333bcc5bc28944b9e8a6da6c5411cc86cc4 mysql-5.ebuild 677 |
|
25 |
-MISC ChangeLog 215 RMD160 e0efaa0907544feb0bed5176d09cc613ab5ac6ec SHA1 18c3589897fc9c0a61b67c4c7f94cbe147104ab1 SHA256 fbdc6b0fd128a03a62490ca8db778d8a7c1d255b8819339d291887d40440140a size 215 |
|
26 |
-MD5 b0c339ed8db8a4512f1664a3d7915531 ChangeLog 215 |
|
27 |
-RMD160 e0efaa0907544feb0bed5176d09cc613ab5ac6ec ChangeLog 215 |
|
28 |
-SHA256 fbdc6b0fd128a03a62490ca8db778d8a7c1d255b8819339d291887d40440140a ChangeLog 215 |
|
29 |
-MD5 68b329da9893e34099c7d8ad5cb9c940 files/digest-mysql-5 1 |
|
30 |
-RMD160 c0da025038ed83c687ddc430da9846ecb97f3998 files/digest-mysql-5 1 |
|
31 |
-SHA256 01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b files/digest-mysql-5 1 |
... | ... |
@@ -1,656 +0,0 @@ |
1 |
-%%%------------------------------------------------------------------- |
|
2 |
-%%% File : mysql.erl |
|
3 |
-%%% Author : Magnus Ahltorp <ahltorp@nada.kth.se> |
|
4 |
-%%% Descrip.: MySQL client. |
|
5 |
-%%% |
|
6 |
-%%% Created : 4 Aug 2005 by Magnus Ahltorp <ahltorp@nada.kth.se> |
|
7 |
-%%% |
|
8 |
-%%% Copyright (c) 2001-2004 Kungliga Tekniska H�gskolan |
|
9 |
-%%% See the file COPYING |
|
10 |
-%%% |
|
11 |
-%%% Usage: |
|
12 |
-%%% |
|
13 |
-%%% |
|
14 |
-%%% Call one of the start-functions before any call to fetch/2 |
|
15 |
-%%% |
|
16 |
-%%% start_link(Id, Host, User, Password, Database) |
|
17 |
-%%% start_link(Id, Host, Port, User, Password, Database) |
|
18 |
-%%% start_link(Id, Host, User, Password, Database, LogFun) |
|
19 |
-%%% start_link(Id, Host, Port, User, Password, Database, LogFun) |
|
20 |
-%%% |
|
21 |
-%%% Id is a connection group identifier. If you want to have more |
|
22 |
-%%% than one connection to a server (or a set of MySQL replicas), |
|
23 |
-%%% add more with |
|
24 |
-%%% |
|
25 |
-%%% connect(Id, Host, Port, User, Password, Database, Reconnect) |
|
26 |
-%%% |
|
27 |
-%%% use 'undefined' as Port to get default MySQL port number (3306). |
|
28 |
-%%% MySQL querys will be sent in a per-Id round-robin fashion. |
|
29 |
-%%% Set Reconnect to 'true' if you want the dispatcher to try and |
|
30 |
-%%% open a new connection, should this one die. |
|
31 |
-%%% |
|
32 |
-%%% When you have a mysql_dispatcher running, this is how you make a |
|
33 |
-%%% query : |
|
34 |
-%%% |
|
35 |
-%%% fetch(Id, "select * from hello") -> Result |
|
36 |
-%%% Result = {data, MySQLRes} | {updated, MySQLRes} | |
|
37 |
-%%% {error, MySQLRes} |
|
38 |
-%%% |
|
39 |
-%%% Actual data can be extracted from MySQLRes by calling the following API |
|
40 |
-%%% functions: |
|
41 |
-%%% - on data received: |
|
42 |
-%%% FieldInfo = mysql:get_result_field_info(MysqlRes) |
|
43 |
-%%% AllRows = mysql:get_result_rows(MysqlRes) |
|
44 |
-%%% with FieldInfo = list() of {Table, Field, Length, Name} |
|
45 |
-%%% and AllRows = list() of list() representing records |
|
46 |
-%%% - on update: |
|
47 |
-%%% Affected = mysql:get_result_affected_rows(MysqlRes) |
|
48 |
-%%% with Affected = integer() |
|
49 |
-%%% - on error: |
|
50 |
-%%% Reason = mysql:get_result_reason(MysqlRes) |
|
51 |
-%%% with Reason = string() |
|
52 |
-%%% |
|
53 |
-%%% If you just want a single MySQL connection, or want to manage your |
|
54 |
-%%% connections yourself, you can use the mysql_conn module as a |
|
55 |
-%%% stand-alone single MySQL connection. See the comment at the top of |
|
56 |
-%%% mysql_conn.erl. |
|
57 |
-%%% |
|
58 |
-%%%------------------------------------------------------------------- |
|
59 |
--module(mysql). |
|
60 |
- |
|
61 |
--behaviour(gen_server). |
|
62 |
- |
|
63 |
-%%-------------------------------------------------------------------- |
|
64 |
-%% External exports |
|
65 |
-%%-------------------------------------------------------------------- |
|
66 |
--export([start_link/5, |
|
67 |
- start_link/6, |
|
68 |
- start_link/7, |
|
69 |
- |
|
70 |
- fetch/2, |
|
71 |
- fetch/3, |
|
72 |
- |
|
73 |
- get_result_field_info/1, |
|
74 |
- get_result_rows/1, |
|
75 |
- get_result_affected_rows/1, |
|
76 |
- get_result_reason/1, |
|
77 |
- |
|
78 |
- quote/1, |
|
79 |
- asciz_binary/2, |
|
80 |
- |
|
81 |
- connect/7 |
|
82 |
- ]). |
|
83 |
- |
|
84 |
-%%-------------------------------------------------------------------- |
|
85 |
-%% Internal exports - just for mysql_* modules |
|
86 |
-%%-------------------------------------------------------------------- |
|
87 |
--export([log/3, |
|
88 |
- log/4 |
|
89 |
- ]). |
|
90 |
- |
|
91 |
-%%-------------------------------------------------------------------- |
|
92 |
-%% Internal exports - gen_server callbacks |
|
93 |
-%%-------------------------------------------------------------------- |
|
94 |
--export([init/1, |
|
95 |
- handle_call/3, |
|
96 |
- handle_cast/2, |
|
97 |
- handle_info/2, |
|
98 |
- terminate/2, |
|
99 |
- code_change/3 |
|
100 |
- ]). |
|
101 |
- |
|
102 |
-%%-------------------------------------------------------------------- |
|
103 |
-%% Records |
|
104 |
-%%-------------------------------------------------------------------- |
|
105 |
--include("mysql.hrl"). |
|
106 |
--record(state, { |
|
107 |
- conn_list, %% list() of mysql_connection record() |
|
108 |
- log_fun %% undefined | function for logging, |
|
109 |
- }). |
|
110 |
- |
|
111 |
--record(mysql_connection, { |
|
112 |
- id, %% term(), user of 'mysql' modules id of this socket group |
|
113 |
- conn_pid, %% pid(), mysql_conn process |
|
114 |
- reconnect, %% true | false, should mysql_dispatcher try to reconnect if this connection dies? |
|
115 |
- host, %% undefined | string() |
|
116 |
- port, %% undefined | integer() |
|
117 |
- user, %% undefined | string() |
|
118 |
- password, %% undefined | string() |
|
119 |
- database %% undefined | string() |
|
120 |
- }). |
|
121 |
- |
|
122 |
-%%-------------------------------------------------------------------- |
|
123 |
-%% Macros |
|
124 |
-%%-------------------------------------------------------------------- |
|
125 |
--define(SERVER, mysql_dispatcher). |
|
126 |
--define(CONNECT_TIMEOUT, 5000). |
|
127 |
--define(LOCAL_FILES, 128). |
|
128 |
- |
|
129 |
--define(PORT, 3306). |
|
130 |
- |
|
131 |
- |
|
132 |
-%%==================================================================== |
|
133 |
-%% External functions |
|
134 |
-%%==================================================================== |
|
135 |
- |
|
136 |
-%%-------------------------------------------------------------------- |
|
137 |
-%% Function: start_link(Id, Host, User, Password, Database) |
|
138 |
-%% start_link(Id, Host, Port, User, Password, Database) |
|
139 |
-%% start_link(Id, Host, User, Password, Database, LogFun) |
|
140 |
-%% start_link(Id, Host, Port, User, Password, Database, |
|
141 |
-%% LogFun) |
|
142 |
-%% Id = term(), first connection-group Id |
|
143 |
-%% Host = string() |
|
144 |
-%% Port = integer() |
|
145 |
-%% User = string() |
|
146 |
-%% Password = string() |
|
147 |
-%% Database = string() |
|
148 |
-%% LogFun = undefined | function() of arity 3 |
|
149 |
-%% Descrip.: Starts the MySQL client gen_server process. |
|
150 |
-%% Returns : {ok, Pid} | ignore | {error, Error} |
|
151 |
-%%-------------------------------------------------------------------- |
|
152 |
-start_link(Id, Host, User, Password, Database) when is_list(Host), is_list(User), is_list(Password), |
|
153 |
- is_list(Database) -> |
|
154 |
- start_link(Id, Host, ?PORT, User, Password, Database, undefined). |
|
155 |
- |
|
156 |
-start_link(Id, Host, Port, User, Password, Database) when is_list(Host), is_integer(Port), is_list(User), |
|
157 |
- is_list(Password), is_list(Database) -> |
|
158 |
- start_link(Id, Host, Port, User, Password, Database, undefined); |
|
159 |
- |
|
160 |
-start_link(Id, Host, User, Password, Database, LogFun) when is_list(Host), is_list(User), is_list(Password), |
|
161 |
- is_list(Database) -> |
|
162 |
- start_link(Id, Host, ?PORT, User, Password, Database, LogFun). |
|
163 |
- |
|
164 |
-start_link(Id, Host, Port, User, Password, Database, LogFun) when is_list(Host), is_integer(Port), is_list(User), |
|
165 |
- is_list(Password), is_list(Database) -> |
|
166 |
- crypto:start(), |
|
167 |
- gen_server:start_link({local, ?SERVER}, ?MODULE, [Id, Host, Port, User, Password, Database, LogFun], []). |
|
168 |
- |
|
169 |
-%%-------------------------------------------------------------------- |
|
170 |
-%% Function: fetch(Id, Query) |
|
171 |
-%% fetch(Id, Query, Timeout) |
|
172 |
-%% Id = term(), connection-group Id |
|
173 |
-%% Query = string(), MySQL query in verbatim |
|
174 |
-%% Timeout = integer() | infinity, gen_server timeout value |
|
175 |
-%% Descrip.: Send a query and wait for the result. |
|
176 |
-%% Returns : {data, MySQLRes} | |
|
177 |
-%% {updated, MySQLRes} | |
|
178 |
-%% {error, MySQLRes} |
|
179 |
-%% MySQLRes = term() |
|
180 |
-%%-------------------------------------------------------------------- |
|
181 |
-fetch(Id, Query) when is_list(Query) -> |
|
182 |
- gen_server:call(?SERVER, {fetch, Id, Query}). |
|
183 |
-fetch(Id, Query, Timeout) when is_list(Query) -> |
|
184 |
- gen_server:call(?SERVER, {fetch, Id, Query}, Timeout). |
|
185 |
- |
|
186 |
-%%-------------------------------------------------------------------- |
|
187 |
-%% Function: get_result_field_info(MySQLRes) |
|
188 |
-%% MySQLRes = term(), result of fetch function on "data" |
|
189 |
-%% Descrip.: Extract the FieldInfo from MySQL Result on data received |
|
190 |
-%% Returns : FieldInfo |
|
191 |
-%% FieldInfo = list() of {Table, Field, Length, Name} |
|
192 |
-%%-------------------------------------------------------------------- |
|
193 |
-get_result_field_info(#mysql_result{fieldinfo = FieldInfo}) -> |
|
194 |
- FieldInfo. |
|
195 |
- |
|
196 |
-%%-------------------------------------------------------------------- |
|
197 |
-%% Function: get_result_rows(MySQLRes) |
|
198 |
-%% MySQLRes = term(), result of fetch function on "data" |
|
199 |
-%% Descrip.: Extract the Rows from MySQL Result on data received |
|
200 |
-%% Returns : Rows |
|
201 |
-%% Rows = list() of list() representing records |
|
202 |
-%%-------------------------------------------------------------------- |
|
203 |
-get_result_rows(#mysql_result{rows=AllRows}) -> |
|
204 |
- AllRows. |
|
205 |
- |
|
206 |
-%%-------------------------------------------------------------------- |
|
207 |
-%% Function: get_result_affected_rows(MySQLRes) |
|
208 |
-%% MySQLRes = term(), result of fetch function on "updated" |
|
209 |
-%% Descrip.: Extract the Rows from MySQL Result on update |
|
210 |
-%% Returns : AffectedRows |
|
211 |
-%% AffectedRows = integer() |
|
212 |
-%%-------------------------------------------------------------------- |
|
213 |
-get_result_affected_rows(#mysql_result{affectedrows=AffectedRows}) -> |
|
214 |
- AffectedRows. |
|
215 |
- |
|
216 |
-%%-------------------------------------------------------------------- |
|
217 |
-%% Function: get_result_reason(MySQLRes) |
|
218 |
-%% MySQLRes = term(), result of fetch function on "error" |
|
219 |
-%% Descrip.: Extract the error Reason from MySQL Result on error |
|
220 |
-%% Returns : Reason |
|
221 |
-%% Reason = string() |
|
222 |
-%%-------------------------------------------------------------------- |
|
223 |
-get_result_reason(#mysql_result{error=Reason}) -> |
|
224 |
- Reason. |
|
225 |
- |
|
226 |
-%%-------------------------------------------------------------------- |
|
227 |
-%% Function: quote(String) |
|
228 |
-%% String = string() |
|
229 |
-%% Descrip.: Quote a string so that it can be included safely in a |
|
230 |
-%% MySQL query. |
|
231 |
-%% Returns : Quoted = string() |
|
232 |
-%%-------------------------------------------------------------------- |
|
233 |
-quote(String) when is_list(String) -> |
|
234 |
- [34 | lists:reverse([34 | quote(String, [])])]. %% 34 is $" |
|
235 |
- |
|
236 |
-quote([], Acc) -> |
|
237 |
- Acc; |
|
238 |
-quote([0 | Rest], Acc) -> |
|
239 |
- quote(Rest, [$0, $\\ | Acc]); |
|
240 |
-quote([10 | Rest], Acc) -> |
|
241 |
- quote(Rest, [$n, $\\ | Acc]); |
|
242 |
-quote([13 | Rest], Acc) -> |
|
243 |
- quote(Rest, [$r, $\\ | Acc]); |
|
244 |
-quote([$\\ | Rest], Acc) -> |
|
245 |
- quote(Rest, [$\\ , $\\ | Acc]); |
|
246 |
-quote([39 | Rest], Acc) -> %% 39 is $' |
|
247 |
- quote(Rest, [39, $\\ | Acc]); %% 39 is $' |
|
248 |
-quote([34 | Rest], Acc) -> %% 34 is $" |
|
249 |
- quote(Rest, [34, $\\ | Acc]); %% 34 is $" |
|
250 |
-quote([26 | Rest], Acc) -> |
|
251 |
- quote(Rest, [$Z, $\\ | Acc]); |
|
252 |
-quote([C | Rest], Acc) -> |
|
253 |
- quote(Rest, [C | Acc]). |
|
254 |
- |
|
255 |
-%%-------------------------------------------------------------------- |
|
256 |
-%% Function: asciz_binary(Data, Acc) |
|
257 |
-%% Data = binary() |
|
258 |
-%% Acc = list(), input accumulator |
|
259 |
-%% Descrip.: Find the first zero-byte in Data and add everything |
|
260 |
-%% before it to Acc, as a string. |
|
261 |
-%% Returns : {NewList, Rest} |
|
262 |
-%% NewList = list(), Acc plus what we extracted from Data |
|
263 |
-%% Rest = binary(), whatever was left of Data, not |
|
264 |
-%% including the zero-byte |
|
265 |
-%%-------------------------------------------------------------------- |
|
266 |
-asciz_binary(<<>>, Acc) -> |
|
267 |
- {lists:reverse(Acc), <<>>}; |
|
268 |
-asciz_binary(<<0:8, Rest/binary>>, Acc) -> |
|
269 |
- {lists:reverse(Acc), Rest}; |
|
270 |
-asciz_binary(<<C:8, Rest/binary>>, Acc) -> |
|
271 |
- asciz_binary(Rest, [C | Acc]). |
|
272 |
- |
|
273 |
-%%-------------------------------------------------------------------- |
|
274 |
-%% Function: connect(Id, Host, Port, User, Password, Database, |
|
275 |
-%% Reconnect) |
|
276 |
-%% Id = term(), connection-group Id |
|
277 |
-%% Host = string() |
|
278 |
-%% Port = undefined | integer() |
|
279 |
-%% User = string() |
|
280 |
-%% Password = string() |
|
281 |
-%% Database = string() |
|
282 |
-%% Reconnect = true | false |
|
283 |
-%% Descrip.: Starts a MySQL connection and, if successfull, registers |
|
284 |
-%% it with the mysql_dispatcher. |
|
285 |
-%% Returns : {ok, ConnPid} | {error, Reason} |
|
286 |
-%%-------------------------------------------------------------------- |
|
287 |
-connect(Id, Host, undefined, User, Password, Database, Reconnect) -> |
|
288 |
- connect(Id, Host, ?PORT, User, Password, Database, Reconnect); |
|
289 |
-connect(Id, Host, Port, User, Password, Database, Reconnect) -> |
|
290 |
- {ok, LogFun} = gen_server:call(?SERVER, get_logfun), |
|
291 |
- case mysql_conn:start(Host, Port, User, Password, Database, LogFun) of |
|
292 |
- {ok, ConnPid} -> |
|
293 |
- MysqlConn = |
|
294 |
- case Reconnect of |
|
295 |
- true -> |
|
296 |
- #mysql_connection{id = Id, |
|
297 |
- conn_pid = ConnPid, |
|
298 |
- reconnect = true, |
|
299 |
- host = Host, |
|
300 |
- port = Port, |
|
301 |
- user = User, |
|
302 |
- password = Password, |
|
303 |
- database = Database |
|
304 |
- }; |
|
305 |
- false -> |
|
306 |
- #mysql_connection{id = Id, |
|
307 |
- conn_pid = ConnPid, |
|
308 |
- reconnect = false |
|
309 |
- } |
|
310 |
- end, |
|
311 |
- case gen_server:call(?SERVER, {add_mysql_connection, MysqlConn}) of |
|
312 |
- ok -> |
|
313 |
- {ok, ConnPid}; |
|
314 |
- Res -> |
|
315 |
- Res |
|
316 |
- end; |
|
317 |
- {error, Reason} -> |
|
318 |
- {error, Reason} |
|
319 |
- end. |
|
320 |
- |
|
321 |
-%%-------------------------------------------------------------------- |
|
322 |
-%% Function: log(LogFun, Level, Format) |
|
323 |
-%% log(LogFun, Level, Format, Arguments) |
|
324 |
-%% LogFun = undefined | function() with arity 3 |
|
325 |
-%% Level = debug | normal | error |
|
326 |
-%% Format = string() |
|
327 |
-%% Arguments = list() of term() |
|
328 |
-%% Descrip.: Either call the function LogFun with the Level, Format |
|
329 |
-%% and Arguments as parameters or log it to the console if |
|
330 |
-%% LogFun is undefined. |
|
331 |
-%% Returns : void() |
|
332 |
-%% |
|
333 |
-%% Note : Exported only for use by the mysql_* modules. |
|
334 |
-%% |
|
335 |
-%%-------------------------------------------------------------------- |
|
336 |
-log(LogFun, Level, Format) -> |
|
337 |
- log(LogFun, Level, Format, []). |
|
338 |
- |
|
339 |
-log(LogFun, Level, Format, Arguments) when is_function(LogFun) -> |
|
340 |
- LogFun(Level, Format, Arguments); |
|
341 |
-log(undefined, _Level, Format, Arguments) -> |
|
342 |
- %% default is to log to console |
|
343 |
- io:format(Format, Arguments), |
|
344 |
- io:format("~n", []). |
|
345 |
- |
|
346 |
- |
|
347 |
-%%==================================================================== |
|
348 |
-%% gen_server callbacks |
|
349 |
-%%==================================================================== |
|
350 |
- |
|
351 |
-%%-------------------------------------------------------------------- |
|
352 |
-%% Function: init(Args) -> {ok, State} | |
|
353 |
-%% {ok, State, Timeout} | |
|
354 |
-%% ignore | |
|
355 |
-%% {stop, Reason} |
|
356 |
-%% Args = [Id, Host, Port, User, Password, Database, LogFun] |
|
357 |
-%% Id = term(), connection-group Id |
|
358 |
-%% Host = string() |
|
359 |
-%% Port = integer() |
|
360 |
-%% User = string() |
|
361 |
-%% Password = string() |
|
362 |
-%% Database = string() |
|
363 |
-%% LogFun = undefined | function() with arity 3 |
|
364 |
-%% Descrip.: Initiates the gen_server (MySQL dispatcher). |
|
365 |
-%%-------------------------------------------------------------------- |
|
366 |
-init([Id, Host, Port, User, Password, Database, LogFun]) -> |
|
367 |
- case mysql_conn:start(Host, Port, User, Password, Database, LogFun) of |
|
368 |
- {ok, ConnPid} -> |
|
369 |
- MysqlConn = #mysql_connection{id = Id, |
|
370 |
- conn_pid = ConnPid, |
|
371 |
- reconnect = true, |
|
372 |
- host = Host, |
|
373 |
- port = Port, |
|
374 |
- user = User, |
|
375 |
- password = Password, |
|
376 |
- database = Database |
|
377 |
- }, |
|
378 |
- case add_mysql_conn(MysqlConn, []) of |
|
379 |
- {ok, ConnList} -> |
|
380 |
- {ok, #state{log_fun = LogFun, |
|
381 |
- conn_list = ConnList |
|
382 |
- }}; |
|
383 |
- error -> |
|
384 |
- Msg = "mysql: Failed adding first MySQL connection handler to my list, exiting", |
|
385 |
- log(LogFun, error, Msg), |
|
386 |
- {error, Msg} |
|
387 |
- end; |
|
388 |
- {error, Reason} -> |
|
389 |
- log(LogFun, error, "mysql: Failed starting first MySQL connection handler, exiting"), |
|
390 |
- {stop, {error, Reason}} |
|
391 |
- end. |
|
392 |
- |
|
393 |
-%%-------------------------------------------------------------------- |
|
394 |
-%% Function: handle_call(Msg, From, State) |
|
395 |
-%% Descrip.: Handling call messages. |
|
396 |
-%% Returns : {reply, Reply, State} | |
|
397 |
-%% {reply, Reply, State, Timeout} | |
|
398 |
-%% {noreply, State} | |
|
399 |
-%% {noreply, State, Timeout} | |
|
400 |
-%% {stop, Reason, Reply, State} | (terminate/2 is called) |
|
401 |
-%% {stop, Reason, State} (terminate/2 is called) |
|
402 |
-%%-------------------------------------------------------------------- |
|
403 |
- |
|
404 |
- |
|
405 |
-%%-------------------------------------------------------------------- |
|
406 |
-%% Function: handle_call({fetch, Id, Query}, From, State) |
|
407 |
-%% Id = term(), connection-group id |
|
408 |
-%% Query = string(), MySQL query |
|
409 |
-%% Descrip.: Make a MySQL query. Use the first connection matching Id |
|
410 |
-%% in our connection-list. Don't block the mysql_dispatcher |
|
411 |
-%% by returning {noreply, ...} here and let the mysql_conn |
|
412 |
-%% do gen_server:reply(...) when it has an answer. |
|
413 |
-%% Returns : {noreply, NewState} | |
|
414 |
-%% {reply, {error, Reason}, State} |
|
415 |
-%% NewState = state record() |
|
416 |
-%% Reason = atom() | string() |
|
417 |
-%%-------------------------------------------------------------------- |
|
418 |
-handle_call({fetch, Id, Query}, From, State) -> |
|
419 |
- log(State#state.log_fun, debug, "mysql: fetch ~p (id ~p)", [Query, Id]), |
|
420 |
- case get_next_mysql_connection_for_id(Id, State#state.conn_list) of |
|
421 |
- {ok, MysqlConn, RestOfConnList} when is_record(MysqlConn, mysql_connection) -> |
|
422 |
- mysql_conn:fetch(MysqlConn#mysql_connection.conn_pid, Query, From), |
|
423 |
- %% move this mysql socket to the back of the list |
|
424 |
- NewConnList = RestOfConnList ++ [MysqlConn], |
|
425 |
- %% The ConnPid process does a gen_server:reply() when it has an answer |
|
426 |
- {noreply, State#state{conn_list = NewConnList}}; |
|
427 |
- nomatch -> |
|
428 |
- %% we have no active connection matching Id |
|
429 |
- {reply, {error, no_connection}, State} |
|
430 |
- end; |
|
431 |
- |
|
432 |
-%%-------------------------------------------------------------------- |
|
433 |
-%% Function: handle_call({add_mysql_connection, Conn}, From, State) |
|
434 |
-%% Conn = mysql_connection record() |
|
435 |
-%% Descrip.: Add Conn to our list of connections. |
|
436 |
-%% Returns : {reply, Reply, NewState} |
|
437 |
-%% Reply = ok | {error, Reason} |
|
438 |
-%% NewState = state record() |
|
439 |
-%% Reason = string() |
|
440 |
-%%-------------------------------------------------------------------- |
|
441 |
-handle_call({add_mysql_connection, Conn}, _From, State) when is_record(Conn, mysql_connection) -> |
|
442 |
- case add_mysql_conn(Conn, State#state.conn_list) of |
|
443 |
- {ok, NewConnList} -> |
|
444 |
- {Id, ConnPid} = {Conn#mysql_connection.id, Conn#mysql_connection.conn_pid}, |
|
445 |
- log(State#state.log_fun, normal, "mysql: Added connection with id '~p' (pid ~p) to my list", |
|
446 |
- [Id, ConnPid]), |
|
447 |
- {reply, ok, State#state{conn_list = NewConnList}}; |
|
448 |
- error -> |
|
449 |
- {reply, {error, "failed adding MySQL connection to my list"}, State} |
|
450 |
- end; |
|
451 |
- |
|
452 |
-%%-------------------------------------------------------------------- |
|
453 |
-%% Function: handle_call(get_logfun, From, State) |
|
454 |
-%% Descrip.: Fetch our logfun. |
|
455 |
-%% Returns : {reply, {ok, LogFun}, State} |
|
456 |
-%% LogFun = undefined | function() with arity 3 |
|
457 |
-%%-------------------------------------------------------------------- |
|
458 |
-handle_call(get_logfun, _From, State) -> |
|
459 |
- {reply, {ok, State#state.log_fun}, State}; |
|
460 |
- |
|
461 |
-handle_call(Unknown, _From, State) -> |
|
462 |
- log(State#state.log_fun, error, "mysql: Received unknown gen_server call : ~p", [Unknown]), |
|
463 |
- {reply, {error, "unknown gen_server call in mysql client"}, State}. |
|
464 |
- |
|
465 |
- |
|
466 |
-%%-------------------------------------------------------------------- |
|
467 |
-%% Function: handle_cast(Msg, State) |
|
468 |
-%% Descrip.: Handling cast messages |
|
469 |
-%% Returns : {noreply, State} | |
|
470 |
-%% {noreply, State, Timeout} | |
|
471 |
-%% {stop, Reason, State} (terminate/2 is called) |
|
472 |
-%%-------------------------------------------------------------------- |
|
473 |
-handle_cast(Unknown, State) -> |
|
474 |
- log(State#state.log_fun, error, "mysql: Received unknown gen_server cast : ~p", [Unknown]), |
|
475 |
- {noreply, State}. |
|
476 |
- |
|
477 |
- |
|
478 |
-%%-------------------------------------------------------------------- |
|
479 |
-%% Function: handle_info(Msg, State) |
|
480 |
-%% Descrip.: Handling all non call/cast messages |
|
481 |
-%% Returns : {noreply, State} | |
|
482 |
-%% {noreply, State, Timeout} | |
|
483 |
-%% {stop, Reason, State} (terminate/2 is called) |
|
484 |
-%%-------------------------------------------------------------------- |
|
485 |
- |
|
486 |
-%%-------------------------------------------------------------------- |
|
487 |
-%% Function: handle_info({'DOWN', ...}, State) |
|
488 |
-%% Descrip.: Handle a message that one of our monitored processes |
|
489 |
-%% (mysql_conn processes in our connection list) has exited. |
|
490 |
-%% Remove the entry from our list. |
|
491 |
-%% Returns : {noreply, NewState} | |
|
492 |
-%% {stop, normal, State} |
|
493 |
-%% NewState = state record() |
|
494 |
-%% |
|
495 |
-%% Note : For now, we stop if our connection list becomes empty. |
|
496 |
-%% We should try to reconnect for a while first, to not |
|
497 |
-%% eventually stop the whole OTP application if the MySQL- |
|
498 |
-%% server is shut down and the mysql_dispatcher was super- |
|
499 |
-%% vised by an OTP supervisor. |
|
500 |
-%%-------------------------------------------------------------------- |
|
501 |
-handle_info({'DOWN', _MonitorRef, process, Pid, Info}, State) -> |
|
502 |
- LogFun = State#state.log_fun, |
|
503 |
- case remove_mysql_connection_using_pid(Pid, State#state.conn_list, []) of |
|
504 |
- {ok, Conn, NewConnList} -> |
|
505 |
- LogLevel = case Info of |
|
506 |
- normal -> normal; |
|
507 |
- _ -> error |
|
508 |
- end, |
|
509 |
- log(LogFun, LogLevel, "mysql: MySQL connection pid ~p exited : ~p", [Pid, Info]), |
|
510 |
- log(LogFun, normal, "mysql: Removed MySQL connection with pid ~p from list", |
|
511 |
- [Pid]), |
|
512 |
- case Conn#mysql_connection.reconnect of |
|
513 |
- true -> |
|
514 |
- start_reconnect(Conn, LogFun); |
|
515 |
- false -> |
|
516 |
- ok |
|
517 |
- end, |
|
518 |
- {noreply, State#state{conn_list = NewConnList}}; |
|
519 |
- nomatch -> |
|
520 |
- log(LogFun, error, "mysql: Received 'DOWN' signal from pid ~p not in my list", [Pid]), |
|
521 |
- {noreply, State} |
|
522 |
- end; |
|
523 |
- |
|
524 |
-handle_info(Info, State) -> |
|
525 |
- log(State#state.log_fun, error, "mysql: Received unknown signal : ~p", [Info]), |
|
526 |
- {noreply, State}. |
|
527 |
- |
|
528 |
-%%-------------------------------------------------------------------- |
|
529 |
-%% Function: terminate(Reason, State) |
|
530 |
-%% Descrip.: Shutdown the server |
|
531 |
-%% Returns : Reason |
|
532 |
-%%-------------------------------------------------------------------- |
|
533 |
-terminate(Reason, State) -> |
|
534 |
- LogFun = State#state.log_fun, |
|
535 |
- LogLevel = case Reason of |
|
536 |
- normal -> debug; |
|
537 |
- _ -> error |
|
538 |
- end, |
|
539 |
- log(LogFun, LogLevel, "mysql: Terminating with reason : ~p", [Reason]), |
|
540 |
- Reason. |
|
541 |
- |
|
542 |
-%%-------------------------------------------------------------------- |
|
543 |
-%% Function: code_change(_OldVsn, State, _Extra) |
|
544 |
-%% Descrip.: Convert process state when code is changed |
|
545 |
-%% Returns : {ok, State} |
|
546 |
-%%-------------------------------------------------------------------- |
|
547 |
-code_change(_OldVsn, State, _Extra) -> |
|
548 |
- {ok, State}. |
|
549 |
- |
|
550 |
-%%==================================================================== |
|
551 |
-%% Internal functions |
|
552 |
-%%==================================================================== |
|
553 |
- |
|
554 |
-%%-------------------------------------------------------------------- |
|
555 |
-%% Function: add_mysql_conn(Conn, ConnList) |
|
556 |
-%% Conn = mysql_connection record() |
|
557 |
-%% ConnList = list() of mysql_connection record() |
|
558 |
-%% Descrip.: Set up process monitoring of the mysql_conn process and |
|
559 |
-%% then add it (first) to ConnList. |
|
560 |
-%% Returns : NewConnList = list() of mysql_connection record() |
|
561 |
-%%-------------------------------------------------------------------- |
|
562 |
-add_mysql_conn(Conn, ConnList) when is_record(Conn, mysql_connection), is_list(ConnList) -> |
|
563 |
- erlang:monitor(process, Conn#mysql_connection.conn_pid), |
|
564 |
- {ok, [Conn | ConnList]}. |
|
565 |
- |
|
566 |
-%%-------------------------------------------------------------------- |
|
567 |
-%% Function: remove_mysql_connection_using_pid(Pid, ConnList) |
|
568 |
-%% Pid = pid() |
|
569 |
-%% ConnList = list() of mysql_connection record() |
|
570 |
-%% Descrip.: Removes the first mysql_connection in ConnList that has |
|
571 |
-%% a pid matching Pid. |
|
572 |
-%% Returns : {ok, Conn, NewConnList} | nomatch |
|
573 |
-%% Conn = mysql_connection record() |
|
574 |
-%% NewConnList = list() of mysql_connection record() |
|
575 |
-%%-------------------------------------------------------------------- |
|
576 |
-remove_mysql_connection_using_pid(Pid, [#mysql_connection{conn_pid = Pid} = H | T], Res) -> |
|
577 |
- {ok, H, lists:reverse(Res) ++ T}; |
|
578 |
-remove_mysql_connection_using_pid(Pid, [H | T], Res) when is_record(H, mysql_connection) -> |
|
579 |
- remove_mysql_connection_using_pid(Pid, T, [H | Res]); |
|
580 |
-remove_mysql_connection_using_pid(_Pid, [], _Res) -> |
|
581 |
- nomatch. |
|
582 |
- |
|
583 |
-%%-------------------------------------------------------------------- |
|
584 |
-%% Function: get_next_mysql_connection_for_id(Id, ConnList) |
|
585 |
-%% Id = term(), connection-group id |
|
586 |
-%% ConnList = list() of mysql_connection record() |
|
587 |
-%% Descrip.: Find the first mysql_connection in ConnList that has an |
|
588 |
-%% id matching Id. |
|
589 |
-%% Returns : {ok, Conn, NewConnList} | nomatch |
|
590 |
-%% Conn = mysql_connection record() |
|
591 |
-%% NewConnList = list() of mysql_connection record(), same |
|
592 |
-%% as ConnList but without Conn |
|
593 |
-%%-------------------------------------------------------------------- |
|
594 |
-get_next_mysql_connection_for_id(Id, ConnList) -> |
|
595 |
- get_next_mysql_connection_for_id(Id, ConnList, []). |
|
596 |
- |
|
597 |
-get_next_mysql_connection_for_id(Id, [#mysql_connection{id = Id} = H | T], Res) -> |
|
598 |
- {ok, H, lists:reverse(Res) ++ T}; |
|
599 |
-get_next_mysql_connection_for_id(Id, [H | T], Res) when is_record(H, mysql_connection) -> |
|
600 |
- get_next_mysql_connection_for_id(Id, T, [H | Res]); |
|
601 |
-get_next_mysql_connection_for_id(_Id, [], _Res) -> |
|
602 |
- nomatch. |
|
603 |
- |
|
604 |
-%%-------------------------------------------------------------------- |
|
605 |
-%% Function: start_reconnect(Conn, LogFun) |
|
606 |
-%% Conn = mysql_connection record() |
|
607 |
-%% LogFun = undefined | function() with arity 3 |
|
608 |
-%% Descrip.: Spawns a process that will try to re-establish a new |
|
609 |
-%% connection instead of the one in Conn which has just |
|
610 |
-%% died. |
|
611 |
-%% Returns : ok |
|
612 |
-%%-------------------------------------------------------------------- |
|
613 |
-start_reconnect(Conn, LogFun) when is_record(Conn, mysql_connection) -> |
|
614 |
- Pid = spawn(fun () -> |
|
615 |
- reconnect_loop(Conn#mysql_connection{conn_pid = undefined}, LogFun, 0) |
|
616 |
- end), |
|
617 |
- {Id, Host, Port} = {Conn#mysql_connection.id, Conn#mysql_connection.host, Conn#mysql_connection.port}, |
|
618 |
- log(LogFun, debug, "mysql: Started pid ~p to try and reconnect to ~p:~s:~p (replacing " |
|
619 |
- "connection with pid ~p)", [Pid, Id, Host, Port, Conn#mysql_connection.conn_pid]), |
|
620 |
- ok. |
|
621 |
- |
|
622 |
-%%-------------------------------------------------------------------- |
|
623 |
-%% Function: reconnect_loop(Conn, LogFun, 0) |
|
624 |
-%% Conn = mysql_connection record() |
|
625 |
-%% LogFun = undefined | function() with arity 3 |
|
626 |
-%% Descrip.: Loop indefinately until we are able to reconnect to the |
|
627 |
-%% server specified in the now dead connection Conn. |
|
628 |
-%% Returns : ok |
|
629 |
-%%-------------------------------------------------------------------- |
|
630 |
-reconnect_loop(Conn, LogFun, N) when is_record(Conn, mysql_connection) -> |
|
631 |
- {Id, Host, Port} = {Conn#mysql_connection.id, Conn#mysql_connection.host, Conn#mysql_connection.port}, |
|
632 |
- case connect(Id, |
|
633 |
- Host, |
|
634 |
- Port, |
|
635 |
- Conn#mysql_connection.user, |
|
636 |
- Conn#mysql_connection.password, |
|
637 |
- Conn#mysql_connection.database, |
|
638 |
- Conn#mysql_connection.reconnect) of |
|
639 |
- {ok, ConnPid} -> |
|
640 |
- log(LogFun, debug, "mysql_reconnect: Managed to reconnect to ~p:~s:~p (connection pid ~p)", |
|
641 |
- [Id, Host, Port, ConnPid]), |
|
642 |
- ok; |
|
643 |
- {error, Reason} -> |
|
644 |
- %% log every once in a while |
|
645 |
- NewN = case N of |
|
646 |
- 10 -> |
|
647 |
- log(LogFun, debug, "mysql_reconnect: Still unable to connect to ~p:~s:~p (~p)", |
|
648 |
- [Id, Host, Port, Reason]), |
|
649 |
- 0; |
|
650 |
- _ -> |
|
651 |
- N + 1 |
|
652 |
- end, |
|
653 |
- %% sleep between every unsuccessfull attempt |
|
654 |
- timer:sleep(20 * 1000), |
|
655 |
- reconnect_loop(Conn, LogFun, NewN) |
|
656 |
- end. |
... | ... |
@@ -1,189 +0,0 @@ |
1 |
-%%%------------------------------------------------------------------- |
|
2 |
-%%% File : mysql_auth.erl |
|
3 |
-%%% Author : Fredrik Thulin <ft@it.su.se> |
|
4 |
-%%% Descrip.: MySQL client authentication functions. |
|
5 |
-%%% Created : 4 Aug 2005 by Fredrik Thulin <ft@it.su.se> |
|
6 |
-%%% |
|
7 |
-%%% Note : All MySQL code was written by Magnus Ahltorp, originally |
|
8 |
-%%% in the file mysql.erl - I just moved it here. |
|
9 |
-%%% |
|
10 |
-%%% Copyright (c) 2001-2004 Kungliga Tekniska H�gskolan |
|
11 |
-%%% See the file COPYING |
|
12 |
-%%% |
|
13 |
-%%%------------------------------------------------------------------- |
|
14 |
--module(mysql_auth). |
|
15 |
- |
|
16 |
-%%-------------------------------------------------------------------- |
|
17 |
-%% External exports (should only be used by the 'mysql_conn' module) |
|
18 |
-%%-------------------------------------------------------------------- |
|
19 |
--export([ |
|
20 |
- do_old_auth/7, |
|
21 |
- do_new_auth/8 |
|
22 |
- ]). |
|
23 |
- |
|
24 |
-%%-------------------------------------------------------------------- |
|
25 |
-%% Macros |
|
26 |
-%%-------------------------------------------------------------------- |
|
27 |
--define(LONG_PASSWORD, 1). |
|
28 |
--define(LONG_FLAG, 4). |
|
29 |
--define(PROTOCOL_41, 512). |
|
30 |
--define(TRANSACTIONS, 8192). |
|
31 |
--define(SECURE_CONNECTION, 32768). |
|
32 |
--define(CONNECT_WITH_DB, 8). |
|
33 |
- |
|
34 |
--define(MAX_PACKET_SIZE, 1000000). |
|
35 |
- |
|
36 |
-%%==================================================================== |
|
37 |
-%% External functions |
|
38 |
-%%==================================================================== |
|
39 |
- |
|
40 |
-%%-------------------------------------------------------------------- |
|
41 |
-%% Function: do_old_auth(Sock, RecvPid, SeqNum, User, Password, Salt1, |
|
42 |
-%% LogFun) |
|
43 |
-%% Sock = term(), gen_tcp socket |
|
44 |
-%% RecvPid = pid(), receiver process pid |
|
45 |
-%% SeqNum = integer(), first sequence number we should use |
|
46 |
-%% User = string(), MySQL username |
|
47 |
-%% Password = string(), MySQL password |
|
48 |
-%% Salt1 = string(), salt 1 from server greeting |
|
49 |
-%% LogFun = undefined | function() of arity 3 |
|
50 |
-%% Descrip.: Perform old-style MySQL authentication. |
|
51 |
-%% Returns : result of mysql_conn:do_recv/3 |
|
52 |
-%%-------------------------------------------------------------------- |
|
53 |
-do_old_auth(Sock, RecvPid, SeqNum, User, Password, Salt1, LogFun) -> |
|
54 |
- Auth = password_old(Password, Salt1), |
|
55 |
- Packet2 = make_auth(User, Auth), |
|
56 |
- do_send(Sock, Packet2, SeqNum, LogFun), |
|
57 |
- mysql_conn:do_recv(LogFun, RecvPid, SeqNum). |
|
58 |
- |
|
59 |
-%%-------------------------------------------------------------------- |
|
60 |
-%% Function: do_new_auth(Sock, RecvPid, SeqNum, User, Password, Salt1, |
|
61 |
-%% Salt2, LogFun) |
|
62 |
-%% Sock = term(), gen_tcp socket |
|
63 |
-%% RecvPid = pid(), receiver process pid |
|
64 |
-%% SeqNum = integer(), first sequence number we should use |
|
65 |
-%% User = string(), MySQL username |
|
66 |
-%% Password = string(), MySQL password |
|
67 |
-%% Salt1 = string(), salt 1 from server greeting |
|
68 |
-%% Salt2 = string(), salt 2 from server greeting |
|
69 |
-%% LogFun = undefined | function() of arity 3 |
|
70 |
-%% Descrip.: Perform MySQL authentication. |
|
71 |
-%% Returns : result of mysql_conn:do_recv/3 |
|
72 |
-%%-------------------------------------------------------------------- |
|
73 |
-do_new_auth(Sock, RecvPid, SeqNum, User, Password, Salt1, Salt2, LogFun) -> |
|
74 |
- Auth = password_new(Password, Salt1 ++ Salt2), |
|
75 |
- Packet2 = make_new_auth(User, Auth, none), |
|
76 |
- do_send(Sock, Packet2, SeqNum, LogFun), |
|
77 |
- case mysql_conn:do_recv(LogFun, RecvPid, SeqNum) of |
|
78 |
- {ok, Packet3, SeqNum2} -> |
|
79 |
- case Packet3 of |
|
80 |
- <<254:8>> -> |
|
81 |
- AuthOld = password_old(Password, Salt1), |
|
82 |
- do_send(Sock, <<AuthOld/binary, 0:8>>, SeqNum2 + 1, LogFun), |
|
83 |
- mysql_conn:do_recv(LogFun, RecvPid, SeqNum2 + 1); |
|
84 |
- _ -> |
|
85 |
- {ok, Packet3, SeqNum2} |
|
86 |
- end; |
|
87 |
- {error, Reason} -> |
|
88 |
- {error, Reason} |
|
89 |
- end. |
|
90 |
- |
|
91 |
-%%==================================================================== |
|
92 |
-%% Internal functions |
|
93 |
-%%==================================================================== |
|
94 |
- |
|
95 |
-password_old(Password, Salt) -> |
|
96 |
- {P1, P2} = hash(Password), |
|
97 |
- {S1, S2} = hash(Salt), |
|
98 |
- Seed1 = P1 bxor S1, |
|
99 |
- Seed2 = P2 bxor S2, |
|
100 |
- List = rnd(9, Seed1, Seed2), |
|
101 |
- {L, [Extra]} = lists:split(8, List), |
|
102 |
- list_to_binary(lists:map(fun (E) -> |
|
103 |
- E bxor (Extra - 64) |
|
104 |
- end, L)). |
|
105 |
- |
|
106 |
-%% part of do_old_auth/4, which is part of mysql_init/4 |
|
107 |
-make_auth(User, Password) -> |
|
108 |
- Caps = ?LONG_PASSWORD bor ?LONG_FLAG bor ?TRANSACTIONS, |
|
109 |
- Maxsize = 0, |
|
110 |
- UserB = list_to_binary(User), |
|
111 |
- PasswordB = Password, |
|
112 |
- <<Caps:16/little, Maxsize:24/little, UserB/binary, 0:8, |
|
113 |
- PasswordB/binary>>. |
|
114 |
- |
|
115 |
-%% part of do_new_auth/4, which is part of mysql_init/4 |
|
116 |
-make_new_auth(User, Password, Database) -> |
|
117 |
- DBCaps = case Database of |
|
118 |
- none -> |
|
119 |
- 0; |
|
120 |
- _ -> |
|
121 |
- ?CONNECT_WITH_DB |
|
122 |
- end, |
|
123 |
- Caps = ?LONG_PASSWORD bor ?LONG_FLAG bor ?TRANSACTIONS bor |
|
124 |
- ?PROTOCOL_41 bor ?SECURE_CONNECTION bor DBCaps, |
|
125 |
- Maxsize = ?MAX_PACKET_SIZE, |
|
126 |
- UserB = list_to_binary(User), |
|
127 |
- PasswordL = size(Password), |
|
128 |
- DatabaseB = case Database of |
|
129 |
- none -> |
|
130 |
- <<>>; |
|
131 |
- _ -> |
|
132 |
- list_to_binary(Database) |
|
133 |
- end, |
|
134 |
- <<Caps:32/little, Maxsize:32/little, 8:8, 0:23/integer-unit:8, |
|
135 |
- UserB/binary, 0:8, PasswordL:8, Password/binary, DatabaseB/binary>>. |
|
136 |
- |
|
137 |
-hash(S) -> |
|
138 |
- hash(S, 1345345333, 305419889, 7). |
|
139 |
- |
|
140 |
-hash([C | S], N1, N2, Add) -> |
|
141 |
- N1_1 = N1 bxor (((N1 band 63) + Add) * C + N1 * 256), |
|
142 |
- N2_1 = N2 + ((N2 * 256) bxor N1_1), |
|
143 |
- Add_1 = Add + C, |
|
144 |
- hash(S, N1_1, N2_1, Add_1); |
|
145 |
-hash([], N1, N2, _Add) -> |
|
146 |
- Mask = (1 bsl 31) - 1, |
|
147 |
- {N1 band Mask , N2 band Mask}. |
|
148 |
- |
|
149 |
-rnd(N, Seed1, Seed2) -> |
|
150 |
- Mod = (1 bsl 30) - 1, |
|
151 |
- rnd(N, [], Seed1 rem Mod, Seed2 rem Mod). |
|
152 |
- |
|
153 |
-rnd(0, List, _, _) -> |
|
154 |
- lists:reverse(List); |
|
155 |
-rnd(N, List, Seed1, Seed2) -> |
|
156 |
- Mod = (1 bsl 30) - 1, |
|
157 |
- NSeed1 = (Seed1 * 3 + Seed2) rem Mod, |
|
158 |
- NSeed2 = (NSeed1 + Seed2 + 33) rem Mod, |
|
159 |
- Float = (float(NSeed1) / float(Mod))*31, |
|
160 |
- Val = trunc(Float)+64, |
|
161 |
- rnd(N - 1, [Val | List], NSeed1, NSeed2). |
|
162 |
- |
|
163 |
- |
|
164 |
- |
|
165 |
-dualmap(_F, [], []) -> |
|
166 |
- []; |
|
167 |
-dualmap(F, [E1 | R1], [E2 | R2]) -> |
|
168 |
- [F(E1, E2) | dualmap(F, R1, R2)]. |
|
169 |
- |
|
170 |
-bxor_binary(B1, B2) -> |
|
171 |
- list_to_binary(dualmap(fun (E1, E2) -> |
|
172 |
- E1 bxor E2 |
|
173 |
- end, binary_to_list(B1), binary_to_list(B2))). |
|
174 |
- |
|
175 |
-password_new(Password, Salt) -> |
|
176 |
- Stage1 = crypto:sha(Password), |
|
177 |
- Stage2 = crypto:sha(Stage1), |
|
178 |
- Res = crypto:sha_final( |
|
179 |
- crypto:sha_update( |
|
180 |
- crypto:sha_update(crypto:sha_init(), Salt), |
|
181 |
- Stage2) |
|
182 |
- ), |
|
183 |
- bxor_binary(Res, Stage1). |
|
184 |
- |
|
185 |
- |
|
186 |
-do_send(Sock, Packet, Num, LogFun) -> |
|
187 |
- mysql:log(LogFun, debug, "mysql_auth send packet ~p: ~p", [Num, Packet]), |
|
188 |
- Data = <<(size(Packet)):24/little, Num:8, Packet/binary>>, |
|
189 |
- gen_tcp:send(Sock, Data). |
... | ... |
@@ -1,620 +0,0 @@ |
1 |
-%%%------------------------------------------------------------------- |
|
2 |
-%%% File : mysql_conn.erl |
|
3 |
-%%% Author : Fredrik Thulin <ft@it.su.se> |
|
4 |
-%%% Descrip.: MySQL connection handler, handles de-framing of messages |
|
5 |
-%%% received by the MySQL receiver process. |
|
6 |
-%%% Created : 5 Aug 2005 by Fredrik Thulin <ft@it.su.se> |
|
7 |
-%%% Modified: 11 Jan 2006 by Mickael Remond <mickael.remond@process-one.net> |
|
8 |
-%%% |
|
9 |
-%%% Note : All MySQL code was written by Magnus Ahltorp, originally |
|
10 |
-%%% in the file mysql.erl - I just moved it here. |
|
11 |
-%%% |
|
12 |
-%%% Copyright (c) 2001-2004 Kungliga Tekniska H�gskolan |
|
13 |
-%%% See the file COPYING |
|
14 |
-%%% |
|
15 |
-%%% |
|
16 |
-%%% This module handles a single connection to a single MySQL server. |
|
17 |
-%%% You can use it stand-alone, or through the 'mysql' module if you |
|
18 |
-%%% want to have more than one connection to the server, or |
|
19 |
-%%% connections to different servers. |
|
20 |
-%%% |
|
21 |
-%%% To use it stand-alone, set up the connection with |
|
22 |
-%%% |
|
23 |
-%%% {ok, Pid} = mysql_conn:start(Host, Port, User, Password, |
|
24 |
-%%% Database, LogFun) |
|
25 |
-%%% |
|
26 |
-%%% Host = string() |
|
27 |
-%%% Port = integer() |
|
28 |
-%%% User = string() |
|
29 |
-%%% Password = string() |
|
30 |
-%%% Database = string() |
|
31 |
-%%% LogFun = undefined | (gives logging to console) |
|
32 |
-%%% function() of arity 3 (Level, Fmt, Args) |
|
33 |
-%%% |
|
34 |
-%%% Note: In stand-alone mode you have to start Erlang crypto application by |
|
35 |
-%%% yourself with crypto:start() |
|
36 |
-%%% |
|
37 |
-%%% and then make MySQL querys with |
|
38 |
-%%% |
|
39 |
-%%% Result = mysql_conn:fetch(Pid, Query, self()) |
|
40 |
-%%% |
|
41 |
-%%% Result = {data, MySQLRes} | |
|
42 |
-%%% {updated, MySQLRes} | |
|
43 |
-%%% {error, MySQLRes} |
|
44 |
-%%% Where: MySQLRes = #mysql_result |
|
45 |
-%%% |
|
46 |
-%%% Actual data can be extracted from MySQLRes by calling the following API |
|
47 |
-%%% functions: |
|
48 |
-%%% - on data received: |
|
49 |
-%%% FieldInfo = mysql:get_result_field_info(MysqlRes) |
|
50 |
-%%% AllRows = mysql:get_result_rows(MysqlRes) |
|
51 |
-%%% with FieldInfo = list() of {Table, Field, Length, Name} |
|
52 |
-%%% and AllRows = list() of list() representing records |
|
53 |
-%%% - on update: |
|
54 |
-%%% Affected= mysql:get_result_affected_rows(MysqlRes) |
|
55 |
-%%% with Affected = integer() |
|
56 |
-%%% - on error: |
|
57 |
-%%% Reason = mysql:get_result_reason(MysqlRes) |
|
58 |
-%%% with Reason = string() |
|
59 |
-%%%------------------------------------------------------------------- |
|
60 |
- |
|
61 |
--module(mysql_conn). |
|
62 |
- |
|
63 |
-%%-------------------------------------------------------------------- |
|
64 |
-%% External exports |
|
65 |
-%%-------------------------------------------------------------------- |
|
66 |
--export([start/6, |
|
67 |
- start_link/6, |
|
68 |
- fetch/3, |
|
69 |
- fetch/4 |
|
70 |
- ]). |
|
71 |
- |
|
72 |
-%%-------------------------------------------------------------------- |
|
73 |
-%% External exports (should only be used by the 'mysql_auth' module) |
|
74 |
-%%-------------------------------------------------------------------- |
|
75 |
--export([do_recv/3 |
|
76 |
- ]). |
|
77 |
- |
|
78 |
--include("mysql.hrl"). |
|
79 |
--record(state, { |
|
80 |
- mysql_version, |
|
81 |
- log_fun, |
|
82 |
- recv_pid, |
|
83 |
- socket, |
|
84 |
- data |
|
85 |
- }). |
|
86 |
- |
|
87 |
--define(SECURE_CONNECTION, 32768). |
|
88 |
--define(MYSQL_QUERY_OP, 3). |
|
89 |
--define(DEFAULT_STANDALONE_TIMEOUT, 5000). |
|
90 |
--define(MYSQL_4_0, 40). %% Support for MySQL 4.0.x |
|
91 |
--define(MYSQL_4_1, 41). %% Support for MySQL 4.1.x et 5.0.x |
|
92 |
- |
|
93 |
-%%==================================================================== |
|
94 |
-%% External functions |
|
95 |
-%%==================================================================== |
|
96 |
- |
|
97 |
-%%-------------------------------------------------------------------- |
|
98 |
-%% Function: start(Host, Port, User, Password, Database, LogFun) |
|
99 |
-%% Function: start_link(Host, Port, User, Password, Database, LogFun) |
|
100 |
-%% Host = string() |
|
101 |
-%% Port = integer() |
|
102 |
-%% User = string() |
|
103 |
-%% Password = string() |
|
104 |
-%% Database = string() |
|
105 |
-%% LogFun = undefined | function() of arity 3 |
|
106 |
-%% Descrip.: Starts a mysql_conn process that connects to a MySQL |
|
107 |
-%% server, logs in and chooses a database. |
|
108 |
-%% Returns : {ok, Pid} | {error, Reason} |
|
109 |
-%% Pid = pid() |
|
110 |
-%% Reason = string() |
|
111 |
-%%-------------------------------------------------------------------- |
|
112 |
-start(Host, Port, User, Password, Database, LogFun) when is_list(Host), is_integer(Port), is_list(User), |
|
113 |
- is_list(Password), is_list(Database) -> |
|
114 |
- ConnPid = self(), |
|
115 |
- Pid = spawn(fun () -> |
|
116 |
- init(Host, Port, User, Password, Database, LogFun, ConnPid) |
|
117 |
- end), |
|
118 |
- post_start(Pid, LogFun). |
|
119 |
- |
|
120 |
-start_link(Host, Port, User, Password, Database, LogFun) when is_list(Host), is_integer(Port), is_list(User), |
|
121 |
- is_list(Password), is_list(Database) -> |
|
122 |
- ConnPid = self(), |
|
123 |
- Pid = spawn_link(fun () -> |
|
124 |
- init(Host, Port, User, Password, Database, LogFun, ConnPid) |
|
125 |
- end), |
|
126 |
- post_start(Pid, LogFun). |
|
127 |
- |
|
128 |
-%% part of start/6 or start_link/6: |
|
129 |
-post_start(Pid, LogFun) -> |
|
130 |
- receive |
|
131 |
- {mysql_conn, Pid, ok} -> |
|
132 |
- {ok, Pid}; |
|
133 |
- {mysql_conn, Pid, {error, Reason}} -> |
|
134 |
- {error, Reason}; |
|
135 |
- Unknown -> |
|
136 |
- mysql:log(LogFun, error, "mysql_conn: Received unknown signal, exiting"), |
|
137 |
- mysql:log(LogFun, debug, "mysql_conn: Unknown signal : ~p", [Unknown]), |
|
138 |
- {error, "unknown signal received"} |
|
139 |
- after 5000 -> |
|
140 |
- {error, "timed out"} |
|
141 |
- end. |
|
142 |
- |
|
143 |
-%%-------------------------------------------------------------------- |
|
144 |
-%% Function: fetch(Pid, Query, From) |
|
145 |
-%% fetch(Pid, Query, From, Timeout) |
|
146 |
-%% Pid = pid(), mysql_conn to send fetch-request to |
|
147 |
-%% Query = string(), MySQL query in verbatim |
|
148 |
-%% From = pid() or term(), use a From of self() when |
|
149 |
-%% using this module for a single connection, |
|
150 |
-%% or pass the gen_server:call/3 From argument if |
|
151 |
-%% using a gen_server to do the querys (e.g. the |
|
152 |
-%% mysql_dispatcher) |
|
153 |
-%% Timeout = integer() | infinity, gen_server timeout value |
|
154 |
-%% Descrip.: Send a query and wait for the result if running stand- |
|
155 |
-%% alone (From = self()), but don't block the caller if we |
|
156 |
-%% are not running stand-alone (From = gen_server From). |
|
157 |
-%% Returns : ok | (non-stand-alone mode) |
|
158 |
-%% {data, #mysql_result} | (stand-alone mode) |
|
159 |
-%% {updated, #mysql_result} | (stand-alone mode) |
|
160 |
-%% {error, #mysql_result} (stand-alone mode) |
|
161 |
-%% FieldInfo = term() |
|
162 |
-%% Rows = list() of [string()] |
|
163 |
-%% Reason = term() |
|
164 |
-%%-------------------------------------------------------------------- |
|
165 |
-fetch(Pid, Query, From) -> |
|
166 |
- fetch(Pid, Query, From, ?DEFAULT_STANDALONE_TIMEOUT). |
|
167 |
- |
|
168 |
-fetch(Pid, Query, From, Timeout) when is_pid(Pid), is_list(Query) -> |
|
169 |
- Self = self(), |
|
170 |
- Pid ! {fetch, Query, From}, |
|
171 |
- case From of |
|
172 |
- Self -> |
|
173 |
- %% We are not using a mysql_dispatcher, await the response |
|
174 |
- receive |
|
175 |
- {fetch_result, Pid, Result} -> |
|
176 |
- Result |
|
177 |
- after Timeout -> |
|
178 |
- {error, "query timed out"} |
|
179 |
- end; |
|
180 |
- _ -> |
|
181 |
- %% From is gen_server From, Pid will do gen_server:reply() when it has an answer |
|
182 |
- ok |
|
183 |
- end. |
|
184 |
- |
|
185 |
-%%-------------------------------------------------------------------- |
|
186 |
-%% Function: do_recv(LogFun, RecvPid, SeqNum) |
|
187 |
-%% LogFun = undefined | function() with arity 3 |
|
188 |
-%% RecvPid = pid(), mysql_recv process |
|
189 |
-%% SeqNum = undefined | integer() |
|
190 |
-%% Descrip.: Wait for a frame decoded and sent to us by RecvPid. |
|
191 |
-%% Either wait for a specific frame if SeqNum is an integer, |
|
192 |
-%% or just any frame if SeqNum is undefined. |
|
193 |
-%% Returns : {ok, Packet, Num} | |
|
194 |
-%% {error, Reason} |
|
195 |
-%% Reason = term() |
|
196 |
-%% |
|
197 |
-%% Note : Only to be used externally by the 'mysql_auth' module. |
|
198 |
-%%-------------------------------------------------------------------- |
|
199 |
-do_recv(LogFun, RecvPid, SeqNum) when is_function(LogFun); LogFun == undefined, SeqNum == undefined -> |
|
200 |
- receive |
|
201 |
- {mysql_recv, RecvPid, data, Packet, Num} -> |
|
202 |
- %%mysql:log(LogFun, debug, "mysql_conn: recv packet ~p: ~p", [Num, Packet]), |
|
203 |
- {ok, Packet, Num}; |
|
204 |
- {mysql_recv, RecvPid, closed, _E} -> |
|
205 |
- {error, "mysql_recv: socket was closed"} |
|
206 |
- end; |
|
207 |
-do_recv(LogFun, RecvPid, SeqNum) when is_function(LogFun); LogFun == undefined, is_integer(SeqNum) -> |
|
208 |
- ResponseNum = SeqNum + 1, |
|
209 |
- receive |
|
210 |
- {mysql_recv, RecvPid, data, Packet, ResponseNum} -> |
|
211 |
- %%mysql:log(LogFun, debug, "mysql_conn: recv packet ~p: ~p", [ResponseNum, Packet]), |
|
212 |
- {ok, Packet, ResponseNum}; |
|
213 |
- {mysql_recv, RecvPid, closed, _E} -> |
|
214 |
- {error, "mysql_recv: socket was closed"} |
|
215 |
- end. |
|
216 |
- |
|
217 |
- |
|
218 |
-%%==================================================================== |
|
219 |
-%% Internal functions |
|
220 |
-%%==================================================================== |
|
221 |
- |
|
222 |
-%%-------------------------------------------------------------------- |
|
223 |
-%% Function: init(Host, Port, User, Password, Database, LogFun, |
|
224 |
-%% Parent) |
|
225 |
-%% Host = string() |
|
226 |
-%% Port = integer() |
|
227 |
-%% User = string() |
|
228 |
-%% Password = string() |
|
229 |
-%% Database = string() |
|
230 |
-%% LogFun = undefined | function() of arity 3 |
|
231 |
-%% Parent = pid() of process starting this mysql_conn |
|
232 |
-%% Descrip.: Connect to a MySQL server, log in and chooses a database. |
|
233 |
-%% Report result of this to Parent, and then enter loop() if |
|
234 |
-%% we were successfull. |
|
235 |
-%% Returns : void() | does not return |
|
236 |
-%%-------------------------------------------------------------------- |
|
237 |
-init(Host, Port, User, Password, Database, LogFun, Parent) -> |
|
238 |
- case mysql_recv:start_link(Host, Port, LogFun, self()) of |
|
239 |
- {ok, RecvPid, Sock} -> |
|
240 |
- case mysql_init(Sock, RecvPid, User, Password, LogFun) of |
|
241 |
- {ok, Version} -> |
|
242 |
- case do_query(Sock, RecvPid, LogFun, "use " ++ Database, Version) of |
|
243 |
- {error, MySQLRes} -> |
|
244 |
- mysql:log(LogFun, error, "mysql_conn: Failed changing to database ~p : ~p", |
|
245 |
- [Database, mysql:get_result_reason(MySQLRes)]), |
|
246 |
- Parent ! {mysql_conn, self(), {error, failed_changing_database}}; |
|
247 |
- %% ResultType: data | updated |
|
248 |
- {_ResultType, _MySQLRes} -> |
|
249 |
- Parent ! {mysql_conn, self(), ok}, |
|
250 |
- State = #state{mysql_version=Version, |
|
251 |
- recv_pid = RecvPid, |
|
252 |
- socket = Sock, |
|
253 |
- log_fun = LogFun, |
|
254 |
- data = <<>> |
|
255 |
- }, |
|
256 |
- loop(State) |
|
257 |
- end; |
|
258 |
- {error, _Reason} -> |
|
259 |
- Parent ! {mysql_conn, self(), {error, login_failed}} |
|
260 |
- end; |
|
261 |
- E -> |
|
262 |
- mysql:log(LogFun, error, "mysql_conn: Failed connecting to ~p:~p : ~p", |
|
263 |
- [Host, Port, E]), |
|
264 |
- Parent ! {mysql_conn, self(), {error, connect_failed}} |
|
265 |
- end. |
|
266 |
- |
|
267 |
-%%-------------------------------------------------------------------- |
|
268 |
-%% Function: loop(State) |
|
269 |
-%% State = state record() |
|
270 |
-%% Descrip.: Wait for signals asking us to perform a MySQL query, or |
|
271 |
-%% signals that the socket was closed. |
|
272 |
-%% Returns : error | does not return |
|
273 |
-%%-------------------------------------------------------------------- |
|
274 |
-loop(State) -> |
|
275 |
- RecvPid = State#state.recv_pid, |
|
276 |
- receive |
|
277 |
- {fetch, Query, GenSrvFrom} -> |
|
278 |
- %% GenSrvFrom is either a gen_server:call/3 From term(), or a pid if no |
|
279 |
- %% gen_server was used to make the query |
|
280 |
- Res = do_query(State, Query), |
|
281 |
- case is_pid(GenSrvFrom) of |
|
282 |
- true -> |
|
283 |
- %% The query was not sent using gen_server mechanisms |
|
284 |
- GenSrvFrom ! {fetch_result, self(), Res}; |
|
285 |
- false -> |
|
286 |
- gen_server:reply(GenSrvFrom, Res) |
|
287 |
- end, |
|
288 |
- loop(State); |
|
289 |
- {mysql_recv, RecvPid, data, Packet, Num} -> |
|
290 |
- mysql:log(State#state.log_fun, error, "mysql_conn: Received MySQL data when not expecting any " |
|
291 |
- "(num ~p) - ignoring it", [Num]), |
|
292 |
- mysql:log(State#state.log_fun, error, "mysql_conn: Unexpected MySQL data (num ~p) :~n~p", |
|
293 |
- [Num, Packet]), |
|
294 |
- loop(State); |
|
295 |
- Unknown -> |
|
296 |
- mysql:log(State#state.log_fun, error, "mysql_conn: Received unknown signal, exiting"), |
|
297 |
- mysql:log(State#state.log_fun, debug, "mysql_conn: Unknown signal : ~p", [Unknown]), |
|
298 |
- error |
|
299 |
- end. |
|
300 |
- |
|
301 |
-%%-------------------------------------------------------------------- |
|
302 |
-%% Function: mysql_init(Sock, RecvPid, User, Password, LogFun) |
|
303 |
-%% Sock = term(), gen_tcp socket |
|
304 |
-%% RecvPid = pid(), mysql_recv process |
|
305 |
-%% User = string() |
|
306 |
-%% Password = string() |
|
307 |
-%% LogFun = undefined | function() with arity 3 |
|
308 |
-%% Descrip.: Try to authenticate on our new socket. |
|
309 |
-%% Returns : ok | {error, Reason} |
|
310 |
-%% Reason = string() |
|
311 |
-%%-------------------------------------------------------------------- |
|
312 |
-mysql_init(Sock, RecvPid, User, Password, LogFun) -> |
|
313 |
- case do_recv(LogFun, RecvPid, undefined) of |
|
314 |
- {ok, Packet, InitSeqNum} -> |
|
315 |
- {Version, Salt1, Salt2, Caps} = greeting(Packet, LogFun), |
|
316 |
- AuthRes = |
|
317 |
- case Caps band ?SECURE_CONNECTION of |
|
318 |
- ?SECURE_CONNECTION -> |
|
319 |
- mysql_auth:do_new_auth(Sock, RecvPid, InitSeqNum + 1, User, Password, Salt1, Salt2, LogFun); |
|
320 |
- _ -> |
|
321 |
- mysql_auth:do_old_auth(Sock, RecvPid, InitSeqNum + 1, User, Password, Salt1, LogFun) |
|
322 |
- end, |
|
323 |
- case AuthRes of |
|
324 |
- {ok, <<0:8, _Rest/binary>>, _RecvNum} -> |
|
325 |
- {ok,Version}; |
|
326 |
- {ok, <<255:8, Code:16/little, Message/binary>>, _RecvNum} -> |
|
327 |
- mysql:log(LogFun, error, "mysql_conn: init error ~p: ~p~n", [Code, binary_to_list(Message)]), |
|
328 |
- {error, binary_to_list(Message)}; |
|
329 |
- {ok, RecvPacket, _RecvNum} -> |
|
330 |
- mysql:log(LogFun, error, "mysql_conn: init unknown error ~p~n", [binary_to_list(RecvPacket)]), |
|
331 |
- {error, binary_to_list(RecvPacket)}; |
|
332 |
- {error, Reason} -> |
|
333 |
- mysql:log(LogFun, error, "mysql_conn: init failed receiving data : ~p~n", [Reason]), |
|
334 |
- {error, Reason} |
|
335 |
- end; |
|
336 |
- {error, Reason} -> |
|
337 |
- {error, Reason} |
|
338 |
- end. |
|
339 |
- |
|
340 |
-%% part of mysql_init/4 |
|
341 |
-greeting(Packet, LogFun) -> |
|
342 |
- <<Protocol:8, Rest/binary>> = Packet, |
|
343 |
- {Version, Rest2} = asciz(Rest), |
|
344 |
- <<_TreadID:32/little, Rest3/binary>> = Rest2, |
|
345 |
- {Salt, Rest4} = asciz(Rest3), |
|
346 |
- <<Caps:16/little, Rest5/binary>> = Rest4, |
|
347 |
- <<ServerChar:16/binary-unit:8, Rest6/binary>> = Rest5, |
|
348 |
- {Salt2, _Rest7} = asciz(Rest6), |
|
349 |
- mysql:log(LogFun, debug, "mysql_conn: greeting version ~p (protocol ~p) salt ~p caps ~p serverchar ~p salt2 ~p", |
|
350 |
- [Version, Protocol, Salt, Caps, ServerChar, Salt2]), |
|
351 |
- {normalize_version(Version, LogFun), Salt, Salt2, Caps}. |
|
352 |
- |
|
353 |
-%% part of greeting/2 |
|
354 |
-asciz(Data) when binary(Data) -> |
|
355 |
- mysql:asciz_binary(Data, []); |
|
356 |
-asciz(Data) when list(Data) -> |
|
357 |
- {String, [0 | Rest]} = lists:splitwith(fun (C) -> |
|
358 |
- C /= 0 |
|
359 |
- end, Data), |
|
360 |
- {String, Rest}. |
|
361 |
- |
|
362 |
-%%-------------------------------------------------------------------- |
|
363 |
-%% Function: get_query_response(LogFun, RecvPid) |
|
364 |
-%% LogFun = undefined | function() with arity 3 |
|
365 |
-%% RecvPid = pid(), mysql_recv process |
|
366 |
-%% Version = integer(), Representing MySQL version used |
|
367 |
-%% Descrip.: Wait for frames until we have a complete query response. |
|
368 |
-%% Returns : {data, #mysql_result} |
|
369 |
-%% {updated, #mysql_result} |
|
370 |
-%% {error, #mysql_result} |
|
371 |
-%% FieldInfo = list() of term() |
|
372 |
-%% Rows = list() of [string()] |
|
373 |
-%% AffectedRows = int() |
|
374 |
-%% Reason = term() |
|
375 |
-%%-------------------------------------------------------------------- |
|
376 |
-get_query_response(LogFun, RecvPid, Version) -> |
|
377 |
- case do_recv(LogFun, RecvPid, undefined) of |
|
378 |
- {ok, <<Fieldcount:8, Rest/binary>>, _} -> |
|
379 |
- case Fieldcount of |
|
380 |
- 0 -> |
|
381 |
- %% No Tabular data |
|
382 |
- <<AffectedRows:8, _Rest2/binary>> = Rest, |
|
383 |
- {updated, #mysql_result{affectedrows=AffectedRows}}; |
|
384 |
- 255 -> |
|
385 |
- <<_Code:16/little, Message/binary>> = Rest, |
|
386 |
- {error, #mysql_result{error=binary_to_list(Message)}}; |
|
387 |
- _ -> |
|
388 |
- %% Tabular data received |
|
389 |
- case get_fields(LogFun, RecvPid, [], Version) of |
|
390 |
- {ok, Fields} -> |
|
391 |
- case get_rows(Fieldcount, LogFun, RecvPid, []) of |
|
392 |
- {ok, Rows} -> |
|
393 |
- {data, #mysql_result{fieldinfo=Fields, rows=Rows}}; |
|
394 |
- {error, Reason} -> |
|
395 |
- {error, #mysql_result{error=Reason}} |
|
396 |
- end; |
|
397 |
- {error, Reason} -> |
|
398 |
- {error, #mysql_result{error=Reason}} |
|
399 |
- end |
|
400 |
- end; |
|
401 |
- {error, Reason} -> |
|
402 |
- {error, #mysql_result{error=Reason}} |
|
403 |
- end. |
|
404 |
- |
|
405 |
-%%-------------------------------------------------------------------- |
|
406 |
-%% Function: get_fields(LogFun, RecvPid, [], Version) |
|
407 |
-%% LogFun = undefined | function() with arity 3 |
|
408 |
-%% RecvPid = pid(), mysql_recv process |
|
409 |
-%% Version = integer(), Representing MySQL version used |
|
410 |
-%% Descrip.: Received and decode field information. |
|
411 |
-%% Returns : {ok, FieldInfo} | |
|
412 |
-%% {error, Reason} |
|
413 |
-%% FieldInfo = list() of term() |
|
414 |
-%% Reason = term() |
|
415 |
-%%-------------------------------------------------------------------- |
|
416 |
-%% Support for MySQL 4.0.x: |
|
417 |
-get_fields(LogFun, RecvPid, Res, ?MYSQL_4_0) -> |
|
418 |
- case do_recv(LogFun, RecvPid, undefined) of |
|
419 |
- {ok, Packet, _Num} -> |
|
420 |
- case Packet of |
|
421 |
- <<254:8>> -> |
|
422 |
- {ok, lists:reverse(Res)}; |
|
423 |
- <<254:8, Rest/binary>> when size(Rest) < 8 -> |
|
424 |
- {ok, lists:reverse(Res)}; |
|
425 |
- _ -> |
|
426 |
- {Table, Rest} = get_with_length(Packet), |
|
427 |
- {Field, Rest2} = get_with_length(Rest), |
|
428 |
- {LengthB, Rest3} = get_with_length(Rest2), |
|
429 |
- LengthL = size(LengthB) * 8, |
|
430 |
- <<Length:LengthL/little>> = LengthB, |
|
431 |
- {Type, Rest4} = get_with_length(Rest3), |
|
432 |
- {_Flags, _Rest5} = get_with_length(Rest4), |
|
433 |
- This = {binary_to_list(Table), |
|
434 |
- binary_to_list(Field), |
|
435 |
- Length, |
|
436 |
- %% TODO: Check on MySQL 4.0 if types are specified |
|
437 |
- %% using the same 4.1 formalism and could |
|
438 |
- %% be expanded to atoms: |
|
439 |
- binary_to_list(Type)}, |
|
440 |
- get_fields(LogFun, RecvPid, [This | Res], ?MYSQL_4_0) |
|
441 |
- end; |
|
442 |
- {error, Reason} -> |
|
443 |
- {error, Reason} |
|
444 |
- end; |
|
445 |
-%% Support for MySQL 4.1.x and 5.x: |
|
446 |
-get_fields(LogFun, RecvPid, Res, ?MYSQL_4_1) -> |
|
447 |
- case do_recv(LogFun, RecvPid, undefined) of |
|
448 |
- {ok, Packet, _Num} -> |
|
449 |
- case Packet of |
|
450 |
- <<254:8>> -> |
|
451 |
- {ok, lists:reverse(Res)}; |
|
452 |
- <<254:8, Rest/binary>> when size(Rest) < 8 -> |
|
453 |
- {ok, lists:reverse(Res)}; |
|
454 |
- _ -> |
|
455 |
- {_Catalog, Rest} = get_with_length(Packet), |
|
456 |
- {_Database, Rest2} = get_with_length(Rest), |
|
457 |
- {Table, Rest3} = get_with_length(Rest2), |
|
458 |
- %% OrgTable is the real table name if Table is an alias |
|
459 |
- {_OrgTable, Rest4} = get_with_length(Rest3), |
|
460 |
- {Field, Rest5} = get_with_length(Rest4), |
|
461 |
- %% OrgField is the real field name if Field is an alias |
|
462 |
- {_OrgField, Rest6} = get_with_length(Rest5), |
|
463 |
- |
|
464 |
- <<_Metadata:8/little, _Charset:16/little, |
|
465 |
- Length:32/little, Type:8/little, |
|
466 |
- _Flags:16/little, _Decimals:8/little, |
|
467 |
- _Rest7/binary>> = Rest6, |
|
468 |
- |
|
469 |
- This = {binary_to_list(Table), |
|
470 |
- binary_to_list(Field), |
|
471 |
- Length, |
|
472 |
- get_field_datatype(Type)}, |
|
473 |
- get_fields(LogFun, RecvPid, [This | Res], ?MYSQL_4_1) |
|
474 |
- end; |
|
475 |
- {error, Reason} -> |
|
476 |
- {error, Reason} |
|
477 |
- end. |
|
478 |
- |
|
479 |
-%%-------------------------------------------------------------------- |
|
480 |
-%% Function: get_rows(N, LogFun, RecvPid, []) |
|
481 |
-%% N = integer(), number of rows to get |
|
482 |
-%% LogFun = undefined | function() with arity 3 |
|
483 |
-%% RecvPid = pid(), mysql_recv process |
|
484 |
-%% Descrip.: Receive and decode a number of rows. |
|
485 |
-%% Returns : {ok, Rows} | |
|
486 |
-%% {error, Reason} |
|
487 |
-%% Rows = list() of [string()] |
|
488 |
-%%-------------------------------------------------------------------- |
|
489 |
-get_rows(N, LogFun, RecvPid, Res) -> |
|
490 |
- case do_recv(LogFun, RecvPid, undefined) of |
|
491 |
- {ok, Packet, _Num} -> |
|
492 |
- case Packet of |
|
493 |
- <<254:8, Rest/binary>> when size(Rest) < 8 -> |
|
494 |
- {ok, lists:reverse(Res)}; |
|
495 |
- _ -> |
|
496 |
- {ok, This} = get_row(N, Packet, []), |
|
497 |
- get_rows(N, LogFun, RecvPid, [This | Res]) |
|
498 |
- end; |
|
499 |
- {error, Reason} -> |
|
500 |
- {error, Reason} |
|
501 |
- end. |
|
502 |
- |
|
503 |
-%% part of get_rows/4 |
|
504 |
-get_row(0, _Data, Res) -> |
|
505 |
- {ok, lists:reverse(Res)}; |
|
506 |
-get_row(N, Data, Res) -> |
|
507 |
- {Col, Rest} = get_with_length(Data), |
|
508 |
- This = case Col of |
|
509 |
- null -> |
|
510 |
- null; |
|
511 |
- _ -> |
|
512 |
- binary_to_list(Col) |
|
513 |
- end, |
|
514 |
- get_row(N - 1, Rest, [This | Res]). |
|
515 |
- |
|
516 |
-get_with_length(<<251:8, Rest/binary>>) -> |
|
517 |
- {null, Rest}; |
|
518 |
-get_with_length(<<252:8, Length:16/little, Rest/binary>>) -> |
|
519 |
- split_binary(Rest, Length); |
|
520 |
-get_with_length(<<253:8, Length:24/little, Rest/binary>>) -> |
|
521 |
- split_binary(Rest, Length); |
|
522 |
-get_with_length(<<254:8, Length:64/little, Rest/binary>>) -> |
|
523 |
- split_binary(Rest, Length); |
|
524 |
-get_with_length(<<Length:8, Rest/binary>>) when Length < 251 -> |
|
525 |
- split_binary(Rest, Length). |
|
526 |
- |
|
527 |
-%%-------------------------------------------------------------------- |
|
528 |
-%% Function: do_query(State, Query) |
|
529 |
-%% do_query(Sock, RecvPid, LogFun, Query) |
|
530 |
-%% Sock = term(), gen_tcp socket |
|
531 |
-%% RecvPid = pid(), mysql_recv process |
|
532 |
-%% LogFun = undefined | function() with arity 3 |
|
533 |
-%% Query = string() |
|
534 |
-%% Descrip.: Send a MySQL query and block awaiting it's response. |
|
535 |
-%% Returns : result of get_query_response/2 | {error, Reason} |
|
536 |
-%%-------------------------------------------------------------------- |
|
537 |
-do_query(State, Query) when is_record(State, state) -> |
|
538 |
- do_query(State#state.socket, |
|
539 |
- State#state.recv_pid, |
|
540 |
- State#state.log_fun, |
|
541 |
- Query, |
|
542 |
- State#state.mysql_version |
|
543 |
- ). |
|
544 |
- |
|
545 |
-do_query(Sock, RecvPid, LogFun, Query, Version) when is_pid(RecvPid), |
|
546 |
- is_list(Query) -> |
|
547 |
- Packet = list_to_binary([?MYSQL_QUERY_OP, Query]), |
|
548 |
- case do_send(Sock, Packet, 0, LogFun) of |
|
549 |
- ok -> |
|
550 |
- get_query_response(LogFun, RecvPid, Version); |
|
551 |
- {error, Reason} -> |
|
552 |
- Msg = io_lib:format("Failed sending data on socket : ~p", [Reason]), |
|
553 |
- {error, Msg} |
|
554 |
- end. |
|
555 |
- |
|
556 |
-%%-------------------------------------------------------------------- |
|
557 |
-%% Function: do_send(Sock, Packet, SeqNum, LogFun) |
|
558 |
-%% Sock = term(), gen_tcp socket |
|
559 |
-%% Packet = binary() |
|
560 |
-%% SeqNum = integer(), packet sequence number |
|
561 |
-%% LogFun = undefined | function() with arity 3 |
|
562 |
-%% Descrip.: Send a packet to the MySQL server. |
|
563 |
-%% Returns : result of gen_tcp:send/2 |
|
564 |
-%%-------------------------------------------------------------------- |
|
565 |
-do_send(Sock, Packet, SeqNum, _LogFun) when is_binary(Packet), is_integer(SeqNum) -> |
|
566 |
- Data = <<(size(Packet)):24/little, SeqNum:8, Packet/binary>>, |
|
567 |
- %%mysql:log(LogFun, debug, "mysql_conn: send packet ~p: ~p", [SeqNum, Data]), |
|
568 |
- gen_tcp:send(Sock, Data). |
|
569 |
- |
|
570 |
-%%-------------------------------------------------------------------- |
|
571 |
-%% Function: normalize_version(Version, LogFun) |
|
572 |
-%% Version = string() |
|
573 |
-%% LogFun = undefined | function() with arity 3 |
|
574 |
-%% Descrip.: Return a flag corresponding to the MySQL version used. |
|
575 |
-%% The protocol used depends on this flag. |
|
576 |
-%% Returns : Version = string() |
|
577 |
-%%-------------------------------------------------------------------- |
|
578 |
-normalize_version([$4,$.,$0|_T], LogFun) -> |
|
579 |
- mysql:log(LogFun, debug, "Switching to MySQL 4.0.x protocol.~n"), |
|
580 |
- ?MYSQL_4_0; |
|
581 |
-normalize_version([$4,$.,$1|_T], _LogFun) -> |
|
582 |
- ?MYSQL_4_1; |
|
583 |
-normalize_version([$5|_T], _LogFun) -> |
|
584 |
- %% MySQL version 5.x protocol is compliant with MySQL 4.1.x: |
|
585 |
- ?MYSQL_4_1; |
|
586 |
-normalize_version(_Other, LogFun) -> |
|
587 |
- mysql:log(LogFun, error, "MySQL version not supported: MySQL Erlang module might not work correctly.~n"), |
|
588 |
- %% Error, but trying the oldest protocol anyway: |
|
589 |
- ?MYSQL_4_0. |
|
590 |
- |
|
591 |
-%%-------------------------------------------------------------------- |
|
592 |
-%% Function: get_field_datatype(DataType) |
|
593 |
-%% DataType = integer(), MySQL datatype |
|
594 |
-%% Descrip.: Return MySQL field datatype as description string |
|
595 |
-%% Returns : String, MySQL datatype |
|
596 |
-%%-------------------------------------------------------------------- |
|
597 |
-get_field_datatype(0) -> 'DECIMAL'; |
|
598 |
-get_field_datatype(1) -> 'TINY'; |
|
599 |
-get_field_datatype(2) -> 'SHORT'; |
|
600 |
-get_field_datatype(3) -> 'LONG'; |
|
601 |
-get_field_datatype(4) -> 'FLOAT'; |
|
602 |
-get_field_datatype(5) -> 'DOUBLE'; |
|
603 |
-get_field_datatype(6) -> 'NULL'; |
|
604 |
-get_field_datatype(7) -> 'TIMESTAMP'; |
|
605 |
-get_field_datatype(8) -> 'LONGLONG'; |
|
606 |
-get_field_datatype(9) -> 'INT24'; |
|
607 |
-get_field_datatype(10) -> 'DATE'; |
|
608 |
-get_field_datatype(11) -> 'TIME'; |
|
609 |
-get_field_datatype(12) -> 'DATETIME'; |
|
610 |
-get_field_datatype(13) -> 'YEAR'; |
|
611 |
-get_field_datatype(14) -> 'NEWDATE'; |
|
612 |
-get_field_datatype(247) -> 'ENUM'; |
|
613 |
-get_field_datatype(248) -> 'SET'; |
|
614 |
-get_field_datatype(249) -> 'TINYBLOB'; |
|
615 |
-get_field_datatype(250) -> 'MEDIUM_BLOG'; |
|
616 |
-get_field_datatype(251) -> 'LONG_BLOG'; |
|
617 |
-get_field_datatype(252) -> 'BLOB'; |
|
618 |
-get_field_datatype(253) -> 'VAR_STRING'; |
|
619 |
-get_field_datatype(254) -> 'STRING'; |
|
620 |
-get_field_datatype(255) -> 'GEOMETRY'. |
... | ... |
@@ -1,161 +0,0 @@ |
1 |
-%%%------------------------------------------------------------------- |
|
2 |
-%%% File : mysql_recv.erl |
|
3 |
-%%% Author : Fredrik Thulin <ft@it.su.se> |
|
4 |
-%%% Descrip.: Handles data being received on a MySQL socket. Decodes |
|
5 |
-%%% per-row framing and sends each row to parent. |
|
6 |
-%%% |
|
7 |
-%%% Created : 4 Aug 2005 by Fredrik Thulin <ft@it.su.se> |
|
8 |
-%%% |
|
9 |
-%%% Note : All MySQL code was written by Magnus Ahltorp, originally |
|
10 |
-%%% in the file mysql.erl - I just moved it here. |
|
11 |
-%%% |
|
12 |
-%%% Copyright (c) 2001-2004 Kungliga Tekniska H�gskolan |
|
13 |
-%%% See the file COPYING |
|
14 |
-%%% |
|
15 |
-%%% Signals this receiver process can send to it's parent |
|
16 |
-%%% (the parent is a mysql_conn connection handler) : |
|
17 |
-%%% |
|
18 |
-%%% {mysql_recv, self(), data, Packet, Num} |
|
19 |
-%%% {mysql_recv, self(), closed, {error, Reason}} |
|
20 |
-%%% {mysql_recv, self(), closed, normal} |
|
21 |
-%%% |
|
22 |
-%%% Internally (from inside init/4 to start_link/4) the |
|
23 |
-%%% following signals may be sent to the parent process : |
|
24 |
-%%% |
|
25 |
-%%% {mysql_recv, self(), init, {ok, Sock}} |
|
26 |
-%%% {mysql_recv, self(), init, {error, E}} |
|
27 |
-%%% |
|
28 |
-%%%------------------------------------------------------------------- |
|
29 |
--module(mysql_recv). |
|
30 |
- |
|
31 |
-%%-------------------------------------------------------------------- |
|
32 |
-%% External exports (should only be used by the 'mysql_conn' module) |
|
33 |
-%%-------------------------------------------------------------------- |
|
34 |
--export([start_link/4 |
|
35 |
- ]). |
|
36 |
- |
|
37 |
--record(state, { |
|
38 |
- socket, |
|
39 |
- parent, |
|
40 |
- log_fun, |
|
41 |
- data |
|
42 |
- }). |
|
43 |
- |
|
44 |
--define(SECURE_CONNECTION, 32768). |
|
45 |
--define(CONNECT_TIMEOUT, 5000). |
|
46 |
- |
|
47 |
-%%==================================================================== |
|
48 |
-%% External functions |
|
49 |
-%%==================================================================== |
|
50 |
- |
|
51 |
-%%-------------------------------------------------------------------- |
|
52 |
-%% Function: start_link(Host, Port, LogFun, Parent) |
|
53 |
-%% Host = string() |
|
54 |
-%% Port = integer() |
|
55 |
-%% LogFun = undefined | function() of arity 3 |
|
56 |
-%% Parent = pid(), process that should get received frames |
|
57 |
-%% Descrip.: Start a process that connects to Host:Port and waits for |
|
58 |
-%% data. When it has received a MySQL frame, it sends it to |
|
59 |
-%% Parent and waits for the next frame. |
|
60 |
-%% Returns : {ok, RecvPid, Socket} | |
|
61 |
-%% {error, Reason} |
|
62 |
-%% RecvPid = pid(), receiver process pid |
|
63 |
-%% Socket = term(), gen_tcp socket |
|
64 |
-%% Reason = atom() | string() |
|
65 |
-%%-------------------------------------------------------------------- |
|
66 |
-start_link(Host, Port, LogFun, Parent) when is_list(Host), is_integer(Port) -> |
|
67 |
- RecvPid = |
|
68 |
- spawn_link(fun () -> |
|
69 |
- init(Host, Port, LogFun, Parent) |
|
70 |
- end), |
|
71 |
- %% wait for the socket from the spawned pid |
|
72 |
- receive |
|
73 |
- {mysql_recv, RecvPid, init, {error, E}} -> |
|
74 |
- {error, E}; |
|
75 |
- {mysql_recv, RecvPid, init, {ok, Socket}} -> |
|
76 |
- {ok, RecvPid, Socket} |
|
77 |
- after ?CONNECT_TIMEOUT -> |
|
78 |
- catch exit(RecvPid, kill), |
|
79 |
- {error, "timeout"} |
|
80 |
- end. |
|
81 |
- |
|
82 |
- |
|
83 |
- |
|
84 |
-%%==================================================================== |
|
85 |
-%% Internal functions |
|
86 |
-%%==================================================================== |
|
87 |
- |
|
88 |
-%%-------------------------------------------------------------------- |
|
89 |
-%% Function: init((Host, Port, LogFun, Parent) |
|
90 |
-%% Host = string() |
|
91 |
-%% Port = integer() |
|
92 |
-%% LogFun = undefined | function() of arity 3 |
|
93 |
-%% Parent = pid(), process that should get received frames |
|
94 |
-%% Descrip.: Connect to Host:Port and then enter receive-loop. |
|
95 |
-%% Returns : error | never returns |
|
96 |
-%%-------------------------------------------------------------------- |
|
97 |
-init(Host, Port, LogFun, Parent) -> |
|
98 |
- case gen_tcp:connect(Host, Port, [binary, {packet, 0}]) of |
|
99 |
- {ok, Sock} -> |
|
100 |
- Parent ! {mysql_recv, self(), init, {ok, Sock}}, |
|
101 |
- State = #state{socket = Sock, |
|
102 |
- parent = Parent, |
|
103 |
- log_fun = LogFun, |
|
104 |
- data = <<>> |
|
105 |
- }, |
|
106 |
- loop(State); |
|
107 |
- E -> |
|
108 |
- mysql:log(LogFun, error, "mysql_recv: Failed connecting to ~p:~p : ~p", |
|
109 |
- [Host, Port, E]), |
|
110 |
- Msg = lists:flatten(io_lib:format("connect failed : ~p", [E])), |
|
111 |
- Parent ! {mysql_recv, self(), init, {error, Msg}} |
|
112 |
- end. |
|
113 |
- |
|
114 |
-%%-------------------------------------------------------------------- |
|
115 |
-%% Function: loop(State) |
|
116 |
-%% State = state record() |
|
117 |
-%% Descrip.: The main loop. Wait for data from our TCP socket and act |
|
118 |
-%% on received data or signals that our socket was closed. |
|
119 |
-%% Returns : error | never returns |
|
120 |
-%%-------------------------------------------------------------------- |
|
121 |
-loop(State) -> |
|
122 |
- Sock = State#state.socket, |
|
123 |
- receive |
|
124 |
- {tcp, Sock, InData} -> |
|
125 |
- NewData = list_to_binary([State#state.data, InData]), |
|
126 |
- %% send data to parent if we have enough data |
|
127 |
- Rest = sendpacket(State#state.parent, NewData), |
|
128 |
- loop(State#state{data = Rest}); |
|
129 |
- {tcp_error, Sock, Reason} -> |
|
130 |
- mysql:log(State#state.log_fun, error, "mysql_recv: Socket ~p closed : ~p", [Sock, Reason]), |
|
131 |
- State#state.parent ! {mysql_recv, self(), closed, {error, Reason}}, |
|
132 |
- error; |
|
133 |
- {tcp_closed, Sock} -> |
|
134 |
- mysql:log(State#state.log_fun, debug, "mysql_recv: Socket ~p closed", [Sock]), |
|
135 |
- State#state.parent ! {mysql_recv, self(), closed, normal}, |
|
136 |
- error |
|
137 |
- end. |
|
138 |
- |
|
139 |
-%%-------------------------------------------------------------------- |
|
140 |
-%% Function: sendpacket(Parent, Data) |
|
141 |
-%% Parent = pid() |
|
142 |
-%% Data = binary() |
|
143 |
-%% Descrip.: Check if we have received one or more complete frames by |
|
144 |
-%% now, and if so - send them to Parent. |
|
145 |
-%% Returns : Rest = binary() |
|
146 |
-%%-------------------------------------------------------------------- |
|
147 |
-%% send data to parent if we have enough data |
|
148 |
-sendpacket(Parent, Data) -> |
|
149 |
- case Data of |
|
150 |
- <<Length:24/little, Num:8, D/binary>> -> |
|
151 |
- if |
|
152 |
- Length =< size(D) -> |
|
153 |
- {Packet, Rest} = split_binary(D, Length), |
|
154 |
- Parent ! {mysql_recv, self(), data, Packet, Num}, |
|
155 |
- sendpacket(Parent, Rest); |
|
156 |
- true -> |
|
157 |
- Data |
|
158 |
- end; |
|
159 |
- _ -> |
|
160 |
- Data |
|
161 |
- end. |
... | ... |
@@ -1,38 +0,0 @@ |
1 |
-# Copyright 2004-2006 BreakMyGentoo.net |
|
2 |
-# Distributed under the terms of the GNU General Public License v2 |
|
3 |
-# $Header: $ |
|
4 |
- |
|
5 |
-inherit multilib |
|
6 |
- |
|
7 |
-DESCRIPTION="Native MySQL driver for OTP/erlang" |
|
8 |
-HOMEPAGE="http://process-one.net" |
|
9 |
-SRC_URI="" |
|
10 |
- |
|
11 |
-LICENSE="" |
|
12 |
-SLOT="0" |
|
13 |
-KEYWORDS="~amd64" |
|
14 |
-IUSE="" |
|
15 |
- |
|
16 |
-DEPEND="dev-lang/erlang" |
|
17 |
-RDEPEND="${DEPEND}" |
|
18 |
-S=${WORKDIR}/${P}/ |
|
19 |
- |
|
20 |
-src_unpack() { |
|
21 |
- cp -r ${FILESDIR}/${P} ${WORKDIR} |
|
22 |
-} |
|
23 |
- |
|
24 |
-src_compile() { |
|
25 |
- find -name "*.erl" -exec erlc {} \; |
|
26 |
-} |
|
27 |
- |
|
28 |
-src_install() { |
|
29 |
- local ERL_LIBDIR=/usr/$(get_libdir)/erlang/lib |
|
30 |
- |
|
31 |
- dodir ${ERL_LIBDIR}/${P}/ebin |
|
32 |
- insinto ${ERL_LIBDIR}/${P}/ebin |
|
33 |
- doins *.beam |
|
34 |
- |
|
35 |
- dodir ${ERL_LIBDIR}/${P}/src |
|
36 |
- insinto ${ERL_LIBDIR}/${P}/src |
|
37 |
- doins *.erl |
|
38 |
-} |
|
39 | 0 |