Small changes
This commit is contained in:
@@ -40,6 +40,7 @@ typedef enum {
|
||||
cmd_open,
|
||||
cmd_exec,
|
||||
cmd_prepare,
|
||||
cmd_bind,
|
||||
cmd_step,
|
||||
cmd_close,
|
||||
cmd_stop
|
||||
@@ -47,11 +48,12 @@ typedef enum {
|
||||
|
||||
typedef struct {
|
||||
command_type type;
|
||||
|
||||
|
||||
ErlNifEnv *env;
|
||||
ERL_NIF_TERM ref;
|
||||
ErlNifPid pid;
|
||||
ERL_NIF_TERM arg;
|
||||
sqlite3_stmt *stmt;
|
||||
} esqlite_command;
|
||||
|
||||
static ERL_NIF_TERM
|
||||
@@ -104,6 +106,7 @@ command_create()
|
||||
cmd->type = cmd_unknown;
|
||||
cmd->ref = 0;
|
||||
cmd->arg = 0;
|
||||
cmd->stmt = NULL;
|
||||
|
||||
return cmd;
|
||||
}
|
||||
@@ -159,9 +162,6 @@ do_open(ErlNifEnv *env, esqlite_connection *db, const ERL_NIF_TERM arg)
|
||||
int rc;
|
||||
ERL_NIF_TERM error;
|
||||
|
||||
if(db->db)
|
||||
return make_error_tuple(env, "database_already_open");
|
||||
|
||||
size = enif_get_string(env, arg, filename, MAX_PATHNAME, ERL_NIF_LATIN1);
|
||||
if(size <= 0)
|
||||
return make_error_tuple(env, "invalid_filename");
|
||||
@@ -202,9 +202,6 @@ do_exec(ErlNifEnv *env, esqlite_connection *conn, const ERL_NIF_TERM arg)
|
||||
ErlNifBinary bin;
|
||||
int rc;
|
||||
|
||||
if(!conn->db)
|
||||
return make_error_tuple(env, "database_not_open");
|
||||
|
||||
/* Get the query as a binary -- and the end of string -- */
|
||||
enif_inspect_iolist_as_binary(env, arg, &bin);
|
||||
|
||||
@@ -224,9 +221,6 @@ do_prepare(ErlNifEnv *env, esqlite_connection *conn, const ERL_NIF_TERM arg)
|
||||
const char *tail;
|
||||
int rc;
|
||||
|
||||
if(!conn->db)
|
||||
return make_error_tuple(env, "database_not_open");
|
||||
|
||||
/* Get the query as a binary -- and the end of string -- */
|
||||
enif_inspect_iolist_as_binary(env, arg, &bin);
|
||||
|
||||
@@ -242,7 +236,6 @@ do_prepare(ErlNifEnv *env, esqlite_connection *conn, const ERL_NIF_TERM arg)
|
||||
/* Keep a reference to the connection */
|
||||
enif_keep_resource(conn);
|
||||
stmt->connection = conn;
|
||||
stmt->statement = NULL;
|
||||
|
||||
esqlite_stmt = enif_make_resource(env, stmt);
|
||||
enif_release_resource(stmt);
|
||||
@@ -251,8 +244,17 @@ do_prepare(ErlNifEnv *env, esqlite_connection *conn, const ERL_NIF_TERM arg)
|
||||
}
|
||||
|
||||
static ERL_NIF_TERM
|
||||
do_step(ErlNifEnv *env, esqlite_connection *conn, const ERL_NIF_TERM arg)
|
||||
do_step(ErlNifEnv *env, esqlite_connection *conn, sqlite3_stmt *stmt)
|
||||
{
|
||||
int rc;
|
||||
|
||||
fprintf(stderr, "step\n");
|
||||
|
||||
rc = sqlite3_step(stmt);
|
||||
|
||||
fprintf(stderr, "step returned: %d\n", rc);
|
||||
fprintf(stderr, "nu columns: %d\n", sqlite3_column_count(stmt));
|
||||
|
||||
return _atom_ok;
|
||||
}
|
||||
|
||||
@@ -260,10 +262,7 @@ static ERL_NIF_TERM
|
||||
do_close(ErlNifEnv *env, esqlite_connection *conn, const ERL_NIF_TERM arg)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if(!conn->db)
|
||||
return make_error_tuple(env, "database_not_open");
|
||||
|
||||
|
||||
rc = sqlite3_close(conn->db);
|
||||
if(rc != SQLITE_OK)
|
||||
return make_error_tuple(env, sqlite3_errmsg(conn->db));
|
||||
@@ -273,19 +272,22 @@ do_close(ErlNifEnv *env, esqlite_connection *conn, const ERL_NIF_TERM arg)
|
||||
}
|
||||
|
||||
static ERL_NIF_TERM
|
||||
evaluate_command(ErlNifEnv *env, command_type type, esqlite_connection *db, const ERL_NIF_TERM arg)
|
||||
evaluate_command(ErlNifEnv *env, command_type type, esqlite_connection *conn, sqlite3_stmt *stmt, const ERL_NIF_TERM arg)
|
||||
{
|
||||
if(!conn->db)
|
||||
make_error_tuple(env, "database_not_open");
|
||||
|
||||
switch(type) {
|
||||
case cmd_open:
|
||||
return do_open(env, db, arg);
|
||||
return do_open(env, conn, arg);
|
||||
case cmd_exec:
|
||||
return do_exec(env, db, arg);
|
||||
return do_exec(env, conn, arg);
|
||||
case cmd_prepare:
|
||||
return do_prepare(env, db, arg);
|
||||
return do_prepare(env, conn, arg);
|
||||
case cmd_step:
|
||||
return do_step(env, db, arg);
|
||||
return do_step(env, conn, stmt);
|
||||
case cmd_close:
|
||||
return do_close(env, db, arg);
|
||||
return do_close(env, conn, arg);
|
||||
default:
|
||||
return make_error_tuple(env, "invalid_command");
|
||||
}
|
||||
@@ -308,7 +310,7 @@ esqlite_connection_run(void *arg)
|
||||
} else {
|
||||
enif_send(NULL, &cmd->pid, cmd->env,
|
||||
enif_make_tuple2(cmd->env, cmd->ref,
|
||||
evaluate_command(cmd->env, cmd->type, db, cmd->arg)));
|
||||
evaluate_command(cmd->env, cmd->type, db, cmd->stmt, cmd->arg)));
|
||||
}
|
||||
|
||||
command_destroy(cmd);
|
||||
@@ -465,6 +467,87 @@ esqlite_prepare_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
|
||||
return _atom_ok;
|
||||
}
|
||||
|
||||
/*
|
||||
* Bind a variable to a prepared statement
|
||||
*/
|
||||
static ERL_NIF_TERM
|
||||
esqlite_bind_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
|
||||
{
|
||||
esqlite_statement *stmt;
|
||||
esqlite_command *cmd = NULL;
|
||||
ErlNifPid pid;
|
||||
|
||||
if(argc != 4)
|
||||
return enif_make_badarg(env);
|
||||
if(!enif_get_resource(env, argv[0], esqlite_statement_type, (void **) &stmt))
|
||||
return enif_make_badarg(env);
|
||||
if(!enif_is_ref(env, argv[1]))
|
||||
return make_error_tuple(env, "invalid_ref");
|
||||
if(!enif_get_local_pid(env, argv[2], &pid))
|
||||
return make_error_tuple(env, "invalid_pid");
|
||||
|
||||
cmd = command_create();
|
||||
if(!cmd)
|
||||
return make_error_tuple(env, "command_create_failed");
|
||||
|
||||
cmd->type = cmd_bind;
|
||||
cmd->ref = enif_make_copy(cmd->env, argv[1]);
|
||||
cmd->pid = pid;
|
||||
cmd->arg = enif_make_copy(cmd->env, argv[3]);
|
||||
|
||||
if(!stmt->connection)
|
||||
return make_error_tuple(env, "no_connection");
|
||||
if(!stmt->connection->commands)
|
||||
return make_error_tuple(env, "no_command_queue");
|
||||
|
||||
if(!queue_push(stmt->connection->commands, cmd))
|
||||
return make_error_tuple(env, "command_push_failed");
|
||||
|
||||
return _atom_ok;
|
||||
}
|
||||
|
||||
/*
|
||||
* Step to a prepared statement
|
||||
*/
|
||||
static ERL_NIF_TERM
|
||||
esqlite_step_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
|
||||
{
|
||||
esqlite_statement *stmt;
|
||||
esqlite_command *cmd = NULL;
|
||||
ErlNifPid pid;
|
||||
|
||||
if(argc != 3)
|
||||
return enif_make_badarg(env);
|
||||
if(!enif_get_resource(env, argv[0], esqlite_statement_type, (void **) &stmt))
|
||||
return enif_make_badarg(env);
|
||||
if(!enif_is_ref(env, argv[1]))
|
||||
return make_error_tuple(env, "invalid_ref");
|
||||
if(!enif_get_local_pid(env, argv[2], &pid))
|
||||
return make_error_tuple(env, "invalid_pid");
|
||||
|
||||
if(!stmt->statement)
|
||||
return make_error_tuple(env, "no_prepared_statement");
|
||||
|
||||
cmd = command_create();
|
||||
if(!cmd)
|
||||
return make_error_tuple(env, "command_create_failed");
|
||||
|
||||
cmd->type = cmd_step;
|
||||
cmd->ref = enif_make_copy(cmd->env, argv[1]);
|
||||
cmd->pid = pid;
|
||||
cmd->stmt = stmt->statement;
|
||||
|
||||
if(!stmt->connection)
|
||||
return make_error_tuple(env, "no_connection");
|
||||
if(!stmt->connection->commands)
|
||||
return make_error_tuple(env, "no_command_queue");
|
||||
|
||||
if(!queue_push(stmt->connection->commands, cmd))
|
||||
return make_error_tuple(env, "command_push_failed");
|
||||
|
||||
return _atom_ok;
|
||||
}
|
||||
|
||||
/*
|
||||
* Close the database
|
||||
*/
|
||||
@@ -530,8 +613,9 @@ static ErlNifFunc nif_funcs[] = {
|
||||
{"esqlite_open", 4, esqlite_open_nif},
|
||||
{"esqlite_exec", 4, esqlite_exec_nif},
|
||||
{"esqlite_prepare", 4, esqlite_prepare_nif},
|
||||
//{"esqlite_bind", 3, esqlite_bind_named},
|
||||
//{"esqlite_bind", 2, esqlite_bind},
|
||||
{"esqlite_step", 3, esqlite_step_nif},
|
||||
// {"esqlite_bind", 3, esqlite_bind_named},
|
||||
// {"esqlite_bind", 2, esqlite_bind},
|
||||
{"esqlite_close", 3, esqlite_close_nif}
|
||||
};
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
-module(esqlite).
|
||||
-author("Maas-Maarten Zeeman <mmzeeman@xs4all.nl>").
|
||||
|
||||
-export([open/1, open/2, exec/2, prepare/2, prepare/3, exec/3, close/1, close/2]).
|
||||
-export([open/1, open/2, exec/2, prepare/2, prepare/3, step/1, step/2, exec/3, close/1, close/2]).
|
||||
|
||||
-on_load(init/0).
|
||||
|
||||
@@ -55,6 +55,16 @@ prepare(Db, Sql, Timeout) ->
|
||||
ok = esqlite_prepare(Db, Ref, self(), [Sql, 0]),
|
||||
receive_answer(Ref, Timeout).
|
||||
|
||||
%% @doc Step
|
||||
%%
|
||||
step(Stmt) ->
|
||||
step(Stmt, ?DEFAULT_TIMEOUT).
|
||||
|
||||
step(Stmt, Timeout) ->
|
||||
Ref = make_ref(),
|
||||
ok = esqlite_step(Stmt, Ref, self()),
|
||||
receive_answer(Ref, Timeout).
|
||||
|
||||
%% @doc Close the database
|
||||
%%
|
||||
close(Db) ->
|
||||
@@ -78,6 +88,9 @@ esqlite_exec(_Db, _Ref, _Dest, _Sql) ->
|
||||
esqlite_prepare(_Db, _Ref, _Dest, _Sql) ->
|
||||
exit(nif_library_not_loaded).
|
||||
|
||||
esqlite_step(_Stmt, _Ref, _Dest) ->
|
||||
exit(nif_library_not_loaded).
|
||||
|
||||
esqlite_close(_Db, _Ref, _Dest) ->
|
||||
exit(nif_library_not_loaded).
|
||||
|
||||
|
||||
@@ -36,7 +36,12 @@ prepare_test() ->
|
||||
{ok, Db} = esqlite:open(":memory:"),
|
||||
esqlite:exec(Db, "begin;"),
|
||||
esqlite:exec(Db, "create table test_table(one varchar(10), two int);"),
|
||||
{ok, Statement} = esqlite:prepare(Db, "insert into test_table values(:one, :two)").
|
||||
{ok, Statement} = esqlite:prepare(Db, "insert into test_table values(\"one\", 2)"),
|
||||
|
||||
esqlite:step(Statement),
|
||||
|
||||
{ok, St2} = esqlite:prepare(Db, "select * from test_table"),
|
||||
esqlite:step(St2).
|
||||
|
||||
%% esqlite:bind(Statement, ":one", "hello"),
|
||||
%% esqlite:bind(Statement, ":two", 11),
|
||||
|
||||
Reference in New Issue
Block a user