Skip to content

Commit e1f7d87

Browse files
committed
add individual binds
1 parent 6edec07 commit e1f7d87

File tree

4 files changed

+444
-0
lines changed

4 files changed

+444
-0
lines changed

c_src/sqlite3_nif.c

+175
Original file line numberDiff line numberDiff line change
@@ -638,6 +638,135 @@ exqlite_bind(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
638638
return make_atom(env, "ok");
639639
}
640640

641+
static ERL_NIF_TERM
642+
exqlite_bind_text(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
643+
{
644+
assert(argc == 3);
645+
646+
statement_t* statement;
647+
if (!enif_get_resource(env, argv[0], statement_type, (void**)&statement)) {
648+
ERL_NIF_TERM badarg = enif_make_tuple2(env, make_atom(env, "badarg"), argv[0]);
649+
return enif_raise_exception(env, badarg);
650+
}
651+
652+
unsigned int idx;
653+
if (!enif_get_uint(env, argv[1], &idx)) {
654+
ERL_NIF_TERM badarg = enif_make_tuple2(env, make_atom(env, "badarg"), argv[1]);
655+
return enif_raise_exception(env, badarg);
656+
}
657+
658+
ErlNifBinary text;
659+
if (!enif_inspect_binary(env, argv[2], &text)) {
660+
ERL_NIF_TERM badarg = enif_make_tuple2(env, make_atom(env, "badarg"), argv[2]);
661+
return enif_raise_exception(env, badarg);
662+
}
663+
664+
int rc = sqlite3_bind_text(statement->statement, idx, (char*)text.data, text.size, SQLITE_TRANSIENT);
665+
return enif_make_int(env, rc);
666+
}
667+
668+
static ERL_NIF_TERM
669+
exqlite_bind_blob(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
670+
{
671+
assert(argc == 3);
672+
673+
statement_t* statement;
674+
if (!enif_get_resource(env, argv[0], statement_type, (void**)&statement)) {
675+
ERL_NIF_TERM badarg = enif_make_tuple2(env, make_atom(env, "badarg"), argv[0]);
676+
return enif_raise_exception(env, badarg);
677+
}
678+
679+
unsigned int idx;
680+
if (!enif_get_uint(env, argv[1], &idx)) {
681+
ERL_NIF_TERM badarg = enif_make_tuple2(env, make_atom(env, "badarg"), argv[1]);
682+
return enif_raise_exception(env, badarg);
683+
}
684+
685+
ErlNifBinary blob;
686+
if (!enif_inspect_binary(env, argv[2], &blob)) {
687+
ERL_NIF_TERM badarg = enif_make_tuple2(env, make_atom(env, "badarg"), argv[2]);
688+
return enif_raise_exception(env, badarg);
689+
}
690+
691+
int rc = sqlite3_bind_blob(statement->statement, idx, (char*)blob.data, blob.size, SQLITE_TRANSIENT);
692+
return enif_make_int(env, rc);
693+
}
694+
695+
static ERL_NIF_TERM
696+
exqlite_bind_integer(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
697+
{
698+
assert(argc == 3);
699+
700+
statement_t* statement;
701+
if (!enif_get_resource(env, argv[0], statement_type, (void**)&statement)) {
702+
ERL_NIF_TERM badarg = enif_make_tuple2(env, make_atom(env, "badarg"), argv[0]);
703+
return enif_raise_exception(env, badarg);
704+
}
705+
706+
unsigned int idx;
707+
if (!enif_get_uint(env, argv[1], &idx)) {
708+
ERL_NIF_TERM badarg = enif_make_tuple2(env, make_atom(env, "badarg"), argv[1]);
709+
return enif_raise_exception(env, badarg);
710+
}
711+
712+
ErlNifSInt64 i;
713+
if (!enif_get_int64(env, argv[2], &i)) {
714+
ERL_NIF_TERM badarg = enif_make_tuple2(env, make_atom(env, "badarg"), argv[2]);
715+
return enif_raise_exception(env, badarg);
716+
}
717+
718+
int rc = sqlite3_bind_int64(statement->statement, idx, i);
719+
return enif_make_int(env, rc);
720+
}
721+
722+
static ERL_NIF_TERM
723+
exqlite_bind_float(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
724+
{
725+
assert(argc == 3);
726+
727+
statement_t* statement;
728+
if (!enif_get_resource(env, argv[0], statement_type, (void**)&statement)) {
729+
ERL_NIF_TERM badarg = enif_make_tuple2(env, make_atom(env, "badarg"), argv[0]);
730+
return enif_raise_exception(env, badarg);
731+
}
732+
733+
unsigned int idx;
734+
if (!enif_get_uint(env, argv[1], &idx)) {
735+
ERL_NIF_TERM badarg = enif_make_tuple2(env, make_atom(env, "badarg"), argv[1]);
736+
return enif_raise_exception(env, badarg);
737+
}
738+
739+
double f;
740+
if (!enif_get_double(env, argv[2], &f)) {
741+
ERL_NIF_TERM badarg = enif_make_tuple2(env, make_atom(env, "badarg"), argv[2]);
742+
return enif_raise_exception(env, badarg);
743+
}
744+
745+
int rc = sqlite3_bind_double(statement->statement, idx, f);
746+
return enif_make_int(env, rc);
747+
}
748+
749+
static ERL_NIF_TERM
750+
exqlite_bind_null(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
751+
{
752+
assert(argc == 2);
753+
754+
statement_t* statement;
755+
if (!enif_get_resource(env, argv[0], statement_type, (void**)&statement)) {
756+
ERL_NIF_TERM badarg = enif_make_tuple2(env, make_atom(env, "badarg"), argv[0]);
757+
return enif_raise_exception(env, badarg);
758+
}
759+
760+
unsigned int idx;
761+
if (!enif_get_uint(env, argv[1], &idx)) {
762+
ERL_NIF_TERM badarg = enif_make_tuple2(env, make_atom(env, "badarg"), argv[1]);
763+
return enif_raise_exception(env, badarg);
764+
}
765+
766+
int rc = sqlite3_bind_null(statement->statement, idx);
767+
return enif_make_int(env, rc);
768+
}
769+
641770
static ERL_NIF_TERM
642771
make_cell(ErlNifEnv* env, sqlite3_stmt* statement, unsigned int i)
643772
{
@@ -1272,6 +1401,45 @@ exqlite_interrupt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
12721401
return make_atom(env, "ok");
12731402
}
12741403

1404+
static ERL_NIF_TERM
1405+
exqlite_errmsg(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
1406+
{
1407+
assert(argc == 1);
1408+
1409+
connection_t* conn;
1410+
statement_t* statement;
1411+
const char* msg;
1412+
1413+
if (enif_get_resource(env, argv[0], connection_type, (void**)&conn)) {
1414+
msg = sqlite3_errmsg(conn->db);
1415+
} else if (enif_get_resource(env, argv[0], statement_type, (void**)&statement)) {
1416+
msg = sqlite3_errmsg(sqlite3_db_handle(statement->statement));
1417+
} else {
1418+
ERL_NIF_TERM badarg = enif_make_tuple2(env, make_atom(env, "badarg"), argv[0]);
1419+
return enif_raise_exception(env, badarg);
1420+
}
1421+
1422+
if (!msg)
1423+
return make_atom(env, "nil");
1424+
1425+
return make_binary(env, msg, strlen(msg));
1426+
}
1427+
1428+
static ERL_NIF_TERM
1429+
exqlite_errstr(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
1430+
{
1431+
assert(argc == 1);
1432+
1433+
int rc;
1434+
if (!enif_get_int(env, argv[0], &rc)) {
1435+
ERL_NIF_TERM badarg = enif_make_tuple2(env, make_atom(env, "badarg"), argv[0]);
1436+
return enif_raise_exception(env, badarg);
1437+
}
1438+
1439+
const char* msg = sqlite3_errstr(rc);
1440+
return make_binary(env, msg, strlen(msg));
1441+
}
1442+
12751443
//
12761444
// Most of our nif functions are going to be IO bounded
12771445
//
@@ -1283,6 +1451,11 @@ static ErlNifFunc nif_funcs[] = {
12831451
{"changes", 1, exqlite_changes, ERL_NIF_DIRTY_JOB_IO_BOUND},
12841452
{"prepare", 2, exqlite_prepare, ERL_NIF_DIRTY_JOB_IO_BOUND},
12851453
{"bind", 3, exqlite_bind, ERL_NIF_DIRTY_JOB_IO_BOUND},
1454+
{"bind_text", 3, exqlite_bind_text},
1455+
{"bind_blob", 3, exqlite_bind_blob},
1456+
{"bind_integer", 3, exqlite_bind_integer},
1457+
{"bind_float", 3, exqlite_bind_float},
1458+
{"bind_null", 2, exqlite_bind_null},
12861459
{"step", 2, exqlite_step, ERL_NIF_DIRTY_JOB_IO_BOUND},
12871460
{"multi_step", 3, exqlite_multi_step, ERL_NIF_DIRTY_JOB_IO_BOUND},
12881461
{"columns", 2, exqlite_columns, ERL_NIF_DIRTY_JOB_IO_BOUND},
@@ -1295,6 +1468,8 @@ static ErlNifFunc nif_funcs[] = {
12951468
{"set_update_hook", 2, exqlite_set_update_hook, ERL_NIF_DIRTY_JOB_IO_BOUND},
12961469
{"set_log_hook", 1, exqlite_set_log_hook, ERL_NIF_DIRTY_JOB_IO_BOUND},
12971470
{"interrupt", 1, exqlite_interrupt, ERL_NIF_DIRTY_JOB_IO_BOUND},
1471+
{"errmsg", 1, exqlite_errmsg},
1472+
{"errstr", 1, exqlite_errstr},
12981473
};
12991474

13001475
ERL_NIF_INIT(Elixir.Exqlite.Sqlite3NIF, nif_funcs, on_load, NULL, NULL, on_unload)

lib/exqlite/sqlite3.ex

+88
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,94 @@ defmodule Exqlite.Sqlite3 do
303303
Sqlite3NIF.set_log_hook(pid)
304304
end
305305

306+
@doc """
307+
Binds a text value to a prepared statement.
308+
309+
iex> {:ok, conn} = Sqlite3.open(":memory:", [:readonly])
310+
iex> {:ok, stmt} = Sqlite3.prepare(conn, "SELECT ?")
311+
iex> Sqlite3.bind_text(stmt, 1, "Alice")
312+
:ok
313+
314+
"""
315+
@spec bind_text(statement, non_neg_integer, String.t()) :: :ok
316+
def bind_text(stmt, index, text) do
317+
case Sqlite3NIF.bind_text(stmt, index, text) do
318+
0 = _SQLITE_OK -> :ok
319+
rc -> raise Exqlite.Error, message: errmsg(stmt) || errstr(rc)
320+
end
321+
end
322+
323+
@doc """
324+
Binds a blob value to a prepared statement.
325+
326+
iex> {:ok, conn} = Sqlite3.open(":memory:", [:readonly])
327+
iex> {:ok, stmt} = Sqlite3.prepare(conn, "SELECT ?")
328+
iex> Sqlite3.bind_blob(stmt, 1, <<0, 0, 0>>)
329+
:ok
330+
331+
"""
332+
@spec bind_blob(statement, non_neg_integer, binary) :: :ok
333+
def bind_blob(stmt, index, blob) do
334+
case Sqlite3NIF.bind_blob(stmt, index, blob) do
335+
0 = _SQLITE_OK -> :ok
336+
rc -> raise Exqlite.Error, message: errmsg(stmt) || errstr(rc)
337+
end
338+
end
339+
340+
@doc """
341+
Binds an integer value to a prepared statement.
342+
343+
iex> {:ok, conn} = Sqlite3.open(":memory:", [:readonly])
344+
iex> {:ok, stmt} = Sqlite3.prepare(conn, "SELECT ?")
345+
iex> Sqlite3.bind_integer(stmt, 1, 42)
346+
:ok
347+
348+
"""
349+
@spec bind_integer(statement, non_neg_integer, integer) :: :ok
350+
def bind_integer(stmt, index, integer) do
351+
case Sqlite3NIF.bind_integer(stmt, index, integer) do
352+
0 = _SQLITE_OK -> :ok
353+
rc -> raise Exqlite.Error, message: errmsg(stmt) || errstr(rc)
354+
end
355+
end
356+
357+
@doc """
358+
Binds a float value to a prepared statement.
359+
360+
iex> {:ok, conn} = Sqlite3.open(":memory:", [:readonly])
361+
iex> {:ok, stmt} = Sqlite3.prepare(conn, "SELECT ?")
362+
iex> Sqlite3.bind_float(stmt, 1, 3.14)
363+
:ok
364+
365+
"""
366+
@spec bind_float(statement, non_neg_integer, float) :: :ok
367+
def bind_float(stmt, index, float) do
368+
case Sqlite3NIF.bind_float(stmt, index, float) do
369+
0 = _SQLITE_OK -> :ok
370+
rc -> raise Exqlite.Error, message: errmsg(stmt) || errstr(rc)
371+
end
372+
end
373+
374+
@doc """
375+
Binds a null value to a prepared statement.
376+
377+
iex> {:ok, conn} = Sqlite3.open(":memory:", [:readonly])
378+
iex> {:ok, stmt} = Sqlite3.prepare(conn, "SELECT ?")
379+
iex> Sqlite3.bind_null(stmt, 1)
380+
:ok
381+
382+
"""
383+
@spec bind_null(statement, non_neg_integer) :: :ok
384+
def bind_null(stmt, index) do
385+
case Sqlite3NIF.bind_null(stmt, index) do
386+
0 = _SQLITE_OK -> :ok
387+
rc -> raise Exqlite.Error, message: errmsg(stmt) || errstr(rc)
388+
end
389+
end
390+
391+
defp errmsg(stmt), do: Sqlite3NIF.errmsg(stmt)
392+
defp errstr(rc), do: Sqlite3NIF.errstr(rc)
393+
306394
defp convert(%Date{} = val), do: Date.to_iso8601(val)
307395
defp convert(%Time{} = val), do: Time.to_iso8601(val)
308396
defp convert(%NaiveDateTime{} = val), do: NaiveDateTime.to_iso8601(val)

lib/exqlite/sqlite3_nif.ex

+21
Original file line numberDiff line numberDiff line change
@@ -73,5 +73,26 @@ defmodule Exqlite.Sqlite3NIF do
7373
@spec set_log_hook(pid()) :: :ok | {:error, reason()}
7474
def set_log_hook(_pid), do: :erlang.nif_error(:not_loaded)
7575

76+
@spec bind_text(statement, non_neg_integer, String.t()) :: :ok
77+
def bind_text(_stmt, _index, _text), do: :erlang.nif_error(:not_loaded)
78+
79+
@spec bind_blob(statement, non_neg_integer, binary) :: :ok
80+
def bind_blob(_stmt, _index, _blob), do: :erlang.nif_error(:not_loaded)
81+
82+
@spec bind_integer(statement, non_neg_integer, integer) :: :ok
83+
def bind_integer(_stmt, _index, _integer), do: :erlang.nif_error(:not_loaded)
84+
85+
@spec bind_float(statement, non_neg_integer, float) :: :ok
86+
def bind_float(_stmt, _index, _float), do: :erlang.nif_error(:not_loaded)
87+
88+
@spec bind_null(statement, non_neg_integer) :: :ok
89+
def bind_null(_stmt, _index), do: :erlang.nif_error(:not_loaded)
90+
91+
@spec errmsg(db | statement) :: String.t() | nil
92+
def errmsg(_db_or_stmt), do: :erlang.nif_error(:not_loaded)
93+
94+
@spec errstr(integer) :: String.t()
95+
def errstr(_rc), do: :erlang.nif_error(:not_loaded)
96+
7697
# add statement inspection tooling https://sqlite.org/c3ref/expanded_sql.html
7798
end

0 commit comments

Comments
 (0)