Adding column names functionality
This commit is contained in:
@@ -59,6 +59,7 @@ typedef enum {
|
|||||||
cmd_prepare,
|
cmd_prepare,
|
||||||
cmd_bind,
|
cmd_bind,
|
||||||
cmd_step,
|
cmd_step,
|
||||||
|
cmd_column_names,
|
||||||
cmd_close,
|
cmd_close,
|
||||||
cmd_stop
|
cmd_stop
|
||||||
} command_type;
|
} command_type;
|
||||||
@@ -381,6 +382,13 @@ do_step(ErlNifEnv *env, sqlite3_stmt *stmt)
|
|||||||
if(rc == SQLITE_ROW)
|
if(rc == SQLITE_ROW)
|
||||||
return make_row(env, stmt);
|
return make_row(env, stmt);
|
||||||
|
|
||||||
|
return make_error_tuple(env, "unexpected_return_value");
|
||||||
|
}
|
||||||
|
|
||||||
|
static ERL_NIF_TERM
|
||||||
|
do_column_names(ErlNifEnv *env, sqlite3_stmt *stmt)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Called column names\n");
|
||||||
return _atom_ok;
|
return _atom_ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -414,6 +422,8 @@ evaluate_command(esqlite_command *cmd, esqlite_connection *conn)
|
|||||||
return do_step(cmd->env, cmd->stmt);
|
return do_step(cmd->env, cmd->stmt);
|
||||||
case cmd_bind:
|
case cmd_bind:
|
||||||
return do_bind(cmd->env, conn->db, cmd->stmt, cmd->arg);
|
return do_bind(cmd->env, conn->db, cmd->stmt, cmd->arg);
|
||||||
|
case cmd_column_names:
|
||||||
|
return do_column_names(cmd->env, cmd->stmt);
|
||||||
case cmd_close:
|
case cmd_close:
|
||||||
return do_close(cmd->env, conn, cmd->arg);
|
return do_close(cmd->env, conn, cmd->arg);
|
||||||
default:
|
default:
|
||||||
@@ -682,6 +692,48 @@ esqlite_step(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
|
|||||||
return _atom_ok;
|
return _atom_ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Step to a prepared statement
|
||||||
|
*/
|
||||||
|
static ERL_NIF_TERM
|
||||||
|
esqlite_column_names(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_column_names;
|
||||||
|
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
|
||||||
*/
|
*/
|
||||||
@@ -750,6 +802,7 @@ static ErlNifFunc nif_funcs[] = {
|
|||||||
{"step", 3, esqlite_step},
|
{"step", 3, esqlite_step},
|
||||||
// {"esqlite_bind", 3, esqlite_bind_named},
|
// {"esqlite_bind", 3, esqlite_bind_named},
|
||||||
{"bind", 4, esqlite_bind},
|
{"bind", 4, esqlite_bind},
|
||||||
|
{"column_names", 3, esqlite_column_names},
|
||||||
{"close", 3, esqlite_close}
|
{"close", 3, esqlite_close}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -71,7 +71,8 @@ foreach(F, Sql, Connection) ->
|
|||||||
%%
|
%%
|
||||||
foreach_s(F, Statement) ->
|
foreach_s(F, Statement) ->
|
||||||
case try_step(Statement, 0) of
|
case try_step(Statement, 0) of
|
||||||
'$done' -> ok;
|
'$done' ->
|
||||||
|
ok;
|
||||||
Row when is_tuple(Row) ->
|
Row when is_tuple(Row) ->
|
||||||
F(Row),
|
F(Row),
|
||||||
foreach_s(F, Statement)
|
foreach_s(F, Statement)
|
||||||
@@ -82,7 +83,7 @@ map_s(F, Statement) ->
|
|||||||
case try_step(Statement, 0) of
|
case try_step(Statement, 0) of
|
||||||
'$done' ->
|
'$done' ->
|
||||||
[];
|
[];
|
||||||
Row ->
|
Row when is_tuple(Row) ->
|
||||||
[F(Row) | map_s(F, Statement)]
|
[F(Row) | map_s(F, Statement)]
|
||||||
end.
|
end.
|
||||||
|
|
||||||
@@ -95,11 +96,13 @@ do_steps(Statement) ->
|
|||||||
[Row | do_steps(Statement)]
|
[Row | do_steps(Statement)]
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
%% Try the step, when the database is busy,
|
||||||
try_step(_Statement, Tries) when Tries > 5 ->
|
try_step(_Statement, Tries) when Tries > 5 ->
|
||||||
throw(too_many_tries);
|
throw(too_many_tries);
|
||||||
try_step(Statement, Tries) ->
|
try_step(Statement, Tries) ->
|
||||||
case esqlite3:step(Statement) of
|
case esqlite3:step(Statement) of
|
||||||
'$busy' ->
|
'$busy' ->
|
||||||
|
timer:sleep(100 * Tries),
|
||||||
try_step(Statement, Tries + 1);
|
try_step(Statement, Tries + 1);
|
||||||
Something ->
|
Something ->
|
||||||
Something
|
Something
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
prepare/4,
|
prepare/4,
|
||||||
step/3,
|
step/3,
|
||||||
bind/4,
|
bind/4,
|
||||||
|
column_names/3,
|
||||||
close/3
|
close/3
|
||||||
]).
|
]).
|
||||||
|
|
||||||
@@ -70,16 +71,22 @@ prepare(_Db, _Ref, _Dest, _Sql) ->
|
|||||||
|
|
||||||
%% @doc
|
%% @doc
|
||||||
%%
|
%%
|
||||||
%% @spec step(connection(), reference(), pid()) -> ok | {error, message()}
|
%% @spec step(statement(), reference(), pid()) -> ok | {error, message()}
|
||||||
step(_Stmt, _Ref, _Dest) ->
|
step(_Stmt, _Ref, _Dest) ->
|
||||||
exit(nif_library_not_loaded).
|
exit(nif_library_not_loaded).
|
||||||
|
|
||||||
%% @doc Bind parameters to a prepared statement.
|
%% @doc Bind parameters to a prepared statement.
|
||||||
%%
|
%%
|
||||||
%% @spec bind(connection(), reference(), pid(), []) -> ok | {error, message()}
|
%% @spec bind(statement(), reference(), pid(), []) -> ok | {error, message()}
|
||||||
bind(_Stmt, _Ref, _Dest, _Args) ->
|
bind(_Stmt, _Ref, _Dest, _Args) ->
|
||||||
exit(nif_library_not_loaded).
|
exit(nif_library_not_loaded).
|
||||||
|
|
||||||
|
%% @doc Retrieve the column names of the prepared statement
|
||||||
|
%%
|
||||||
|
%% @spec column_names(statement(), reference(), pid()) -> {ok, tuple()} | {error, message()}
|
||||||
|
column_names(_Stmt, _Ref, _Dest) ->
|
||||||
|
exit(nif_library_not_loaded).
|
||||||
|
|
||||||
%% @doc Close the connection.
|
%% @doc Close the connection.
|
||||||
%%
|
%%
|
||||||
%% @spec close(connection(), reference(), pid()) -> ok | {error, message()}
|
%% @spec close(connection(), reference(), pid()) -> ok | {error, message()}
|
||||||
|
|||||||
@@ -74,6 +74,21 @@ bind_test() ->
|
|||||||
|
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
|
column_names_test() ->
|
||||||
|
{ok, Db} = esqlite3:open(":memory:"),
|
||||||
|
ok = esqlite3:exec("begin;", Db),
|
||||||
|
ok = esqlite3:exec("create table test_table(one varchar(10), two int);", Db),
|
||||||
|
ok = esqlite3:exec(["insert into test_table values(", "\"hello1\"", ",", "10" ");"], Db),
|
||||||
|
ok = esqlite3:exec("commit;", Db),
|
||||||
|
|
||||||
|
{ok, Stmt} = esqlite3:prepare("select * from test_table", Db),
|
||||||
|
|
||||||
|
test = esqlite3:column_names(Stmt),
|
||||||
|
|
||||||
|
ok.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
foreach_test() ->
|
foreach_test() ->
|
||||||
{ok, Db} = esqlite3:open(":memory:"),
|
{ok, Db} = esqlite3:open(":memory:"),
|
||||||
ok = esqlite3:exec("begin;", Db),
|
ok = esqlite3:exec("begin;", Db),
|
||||||
@@ -93,7 +108,7 @@ foreach_test() ->
|
|||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
|
|
||||||
esqlite3:foreach(F, "select * from test_table", Db),
|
esqlite3:foreach(F, "select * from test_table;", Db),
|
||||||
|
|
||||||
10 = get("hello1"),
|
10 = get("hello1"),
|
||||||
11 = get("hello2"),
|
11 = get("hello2"),
|
||||||
|
|||||||
Reference in New Issue
Block a user