diff --git a/c_src/sqlite3_drv.c b/c_src/sqlite3_drv.c index 30b4774..ca918d2 100644 --- a/c_src/sqlite3_drv.c +++ b/c_src/sqlite3_drv.c @@ -197,6 +197,10 @@ static inline int return_error( (*p_dataset)[*p_term_count - 3] = strlen(error); (*p_dataset)[*p_term_count - 2] = ERL_DRV_TUPLE; (*p_dataset)[*p_term_count - 1] = 3; +// int i; +// for (i = 0; i < *p_term_count; i++) { +// printf("%d\n", (*p_dataset)[i]); +// } return 0; } @@ -289,7 +293,6 @@ static int sql_exec(sqlite3_drv_t *drv, char *command, int command_size) { } else if (statement == NULL) { return output_error(drv, SQLITE_MISUSE, "empty statement"); } - return sql_exec_statement(drv, statement); } @@ -592,6 +595,7 @@ static int sql_exec_one_statement( int column_count = sqlite3_column_count(statement); int row_count = 0, next_row; int base_term_count; + int has_error = 0; // bool sqlite3_drv_t *drv = async_command->driver_data; ptr_list **ptrs_p = &(async_command->ptrs); ptr_list **binaries_p = &(async_command->binaries); @@ -727,37 +731,46 @@ static int sql_exec_one_statement( row_count++; } - if (next_row == SQLITE_BUSY) { - return_error(drv, SQLITE_BUSY, "SQLite3 database is busy", - dataset_p, term_count_p, - term_allocated_p, &async_command->error_code); - async_command->finalize_statement_on_free = 1; - return next_row; - } if (next_row != SQLITE_DONE) { - return_error(drv, next_row, sqlite3_errmsg(drv->db), - dataset_p, term_count_p, - term_allocated_p, &async_command->error_code); - async_command->finalize_statement_on_free = 1; - return next_row; + if (column_count == 0) { + return_error(drv, next_row, sqlite3_errmsg(drv->db), + dataset_p, term_count_p, + term_allocated_p, &async_command->error_code); + async_command->finalize_statement_on_free = 1; + return 1; + } else { + has_error = 1; + } } if (column_count > 0) { - *term_count_p += 3+2+3; + *term_count_p += 3+2; if (*term_count_p > *term_allocated_p) { *term_allocated_p = max(*term_count_p, *term_allocated_p*2); *dataset_p = driver_realloc(*dataset_p, sizeof(ErlDrvTermData) * *term_allocated_p); } - (*dataset_p)[*term_count_p - 8] = ERL_DRV_NIL; - (*dataset_p)[*term_count_p - 7] = ERL_DRV_LIST; - (*dataset_p)[*term_count_p - 6] = row_count + 1; + (*dataset_p)[*term_count_p - 5] = ERL_DRV_NIL; + (*dataset_p)[*term_count_p - 4] = ERL_DRV_LIST; + (*dataset_p)[*term_count_p - 3] = row_count + 1; - (*dataset_p)[*term_count_p - 5] = ERL_DRV_TUPLE; - (*dataset_p)[*term_count_p - 4] = 2; + (*dataset_p)[*term_count_p - 2] = ERL_DRV_TUPLE; + (*dataset_p)[*term_count_p - 1] = 2; + + if (has_error) { + return_error(drv, next_row, sqlite3_errmsg(drv->db), + dataset_p, term_count_p, + term_allocated_p, &async_command->error_code); + } + + *term_count_p += 3; + if (*term_count_p > *term_allocated_p) { + *term_allocated_p = max(*term_count_p, *term_allocated_p*2); + *dataset_p = driver_realloc(*dataset_p, sizeof(ErlDrvTermData) * *term_allocated_p); + } (*dataset_p)[*term_count_p - 3] = ERL_DRV_NIL; (*dataset_p)[*term_count_p - 2] = ERL_DRV_LIST; - (*dataset_p)[*term_count_p - 1] = 3; + (*dataset_p)[*term_count_p - 1] = 3 + has_error; } else if (sql_is_insert(sqlite3_sql(statement))) { ErlDrvSInt64 *rowid_ptr = driver_alloc(sizeof(ErlDrvSInt64)); *rowid_ptr = (ErlDrvSInt64) sqlite3_last_insert_rowid(drv->db); @@ -789,7 +802,7 @@ static int sql_exec_one_statement( #endif async_command->finalize_statement_on_free = 1; - return 0; + return has_error; } static void sql_exec_async(void *_async_command) { diff --git a/include/sqlite3.hrl b/include/sqlite3.hrl index 5b3507d..c505b39 100644 --- a/include/sqlite3.hrl +++ b/include/sqlite3.hrl @@ -38,4 +38,4 @@ -type sqlite_error() :: {error, integer(), string()} | {error, term()}. -type sql_params() :: [sql_value() | {atom() | string() | integer(), sql_value()}]. -type sql_non_query_result() :: ok | sqlite_error() | {rowid, integer()}. --type sql_result() :: sql_non_query_result() | [{columns, [column_id()]} | {rows, [tuple()]}]. +-type sql_result() :: sql_non_query_result() | [{columns, [column_id()]} | {rows, [tuple()]} | sqlite_error()]. diff --git a/src/sqlite3.erl b/src/sqlite3.erl index c33d4ff..3e3d4b3 100644 --- a/src/sqlite3.erl +++ b/src/sqlite3.erl @@ -1208,7 +1208,7 @@ list_init([H|T]) -> [H|list_init(T)]. %% @end %% @type sqlite_error() = {'error', integer(), string()} | {'error', any()}. %% -%% Errors occuring on the C side are represented by 3-element tuples containing +%% Errors reported by SQLite side are represented by 3-element tuples containing %% atom 'error', SQLite result code ([http://www.sqlite.org/c3ref/c_abort.html], %% [http://www.sqlite.org/c3ref/c_busy_recovery.html]) and an English-language error %% message. @@ -1220,8 +1220,10 @@ list_init([H|T]) -> [H|list_init(T)]. %% The result returned by functions which call the database but don't return %% any records. %% @end -%% @type sql_result() = sql_non_query_result() | [{columns, [string()]} | {rows, [tuple()]}]. -%% The result returned by functions which query the database. +%% @type sql_result() = sql_non_query_result() | [{columns, [string()]} | {rows, [tuple()]} | sqlite_error()]. +%% The result returned by functions which query the database. If there are errors, +%% list of three tuples is returned: [{columns, ListOfColumnNames}, {rows, ListOfResults}, ErrorTuple]. +%% If there are no errors, the list has two elements. %% @end %%-------------------------------------------------------------------- diff --git a/test/sqlite3_test.erl b/test/sqlite3_test.erl index b177287..b0cd89b 100644 --- a/test/sqlite3_test.erl +++ b/test/sqlite3_test.erl @@ -49,7 +49,8 @@ all_test_() -> ?FuncTest(nonexistent_table_info), ?FuncTest(large_number), ?FuncTest(unicode), - ?FuncTest(acc_string_encoding)]}. + ?FuncTest(acc_string_encoding), + ?FuncTest(large_offset)]}. open_db() -> sqlite3:open(ct, [in_memory]). @@ -295,6 +296,13 @@ script_test() -> sqlite3:sql_exec_script(script, BadScript)), sqlite3:close(script). +large_offset() -> + drop_table_if_exists(ct, large_offset), + ok = sqlite3:create_table(ct, large_offset, [{id, integer}]), + ?assertEqual( + [{columns, ["id"]}, {rows, []}, {error, 20, "datatype mismatch"}], + sqlite3:sql_exec(ct, "select * from large_offset limit 1 offset 9223372036854775808")). + % create, read, update, delete %%==================================================================== %% Internal functions