Improved initial connection check
This commit is contained in:
@@ -124,6 +124,68 @@ static inline unsigned int sql_async_key(char *db_name, ErlDrvPort port) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int return_error(
|
||||||
|
sqlite3_drv_t *drv, int error_code, const char *error,
|
||||||
|
ErlDrvTermData **dataset_p, int *term_count_p, int *term_allocated_p,
|
||||||
|
int* error_code_p) {
|
||||||
|
if (error_code_p) {
|
||||||
|
*error_code_p = error_code;
|
||||||
|
}
|
||||||
|
EXTEND_DATASET_PTR(9);
|
||||||
|
append_to_dataset(9, *dataset_p, *term_count_p,
|
||||||
|
ERL_DRV_ATOM, drv->atom_error,
|
||||||
|
ERL_DRV_INT, (ErlDrvTermData) error_code,
|
||||||
|
ERL_DRV_STRING, (ErlDrvTermData) error, (ErlDrvTermData) strlen(error),
|
||||||
|
ERL_DRV_TUPLE, (ErlDrvTermData) 3);
|
||||||
|
// int i;
|
||||||
|
// for (i = 0; i < *term_count_p; i++) {
|
||||||
|
// printf("%d\n", (*dataset_p)[i]);
|
||||||
|
// }
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int output_error(
|
||||||
|
sqlite3_drv_t *drv, int error_code, const char *error) {
|
||||||
|
int term_count = 2, term_allocated = 13;
|
||||||
|
// for some reason breaks if allocated as an array on stack
|
||||||
|
// even though it shouldn't be extended
|
||||||
|
ErlDrvTermData *dataset = driver_alloc(sizeof(ErlDrvTermData) * term_allocated);
|
||||||
|
dataset[0] = ERL_DRV_PORT;
|
||||||
|
dataset[1] = driver_mk_port(drv->port);
|
||||||
|
return_error(drv, error_code, error, &dataset, &term_count, &term_allocated, NULL);
|
||||||
|
term_count += 2;
|
||||||
|
dataset[11] = ERL_DRV_TUPLE;
|
||||||
|
dataset[12] = 2;
|
||||||
|
#ifdef PRE_R16B
|
||||||
|
driver_output_term(drv->port,
|
||||||
|
#else
|
||||||
|
erl_drv_output_term(dataset[1],
|
||||||
|
#endif
|
||||||
|
dataset, term_count);
|
||||||
|
driver_free(dataset);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int output_db_error(sqlite3_drv_t *drv) {
|
||||||
|
return output_error(drv, sqlite3_errcode(drv->db), sqlite3_errmsg(drv->db));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int output_ok(sqlite3_drv_t *drv) {
|
||||||
|
// Return {Port, ok}
|
||||||
|
ErlDrvTermData spec[] = {
|
||||||
|
ERL_DRV_PORT, driver_mk_port(drv->port),
|
||||||
|
ERL_DRV_ATOM, drv->atom_ok,
|
||||||
|
ERL_DRV_TUPLE, 2
|
||||||
|
};
|
||||||
|
return
|
||||||
|
#ifdef PRE_R16B
|
||||||
|
driver_output_term(drv->port,
|
||||||
|
#else
|
||||||
|
erl_drv_output_term(spec[1],
|
||||||
|
#endif
|
||||||
|
spec, sizeof(spec) / sizeof(spec[0]));
|
||||||
|
}
|
||||||
|
|
||||||
static ErlDrvEntry sqlite3_driver_entry = {
|
static ErlDrvEntry sqlite3_driver_entry = {
|
||||||
NULL, /* init */
|
NULL, /* init */
|
||||||
start, /* startup (defined below) */
|
start, /* startup (defined below) */
|
||||||
@@ -196,16 +258,6 @@ static ErlDrvData start(ErlDrvPort port, char* cmd) {
|
|||||||
|
|
||||||
// Create and open the database
|
// Create and open the database
|
||||||
status = sqlite3_open(db_name, &db);
|
status = sqlite3_open(db_name, &db);
|
||||||
|
|
||||||
if (status != SQLITE_OK) {
|
|
||||||
LOG_ERROR("Unable to open file: %s because %s\n\n", db_name, sqlite3_errmsg(db));
|
|
||||||
// We don't do this because there's no way to pass the error to Erlang
|
|
||||||
// sqlite3_close(db);
|
|
||||||
// driver_free(drv);
|
|
||||||
// return ERL_DRV_ERROR_GENERAL;
|
|
||||||
} else {
|
|
||||||
LOG_DEBUG("Opened file %s\n", db_name);
|
|
||||||
}
|
|
||||||
#if defined(_MSC_VER)
|
#if defined(_MSC_VER)
|
||||||
#pragma warning(default: 4306)
|
#pragma warning(default: 4306)
|
||||||
#endif
|
#endif
|
||||||
@@ -232,6 +284,14 @@ static ErlDrvData start(ErlDrvPort port, char* cmd) {
|
|||||||
drv->atom_done = driver_mk_atom("done");
|
drv->atom_done = driver_mk_atom("done");
|
||||||
drv->atom_unknown_cmd = driver_mk_atom("unknown_command");
|
drv->atom_unknown_cmd = driver_mk_atom("unknown_command");
|
||||||
|
|
||||||
|
if (status != SQLITE_OK) {
|
||||||
|
LOG_ERROR("Unable to open file %s: \"%s\"\n\n", db_name, sqlite3_errmsg(db));
|
||||||
|
output_db_error(drv);
|
||||||
|
} else {
|
||||||
|
LOG_DEBUG("Opened file %s\n", db_name);
|
||||||
|
output_ok(drv);
|
||||||
|
}
|
||||||
|
|
||||||
return (ErlDrvData) drv;
|
return (ErlDrvData) drv;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -261,8 +321,6 @@ static void stop(ErlDrvData handle) {
|
|||||||
driver_free(drv);
|
driver_free(drv);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int output_error(sqlite3_drv_t *drv, int error_code, const char *error);
|
|
||||||
|
|
||||||
// Handle input from Erlang VM
|
// Handle input from Erlang VM
|
||||||
static ErlDrvSSizeT control(
|
static ErlDrvSSizeT control(
|
||||||
ErlDrvData drv_data, unsigned int command, char *buf,
|
ErlDrvData drv_data, unsigned int command, char *buf,
|
||||||
@@ -312,68 +370,6 @@ static ErlDrvSSizeT control(
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int return_error(
|
|
||||||
sqlite3_drv_t *drv, int error_code, const char *error,
|
|
||||||
ErlDrvTermData **dataset_p, int *term_count_p, int *term_allocated_p,
|
|
||||||
int* error_code_p) {
|
|
||||||
if (error_code_p) {
|
|
||||||
*error_code_p = error_code;
|
|
||||||
}
|
|
||||||
EXTEND_DATASET_PTR(9);
|
|
||||||
append_to_dataset(9, *dataset_p, *term_count_p,
|
|
||||||
ERL_DRV_ATOM, drv->atom_error,
|
|
||||||
ERL_DRV_INT, (ErlDrvTermData) error_code,
|
|
||||||
ERL_DRV_STRING, (ErlDrvTermData) error, (ErlDrvTermData) strlen(error),
|
|
||||||
ERL_DRV_TUPLE, (ErlDrvTermData) 3);
|
|
||||||
// int i;
|
|
||||||
// for (i = 0; i < *term_count_p; i++) {
|
|
||||||
// printf("%d\n", (*dataset_p)[i]);
|
|
||||||
// }
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int output_error(
|
|
||||||
sqlite3_drv_t *drv, int error_code, const char *error) {
|
|
||||||
int term_count = 2, term_allocated = 13;
|
|
||||||
// for some reason breaks if allocated as an array on stack
|
|
||||||
// even though it shouldn't be extended
|
|
||||||
ErlDrvTermData *dataset = driver_alloc(sizeof(ErlDrvTermData) * term_allocated);
|
|
||||||
dataset[0] = ERL_DRV_PORT;
|
|
||||||
dataset[1] = driver_mk_port(drv->port);
|
|
||||||
return_error(drv, error_code, error, &dataset, &term_count, &term_allocated, NULL);
|
|
||||||
term_count += 2;
|
|
||||||
dataset[11] = ERL_DRV_TUPLE;
|
|
||||||
dataset[12] = 2;
|
|
||||||
#ifdef PRE_R16B
|
|
||||||
driver_output_term(drv->port,
|
|
||||||
#else
|
|
||||||
erl_drv_output_term(dataset[1],
|
|
||||||
#endif
|
|
||||||
dataset, term_count);
|
|
||||||
driver_free(dataset);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int output_db_error(sqlite3_drv_t *drv) {
|
|
||||||
return output_error(drv, sqlite3_errcode(drv->db), sqlite3_errmsg(drv->db));
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int output_ok(sqlite3_drv_t *drv) {
|
|
||||||
// Return {Port, ok}
|
|
||||||
ErlDrvTermData spec[] = {
|
|
||||||
ERL_DRV_PORT, driver_mk_port(drv->port),
|
|
||||||
ERL_DRV_ATOM, drv->atom_ok,
|
|
||||||
ERL_DRV_TUPLE, 2
|
|
||||||
};
|
|
||||||
return
|
|
||||||
#ifdef PRE_R16B
|
|
||||||
driver_output_term(drv->port,
|
|
||||||
#else
|
|
||||||
erl_drv_output_term(spec[1],
|
|
||||||
#endif
|
|
||||||
spec, sizeof(spec) / sizeof(spec[0]));
|
|
||||||
}
|
|
||||||
|
|
||||||
static int enable_load_extension(sqlite3_drv_t* drv, char *buf, int len) {
|
static int enable_load_extension(sqlite3_drv_t* drv, char *buf, int len) {
|
||||||
#ifdef ERLANG_SQLITE3_LOAD_EXTENSION
|
#ifdef ERLANG_SQLITE3_LOAD_EXTENSION
|
||||||
char enable = buf[0];
|
char enable = buf[0];
|
||||||
|
|||||||
@@ -778,21 +778,31 @@ value_to_sql(X) -> sqlite3_lib:value_to_sql(X).
|
|||||||
|
|
||||||
-spec init([any()]) -> {'ok', #state{}} | {'stop', string()}.
|
-spec init([any()]) -> {'ok', #state{}} | {'stop', string()}.
|
||||||
init(Options) ->
|
init(Options) ->
|
||||||
DbFile = proplists:get_value(file, Options),
|
|
||||||
PrivDir = get_priv_dir(),
|
PrivDir = get_priv_dir(),
|
||||||
case erl_ddll:load(PrivDir, atom_to_list(?DRIVER_NAME)) of
|
case erl_ddll:load(PrivDir, atom_to_list(?DRIVER_NAME)) of
|
||||||
ok ->
|
ok ->
|
||||||
Port = open_port({spawn, create_port_cmd(DbFile)}, [binary]),
|
do_init(Options);
|
||||||
{ok, #state{port = Port, ops = Options}};
|
|
||||||
{error, permanent} -> %% already loaded!
|
{error, permanent} -> %% already loaded!
|
||||||
Port = open_port({spawn, create_port_cmd(DbFile)}, [binary]),
|
do_init(Options);
|
||||||
{ok, #state{port = Port, ops = Options}};
|
|
||||||
{error, Error} ->
|
{error, Error} ->
|
||||||
Msg = io_lib:format("Error loading ~p: ~s",
|
Msg = io_lib:format("Error loading ~p: ~s",
|
||||||
[?DRIVER_NAME, erl_ddll:format_error(Error)]),
|
[?DRIVER_NAME, erl_ddll:format_error(Error)]),
|
||||||
{stop, lists:flatten(Msg)}
|
{stop, lists:flatten(Msg)}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
-spec do_init([any()]) -> {'ok', #state{}} | {'stop', string()}.
|
||||||
|
do_init(Options) ->
|
||||||
|
DbFile = proplists:get_value(file, Options),
|
||||||
|
Port = open_port({spawn, create_port_cmd(DbFile)}, [binary]),
|
||||||
|
receive
|
||||||
|
{Port, ok} ->
|
||||||
|
{ok, #state{port = Port, ops = Options}};
|
||||||
|
{Port, {error, Code, Message}} ->
|
||||||
|
Msg = io_lib:format("Error opening DB file ~p: code ~B, message '~s'",
|
||||||
|
[DbFile, Code, Message]),
|
||||||
|
{stop, lists:flatten(Msg)}
|
||||||
|
end.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% @doc Handling call messages
|
%% @doc Handling call messages
|
||||||
%% @end
|
%% @end
|
||||||
|
|||||||
@@ -344,6 +344,16 @@ issue23() ->
|
|||||||
?assertEqual([SingleStmtResult, SingleStmtResult], ScriptResult),
|
?assertEqual([SingleStmtResult, SingleStmtResult], ScriptResult),
|
||||||
sqlite3:close(issue23).
|
sqlite3:close(issue23).
|
||||||
|
|
||||||
|
non_db_file_test() ->
|
||||||
|
process_flag(trap_exit, true),
|
||||||
|
?assertMatch({error, _},
|
||||||
|
sqlite3:start_link(bad_file, [{file, "/"}])),
|
||||||
|
receive
|
||||||
|
{'EXIT', _, _} -> ok;
|
||||||
|
_ -> ?assert(false)
|
||||||
|
end.
|
||||||
|
|
||||||
|
|
||||||
% create, read, update, delete
|
% create, read, update, delete
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
%% Internal functions
|
%% Internal functions
|
||||||
|
|||||||
Reference in New Issue
Block a user