diff --git a/c_src/esqlite3_nif.c b/c_src/esqlite3_nif.c index dd289e9..ef285f7 100644 --- a/c_src/esqlite3_nif.c +++ b/c_src/esqlite3_nif.c @@ -486,37 +486,23 @@ make_cell(ErlNifEnv *env, sqlite3_stmt *statement, unsigned int i) int type = sqlite3_column_type(statement, i); switch(type) { + case SQLITE_NULL: + return make_atom(env, "undefined"); case SQLITE_INTEGER: return enif_make_int64(env, sqlite3_column_int64(statement, i)); case SQLITE_FLOAT: return enif_make_double(env, sqlite3_column_double(statement, i)); case SQLITE_BLOB: - return enif_make_tuple2(env, make_atom(env, "blob"), - make_binary(env, sqlite3_column_blob(statement, i), - sqlite3_column_bytes(statement, i))); - case SQLITE_NULL: - return make_atom(env, "undefined"); + return make_binary(env, sqlite3_column_blob(statement, i), + sqlite3_column_bytes(statement, i)); case SQLITE_TEXT: return make_binary(env, sqlite3_column_text(statement, i), sqlite3_column_bytes(statement, i)); } + return enif_raise_exception(env, make_atom(env, "internal_error")); } - -/* -static ERL_NIF_TERM -do_reset(ErlNifEnv *env, sqlite3 *db, sqlite3_stmt *stmt) -{ - int rc = sqlite3_reset(stmt); - if(rc != SQLITE_OK) - return make_sqlite3_error_tuple(env, rc, db); - - return make_atom(env, "ok"); -} -*/ - - /* static ERL_NIF_TERM do_backup_init(ErlNifEnv *env, sqlite3 *db, const ERL_NIF_TERM arg) @@ -1136,6 +1122,82 @@ esqlite_bind_double(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) return make_atom(env, "ok"); } +static ERL_NIF_TERM +esqlite_bind_text(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) +{ + esqlite3_stmt *stmt; + int index; + ErlNifBinary text; + + if(argc != 3) { + return enif_make_badarg(env); + } + + if(!enif_get_resource(env, argv[0], esqlite3_stmt_type, (void **) &stmt)) { + return enif_make_badarg(env); + } + + if(!stmt->statement) { + return enif_raise_exception(env, make_atom(env, "no_prepared_statement")); + } + + if(!enif_get_int(env, argv[1], &index)) { + return enif_make_badarg(env); + } + + if(!enif_inspect_iolist_as_binary(env, argv[1], &text)) { + return enif_make_badarg(env); + } + + /* + * Don't do any checks on the input data, sqlite handes all kinds of input. It is + * garbage-in, garbage-out. + * + */ + + int rc = sqlite3_bind_text64(stmt->statement, index, text.data, text.size, SQLITE_TRANSIENT, SQLITE_UTF8); + if(rc != SQLITE_OK) { + return make_sqlite3_error_tuple(env, rc); + } + + return make_atom(env, "ok"); +} + +static ERL_NIF_TERM +esqlite_bind_blob(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) +{ + esqlite3_stmt *stmt; + int index; + ErlNifBinary blob; + + if(argc != 3) { + return enif_make_badarg(env); + } + + if(!enif_get_resource(env, argv[0], esqlite3_stmt_type, (void **) &stmt)) { + return enif_make_badarg(env); + } + + if(!stmt->statement) { + return enif_raise_exception(env, make_atom(env, "no_prepared_statement")); + } + + if(!enif_get_int(env, argv[1], &index)) { + return enif_make_badarg(env); + } + + if(!enif_inspect_iolist_as_binary(env, argv[1], &blob)) { + return enif_make_badarg(env); + } + + int rc = sqlite3_bind_blob64(stmt->statement, index, blob.data, blob.size, SQLITE_TRANSIENT); + if(rc != SQLITE_OK) { + return make_sqlite3_error_tuple(env, rc); + } + + return make_atom(env, "ok"); +} + static ERL_NIF_TERM esqlite_bind_null(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { @@ -1543,23 +1605,22 @@ static ErlNifFunc nif_funcs[] = { {"bind_int", 3, esqlite_bind_int}, {"bind_int64", 3, esqlite_bind_int64}, {"bind_double", 3, esqlite_bind_double}, - + {"bind_text", 3, esqlite_bind_text}, + {"bind_blob", 3, esqlite_bind_blob}, {"bind_null", 2, esqlite_bind_null}, /* {"bind_text", 3, esqlite_bind_blob}, - {"bind_blob", 3, esqlite_bind_blob}, - {"bind_null", 2, esqlite_bind_blob}, */ {"step", 1, esqlite_step}, {"reset", 1, esqlite_reset}, /* - Other interesting additions... trace. - wal_hook triggered after every commit. - also interesting commit and rollback_hooks - */ + * Other interesting additions... trace. + * wal_hook triggered after every commit. + * also interesting commit and rollback_hooks + */ {"interrupt", 1, esqlite_interrupt, ERL_NIF_DIRTY_JOB_IO_BOUND}, {"last_insert_rowid", 1, esqlite_last_insert_rowid}, @@ -1567,9 +1628,6 @@ static ErlNifFunc nif_funcs[] = { {"changes", 1, esqlite_changes}, /* - - {"exec", 4, esqlite_exec, ERL_NIF_DIRTY_JOB_IO_BOUND}, - {"backup_init", 6, esqlite_backup_init}, {"backup_step", 5, esqlite_backup_step}, {"backup_remaining", 4, esqlite_backup_remaining}, diff --git a/src/esqlite3.erl b/src/esqlite3.erl index 0b475f2..fc650dc 100644 --- a/src/esqlite3.erl +++ b/src/esqlite3.erl @@ -22,13 +22,13 @@ open/1, close/1, %% db connection functions - set_update_hook/2, get_autocommit/1, last_insert_rowid/1, changes/1, + %% queries exec/2, prepare/2, prepare/3, @@ -41,13 +41,13 @@ bind_int64/3, bind_double/3, % bind_text/3, - % bind_blob/3, + bind_blob/3, bind_null/2, step/1, reset/1 -% + % fetchone/1, % fetchall/1, fetchall/2, fetchall/3, % @@ -63,7 +63,6 @@ -define(DEFAULT_TIMEOUT, infinity). -define(DEFAULT_CHUNK_SIZE, 5000). - -define(SQLITE_PREPARE_PERSISTENT, 16#01). -define(SQLITE_PREPARE_NO_VTAB, 16#04). @@ -391,6 +390,14 @@ bind_int64(#esqlite3_stmt{stmt=Stmt}, Index, Value) -> bind_double(#esqlite3_stmt{stmt=Stmt}, Index, Value) -> esqlite3_nif:bind_double(Stmt, Index, Value). +-spec bind_blob(Statement, Index, Value) -> BindResult + when Statement :: esqlite3_stmt(), + Index :: integer(), + Value :: iodata(), + BindResult :: ok | {error, _}. +bind_blob(#esqlite3_stmt{stmt=Stmt}, Index, Value) -> + esqlite3_nif:bind_blob(Stmt, Index, Value). + -spec bind_null(Statement, Index) -> BindResult when Statement :: esqlite3_stmt(), Index :: integer(), diff --git a/src/esqlite3_nif.erl b/src/esqlite3_nif.erl index 0e5c21f..e9232ec 100644 --- a/src/esqlite3_nif.erl +++ b/src/esqlite3_nif.erl @@ -37,8 +37,8 @@ bind_int/3, bind_int64/3, bind_double/3, - %bind_text/3, - %bind_blob/3, + bind_text/3, + bind_blob/3, bind_null/2, step/1, @@ -46,16 +46,7 @@ reset/1, interrupt/1 -% exec/4, -% changes/3, -% -% multi_step/5, -% reset/4, -% finalize/4, -% bind/5, - -% column_types/4, - + % backup_init/6, % backup_step/5, % backup_remaining/4, @@ -137,6 +128,12 @@ bind_int64(_Statement, _Index, _Value) -> bind_double(_Statement, _Index, _Value) -> erlang:nif_error(nif_library_not_loaded). +bind_blob(_Statement, _Index, _Value) -> + erlang:nif_error(nif_library_not_loaded). + +bind_text(_Statement, _Index, _Value) -> + erlang:nif_error(nif_library_not_loaded). + bind_null(_Statement, _Index) -> erlang:nif_error(nif_library_not_loaded). diff --git a/test/esqlite_test.erl b/test/esqlite_test.erl index 1611cda..85adbf6 100644 --- a/test/esqlite_test.erl +++ b/test/esqlite_test.erl @@ -23,12 +23,13 @@ close_test() -> ok = esqlite3:close(C), %% Check if functions still return sensible values. -% {error, closed} = esqlite3:set_update_hook(self(), C), + {error, closed} = esqlite3:set_update_hook(C, self()), {error, closed} = esqlite3:changes(C), {error, closed} = esqlite3:get_autocommit(C), {error, closed} = esqlite3:last_insert_rowid(C), - ?assertEqual({error, {misuse, invoked_incorrectly}}, esqlite3:exec(C, "create table test(one, two, three)")), + ?assertEqual({error, {misuse, invoked_incorrectly}}, + esqlite3:exec(C, "create table test(one, two, three)")), ok.