Fixed handling of errors after columns are determined
This commit is contained in:
@@ -197,6 +197,10 @@ static inline int return_error(
|
|||||||
(*p_dataset)[*p_term_count - 3] = strlen(error);
|
(*p_dataset)[*p_term_count - 3] = strlen(error);
|
||||||
(*p_dataset)[*p_term_count - 2] = ERL_DRV_TUPLE;
|
(*p_dataset)[*p_term_count - 2] = ERL_DRV_TUPLE;
|
||||||
(*p_dataset)[*p_term_count - 1] = 3;
|
(*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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -289,7 +293,6 @@ static int sql_exec(sqlite3_drv_t *drv, char *command, int command_size) {
|
|||||||
} else if (statement == NULL) {
|
} else if (statement == NULL) {
|
||||||
return output_error(drv, SQLITE_MISUSE, "empty statement");
|
return output_error(drv, SQLITE_MISUSE, "empty statement");
|
||||||
}
|
}
|
||||||
|
|
||||||
return sql_exec_statement(drv, 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 column_count = sqlite3_column_count(statement);
|
||||||
int row_count = 0, next_row;
|
int row_count = 0, next_row;
|
||||||
int base_term_count;
|
int base_term_count;
|
||||||
|
int has_error = 0; // bool
|
||||||
sqlite3_drv_t *drv = async_command->driver_data;
|
sqlite3_drv_t *drv = async_command->driver_data;
|
||||||
ptr_list **ptrs_p = &(async_command->ptrs);
|
ptr_list **ptrs_p = &(async_command->ptrs);
|
||||||
ptr_list **binaries_p = &(async_command->binaries);
|
ptr_list **binaries_p = &(async_command->binaries);
|
||||||
@@ -727,37 +731,46 @@ static int sql_exec_one_statement(
|
|||||||
row_count++;
|
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) {
|
if (next_row != SQLITE_DONE) {
|
||||||
return_error(drv, next_row, sqlite3_errmsg(drv->db),
|
if (column_count == 0) {
|
||||||
dataset_p, term_count_p,
|
return_error(drv, next_row, sqlite3_errmsg(drv->db),
|
||||||
term_allocated_p, &async_command->error_code);
|
dataset_p, term_count_p,
|
||||||
async_command->finalize_statement_on_free = 1;
|
term_allocated_p, &async_command->error_code);
|
||||||
return next_row;
|
async_command->finalize_statement_on_free = 1;
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
has_error = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (column_count > 0) {
|
if (column_count > 0) {
|
||||||
*term_count_p += 3+2+3;
|
*term_count_p += 3+2;
|
||||||
if (*term_count_p > *term_allocated_p) {
|
if (*term_count_p > *term_allocated_p) {
|
||||||
*term_allocated_p = max(*term_count_p, *term_allocated_p*2);
|
*term_allocated_p = max(*term_count_p, *term_allocated_p*2);
|
||||||
*dataset_p = driver_realloc(*dataset_p, sizeof(ErlDrvTermData) * *term_allocated_p);
|
*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 - 5] = ERL_DRV_NIL;
|
||||||
(*dataset_p)[*term_count_p - 7] = ERL_DRV_LIST;
|
(*dataset_p)[*term_count_p - 4] = ERL_DRV_LIST;
|
||||||
(*dataset_p)[*term_count_p - 6] = row_count + 1;
|
(*dataset_p)[*term_count_p - 3] = row_count + 1;
|
||||||
|
|
||||||
(*dataset_p)[*term_count_p - 5] = ERL_DRV_TUPLE;
|
(*dataset_p)[*term_count_p - 2] = ERL_DRV_TUPLE;
|
||||||
(*dataset_p)[*term_count_p - 4] = 2;
|
(*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 - 3] = ERL_DRV_NIL;
|
||||||
(*dataset_p)[*term_count_p - 2] = ERL_DRV_LIST;
|
(*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))) {
|
} else if (sql_is_insert(sqlite3_sql(statement))) {
|
||||||
ErlDrvSInt64 *rowid_ptr = driver_alloc(sizeof(ErlDrvSInt64));
|
ErlDrvSInt64 *rowid_ptr = driver_alloc(sizeof(ErlDrvSInt64));
|
||||||
*rowid_ptr = (ErlDrvSInt64) sqlite3_last_insert_rowid(drv->db);
|
*rowid_ptr = (ErlDrvSInt64) sqlite3_last_insert_rowid(drv->db);
|
||||||
@@ -789,7 +802,7 @@ static int sql_exec_one_statement(
|
|||||||
#endif
|
#endif
|
||||||
async_command->finalize_statement_on_free = 1;
|
async_command->finalize_statement_on_free = 1;
|
||||||
|
|
||||||
return 0;
|
return has_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sql_exec_async(void *_async_command) {
|
static void sql_exec_async(void *_async_command) {
|
||||||
|
|||||||
@@ -38,4 +38,4 @@
|
|||||||
-type sqlite_error() :: {error, integer(), string()} | {error, term()}.
|
-type sqlite_error() :: {error, integer(), string()} | {error, term()}.
|
||||||
-type sql_params() :: [sql_value() | {atom() | string() | integer(), sql_value()}].
|
-type sql_params() :: [sql_value() | {atom() | string() | integer(), sql_value()}].
|
||||||
-type sql_non_query_result() :: ok | sqlite_error() | {rowid, integer()}.
|
-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()].
|
||||||
|
|||||||
@@ -1208,7 +1208,7 @@ list_init([H|T]) -> [H|list_init(T)].
|
|||||||
%% @end
|
%% @end
|
||||||
%% @type sqlite_error() = {'error', integer(), string()} | {'error', any()}.
|
%% @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],
|
%% 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
|
%% [http://www.sqlite.org/c3ref/c_busy_recovery.html]) and an English-language error
|
||||||
%% message.
|
%% 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
|
%% The result returned by functions which call the database but don't return
|
||||||
%% any records.
|
%% any records.
|
||||||
%% @end
|
%% @end
|
||||||
%% @type sql_result() = sql_non_query_result() | [{columns, [string()]} | {rows, [tuple()]}].
|
%% @type sql_result() = sql_non_query_result() | [{columns, [string()]} | {rows, [tuple()]} | sqlite_error()].
|
||||||
%% The result returned by functions which query the database.
|
%% 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
|
%% @end
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
|
|||||||
@@ -49,7 +49,8 @@ all_test_() ->
|
|||||||
?FuncTest(nonexistent_table_info),
|
?FuncTest(nonexistent_table_info),
|
||||||
?FuncTest(large_number),
|
?FuncTest(large_number),
|
||||||
?FuncTest(unicode),
|
?FuncTest(unicode),
|
||||||
?FuncTest(acc_string_encoding)]}.
|
?FuncTest(acc_string_encoding),
|
||||||
|
?FuncTest(large_offset)]}.
|
||||||
|
|
||||||
open_db() ->
|
open_db() ->
|
||||||
sqlite3:open(ct, [in_memory]).
|
sqlite3:open(ct, [in_memory]).
|
||||||
@@ -295,6 +296,13 @@ script_test() ->
|
|||||||
sqlite3:sql_exec_script(script, BadScript)),
|
sqlite3:sql_exec_script(script, BadScript)),
|
||||||
sqlite3:close(script).
|
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
|
% create, read, update, delete
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
%% Internal functions
|
%% Internal functions
|
||||||
|
|||||||
Reference in New Issue
Block a user