aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ejabberd_odbc.erl48
-rw-r--r--src/ejabberd_odbc_sup.erl86
-rw-r--r--src/ejabberd_rdbms.erl2
-rw-r--r--src/odbc_queries.erl1
4 files changed, 132 insertions, 5 deletions
diff --git a/src/ejabberd_odbc.erl b/src/ejabberd_odbc.erl
index 5828912d5..278bb760f 100644
--- a/src/ejabberd_odbc.erl
+++ b/src/ejabberd_odbc.erl
@@ -58,7 +58,7 @@
-record(state,
{db_ref = self() :: pid(),
- db_type = odbc :: pgsql | mysql | odbc,
+ db_type = odbc :: pgsql | mysql | sqlite | odbc,
start_interval = 0 :: non_neg_integer(),
host = <<"">> :: binary(),
max_pending_requests_len :: non_neg_integer(),
@@ -224,7 +224,8 @@ init([Host, StartInterval]) ->
connecting(connect, #state{host = Host} = State) ->
ConnectRes = case db_opts(Host) of
[mysql | Args] -> apply(fun mysql_connect/5, Args);
- [pgsql | Args] -> apply(fun pgsql_connect/5, Args);
+ [pgsql | Args] -> apply(fun pgsql_connect/5, Args);
+ [sqlite | Args] -> apply(fun sqlite_connect/1, Args);
[odbc | Args] -> apply(fun odbc_connect/1, Args)
end,
{_, PendingRequests} = State#state.pending_requests,
@@ -327,8 +328,9 @@ handle_info(Info, StateName, State) ->
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);
- _ -> ok
+ mysql -> catch p1_mysql_conn:stop(State#state.db_ref);
+ sqlite -> catch sqlite3:close(?SQLITE_DB);
+ _ -> ok
end,
ok.
@@ -456,7 +458,9 @@ sql_query_internal(Query) ->
[{timeout, (?TRANSACTION_TIMEOUT) - 1000},
{result_type, binary}])),
%% ?INFO_MSG("MySQL, Received result~n~p~n", [R]),
- R
+ R;
+ sqlite ->
+ sqlite_to_odbc(sqlite3:sql_exec(?SQLITE_DB, Query))
end,
case Res of
{error, <<"No SQL-driver information available.">>} ->
@@ -488,6 +492,34 @@ odbc_connect(SQLServer) ->
ejabberd:start_app(odbc),
odbc:connect(binary_to_list(SQLServer), [{scrollable_cursors, off}]).
+%% == Native SQLite code
+
+%% part of init/1
+%% Open a database connection to SQLite
+
+sqlite_connect(DB) ->
+ process_flag(trap_exit, true),
+ case sqlite3:open(?SQLITE_DB, [{file, binary_to_list(DB)}]) of
+ {ok, Ref} ->
+ {ok, Ref};
+ {error, {already_started, Ref}} ->
+ {ok, Ref};
+ {error, Reason} ->
+ {error, Reason}
+ 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, Rows}]) ->
+ {selected, [list_to_binary(C) || C <- Columns], [tuple_to_list(Row) || Row <- Rows]};
+sqlite_to_odbc({error, _Code, Reason}) ->
+ {error, Reason};
+sqlite_to_odbc(_) ->
+ {updated, undefined}.
+
%% == Native PostgreSQL code
%% part of init/1
@@ -584,6 +616,7 @@ db_opts(Host) ->
Type = ejabberd_config:get_option({odbc_type, Host},
fun(mysql) -> mysql;
(pgsql) -> pgsql;
+ (sqlite) -> sqlite;
(odbc) -> odbc
end, odbc),
Server = ejabberd_config:get_option({odbc_server, Host},
@@ -592,6 +625,11 @@ db_opts(Host) ->
case Type of
odbc ->
[odbc, Server];
+ sqlite ->
+ DB = ejabberd_config:get_option({odbc_database, Host},
+ fun iolist_to_binary/1,
+ ?DEFAULT_SQLITE_DB_PATH),
+ [sqlite, DB];
_ ->
Port = ejabberd_config:get_option(
{odbc_port, Host},
diff --git a/src/ejabberd_odbc_sup.erl b/src/ejabberd_odbc_sup.erl
index 602e7e03b..95e8fa300 100644
--- a/src/ejabberd_odbc_sup.erl
+++ b/src/ejabberd_odbc_sup.erl
@@ -67,6 +67,22 @@ init([Host]) ->
{odbc_start_interval, Host},
fun(I) when is_integer(I), I>0 -> I end,
?DEFAULT_ODBC_START_INTERVAL),
+ Type = ejabberd_config:get_option({odbc_type, Host},
+ fun(mysql) -> mysql;
+ (pgsql) -> pgsql;
+ (sqlite) -> sqlite;
+ (odbc) -> odbc
+ 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);
+ _ ->
+ ok
+ end,
+
{ok,
{{one_for_one, PoolSize * 10, 1},
lists:map(fun (I) ->
@@ -113,5 +129,75 @@ transform_options({odbc_server, {mysql, Server, DB, User, Pass}}, Opts) ->
transform_options({odbc_server, {mysql, Server, ?MYSQL_PORT, DB, User, Pass}}, Opts);
transform_options({odbc_server, {pgsql, Server, DB, User, Pass}}, Opts) ->
transform_options({odbc_server, {pgsql, Server, ?PGSQL_PORT, DB, User, Pass}}, Opts);
+transform_options({odbc_server, {sqlite, DB}}, Opts) ->
+ transform_options({odbc_server, {sqlite, DB}}, Opts);
transform_options(Opt, Opts) ->
[Opt|Opts].
+
+check_sqlite_db(DB) ->
+ process_flag(trap_exit, true),
+ 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,
+ case Ret of
+ ok ->
+ case sqlite3:list_tables(?SQLITE_DB) of
+ [] ->
+ create_sqlite_tables(),
+ sqlite3:close(?SQLITE_DB),
+ ok;
+ [_H | _] ->
+ ok
+ end;
+ {error, Reason} ->
+ ?INFO_MSG("Failed open sqlite database, reason ~p", [Reason])
+ end.
+
+create_sqlite_tables() ->
+ SqlDir = case code:priv_dir(ejabberd) of
+ {error, _} ->
+ ?SQL_DIR;
+ PrivDir ->
+ filename:join(PrivDir, "sql")
+ end,
+ File = filename:join(SqlDir, "lite.sql"),
+ 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");
+ {error, Reason} ->
+ ?INFO_MSG("Not found sqlite database schema, reason: ~p", [Reason]),
+ ok
+ end.
+
+read_lines(Fd, File, Acc) ->
+ case file:read_line(Fd) of
+ {ok, Line} ->
+ NewAcc = case str:strip(str:strip(Line, both, $\r), both, $\n) of
+ <<"--", _/binary>> ->
+ Acc;
+ <<>> ->
+ Acc;
+ _ ->
+ [Line|Acc]
+ end,
+ read_lines(Fd, File, NewAcc);
+ eof ->
+ QueryList = str:tokens(list_to_binary(lists:reverse(Acc)), <<";">>),
+ lists:flatmap(
+ fun(Query) ->
+ case str:strip(str:strip(Query, both, $\r), both, $\n) of
+ <<>> ->
+ [];
+ Q ->
+ [<<Q/binary, $;>>]
+ end
+ end, QueryList);
+ {error, _} = Err ->
+ ?ERROR_MSG("Failed read from lite.sql, reason: ~p", [Err]),
+ []
+ end.
diff --git a/src/ejabberd_rdbms.erl b/src/ejabberd_rdbms.erl
index e71728da5..93bd9fc49 100644
--- a/src/ejabberd_rdbms.erl
+++ b/src/ejabberd_rdbms.erl
@@ -74,10 +74,12 @@ needs_odbc(Host) ->
case ejabberd_config:get_option({odbc_type, LHost},
fun(mysql) -> mysql;
(pgsql) -> pgsql;
+ (sqlite) -> sqlite;
(odbc) -> odbc
end, undefined) of
mysql -> {true, p1_mysql};
pgsql -> {true, p1_pgsql};
+ sqlite -> {true, sqlite3};
odbc -> {true, odbc};
undefined -> false
end.
diff --git a/src/odbc_queries.erl b/src/odbc_queries.erl
index f2771e52f..86c3af6d0 100644
--- a/src/odbc_queries.erl
+++ b/src/odbc_queries.erl
@@ -229,6 +229,7 @@ users_number(LServer) ->
Type = ejabberd_config:get_option({odbc_type, LServer},
fun(pgsql) -> pgsql;
(mysql) -> mysql;
+ (sqlite) -> sqlite;
(odbc) -> odbc
end, odbc),
case Type of