diff --git a/c_src/sqlite3_drv.c b/c_src/sqlite3_drv.c index 42309ce..69be19a 100644 --- a/c_src/sqlite3_drv.c +++ b/c_src/sqlite3_drv.c @@ -36,7 +36,7 @@ DRIVER_INIT(basic_driver) { static int print_dataset(ErlDrvTermData *dataset, int term_count); static inline ptr_list *add_to_ptr_list(ptr_list *list, void *value_ptr); -static inline void free_ptr_list(ptr_list *list); +static inline void free_ptr_list(ptr_list *list, void(* free_head)(void *)); // Driver Start static ErlDrvData start(ErlDrvPort port, char* cmd) { @@ -77,6 +77,7 @@ static ErlDrvData start(ErlDrvPort port, char* cmd) { retval->db = db; retval->key = 42; //FIXME: Just a magic number, make real key + retval->atom_blob = driver_mk_atom("blob"); retval->atom_error = driver_mk_atom("error"); retval->atom_columns = driver_mk_atom("columns"); retval->atom_rows = driver_mk_atom("rows"); @@ -364,13 +365,16 @@ static void sql_free_async(void *_async_command) { async_command->driver_data->async_handle = 0; - free_ptr_list(async_command->ptrs); - for (i = 0; i < async_command->binaries_count; i++) { - driver_free_binary(async_command->binaries[i]); - } - if (async_command->binaries) { - free(async_command->binaries); - } + free_ptr_list(async_command->ptrs, &free); + + free_ptr_list(async_command->binaries, &driver_free_binary); + + // for (i = 0; i < async_command->binaries_count; i++) { + // driver_free_binary(async_command->binaries[i]); + // } + // if (async_command->binaries) { + // free(async_command->binaries); + // } if (async_command->statement) { sqlite3_finalize(async_command->statement); } @@ -393,8 +397,7 @@ static void sql_exec_async(void *_async_command) { ptr_list *ptrs = NULL; - ErlDrvBinary **binaries = NULL; - int binaries_count = 0; + ptr_list *binaries = NULL; int i; column_count = sqlite3_column_count(statement); @@ -475,16 +478,37 @@ static void sql_exec_async(void *_async_command) { dataset[term_count - 1] = (ErlDrvTermData) float_ptr; break; } - case SQLITE_BLOB: + case SQLITE_BLOB: { + int bytes = sqlite3_column_bytes(statement, i); + ErlDrvBinary* binary = driver_alloc_binary(bytes); + binary->orig_size = bytes; + memcpy(binary->orig_bytes, + sqlite3_column_blob(statement, i), bytes); + binaries = add_to_ptr_list(binaries, binary); + + term_count += 8; + if (term_count > term_allocated) { + term_allocated = + (term_count >= term_allocated*2) ? term_count : term_allocated*2; + dataset = realloc(dataset, sizeof(*dataset) * term_allocated); + } + dataset[term_count - 8] = ERL_DRV_ATOM; + dataset[term_count - 7] = drv->atom_blob; + dataset[term_count - 6] = ERL_DRV_BINARY; + dataset[term_count - 5] = (ErlDrvTermData) binary; + dataset[term_count - 4] = bytes; + dataset[term_count - 3] = 0; + dataset[term_count - 2] = ERL_DRV_TUPLE; + dataset[term_count - 1] = 2; + break; + } case SQLITE_TEXT: { int bytes = sqlite3_column_bytes(statement, i); - binaries_count++; - binaries = - realloc(binaries, sizeof(*binaries) * binaries_count); - binaries[binaries_count - 1] = driver_alloc_binary(bytes); - binaries[binaries_count - 1]->orig_size = bytes; - memcpy(binaries[binaries_count - 1]->orig_bytes, + ErlDrvBinary* binary = driver_alloc_binary(bytes); + binary->orig_size = bytes; + memcpy(binary->orig_bytes, sqlite3_column_blob(statement, i), bytes); + binaries = add_to_ptr_list(binaries, binary); term_count += 4; if (term_count > term_allocated) { @@ -493,8 +517,7 @@ static void sql_exec_async(void *_async_command) { dataset = realloc(dataset, sizeof(*dataset) * term_allocated); } dataset[term_count - 4] = ERL_DRV_BINARY; - dataset[term_count - 3] = - (ErlDrvTermData) binaries[binaries_count - 1]; + dataset[term_count - 3] = (ErlDrvTermData) binary; dataset[term_count - 2] = bytes; dataset[term_count - 1] = 0; break; @@ -526,7 +549,6 @@ static void sql_exec_async(void *_async_command) { async_command->row_count = row_count; async_command->ptrs = ptrs; async_command->binaries = binaries; - async_command->binaries_count = binaries_count; if (next_row == SQLITE_BUSY) { return_error(drv, "SQLite3 database is busy", &async_command->dataset, @@ -666,11 +688,11 @@ static inline ptr_list *add_to_ptr_list(ptr_list *list, void *value_ptr) { } } -static inline void free_ptr_list(ptr_list *list) { +static inline void free_ptr_list(ptr_list *list, void(* free_head)(void *)) { ptr_list* tail; while (list) { tail = list->tail; - free(list->head); + (*free_head)(list->head); free(list); list = tail; } diff --git a/c_src/sqlite3_drv.h b/c_src/sqlite3_drv.h index 39fd003..bf825c0 100644 --- a/c_src/sqlite3_drv.h +++ b/c_src/sqlite3_drv.h @@ -36,6 +36,7 @@ typedef struct sqlite3_drv_t { struct sqlite3 *db; long async_handle; FILE *log; + ErlDrvTermData atom_blob; ErlDrvTermData atom_error; ErlDrvTermData atom_columns; ErlDrvTermData atom_rows; @@ -52,8 +53,7 @@ typedef struct async_sqlite3_command { int term_count; int row_count; ptr_list *ptrs; - int binaries_count; - ErlDrvBinary **binaries; + ptr_list *binaries; } async_sqlite3_command; diff --git a/test/sqlite3_test.erl b/test/sqlite3_test.erl index 4efa9cb..73c4606 100644 --- a/test/sqlite3_test.erl +++ b/test/sqlite3_test.erl @@ -122,7 +122,7 @@ parametrized() -> [null, 1.0, {blob, <<1,0,0>>}]), ?assertEqual( [{columns, ["i", "d", "b"]}, - {rows, [{null, 1.0, <<1,0,0>>}]}], + {rows, [{null, 1.0, {blob, <<1,0,0>>}}]}], sqlite3:read_all(ct, user1)). blob() -> @@ -130,7 +130,7 @@ blob() -> sqlite3:create_table(ct, blobs, [{blob_col, blob}]), sqlite3:write(ct, blobs, [{blob_col, {blob, <<0,255,1,2>>}}]), ?assertEqual( - [{columns, ["blob_col"]}, {rows, [{<<0,255,1,2>>}]}], + [{columns, ["blob_col"]}, {rows, [{{blob, <<0,255,1,2>>}}]}], sqlite3:read_all(ct, blobs)). escaping() ->