diff --git a/c_src/esqlite3_nif.c b/c_src/esqlite3_nif.c index 5e2e001..3d17702 100644 --- a/c_src/esqlite3_nif.c +++ b/c_src/esqlite3_nif.c @@ -310,6 +310,8 @@ bind_cell(ErlNifEnv *env, const ERL_NIF_TERM cell, sqlite3_stmt *stmt, unsigned double the_double; char the_atom[MAX_ATOM_LENGTH+1]; ErlNifBinary the_blob; + int arity; + const ERL_NIF_TERM* tuple; if(enif_get_int(env, cell, &the_int)) return sqlite3_bind_int(stmt, i, the_int); @@ -325,13 +327,22 @@ bind_cell(ErlNifEnv *env, const ERL_NIF_TERM cell, sqlite3_stmt *stmt, unsigned return sqlite3_bind_text(stmt, i, the_atom, strlen(the_atom), SQLITE_TRANSIENT); } - if(enif_inspect_iolist_as_binary(env, cell, &the_blob)) { - /* Bind lists which have the same length as the binary as text. */ - if(enif_is_list(env, cell) && (strnlen((char *) the_blob.data, the_blob.size) == the_blob.size)) { - return sqlite3_bind_text(stmt, i, (char *) the_blob.data, the_blob.size, SQLITE_TRANSIENT); - } - - return sqlite3_bind_blob(stmt, i, the_blob.data, the_blob.size, SQLITE_TRANSIENT); + /* Bind as text assume it is utf-8 encoded text */ + if(enif_inspect_iolist_as_binary(env, cell, &the_blob)) + return sqlite3_bind_text(stmt, i, (char *) the_blob.data, the_blob.size, SQLITE_TRANSIENT); + + /* Check for blob tuple */ + if(enif_get_tuple(env, cell, &arity, &tuple)) { + if(arity != 2) + return -1; + + if(enif_get_atom(env, tuple[0], the_atom, sizeof(the_atom), ERL_NIF_LATIN1)) { + if(0 == strncmp("blob", the_atom, strlen("blob"))) { + if(enif_inspect_iolist_as_binary(env, tuple[1], &the_blob)) { + return sqlite3_bind_blob(stmt, i, the_blob.data, the_blob.size, SQLITE_TRANSIENT); + } + } + } } return -1; @@ -396,12 +407,14 @@ make_cell(ErlNifEnv *env, sqlite3_stmt *statement, unsigned int i) case SQLITE_FLOAT: return enif_make_double(env, sqlite3_column_double(statement, i)); case SQLITE_BLOB: - return make_binary(env, sqlite3_column_blob(statement, i), sqlite3_column_bytes(statement, i)); + 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"); case SQLITE_TEXT: - /* TODO, make some tests to see what happens when you insert a utf-8 string */ - return enif_make_string(env, (char *) sqlite3_column_text(statement, i), ERL_NIF_LATIN1); + return make_binary(env, sqlite3_column_text(statement, i), + sqlite3_column_bytes(statement, i)); default: return make_atom(env, "should_not_happen"); } diff --git a/test/esqlite_test.erl b/test/esqlite_test.erl index bd21975..4453311 100644 --- a/test/esqlite_test.erl +++ b/test/esqlite_test.erl @@ -43,7 +43,7 @@ prepare_test() -> ok = esqlite3:exec(["insert into test_table values(", "\"hello4\"", ",", "13" ");"], Db), %% Check if the values are there. - [{"one", 2}, {"hello4", 13}] = esqlite3:q("select * from test_table order by two", Db), + [{<<"one">>, 2}, {<<"hello4">>, 13}] = esqlite3:q("select * from test_table order by two", Db), esqlite3:exec("commit;", Db), esqlite3:close(Db), @@ -62,28 +62,36 @@ bind_test() -> esqlite3:step(Statement), esqlite3:bind(Statement, ["three", 4]), esqlite3:step(Statement), - esqlite3:bind(Statement, [<<"five">>, 6]), + esqlite3:bind(Statement, ["five", 6]), esqlite3:step(Statement), esqlite3:bind(Statement, [[<<"se">>, $v, "en"], 8]), % iolist bound as text esqlite3:step(Statement), - esqlite3:bind(Statement, [[<<"nine">>], 10]), % iolist bound as text + esqlite3:bind(Statement, [<<"nine">>, 10]), % iolist bound as text esqlite3:step(Statement), - esqlite3:bind(Statement, [[<<"eleven">>, 0], 12]), % iolist bound as blob with trailing eos. + esqlite3:bind(Statement, [{blob, [<<"eleven">>, 0]}, 12]), % iolist bound as blob with trailing eos. esqlite3:step(Statement), - ?assertEqual([{"one", 2}], + %% utf-8 + esqlite3:bind(Statement, [[<<228,184,138,230,181,183>>], 100]), + esqlite3:step(Statement), + + ?assertEqual([{<<"one">>, 2}], esqlite3:q("select one, two from test_table where two = '2'", Db)), - ?assertEqual([{"three", 4}], + ?assertEqual([{<<"three">>, 4}], esqlite3:q("select one, two from test_table where two = 4", Db)), ?assertEqual([{<<"five">>, 6}], esqlite3:q("select one, two from test_table where two = 6", Db)), - ?assertEqual([{"seven", 8}], + ?assertEqual([{<<"seven">>, 8}], esqlite3:q("select one, two from test_table where two = 8", Db)), - ?assertEqual([{"nine", 10}], + ?assertEqual([{<<"nine">>, 10}], esqlite3:q("select one, two from test_table where two = 10", Db)), - ?assertEqual([{<<$e,$l,$e,$v,$e,$n,0>>, 12}], + ?assertEqual([{{blob, <<$e,$l,$e,$v,$e,$n,0>>}, 12}], esqlite3:q("select one, two from test_table where two = 12", Db)), + %% utf-8 + ?assertEqual([{<<228,184,138,230,181,183>>, 100}], + esqlite3:q("select one, two from test_table where two = 100", Db)), + ok. bind_for_queries_test() -> @@ -97,12 +105,8 @@ bind_for_queries_test() -> [test_table], Db)), ?assertEqual([{1}], esqlite3:q(<<"SELECT count(type) FROM sqlite_master WHERE type='table' AND name=?;">>, ["test_table"], Db)), - - %% Bound as blob... sqlite can't find the table then. - ?assertEqual([{0}], esqlite3:q(<<"SELECT count(type) FROM sqlite_master WHERE type='table' AND name=?;">>, + ?assertEqual([{1}], esqlite3:q(<<"SELECT count(type) FROM sqlite_master WHERE type='table' AND name=?;">>, [<<"test_table">>], Db)), - - %% As list it is matched as text. ?assertEqual([{1}], esqlite3:q(<<"SELECT count(type) FROM sqlite_master WHERE type='table' AND name=?;">>, [[<<"test_table">>]], Db)), @@ -142,10 +146,10 @@ foreach_test() -> esqlite3:foreach(F, "select * from test_table;", Db), - 10 = get("hello1"), - 11 = get("hello2"), - 12 = get("hello3"), - 13 = get("hello4"), + 10 = get(<<"hello1">>), + 11 = get(<<"hello2">>), + 12 = get(<<"hello3">>), + 13 = get(<<"hello4">>), ok. @@ -161,17 +165,18 @@ map_test() -> F = fun(Row) -> Row end, - [{"hello1",10},{"hello2",11},{"hello3",12},{"hello4",13}] = esqlite3:map(F, "select * from test_table", Db), + [{<<"hello1">>,10},{<<"hello2">>,11},{<<"hello3">>,12},{<<"hello4">>,13}] + = esqlite3:map(F, "select * from test_table", Db), %% Test that when the row-names are added.. Assoc = fun(Names, Row) -> lists:zip(tuple_to_list(Names), tuple_to_list(Row)) end, - [[{one,"hello1"},{two,10}], - [{one,"hello2"},{two,11}], - [{one,"hello3"},{two,12}], - [{one,"hello4"},{two,13}]] = esqlite3:map(Assoc, "select * from test_table", Db), + [[{one,<<"hello1">>},{two,10}], + [{one,<<"hello2">>},{two,11}], + [{one,<<"hello3">>},{two,12}], + [{one,<<"hello4">>},{two,13}]] = esqlite3:map(Assoc, "select * from test_table", Db), ok. @@ -188,15 +193,6 @@ error1_msg_test() -> {error, {cantopen, _Msg3}} = esqlite3:open("/dit/bestaat/niet"), ok. - - - - - - - - -