Small changes
This commit is contained in:
@@ -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}
|
||||||
|
|||||||
@@ -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).
|
||||||
|
|
||||||
|
|||||||
@@ -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),
|
||||||
|
|||||||
Reference in New Issue
Block a user