Trying to fix (this version doesn't work)

This commit is contained in:
Alexey Romanov
2011-04-05 12:44:14 +04:00
parent 12a5d3c9a6
commit 7935c3c652
3 changed files with 210 additions and 64 deletions

View File

@@ -41,6 +41,7 @@ static inline void free_ptr_list(ptr_list *list, void(* free_head)(void *));
static inline int max(int a, int b); static inline int max(int a, int b);
#endif #endif
static inline int sql_is_insert(const char *sql); static inline int sql_is_insert(const char *sql);
static void print_dataset(ErlDrvTermData* dataset, int term_count);
// required because driver_free(_binary) are macros in Windows // required because driver_free(_binary) are macros in Windows
void driver_free_fun(void *ptr) { void driver_free_fun(void *ptr) {
@@ -173,7 +174,10 @@ static int control(
static inline int return_error( static inline int return_error(
sqlite3_drv_t *drv, int error_code, const char *error, sqlite3_drv_t *drv, int error_code, const char *error,
ErlDrvTermData **spec, int *term_count) { ErlDrvTermData **spec, int *term_count, int* error_code_p) {
if (error_code_p) {
*error_code_p = error_code;
}
*spec = (ErlDrvTermData *) driver_alloc(11 * sizeof(ErlDrvTermData)); *spec = (ErlDrvTermData *) driver_alloc(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);
@@ -194,7 +198,7 @@ static inline int output_error(
sqlite3_drv_t *drv, int error_code, const char *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_code, error, &dataset, &term_count); return_error(drv, error_code, error, &dataset, &term_count, NULL);
driver_output_term(drv->port, dataset, term_count); driver_output_term(drv->port, dataset, term_count);
return 1; return 1;
} }
@@ -236,14 +240,17 @@ static inline async_sqlite3_command *make_async_command_statement(
} }
static inline async_sqlite3_command *make_async_command_script( static inline async_sqlite3_command *make_async_command_script(
sqlite3_drv_t *drv, char *script) { sqlite3_drv_t *drv, char *script, int script_length) {
async_sqlite3_command *result = async_sqlite3_command *result =
(async_sqlite3_command *) driver_alloc(sizeof(async_sqlite3_command)); (async_sqlite3_command *) driver_alloc(sizeof(async_sqlite3_command));
memset(result, 0, sizeof(async_sqlite3_command)); memset(result, 0, sizeof(async_sqlite3_command));
char *script_copy = driver_alloc(sizeof(char) * script_length);
memcpy(script_copy, script, sizeof(char) * script_length);
result->driver_data = drv; result->driver_data = drv;
result->type = t_script; result->type = t_script;
result->script = script; result->script = script_copy;
result->end = script_copy + script_length;
return result; return result;
} }
@@ -286,30 +293,21 @@ static int sql_exec(sqlite3_drv_t *drv, char *command, int command_size) {
} }
static int sql_exec_script(sqlite3_drv_t *drv, char *command, int command_size) { static int sql_exec_script(sqlite3_drv_t *drv, char *command, int command_size) {
int result; async_sqlite3_command *async_command = make_async_command_script(drv, command, command_size);
const char *rest = command;
const char *end = command + command_size;
sqlite3_stmt *statement;
while (rest < end) { #ifdef DEBUG
result = sqlite3_prepare_v2(drv->db, command, end - command, &statement, &rest); fprintf(drv->log, "Driver async: %d %p\n", SQLITE_VERSION_NUMBER, async_command->statement);
command = (char *) rest; // won't actually mutate! fflush(drv->log);
if (result != SQLITE_OK) { #endif
output_db_error(drv);
break;
} else if (statement == NULL) {
output_error(drv, SQLITE_MISUSE, "empty statement");
break;
}
result = sql_exec_statement(drv, statement); if (sqlite3_threadsafe()) {
if (result) { drv->async_handle = driver_async(drv->port, &drv->key, sql_exec_async,
// there was an error, bail out async_command, sql_free_async);
break; } else {
} sql_exec_async(async_command);
ready_async((ErlDrvData) drv, (ErlDrvThreadData) async_command);
} }
output_done(drv); return 0;
return result;
} }
static inline int decode_and_bind_param( static inline int decode_and_bind_param(
@@ -565,27 +563,17 @@ static void sql_free_async(void *_async_command) {
} }
static void sql_exec_one_statement( static void sql_exec_one_statement(
sqlite3_stmt *statement, async_sqlite3_command *async_command) { sqlite3_stmt *statement, async_sqlite3_command *async_command,
int *term_count_p, int *term_allocated_p, ErlDrvTermData **dataset_p) {
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 *term_count_p = &(async_command->term_count);
int *term_allocated_p = &(async_command->term_allocated);
ErlDrvTermData **dataset_p = &(async_command->dataset);
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);
int i; int i;
*term_count_p += 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 - 2] = ERL_DRV_PORT;
(*dataset_p)[*term_count_p - 1] = driver_mk_port(drv->port);
if (column_count > 0) { if (column_count > 0) {
*term_count_p += 2; *term_count_p += 2;
if (*term_count_p > *term_allocated_p) { if (*term_count_p > *term_allocated_p) {
@@ -716,12 +704,14 @@ static void sql_exec_one_statement(
if (next_row == SQLITE_BUSY) { if (next_row == SQLITE_BUSY) {
return_error(drv, SQLITE_BUSY, "SQLite3 database is busy", return_error(drv, SQLITE_BUSY, "SQLite3 database is busy",
&async_command->dataset, &async_command->term_count); &async_command->dataset, &async_command->term_count,
&async_command->error_code);
return; return;
} }
if (next_row != SQLITE_DONE) { if (next_row != SQLITE_DONE) {
return_error(drv, next_row, sqlite3_errmsg(drv->db), return_error(drv, next_row, sqlite3_errmsg(drv->db),
&async_command->dataset, &async_command->term_count); &async_command->dataset, &async_command->term_count,
&async_command->error_code);
return; return;
} }
@@ -765,14 +755,7 @@ static void sql_exec_one_statement(
(*dataset_p)[*term_count_p - 2] = ERL_DRV_ATOM; (*dataset_p)[*term_count_p - 2] = ERL_DRV_ATOM;
(*dataset_p)[*term_count_p - 1] = drv->atom_ok; (*dataset_p)[*term_count_p - 1] = drv->atom_ok;
} }
printf("\nEnd of sql_exec_one_statement. Term count: %d, terms alloc: %d\n", *term_count_p, *term_allocated_p);
*term_count_p += 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 - 2] = ERL_DRV_TUPLE;
(*dataset_p)[*term_count_p - 1] = 2;
#ifdef DEBUG #ifdef DEBUG
fprintf(drv->log, "Total term count: %p %d, rows count: %dx%d\n", statement, *term_count_p, column_count, row_count); fprintf(drv->log, "Total term count: %p %d, rows count: %dx%d\n", statement, *term_count_p, column_count, row_count);
@@ -785,13 +768,74 @@ static void sql_exec_async(void *_async_command) {
async_sqlite3_command *async_command = async_sqlite3_command *async_command =
(async_sqlite3_command *) _async_command; (async_sqlite3_command *) _async_command;
sqlite3_stmt *statement; sqlite3_stmt *statement = NULL;
int result;
const char *rest;
const char *end;
int num_statements = 0;
int term_count = 0, term_allocated = 0;
ErlDrvTermData *dataset = NULL;
sqlite3_drv_t *drv = async_command->driver_data;
term_count += 2;
if (term_count > term_allocated) {
term_allocated = max(term_count, term_allocated*2);
dataset = driver_realloc(dataset, sizeof(ErlDrvTermData) * term_allocated);
}
dataset[term_count - 2] = ERL_DRV_PORT;
dataset[term_count - 1] = driver_mk_port(drv->port);
switch (async_command->type) { switch (async_command->type) {
case t_stmt: case t_stmt:
statement = async_command->statement; statement = async_command->statement;
sql_exec_one_statement(statement, async_command); sql_exec_one_statement(statement, async_command, &term_count,
&term_allocated, &dataset);
case t_script:
rest = async_command->script;
end = async_command->end;
while ((rest < end) && !(async_command->error_code)) {
if (statement) {
sqlite3_finalize(statement);
}
result = sqlite3_prepare_v2(drv->db, rest, end - rest, &statement, &rest);
if (result != SQLITE_OK) {
// output_db_error(drv);
break;
} else if (statement == NULL) {
// output_error(drv, SQLITE_MISUSE, "empty statement");
break;
}
num_statements++;
sql_exec_one_statement(statement, async_command, &term_count,
&term_allocated, &dataset);
}
term_count += 3;
if (term_count > term_allocated) {
term_allocated = max(term_count, term_allocated*2);
dataset = driver_realloc(dataset, sizeof(ErlDrvTermData) * term_allocated);
}
dataset[term_count - 3] = ERL_DRV_NIL;
dataset[term_count - 2] = ERL_DRV_LIST;
dataset[term_count - 1] = num_statements + 1;
} }
term_count += 2;
if (term_count > term_allocated) {
term_allocated = max(term_count, term_allocated*2);
dataset = driver_realloc(dataset, sizeof(ErlDrvTermData) * term_allocated);
}
dataset[term_count - 2] = ERL_DRV_TUPLE;
dataset[term_count - 1] = 2;
print_dataset(dataset, term_count);
async_command->term_count = term_count;
async_command->term_allocated = term_allocated;
async_command->dataset = dataset;
} }
static void sql_step_async(void *_async_command) { static void sql_step_async(void *_async_command) {
@@ -934,13 +978,15 @@ static void sql_step_async(void *_async_command) {
break; break;
case SQLITE_BUSY: case SQLITE_BUSY:
return_error(drv, SQLITE_BUSY, "SQLite3 database is busy", return_error(drv, SQLITE_BUSY, "SQLite3 database is busy",
&dataset, &term_count); &dataset, &term_count,
&async_command->error_code);
sqlite3_reset(statement); sqlite3_reset(statement);
goto POPULATE_COMMAND; goto POPULATE_COMMAND;
break; break;
default: default:
return_error(drv, result, sqlite3_errmsg(drv->db), return_error(drv, result, sqlite3_errmsg(drv->db),
&dataset, &term_count); &dataset, &term_count,
&async_command->error_code);
sqlite3_reset(statement); sqlite3_reset(statement);
goto POPULATE_COMMAND; goto POPULATE_COMMAND;
} }
@@ -1258,3 +1304,110 @@ static inline int sql_is_insert(const char *sql) {
} }
return 1; return 1;
} }
static void print_dataset(ErlDrvTermData *dataset, int term_count) {
int i = 0, stack_size = 0;
printf("\nPrinting dataset\n");
while (i < term_count) {
switch (dataset[i]) {
case ERL_DRV_NIL:
if (dataset[i+1] == ERL_DRV_LIST) {
printf("%d-%d: proper list, length %lu\n", i, i+2, (ErlDrvUInt) dataset[i+2]-1);
i += 3;
stack_size -= (ErlDrvUInt) dataset[i+2]-1;
} else {
printf("%d: []\n", i);
i++;
stack_size++;
}
break;
case ERL_DRV_ATOM:
printf("%d-%d: an atom\n", i, i+1);
i += 2;
stack_size++;
break;
case ERL_DRV_INT:
printf("%d-%d: int %ld\n", i, i+1, (ErlDrvSInt) dataset[i+1]);
i += 2;
stack_size++;
break;
case ERL_DRV_PORT:
printf("%d-%d: a port\n", i, i+1);
i += 2;
stack_size++;
break;
case ERL_DRV_BINARY:
printf("%d-%d: a binary (length %lu, offset %lu)\n",
i, i+3, (ErlDrvUInt) dataset[i+2], (ErlDrvUInt) dataset[i+3]);
i += 4;
stack_size++;
break;
case ERL_DRV_BUF2BINARY:
printf("%d-%d: a string used as binary (length %lu)\n", i, i+2, (ErlDrvUInt) dataset[i+2]);
i += 3;
stack_size++;
break;
case ERL_DRV_STRING:
printf("%d-%d: a string (length %lu)\n", i, i+2, (ErlDrvUInt) dataset[i+2]);
i += 3;
stack_size++;
break;
case ERL_DRV_TUPLE:
printf("%d-%d: a tuple (size %lu)\n", i, i+1, (ErlDrvUInt) dataset[i+1]);
i += 2;
stack_size -= (ErlDrvUInt) dataset[i+1];
break;
case ERL_DRV_LIST:
printf("%d-%d: an improper list (length %lu)\n", i, i+1, (ErlDrvUInt) dataset[i+1]);
i += 2;
stack_size -= (ErlDrvUInt) dataset[i+1];
break;
case ERL_DRV_PID:
printf("%d-%d: a pid\n", i, i+1);
i += 2;
stack_size++;
break;
case ERL_DRV_STRING_CONS:
printf("%d-%d: a string inside surrounding list (length %lu)\n", i, i+2, (ErlDrvUInt) dataset[i+2]);
i += 3;
stack_size += (ErlDrvUInt) dataset[i+2];
break;
case ERL_DRV_FLOAT:
printf("%d-%d: float %f\n", i, i+1, (double) dataset[i+1]);
i += 2;
stack_size++;
break;
case ERL_DRV_EXT2TERM:
printf("%d-%d: a term in external format of length %lu\n", i, i+1, (ErlDrvUInt) dataset[i+1]);
i += 2;
stack_size++;
break;
case ERL_DRV_INT64:
#if defined(_MSC_VER)
printf("%d-%d: int %I64d\n", i, i+1, (ErlDrvSInt64) dataset[i+1]);
#else
printf("%d-%d: int %lld\n", i, i+1, (ErlDrvSInt64) dataset[i+1]);
#endif
i += 2;
stack_size++;
break;
case ERL_DRV_UINT64:
#if defined(_MSC_VER)
printf("%d-%d: int %I64lu\n", i, i+1, (ErlDrvUInt64) dataset[i+1]);
#else
printf("%d-%d: int %llu\n", i, i+1, (ErlDrvUInt64) dataset[i+1]);
#endif
i += 2;
stack_size++;
break;
default:
printf("%d: unexpected type\n", i);
i++;
break;
}
printf("After %d entries in dataset, %d terms are on stack\n", i, stack_size);
}
printf("After %d entries in dataset, %d terms are on stack\n", i, stack_size);
}

View File

@@ -73,7 +73,10 @@ typedef struct async_sqlite3_command {
async_sqlite3_command_type type; async_sqlite3_command_type type;
union { union {
sqlite3_stmt *statement; sqlite3_stmt *statement;
char *script; struct {
char *script;
char *end;
};
}; };
ErlDrvTermData *dataset; ErlDrvTermData *dataset;
int term_count; int term_count;
@@ -82,6 +85,7 @@ typedef struct async_sqlite3_command {
ptr_list *ptrs; ptr_list *ptrs;
ptr_list *binaries; ptr_list *binaries;
int finalize_statement_on_free; int finalize_statement_on_free;
int error_code;
} async_sqlite3_command; } async_sqlite3_command;

View File

@@ -1086,7 +1086,7 @@ exec(Port, {sql_bind_and_exec, SQL, Params}) ->
wait_result(Port); wait_result(Port);
exec(Port, {sql_exec_script, SQL}) -> exec(Port, {sql_exec_script, SQL}) ->
port_control(Port, ?SQL_EXEC_SCRIPT, SQL), port_control(Port, ?SQL_EXEC_SCRIPT, SQL),
many_results_loop(Port); wait_result(Port);
exec(Port, {prepare, SQL}) -> exec(Port, {prepare, SQL}) ->
port_control(Port, ?PREPARE, SQL), port_control(Port, ?PREPARE, SQL),
wait_result(Port); wait_result(Port);
@@ -1123,17 +1123,6 @@ wait_result(Port) ->
{error, -1, Reason} {error, -1, Reason}
end. end.
many_results_loop(Port) ->
do_many_results_loop(Port, []).
do_many_results_loop(Port, Acc) ->
case wait_result(Port) of
done ->
lists:reverse(Acc);
Reply ->
do_many_results_loop(Port, [Reply | Acc])
end.
parse_table_info(Info) -> parse_table_info(Info) ->
[_, Tail] = string:tokens(Info, "()"), [_, Tail] = string:tokens(Info, "()"),
Cols = string:tokens(Tail, ","), Cols = string:tokens(Tail, ","),