From 559b5cae14c0226abb1f24f6e43ce8315aa82c1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20R=C3=A9mond?= Date: Wed, 21 Dec 2005 16:10:56 +0000 Subject: [PATCH] * src/odbc/mysql.sql: Database description for MySQL Database 4.1 (Max version, with Innodb) * src/ejabberd_auth_odbc.erl: MySQL ODBC support. * src/mod_offline_odbc.erl: likewise * src/mod_vcard_odbc.erl: likewsie * src/mod_roster_odbc.erl: likewise * src/odbc/ejabberd_odbc.erl: likewise * src/mod_last_odbc.erl: likewise SVN Revision: 474 --- ChangeLog | 11 +++++ src/ejabberd_auth_odbc.erl | 50 ++++++++++++----------- src/mod_last_odbc.erl | 23 ++++------- src/mod_offline_odbc.erl | 28 ++++++------- src/mod_roster_odbc.erl | 82 ++++++++++++++++++++------------------ src/mod_vcard_odbc.erl | 63 +++++++++++++---------------- src/odbc/ejabberd_odbc.erl | 20 ++++++++-- 7 files changed, 147 insertions(+), 130 deletions(-) diff --git a/ChangeLog b/ChangeLog index 651d68667..2bb2ee46a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2005-12-21 Mickael Remond + + * src/odbc/mysql.sql: Database description for MySQL Database 4.1 (Max + version, with Innodb) + * src/ejabberd_auth_odbc.erl: MySQL ODBC support. + * src/mod_offline_odbc.erl: likewise + * src/mod_vcard_odbc.erl: likewsie + * src/mod_roster_odbc.erl: likewise + * src/odbc/ejabberd_odbc.erl: likewise + * src/mod_last_odbc.erl: likewise + 2005-12-16 Mickael Remond * doc/Makefile: Added helper to generate the docs (Thanks to Sander diff --git a/src/ejabberd_auth_odbc.erl b/src/ejabberd_auth_odbc.erl index 3a76d283c..c09133488 100644 --- a/src/ejabberd_auth_odbc.erl +++ b/src/ejabberd_auth_odbc.erl @@ -91,12 +91,12 @@ set_password(User, Server, Password) -> LUser -> Username = ejabberd_odbc:escape(LUser), Pass = ejabberd_odbc:escape(Password), - catch ejabberd_odbc:sql_query( - jlib:nameprep(Server), - ["begin;" - "delete from users where username='", Username ,"';" - "insert into users(username, password) " - "values ('", Username, "', '", Pass, "'); commit"]) + LServer = jlib:nameprep(Server), + catch ejabberd_odbc:sql_transaction( + LServer, + [["delete from users where username='", Username ,"';"], + ["insert into users(username, password) " + "values ('", Username, "', '", Pass, "');"]]) end. @@ -203,21 +203,25 @@ remove_user(User, Server, Password) -> LUser -> Username = ejabberd_odbc:escape(LUser), Pass = ejabberd_odbc:escape(Password), - case catch - ejabberd_odbc:sql_query( - jlib:nameprep(Server), - ["begin;" - "select password from users where username='", Username, "';" - "delete from users " - "where username='", Username, "' and password='", Pass, "';" - "commit"]) of - {selected, ["password"], [{Password}]} -> - ejabberd_hooks:run(remove_user, jlib:nameprep(Server), - [User, Server]), - ok; - {selected, ["password"], []} -> - not_exists; - _ -> - not_allowed - end + LServer = jlib:nameprep(Server), + F = fun() -> + Result = ejabberd_odbc:sql_query_t( + ["select password from users where username='", + Username, "';"]), + ejabberd_odbc:sql_query_t(["delete from users " + "where username='", Username, + "' and password='", Pass, "';"]), + case Result of + {selected, ["password"], [{Password}]} -> + ejabberd_hooks:run(remove_user, jlib:nameprep(Server), + [User, Server]), + ok; + {selected, ["password"], []} -> + not_exists; + _ -> + not_allowed + end + end, + {atomic, Result } = ejabberd_odbc:transaction(LServer, F), + Result end. diff --git a/src/mod_last_odbc.erl b/src/mod_last_odbc.erl index 1558cf097..1b9115238 100644 --- a/src/mod_last_odbc.erl +++ b/src/mod_last_odbc.erl @@ -56,7 +56,6 @@ process_local_iq(_From, _To, #iq{type = Type, sub_el = SubEl} = IQ) -> []}]} end. - process_sm_iq(From, To, #iq{type = Type, sub_el = SubEl} = IQ) -> case Type of set -> @@ -99,7 +98,7 @@ get_last(IQ, SubEl, LUser, LServer) -> case catch ejabberd_odbc:sql_query( LServer, ["select seconds, state from last " - "where username='", Username, "'"]) of + "where username='", Username, "';"]) of {'EXIT', _Reason} -> IQ#iq{type = error, sub_el = [SubEl, ?ERR_INTERNAL_SERVER_ERROR]}; {selected, ["seconds","state"], []} -> @@ -121,8 +120,6 @@ get_last(IQ, SubEl, LUser, LServer) -> end end. - - on_presence_update(User, Server, _Resource, Status) -> {MegaSecs, Secs, _MicroSecs} = now(), TimeStamp = MegaSecs * 1000000 + Secs, @@ -134,20 +131,16 @@ store_last_info(User, Server, TimeStamp, Status) -> Username = ejabberd_odbc:escape(LUser), Seconds = ejabberd_odbc:escape(integer_to_list(TimeStamp)), State = ejabberd_odbc:escape(Status), - ejabberd_odbc:sql_query( + %% MREMOND: I think this should be turn into a non transactional behaviour + ejabberd_odbc:sql_transaction( LServer, - ["begin;" - "delete from last where username='", Username, "';" - "insert into last(username, seconds, state) " - "values ('", Username, "', '", Seconds, "', '", State, "');", - "commit"]). - + [["delete from last where username='", Username, "';"], + ["insert into last(username, seconds, state) " + "values ('", Username, "', '", Seconds, "', '", State, "');"]]). remove_user(User, Server) -> LUser = jlib:nodeprep(User), LServer = jlib:nameprep(Server), Username = ejabberd_odbc:escape(LUser), - ejabberd_odbc:sql_query( - LServer, - ["delete from last where username='", Username, "'"]). - + ejabberd_odbc:sql_query(LServer, + ["delete from last where username='", Username, "';"]). diff --git a/src/mod_offline_odbc.erl b/src/mod_offline_odbc.erl index 1a62f08d8..2241ce27d 100644 --- a/src/mod_offline_odbc.erl +++ b/src/mod_offline_odbc.erl @@ -5,7 +5,6 @@ %%% Created : 5 Jan 2003 by Alexey Shchepin %%% Id : $Id$ %%%---------------------------------------------------------------------- - -module(mod_offline_odbc). -author('alexey@sevcom.net'). @@ -73,9 +72,9 @@ loop(Host) -> XML, "');"] end, Msgs), - case catch ejabberd_odbc:sql_query( + case catch ejabberd_odbc:sql_transaction( Host, - ["begin; ", Query, " commit"]) of + Query) of {'EXIT', Reason} -> ?ERROR_MSG("~p~n", [Reason]); _ -> @@ -212,17 +211,16 @@ pop_offline_messages(Ls, User, Server) -> LUser = jlib:nodeprep(User), LServer = jlib:nameprep(Server), EUser = ejabberd_odbc:escape(LUser), - case ejabberd_odbc:sql_query( - LServer, - ["begin;" - "select username, xml from spool where username='", EUser, "'" - " order by seq;" - "delete from spool where username='", EUser, "';" - "commit"]) of - [{updated, undefined}, - {selected, ["username","xml"], Rs}, - {updated, _}, - {updated, undefined}] -> + F = fun() -> + Result = ejabberd_odbc:sql_query_t( + ["select username, xml from spool where username='", EUser, "'" + " order by seq;"]), + ejabberd_odbc:sql_query_t( + ["delete from spool where username='", EUser, "';"]), + Result + end, + case ejabberd_odbc:sql_transaction(LServer,F) of + {atomic, {selected, ["username","xml"], Rs}} -> Ls ++ lists:flatmap( fun({_, XML}) -> case xml_stream:parse_element(XML) of @@ -253,5 +251,5 @@ remove_user(User, Server) -> Username = ejabberd_odbc:escape(LUser), ejabberd_odbc:sql_query( LServer, - ["delete from spool where username='", Username, "'"]). + ["delete from spool where username='", Username, "';"]). diff --git a/src/mod_roster_odbc.erl b/src/mod_roster_odbc.erl index 8b14e432c..be4392e2e 100644 --- a/src/mod_roster_odbc.erl +++ b/src/mod_roster_odbc.erl @@ -255,29 +255,35 @@ process_item_set(From, To, {xmlelement, _Name, Attrs, Els}) -> ejabberd_odbc:sql_query_t( ["delete from rosterusers " " where username='", Username, "' " - " and jid='", SJID, "';" - "delete from rostergroups " + " and jid='", SJID, "';"]), + ejabberd_odbc:sql_query_t( + ["delete from rostergroups " " where username='", Username, "' " - " and jid='", SJID, "'"]); + " and jid='", SJID, "';"]); _ -> ItemVals = record_to_string(Item2), ItemGroups = groups_to_string(Item2), ejabberd_odbc:sql_query_t( ["delete from rosterusers " " where username='", Username, "' " - " and jid='", SJID, "';" - "insert into rosterusers(" + " and jid='", SJID, "';"]), + ejabberd_odbc:sql_query_t( + ["insert into rosterusers(" " username, jid, nick, " " subscription, ask, " " server, subscribe, type) " - " values ", ItemVals, ";" - "delete from rostergroups " + " values ", ItemVals, ";"]), + ejabberd_odbc:sql_query_t( + ["delete from rostergroups " " where username='", Username, "' " - " and jid='", SJID, "';", - [["insert into rostergroups(" - " username, jid, grp) " - " values ", ItemGroup, ";"] || - ItemGroup <- ItemGroups]]) + " and jid='", SJID, "';"]), + lists:foreach(fun(ItemGroup) -> + ejabberd_odbc:sql_query_t( + ["insert into rostergroups(" + " username, jid, grp) " + " values ", ItemGroup, ";"]) + end, + ItemGroups) end, {Item, Item2} end, @@ -466,7 +472,7 @@ process_subscription(Direction, User, Server, JID1, Type) -> ["select username, jid, nick, subscription, ask, " "server, subscribe, type from rosterusers " "where username='", Username, "' " - "and jid='", SJID, "'"]) of + "and jid='", SJID, "';"]) of {selected, ["username", "jid", "nick", "subscription", "ask", "server", "subscribe", "type"], @@ -476,7 +482,7 @@ process_subscription(Direction, User, Server, JID1, Type) -> case ejabberd_odbc:sql_query_t( ["select grp from rostergroups " "where username='", Username, "' " - "and jid='", SJID, "'"]) of + "and jid='", SJID, "';"]) of {selected, ["grp"], JGrps} when is_list(JGrps) -> [JGrp || {JGrp} <- JGrps]; _ -> @@ -518,12 +524,13 @@ process_subscription(Direction, User, Server, JID1, Type) -> ejabberd_odbc:sql_query_t( ["delete from rosterusers " " where username='", Username, "' " - " and jid='", SJID, "';" - "insert into rosterusers(" + " and jid='", SJID, "';"]), + ejabberd_odbc:sql_query_t( + ["insert into rosterusers(" " username, jid, nick, " " subscription, ask, " " server, subscribe, type) " - " values ", ItemVals]), + " values ", ItemVals, ";"]), {{push, NewItem}, AutoReply} end end, @@ -659,9 +666,10 @@ remove_user(User, Server) -> fun() -> ejabberd_odbc:sql_query_t( ["delete from rosterusers " - " where username='", Username, "';" - "delete from rostergroups " - " where username='", Username, "'"]) + " where username='", Username, "';"]), + ejabberd_odbc:sql_query_t( + ["delete from rostergroups " + " where username='", Username, "';"]) end), ok. @@ -671,13 +679,11 @@ set_items(User, Server, SubEl) -> {xmlelement, _Name, _Attrs, Els} = SubEl, LUser = jlib:nodeprep(User), LServer = jlib:nameprep(Server), - catch ejabberd_odbc:sql_query( + catch ejabberd_odbc:transaction( LServer, - ["begin;", lists:map(fun(El) -> process_item_set_t(LUser, LServer, El) - end, Els), - "commit"]). + end, Els)). process_item_set_t(LUser, LServer, {xmlelement, _Name, Attrs, Els}) -> JID1 = jlib:string_to_jid(xml:get_attr_s("jid", Attrs)), @@ -695,26 +701,26 @@ process_item_set_t(LUser, LServer, {xmlelement, _Name, Attrs, Els}) -> Item2 = process_item_els(Item1, Els), case Item2#roster.subscription of remove -> - ["delete from rosterusers " + [["delete from rosterusers " " where username='", Username, "' " - " and jid='", SJID, "';" - "delete from rostergroups " + " and jid='", SJID, "';"], + ["delete from rostergroups " " where username='", Username, "' " - " and jid='", SJID, "';"]; + " and jid='", SJID, "';"]]; _ -> ItemVals = record_to_string(Item1), ItemGroups = groups_to_string(Item2), - ["delete from rosterusers " + [["delete from rosterusers " " where username='", Username, "' " - " and jid='", SJID, "';" - "insert into rosterusers(" - " username, jid, nick, " - " subscription, ask, " - " server, subscribe, type) " - " values ", ItemVals, ";" - "delete from rostergroups " - " where username='", Username, "' " - " and jid='", SJID, "';", + " and jid='", SJID, "';"], + ["insert into rosterusers(" + " username, jid, nick, " + " subscription, ask, " + " server, subscribe, type) " + " values ", ItemVals, ";"], + ["delete from rostergroups " + " where username='", Username, "' " + " and jid='", SJID, "';"], [["insert into rostergroups(" " username, jid, grp) " " values ", ItemGroup, ";"] || diff --git a/src/mod_vcard_odbc.erl b/src/mod_vcard_odbc.erl index 954c0f85c..ba5ef5b12 100644 --- a/src/mod_vcard_odbc.erl +++ b/src/mod_vcard_odbc.erl @@ -136,7 +136,7 @@ process_sm_iq(From, To, #iq{type = Type, sub_el = SubEl} = IQ) -> case catch ejabberd_odbc:sql_query( LServer, ["select vcard from vcard " - "where username='", Username, "'"]) of + "where username='", Username, "';"]) of {selected, ["vcard"], [{SVCARD}]} -> case xml_stream:parse_element(SVCARD) of {error, _Reason} -> @@ -231,32 +231,30 @@ set_vcard(User, LServer, VCARD) -> SOrgUnit = ejabberd_odbc:escape(OrgUnit), SLOrgUnit = ejabberd_odbc:escape(LOrgUnit), - ejabberd_odbc:sql_query( + ejabberd_odbc:sql_transaction( LServer, - ["begin;" - "delete from vcard where username='", LUsername, "';" - "insert into vcard(username, vcard) " - "values ('", LUsername, "', '", SVCARD, "');" - "delete from vcard_search where lusername='", LUsername, "';" - "insert into vcard_search(" - " username, lusername, fn, lfn, family, lfamily," - " given, lgiven, middle, lmiddle, nickname, lnickname," - " bday, lbday, ctry, lctry, locality, llocality," - " email, lemail, orgname, lorgname, orgunit, lorgunit)" - "values (", - " '", Username, "', '", LUsername, "'," - " '", SFN, "', '", SLFN, "'," - " '", SFamily, "', '", SLFamily, "'," - " '", SGiven, "', '", SLGiven, "'," - " '", SMiddle, "', '", SLMiddle, "'," - " '", SNickname, "', '", SLNickname, "'," - " '", SBDay, "', '", SLBDay, "'," - " '", SCTRY, "', '", SLCTRY, "'," - " '", SLocality, "', '", SLLocality, "'," - " '", SEMail, "', '", SLEMail, "'," - " '", SOrgName, "', '", SLOrgName, "'," - " '", SOrgUnit, "', '", SLOrgUnit, "');" - "commit"]) + [["delete from vcard where username='", LUsername, "';"], + ["insert into vcard(username, vcard) " + "values ('", LUsername, "', '", SVCARD, "');"], + ["delete from vcard_search where lusername='", LUsername, "';"], + ["insert into vcard_search(" + " username, lusername, fn, lfn, family, lfamily," + " given, lgiven, middle, lmiddle, nickname, lnickname," + " bday, lbday, ctry, lctry, locality, llocality," + " email, lemail, orgname, lorgname, orgunit, lorgunit)" + "values (", + " '", Username, "', '", LUsername, "'," + " '", SFN, "', '", SLFN, "'," + " '", SFamily, "', '", SLFamily, "'," + " '", SGiven, "', '", SLGiven, "'," + " '", SMiddle, "', '", SLMiddle, "'," + " '", SNickname, "', '", SLNickname, "'," + " '", SBDay, "', '", SLBDay, "'," + " '", SCTRY, "', '", SLCTRY, "'," + " '", SLocality, "', '", SLLocality, "'," + " '", SEMail, "', '", SLEMail, "'," + " '", SOrgName, "', '", SLOrgName, "'," + " '", SOrgUnit, "', '", SLOrgUnit, "');"]]) end. -define(TLFIELD(Type, Label, Var), @@ -291,9 +289,6 @@ set_vcard(User, LServer, VCARD) -> ?TLFIELD("text-single", "Organization Unit", "orgunit") ]}]). - - - do_route(ServerHost, From, To, Packet) -> #jid{user = User, resource = Resource} = To, if @@ -514,7 +509,7 @@ search(LServer, Data) -> ["select username, fn, family, given, middle, " " nickname, bday, ctry, locality, " " email, orgname, orgunit from vcard_search ", - MatchSpec, Limit]) of + MatchSpec, Limit, ";"]) of {selected, ["username", "fn", "family", "given", "middle", "nickname", "bday", "ctry", "locality", "email", "orgname", "orgunit"], @@ -660,11 +655,9 @@ remove_user(User, Server) -> LUser = jlib:nodeprep(User), LServer = jlib:nameprep(Server), Username = ejabberd_odbc:escape(LUser), - ejabberd_odbc:sql_query( + ejabberd_odbc:sql_transaction( LServer, - ["begin;" - "delete from vcard where username='", Username, "';" - "delete from vcard_search where lusername='", Username, "';" - "commit"]). + [["delete from vcard where username='", Username, "';"], + ["delete from vcard_search where lusername='", Username, "';"]]). diff --git a/src/odbc/ejabberd_odbc.erl b/src/odbc/ejabberd_odbc.erl index 49540e34e..1e8fbf7e4 100644 --- a/src/odbc/ejabberd_odbc.erl +++ b/src/odbc/ejabberd_odbc.erl @@ -45,10 +45,22 @@ sql_query(Host, Query) -> gen_server:call(ejabberd_odbc_sup:get_random_pid(Host), {sql_query, Query}, 60000). +%% SQL transaction based on a list of queries +%% This function automatically +sql_transaction(Host, Queries) when is_list(Queries) -> + F = fun() -> + lists:foreach(fun(Query) -> + R = sql_query(Host, Query) + end, + Queries) + end, + sql_transaction(Host, F); +%% SQL transaction, based on a erlang anonymous function (F = fun) sql_transaction(Host, F) -> gen_server:call(ejabberd_odbc_sup:get_random_pid(Host), {sql_transaction, F}, 60000). +%% This function is intended to be used from inside an sql_transaction: sql_query_t(Query) -> State = get(?STATE_KEY), QRes = sql_query_internal(State, Query), @@ -106,7 +118,7 @@ init([Host]) -> _ when is_list(SQLServer) -> {ok, Ref} = odbc:connect(SQLServer, [{scrollable_cursors, off}]), - {ok, #state{db_ref = Ref, + {ok, #state{db_ref = Ref, db_type = odbc}} end. @@ -177,15 +189,15 @@ execute_transaction(_State, _F, 0) -> {aborted, restarts_exceeded}; execute_transaction(State, F, NRestarts) -> put(?STATE_KEY, State), - sql_query_internal(State, "begin"), + sql_query_internal(State, "begin;"), case catch F() of aborted -> execute_transaction(State, F, NRestarts - 1); {'EXIT', Reason} -> - sql_query_internal(State, "rollback"), + sql_query_internal(State, "rollback;"), {aborted, Reason}; Res -> - sql_query_internal(State, "commit"), + sql_query_internal(State, "commit;"), {atomic, Res} end.