Small changes

This commit is contained in:
Maas-Maarten Zeeman
2011-10-26 00:59:27 +02:00
parent f21f022eb7
commit e7089bc099
3 changed files with 129 additions and 27 deletions

View File

@@ -40,6 +40,7 @@ typedef enum {
cmd_open, cmd_open,
cmd_exec, cmd_exec,
cmd_prepare, cmd_prepare,
cmd_bind,
cmd_step, cmd_step,
cmd_close, cmd_close,
cmd_stop cmd_stop
@@ -52,6 +53,7 @@ typedef struct {
ERL_NIF_TERM ref; ERL_NIF_TERM ref;
ErlNifPid pid; ErlNifPid pid;
ERL_NIF_TERM arg; ERL_NIF_TERM arg;
sqlite3_stmt *stmt;
} esqlite_command; } esqlite_command;
static ERL_NIF_TERM static ERL_NIF_TERM
@@ -104,6 +106,7 @@ command_create()
cmd->type = cmd_unknown; cmd->type = cmd_unknown;
cmd->ref = 0; cmd->ref = 0;
cmd->arg = 0; cmd->arg = 0;
cmd->stmt = NULL;
return cmd; return cmd;
} }
@@ -159,9 +162,6 @@ do_open(ErlNifEnv *env, esqlite_connection *db, const ERL_NIF_TERM arg)
int rc; int rc;
ERL_NIF_TERM error; 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); size = enif_get_string(env, arg, filename, MAX_PATHNAME, ERL_NIF_LATIN1);
if(size <= 0) if(size <= 0)
return make_error_tuple(env, "invalid_filename"); 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; ErlNifBinary bin;
int rc; int rc;
if(!conn->db)
return make_error_tuple(env, "database_not_open");
/* Get the query as a binary -- and the end of string -- */ /* Get the query as a binary -- and the end of string -- */
enif_inspect_iolist_as_binary(env, arg, &bin); 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; const char *tail;
int rc; int rc;
if(!conn->db)
return make_error_tuple(env, "database_not_open");
/* Get the query as a binary -- and the end of string -- */ /* Get the query as a binary -- and the end of string -- */
enif_inspect_iolist_as_binary(env, arg, &bin); 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 */ /* Keep a reference to the connection */
enif_keep_resource(conn); enif_keep_resource(conn);
stmt->connection = conn; stmt->connection = conn;
stmt->statement = NULL;
esqlite_stmt = enif_make_resource(env, stmt); esqlite_stmt = enif_make_resource(env, stmt);
enif_release_resource(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 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; return _atom_ok;
} }
@@ -261,9 +263,6 @@ do_close(ErlNifEnv *env, esqlite_connection *conn, const ERL_NIF_TERM arg)
{ {
int rc; int rc;
if(!conn->db)
return make_error_tuple(env, "database_not_open");
rc = sqlite3_close(conn->db); rc = sqlite3_close(conn->db);
if(rc != SQLITE_OK) if(rc != SQLITE_OK)
return make_error_tuple(env, sqlite3_errmsg(conn->db)); 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 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) { switch(type) {
case cmd_open: case cmd_open:
return do_open(env, db, arg); return do_open(env, conn, arg);
case cmd_exec: case cmd_exec:
return do_exec(env, db, arg); return do_exec(env, conn, arg);
case cmd_prepare: case cmd_prepare:
return do_prepare(env, db, arg); return do_prepare(env, conn, arg);
case cmd_step: case cmd_step:
return do_step(env, db, arg); return do_step(env, conn, stmt);
case cmd_close: case cmd_close:
return do_close(env, db, arg); return do_close(env, conn, arg);
default: default:
return make_error_tuple(env, "invalid_command"); return make_error_tuple(env, "invalid_command");
} }
@@ -308,7 +310,7 @@ esqlite_connection_run(void *arg)
} else { } else {
enif_send(NULL, &cmd->pid, cmd->env, enif_send(NULL, &cmd->pid, cmd->env,
enif_make_tuple2(cmd->env, cmd->ref, 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); command_destroy(cmd);
@@ -465,6 +467,87 @@ esqlite_prepare_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
return _atom_ok; 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 * Close the database
*/ */
@@ -530,6 +613,7 @@ static ErlNifFunc nif_funcs[] = {
{"esqlite_open", 4, esqlite_open_nif}, {"esqlite_open", 4, esqlite_open_nif},
{"esqlite_exec", 4, esqlite_exec_nif}, {"esqlite_exec", 4, esqlite_exec_nif},
{"esqlite_prepare", 4, esqlite_prepare_nif}, {"esqlite_prepare", 4, esqlite_prepare_nif},
{"esqlite_step", 3, esqlite_step_nif},
// {"esqlite_bind", 3, esqlite_bind_named}, // {"esqlite_bind", 3, esqlite_bind_named},
// {"esqlite_bind", 2, esqlite_bind}, // {"esqlite_bind", 2, esqlite_bind},
{"esqlite_close", 3, esqlite_close_nif} {"esqlite_close", 3, esqlite_close_nif}

View File

@@ -5,7 +5,7 @@
-module(esqlite). -module(esqlite).
-author("Maas-Maarten Zeeman <mmzeeman@xs4all.nl>"). -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). -on_load(init/0).
@@ -55,6 +55,16 @@ prepare(Db, Sql, Timeout) ->
ok = esqlite_prepare(Db, Ref, self(), [Sql, 0]), ok = esqlite_prepare(Db, Ref, self(), [Sql, 0]),
receive_answer(Ref, Timeout). 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 %% @doc Close the database
%% %%
close(Db) -> close(Db) ->
@@ -78,6 +88,9 @@ esqlite_exec(_Db, _Ref, _Dest, _Sql) ->
esqlite_prepare(_Db, _Ref, _Dest, _Sql) -> esqlite_prepare(_Db, _Ref, _Dest, _Sql) ->
exit(nif_library_not_loaded). exit(nif_library_not_loaded).
esqlite_step(_Stmt, _Ref, _Dest) ->
exit(nif_library_not_loaded).
esqlite_close(_Db, _Ref, _Dest) -> esqlite_close(_Db, _Ref, _Dest) ->
exit(nif_library_not_loaded). exit(nif_library_not_loaded).

View File

@@ -36,7 +36,12 @@ prepare_test() ->
{ok, Db} = esqlite:open(":memory:"), {ok, Db} = esqlite:open(":memory:"),
esqlite:exec(Db, "begin;"), esqlite:exec(Db, "begin;"),
esqlite:exec(Db, "create table test_table(one varchar(10), two int);"), 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, ":one", "hello"),
%% esqlite:bind(Statement, ":two", 11), %% esqlite:bind(Statement, ":two", 11),