Add virtual host support for SQLite

This commit is contained in:
Evgeniy Khramtsov 2015-04-08 15:31:28 +03:00
parent fb0e82f743
commit 9b4942890d
5 changed files with 71 additions and 50 deletions

View File

@ -33,10 +33,6 @@
-define(SQL_DIR, filename:join(["priv", "sql"])). -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(CONFIG_PATH, <<"ejabberd.cfg">>).
-define(LOG_PATH, <<"ejabberd.log">>). -define(LOG_PATH, <<"ejabberd.log">>).

View File

@ -40,6 +40,8 @@
escape/1, escape/1,
escape_like/1, escape_like/1,
to_bool/1, to_bool/1,
sqlite_db/1,
sqlite_file/1,
encode_term/1, encode_term/1,
decode_term/1, decode_term/1,
keep_alive/1]). keep_alive/1]).
@ -199,6 +201,22 @@ decode_term(Bin) ->
{ok, Term} = erl_parse:parse_term(Tokens), {ok, Term} = erl_parse:parse_term(Tokens),
Term. 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 %%% Callback functions from gen_fsm
%%%---------------------------------------------------------------------- %%%----------------------------------------------------------------------
@ -329,7 +347,7 @@ terminate(_Reason, _StateName, State) ->
ejabberd_odbc_sup:remove_pid(State#state.host, self()), ejabberd_odbc_sup:remove_pid(State#state.host, self()),
case State#state.db_type of case State#state.db_type of
mysql -> catch p1_mysql_conn:stop(State#state.db_ref); 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 _ -> ok
end, end,
ok. ok.
@ -458,9 +476,10 @@ sql_query_internal(Query) ->
[{timeout, (?TRANSACTION_TIMEOUT) - 1000}, [{timeout, (?TRANSACTION_TIMEOUT) - 1000},
{result_type, binary}])), {result_type, binary}])),
%% ?INFO_MSG("MySQL, Received result~n~p~n", [R]), %% ?INFO_MSG("MySQL, Received result~n~p~n", [R]),
R; R;
sqlite -> sqlite ->
sqlite_to_odbc(sqlite3:sql_exec(?SQLITE_DB, Query)) Host = State#state.host,
sqlite_to_odbc(Host, sqlite3:sql_exec(sqlite_db(Host), Query))
end, end,
case Res of case Res of
{error, <<"No SQL-driver information available.">>} -> {error, <<"No SQL-driver information available.">>} ->
@ -497,23 +516,30 @@ odbc_connect(SQLServer) ->
%% part of init/1 %% part of init/1
%% Open a database connection to SQLite %% Open a database connection to SQLite
sqlite_connect(DB) -> sqlite_connect(Host) ->
case sqlite3:open(?SQLITE_DB, [{file, binary_to_list(DB)}]) of File = sqlite_file(Host),
{ok, Ref} -> case filelib:ensure_dir(File) of
sqlite3:sql_exec(?SQLITE_DB, "pragma foreign_keys = on"), ok ->
{ok, Ref}; case sqlite3:open(sqlite_db(Host), [{file, File}]) of
{error, {already_started, Ref}} -> {ok, Ref} ->
{ok, Ref}; sqlite3:sql_exec(
{error, Reason} -> sqlite_db(Host), "pragma foreign_keys = on"),
{error, Reason} {ok, Ref};
{error, {already_started, Ref}} ->
{ok, Ref};
{error, Reason} ->
{error, Reason}
end;
Err ->
Err
end. end.
%% Convert SQLite query result to Erlang ODBC result formalism %% Convert SQLite query result to Erlang ODBC result formalism
sqlite_to_odbc(ok) -> sqlite_to_odbc(Host, ok) ->
{updated, sqlite3:changes(?SQLITE_DB)}; {updated, sqlite3:changes(sqlite_db(Host))};
sqlite_to_odbc({rowid, _}) -> sqlite_to_odbc(Host, {rowid, _}) ->
{updated, sqlite3:changes(?SQLITE_DB)}; {updated, sqlite3:changes(sqlite_db(Host))};
sqlite_to_odbc([{columns, Columns}, {rows, TRows}]) -> sqlite_to_odbc(_Host, [{columns, Columns}, {rows, TRows}]) ->
Rows = [lists:map( Rows = [lists:map(
fun(I) when is_integer(I) -> fun(I) when is_integer(I) ->
jlib:integer_to_binary(I); jlib:integer_to_binary(I);
@ -521,9 +547,9 @@ sqlite_to_odbc([{columns, Columns}, {rows, TRows}]) ->
B B
end, tuple_to_list(Row)) || Row <- TRows], end, tuple_to_list(Row)) || Row <- TRows],
{selected, [list_to_binary(C) || C <- Columns], Rows}; {selected, [list_to_binary(C) || C <- Columns], Rows};
sqlite_to_odbc({error, _Code, Reason}) -> sqlite_to_odbc(_Host, {error, _Code, Reason}) ->
{error, Reason}; {error, Reason};
sqlite_to_odbc(_) -> sqlite_to_odbc(_Host, _) ->
{updated, undefined}. {updated, undefined}.
%% == Native PostgreSQL code %% == Native PostgreSQL code
@ -633,10 +659,7 @@ db_opts(Host) ->
odbc -> odbc ->
[odbc, Server]; [odbc, Server];
sqlite -> sqlite ->
DB = ejabberd_config:get_option({odbc_database, Host}, [sqlite, Host];
fun iolist_to_binary/1,
?DEFAULT_SQLITE_DB_PATH),
[sqlite, DB];
_ -> _ ->
Port = ejabberd_config:get_option( Port = ejabberd_config:get_option(
{odbc_port, Host}, {odbc_port, Host},

View File

@ -75,10 +75,7 @@ init([Host]) ->
end, odbc), end, odbc),
case Type of case Type of
sqlite -> sqlite ->
DB = ejabberd_config:get_option({odbc_database, Host}, check_sqlite_db(Host);
fun iolist_to_binary/1,
?DEFAULT_SQLITE_DB_PATH),
check_sqlite_db(DB);
_ -> _ ->
ok ok
end, end,
@ -134,19 +131,26 @@ transform_options({odbc_server, {sqlite, DB}}, Opts) ->
transform_options(Opt, Opts) -> transform_options(Opt, Opts) ->
[Opt|Opts]. [Opt|Opts].
check_sqlite_db(DB) -> check_sqlite_db(Host) ->
Ret = case sqlite3:open(?SQLITE_DB, [{file, binary_to_list(DB)}]) of DB = ejabberd_odbc:sqlite_db(Host),
{ok, _Ref} -> ok; File = ejabberd_odbc:sqlite_file(Host),
{error, {already_started, _Ref}} -> ok; Ret = case filelib:ensure_dir(File) of
{error, R} -> {error, R} ok ->
end, 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 case Ret of
ok -> ok ->
sqlite3:sql_exec(?SQLITE_DB, "pragma foreign_keys = on"), sqlite3:sql_exec(DB, "pragma foreign_keys = on"),
case sqlite3:list_tables(?SQLITE_DB) of case sqlite3:list_tables(DB) of
[] -> [] ->
create_sqlite_tables(), create_sqlite_tables(DB),
sqlite3:close(?SQLITE_DB), sqlite3:close(DB),
ok; ok;
[_H | _] -> [_H | _] ->
ok ok
@ -155,7 +159,7 @@ check_sqlite_db(DB) ->
?INFO_MSG("Failed open sqlite database, reason ~p", [Reason]) ?INFO_MSG("Failed open sqlite database, reason ~p", [Reason])
end. end.
create_sqlite_tables() -> create_sqlite_tables(DB) ->
SqlDir = case code:priv_dir(ejabberd) of SqlDir = case code:priv_dir(ejabberd) of
{error, _} -> {error, _} ->
?SQL_DIR; ?SQL_DIR;
@ -166,12 +170,12 @@ create_sqlite_tables() ->
case file:open(File, [read, binary]) of case file:open(File, [read, binary]) of
{ok, Fd} -> {ok, Fd} ->
Qs = read_lines(Fd, File, []), Qs = read_lines(Fd, File, []),
ok = sqlite3:sql_exec(?SQLITE_DB, "begin"), ok = sqlite3:sql_exec(DB, "begin"),
[ok = sqlite3:sql_exec(?SQLITE_DB, Q) || Q <- Qs], [ok = sqlite3:sql_exec(DB, Q) || Q <- Qs],
ok = sqlite3:sql_exec(?SQLITE_DB, "commit"); ok = sqlite3:sql_exec(DB, "commit");
{error, Reason} -> {error, Reason} ->
?INFO_MSG("Not found sqlite database schema, reason: ~p", [Reason]), ?INFO_MSG("Failed to read SQLite schema file: ~s",
ok [file:format_error(Reason)])
end. end.
read_lines(Fd, File, Acc) -> read_lines(Fd, File, Acc) ->

View File

@ -35,7 +35,6 @@ init_per_suite(Config) ->
LDIFFile = filename:join([DataDir, "ejabberd.ldif"]), LDIFFile = filename:join([DataDir, "ejabberd.ldif"]),
{ok, _} = file:copy(ExtAuthScript, filename:join([CWD, "extauth.py"])), {ok, _} = file:copy(ExtAuthScript, filename:join([CWD, "extauth.py"])),
{ok, _} = ldap_srv:start(LDIFFile), {ok, _} = ldap_srv:start(LDIFFile),
file:delete("/tmp/ejabberd_test.db"),
ok = application:start(ejabberd), ok = application:start(ejabberd),
NewConfig. NewConfig.

View File

@ -57,7 +57,6 @@ Welcome to this XMPP server."
mod_version: [] mod_version: []
"sqlite.localhost": "sqlite.localhost":
odbc_type: sqlite odbc_type: sqlite
odbc_database: "/tmp/ejabberd_test.db"
auth_method: odbc auth_method: odbc
modules: modules:
mod_announce: mod_announce: