mirror of
https://github.com/processone/ejabberd.git
synced 2024-11-28 16:34:13 +01:00
Automatically create and update SQL schema
This commit is contained in:
parent
9ba645503b
commit
dbbbd49522
@ -50,3 +50,20 @@
|
||||
boolean :: fun((boolean()) -> binary()),
|
||||
in_array_string :: fun((binary()) -> binary()),
|
||||
like_escape :: fun(() -> binary())}).
|
||||
|
||||
|
||||
-record(sql_index, {columns,
|
||||
unique = false :: boolean()}).
|
||||
-record(sql_column, {name :: binary(),
|
||||
type,
|
||||
default = false,
|
||||
opts = []}).
|
||||
-record(sql_table, {name :: binary(),
|
||||
columns :: [#sql_column{}],
|
||||
indices = [] :: [#sql_index{}],
|
||||
post_create}).
|
||||
-record(sql_schema, {version :: integer(),
|
||||
tables :: [#sql_table{}],
|
||||
update = []}).
|
||||
-record(sql_references, {table :: binary(),
|
||||
column :: binary()}).
|
||||
|
@ -45,7 +45,31 @@
|
||||
%%%----------------------------------------------------------------------
|
||||
%%% API
|
||||
%%%----------------------------------------------------------------------
|
||||
start(_Host) -> ok.
|
||||
start(Host) ->
|
||||
ejabberd_sql_schema:update_schema(Host, ?MODULE, schemas()),
|
||||
ok.
|
||||
|
||||
schemas() ->
|
||||
[#sql_schema{
|
||||
version = 1,
|
||||
tables =
|
||||
[#sql_table{
|
||||
name = <<"users">>,
|
||||
columns =
|
||||
[#sql_column{name = <<"username">>, type = text},
|
||||
#sql_column{name = <<"server_host">>, type = text},
|
||||
#sql_column{name = <<"password">>, type = text},
|
||||
#sql_column{name = <<"serverkey">>, type = {text, 128},
|
||||
default = true},
|
||||
#sql_column{name = <<"salt">>, type = {text, 128},
|
||||
default = true},
|
||||
#sql_column{name = <<"iterationcount">>, type = integer,
|
||||
default = true},
|
||||
#sql_column{name = <<"created_at">>, type = timestamp,
|
||||
default = true}],
|
||||
indices = [#sql_index{
|
||||
columns = [<<"server_host">>, <<"username">>],
|
||||
unique = true}]}]}].
|
||||
|
||||
stop(_Host) -> ok.
|
||||
|
||||
|
@ -41,8 +41,35 @@
|
||||
-include("logger.hrl").
|
||||
|
||||
init() ->
|
||||
ejabberd_sql_schema:update_schema(
|
||||
ejabberd_config:get_myname(), ?MODULE, schemas()),
|
||||
ok.
|
||||
|
||||
schemas() ->
|
||||
[#sql_schema{
|
||||
version = 1,
|
||||
tables =
|
||||
[#sql_table{
|
||||
name = <<"oauth_token">>,
|
||||
columns =
|
||||
[#sql_column{name = <<"token">>, type = text},
|
||||
#sql_column{name = <<"jid">>, type = text},
|
||||
#sql_column{name = <<"scope">>, type = text},
|
||||
#sql_column{name = <<"expire">>, type = bigint}],
|
||||
indices = [#sql_index{
|
||||
columns = [<<"token">>],
|
||||
unique = true}]},
|
||||
#sql_table{
|
||||
name = <<"oauth_client">>,
|
||||
columns =
|
||||
[#sql_column{name = <<"client_id">>, type = text},
|
||||
#sql_column{name = <<"client_name">>, type = text},
|
||||
#sql_column{name = <<"grant_type">>, type = text},
|
||||
#sql_column{name = <<"options">>, type = text}],
|
||||
indices = [#sql_index{
|
||||
columns = [<<"client_id">>],
|
||||
unique = true}]}]}].
|
||||
|
||||
store(R) ->
|
||||
Token = R#oauth_token.token,
|
||||
{User, Server} = R#oauth_token.us,
|
||||
|
@ -161,6 +161,7 @@
|
||||
-export([sql_type/0, sql_type/1]).
|
||||
-export([sql_username/0, sql_username/1]).
|
||||
-export([trusted_proxies/0]).
|
||||
-export([update_sql_schema/0]).
|
||||
-export([use_cache/0, use_cache/1]).
|
||||
-export([validate_stream/0]).
|
||||
-export([version/0]).
|
||||
@ -1088,6 +1089,10 @@ sql_username(Host) ->
|
||||
trusted_proxies() ->
|
||||
ejabberd_config:get_option({trusted_proxies, global}).
|
||||
|
||||
-spec update_sql_schema() -> boolean().
|
||||
update_sql_schema() ->
|
||||
ejabberd_config:get_option({update_sql_schema, global}).
|
||||
|
||||
-spec use_cache() -> boolean().
|
||||
use_cache() ->
|
||||
use_cache(global).
|
||||
|
@ -258,6 +258,8 @@ opt_type(net_ticktime) ->
|
||||
econf:timeout(second);
|
||||
opt_type(new_sql_schema) ->
|
||||
econf:bool();
|
||||
opt_type(update_sql_schema) ->
|
||||
econf:bool();
|
||||
opt_type(oauth_access) ->
|
||||
econf:acl();
|
||||
opt_type(oauth_cache_life_time) ->
|
||||
@ -604,6 +606,7 @@ options() ->
|
||||
{negotiation_timeout, timer:seconds(30)},
|
||||
{net_ticktime, timer:seconds(60)},
|
||||
{new_sql_schema, ?USE_NEW_SQL_SCHEMA_DEFAULT},
|
||||
{update_sql_schema, true},
|
||||
{oauth_access, none},
|
||||
{oauth_cache_life_time,
|
||||
fun(Host) -> ejabberd_config:get_option({cache_life_time, Host}) end},
|
||||
@ -753,6 +756,7 @@ globals() ->
|
||||
negotiation_timeout,
|
||||
net_ticktime,
|
||||
new_sql_schema,
|
||||
update_sql_schema,
|
||||
node_start,
|
||||
oauth_cache_life_time,
|
||||
oauth_cache_missed,
|
||||
|
@ -902,6 +902,11 @@ doc() ->
|
||||
"configuration flag '--enable-new-sql-schema' which is set "
|
||||
"at compile time."),
|
||||
[binary:part(ejabberd_config:version(), {0,5})]}}},
|
||||
{update_sql_schema,
|
||||
#{value => "true | false",
|
||||
desc =>
|
||||
?T("Allow ejabberd to update SQL schema. "
|
||||
"The default value is 'true'.")}},
|
||||
{oauth_access,
|
||||
#{value => ?T("AccessName"),
|
||||
desc => ?T("By default creating OAuth tokens is not allowed. "
|
||||
|
@ -37,6 +37,8 @@
|
||||
%%% API
|
||||
%%%===================================================================
|
||||
init() ->
|
||||
ejabberd_sql_schema:update_schema(
|
||||
ejabberd_config:get_myname(), ?MODULE, schemas()),
|
||||
Node = erlang:atom_to_binary(node(), latin1),
|
||||
?DEBUG("Cleaning SQL 'route' table...", []),
|
||||
case ejabberd_sql:sql_query(
|
||||
@ -48,6 +50,23 @@ init() ->
|
||||
Err
|
||||
end.
|
||||
|
||||
schemas() ->
|
||||
[#sql_schema{
|
||||
version = 1,
|
||||
tables =
|
||||
[#sql_table{
|
||||
name = <<"route">>,
|
||||
columns =
|
||||
[#sql_column{name = <<"domain">>, type = text},
|
||||
#sql_column{name = <<"server_host">>, type = text},
|
||||
#sql_column{name = <<"node">>, type = text},
|
||||
#sql_column{name = <<"pid">>, type = text},
|
||||
#sql_column{name = <<"local_hint">>, type = text}],
|
||||
indices = [#sql_index{
|
||||
columns = [<<"domain">>, <<"server_host">>,
|
||||
<<"node">>, <<"pid">>],
|
||||
unique = true}]}]}].
|
||||
|
||||
register_route(Domain, ServerHost, LocalHint, _, Pid) ->
|
||||
PidS = misc:encode_pid(Pid),
|
||||
LocalHintS = enc_local_hint(LocalHint),
|
||||
|
@ -48,6 +48,7 @@ init() ->
|
||||
?DEBUG("Cleaning SQL SM table...", []),
|
||||
lists:foldl(
|
||||
fun(Host, ok) ->
|
||||
ejabberd_sql_schema:update_schema(Host, ?MODULE, schemas()),
|
||||
case ejabberd_sql:sql_query(
|
||||
Host, ?SQL("delete from sm where node=%(Node)s")) of
|
||||
{updated, _} ->
|
||||
@ -60,6 +61,29 @@ init() ->
|
||||
Err
|
||||
end, ok, ejabberd_sm:get_vh_by_backend(?MODULE)).
|
||||
|
||||
schemas() ->
|
||||
[#sql_schema{
|
||||
version = 1,
|
||||
tables =
|
||||
[#sql_table{
|
||||
name = <<"sm">>,
|
||||
columns =
|
||||
[#sql_column{name = <<"usec">>, type = bigint},
|
||||
#sql_column{name = <<"pid">>, type = text},
|
||||
#sql_column{name = <<"node">>, type = text},
|
||||
#sql_column{name = <<"username">>, type = text},
|
||||
#sql_column{name = <<"server_host">>, type = text},
|
||||
#sql_column{name = <<"resource">>, type = text},
|
||||
#sql_column{name = <<"priority">>, type = text},
|
||||
#sql_column{name = <<"info">>, type = text}],
|
||||
indices = [#sql_index{
|
||||
columns = [<<"usec">>, <<"pid">>],
|
||||
unique = true},
|
||||
#sql_index{
|
||||
columns = [<<"node">>]},
|
||||
#sql_index{
|
||||
columns = [<<"server_host">>, <<"username">>]}]}]}].
|
||||
|
||||
set_session(#session{sid = {Now, Pid}, usr = {U, LServer, R},
|
||||
priority = Priority, info = Info}) ->
|
||||
InfoS = misc:term_to_expr(Info),
|
||||
|
928
src/ejabberd_sql_schema.erl
Normal file
928
src/ejabberd_sql_schema.erl
Normal file
@ -0,0 +1,928 @@
|
||||
%%%----------------------------------------------------------------------
|
||||
%%% File : ejabberd_sql.erl
|
||||
%%% Author : Alexey Shchepin <alexey@process-one.net>
|
||||
%%% Purpose : SQL schema versioning
|
||||
%%% Created : 15 Aug 2023 by Alexey Shchepin <alexey@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2023 ProcessOne
|
||||
%%%
|
||||
%%% This program is free software; you can redistribute it and/or
|
||||
%%% modify it under the terms of the GNU General Public License as
|
||||
%%% published by the Free Software Foundation; either version 2 of the
|
||||
%%% License, or (at your option) any later version.
|
||||
%%%
|
||||
%%% This program is distributed in the hope that it will be useful,
|
||||
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
%%% General Public License for more details.
|
||||
%%%
|
||||
%%% You should have received a copy of the GNU General Public License along
|
||||
%%% with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
%%%
|
||||
%%%----------------------------------------------------------------------
|
||||
|
||||
-module(ejabberd_sql_schema).
|
||||
|
||||
-author('alexey@process-one.net').
|
||||
|
||||
-export([start/1, update_schema/3,
|
||||
get_table_schema/2, get_table_indices/2, test/0]).
|
||||
|
||||
-include("logger.hrl").
|
||||
-include("ejabberd_sql_pt.hrl").
|
||||
|
||||
start(Host) ->
|
||||
case should_update_schema(Host) of
|
||||
true ->
|
||||
case table_exists(Host, <<"schema_version">>) of
|
||||
true ->
|
||||
ok;
|
||||
false ->
|
||||
Table = filter_table_sh(schema_table()),
|
||||
Res = create_table(Host, Table),
|
||||
case Res of
|
||||
{error, Error} ->
|
||||
?ERROR_MSG("Failed to create table ~s: ~p",
|
||||
[Table#sql_table.name, Error]),
|
||||
{error, Error};
|
||||
_ ->
|
||||
ok
|
||||
end
|
||||
end;
|
||||
false ->
|
||||
ok
|
||||
end.
|
||||
|
||||
schema_table() ->
|
||||
#sql_table{
|
||||
name = <<"schema_version">>,
|
||||
columns = [#sql_column{name = <<"module">>, type = text},
|
||||
#sql_column{name = <<"version">>, type = bigint}],
|
||||
indices = [#sql_index{
|
||||
columns = [<<"module">>],
|
||||
unique = true}]}.
|
||||
|
||||
get_table_schema(Host, Table) ->
|
||||
ejabberd_sql:sql_query(
|
||||
Host,
|
||||
fun(pgsql, _) ->
|
||||
case
|
||||
ejabberd_sql:sql_query_t(
|
||||
?SQL("select "
|
||||
" @(a.attname)s, "
|
||||
" @(pg_catalog.format_type(a.atttypid, a.atttypmod))s "
|
||||
" from "
|
||||
" pg_class t, "
|
||||
" pg_attribute a "
|
||||
" where "
|
||||
" a.attrelid = t.oid and "
|
||||
" a.attnum > 0 and "
|
||||
" a.atttypid > 0 and "
|
||||
" t.relkind = 'r' and "
|
||||
" t.relname=%(Table)s"))
|
||||
of
|
||||
{selected, Cols} ->
|
||||
[{Col, string_to_type(SType)} || {Col, SType} <- Cols]
|
||||
end;
|
||||
(sqlite, _) ->
|
||||
case
|
||||
ejabberd_sql:sql_query_t(
|
||||
?SQL("select @(i.name)s, @(i.type)s"
|
||||
" from pragma_table_info(%(Table)s) as i"))
|
||||
of
|
||||
{selected, Cols} ->
|
||||
[{Col, string_to_type(SType)} || {Col, SType} <- Cols]
|
||||
end;
|
||||
(mysql, _) ->
|
||||
case
|
||||
ejabberd_sql:sql_query_t(
|
||||
?SQL("select @(column_name)s, @(column_type)s"
|
||||
" from information_schema.columns"
|
||||
" where table_name=%(Table)s and"
|
||||
" table_schema=schema()"
|
||||
" order by ordinal_position"))
|
||||
of
|
||||
{selected, Cols} ->
|
||||
[{Col, string_to_type(SType)} || {Col, SType} <- Cols]
|
||||
end
|
||||
end).
|
||||
|
||||
get_table_indices(Host, Table) ->
|
||||
ejabberd_sql:sql_query(
|
||||
Host,
|
||||
fun(pgsql, _) ->
|
||||
case
|
||||
ejabberd_sql:sql_query_t(
|
||||
?SQL("select "
|
||||
" @(i.relname)s, "
|
||||
" @(a.attname)s "
|
||||
" from "
|
||||
" pg_class t, "
|
||||
" pg_class i, "
|
||||
" pg_index ix, "
|
||||
" pg_attribute a "
|
||||
" where "
|
||||
" t.oid = ix.indrelid and "
|
||||
" i.oid = ix.indexrelid and "
|
||||
" a.attrelid = t.oid and "
|
||||
" a.attnum = ANY(ix.indkey) and "
|
||||
" t.relkind = 'r' and "
|
||||
" t.relname=%(Table)s "
|
||||
" order by "
|
||||
" i.relname, "
|
||||
" array_position(ix.indkey, a.attnum)"))
|
||||
of
|
||||
{selected, Cols} ->
|
||||
Indices =
|
||||
lists:foldr(
|
||||
fun({IdxName, ColName}, Acc) ->
|
||||
maps:update_with(
|
||||
IdxName,
|
||||
fun(Cs) -> [ColName | Cs] end,
|
||||
[ColName],
|
||||
Acc)
|
||||
end, #{}, Cols),
|
||||
maps:to_list(Indices)
|
||||
end;
|
||||
(sqlite, _) ->
|
||||
case
|
||||
ejabberd_sql:sql_query_t(
|
||||
?SQL("select @(i.name)s, @(c.name)s "
|
||||
" from pragma_index_list(%(Table)s) as i,"
|
||||
" pragma_index_xinfo(i.name) as c"
|
||||
" where c.cid >= 0"
|
||||
" order by i.name, c.seqno"))
|
||||
of
|
||||
{selected, Cols} ->
|
||||
Indices =
|
||||
lists:foldr(
|
||||
fun({IdxName, ColName}, Acc) ->
|
||||
maps:update_with(
|
||||
IdxName,
|
||||
fun(Cs) -> [ColName | Cs] end,
|
||||
[ColName],
|
||||
Acc)
|
||||
end, #{}, Cols),
|
||||
maps:to_list(Indices)
|
||||
end;
|
||||
(mysql, _) ->
|
||||
case
|
||||
ejabberd_sql:sql_query_t(
|
||||
?SQL("select @(index_name)s, @(column_name)s"
|
||||
" from information_schema.statistics"
|
||||
" where table_name=%(Table)s and"
|
||||
" table_schema=schema()"
|
||||
" order by index_name, seq_in_index"))
|
||||
of
|
||||
{selected, Cols} ->
|
||||
Indices =
|
||||
lists:foldr(
|
||||
fun({IdxName, ColName}, Acc) ->
|
||||
maps:update_with(
|
||||
IdxName,
|
||||
fun(Cs) -> [ColName | Cs] end,
|
||||
[ColName],
|
||||
Acc)
|
||||
end, #{}, Cols),
|
||||
maps:to_list(Indices)
|
||||
end
|
||||
end).
|
||||
|
||||
find_index_name(Host, Table, Columns) ->
|
||||
Indices = get_table_indices(Host, Table),
|
||||
case lists:keyfind(Columns, 2, Indices) of
|
||||
false ->
|
||||
false;
|
||||
{Name, _} ->
|
||||
{ok, Name}
|
||||
end.
|
||||
|
||||
get_version(Host, Module) ->
|
||||
SModule = atom_to_binary(Module),
|
||||
ejabberd_sql:sql_query(
|
||||
Host,
|
||||
?SQL("select @(version)d"
|
||||
" from schema_version"
|
||||
" where module=%(SModule)s")).
|
||||
|
||||
store_version(Host, Module, Version) ->
|
||||
SModule = atom_to_binary(Module),
|
||||
?SQL_UPSERT(
|
||||
Host,
|
||||
"schema_version",
|
||||
["!module=%(SModule)s",
|
||||
"version=%(Version)d"]).
|
||||
|
||||
table_exists(Host, Table) ->
|
||||
ejabberd_sql:sql_query(
|
||||
Host,
|
||||
fun(pgsql, _) ->
|
||||
case
|
||||
ejabberd_sql:sql_query_t(
|
||||
?SQL("select @()b exists (select from pg_tables "
|
||||
" where tablename=%(Table)s)"))
|
||||
of
|
||||
{selected, [{Res}]} ->
|
||||
Res
|
||||
end;
|
||||
(sqlite, _) ->
|
||||
case
|
||||
ejabberd_sql:sql_query_t(
|
||||
?SQL("select @()b exists"
|
||||
" (select 0 from pragma_table_info(%(Table)s))"))
|
||||
of
|
||||
{selected, [{Res}]} ->
|
||||
Res
|
||||
end;
|
||||
(mysql, _) ->
|
||||
case
|
||||
ejabberd_sql:sql_query_t(
|
||||
?SQL("select @()b exists"
|
||||
" (select 0 from information_schema.tables"
|
||||
" where table_name=%(Table)s and"
|
||||
" table_schema=schema())"))
|
||||
of
|
||||
{selected, [{Res}]} ->
|
||||
Res
|
||||
end
|
||||
end).
|
||||
|
||||
filter_table_sh(Table) ->
|
||||
case {ejabberd_sql:use_new_schema(), Table#sql_table.name} of
|
||||
{true, _} ->
|
||||
Table;
|
||||
{_, <<"route">>} ->
|
||||
Table;
|
||||
{false, _} ->
|
||||
Table#sql_table{
|
||||
columns =
|
||||
lists:keydelete(
|
||||
<<"server_host">>, #sql_column.name, Table#sql_table.columns),
|
||||
indices =
|
||||
lists:map(
|
||||
fun(Idx) ->
|
||||
Idx#sql_index{
|
||||
columns =
|
||||
lists:delete(
|
||||
<<"server_host">>, Idx#sql_index.columns)
|
||||
}
|
||||
end, Table#sql_table.indices)
|
||||
}
|
||||
end.
|
||||
|
||||
string_to_type(SType) ->
|
||||
case string:lowercase(SType) of
|
||||
<<"text">> -> text;
|
||||
<<"mediumtext">> -> text;
|
||||
<<"bigint">> -> bigint;
|
||||
<<"bigint ", _/binary>> -> bigint;
|
||||
<<"bigint(", _/binary>> -> bigint;
|
||||
<<"integer">> -> integer;
|
||||
<<"int(", _/binary>> -> integer;
|
||||
<<"smallint">> -> smallint;
|
||||
<<"smallint(", _/binary>> -> smallint;
|
||||
<<"numeric">> -> numeric;
|
||||
<<"decimal", _/binary>> -> numeric;
|
||||
<<"bigserial">> -> bigserial;
|
||||
<<"boolean">> -> boolean;
|
||||
<<"tinyint(1)">> -> boolean;
|
||||
<<"bytea">> -> blob;
|
||||
<<"blob">> -> blob;
|
||||
<<"timestamp", _/binary>> -> timestamp;
|
||||
<<"character(", R/binary>> ->
|
||||
{ok, [N], []} = io_lib:fread("~d)", binary_to_list(R)),
|
||||
{char, N};
|
||||
<<"char(", R/binary>> ->
|
||||
{ok, [N], []} = io_lib:fread("~d)", binary_to_list(R)),
|
||||
{char, N};
|
||||
<<"varchar(", _/binary>> -> text;
|
||||
<<"character varying(", _/binary>> -> text;
|
||||
T ->
|
||||
?ERROR_MSG("Unknown SQL type '~s'", [T]),
|
||||
{undefined, T}
|
||||
end.
|
||||
|
||||
check_columns_compatibility(RequiredColumns, Columns) ->
|
||||
lists:all(
|
||||
fun(#sql_column{name = Name, type = Type}) ->
|
||||
%io:format("col ~p~n", [{Name, Type}]),
|
||||
case lists:keyfind(Name, 1, Columns) of
|
||||
false ->
|
||||
false;
|
||||
{_, Type2} ->
|
||||
%io:format("tt ~p~n", [{Type, Type2}]),
|
||||
case {Type, Type2} of
|
||||
{T, T} -> true;
|
||||
{text, blob} -> true;
|
||||
{{text, _}, blob} -> true;
|
||||
{{text, _}, text} -> true;
|
||||
{{text, _}, {varchar, _}} -> true;
|
||||
{text, {varchar, _}} -> true;
|
||||
{{char, _}, text} -> true;
|
||||
{{varchar, _}, text} -> true;
|
||||
{smallint, integer} -> true;
|
||||
{smallint, bigint} -> true;
|
||||
{smallint, numeric} -> true;
|
||||
{integer, bigint} -> true;
|
||||
{integer, numeric} -> true;
|
||||
{bigint, numeric} -> true;
|
||||
{bigserial, integer} -> true;
|
||||
{bigserial, bigint} -> true;
|
||||
{bigserial, numeric} -> true;
|
||||
_ -> false
|
||||
end
|
||||
end
|
||||
end, RequiredColumns).
|
||||
|
||||
guess_version(Host, Schemas) ->
|
||||
LastSchema = lists:max(Schemas),
|
||||
SomeTablesExist =
|
||||
lists:any(
|
||||
fun(Table) ->
|
||||
table_exists(Host, Table#sql_table.name)
|
||||
end, LastSchema#sql_schema.tables),
|
||||
if
|
||||
SomeTablesExist ->
|
||||
CompatibleSchemas =
|
||||
lists:filter(
|
||||
fun(Schema) ->
|
||||
lists:all(
|
||||
fun(Table) ->
|
||||
Table2 = filter_table_sh(Table),
|
||||
CurrentColumns =
|
||||
get_table_schema(
|
||||
Host, Table2#sql_table.name),
|
||||
check_columns_compatibility(
|
||||
Table2#sql_table.columns,
|
||||
CurrentColumns)
|
||||
end, Schema#sql_schema.tables)
|
||||
end, Schemas),
|
||||
case CompatibleSchemas of
|
||||
[] -> -1;
|
||||
_ ->
|
||||
(lists:max(CompatibleSchemas))#sql_schema.version
|
||||
end;
|
||||
true ->
|
||||
0
|
||||
end.
|
||||
|
||||
get_current_version(Host, Module, Schemas) ->
|
||||
case get_version(Host, Module) of
|
||||
{selected, [{Version}]} ->
|
||||
Version;
|
||||
{selected, []} ->
|
||||
Version = guess_version(Host, Schemas),
|
||||
if
|
||||
Version > 0 ->
|
||||
store_version(Host, Module, Version);
|
||||
true ->
|
||||
ok
|
||||
end,
|
||||
Version
|
||||
end.
|
||||
|
||||
format_type(pgsql, _DBVersion, Column) ->
|
||||
case Column#sql_column.type of
|
||||
text -> <<"text">>;
|
||||
{text, _} -> <<"text">>;
|
||||
bigint -> <<"bigint">>;
|
||||
integer -> <<"integer">>;
|
||||
smallint -> <<"smallint">>;
|
||||
numeric -> <<"numeric">>;
|
||||
boolean -> <<"boolean">>;
|
||||
blob -> <<"bytea">>;
|
||||
timestamp -> <<"timestamp">>;
|
||||
{char, N} -> [<<"character(">>, integer_to_binary(N), <<")">>];
|
||||
bigserial -> <<"bigserial">>
|
||||
end;
|
||||
format_type(sqlite, _DBVersion, Column) ->
|
||||
case Column#sql_column.type of
|
||||
text -> <<"text">>;
|
||||
{text, _} -> <<"text">>;
|
||||
bigint -> <<"bigint">>;
|
||||
integer -> <<"integer">>;
|
||||
smallint -> <<"smallint">>;
|
||||
numeric -> <<"numeric">>;
|
||||
boolean -> <<"boolean">>;
|
||||
blob -> <<"blob">>;
|
||||
timestamp -> <<"timestamp">>;
|
||||
{char, N} -> [<<"character(">>, integer_to_binary(N), <<")">>];
|
||||
bigserial -> <<"integer primary key autoincrement">>
|
||||
end;
|
||||
format_type(mysql, _DBVersion, Column) ->
|
||||
case Column#sql_column.type of
|
||||
text -> <<"text">>;
|
||||
{text, big} -> <<"mediumtext">>;
|
||||
{text, N} when is_integer(N), N < 191 ->
|
||||
[<<"varchar(">>, integer_to_binary(N), <<")">>];
|
||||
{text, _} -> <<"text">>;
|
||||
bigint -> <<"bigint">>;
|
||||
integer -> <<"integer">>;
|
||||
smallint -> <<"smallint">>;
|
||||
numeric -> <<"numeric">>;
|
||||
boolean -> <<"boolean">>;
|
||||
blob -> <<"blob">>;
|
||||
timestamp -> <<"timestamp">>;
|
||||
{char, N} -> [<<"character(">>, integer_to_binary(N), <<")">>];
|
||||
bigserial -> <<"bigint auto_increment primary key">>
|
||||
end.
|
||||
|
||||
format_default(pgsql, _DBVersion, Column) ->
|
||||
case Column#sql_column.type of
|
||||
text -> <<"''">>;
|
||||
{text, _} -> <<"''">>;
|
||||
bigint -> <<"0">>;
|
||||
integer -> <<"0">>;
|
||||
smallint -> <<"0">>;
|
||||
numeric -> <<"0">>;
|
||||
boolean -> <<"false">>;
|
||||
blob -> <<"''">>;
|
||||
timestamp -> <<"now()">>
|
||||
%{char, N} -> <<"''">>;
|
||||
%bigserial -> <<"0">>
|
||||
end;
|
||||
format_default(sqlite, _DBVersion, Column) ->
|
||||
case Column#sql_column.type of
|
||||
text -> <<"''">>;
|
||||
{text, _} -> <<"''">>;
|
||||
bigint -> <<"0">>;
|
||||
integer -> <<"0">>;
|
||||
smallint -> <<"0">>;
|
||||
numeric -> <<"0">>;
|
||||
boolean -> <<"false">>;
|
||||
blob -> <<"''">>;
|
||||
timestamp -> <<"CURRENT_TIMESTAMP">>
|
||||
%{char, N} -> <<"''">>;
|
||||
%bigserial -> <<"0">>
|
||||
end;
|
||||
format_default(mysql, _DBVersion, Column) ->
|
||||
case Column#sql_column.type of
|
||||
text -> <<"''">>;
|
||||
{text, _} -> <<"''">>;
|
||||
bigint -> <<"0">>;
|
||||
integer -> <<"0">>;
|
||||
smallint -> <<"0">>;
|
||||
numeric -> <<"0">>;
|
||||
boolean -> <<"false">>;
|
||||
blob -> <<"''">>;
|
||||
timestamp -> <<"CURRENT_TIMESTAMP">>
|
||||
%{char, N} -> <<"''">>;
|
||||
%bigserial -> <<"0">>
|
||||
end.
|
||||
|
||||
escape_name(pgsql, _DBVersion, <<"type">>) ->
|
||||
<<"\"type\"">>;
|
||||
escape_name(_DBType, _DBVersion, ColumnName) ->
|
||||
ColumnName.
|
||||
|
||||
format_column_def(DBType, DBVersion, Column) ->
|
||||
[<<" ">>,
|
||||
escape_name(DBType, DBVersion, Column#sql_column.name), <<" ">>,
|
||||
format_type(DBType, DBVersion, Column),
|
||||
<<" NOT NULL">>,
|
||||
case Column#sql_column.default of
|
||||
false -> [];
|
||||
true ->
|
||||
[<<" DEFAULT ">>, format_default(DBType, DBVersion, Column)]
|
||||
end,
|
||||
case lists:keyfind(sql_references, 1, Column#sql_column.opts) of
|
||||
false -> [];
|
||||
#sql_references{table = T, column = C} ->
|
||||
[<<" REFERENCES ">>, T, <<"(">>, C, <<") ON DELETE CASCADE">>]
|
||||
end].
|
||||
|
||||
format_mysql_index_column(Table, ColumnName) ->
|
||||
{value, Column} =
|
||||
lists:keysearch(
|
||||
ColumnName, #sql_column.name, Table#sql_table.columns),
|
||||
NeedsSizeLimit =
|
||||
case Column#sql_column.type of
|
||||
{text, N} when is_integer(N), N < 191 -> false;
|
||||
{text, _} -> true;
|
||||
text -> true;
|
||||
_ -> false
|
||||
end,
|
||||
if
|
||||
NeedsSizeLimit ->
|
||||
[ColumnName, <<"(191)">>];
|
||||
true ->
|
||||
ColumnName
|
||||
end.
|
||||
|
||||
format_create_index(pgsql, _DBVersion, Table, Index) ->
|
||||
TableName = Table#sql_table.name,
|
||||
Unique =
|
||||
case Index#sql_index.unique of
|
||||
true -> <<"UNIQUE ">>;
|
||||
false -> <<"">>
|
||||
end,
|
||||
Name = [<<"i_">>, TableName, <<"_">>,
|
||||
lists:join(
|
||||
<<"_">>,
|
||||
Index#sql_index.columns)],
|
||||
[<<"CREATE ">>, Unique, <<"INDEX ">>, Name, <<" ON ">>, TableName,
|
||||
<<" USING btree (">>,
|
||||
lists:join(
|
||||
<<", ">>,
|
||||
Index#sql_index.columns),
|
||||
<<");">>];
|
||||
format_create_index(sqlite, _DBVersion, Table, Index) ->
|
||||
TableName = Table#sql_table.name,
|
||||
Unique =
|
||||
case Index#sql_index.unique of
|
||||
true -> <<"UNIQUE ">>;
|
||||
false -> <<"">>
|
||||
end,
|
||||
Name = [<<"i_">>, TableName, <<"_">>,
|
||||
lists:join(
|
||||
<<"_">>,
|
||||
Index#sql_index.columns)],
|
||||
[<<"CREATE ">>, Unique, <<"INDEX ">>, Name, <<" ON ">>, TableName,
|
||||
<<"(">>,
|
||||
lists:join(
|
||||
<<", ">>,
|
||||
Index#sql_index.columns),
|
||||
<<");">>];
|
||||
format_create_index(mysql, _DBVersion, Table, Index) ->
|
||||
TableName = Table#sql_table.name,
|
||||
Unique =
|
||||
case Index#sql_index.unique of
|
||||
true -> <<"UNIQUE ">>;
|
||||
false -> <<"">>
|
||||
end,
|
||||
Name = [<<"i_">>, TableName, <<"_">>,
|
||||
lists:join(
|
||||
<<"_">>,
|
||||
Index#sql_index.columns)],
|
||||
[<<"CREATE ">>, Unique, <<"INDEX ">>, Name,
|
||||
<<" USING BTREE ON ">>, TableName,
|
||||
<<"(">>,
|
||||
lists:join(
|
||||
<<", ">>,
|
||||
lists:map(
|
||||
fun(Col) ->
|
||||
format_mysql_index_column(Table, Col)
|
||||
end, Index#sql_index.columns)),
|
||||
<<");">>].
|
||||
|
||||
format_create_table(pgsql = DBType, DBVersion, Table) ->
|
||||
TableName = Table#sql_table.name,
|
||||
[iolist_to_binary(
|
||||
[<<"CREATE TABLE ">>, TableName, <<" (\n">>,
|
||||
lists:join(
|
||||
<<",\n">>,
|
||||
lists:map(
|
||||
fun(C) -> format_column_def(DBType, DBVersion, C) end,
|
||||
Table#sql_table.columns)),
|
||||
<<"\n);\n">>])] ++
|
||||
lists:map(
|
||||
fun(I) ->
|
||||
iolist_to_binary(
|
||||
[format_create_index(DBType, DBVersion, Table, I),
|
||||
<<"\n">>])
|
||||
end,
|
||||
Table#sql_table.indices);
|
||||
format_create_table(sqlite = DBType, DBVersion, Table) ->
|
||||
TableName = Table#sql_table.name,
|
||||
[iolist_to_binary(
|
||||
[<<"CREATE TABLE ">>, TableName, <<" (\n">>,
|
||||
lists:join(
|
||||
<<",\n">>,
|
||||
lists:map(
|
||||
fun(C) -> format_column_def(DBType, DBVersion, C) end,
|
||||
Table#sql_table.columns)),
|
||||
<<"\n);\n">>])] ++
|
||||
lists:map(
|
||||
fun(I) ->
|
||||
iolist_to_binary(
|
||||
[format_create_index(DBType, DBVersion, Table, I),
|
||||
<<"\n">>])
|
||||
end,
|
||||
Table#sql_table.indices);
|
||||
format_create_table(mysql = DBType, DBVersion, Table) ->
|
||||
TableName = Table#sql_table.name,
|
||||
[iolist_to_binary(
|
||||
[<<"CREATE TABLE ">>, TableName, <<" (\n">>,
|
||||
lists:join(
|
||||
<<",\n">>,
|
||||
lists:map(
|
||||
fun(C) -> format_column_def(DBType, DBVersion, C) end,
|
||||
Table#sql_table.columns)),
|
||||
<<"\n) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;\n">>])] ++
|
||||
lists:map(
|
||||
fun(I) ->
|
||||
iolist_to_binary(
|
||||
[format_create_index(DBType, DBVersion, Table, I),
|
||||
<<"\n">>])
|
||||
end,
|
||||
Table#sql_table.indices).
|
||||
%format_create_table(DBType, _DBVersion, Table) ->
|
||||
% ?ERROR_MSG("Can't create SQL table ~p on ~p",
|
||||
% [Table#sql_table.name, DBType]),
|
||||
% error.
|
||||
|
||||
create_table(Host, Table) ->
|
||||
ejabberd_sql:sql_query(
|
||||
Host,
|
||||
fun(DBType, DBVersion) ->
|
||||
SQLs = format_create_table(DBType, DBVersion, Table),
|
||||
?INFO_MSG("Creating table ~s:~n~s~n",
|
||||
[Table#sql_table.name, SQLs]),
|
||||
lists:foreach(
|
||||
fun(SQL) -> ejabberd_sql:sql_query_t(SQL) end, SQLs),
|
||||
case Table#sql_table.post_create of
|
||||
undefined ->
|
||||
ok;
|
||||
F ->
|
||||
F(DBType, DBVersion)
|
||||
end
|
||||
end).
|
||||
|
||||
create_tables(Host, Module, Schema) ->
|
||||
lists:foreach(
|
||||
fun(Table) ->
|
||||
Table2 = filter_table_sh(Table),
|
||||
Res = create_table(Host, Table2),
|
||||
case Res of
|
||||
{error, Error} ->
|
||||
?ERROR_MSG("Failed to create table ~s: ~p",
|
||||
[Table2#sql_table.name, Error]),
|
||||
error(Error);
|
||||
_ ->
|
||||
ok
|
||||
end
|
||||
end, Schema#sql_schema.tables),
|
||||
store_version(Host, Module, Schema#sql_schema.version).
|
||||
|
||||
should_update_schema(Host) ->
|
||||
case ejabberd_option:update_sql_schema() of
|
||||
true ->
|
||||
case ejabberd_sql:use_new_schema() of
|
||||
true ->
|
||||
Host == ejabberd_config:get_myname();
|
||||
false ->
|
||||
true
|
||||
end;
|
||||
false ->
|
||||
false
|
||||
end.
|
||||
|
||||
update_schema(Host, Module, Schemas) ->
|
||||
case should_update_schema(Host) of
|
||||
true ->
|
||||
Version = get_current_version(Host, Module, Schemas),
|
||||
LastSchema = lists:max(Schemas),
|
||||
LastVersion = LastSchema#sql_schema.version,
|
||||
case Version of
|
||||
_ when Version < 0 ->
|
||||
?ERROR_MSG("Can't update SQL schema for module ~p, please do it manually", [Module]);
|
||||
0 ->
|
||||
create_tables(Host, Module, LastSchema);
|
||||
LastVersion ->
|
||||
ok;
|
||||
_ when LastVersion < Version ->
|
||||
?ERROR_MSG("The current SQL schema for module ~p is ~p, but the latest known schema in the module is ~p", [Module, Version, LastVersion]);
|
||||
_ ->
|
||||
lists:foreach(
|
||||
fun(Schema) ->
|
||||
if
|
||||
Schema#sql_schema.version > Version ->
|
||||
do_update_schema(Host, Module, Schema);
|
||||
true ->
|
||||
ok
|
||||
end
|
||||
end, lists:sort(Schemas))
|
||||
end;
|
||||
false ->
|
||||
ok
|
||||
end.
|
||||
|
||||
do_update_schema(Host, Module, Schema) ->
|
||||
lists:foreach(
|
||||
fun({add_column, TableName, ColumnName}) ->
|
||||
{value, Table} =
|
||||
lists:keysearch(
|
||||
TableName, #sql_table.name, Schema#sql_schema.tables),
|
||||
{value, Column} =
|
||||
lists:keysearch(
|
||||
ColumnName, #sql_column.name, Table#sql_table.columns),
|
||||
Res =
|
||||
ejabberd_sql:sql_query(
|
||||
Host,
|
||||
fun(DBType, DBVersion) ->
|
||||
Def = format_column_def(DBType, DBVersion, Column),
|
||||
Default = format_default(DBType, DBVersion, Column),
|
||||
SQLs =
|
||||
[[<<"ALTER TABLE ">>,
|
||||
TableName,
|
||||
<<" ADD COLUMN\n">>,
|
||||
Def,
|
||||
<<" DEFAULT ">>,
|
||||
Default, <<";\n">>]] ++
|
||||
case Column#sql_column.default of
|
||||
false ->
|
||||
[[<<"ALTER TABLE ">>,
|
||||
TableName,
|
||||
<<" ALTER COLUMN ">>,
|
||||
ColumnName,
|
||||
<<" DROP DEFAULT;">>]];
|
||||
_ ->
|
||||
[]
|
||||
end,
|
||||
?INFO_MSG("Add column ~s/~s:~n~s~n",
|
||||
[TableName,
|
||||
ColumnName,
|
||||
SQLs]),
|
||||
lists:foreach(
|
||||
fun(SQL) -> ejabberd_sql:sql_query_t(SQL) end,
|
||||
SQLs)
|
||||
end),
|
||||
case Res of
|
||||
{error, Error} ->
|
||||
?ERROR_MSG("Failed to update table ~s: ~p",
|
||||
[TableName, Error]),
|
||||
error(Error);
|
||||
_ ->
|
||||
ok
|
||||
end;
|
||||
({drop_column, TableName, ColumnName}) ->
|
||||
Res =
|
||||
ejabberd_sql:sql_query(
|
||||
Host,
|
||||
fun(_DBType, _DBVersion) ->
|
||||
SQL = [<<"ALTER TABLE ">>,
|
||||
TableName,
|
||||
<<" DROP COLUMN ">>,
|
||||
ColumnName,
|
||||
<<";">>],
|
||||
?INFO_MSG("Drop column ~s/~s:~n~s~n",
|
||||
[TableName,
|
||||
ColumnName,
|
||||
SQL]),
|
||||
ejabberd_sql:sql_query_t(SQL)
|
||||
end),
|
||||
case Res of
|
||||
{error, Error} ->
|
||||
?ERROR_MSG("Failed to update table ~s: ~p",
|
||||
[TableName, Error]),
|
||||
error(Error);
|
||||
_ ->
|
||||
ok
|
||||
end;
|
||||
({create_index, TableName, Columns}) ->
|
||||
{value, Table1} =
|
||||
lists:keysearch(
|
||||
TableName, #sql_table.name, Schema#sql_schema.tables),
|
||||
{value, Index1} =
|
||||
lists:keysearch(
|
||||
Columns, #sql_index.columns, Table1#sql_table.indices),
|
||||
Table = filter_table_sh(Table1),
|
||||
Index =
|
||||
case ejabberd_sql:use_new_schema() of
|
||||
true ->
|
||||
Index1;
|
||||
false ->
|
||||
Index1#sql_index{
|
||||
columns =
|
||||
lists:delete(
|
||||
<<"server_host">>, Index1#sql_index.columns)
|
||||
}
|
||||
end,
|
||||
Res =
|
||||
ejabberd_sql:sql_query(
|
||||
Host,
|
||||
fun(DBType, DBVersion) ->
|
||||
SQL1 = format_create_index(
|
||||
DBType, DBVersion, Table, Index),
|
||||
SQL = iolist_to_binary(SQL1),
|
||||
?INFO_MSG("Create index ~s/~p:~n~s~n",
|
||||
[Table#sql_table.name,
|
||||
Index#sql_index.columns,
|
||||
SQL]),
|
||||
ejabberd_sql:sql_query_t(SQL)
|
||||
end),
|
||||
case Res of
|
||||
{error, Error} ->
|
||||
?ERROR_MSG("Failed to update table ~s: ~p",
|
||||
[TableName, Error]),
|
||||
error(Error);
|
||||
_ ->
|
||||
ok
|
||||
end;
|
||||
({drop_index, TableName, Columns1}) ->
|
||||
Columns =
|
||||
case ejabberd_sql:use_new_schema() of
|
||||
true ->
|
||||
Columns1;
|
||||
false ->
|
||||
lists:delete(
|
||||
<<"server_host">>, Columns1)
|
||||
end,
|
||||
case find_index_name(Host, TableName, Columns) of
|
||||
false ->
|
||||
?ERROR_MSG("Can't find an index to drop for ~s/~p",
|
||||
[TableName, Columns]);
|
||||
{ok, IndexName} ->
|
||||
Res =
|
||||
ejabberd_sql:sql_query(
|
||||
Host,
|
||||
fun(DBType, _DBVersion) ->
|
||||
SQL =
|
||||
case DBType of
|
||||
mysql ->
|
||||
[<<"DROP INDEX ">>,
|
||||
IndexName,
|
||||
<<" ON ">>,
|
||||
TableName,
|
||||
<<";">>];
|
||||
_ ->
|
||||
[<<"DROP INDEX ">>,
|
||||
IndexName, <<";">>]
|
||||
end,
|
||||
?INFO_MSG("Drop index ~s/~p:~n~s~n",
|
||||
[TableName,
|
||||
Columns,
|
||||
SQL]),
|
||||
ejabberd_sql:sql_query_t(SQL)
|
||||
end),
|
||||
case Res of
|
||||
{error, Error} ->
|
||||
?ERROR_MSG("Failed to update table ~s: ~p",
|
||||
[TableName, Error]),
|
||||
error(Error);
|
||||
_ ->
|
||||
ok
|
||||
end
|
||||
end
|
||||
end, Schema#sql_schema.update),
|
||||
store_version(Host, Module, Schema#sql_schema.version).
|
||||
|
||||
test() ->
|
||||
Schemas =
|
||||
[#sql_schema{
|
||||
version = 2,
|
||||
tables =
|
||||
[#sql_table{
|
||||
name = <<"archive2">>,
|
||||
columns = [#sql_column{name = <<"username">>, type = text},
|
||||
#sql_column{name = <<"server_host">>, type = text},
|
||||
#sql_column{name = <<"timestamp">>, type = bigint},
|
||||
#sql_column{name = <<"peer">>, type = text},
|
||||
#sql_column{name = <<"bare_peer">>, type = text},
|
||||
#sql_column{name = <<"xml">>, type = {text, big}},
|
||||
#sql_column{name = <<"txt">>, type = {text, big}},
|
||||
#sql_column{name = <<"id">>, type = bigserial},
|
||||
#sql_column{name = <<"kind">>, type = text},
|
||||
#sql_column{name = <<"nick">>, type = text},
|
||||
#sql_column{name = <<"origin_id">>, type = text},
|
||||
#sql_column{name = <<"type">>, type = text},
|
||||
#sql_column{name = <<"created_at">>, type = timestamp,
|
||||
default = true}],
|
||||
indices = [#sql_index{
|
||||
columns = [<<"server_host">>, <<"username">>, <<"timestamp">>]},
|
||||
#sql_index{
|
||||
columns = [<<"server_host">>, <<"username">>, <<"peer">>]},
|
||||
#sql_index{
|
||||
columns = [<<"server_host">>, <<"username">>, <<"bare_peer">>]},
|
||||
#sql_index{
|
||||
columns = [<<"server_host">>, <<"origin_id">>]},
|
||||
#sql_index{
|
||||
columns = [<<"server_host">>, <<"timestamp">>]}
|
||||
]}],
|
||||
update =
|
||||
[{add_column, <<"archive2">>, <<"origin_id">>},
|
||||
{create_index, <<"archive2">>,
|
||||
[<<"server_host">>, <<"origin_id">>]},
|
||||
{drop_index, <<"archive2">>,
|
||||
[<<"server_host">>, <<"origin_id">>]},
|
||||
{drop_column, <<"archive2">>, <<"origin_id">>}
|
||||
]},
|
||||
#sql_schema{
|
||||
version = 1,
|
||||
tables =
|
||||
[#sql_table{
|
||||
name = <<"archive2">>,
|
||||
columns = [#sql_column{name = <<"username">>, type = text},
|
||||
#sql_column{name = <<"server_host">>, type = text},
|
||||
#sql_column{name = <<"timestamp">>, type = bigint},
|
||||
#sql_column{name = <<"peer">>, type = text},
|
||||
#sql_column{name = <<"bare_peer">>, type = text},
|
||||
#sql_column{name = <<"xml">>, type = {text, big}},
|
||||
#sql_column{name = <<"txt">>, type = {text, big}},
|
||||
#sql_column{name = <<"id">>, type = bigserial},
|
||||
#sql_column{name = <<"kind">>, type = {text, 10}},
|
||||
#sql_column{name = <<"nick">>, type = text},
|
||||
#sql_column{name = <<"created_at">>, type = timestamp,
|
||||
default = true}],
|
||||
indices = [#sql_index{
|
||||
columns = [<<"server_host">>, <<"username">>, <<"timestamp">>]},
|
||||
#sql_index{
|
||||
columns = [<<"server_host">>, <<"username">>, <<"peer">>]},
|
||||
#sql_index{
|
||||
columns = [<<"server_host">>, <<"username">>, <<"bare_peer">>]},
|
||||
#sql_index{
|
||||
columns = [<<"server_host">>, <<"timestamp">>]}
|
||||
]}]}],
|
||||
update_schema(<<"localhost">>, mod_foo, Schemas).
|
@ -51,7 +51,9 @@ start(Host) ->
|
||||
type => supervisor,
|
||||
modules => [?MODULE]},
|
||||
case supervisor:start_child(ejabberd_db_sup, Spec) of
|
||||
{ok, _} -> ok;
|
||||
{ok, _} ->
|
||||
ejabberd_sql_schema:start(Host),
|
||||
ok;
|
||||
{error, {already_started, Pid}} ->
|
||||
%% Wait for the supervisor to fully start
|
||||
_ = supervisor:count_children(Pid),
|
||||
|
@ -40,9 +40,26 @@
|
||||
%%%===================================================================
|
||||
%%% API
|
||||
%%%===================================================================
|
||||
init(_Host, _Opts) ->
|
||||
init(Host, _Opts) ->
|
||||
ejabberd_sql_schema:update_schema(Host, ?MODULE, schemas()),
|
||||
ok.
|
||||
|
||||
schemas() ->
|
||||
[#sql_schema{
|
||||
version = 1,
|
||||
tables =
|
||||
[#sql_table{
|
||||
name = <<"motd">>,
|
||||
columns =
|
||||
[#sql_column{name = <<"username">>, type = text},
|
||||
#sql_column{name = <<"server_host">>, type = text},
|
||||
#sql_column{name = <<"xml">>, type = text},
|
||||
#sql_column{name = <<"created_at">>, type = timestamp,
|
||||
default = true}],
|
||||
indices = [#sql_index{
|
||||
columns = [<<"server_host">>, <<"username">>],
|
||||
unique = true}]}]}].
|
||||
|
||||
set_motd_users(LServer, USRs) ->
|
||||
F = fun() ->
|
||||
lists:foreach(
|
||||
|
@ -37,6 +37,8 @@
|
||||
%%% API
|
||||
%%%===================================================================
|
||||
init() ->
|
||||
ejabberd_sql_schema:update_schema(
|
||||
ejabberd_config:get_myname(), ?MODULE, schemas()),
|
||||
Node = erlang:atom_to_binary(node(), latin1),
|
||||
?DEBUG("Cleaning SQL 'bosh' table...", []),
|
||||
case ejabberd_sql:sql_query(
|
||||
@ -48,6 +50,20 @@ init() ->
|
||||
Err
|
||||
end.
|
||||
|
||||
schemas() ->
|
||||
[#sql_schema{
|
||||
version = 1,
|
||||
tables =
|
||||
[#sql_table{
|
||||
name = <<"bosh">>,
|
||||
columns =
|
||||
[#sql_column{name = <<"sid">>, type = text},
|
||||
#sql_column{name = <<"node">>, type = text},
|
||||
#sql_column{name = <<"pid">>, type = text}],
|
||||
indices = [#sql_index{
|
||||
columns = [<<"sid">>],
|
||||
unique = true}]}]}].
|
||||
|
||||
open_session(SID, Pid) ->
|
||||
PidS = misc:encode_pid(Pid),
|
||||
Node = erlang:atom_to_binary(node(Pid), latin1),
|
||||
|
@ -37,9 +37,25 @@
|
||||
%%%===================================================================
|
||||
%%% API
|
||||
%%%===================================================================
|
||||
init(_Host, _Opts) ->
|
||||
init(Host, _Opts) ->
|
||||
ejabberd_sql_schema:update_schema(Host, ?MODULE, schemas()),
|
||||
ok.
|
||||
|
||||
schemas() ->
|
||||
[#sql_schema{
|
||||
version = 1,
|
||||
tables =
|
||||
[#sql_table{
|
||||
name = <<"caps_features">>,
|
||||
columns =
|
||||
[#sql_column{name = <<"node">>, type = text},
|
||||
#sql_column{name = <<"subnode">>, type = text},
|
||||
#sql_column{name = <<"feature">>, type = text},
|
||||
#sql_column{name = <<"created_at">>, type = timestamp,
|
||||
default = true}],
|
||||
indices = [#sql_index{
|
||||
columns = [<<"node">>, <<"subnode">>]}]}]}].
|
||||
|
||||
caps_read(LServer, {Node, SubNode}) ->
|
||||
case ejabberd_sql:sql_query(
|
||||
LServer,
|
||||
|
@ -38,9 +38,25 @@
|
||||
%%%===================================================================
|
||||
%%% API
|
||||
%%%===================================================================
|
||||
init(_Host, _Opts) ->
|
||||
init(Host, _Opts) ->
|
||||
ejabberd_sql_schema:update_schema(Host, ?MODULE, schemas()),
|
||||
ok.
|
||||
|
||||
schemas() ->
|
||||
[#sql_schema{
|
||||
version = 1,
|
||||
tables =
|
||||
[#sql_table{
|
||||
name = <<"last">>,
|
||||
columns =
|
||||
[#sql_column{name = <<"username">>, type = text},
|
||||
#sql_column{name = <<"server_host">>, type = text},
|
||||
#sql_column{name = <<"seconds">>, type = text},
|
||||
#sql_column{name = <<"state">>, type = text}],
|
||||
indices = [#sql_index{
|
||||
columns = [<<"server_host">>, <<"username">>],
|
||||
unique = true}]}]}].
|
||||
|
||||
get_last(LUser, LServer) ->
|
||||
case ejabberd_sql:sql_query(
|
||||
LServer,
|
||||
|
@ -43,9 +43,59 @@
|
||||
%%%===================================================================
|
||||
%%% API
|
||||
%%%===================================================================
|
||||
init(_Host, _Opts) ->
|
||||
init(Host, _Opts) ->
|
||||
ejabberd_sql_schema:update_schema(Host, ?MODULE, schemas()),
|
||||
ok.
|
||||
|
||||
schemas() ->
|
||||
[#sql_schema{
|
||||
version = 1,
|
||||
tables =
|
||||
[#sql_table{
|
||||
name = <<"archive">>,
|
||||
columns =
|
||||
[#sql_column{name = <<"username">>, type = text},
|
||||
#sql_column{name = <<"server_host">>, type = text},
|
||||
#sql_column{name = <<"timestamp">>, type = bigint},
|
||||
#sql_column{name = <<"peer">>, type = text},
|
||||
#sql_column{name = <<"bare_peer">>, type = text},
|
||||
#sql_column{name = <<"xml">>, type = {text, big}},
|
||||
#sql_column{name = <<"txt">>, type = {text, big}},
|
||||
#sql_column{name = <<"id">>, type = bigserial},
|
||||
#sql_column{name = <<"kind">>, type = {text, 10}},
|
||||
#sql_column{name = <<"nick">>, type = text},
|
||||
#sql_column{name = <<"created_at">>, type = timestamp,
|
||||
default = true}],
|
||||
indices = [#sql_index{
|
||||
columns = [<<"server_host">>, <<"username">>, <<"timestamp">>]},
|
||||
#sql_index{
|
||||
columns = [<<"server_host">>, <<"username">>, <<"peer">>]},
|
||||
#sql_index{
|
||||
columns = [<<"server_host">>, <<"username">>, <<"bare_peer">>]},
|
||||
#sql_index{
|
||||
columns = [<<"server_host">>, <<"timestamp">>]}
|
||||
],
|
||||
post_create =
|
||||
fun(mysql, _) ->
|
||||
ejabberd_sql:sql_query_t(
|
||||
<<"CREATE FULLTEXT INDEX i_archive_txt ON archive(txt);">>);
|
||||
(_, _) ->
|
||||
ok
|
||||
end},
|
||||
#sql_table{
|
||||
name = <<"archive_prefs">>,
|
||||
columns =
|
||||
[#sql_column{name = <<"username">>, type = text},
|
||||
#sql_column{name = <<"server_host">>, type = text},
|
||||
#sql_column{name = <<"def">>, type = text},
|
||||
#sql_column{name = <<"always">>, type = text},
|
||||
#sql_column{name = <<"never">>, type = text},
|
||||
#sql_column{name = <<"created_at">>, type = timestamp,
|
||||
default = true}],
|
||||
indices = [#sql_index{
|
||||
columns = [<<"server_host">>, <<"username">>],
|
||||
unique = true}]}]}].
|
||||
|
||||
remove_user(LUser, LServer) ->
|
||||
ejabberd_sql:sql_query(
|
||||
LServer,
|
||||
|
@ -33,10 +33,29 @@
|
||||
%%%===================================================================
|
||||
%%% API
|
||||
%%%===================================================================
|
||||
init(_Host, _Opts) ->
|
||||
%% TODO
|
||||
init(Host, _Opts) ->
|
||||
ejabberd_sql_schema:update_schema(Host, ?MODULE, schemas()),
|
||||
ok.
|
||||
|
||||
schemas() ->
|
||||
[#sql_schema{
|
||||
version = 1,
|
||||
tables =
|
||||
[#sql_table{
|
||||
name = <<"mix_pam">>,
|
||||
columns =
|
||||
[#sql_column{name = <<"username">>, type = text},
|
||||
#sql_column{name = <<"server_host">>, type = text},
|
||||
#sql_column{name = <<"channel">>, type = text},
|
||||
#sql_column{name = <<"service">>, type = text},
|
||||
#sql_column{name = <<"id">>, type = text},
|
||||
#sql_column{name = <<"created_at">>, type = timestamp,
|
||||
default = true}],
|
||||
indices = [#sql_index{
|
||||
columns = [<<"username">>, <<"server_host">>,
|
||||
<<"channel">>, <<"service">>],
|
||||
unique = true}]}]}].
|
||||
|
||||
add_channel(User, Channel, ID) ->
|
||||
{LUser, LServer, _} = jid:tolower(User),
|
||||
{Chan, Service, _} = jid:tolower(Channel),
|
||||
|
@ -34,10 +34,65 @@
|
||||
%%%===================================================================
|
||||
%%% API
|
||||
%%%===================================================================
|
||||
init(_Host, _Opts) ->
|
||||
%% TODO
|
||||
init(Host, _Opts) ->
|
||||
ejabberd_sql_schema:update_schema(Host, ?MODULE, schemas()),
|
||||
ok.
|
||||
|
||||
schemas() ->
|
||||
[#sql_schema{
|
||||
version = 1,
|
||||
tables =
|
||||
[#sql_table{
|
||||
name = <<"mix_channel">>,
|
||||
columns =
|
||||
[#sql_column{name = <<"channel">>, type = text},
|
||||
#sql_column{name = <<"service">>, type = text},
|
||||
#sql_column{name = <<"username">>, type = text},
|
||||
#sql_column{name = <<"domain">>, type = text},
|
||||
#sql_column{name = <<"jid">>, type = text},
|
||||
#sql_column{name = <<"hidden">>, type = boolean},
|
||||
#sql_column{name = <<"hmac_key">>, type = text},
|
||||
#sql_column{name = <<"created_at">>, type = timestamp,
|
||||
default = true}],
|
||||
indices = [#sql_index{
|
||||
columns = [<<"channel">>, <<"service">>],
|
||||
unique = true},
|
||||
#sql_index{
|
||||
columns = [<<"service">>]}]},
|
||||
#sql_table{
|
||||
name = <<"mix_participant">>,
|
||||
columns =
|
||||
[#sql_column{name = <<"channel">>, type = text},
|
||||
#sql_column{name = <<"service">>, type = text},
|
||||
#sql_column{name = <<"username">>, type = text},
|
||||
#sql_column{name = <<"domain">>, type = text},
|
||||
#sql_column{name = <<"jid">>, type = text},
|
||||
#sql_column{name = <<"id">>, type = text},
|
||||
#sql_column{name = <<"nick">>, type = text},
|
||||
#sql_column{name = <<"created_at">>, type = timestamp,
|
||||
default = true}],
|
||||
indices = [#sql_index{
|
||||
columns = [<<"channel">>, <<"service">>,
|
||||
<<"username">>, <<"domain">>],
|
||||
unique = true}]},
|
||||
#sql_table{
|
||||
name = <<"mix_subscription">>,
|
||||
columns =
|
||||
[#sql_column{name = <<"channel">>, type = text},
|
||||
#sql_column{name = <<"service">>, type = {text, 75}},
|
||||
#sql_column{name = <<"username">>, type = text},
|
||||
#sql_column{name = <<"domain">>, type = {text, 75}},
|
||||
#sql_column{name = <<"node">>, type = text},
|
||||
#sql_column{name = <<"jid">>, type = text}],
|
||||
indices = [#sql_index{
|
||||
columns = [<<"channel">>, <<"service">>,
|
||||
<<"username">>, <<"domain">>,
|
||||
<<"node">>],
|
||||
unique = true},
|
||||
#sql_index{
|
||||
columns = [<<"channel">>, <<"service">>,
|
||||
<<"node">>]}]}]}].
|
||||
|
||||
set_channel(LServer, Channel, Service, CreatorJID, Hidden, Key) ->
|
||||
{User, Domain, _} = jid:tolower(CreatorJID),
|
||||
RawJID = jid:encode(jid:remove_resource(CreatorJID)),
|
||||
|
@ -36,9 +36,33 @@ init() ->
|
||||
?ERROR_MSG("Backend 'sql' is only supported for db_type", []),
|
||||
{error, db_failure}.
|
||||
|
||||
init(_Host, _Opts) ->
|
||||
init(Host, _Opts) ->
|
||||
ejabberd_sql_schema:update_schema(Host, ?MODULE, schemas()),
|
||||
ok.
|
||||
|
||||
schemas() ->
|
||||
[#sql_schema{
|
||||
version = 1,
|
||||
tables =
|
||||
[#sql_table{
|
||||
name = <<"mqtt_pub">>,
|
||||
columns =
|
||||
[#sql_column{name = <<"username">>, type = text},
|
||||
#sql_column{name = <<"server_host">>, type = text},
|
||||
#sql_column{name = <<"resource">>, type = text},
|
||||
#sql_column{name = <<"topic">>, type = text},
|
||||
#sql_column{name = <<"qos">>, type = smallint},
|
||||
#sql_column{name = <<"payload">>, type = blob},
|
||||
#sql_column{name = <<"payload_format">>, type = smallint},
|
||||
#sql_column{name = <<"content_type">>, type = text},
|
||||
#sql_column{name = <<"response_topic">>, type = text},
|
||||
#sql_column{name = <<"correlation_data">>, type = blob},
|
||||
#sql_column{name = <<"user_property">>, type = blob},
|
||||
#sql_column{name = <<"expiry">>, type = bigint}],
|
||||
indices = [#sql_index{
|
||||
columns = [<<"topic">>, <<"server_host">>],
|
||||
unique = true}]}]}].
|
||||
|
||||
publish({U, LServer, R}, Topic, Payload, QoS, Props, ExpiryTime) ->
|
||||
PayloadFormat = encode_pfi(maps:get(payload_format_indicator, Props, binary)),
|
||||
ResponseTopic = maps:get(response_topic, Props, <<"">>),
|
||||
|
@ -52,6 +52,7 @@
|
||||
%%% API
|
||||
%%%===================================================================
|
||||
init(Host, Opts) ->
|
||||
ejabberd_sql_schema:update_schema(Host, ?MODULE, schemas()),
|
||||
case gen_mod:ram_db_mod(Opts, mod_muc) of
|
||||
?MODULE ->
|
||||
clean_tables(Host);
|
||||
@ -59,6 +60,82 @@ init(Host, Opts) ->
|
||||
ok
|
||||
end.
|
||||
|
||||
schemas() ->
|
||||
[#sql_schema{
|
||||
version = 1,
|
||||
tables =
|
||||
[#sql_table{
|
||||
name = <<"muc_room">>,
|
||||
columns =
|
||||
[#sql_column{name = <<"name">>, type = text},
|
||||
#sql_column{name = <<"host">>, type = text},
|
||||
#sql_column{name = <<"server_host">>, type = text},
|
||||
#sql_column{name = <<"opts">>, type = {text, big}},
|
||||
#sql_column{name = <<"created_at">>, type = timestamp,
|
||||
default = true}],
|
||||
indices = [#sql_index{
|
||||
columns = [<<"name">>, <<"host">>],
|
||||
unique = true},
|
||||
#sql_index{
|
||||
columns = [<<"host">>, <<"created_at">>]}]},
|
||||
#sql_table{
|
||||
name = <<"muc_registered">>,
|
||||
columns =
|
||||
[#sql_column{name = <<"jid">>, type = text},
|
||||
#sql_column{name = <<"host">>, type = text},
|
||||
#sql_column{name = <<"server_host">>, type = text},
|
||||
#sql_column{name = <<"nick">>, type = text},
|
||||
#sql_column{name = <<"created_at">>, type = timestamp,
|
||||
default = true}],
|
||||
indices = [#sql_index{
|
||||
columns = [<<"jid">>, <<"host">>],
|
||||
unique = true},
|
||||
#sql_index{
|
||||
columns = [<<"nick">>]}]},
|
||||
#sql_table{
|
||||
name = <<"muc_online_room">>,
|
||||
columns =
|
||||
[#sql_column{name = <<"name">>, type = text},
|
||||
#sql_column{name = <<"host">>, type = text},
|
||||
#sql_column{name = <<"server_host">>, type = text},
|
||||
#sql_column{name = <<"node">>, type = text},
|
||||
#sql_column{name = <<"pid">>, type = text}],
|
||||
indices = [#sql_index{
|
||||
columns = [<<"name">>, <<"host">>],
|
||||
unique = true}]},
|
||||
#sql_table{
|
||||
name = <<"muc_online_users">>,
|
||||
columns =
|
||||
[#sql_column{name = <<"username">>, type = text},
|
||||
#sql_column{name = <<"server">>, type = {text, 75}},
|
||||
#sql_column{name = <<"resource">>, type = text},
|
||||
#sql_column{name = <<"name">>, type = text},
|
||||
#sql_column{name = <<"host">>, type = {text, 75}},
|
||||
#sql_column{name = <<"server_host">>, type = text},
|
||||
#sql_column{name = <<"node">>, type = text}],
|
||||
indices = [#sql_index{
|
||||
columns = [<<"username">>, <<"server">>,
|
||||
<<"resource">>, <<"name">>,
|
||||
<<"host">>],
|
||||
unique = true}]},
|
||||
#sql_table{
|
||||
name = <<"muc_room_subscribers">>,
|
||||
columns =
|
||||
[#sql_column{name = <<"room">>, type = text},
|
||||
#sql_column{name = <<"host">>, type = text},
|
||||
#sql_column{name = <<"jid">>, type = text},
|
||||
#sql_column{name = <<"nick">>, type = text},
|
||||
#sql_column{name = <<"nodes">>, type = text},
|
||||
#sql_column{name = <<"created_at">>, type = timestamp,
|
||||
default = true}],
|
||||
indices = [#sql_index{
|
||||
columns = [<<"host">>, <<"room">>, <<"jid">>],
|
||||
unique = true},
|
||||
#sql_index{
|
||||
columns = [<<"host">>, <<"jid">>]},
|
||||
#sql_index{
|
||||
columns = [<<"jid">>]}]}]}].
|
||||
|
||||
store_room(LServer, Host, Name, Opts, ChangesHints) ->
|
||||
{Subs, Opts2} = case lists:keytake(subscribers, 1, Opts) of
|
||||
{value, {subscribers, S}, OptN} -> {S, OptN};
|
||||
|
@ -40,9 +40,28 @@
|
||||
%%%===================================================================
|
||||
%%% API
|
||||
%%%===================================================================
|
||||
init(_Host, _Opts) ->
|
||||
init(Host, _Opts) ->
|
||||
ejabberd_sql_schema:update_schema(Host, ?MODULE, schemas()),
|
||||
ok.
|
||||
|
||||
schemas() ->
|
||||
[#sql_schema{
|
||||
version = 1,
|
||||
tables =
|
||||
[#sql_table{
|
||||
name = <<"spool">>,
|
||||
columns =
|
||||
[#sql_column{name = <<"username">>, type = text},
|
||||
#sql_column{name = <<"server_host">>, type = text},
|
||||
#sql_column{name = <<"xml">>, type = {text, big}},
|
||||
#sql_column{name = <<"seq">>, type = bigserial},
|
||||
#sql_column{name = <<"created_at">>, type = timestamp,
|
||||
default = true}],
|
||||
indices = [#sql_index{
|
||||
columns = [<<"server_host">>, <<"username">>]},
|
||||
#sql_index{
|
||||
columns = [<<"created_at">>]}]}]}].
|
||||
|
||||
store_message(#offline_msg{us = {LUser, LServer}} = M) ->
|
||||
From = M#offline_msg.from,
|
||||
To = M#offline_msg.to,
|
||||
|
@ -42,9 +42,57 @@
|
||||
%%%===================================================================
|
||||
%%% API
|
||||
%%%===================================================================
|
||||
init(_Host, _Opts) ->
|
||||
init(Host, _Opts) ->
|
||||
ejabberd_sql_schema:update_schema(Host, ?MODULE, schemas()),
|
||||
ok.
|
||||
|
||||
schemas() ->
|
||||
[#sql_schema{
|
||||
version = 1,
|
||||
tables =
|
||||
[#sql_table{
|
||||
name = <<"privacy_default_list">>,
|
||||
columns =
|
||||
[#sql_column{name = <<"username">>, type = text},
|
||||
#sql_column{name = <<"server_host">>, type = text},
|
||||
#sql_column{name = <<"name">>, type = text}],
|
||||
indices = [#sql_index{
|
||||
columns = [<<"server_host">>, <<"username">>],
|
||||
unique = true}]},
|
||||
#sql_table{
|
||||
name = <<"privacy_list">>,
|
||||
columns =
|
||||
[#sql_column{name = <<"username">>, type = text},
|
||||
#sql_column{name = <<"server_host">>, type = text},
|
||||
#sql_column{name = <<"name">>, type = text},
|
||||
#sql_column{name = <<"id">>, type = bigserial},
|
||||
#sql_column{name = <<"created_at">>, type = timestamp,
|
||||
default = true}],
|
||||
indices = [#sql_index{
|
||||
columns = [<<"id">>],
|
||||
unique = true},
|
||||
#sql_index{
|
||||
columns = [<<"server_host">>, <<"username">>,
|
||||
<<"name">>],
|
||||
unique = true}]},
|
||||
#sql_table{
|
||||
name = <<"privacy_list_data">>,
|
||||
columns =
|
||||
[#sql_column{name = <<"id">>, type = bigint,
|
||||
opts = [#sql_references{
|
||||
table = <<"privacy_list">>,
|
||||
column = <<"id">>}]},
|
||||
#sql_column{name = <<"t">>, type = {char, 1}},
|
||||
#sql_column{name = <<"value">>, type = text},
|
||||
#sql_column{name = <<"action">>, type = {char, 1}},
|
||||
#sql_column{name = <<"ord">>, type = numeric},
|
||||
#sql_column{name = <<"match_all">>, type = boolean},
|
||||
#sql_column{name = <<"match_iq">>, type = boolean},
|
||||
#sql_column{name = <<"match_message">>, type = boolean},
|
||||
#sql_column{name = <<"match_presence_in">>, type = boolean},
|
||||
#sql_column{name = <<"match_presence_out">>, type = boolean}],
|
||||
indices = [#sql_index{columns = [<<"id">>]}]}]}].
|
||||
|
||||
unset_default(LUser, LServer) ->
|
||||
case unset_default_privacy_list(LUser, LServer) of
|
||||
ok ->
|
||||
|
@ -37,9 +37,28 @@
|
||||
%%%===================================================================
|
||||
%%% API
|
||||
%%%===================================================================
|
||||
init(_Host, _Opts) ->
|
||||
init(Host, _Opts) ->
|
||||
ejabberd_sql_schema:update_schema(Host, ?MODULE, schemas()),
|
||||
ok.
|
||||
|
||||
schemas() ->
|
||||
[#sql_schema{
|
||||
version = 1,
|
||||
tables =
|
||||
[#sql_table{
|
||||
name = <<"private_storage">>,
|
||||
columns =
|
||||
[#sql_column{name = <<"username">>, type = text},
|
||||
#sql_column{name = <<"server_host">>, type = text},
|
||||
#sql_column{name = <<"namespace">>, type = text},
|
||||
#sql_column{name = <<"data">>, type = text},
|
||||
#sql_column{name = <<"created_at">>, type = timestamp,
|
||||
default = true}],
|
||||
indices = [#sql_index{
|
||||
columns = [<<"server_host">>, <<"username">>,
|
||||
<<"namespace">>],
|
||||
unique = true}]}]}].
|
||||
|
||||
set_data(LUser, LServer, Data) ->
|
||||
F = fun() ->
|
||||
lists:foreach(
|
||||
|
@ -34,6 +34,8 @@
|
||||
%%% API
|
||||
%%%===================================================================
|
||||
init() ->
|
||||
ejabberd_sql_schema:update_schema(
|
||||
ejabberd_config:get_myname(), ?MODULE, schemas()),
|
||||
NodeS = erlang:atom_to_binary(node(), latin1),
|
||||
?DEBUG("Cleaning SQL 'proxy65' table...", []),
|
||||
case ejabberd_sql:sql_query(
|
||||
@ -47,6 +49,25 @@ init() ->
|
||||
Err
|
||||
end.
|
||||
|
||||
schemas() ->
|
||||
[#sql_schema{
|
||||
version = 1,
|
||||
tables =
|
||||
[#sql_table{
|
||||
name = <<"proxy65">>,
|
||||
columns =
|
||||
[#sql_column{name = <<"sid">>, type = text},
|
||||
#sql_column{name = <<"pid_t">>, type = text},
|
||||
#sql_column{name = <<"pid_i">>, type = text},
|
||||
#sql_column{name = <<"node_t">>, type = text},
|
||||
#sql_column{name = <<"node_i">>, type = text},
|
||||
#sql_column{name = <<"jid_i">>, type = text}],
|
||||
indices = [#sql_index{
|
||||
columns = [<<"sid">>],
|
||||
unique = true},
|
||||
#sql_index{
|
||||
columns = [<<"jid_i">>]}]}]}].
|
||||
|
||||
register_stream(SID, Pid) ->
|
||||
PidS = misc:encode_pid(Pid),
|
||||
NodeS = erlang:atom_to_binary(node(Pid), latin1),
|
||||
|
@ -21,12 +21,96 @@
|
||||
%% API
|
||||
-export([init/3]).
|
||||
|
||||
-include("ejabberd_sql_pt.hrl").
|
||||
|
||||
%%%===================================================================
|
||||
%%% API
|
||||
%%%===================================================================
|
||||
init(_Host, _ServerHost, _Opts) ->
|
||||
init(_Host, ServerHost, _Opts) ->
|
||||
ejabberd_sql_schema:update_schema(ServerHost, ?MODULE, schemas()),
|
||||
ok.
|
||||
|
||||
%%%===================================================================
|
||||
%%% Internal functions
|
||||
%%%===================================================================
|
||||
schemas() ->
|
||||
[#sql_schema{
|
||||
version = 1,
|
||||
tables =
|
||||
[#sql_table{
|
||||
name = <<"pubsub_node">>,
|
||||
columns =
|
||||
[#sql_column{name = <<"host">>, type = text},
|
||||
#sql_column{name = <<"node">>, type = text},
|
||||
#sql_column{name = <<"parent">>, type = text,
|
||||
default = true},
|
||||
#sql_column{name = <<"plugin">>, type = text},
|
||||
#sql_column{name = <<"nodeid">>, type = bigserial}],
|
||||
indices = [#sql_index{
|
||||
columns = [<<"nodeid">>],
|
||||
unique = true},
|
||||
#sql_index{
|
||||
columns = [<<"parent">>]},
|
||||
#sql_index{
|
||||
columns = [<<"host">>, <<"node">>],
|
||||
unique = true}]},
|
||||
#sql_table{
|
||||
name = <<"pubsub_node_option">>,
|
||||
columns =
|
||||
[#sql_column{name = <<"nodeid">>, type = bigint,
|
||||
opts = [#sql_references{
|
||||
table = <<"pubsub_node">>,
|
||||
column = <<"nodeid">>}]},
|
||||
#sql_column{name = <<"name">>, type = text},
|
||||
#sql_column{name = <<"val">>, type = text}],
|
||||
indices = [#sql_index{columns = [<<"nodeid">>]}]},
|
||||
#sql_table{
|
||||
name = <<"pubsub_node_owner">>,
|
||||
columns =
|
||||
[#sql_column{name = <<"nodeid">>, type = bigint,
|
||||
opts = [#sql_references{
|
||||
table = <<"pubsub_node">>,
|
||||
column = <<"nodeid">>}]},
|
||||
#sql_column{name = <<"owner">>, type = text}],
|
||||
indices = [#sql_index{columns = [<<"nodeid">>]}]},
|
||||
#sql_table{
|
||||
name = <<"pubsub_state">>,
|
||||
columns =
|
||||
[#sql_column{name = <<"nodeid">>, type = bigint,
|
||||
opts = [#sql_references{
|
||||
table = <<"pubsub_node">>,
|
||||
column = <<"nodeid">>}]},
|
||||
#sql_column{name = <<"jid">>, type = text},
|
||||
#sql_column{name = <<"affiliation">>, type = {char, 1}},
|
||||
#sql_column{name = <<"subscriptions">>, type = text,
|
||||
default = true},
|
||||
#sql_column{name = <<"stateid">>, type = bigserial}],
|
||||
indices = [#sql_index{columns = [<<"stateid">>],
|
||||
unique = true},
|
||||
#sql_index{columns = [<<"jid">>]},
|
||||
#sql_index{columns = [<<"nodeid">>, <<"jid">>],
|
||||
unique = true}]},
|
||||
#sql_table{
|
||||
name = <<"pubsub_item">>,
|
||||
columns =
|
||||
[#sql_column{name = <<"nodeid">>, type = bigint,
|
||||
opts = [#sql_references{
|
||||
table = <<"pubsub_node">>,
|
||||
column = <<"nodeid">>}]},
|
||||
#sql_column{name = <<"itemid">>, type = text},
|
||||
#sql_column{name = <<"publisher">>, type = text},
|
||||
#sql_column{name = <<"creation">>, type = {text, 32}},
|
||||
#sql_column{name = <<"modification">>, type = {text, 32}},
|
||||
#sql_column{name = <<"payload">>, type = {text, big},
|
||||
default = true}],
|
||||
indices = [#sql_index{columns = [<<"nodeid">>, <<"itemid">>],
|
||||
unique = true},
|
||||
#sql_index{columns = [<<"itemid">>]}]},
|
||||
#sql_table{
|
||||
name = <<"pubsub_subscription_opt">>,
|
||||
columns =
|
||||
[#sql_column{name = <<"subid">>, type = text},
|
||||
#sql_column{name = <<"opt_name">>, type = {text, 32}},
|
||||
#sql_column{name = <<"opt_value">>, type = text}],
|
||||
indices = [#sql_index{columns = [<<"subid">>, <<"opt_name">>],
|
||||
unique = true}]}]}].
|
||||
|
@ -39,9 +39,32 @@
|
||||
%%%===================================================================
|
||||
%%% API
|
||||
%%%===================================================================
|
||||
init(_Host, _Opts) ->
|
||||
init(Host, _Opts) ->
|
||||
ejabberd_sql_schema:update_schema(Host, ?MODULE, schemas()),
|
||||
ok.
|
||||
|
||||
schemas() ->
|
||||
[#sql_schema{
|
||||
version = 1,
|
||||
tables =
|
||||
[#sql_table{
|
||||
name = <<"push_session">>,
|
||||
columns =
|
||||
[#sql_column{name = <<"username">>, type = text},
|
||||
#sql_column{name = <<"server_host">>, type = text},
|
||||
#sql_column{name = <<"timestamp">>, type = bigint},
|
||||
#sql_column{name = <<"service">>, type = text},
|
||||
#sql_column{name = <<"node">>, type = text},
|
||||
#sql_column{name = <<"xml">>, type = text}],
|
||||
indices = [#sql_index{
|
||||
columns = [<<"server_host">>, <<"username">>,
|
||||
<<"timestamp">>],
|
||||
unique = true},
|
||||
#sql_index{
|
||||
columns = [<<"server_host">>, <<"username">>,
|
||||
<<"service">>, <<"node">>],
|
||||
unique = true}]}]}].
|
||||
|
||||
store_session(LUser, LServer, NowTS, PushJID, Node, XData) ->
|
||||
XML = encode_xdata(XData),
|
||||
TS = misc:now_to_usec(NowTS),
|
||||
|
@ -43,9 +43,55 @@
|
||||
%%%===================================================================
|
||||
%%% API
|
||||
%%%===================================================================
|
||||
init(_Host, _Opts) ->
|
||||
init(Host, _Opts) ->
|
||||
ejabberd_sql_schema:update_schema(Host, ?MODULE, schemas()),
|
||||
ok.
|
||||
|
||||
schemas() ->
|
||||
[#sql_schema{
|
||||
version = 1,
|
||||
tables =
|
||||
[#sql_table{
|
||||
name = <<"rosterusers">>,
|
||||
columns =
|
||||
[#sql_column{name = <<"username">>, type = text},
|
||||
#sql_column{name = <<"server_host">>, type = text},
|
||||
#sql_column{name = <<"jid">>, type = text},
|
||||
#sql_column{name = <<"nick">>, type = text},
|
||||
#sql_column{name = <<"subscription">>, type = {char, 1}},
|
||||
#sql_column{name = <<"ask">>, type = {char, 1}},
|
||||
#sql_column{name = <<"askmessage">>, type = text},
|
||||
#sql_column{name = <<"server">>, type = {char, 1}},
|
||||
#sql_column{name = <<"subscribe">>, type = text},
|
||||
#sql_column{name = <<"type">>, type = text},
|
||||
#sql_column{name = <<"created_at">>, type = timestamp,
|
||||
default = true}],
|
||||
indices = [#sql_index{
|
||||
columns = [<<"server_host">>, <<"username">>,
|
||||
<<"jid">>],
|
||||
unique = true},
|
||||
#sql_index{
|
||||
columns = [<<"server_host">>, <<"jid">>]}]},
|
||||
#sql_table{
|
||||
name = <<"rostergroups">>,
|
||||
columns =
|
||||
[#sql_column{name = <<"username">>, type = text},
|
||||
#sql_column{name = <<"server_host">>, type = text},
|
||||
#sql_column{name = <<"jid">>, type = text},
|
||||
#sql_column{name = <<"grp">>, type = text}],
|
||||
indices = [#sql_index{
|
||||
columns = [<<"server_host">>, <<"username">>,
|
||||
<<"jid">>]}]},
|
||||
#sql_table{
|
||||
name = <<"roster_version">>,
|
||||
columns =
|
||||
[#sql_column{name = <<"username">>, type = text},
|
||||
#sql_column{name = <<"server_host">>, type = text},
|
||||
#sql_column{name = <<"version">>, type = text}],
|
||||
indices = [#sql_index{
|
||||
columns = [<<"server_host">>, <<"username">>],
|
||||
unique = true}]}]}].
|
||||
|
||||
read_roster_version(LUser, LServer) ->
|
||||
case ejabberd_sql:sql_query(
|
||||
LServer,
|
||||
|
@ -43,9 +43,40 @@
|
||||
%%%===================================================================
|
||||
%%% API
|
||||
%%%===================================================================
|
||||
init(_Host, _Opts) ->
|
||||
init(Host, _Opts) ->
|
||||
ejabberd_sql_schema:update_schema(Host, ?MODULE, schemas()),
|
||||
ok.
|
||||
|
||||
schemas() ->
|
||||
[#sql_schema{
|
||||
version = 1,
|
||||
tables =
|
||||
[#sql_table{
|
||||
name = <<"sr_group">>,
|
||||
columns =
|
||||
[#sql_column{name = <<"name">>, type = text},
|
||||
#sql_column{name = <<"server_host">>, type = text},
|
||||
#sql_column{name = <<"opts">>, type = text},
|
||||
#sql_column{name = <<"created_at">>, type = timestamp,
|
||||
default = true}],
|
||||
indices = [#sql_index{
|
||||
columns = [<<"server_host">>, <<"name">>],
|
||||
unique = true}]},
|
||||
#sql_table{
|
||||
name = <<"sr_user">>,
|
||||
columns =
|
||||
[#sql_column{name = <<"jid">>, type = text},
|
||||
#sql_column{name = <<"server_host">>, type = text},
|
||||
#sql_column{name = <<"grp">>, type = text},
|
||||
#sql_column{name = <<"created_at">>, type = timestamp,
|
||||
default = true}],
|
||||
indices = [#sql_index{
|
||||
columns = [<<"server_host">>,
|
||||
<<"jid">>, <<"grp">>],
|
||||
unique = true},
|
||||
#sql_index{
|
||||
columns = [<<"server_host">>, <<"grp">>]}]}]}].
|
||||
|
||||
list_groups(Host) ->
|
||||
case ejabberd_sql:sql_query(
|
||||
Host,
|
||||
|
@ -41,9 +41,79 @@
|
||||
%%%===================================================================
|
||||
%%% API
|
||||
%%%===================================================================
|
||||
init(_Host, _Opts) ->
|
||||
init(Host, _Opts) ->
|
||||
ejabberd_sql_schema:update_schema(Host, ?MODULE, schemas()),
|
||||
ok.
|
||||
|
||||
schemas() ->
|
||||
[#sql_schema{
|
||||
version = 1,
|
||||
tables =
|
||||
[#sql_table{
|
||||
name = <<"vcard">>,
|
||||
columns =
|
||||
[#sql_column{name = <<"username">>, type = text},
|
||||
#sql_column{name = <<"server_host">>, type = text},
|
||||
#sql_column{name = <<"vcard">>, type = {text, big}},
|
||||
#sql_column{name = <<"created_at">>, type = timestamp,
|
||||
default = true}],
|
||||
indices = [#sql_index{
|
||||
columns = [<<"server_host">>, <<"username">>],
|
||||
unique = true}]},
|
||||
#sql_table{
|
||||
name = <<"vcard_search">>,
|
||||
columns =
|
||||
[#sql_column{name = <<"username">>, type = text},
|
||||
#sql_column{name = <<"lusername">>, type = text},
|
||||
#sql_column{name = <<"server_host">>, type = text},
|
||||
#sql_column{name = <<"fn">>, type = text},
|
||||
#sql_column{name = <<"lfn">>, type = text},
|
||||
#sql_column{name = <<"family">>, type = text},
|
||||
#sql_column{name = <<"lfamily">>, type = text},
|
||||
#sql_column{name = <<"given">>, type = text},
|
||||
#sql_column{name = <<"lgiven">>, type = text},
|
||||
#sql_column{name = <<"middle">>, type = text},
|
||||
#sql_column{name = <<"lmiddle">>, type = text},
|
||||
#sql_column{name = <<"nickname">>, type = text},
|
||||
#sql_column{name = <<"lnickname">>, type = text},
|
||||
#sql_column{name = <<"bday">>, type = text},
|
||||
#sql_column{name = <<"lbday">>, type = text},
|
||||
#sql_column{name = <<"ctry">>, type = text},
|
||||
#sql_column{name = <<"lctry">>, type = text},
|
||||
#sql_column{name = <<"locality">>, type = text},
|
||||
#sql_column{name = <<"llocality">>, type = text},
|
||||
#sql_column{name = <<"email">>, type = text},
|
||||
#sql_column{name = <<"lemail">>, type = text},
|
||||
#sql_column{name = <<"orgname">>, type = text},
|
||||
#sql_column{name = <<"lorgname">>, type = text},
|
||||
#sql_column{name = <<"orgunit">>, type = text},
|
||||
#sql_column{name = <<"lorgunit">>, type = text}],
|
||||
indices = [#sql_index{
|
||||
columns = [<<"server_host">>, <<"lusername">>],
|
||||
unique = true},
|
||||
#sql_index{
|
||||
columns = [<<"server_host">>, <<"lfn">>]},
|
||||
#sql_index{
|
||||
columns = [<<"server_host">>, <<"lfamily">>]},
|
||||
#sql_index{
|
||||
columns = [<<"server_host">>, <<"lgiven">>]},
|
||||
#sql_index{
|
||||
columns = [<<"server_host">>, <<"lmiddle">>]},
|
||||
#sql_index{
|
||||
columns = [<<"server_host">>, <<"lnickname">>]},
|
||||
#sql_index{
|
||||
columns = [<<"server_host">>, <<"lbday">>]},
|
||||
#sql_index{
|
||||
columns = [<<"server_host">>, <<"lctry">>]},
|
||||
#sql_index{
|
||||
columns = [<<"server_host">>, <<"llocality">>]},
|
||||
#sql_index{
|
||||
columns = [<<"server_host">>, <<"lemail">>]},
|
||||
#sql_index{
|
||||
columns = [<<"server_host">>, <<"lorgname">>]},
|
||||
#sql_index{
|
||||
columns = [<<"server_host">>, <<"lorgunit">>]}]}]}].
|
||||
|
||||
stop(_Host) ->
|
||||
ok.
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user