mirror of
https://github.com/processone/ejabberd.git
synced 2024-11-24 16:23:40 +01:00
Automatically create and update SQL schema
This commit is contained in:
parent
f6e8eb52f0
commit
c1af36ac20
@ -50,3 +50,20 @@
|
|||||||
boolean :: fun((boolean()) -> binary()),
|
boolean :: fun((boolean()) -> binary()),
|
||||||
in_array_string :: fun((binary()) -> binary()),
|
in_array_string :: fun((binary()) -> binary()),
|
||||||
like_escape :: fun(() -> 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
|
%%% 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.
|
stop(_Host) -> ok.
|
||||||
|
|
||||||
|
@ -41,8 +41,35 @@
|
|||||||
-include("logger.hrl").
|
-include("logger.hrl").
|
||||||
|
|
||||||
init() ->
|
init() ->
|
||||||
|
ejabberd_sql_schema:update_schema(
|
||||||
|
ejabberd_config:get_myname(), ?MODULE, schemas()),
|
||||||
ok.
|
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) ->
|
store(R) ->
|
||||||
Token = R#oauth_token.token,
|
Token = R#oauth_token.token,
|
||||||
{User, Server} = R#oauth_token.us,
|
{User, Server} = R#oauth_token.us,
|
||||||
|
@ -162,6 +162,7 @@
|
|||||||
-export([sql_type/0, sql_type/1]).
|
-export([sql_type/0, sql_type/1]).
|
||||||
-export([sql_username/0, sql_username/1]).
|
-export([sql_username/0, sql_username/1]).
|
||||||
-export([trusted_proxies/0]).
|
-export([trusted_proxies/0]).
|
||||||
|
-export([update_sql_schema/0]).
|
||||||
-export([use_cache/0, use_cache/1]).
|
-export([use_cache/0, use_cache/1]).
|
||||||
-export([validate_stream/0]).
|
-export([validate_stream/0]).
|
||||||
-export([version/0]).
|
-export([version/0]).
|
||||||
@ -1096,6 +1097,10 @@ sql_username(Host) ->
|
|||||||
trusted_proxies() ->
|
trusted_proxies() ->
|
||||||
ejabberd_config:get_option({trusted_proxies, global}).
|
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().
|
-spec use_cache() -> boolean().
|
||||||
use_cache() ->
|
use_cache() ->
|
||||||
use_cache(global).
|
use_cache(global).
|
||||||
|
@ -260,6 +260,8 @@ opt_type(net_ticktime) ->
|
|||||||
econf:timeout(second);
|
econf:timeout(second);
|
||||||
opt_type(new_sql_schema) ->
|
opt_type(new_sql_schema) ->
|
||||||
econf:bool();
|
econf:bool();
|
||||||
|
opt_type(update_sql_schema) ->
|
||||||
|
econf:bool();
|
||||||
opt_type(oauth_access) ->
|
opt_type(oauth_access) ->
|
||||||
econf:acl();
|
econf:acl();
|
||||||
opt_type(oauth_cache_life_time) ->
|
opt_type(oauth_cache_life_time) ->
|
||||||
@ -607,6 +609,7 @@ options() ->
|
|||||||
{negotiation_timeout, timer:seconds(30)},
|
{negotiation_timeout, timer:seconds(30)},
|
||||||
{net_ticktime, timer:seconds(60)},
|
{net_ticktime, timer:seconds(60)},
|
||||||
{new_sql_schema, ?USE_NEW_SQL_SCHEMA_DEFAULT},
|
{new_sql_schema, ?USE_NEW_SQL_SCHEMA_DEFAULT},
|
||||||
|
{update_sql_schema, true},
|
||||||
{oauth_access, none},
|
{oauth_access, none},
|
||||||
{oauth_cache_life_time,
|
{oauth_cache_life_time,
|
||||||
fun(Host) -> ejabberd_config:get_option({cache_life_time, Host}) end},
|
fun(Host) -> ejabberd_config:get_option({cache_life_time, Host}) end},
|
||||||
@ -756,6 +759,7 @@ globals() ->
|
|||||||
negotiation_timeout,
|
negotiation_timeout,
|
||||||
net_ticktime,
|
net_ticktime,
|
||||||
new_sql_schema,
|
new_sql_schema,
|
||||||
|
update_sql_schema,
|
||||||
node_start,
|
node_start,
|
||||||
oauth_cache_life_time,
|
oauth_cache_life_time,
|
||||||
oauth_cache_missed,
|
oauth_cache_missed,
|
||||||
|
@ -911,6 +911,11 @@ doc() ->
|
|||||||
"configuration flag '--enable-new-sql-schema' which is set "
|
"configuration flag '--enable-new-sql-schema' which is set "
|
||||||
"at compile time."),
|
"at compile time."),
|
||||||
[binary:part(ejabberd_config:version(), {0,5})]}}},
|
[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,
|
{oauth_access,
|
||||||
#{value => ?T("AccessName"),
|
#{value => ?T("AccessName"),
|
||||||
desc => ?T("By default creating OAuth tokens is not allowed. "
|
desc => ?T("By default creating OAuth tokens is not allowed. "
|
||||||
|
@ -37,6 +37,8 @@
|
|||||||
%%% API
|
%%% API
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
init() ->
|
init() ->
|
||||||
|
ejabberd_sql_schema:update_schema(
|
||||||
|
ejabberd_config:get_myname(), ?MODULE, schemas()),
|
||||||
Node = erlang:atom_to_binary(node(), latin1),
|
Node = erlang:atom_to_binary(node(), latin1),
|
||||||
?DEBUG("Cleaning SQL 'route' table...", []),
|
?DEBUG("Cleaning SQL 'route' table...", []),
|
||||||
case ejabberd_sql:sql_query(
|
case ejabberd_sql:sql_query(
|
||||||
@ -48,6 +50,23 @@ init() ->
|
|||||||
Err
|
Err
|
||||||
end.
|
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) ->
|
register_route(Domain, ServerHost, LocalHint, _, Pid) ->
|
||||||
PidS = misc:encode_pid(Pid),
|
PidS = misc:encode_pid(Pid),
|
||||||
LocalHintS = enc_local_hint(LocalHint),
|
LocalHintS = enc_local_hint(LocalHint),
|
||||||
|
@ -48,6 +48,7 @@ init() ->
|
|||||||
?DEBUG("Cleaning SQL SM table...", []),
|
?DEBUG("Cleaning SQL SM table...", []),
|
||||||
lists:foldl(
|
lists:foldl(
|
||||||
fun(Host, ok) ->
|
fun(Host, ok) ->
|
||||||
|
ejabberd_sql_schema:update_schema(Host, ?MODULE, schemas()),
|
||||||
case ejabberd_sql:sql_query(
|
case ejabberd_sql:sql_query(
|
||||||
Host, ?SQL("delete from sm where node=%(Node)s")) of
|
Host, ?SQL("delete from sm where node=%(Node)s")) of
|
||||||
{updated, _} ->
|
{updated, _} ->
|
||||||
@ -60,6 +61,29 @@ init() ->
|
|||||||
Err
|
Err
|
||||||
end, ok, ejabberd_sm:get_vh_by_backend(?MODULE)).
|
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},
|
set_session(#session{sid = {Now, Pid}, usr = {U, LServer, R},
|
||||||
priority = Priority, info = Info}) ->
|
priority = Priority, info = Info}) ->
|
||||||
InfoS = misc:term_to_expr(Info),
|
InfoS = misc:term_to_expr(Info),
|
||||||
|
936
src/ejabberd_sql_schema.erl
Normal file
936
src/ejabberd_sql_schema.erl
Normal file
@ -0,0 +1,936 @@
|
|||||||
|
%%%----------------------------------------------------------------------
|
||||||
|
%%% 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 = misc: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 = misc: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">> -> 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) ->
|
||||||
|
SupportedDB =
|
||||||
|
case ejabberd_option:sql_type(Host) of
|
||||||
|
pgsql -> true;
|
||||||
|
sqlite -> true;
|
||||||
|
mysql -> true;
|
||||||
|
_ -> false
|
||||||
|
end,
|
||||||
|
case ejabberd_option:update_sql_schema() andalso SupportedDB 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,
|
type => supervisor,
|
||||||
modules => [?MODULE]},
|
modules => [?MODULE]},
|
||||||
case supervisor:start_child(ejabberd_db_sup, Spec) of
|
case supervisor:start_child(ejabberd_db_sup, Spec) of
|
||||||
{ok, _} -> ok;
|
{ok, _} ->
|
||||||
|
ejabberd_sql_schema:start(Host),
|
||||||
|
ok;
|
||||||
{error, {already_started, Pid}} ->
|
{error, {already_started, Pid}} ->
|
||||||
%% Wait for the supervisor to fully start
|
%% Wait for the supervisor to fully start
|
||||||
_ = supervisor:count_children(Pid),
|
_ = supervisor:count_children(Pid),
|
||||||
|
@ -40,9 +40,26 @@
|
|||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
%%% API
|
%%% API
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
init(_Host, _Opts) ->
|
init(Host, _Opts) ->
|
||||||
|
ejabberd_sql_schema:update_schema(Host, ?MODULE, schemas()),
|
||||||
ok.
|
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) ->
|
set_motd_users(LServer, USRs) ->
|
||||||
F = fun() ->
|
F = fun() ->
|
||||||
lists:foreach(
|
lists:foreach(
|
||||||
|
@ -37,6 +37,8 @@
|
|||||||
%%% API
|
%%% API
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
init() ->
|
init() ->
|
||||||
|
ejabberd_sql_schema:update_schema(
|
||||||
|
ejabberd_config:get_myname(), ?MODULE, schemas()),
|
||||||
Node = erlang:atom_to_binary(node(), latin1),
|
Node = erlang:atom_to_binary(node(), latin1),
|
||||||
?DEBUG("Cleaning SQL 'bosh' table...", []),
|
?DEBUG("Cleaning SQL 'bosh' table...", []),
|
||||||
case ejabberd_sql:sql_query(
|
case ejabberd_sql:sql_query(
|
||||||
@ -48,6 +50,20 @@ init() ->
|
|||||||
Err
|
Err
|
||||||
end.
|
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) ->
|
open_session(SID, Pid) ->
|
||||||
PidS = misc:encode_pid(Pid),
|
PidS = misc:encode_pid(Pid),
|
||||||
Node = erlang:atom_to_binary(node(Pid), latin1),
|
Node = erlang:atom_to_binary(node(Pid), latin1),
|
||||||
|
@ -37,9 +37,25 @@
|
|||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
%%% API
|
%%% API
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
init(_Host, _Opts) ->
|
init(Host, _Opts) ->
|
||||||
|
ejabberd_sql_schema:update_schema(Host, ?MODULE, schemas()),
|
||||||
ok.
|
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}) ->
|
caps_read(LServer, {Node, SubNode}) ->
|
||||||
case ejabberd_sql:sql_query(
|
case ejabberd_sql:sql_query(
|
||||||
LServer,
|
LServer,
|
||||||
|
@ -38,9 +38,25 @@
|
|||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
%%% API
|
%%% API
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
init(_Host, _Opts) ->
|
init(Host, _Opts) ->
|
||||||
|
ejabberd_sql_schema:update_schema(Host, ?MODULE, schemas()),
|
||||||
ok.
|
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) ->
|
get_last(LUser, LServer) ->
|
||||||
case ejabberd_sql:sql_query(
|
case ejabberd_sql:sql_query(
|
||||||
LServer,
|
LServer,
|
||||||
|
@ -43,9 +43,59 @@
|
|||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
%%% API
|
%%% API
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
init(_Host, _Opts) ->
|
init(Host, _Opts) ->
|
||||||
|
ejabberd_sql_schema:update_schema(Host, ?MODULE, schemas()),
|
||||||
ok.
|
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) ->
|
remove_user(LUser, LServer) ->
|
||||||
ejabberd_sql:sql_query(
|
ejabberd_sql:sql_query(
|
||||||
LServer,
|
LServer,
|
||||||
|
@ -33,10 +33,29 @@
|
|||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
%%% API
|
%%% API
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
init(_Host, _Opts) ->
|
init(Host, _Opts) ->
|
||||||
%% TODO
|
ejabberd_sql_schema:update_schema(Host, ?MODULE, schemas()),
|
||||||
ok.
|
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) ->
|
add_channel(User, Channel, ID) ->
|
||||||
{LUser, LServer, _} = jid:tolower(User),
|
{LUser, LServer, _} = jid:tolower(User),
|
||||||
{Chan, Service, _} = jid:tolower(Channel),
|
{Chan, Service, _} = jid:tolower(Channel),
|
||||||
|
@ -34,10 +34,65 @@
|
|||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
%%% API
|
%%% API
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
init(_Host, _Opts) ->
|
init(Host, _Opts) ->
|
||||||
%% TODO
|
ejabberd_sql_schema:update_schema(Host, ?MODULE, schemas()),
|
||||||
ok.
|
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) ->
|
set_channel(LServer, Channel, Service, CreatorJID, Hidden, Key) ->
|
||||||
{User, Domain, _} = jid:tolower(CreatorJID),
|
{User, Domain, _} = jid:tolower(CreatorJID),
|
||||||
RawJID = jid:encode(jid:remove_resource(CreatorJID)),
|
RawJID = jid:encode(jid:remove_resource(CreatorJID)),
|
||||||
|
@ -36,9 +36,33 @@ init() ->
|
|||||||
?ERROR_MSG("Backend 'sql' is only supported for db_type", []),
|
?ERROR_MSG("Backend 'sql' is only supported for db_type", []),
|
||||||
{error, db_failure}.
|
{error, db_failure}.
|
||||||
|
|
||||||
init(_Host, _Opts) ->
|
init(Host, _Opts) ->
|
||||||
|
ejabberd_sql_schema:update_schema(Host, ?MODULE, schemas()),
|
||||||
ok.
|
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) ->
|
publish({U, LServer, R}, Topic, Payload, QoS, Props, ExpiryTime) ->
|
||||||
PayloadFormat = encode_pfi(maps:get(payload_format_indicator, Props, binary)),
|
PayloadFormat = encode_pfi(maps:get(payload_format_indicator, Props, binary)),
|
||||||
ResponseTopic = maps:get(response_topic, Props, <<"">>),
|
ResponseTopic = maps:get(response_topic, Props, <<"">>),
|
||||||
|
@ -52,6 +52,7 @@
|
|||||||
%%% API
|
%%% API
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
init(Host, Opts) ->
|
init(Host, Opts) ->
|
||||||
|
ejabberd_sql_schema:update_schema(Host, ?MODULE, schemas()),
|
||||||
case gen_mod:ram_db_mod(Opts, mod_muc) of
|
case gen_mod:ram_db_mod(Opts, mod_muc) of
|
||||||
?MODULE ->
|
?MODULE ->
|
||||||
clean_tables(Host);
|
clean_tables(Host);
|
||||||
@ -59,6 +60,82 @@ init(Host, Opts) ->
|
|||||||
ok
|
ok
|
||||||
end.
|
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) ->
|
store_room(LServer, Host, Name, Opts, ChangesHints) ->
|
||||||
{Subs, Opts2} = case lists:keytake(subscribers, 1, Opts) of
|
{Subs, Opts2} = case lists:keytake(subscribers, 1, Opts) of
|
||||||
{value, {subscribers, S}, OptN} -> {S, OptN};
|
{value, {subscribers, S}, OptN} -> {S, OptN};
|
||||||
|
@ -40,9 +40,28 @@
|
|||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
%%% API
|
%%% API
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
init(_Host, _Opts) ->
|
init(Host, _Opts) ->
|
||||||
|
ejabberd_sql_schema:update_schema(Host, ?MODULE, schemas()),
|
||||||
ok.
|
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) ->
|
store_message(#offline_msg{us = {LUser, LServer}} = M) ->
|
||||||
From = M#offline_msg.from,
|
From = M#offline_msg.from,
|
||||||
To = M#offline_msg.to,
|
To = M#offline_msg.to,
|
||||||
|
@ -42,9 +42,57 @@
|
|||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
%%% API
|
%%% API
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
init(_Host, _Opts) ->
|
init(Host, _Opts) ->
|
||||||
|
ejabberd_sql_schema:update_schema(Host, ?MODULE, schemas()),
|
||||||
ok.
|
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) ->
|
unset_default(LUser, LServer) ->
|
||||||
case unset_default_privacy_list(LUser, LServer) of
|
case unset_default_privacy_list(LUser, LServer) of
|
||||||
ok ->
|
ok ->
|
||||||
|
@ -37,9 +37,28 @@
|
|||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
%%% API
|
%%% API
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
init(_Host, _Opts) ->
|
init(Host, _Opts) ->
|
||||||
|
ejabberd_sql_schema:update_schema(Host, ?MODULE, schemas()),
|
||||||
ok.
|
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) ->
|
set_data(LUser, LServer, Data) ->
|
||||||
F = fun() ->
|
F = fun() ->
|
||||||
lists:foreach(
|
lists:foreach(
|
||||||
|
@ -34,6 +34,8 @@
|
|||||||
%%% API
|
%%% API
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
init() ->
|
init() ->
|
||||||
|
ejabberd_sql_schema:update_schema(
|
||||||
|
ejabberd_config:get_myname(), ?MODULE, schemas()),
|
||||||
NodeS = erlang:atom_to_binary(node(), latin1),
|
NodeS = erlang:atom_to_binary(node(), latin1),
|
||||||
?DEBUG("Cleaning SQL 'proxy65' table...", []),
|
?DEBUG("Cleaning SQL 'proxy65' table...", []),
|
||||||
case ejabberd_sql:sql_query(
|
case ejabberd_sql:sql_query(
|
||||||
@ -47,6 +49,25 @@ init() ->
|
|||||||
Err
|
Err
|
||||||
end.
|
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) ->
|
register_stream(SID, Pid) ->
|
||||||
PidS = misc:encode_pid(Pid),
|
PidS = misc:encode_pid(Pid),
|
||||||
NodeS = erlang:atom_to_binary(node(Pid), latin1),
|
NodeS = erlang:atom_to_binary(node(Pid), latin1),
|
||||||
|
@ -21,12 +21,96 @@
|
|||||||
%% API
|
%% API
|
||||||
-export([init/3]).
|
-export([init/3]).
|
||||||
|
|
||||||
|
-include("ejabberd_sql_pt.hrl").
|
||||||
|
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
%%% API
|
%%% API
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
init(_Host, _ServerHost, _Opts) ->
|
init(_Host, ServerHost, _Opts) ->
|
||||||
|
ejabberd_sql_schema:update_schema(ServerHost, ?MODULE, schemas()),
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
%%% Internal functions
|
%%% 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
|
%%% API
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
init(_Host, _Opts) ->
|
init(Host, _Opts) ->
|
||||||
|
ejabberd_sql_schema:update_schema(Host, ?MODULE, schemas()),
|
||||||
ok.
|
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) ->
|
store_session(LUser, LServer, NowTS, PushJID, Node, XData) ->
|
||||||
XML = encode_xdata(XData),
|
XML = encode_xdata(XData),
|
||||||
TS = misc:now_to_usec(NowTS),
|
TS = misc:now_to_usec(NowTS),
|
||||||
|
@ -43,9 +43,55 @@
|
|||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
%%% API
|
%%% API
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
init(_Host, _Opts) ->
|
init(Host, _Opts) ->
|
||||||
|
ejabberd_sql_schema:update_schema(Host, ?MODULE, schemas()),
|
||||||
ok.
|
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) ->
|
read_roster_version(LUser, LServer) ->
|
||||||
case ejabberd_sql:sql_query(
|
case ejabberd_sql:sql_query(
|
||||||
LServer,
|
LServer,
|
||||||
|
@ -43,9 +43,40 @@
|
|||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
%%% API
|
%%% API
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
init(_Host, _Opts) ->
|
init(Host, _Opts) ->
|
||||||
|
ejabberd_sql_schema:update_schema(Host, ?MODULE, schemas()),
|
||||||
ok.
|
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) ->
|
list_groups(Host) ->
|
||||||
case ejabberd_sql:sql_query(
|
case ejabberd_sql:sql_query(
|
||||||
Host,
|
Host,
|
||||||
|
@ -41,9 +41,79 @@
|
|||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
%%% API
|
%%% API
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
init(_Host, _Opts) ->
|
init(Host, _Opts) ->
|
||||||
|
ejabberd_sql_schema:update_schema(Host, ?MODULE, schemas()),
|
||||||
ok.
|
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) ->
|
stop(_Host) ->
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user