Lars Strojny

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,6 +0,0 @@
1
-%% MySQL result record:
2
--record(mysql_result,
3
-	{fieldinfo=[],
4
-	 rows=[],
5
-	 affectedrows=0,
6
-	 error=""}).
... ...
@@ -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