freetds_config/0,
odbcinst_config/0,
init_mssql/1,
- keep_alive/1]).
+ keep_alive/2]).
%% gen_fsm callbacks
-export([init/1, handle_event/3, handle_sync_event/4,
-define(MAX_TRANSACTION_RESTARTS, 10).
--define(TRANSACTION_TIMEOUT, 60000).
-
--define(KEEPALIVE_TIMEOUT, 60000).
-
-define(KEEPALIVE_QUERY, [<<"SELECT 1;">>]).
-define(PREPARE_KEY, ejabberd_sql_prepare).
Pid ->
(?GEN_FSM):sync_send_event(Pid,{sql_cmd, Msg,
p1_time_compat:monotonic_time(milli_seconds)},
- ?TRANSACTION_TIMEOUT)
+ query_timeout(Host))
end;
_State -> nested_op(Msg)
end.
-keep_alive(PID) ->
+keep_alive(Host, PID) ->
(?GEN_FSM):sync_send_event(PID,
{sql_cmd, {sql_query, ?KEEPALIVE_QUERY},
p1_time_compat:monotonic_time(milli_seconds)},
- ?KEEPALIVE_TIMEOUT).
+ query_timeout(Host)).
-spec sql_query_t(sql_query()) -> sql_query_result().
ok;
KeepaliveInterval ->
timer:apply_interval(KeepaliveInterval * 1000, ?MODULE,
- keep_alive, [self()])
+ keep_alive, [Host, self()])
end,
[DBType | _] = db_opts(Host),
(?GEN_FSM):send_event(self(), connect),
%%%----------------------------------------------------------------------
run_sql_cmd(Command, From, State, Timestamp) ->
+ QueryTimeout = query_timeout(State#state.host),
case p1_time_compat:monotonic_time(milli_seconds) - Timestamp of
- Age when Age < (?TRANSACTION_TIMEOUT) ->
+ Age when Age < QueryTimeout ->
put(?NESTING_KEY, ?TOP_LEVEL_TXN),
put(?STATE_KEY, State),
abort_on_driver_error(outer_op(Command), From);
sql_query_internal(Query) ->
State = get(?STATE_KEY),
?DEBUG("SQL: \"~s\"", [Query]),
+ QueryTimeout = query_timeout(State#state.host),
Res = case State#state.db_type of
odbc ->
to_odbc(odbc:sql_query(State#state.db_ref, [Query],
- (?TRANSACTION_TIMEOUT) - 1000));
+ QueryTimeout - 1000));
mssql ->
to_odbc(odbc:sql_query(State#state.db_ref, [Query],
- (?TRANSACTION_TIMEOUT) - 1000));
+ QueryTimeout - 1000));
pgsql ->
pgsql_to_odbc(pgsql:squery(State#state.db_ref, Query,
- (?TRANSACTION_TIMEOUT) - 1000));
+ QueryTimeout - 1000));
mysql ->
R = mysql_to_odbc(p1_mysql_conn:squery(State#state.db_ref,
[Query], self(),
- [{timeout, (?TRANSACTION_TIMEOUT) - 1000},
+ [{timeout, QueryTimeout - 1000},
{result_type, binary}])),
%% ?INFO_MSG("MySQL, Received result~n~p~n", [R]),
R;
fsm_limit_opts() ->
ejabberd_config:fsm_limit_opts([]).
+query_timeout(LServer) ->
+ timer:seconds(
+ ejabberd_config:get_option({sql_query_timeout, LServer}, 60)).
+
check_error({error, Why} = Err, #sql_query{} = Query) ->
?ERROR_MSG("SQL query '~s' at ~p failed: ~p",
[Query#sql_query.hash, Query#sql_query.loc, Why]),
opt_type(sql_ssl_verify) -> fun(B) when is_boolean(B) -> B end;
opt_type(sql_ssl_certfile) -> fun iolist_to_binary/1;
opt_type(sql_ssl_cafile) -> fun iolist_to_binary/1;
+opt_type(sql_query_timeout) ->
+ fun (I) when is_integer(I), I > 0 -> I end;
opt_type(sql_queue_type) ->
fun(ram) -> ram; (file) -> file end;
opt_type(_) ->
[sql_database, sql_keepalive_interval,
sql_password, sql_port, sql_server,
sql_username, sql_ssl, sql_ssl_verify, sql_ssl_cerfile,
- sql_ssl_cafile, sql_queue_type].
+ sql_ssl_cafile, sql_queue_type, sql_query_timeout].