From 9b4942890d251bf8d8bb373984c8e441eafdd300 Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Wed, 8 Apr 2015 15:31:28 +0300 Subject: [PATCH] Add virtual host support for SQLite --- include/ejabberd.hrl | 4 -- src/ejabberd_odbc.erl | 71 ++++++++++++++++++--------- src/ejabberd_odbc_sup.erl | 44 +++++++++-------- test/ejabberd_SUITE.erl | 1 - test/ejabberd_SUITE_data/ejabberd.yml | 1 - 5 files changed, 71 insertions(+), 50 deletions(-) diff --git a/include/ejabberd.hrl b/include/ejabberd.hrl index c5f8dffe3..f07dc0aaf 100644 --- a/include/ejabberd.hrl +++ b/include/ejabberd.hrl @@ -33,10 +33,6 @@ -define(SQL_DIR, filename:join(["priv", "sql"])). --define(SQLITE_DB, ejabberd_sqlite). - --define(DEFAULT_SQLITE_DB_PATH, <<"/tmp/ejabberd.db">>). - -define(CONFIG_PATH, <<"ejabberd.cfg">>). -define(LOG_PATH, <<"ejabberd.log">>). diff --git a/src/ejabberd_odbc.erl b/src/ejabberd_odbc.erl index e0ec3ba00..09f17a635 100644 --- a/src/ejabberd_odbc.erl +++ b/src/ejabberd_odbc.erl @@ -40,6 +40,8 @@ escape/1, escape_like/1, to_bool/1, + sqlite_db/1, + sqlite_file/1, encode_term/1, decode_term/1, keep_alive/1]). @@ -199,6 +201,22 @@ decode_term(Bin) -> {ok, Term} = erl_parse:parse_term(Tokens), Term. +-spec sqlite_db(binary()) -> atom(). +sqlite_db(Host) -> + list_to_atom("ejabberd_sqlite_" ++ binary_to_list(Host)). + +-spec sqlite_file(binary()) -> string(). +sqlite_file(Host) -> + case ejabberd_config:get_option({odbc_database, Host}, + fun iolist_to_binary/1) of + undefined -> + {ok, Cwd} = file:get_cwd(), + filename:join([Cwd, "sqlite", atom_to_list(node()), + binary_to_list(Host), "ejabberd.db"]); + File -> + binary_to_list(File) + end. + %%%---------------------------------------------------------------------- %%% Callback functions from gen_fsm %%%---------------------------------------------------------------------- @@ -329,7 +347,7 @@ terminate(_Reason, _StateName, State) -> ejabberd_odbc_sup:remove_pid(State#state.host, self()), case State#state.db_type of mysql -> catch p1_mysql_conn:stop(State#state.db_ref); - sqlite -> catch sqlite3:close(?SQLITE_DB); + sqlite -> catch sqlite3:close(sqlite_db(State#state.host)); _ -> ok end, ok. @@ -458,9 +476,10 @@ sql_query_internal(Query) -> [{timeout, (?TRANSACTION_TIMEOUT) - 1000}, {result_type, binary}])), %% ?INFO_MSG("MySQL, Received result~n~p~n", [R]), - R; - sqlite -> - sqlite_to_odbc(sqlite3:sql_exec(?SQLITE_DB, Query)) + R; + sqlite -> + Host = State#state.host, + sqlite_to_odbc(Host, sqlite3:sql_exec(sqlite_db(Host), Query)) end, case Res of {error, <<"No SQL-driver information available.">>} -> @@ -497,23 +516,30 @@ odbc_connect(SQLServer) -> %% part of init/1 %% Open a database connection to SQLite -sqlite_connect(DB) -> - case sqlite3:open(?SQLITE_DB, [{file, binary_to_list(DB)}]) of - {ok, Ref} -> - sqlite3:sql_exec(?SQLITE_DB, "pragma foreign_keys = on"), - {ok, Ref}; - {error, {already_started, Ref}} -> - {ok, Ref}; - {error, Reason} -> - {error, Reason} +sqlite_connect(Host) -> + File = sqlite_file(Host), + case filelib:ensure_dir(File) of + ok -> + case sqlite3:open(sqlite_db(Host), [{file, File}]) of + {ok, Ref} -> + sqlite3:sql_exec( + sqlite_db(Host), "pragma foreign_keys = on"), + {ok, Ref}; + {error, {already_started, Ref}} -> + {ok, Ref}; + {error, Reason} -> + {error, Reason} + end; + Err -> + Err end. %% Convert SQLite query result to Erlang ODBC result formalism -sqlite_to_odbc(ok) -> - {updated, sqlite3:changes(?SQLITE_DB)}; -sqlite_to_odbc({rowid, _}) -> - {updated, sqlite3:changes(?SQLITE_DB)}; -sqlite_to_odbc([{columns, Columns}, {rows, TRows}]) -> +sqlite_to_odbc(Host, ok) -> + {updated, sqlite3:changes(sqlite_db(Host))}; +sqlite_to_odbc(Host, {rowid, _}) -> + {updated, sqlite3:changes(sqlite_db(Host))}; +sqlite_to_odbc(_Host, [{columns, Columns}, {rows, TRows}]) -> Rows = [lists:map( fun(I) when is_integer(I) -> jlib:integer_to_binary(I); @@ -521,9 +547,9 @@ sqlite_to_odbc([{columns, Columns}, {rows, TRows}]) -> B end, tuple_to_list(Row)) || Row <- TRows], {selected, [list_to_binary(C) || C <- Columns], Rows}; -sqlite_to_odbc({error, _Code, Reason}) -> +sqlite_to_odbc(_Host, {error, _Code, Reason}) -> {error, Reason}; -sqlite_to_odbc(_) -> +sqlite_to_odbc(_Host, _) -> {updated, undefined}. %% == Native PostgreSQL code @@ -633,10 +659,7 @@ db_opts(Host) -> odbc -> [odbc, Server]; sqlite -> - DB = ejabberd_config:get_option({odbc_database, Host}, - fun iolist_to_binary/1, - ?DEFAULT_SQLITE_DB_PATH), - [sqlite, DB]; + [sqlite, Host]; _ -> Port = ejabberd_config:get_option( {odbc_port, Host}, diff --git a/src/ejabberd_odbc_sup.erl b/src/ejabberd_odbc_sup.erl index c92e988ee..37128e265 100644 --- a/src/ejabberd_odbc_sup.erl +++ b/src/ejabberd_odbc_sup.erl @@ -75,10 +75,7 @@ init([Host]) -> end, odbc), case Type of sqlite -> - DB = ejabberd_config:get_option({odbc_database, Host}, - fun iolist_to_binary/1, - ?DEFAULT_SQLITE_DB_PATH), - check_sqlite_db(DB); + check_sqlite_db(Host); _ -> ok end, @@ -134,19 +131,26 @@ transform_options({odbc_server, {sqlite, DB}}, Opts) -> transform_options(Opt, Opts) -> [Opt|Opts]. -check_sqlite_db(DB) -> - Ret = case sqlite3:open(?SQLITE_DB, [{file, binary_to_list(DB)}]) of - {ok, _Ref} -> ok; - {error, {already_started, _Ref}} -> ok; - {error, R} -> {error, R} - end, +check_sqlite_db(Host) -> + DB = ejabberd_odbc:sqlite_db(Host), + File = ejabberd_odbc:sqlite_file(Host), + Ret = case filelib:ensure_dir(File) of + ok -> + case sqlite3:open(DB, [{file, File}]) of + {ok, _Ref} -> ok; + {error, {already_started, _Ref}} -> ok; + {error, R} -> {error, R} + end; + Err -> + Err + end, case Ret of ok -> - sqlite3:sql_exec(?SQLITE_DB, "pragma foreign_keys = on"), - case sqlite3:list_tables(?SQLITE_DB) of + sqlite3:sql_exec(DB, "pragma foreign_keys = on"), + case sqlite3:list_tables(DB) of [] -> - create_sqlite_tables(), - sqlite3:close(?SQLITE_DB), + create_sqlite_tables(DB), + sqlite3:close(DB), ok; [_H | _] -> ok @@ -155,7 +159,7 @@ check_sqlite_db(DB) -> ?INFO_MSG("Failed open sqlite database, reason ~p", [Reason]) end. -create_sqlite_tables() -> +create_sqlite_tables(DB) -> SqlDir = case code:priv_dir(ejabberd) of {error, _} -> ?SQL_DIR; @@ -166,12 +170,12 @@ create_sqlite_tables() -> case file:open(File, [read, binary]) of {ok, Fd} -> Qs = read_lines(Fd, File, []), - ok = sqlite3:sql_exec(?SQLITE_DB, "begin"), - [ok = sqlite3:sql_exec(?SQLITE_DB, Q) || Q <- Qs], - ok = sqlite3:sql_exec(?SQLITE_DB, "commit"); + ok = sqlite3:sql_exec(DB, "begin"), + [ok = sqlite3:sql_exec(DB, Q) || Q <- Qs], + ok = sqlite3:sql_exec(DB, "commit"); {error, Reason} -> - ?INFO_MSG("Not found sqlite database schema, reason: ~p", [Reason]), - ok + ?INFO_MSG("Failed to read SQLite schema file: ~s", + [file:format_error(Reason)]) end. read_lines(Fd, File, Acc) -> diff --git a/test/ejabberd_SUITE.erl b/test/ejabberd_SUITE.erl index ec60b728d..a90ebdb69 100644 --- a/test/ejabberd_SUITE.erl +++ b/test/ejabberd_SUITE.erl @@ -35,7 +35,6 @@ init_per_suite(Config) -> LDIFFile = filename:join([DataDir, "ejabberd.ldif"]), {ok, _} = file:copy(ExtAuthScript, filename:join([CWD, "extauth.py"])), {ok, _} = ldap_srv:start(LDIFFile), - file:delete("/tmp/ejabberd_test.db"), ok = application:start(ejabberd), NewConfig. diff --git a/test/ejabberd_SUITE_data/ejabberd.yml b/test/ejabberd_SUITE_data/ejabberd.yml index 1714464d5..b23c69271 100644 --- a/test/ejabberd_SUITE_data/ejabberd.yml +++ b/test/ejabberd_SUITE_data/ejabberd.yml @@ -57,7 +57,6 @@ Welcome to this XMPP server." mod_version: [] "sqlite.localhost": odbc_type: sqlite - odbc_database: "/tmp/ejabberd_test.db" auth_method: odbc modules: mod_announce: