Added error code from SQLite into returned value on error

This commit is contained in:
Alexey Romanov
2010-11-23 15:56:30 +03:00
parent 9041a0bb98
commit 2ea2dc8fcc
3 changed files with 28 additions and 26 deletions

View File

@@ -118,32 +118,34 @@ static int control(ErlDrvData drv_data, unsigned int command, char *buf,
return 0; return 0;
} }
static inline int return_error(sqlite3_drv_t *drv, const char *error, static inline int return_error(sqlite3_drv_t *drv, int error_code,
ErlDrvTermData **spec, int *term_count) { const char *error, ErlDrvTermData **spec, int *term_count) {
*spec = (ErlDrvTermData *) malloc(9 * sizeof(ErlDrvTermData)); *spec = (ErlDrvTermData *) malloc(11 * sizeof(ErlDrvTermData));
(*spec)[0] = ERL_DRV_PORT; (*spec)[0] = ERL_DRV_PORT;
(*spec)[1] = driver_mk_port(drv->port); (*spec)[1] = driver_mk_port(drv->port);
(*spec)[2] = ERL_DRV_ATOM; (*spec)[2] = ERL_DRV_ATOM;
(*spec)[3] = drv->atom_error; (*spec)[3] = drv->atom_error;
(*spec)[4] = ERL_DRV_STRING; (*spec)[4] = ERL_DRV_INT;
(*spec)[5] = (ErlDrvTermData) error; (*spec)[5] = error_code;
(*spec)[6] = strlen(error); (*spec)[6] = ERL_DRV_STRING;
(*spec)[7] = ERL_DRV_TUPLE; (*spec)[7] = (ErlDrvTermData) error;
(*spec)[8] = 3; (*spec)[8] = strlen(error);
*term_count = 9; (*spec)[9] = ERL_DRV_TUPLE;
(*spec)[10] = 4;
*term_count = 11;
return 0; return 0;
} }
static inline int output_error(sqlite3_drv_t *drv, const char *error) { static inline int output_error(sqlite3_drv_t *drv, int error_code, const char *error) {
ErlDrvTermData *dataset; ErlDrvTermData *dataset;
int term_count; int term_count;
return_error(drv, error, &dataset, &term_count); return_error(drv, error_code, error, &dataset, &term_count);
driver_output_term(drv->port, dataset, term_count); driver_output_term(drv->port, dataset, term_count);
return 0; return 0;
} }
static inline int output_db_error(sqlite3_drv_t *drv) { static inline int output_db_error(sqlite3_drv_t *drv) {
return output_error(drv, sqlite3_errmsg(drv->db)); return output_error(drv, sqlite3_errcode(drv->db), sqlite3_errmsg(drv->db));
} }
static inline int sql_exec_statement(sqlite3_drv_t *drv, sqlite3_stmt *statement) { static inline int sql_exec_statement(sqlite3_drv_t *drv, sqlite3_stmt *statement) {
@@ -215,7 +217,7 @@ static inline int decode_and_bind_param(
result = sqlite3_bind_null(statement, param_index); result = sqlite3_bind_null(statement, param_index);
} }
else { else {
output_error(drv, "Non-null atom as parameter"); output_error(drv, SQLITE_MISUSE, "Non-null atom as parameter");
return 1; return 1;
} }
break; break;
@@ -242,7 +244,7 @@ static inline int decode_and_bind_param(
result = sqlite3_bind_blob(statement, param_index, char_buf_val, *size, &free); result = sqlite3_bind_blob(statement, param_index, char_buf_val, *size, &free);
break; break;
default: default:
output_error(drv, "bad parameter type"); output_error(drv, SQLITE_MISUSE, "bad parameter type");
return 1; return 1;
} }
if (result != SQLITE_OK) { if (result != SQLITE_OK) {
@@ -265,13 +267,13 @@ static int sql_bind_and_exec(sqlite3_drv_t *drv, char *buffer, int buffer_size)
ei_decode_version(buffer, &index, NULL); ei_decode_version(buffer, &index, NULL);
result = ei_decode_tuple_header(buffer, &index, &size); result = ei_decode_tuple_header(buffer, &index, &size);
if (size != 2) { if (size != 2) {
return output_error(drv, "bad argument"); return output_error(drv, SQLITE_MISUSE, "bad argument");
} }
// decode SQL statement // decode SQL statement
ei_get_type(buffer, &index, &type, &size); ei_get_type(buffer, &index, &type, &size);
if (type != ERL_BINARY_EXT) { if (type != ERL_BINARY_EXT) {
return output_error(drv, "bad argument"); return output_error(drv, SQLITE_MISUSE, "bad argument");
} }
char *command = malloc(size * sizeof(char)); char *command = malloc(size * sizeof(char));
@@ -298,7 +300,7 @@ static int sql_bind_and_exec(sqlite3_drv_t *drv, char *buffer, int buffer_size)
// param with name or explicit index // param with name or explicit index
param_indices_are_explicit = 1; param_indices_are_explicit = 1;
if (size != 2) { if (size != 2) {
return output_error(drv, "bad argument"); return output_error(drv, SQLITE_MISUSE, "bad argument");
} }
ei_decode_tuple_header(buffer, &index, &size); ei_decode_tuple_header(buffer, &index, &size);
ei_get_type(buffer, &index, &type, &size); ei_get_type(buffer, &index, &type, &size);
@@ -323,7 +325,7 @@ static int sql_bind_and_exec(sqlite3_drv_t *drv, char *buffer, int buffer_size)
break; break;
case ERL_STRING_EXT: case ERL_STRING_EXT:
if (size >= MAXATOMLEN) { if (size >= MAXATOMLEN) {
return output_error(drv, "parameter name too long"); return output_error(drv, SQLITE_TOOBIG, "parameter name too long");
} }
ei_decode_string(buffer, &index, param_name); ei_decode_string(buffer, &index, param_name);
// insert zero terminator // insert zero terminator
@@ -331,7 +333,7 @@ static int sql_bind_and_exec(sqlite3_drv_t *drv, char *buffer, int buffer_size)
param_index = sqlite3_bind_parameter_index(statement, param_name); param_index = sqlite3_bind_parameter_index(statement, param_name);
break; break;
default: default:
return output_error(drv, "parameter index must be given as integer, atom, or string"); return output_error(drv, SQLITE_MISMATCH, "parameter index must be given as integer, atom, or string");
} }
result = decode_and_bind_param(drv, buffer, &index, statement, param_index, &type, &size); result = decode_and_bind_param(drv, buffer, &index, statement, param_index, &type, &size);
if (result != SQLITE_OK) { if (result != SQLITE_OK) {
@@ -341,7 +343,7 @@ static int sql_bind_and_exec(sqlite3_drv_t *drv, char *buffer, int buffer_size)
else { else {
IMPLICIT_INDEX: IMPLICIT_INDEX:
if (param_indices_are_explicit) { if (param_indices_are_explicit) {
return output_error(drv, return output_error(drv, SQLITE_MISUSE,
"parameters without indices shouldn't follow indexed or named parameters"); "parameters without indices shouldn't follow indexed or named parameters");
} }
@@ -551,12 +553,12 @@ static void sql_exec_async(void *_async_command) {
async_command->binaries = binaries; async_command->binaries = binaries;
if (next_row == SQLITE_BUSY) { if (next_row == SQLITE_BUSY) {
return_error(drv, "SQLite3 database is busy", &async_command->dataset, return_error(drv, SQLITE_BUSY, "SQLite3 database is busy", &async_command->dataset,
&async_command->term_count); &async_command->term_count);
return; return;
} }
if (next_row != SQLITE_DONE) { if (next_row != SQLITE_DONE) {
return_error(drv, sqlite3_errmsg(drv->db), &async_command->dataset, return_error(drv, next_row, sqlite3_errmsg(drv->db), &async_command->dataset,
&async_command->term_count); &async_command->term_count);
return; return;
} }

View File

@@ -737,10 +737,10 @@ exec(Port, {sql_bind_and_exec, SQL, Params}) ->
wait_result(Port) -> wait_result(Port) ->
receive receive
{Port, error, Reason} -> {Port, error, Code, Reason} ->
error_logger:error_msg("sqlite3 driver error: ~s~n", [Reason]), error_logger:error_msg("sqlite3 driver error: ~s~n", [Reason]),
% ?dbg("Error: ~p~n", [Reason]), % ?dbg("Error: ~p~n", [Reason]),
{error, Reason}; {error, Code, Reason};
{Port, Reply} -> {Port, Reply} ->
% ?dbg("Reply: ~p~n", [Reply]), % ?dbg("Reply: ~p~n", [Reply]),
Reply; Reply;

View File

@@ -32,7 +32,7 @@ drop_table_if_exists(Db, Table) ->
rows(SqlExecReply) -> rows(SqlExecReply) ->
case SqlExecReply of case SqlExecReply of
[{columns, _Columns}, {rows, Rows}] -> Rows; [{columns, _Columns}, {rows, Rows}] -> Rows;
{error, Reason} -> {error, Reason} {error, Code, Reason} -> {error, Code, Reason}
end. end.
all_test_() -> all_test_() ->
@@ -78,7 +78,7 @@ basic_functionality() ->
{rowid, 2}, {rowid, 2},
sqlite3:write(ct, user, [{name, "marge"}, {age, 30}, {wage, 2000}])), sqlite3:write(ct, user, [{name, "marge"}, {age, 30}, {wage, 2000}])),
?assertEqual( ?assertEqual(
{error, "constraint failed"}, {error, 19, "constraint failed"},
sqlite3:write(ct, user, [{name, "marge"}, {age, 30}, {wage, 2000}])), sqlite3:write(ct, user, [{name, "marge"}, {age, 30}, {wage, 2000}])),
?assertEqual( ?assertEqual(
[{columns, Columns}, {rows, AllRows}], [{columns, Columns}, {rows, AllRows}],