diff --git a/c_src/esqlite3_nif.c b/c_src/esqlite3_nif.c index c59905c..78dd131 100644 --- a/c_src/esqlite3_nif.c +++ b/c_src/esqlite3_nif.c @@ -34,13 +34,13 @@ static ErlNifResourceType *esqlite_statement_type = NULL; /* database connection context */ typedef struct { - ErlNifTid tid; - ErlNifThreadOpts* opts; + ErlNifTid tid; + ErlNifThreadOpts* opts; - sqlite3 *db; - queue *commands; + sqlite3 *db; + queue *commands; - int alive; + int alive; } esqlite_connection; /* prepared statement */ @@ -51,88 +51,88 @@ typedef struct { typedef enum { - cmd_unknown, - cmd_open, - cmd_exec, - cmd_prepare, - cmd_bind, - cmd_step, - cmd_column_names, - cmd_close, - cmd_stop + cmd_unknown, + cmd_open, + cmd_exec, + cmd_prepare, + cmd_bind, + cmd_step, + cmd_column_names, + cmd_close, + cmd_stop } command_type; typedef struct { - command_type type; + command_type type; - ErlNifEnv *env; - ERL_NIF_TERM ref; - ErlNifPid pid; - ERL_NIF_TERM arg; - sqlite3_stmt *stmt; + ErlNifEnv *env; + ERL_NIF_TERM ref; + ErlNifPid pid; + ERL_NIF_TERM arg; + sqlite3_stmt *stmt; } esqlite_command; static ERL_NIF_TERM make_atom(ErlNifEnv *env, const char *atom_name) { - ERL_NIF_TERM atom; + ERL_NIF_TERM atom; - if(enif_make_existing_atom(env, atom_name, &atom, ERL_NIF_LATIN1)) - return atom; + if(enif_make_existing_atom(env, atom_name, &atom, ERL_NIF_LATIN1)) + return atom; - return enif_make_atom(env, atom_name); + return enif_make_atom(env, atom_name); } static ERL_NIF_TERM make_ok_tuple(ErlNifEnv *env, ERL_NIF_TERM value) { - return enif_make_tuple2(env, make_atom(env, "ok"), value); + return enif_make_tuple2(env, make_atom(env, "ok"), value); } static ERL_NIF_TERM make_error_tuple(ErlNifEnv *env, const char *reason) { - return enif_make_tuple2(env, make_atom(env, "error"), make_atom(env, reason)); + return enif_make_tuple2(env, make_atom(env, "error"), make_atom(env, reason)); } static ERL_NIF_TERM make_sqlite3_error_tuple(ErlNifEnv *env, const char *msg) { return enif_make_tuple2(env, make_atom(env, "error"), - enif_make_tuple2(env, make_atom(env, "sqlite3_error"), - enif_make_string(env, msg, ERL_NIF_LATIN1))); + enif_make_tuple2(env, make_atom(env, "sqlite3_error"), + enif_make_string(env, msg, ERL_NIF_LATIN1))); } static void command_destroy(void *obj) { - esqlite_command *cmd = (esqlite_command *) obj; + esqlite_command *cmd = (esqlite_command *) obj; - if(cmd->env != NULL) - enif_free_env(cmd->env); + if(cmd->env != NULL) + enif_free_env(cmd->env); - enif_free(cmd); + enif_free(cmd); } static esqlite_command * command_create() { - esqlite_command *cmd = (esqlite_command *) enif_alloc(sizeof(esqlite_command)); - if(cmd == NULL) - return NULL; + esqlite_command *cmd = (esqlite_command *) enif_alloc(sizeof(esqlite_command)); + if(cmd == NULL) + return NULL; - cmd->env = enif_alloc_env(); - if(cmd->env == NULL) { - command_destroy(cmd); - return NULL; - } + cmd->env = enif_alloc_env(); + if(cmd->env == NULL) { + command_destroy(cmd); + return NULL; + } - cmd->type = cmd_unknown; - cmd->ref = 0; - cmd->arg = 0; - cmd->stmt = NULL; + cmd->type = cmd_unknown; + cmd->ref = 0; + cmd->arg = 0; + cmd->stmt = NULL; - return cmd; + return cmd; } /* @@ -141,66 +141,66 @@ command_create() static void destruct_esqlite_connection(ErlNifEnv *env, void *arg) { - esqlite_connection *db = (esqlite_connection *) arg; - esqlite_command *cmd = command_create(); + esqlite_connection *db = (esqlite_connection *) arg; + esqlite_command *cmd = command_create(); - /* Send the stop command - */ - cmd->type = cmd_stop; - queue_push(db->commands, cmd); - queue_send(db->commands, cmd); + /* Send the stop command + */ + cmd->type = cmd_stop; + queue_push(db->commands, cmd); + queue_send(db->commands, cmd); - /* Wait for the thread to finish - */ - enif_thread_join(db->tid, NULL); - enif_thread_opts_destroy(db->opts); + /* Wait for the thread to finish + */ + enif_thread_join(db->tid, NULL); + enif_thread_opts_destroy(db->opts); - /* The thread has finished... now remove the command queue, and close - * the datbase (if it was still open). - */ - queue_destroy(db->commands); + /* The thread has finished... now remove the command queue, and close + * the datbase (if it was still open). + */ + queue_destroy(db->commands); - if(db->db) - sqlite3_close(db->db); + if(db->db) + sqlite3_close(db->db); } static void destruct_esqlite_statement(ErlNifEnv *env, void *arg) { - esqlite_statement *stmt = (esqlite_statement *) arg; + esqlite_statement *stmt = (esqlite_statement *) arg; - if(stmt->statement) { - sqlite3_finalize(stmt->statement); - stmt->statement = NULL; - } + if(stmt->statement) { + sqlite3_finalize(stmt->statement); + stmt->statement = NULL; + } - enif_release_resource(stmt->connection); + enif_release_resource(stmt->connection); } static ERL_NIF_TERM do_open(ErlNifEnv *env, esqlite_connection *db, const ERL_NIF_TERM arg) { - char filename[MAX_PATHNAME]; - unsigned int size; - int rc; - ERL_NIF_TERM error; + char filename[MAX_PATHNAME]; + unsigned int size; + int rc; + ERL_NIF_TERM error; - size = enif_get_string(env, arg, filename, MAX_PATHNAME, ERL_NIF_LATIN1); - if(size <= 0) - return make_error_tuple(env, "invalid_filename"); + size = enif_get_string(env, arg, filename, MAX_PATHNAME, ERL_NIF_LATIN1); + if(size <= 0) + return make_error_tuple(env, "invalid_filename"); - /* Open the database. - */ - rc = sqlite3_open(filename, &db->db); - if(rc != SQLITE_OK) { - error = make_sqlite3_error_tuple(env, sqlite3_errmsg(db->db)); - sqlite3_close(db->db); - db->db = NULL; + /* Open the database. + */ + rc = sqlite3_open(filename, &db->db); + if(rc != SQLITE_OK) { + error = make_sqlite3_error_tuple(env, sqlite3_errmsg(db->db)); + sqlite3_close(db->db); + db->db = NULL; - return error; - } + return error; + } - return make_atom(env, "ok"); + return make_atom(env, "ok"); } /* @@ -208,16 +208,16 @@ do_open(ErlNifEnv *env, esqlite_connection *db, const ERL_NIF_TERM arg) static ERL_NIF_TERM do_exec(ErlNifEnv *env, esqlite_connection *conn, const ERL_NIF_TERM arg) { - ErlNifBinary bin; - int rc; + ErlNifBinary bin; + int rc; - enif_inspect_iolist_as_binary(env, arg, &bin); + enif_inspect_iolist_as_binary(env, arg, &bin); - rc = sqlite3_exec(conn->db, (char *) bin.data, NULL, NULL, NULL); - if(rc != SQLITE_OK) - return make_sqlite3_error_tuple(env, sqlite3_errmsg(conn->db)); + rc = sqlite3_exec(conn->db, (char *) bin.data, NULL, NULL, NULL); + if(rc != SQLITE_OK) + return make_sqlite3_error_tuple(env, sqlite3_errmsg(conn->db)); - return make_atom(env, "ok"); + return make_atom(env, "ok"); } /* @@ -225,262 +225,259 @@ do_exec(ErlNifEnv *env, esqlite_connection *conn, const ERL_NIF_TERM arg) static ERL_NIF_TERM do_prepare(ErlNifEnv *env, esqlite_connection *conn, const ERL_NIF_TERM arg) { - ErlNifBinary bin; - esqlite_statement *stmt; - ERL_NIF_TERM esqlite_stmt; - const char *tail; - int rc; + ErlNifBinary bin; + esqlite_statement *stmt; + ERL_NIF_TERM esqlite_stmt; + const char *tail; + int rc; - enif_inspect_iolist_as_binary(env, arg, &bin); + enif_inspect_iolist_as_binary(env, arg, &bin); - stmt = enif_alloc_resource(esqlite_statement_type, sizeof(esqlite_statement)); - if(!stmt) - return make_error_tuple(env, "no_memory"); + stmt = enif_alloc_resource(esqlite_statement_type, sizeof(esqlite_statement)); + if(!stmt) + return make_error_tuple(env, "no_memory"); - rc = sqlite3_prepare_v2(conn->db, (char *) bin.data, bin.size, &(stmt->statement), &tail); - if(rc != SQLITE_OK) - return make_sqlite3_error_tuple(env, sqlite3_errmsg(conn->db)); + rc = sqlite3_prepare_v2(conn->db, (char *) bin.data, bin.size, &(stmt->statement), &tail); + if(rc != SQLITE_OK) + return make_sqlite3_error_tuple(env, sqlite3_errmsg(conn->db)); - enif_keep_resource(conn); - stmt->connection = conn; + enif_keep_resource(conn); + stmt->connection = conn; - esqlite_stmt = enif_make_resource(env, stmt); - enif_release_resource(stmt); + esqlite_stmt = enif_make_resource(env, stmt); + enif_release_resource(stmt); - return make_ok_tuple(env, esqlite_stmt); + return make_ok_tuple(env, esqlite_stmt); } static int bind_cell(ErlNifEnv *env, const ERL_NIF_TERM cell, sqlite3_stmt *stmt, unsigned int i) { - int the_int; - double the_double; - char the_atom[MAX_ATOM_LENGTH+1]; - ErlNifBinary the_blob; + int the_int; + double the_double; + char the_atom[MAX_ATOM_LENGTH+1]; + ErlNifBinary the_blob; - if(enif_get_int(env, cell, &the_int)) - return sqlite3_bind_int(stmt, i, the_int); + if(enif_get_int(env, cell, &the_int)) + return sqlite3_bind_int(stmt, i, the_int); - if(enif_get_double(env, cell, &the_double)) - return sqlite3_bind_double(stmt, i, the_double); + if(enif_get_double(env, cell, &the_double)) + return sqlite3_bind_double(stmt, i, the_double); - if(enif_get_atom(env, cell, the_atom, sizeof(the_atom), ERL_NIF_LATIN1)) { - if(strcmp("undefined", the_atom) == 0) { + if(enif_get_atom(env, cell, the_atom, sizeof(the_atom), ERL_NIF_LATIN1)) { + if(strcmp("undefined", the_atom) == 0) { return sqlite3_bind_null(stmt, i); - } + } - return sqlite3_bind_text(stmt, i, the_atom, strlen(the_atom), SQLITE_TRANSIENT); - } + return sqlite3_bind_text(stmt, i, the_atom, strlen(the_atom), SQLITE_TRANSIENT); + } - if(enif_inspect_iolist_as_binary(env, cell, &the_blob)) { - /* Bind lists which have the same length as the binary as text */ - if(enif_is_list(env, cell) && (strlen((char *) the_blob.data) == the_blob.size)) { + if(enif_inspect_iolist_as_binary(env, cell, &the_blob)) { + /* Bind lists which have the same length as the binary as text */ + if(enif_is_list(env, cell) && (strlen((char *) the_blob.data) == the_blob.size)) { return sqlite3_bind_text(stmt, i, (char *) the_blob.data, the_blob.size, SQLITE_TRANSIENT); - } + } - return sqlite3_bind_blob(stmt, i, the_blob.data, the_blob.size, SQLITE_TRANSIENT); - } + return sqlite3_bind_blob(stmt, i, the_blob.data, the_blob.size, SQLITE_TRANSIENT); + } - return -1; + return -1; } static ERL_NIF_TERM do_bind(ErlNifEnv *env, sqlite3 *db, sqlite3_stmt *stmt, const ERL_NIF_TERM arg) { - int parameter_count = sqlite3_bind_parameter_count(stmt); - int i, is_list, r; - ERL_NIF_TERM list, head, tail; - unsigned int list_length; + int parameter_count = sqlite3_bind_parameter_count(stmt); + int i, is_list, r; + ERL_NIF_TERM list, head, tail; + unsigned int list_length; - is_list = enif_get_list_length(env, arg, &list_length); - if(!is_list) - return make_error_tuple(env, "bad_arg_list"); - if(parameter_count != list_length) - return make_error_tuple(env, "args_wrong_length"); + is_list = enif_get_list_length(env, arg, &list_length); + if(!is_list) + return make_error_tuple(env, "bad_arg_list"); + if(parameter_count != list_length) + return make_error_tuple(env, "args_wrong_length"); - sqlite3_reset(stmt); + sqlite3_reset(stmt); - list = arg; - for(i=0; i < list_length; i++) { - enif_get_list_cell(env, list, &head, &tail); - r = bind_cell(env, head, stmt, i+1); - if(r == -1) - return make_error_tuple(env, "wrong_type"); - if(r != SQLITE_OK) - return make_sqlite3_error_tuple(env, sqlite3_errmsg(db)); - list = tail; - } + list = arg; + for(i=0; i < list_length; i++) { + enif_get_list_cell(env, list, &head, &tail); + r = bind_cell(env, head, stmt, i+1); + if(r == -1) + return make_error_tuple(env, "wrong_type"); + if(r != SQLITE_OK) + return make_sqlite3_error_tuple(env, sqlite3_errmsg(db)); + list = tail; + } - return make_atom(env, "ok"); + return make_atom(env, "ok"); } static ERL_NIF_TERM make_binary(ErlNifEnv *env, const void *bytes, unsigned int size) { - ErlNifBinary blob; - ERL_NIF_TERM term; + ErlNifBinary blob; + ERL_NIF_TERM term; - if(!enif_alloc_binary(size, &blob)) { - /* TODO: fix this */ - return make_atom(env, "error"); - } + if(!enif_alloc_binary(size, &blob)) { + /* TODO: fix this */ + return make_atom(env, "error"); + } - memcpy(blob.data, bytes, size); - term = enif_make_binary(env, &blob); - enif_release_binary(&blob); + memcpy(blob.data, bytes, size); + term = enif_make_binary(env, &blob); + enif_release_binary(&blob); - return term; + return term; } static ERL_NIF_TERM make_cell(ErlNifEnv *env, sqlite3_stmt *statement, unsigned int i) { - int type = sqlite3_column_type(statement, i); + int type = sqlite3_column_type(statement, i); - switch(type) { - case SQLITE_INTEGER: - return enif_make_int(env, sqlite3_column_int(statement, i)); - case SQLITE_FLOAT: - return enif_make_double(env, sqlite3_column_double(statement, i)); - case SQLITE_BLOB: - return make_binary(env, sqlite3_column_blob(statement, i), sqlite3_column_bytes(statement, i)); - case SQLITE_NULL: - return make_atom(env, "undefined"); - case SQLITE_TEXT: - /* TODO, make some tests to see what happens when you insert a utf-8 string */ - return enif_make_string(env, (char *) sqlite3_column_text(statement, i), ERL_NIF_LATIN1); - default: - return make_atom(env, "should_not_happen"); - } + switch(type) { + case SQLITE_INTEGER: + return enif_make_int(env, sqlite3_column_int(statement, i)); + case SQLITE_FLOAT: + return enif_make_double(env, sqlite3_column_double(statement, i)); + case SQLITE_BLOB: + return make_binary(env, sqlite3_column_blob(statement, i), sqlite3_column_bytes(statement, i)); + case SQLITE_NULL: + return make_atom(env, "undefined"); + case SQLITE_TEXT: + /* TODO, make some tests to see what happens when you insert a utf-8 string */ + return enif_make_string(env, (char *) sqlite3_column_text(statement, i), ERL_NIF_LATIN1); + default: + return make_atom(env, "should_not_happen"); + } } static ERL_NIF_TERM make_row(ErlNifEnv *env, sqlite3_stmt *statement) { - int i, size; - ERL_NIF_TERM *array; - ERL_NIF_TERM row; + int i, size; + ERL_NIF_TERM *array; + ERL_NIF_TERM row; - size = sqlite3_column_count(statement); - array = (ERL_NIF_TERM *) malloc(sizeof(ERL_NIF_TERM)*size); + size = sqlite3_column_count(statement); + array = (ERL_NIF_TERM *) malloc(sizeof(ERL_NIF_TERM)*size); - if(!array) - return make_error_tuple(env, "no_memory"); + if(!array) + return make_error_tuple(env, "no_memory"); - for(i = 0; i < size; i++) - array[i] = make_cell(env, statement, i); + for(i = 0; i < size; i++) + array[i] = make_cell(env, statement, i); - row = enif_make_tuple_from_array(env, array, size); - free(array); - return row; + row = enif_make_tuple_from_array(env, array, size); + free(array); + return row; } static ERL_NIF_TERM do_step(ErlNifEnv *env, sqlite3_stmt *stmt) { - int rc = sqlite3_step(stmt); + int rc = sqlite3_step(stmt); - if(rc == SQLITE_DONE) - return make_atom(env, "$done"); - if(rc == SQLITE_BUSY) - return make_atom(env, "$busy"); - if(rc == SQLITE_ROW) - return make_row(env, stmt); + if(rc == SQLITE_DONE) + return make_atom(env, "$done"); + if(rc == SQLITE_BUSY) + return make_atom(env, "$busy"); + if(rc == SQLITE_ROW) + return make_row(env, stmt); - return make_error_tuple(env, "unexpected_return_value"); + return make_error_tuple(env, "unexpected_return_value"); } static ERL_NIF_TERM do_column_names(ErlNifEnv *env, sqlite3_stmt *stmt) { - int i, size; - const char *name; - ERL_NIF_TERM *array; - ERL_NIF_TERM column_names; + int i, size; + const char *name; + ERL_NIF_TERM *array; + ERL_NIF_TERM column_names; - size = sqlite3_column_count(stmt); - array = (ERL_NIF_TERM *) malloc(sizeof(ERL_NIF_TERM) * size); + size = sqlite3_column_count(stmt); + array = (ERL_NIF_TERM *) malloc(sizeof(ERL_NIF_TERM) * size); - if(!array) - return make_error_tuple(env, "no_memory"); + if(!array) + return make_error_tuple(env, "no_memory"); - for(i = 0; i < size; i++) { - name = sqlite3_column_name(stmt, i); - array[i] = make_atom(env, name); - } + for(i = 0; i < size; i++) { + name = sqlite3_column_name(stmt, i); + array[i] = make_atom(env, name); + } - column_names = enif_make_tuple_from_array(env, array, size); - free(array); - return column_names; + column_names = enif_make_tuple_from_array(env, array, size); + free(array); + return column_names; } static ERL_NIF_TERM do_close(ErlNifEnv *env, esqlite_connection *conn, const ERL_NIF_TERM arg) { - int rc; + int rc; - rc = sqlite3_close(conn->db); - if(rc != SQLITE_OK) - return make_sqlite3_error_tuple(env, sqlite3_errmsg(conn->db)); + rc = sqlite3_close(conn->db); + if(rc != SQLITE_OK) + return make_sqlite3_error_tuple(env, sqlite3_errmsg(conn->db)); - conn->db = NULL; - return make_atom(env, "ok"); + conn->db = NULL; + return make_atom(env, "ok"); } static ERL_NIF_TERM evaluate_command(esqlite_command *cmd, esqlite_connection *conn) { - if(!conn->db) - make_error_tuple(cmd->env, "database_not_open"); - - switch(cmd->type) { - case cmd_open: - return do_open(cmd->env, conn, cmd->arg); - case cmd_exec: - return do_exec(cmd->env, conn, cmd->arg); - case cmd_prepare: - return do_prepare(cmd->env, conn, cmd->arg); - case cmd_step: - return do_step(cmd->env, cmd->stmt); - case cmd_bind: - return do_bind(cmd->env, conn->db, cmd->stmt, cmd->arg); - case cmd_column_names: - return do_column_names(cmd->env, cmd->stmt); - case cmd_close: - return do_close(cmd->env, conn, cmd->arg); - default: - return make_error_tuple(cmd->env, "invalid_command"); - } + switch(cmd->type) { + case cmd_open: + return do_open(cmd->env, conn, cmd->arg); + case cmd_exec: + return do_exec(cmd->env, conn, cmd->arg); + case cmd_prepare: + return do_prepare(cmd->env, conn, cmd->arg); + case cmd_step: + return do_step(cmd->env, cmd->stmt); + case cmd_bind: + return do_bind(cmd->env, conn->db, cmd->stmt, cmd->arg); + case cmd_column_names: + return do_column_names(cmd->env, cmd->stmt); + case cmd_close: + return do_close(cmd->env, conn, cmd->arg); + default: + return make_error_tuple(cmd->env, "invalid_command"); + } } static ERL_NIF_TERM make_answer(esqlite_command *cmd, ERL_NIF_TERM answer) { - return enif_make_tuple2(cmd->env, cmd->ref, answer); + return enif_make_tuple2(cmd->env, cmd->ref, answer); } static void * esqlite_connection_run(void *arg) { - esqlite_connection *db = (esqlite_connection *) arg; - esqlite_command *cmd; - int continue_running = 1; + esqlite_connection *db = (esqlite_connection *) arg; + esqlite_command *cmd; + int continue_running = 1; - db->alive = 1; + db->alive = 1; - while(continue_running) { - cmd = queue_pop(db->commands); + while(continue_running) { + cmd = queue_pop(db->commands); - if(cmd->type == cmd_stop) - continue_running = 0; - else - enif_send(NULL, &cmd->pid, cmd->env, make_answer(cmd, evaluate_command(cmd, db))); + if(cmd->type == cmd_stop) + continue_running = 0; + else + enif_send(NULL, &cmd->pid, cmd->env, make_answer(cmd, evaluate_command(cmd, db))); - command_destroy(cmd); - } + command_destroy(cmd); + } - db->alive = 0; - return NULL; + db->alive = 0; + return NULL; } /* @@ -489,34 +486,34 @@ esqlite_connection_run(void *arg) static ERL_NIF_TERM esqlite_start(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { - esqlite_connection *conn; - ERL_NIF_TERM db_conn; + esqlite_connection *conn; + ERL_NIF_TERM db_conn; - /* Initialize the resource */ - conn = enif_alloc_resource(esqlite_connection_type, sizeof(esqlite_connection)); - if(!conn) - return make_error_tuple(env, "no_memory"); + /* Initialize the resource */ + conn = enif_alloc_resource(esqlite_connection_type, sizeof(esqlite_connection)); + if(!conn) + return make_error_tuple(env, "no_memory"); - conn->db = NULL; + conn->db = NULL; - /* Create command queue */ - conn->commands = queue_create(); - if(!conn->commands) { - enif_release_resource(conn); - return make_error_tuple(env, "command_queue_create_failed"); - } + /* Create command queue */ + conn->commands = queue_create(); + if(!conn->commands) { + enif_release_resource(conn); + return make_error_tuple(env, "command_queue_create_failed"); + } - /* Start command processing thread */ - conn->opts = enif_thread_opts_create("esqldb_thread_opts"); - if(enif_thread_create("esqlite_connection", &conn->tid, esqlite_connection_run, conn, conn->opts) != 0) { - enif_release_resource(conn); - return make_error_tuple(env, "thread_create_failed"); - } + /* Start command processing thread */ + conn->opts = enif_thread_opts_create("esqldb_thread_opts"); + if(enif_thread_create("esqlite_connection", &conn->tid, esqlite_connection_run, conn, conn->opts) != 0) { + enif_release_resource(conn); + return make_error_tuple(env, "thread_create_failed"); + } - db_conn = enif_make_resource(env, conn); - enif_release_resource(conn); + db_conn = enif_make_resource(env, conn); + enif_release_resource(conn); - return make_ok_tuple(env, db_conn); + return make_ok_tuple(env, db_conn); } /* @@ -525,37 +522,37 @@ esqlite_start(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) static ERL_NIF_TERM esqlite_open(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { - esqlite_connection *db; - esqlite_command *cmd = NULL; - ErlNifPid pid; + esqlite_connection *db; + esqlite_command *cmd = NULL; + ErlNifPid pid; - if(argc != 4) - return enif_make_badarg(env); + if(argc != 4) + return enif_make_badarg(env); - if(!enif_get_resource(env, argv[0], esqlite_connection_type, (void **) &db)) - return enif_make_badarg(env); + if(!enif_get_resource(env, argv[0], esqlite_connection_type, (void **) &db)) + return enif_make_badarg(env); - if(!enif_is_ref(env, argv[1])) - return make_error_tuple(env, "invalid_ref"); + if(!enif_is_ref(env, argv[1])) + return make_error_tuple(env, "invalid_ref"); - if(!enif_get_local_pid(env, argv[2], &pid)) - return make_error_tuple(env, "invalid_pid"); + if(!enif_get_local_pid(env, argv[2], &pid)) + return make_error_tuple(env, "invalid_pid"); - /* Note, no check is made for the type of the argument */ - cmd = command_create(); - if(!cmd) - return make_error_tuple(env, "command_create_failed"); + /* Note, no check is made for the type of the argument */ + cmd = command_create(); + if(!cmd) + return make_error_tuple(env, "command_create_failed"); - /* command */ - cmd->type = cmd_open; - cmd->ref = enif_make_copy(cmd->env, argv[1]); - cmd->pid = pid; - cmd->arg = enif_make_copy(cmd->env, argv[3]); + /* command */ + cmd->type = cmd_open; + cmd->ref = enif_make_copy(cmd->env, argv[1]); + cmd->pid = pid; + cmd->arg = enif_make_copy(cmd->env, argv[3]); - if(!queue_push(db->commands, cmd)) - return make_error_tuple(env, "command_push_failed"); + if(!queue_push(db->commands, cmd)) + return make_error_tuple(env, "command_push_failed"); - return make_atom(env, "ok"); + return make_atom(env, "ok"); } /* @@ -564,36 +561,33 @@ esqlite_open(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) static ERL_NIF_TERM esqlite_exec(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { - esqlite_connection *db; - esqlite_command *cmd = NULL; - ErlNifPid pid; + esqlite_connection *db; + esqlite_command *cmd = NULL; + ErlNifPid pid; - if(argc != 4) - return enif_make_badarg(env); + if(argc != 4) + return enif_make_badarg(env); + if(!enif_get_resource(env, argv[0], esqlite_connection_type, (void **) &db)) + return enif_make_badarg(env); + if(!enif_is_ref(env, argv[1])) + return make_error_tuple(env, "invalid_ref"); + if(!enif_get_local_pid(env, argv[2], &pid)) + return make_error_tuple(env, "invalid_pid"); + + cmd = command_create(); + if(!cmd) + return make_error_tuple(env, "command_create_failed"); - if(!enif_get_resource(env, argv[0], esqlite_connection_type, (void **) &db)) - return enif_make_badarg(env); - - if(!enif_is_ref(env, argv[1])) - return make_error_tuple(env, "invalid_ref"); - - if(!enif_get_local_pid(env, argv[2], &pid)) - return make_error_tuple(env, "invalid_pid"); - - cmd = command_create(); - if(!cmd) - return make_error_tuple(env, "command_create_failed"); - - /* command */ - cmd->type = cmd_exec; - cmd->ref = enif_make_copy(cmd->env, argv[1]); - cmd->pid = pid; - cmd->arg = enif_make_copy(cmd->env, argv[3]); + /* command */ + cmd->type = cmd_exec; + cmd->ref = enif_make_copy(cmd->env, argv[1]); + cmd->pid = pid; + cmd->arg = enif_make_copy(cmd->env, argv[3]); - if(!queue_push(db->commands, cmd)) - return make_error_tuple(env, "command_push_failed"); + if(!queue_push(db->commands, cmd)) + return make_error_tuple(env, "command_push_failed"); - return make_atom(env, "ok"); + return make_atom(env, "ok"); } @@ -603,32 +597,32 @@ esqlite_exec(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) static ERL_NIF_TERM esqlite_prepare(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { - esqlite_connection *conn; - esqlite_command *cmd = NULL; - ErlNifPid pid; + esqlite_connection *conn; + esqlite_command *cmd = NULL; + ErlNifPid pid; - if(argc != 4) - return enif_make_badarg(env); - if(!enif_get_resource(env, argv[0], esqlite_connection_type, (void **) &conn)) - return enif_make_badarg(env); - if(!enif_is_ref(env, argv[1])) - return make_error_tuple(env, "invalid_ref"); - if(!enif_get_local_pid(env, argv[2], &pid)) - return make_error_tuple(env, "invalid_pid"); + if(argc != 4) + return enif_make_badarg(env); + if(!enif_get_resource(env, argv[0], esqlite_connection_type, (void **) &conn)) + return enif_make_badarg(env); + if(!enif_is_ref(env, argv[1])) + return make_error_tuple(env, "invalid_ref"); + if(!enif_get_local_pid(env, argv[2], &pid)) + return make_error_tuple(env, "invalid_pid"); - cmd = command_create(); - if(!cmd) - return make_error_tuple(env, "command_create_failed"); + cmd = command_create(); + if(!cmd) + return make_error_tuple(env, "command_create_failed"); - cmd->type = cmd_prepare; - cmd->ref = enif_make_copy(cmd->env, argv[1]); - cmd->pid = pid; - cmd->arg = enif_make_copy(cmd->env, argv[3]); + cmd->type = cmd_prepare; + cmd->ref = enif_make_copy(cmd->env, argv[1]); + cmd->pid = pid; + cmd->arg = enif_make_copy(cmd->env, argv[3]); - if(!queue_push(conn->commands, cmd)) - return make_error_tuple(env, "command_push_failed"); + if(!queue_push(conn->commands, cmd)) + return make_error_tuple(env, "command_push_failed"); - return make_atom(env, "ok"); + return make_atom(env, "ok"); } /* @@ -637,38 +631,36 @@ esqlite_prepare(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) static ERL_NIF_TERM esqlite_bind(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { - esqlite_statement *stmt; - esqlite_command *cmd = NULL; - ErlNifPid pid; + esqlite_statement *stmt; + esqlite_command *cmd = NULL; + ErlNifPid pid; - if(argc != 4) - return enif_make_badarg(env); - if(!enif_get_resource(env, argv[0], esqlite_statement_type, (void **) &stmt)) - return enif_make_badarg(env); - if(!enif_is_ref(env, argv[1])) - return make_error_tuple(env, "invalid_ref"); - if(!enif_get_local_pid(env, argv[2], &pid)) - return make_error_tuple(env, "invalid_pid"); + if(argc != 4) + return enif_make_badarg(env); + if(!enif_get_resource(env, argv[0], esqlite_statement_type, (void **) &stmt)) + return enif_make_badarg(env); + if(!enif_is_ref(env, argv[1])) + return make_error_tuple(env, "invalid_ref"); + if(!enif_get_local_pid(env, argv[2], &pid)) + return make_error_tuple(env, "invalid_pid"); - cmd = command_create(); - if(!cmd) - return make_error_tuple(env, "command_create_failed"); + cmd = command_create(); + if(!cmd) + return make_error_tuple(env, "command_create_failed"); - cmd->type = cmd_bind; - cmd->ref = enif_make_copy(cmd->env, argv[1]); - cmd->pid = pid; - cmd->stmt = stmt->statement; - cmd->arg = enif_make_copy(cmd->env, argv[3]); + cmd->type = cmd_bind; + cmd->ref = enif_make_copy(cmd->env, argv[1]); + cmd->pid = pid; + cmd->stmt = stmt->statement; + cmd->arg = enif_make_copy(cmd->env, argv[3]); - if(!stmt->connection) - return make_error_tuple(env, "no_connection"); - if(!stmt->connection->commands) - return make_error_tuple(env, "no_command_queue"); - - if(!queue_push(stmt->connection->commands, cmd)) - return make_error_tuple(env, "command_push_failed"); - - return make_atom(env, "ok"); + if(!stmt->connection) + return make_error_tuple(env, "no_connection"); + if(!stmt->connection->commands) + return make_error_tuple(env, "no_command_queue"); + if(!queue_push(stmt->connection->commands, cmd)) + return make_error_tuple(env, "command_push_failed"); + return make_atom(env, "ok"); } /* @@ -677,40 +669,37 @@ esqlite_bind(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) static ERL_NIF_TERM esqlite_step(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { - esqlite_statement *stmt; - esqlite_command *cmd = NULL; - ErlNifPid pid; + esqlite_statement *stmt; + esqlite_command *cmd = NULL; + ErlNifPid pid; - if(argc != 3) - return enif_make_badarg(env); - if(!enif_get_resource(env, argv[0], esqlite_statement_type, (void **) &stmt)) - return enif_make_badarg(env); - if(!enif_is_ref(env, argv[1])) - return make_error_tuple(env, "invalid_ref"); - if(!enif_get_local_pid(env, argv[2], &pid)) - return make_error_tuple(env, "invalid_pid"); + if(argc != 3) + return enif_make_badarg(env); + if(!enif_get_resource(env, argv[0], esqlite_statement_type, (void **) &stmt)) + return enif_make_badarg(env); + if(!enif_is_ref(env, argv[1])) + return make_error_tuple(env, "invalid_ref"); + if(!enif_get_local_pid(env, argv[2], &pid)) + return make_error_tuple(env, "invalid_pid"); + if(!stmt->statement) + return make_error_tuple(env, "no_prepared_statement"); - if(!stmt->statement) - return make_error_tuple(env, "no_prepared_statement"); + cmd = command_create(); + if(!cmd) + return make_error_tuple(env, "command_create_failed"); - cmd = command_create(); - if(!cmd) - return make_error_tuple(env, "command_create_failed"); + cmd->type = cmd_step; + cmd->ref = enif_make_copy(cmd->env, argv[1]); + cmd->pid = pid; + cmd->stmt = stmt->statement; - cmd->type = cmd_step; - cmd->ref = enif_make_copy(cmd->env, argv[1]); - cmd->pid = pid; - cmd->stmt = stmt->statement; - - if(!stmt->connection) - return make_error_tuple(env, "no_connection"); - if(!stmt->connection->commands) - return make_error_tuple(env, "no_command_queue"); - - if(!queue_push(stmt->connection->commands, cmd)) - return make_error_tuple(env, "command_push_failed"); - - return make_atom(env, "ok"); + if(!stmt->connection) + return make_error_tuple(env, "no_connection"); + if(!stmt->connection->commands) + return make_error_tuple(env, "no_command_queue"); + if(!queue_push(stmt->connection->commands, cmd)) + return make_error_tuple(env, "command_push_failed"); + return make_atom(env, "ok"); } /* @@ -719,40 +708,38 @@ esqlite_step(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) static ERL_NIF_TERM esqlite_column_names(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { - esqlite_statement *stmt; - esqlite_command *cmd = NULL; - ErlNifPid pid; + esqlite_statement *stmt; + esqlite_command *cmd = NULL; + ErlNifPid pid; - if(argc != 3) - return enif_make_badarg(env); - if(!enif_get_resource(env, argv[0], esqlite_statement_type, (void **) &stmt)) - return enif_make_badarg(env); - if(!enif_is_ref(env, argv[1])) - return make_error_tuple(env, "invalid_ref"); - if(!enif_get_local_pid(env, argv[2], &pid)) - return make_error_tuple(env, "invalid_pid"); + if(argc != 3) + return enif_make_badarg(env); + if(!enif_get_resource(env, argv[0], esqlite_statement_type, (void **) &stmt)) + return enif_make_badarg(env); + if(!enif_is_ref(env, argv[1])) + return make_error_tuple(env, "invalid_ref"); + if(!enif_get_local_pid(env, argv[2], &pid)) + return make_error_tuple(env, "invalid_pid"); - if(!stmt->statement) - return make_error_tuple(env, "no_prepared_statement"); + if(!stmt->statement) + return make_error_tuple(env, "no_prepared_statement"); - cmd = command_create(); - if(!cmd) - return make_error_tuple(env, "command_create_failed"); + cmd = command_create(); + if(!cmd) + return make_error_tuple(env, "command_create_failed"); - cmd->type = cmd_column_names; - cmd->ref = enif_make_copy(cmd->env, argv[1]); - cmd->pid = pid; - cmd->stmt = stmt->statement; + cmd->type = cmd_column_names; + cmd->ref = enif_make_copy(cmd->env, argv[1]); + cmd->pid = pid; + cmd->stmt = stmt->statement; - if(!stmt->connection) - return make_error_tuple(env, "no_connection"); - if(!stmt->connection->commands) - return make_error_tuple(env, "no_command_queue"); - - if(!queue_push(stmt->connection->commands, cmd)) - return make_error_tuple(env, "command_push_failed"); - - return make_atom(env, "ok"); + if(!stmt->connection) + return make_error_tuple(env, "no_connection"); + if(!stmt->connection->commands) + return make_error_tuple(env, "no_command_queue"); + if(!queue_push(stmt->connection->commands, cmd)) + return make_error_tuple(env, "command_push_failed"); + return make_atom(env, "ok"); } /* @@ -761,32 +748,28 @@ esqlite_column_names(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) static ERL_NIF_TERM esqlite_close(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { - esqlite_connection *conn; - esqlite_command *cmd = NULL; - ErlNifPid pid; + esqlite_connection *conn; + esqlite_command *cmd = NULL; + ErlNifPid pid; - if(!enif_get_resource(env, argv[0], esqlite_connection_type, (void **) &conn)) - return enif_make_badarg(env); + if(!enif_get_resource(env, argv[0], esqlite_connection_type, (void **) &conn)) + return enif_make_badarg(env); + if(!enif_is_ref(env, argv[1])) + return make_error_tuple(env, "invalid_ref"); + if(!enif_get_local_pid(env, argv[2], &pid)) + return make_error_tuple(env, "invalid_pid"); - if(!enif_is_ref(env, argv[1])) - return make_error_tuple(env, "invalid_ref"); + cmd = command_create(); + if(!cmd) + return make_error_tuple(env, "command_create_failed"); - if(!enif_get_local_pid(env, argv[2], &pid)) - return make_error_tuple(env, "invalid_pid"); + cmd->type = cmd_close; + cmd->ref = enif_make_copy(cmd->env, argv[1]); + cmd->pid = pid; + if(!queue_push(conn->commands, cmd)) + return make_error_tuple(env, "command_push_failed"); - cmd = command_create(); - if(!cmd) - return make_error_tuple(env, "command_create_failed"); - - /* Push the close command on the queue - */ - cmd->type = cmd_close; - cmd->ref = enif_make_copy(cmd->env, argv[1]); - cmd->pid = pid; - if(!queue_push(conn->commands, cmd)) - return make_error_tuple(env, "command_push_failed"); - - return make_atom(env, "ok"); + return make_atom(env, "ok"); } /* @@ -795,33 +778,33 @@ esqlite_close(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) static int on_load(ErlNifEnv* env, void** priv, ERL_NIF_TERM info) { - ErlNifResourceType *rt; + ErlNifResourceType *rt; - rt = enif_open_resource_type(env, "esqlite3_nif", "esqlite_connection_type", - destruct_esqlite_connection, ERL_NIF_RT_CREATE, NULL); - if(!rt) - return -1; - esqlite_connection_type = rt; + rt = enif_open_resource_type(env, "esqlite3_nif", "esqlite_connection_type", + destruct_esqlite_connection, ERL_NIF_RT_CREATE, NULL); + if(!rt) + return -1; + esqlite_connection_type = rt; - rt = enif_open_resource_type(env, "esqlite3_nif", "esqlite_statement_type", + rt = enif_open_resource_type(env, "esqlite3_nif", "esqlite_statement_type", destruct_esqlite_statement, ERL_NIF_RT_CREATE, NULL); - if(!rt) - return -1; - esqlite_statement_type = rt; + if(!rt) + return -1; + esqlite_statement_type = rt; - return 0; + return 0; } static ErlNifFunc nif_funcs[] = { - {"start", 0, esqlite_start}, - {"open", 4, esqlite_open}, - {"exec", 4, esqlite_exec}, - {"prepare", 4, esqlite_prepare}, - {"step", 3, esqlite_step}, - // {"esqlite_bind", 3, esqlite_bind_named}, - {"bind", 4, esqlite_bind}, - {"column_names", 3, esqlite_column_names}, - {"close", 3, esqlite_close} + {"start", 0, esqlite_start}, + {"open", 4, esqlite_open}, + {"exec", 4, esqlite_exec}, + {"prepare", 4, esqlite_prepare}, + {"step", 3, esqlite_step}, + // TODO: {"esqlite_bind", 3, esqlite_bind_named}, + {"bind", 4, esqlite_bind}, + {"column_names", 3, esqlite_column_names}, + {"close", 3, esqlite_close} }; ERL_NIF_INIT(esqlite3_nif, nif_funcs, on_load, NULL, NULL, NULL); diff --git a/c_src/queue.c b/c_src/queue.c index 7214ec6..685e9c8 100644 --- a/c_src/queue.c +++ b/c_src/queue.c @@ -10,8 +10,8 @@ struct qitem_t { - struct qitem_t* next; - void* data; + struct qitem_t* next; + void* data; }; typedef struct qitem_t qitem; @@ -32,8 +32,7 @@ queue_create() queue *ret; ret = (queue *) enif_alloc(sizeof(struct queue_t)); - if(ret == NULL) - goto error; + if(ret == NULL) goto error; ret->lock = NULL; ret->cond = NULL; @@ -43,22 +42,20 @@ queue_create() ret->length = 0; ret->lock = enif_mutex_create("queue_lock"); - if(ret->lock == NULL) - goto error; + if(ret->lock == NULL) goto error; ret->cond = enif_cond_create("queue_cond"); - if(ret->cond == NULL) - goto error; + if(ret->cond == NULL) goto error; return ret; error: if(ret->lock != NULL) - enif_mutex_destroy(ret->lock); + enif_mutex_destroy(ret->lock); if(ret->cond != NULL) - enif_cond_destroy(ret->cond); + enif_cond_destroy(ret->cond); if(ret != NULL) - enif_free(ret); + enif_free(ret); return NULL; } @@ -104,7 +101,7 @@ queue_push(queue *queue, void *item) { qitem * entry = (qitem *) enif_alloc(sizeof(struct qitem_t)); if(entry == NULL) - return 0; + return 0; entry->data = item; entry->next = NULL; @@ -114,16 +111,12 @@ queue_push(queue *queue, void *item) assert(queue->length >= 0 && "Invalid queue size at push"); if(queue->tail != NULL) - { queue->tail->next = entry; - } queue->tail = entry; if(queue->head == NULL) - { queue->head = queue->tail; - } queue->length += 1; @@ -144,9 +137,7 @@ queue_pop(queue *queue) /* Wait for an item to become available. */ while(queue->head == NULL) - { enif_cond_wait(queue->cond, queue->lock); - } assert(queue->length >= 0 && "Invalid queue size at pop."); @@ -157,8 +148,7 @@ queue_pop(queue *queue) queue->head = entry->next; entry->next = NULL; - if(queue->head == NULL) - { + if(queue->head == NULL) { assert(queue->tail == entry && "Invalid queue state: Bad tail."); queue->tail = NULL; } @@ -194,9 +184,7 @@ queue_receive(queue *queue) /* Wait for an item to become available. */ while(queue->message == NULL) - { enif_cond_wait(queue->cond, queue->lock); - } item = queue->message; queue->message = NULL; diff --git a/src/esqlite3.erl b/src/esqlite3.erl index c426c51..4444b3b 100644 --- a/src/esqlite3.erl +++ b/src/esqlite3.erl @@ -22,14 +22,14 @@ %% higher-level export -export([open/1, open/2, - exec/2, exec/3, - prepare/2, prepare/3, - step/1, step/2, - bind/2, bind/3, - fetchone/1, - fetchall/1, - column_names/1, column_names/2, - close/1, close/2]). + exec/2, exec/3, + prepare/2, prepare/3, + step/1, step/2, + bind/2, bind/3, + fetchone/1, + fetchall/1, + column_names/1, column_names/2, + close/1, close/2]). -export([q/2, q/3, map/3, foreach/3]). @@ -50,10 +50,10 @@ open(Filename, Timeout) -> Ref = make_ref(), ok = esqlite3_nif:open(Connection, Ref, self(), Filename), case receive_answer(Ref, Timeout) of - ok -> - {ok, Connection}; - Other -> - {error, Other} + ok -> + {ok, Connection}; + Other -> + {error, Other} end. %% @doc Execute a sql statement, returns a list with tuples. @@ -82,50 +82,50 @@ foreach(F, Sql, Connection) -> %% foreach_s(F, Statement) when is_function(F, 1) -> case try_step(Statement, 0) of - '$done' -> ok; - Row when is_tuple(Row) -> - F(Row), - foreach_s(F, Statement) + '$done' -> ok; + Row when is_tuple(Row) -> + F(Row), + foreach_s(F, Statement) end; foreach_s(F, Statement) when is_function(F, 2) -> ColumnNames = column_names(Statement), case try_step(Statement, 0) of - '$done' -> ok; - Row when is_tuple(Row) -> - F(ColumnNames, Row), - foreach_s(F, Statement) + '$done' -> ok; + Row when is_tuple(Row) -> + F(ColumnNames, Row), + foreach_s(F, Statement) end. %% map_s(F, Statement) when is_function(F, 1) -> case try_step(Statement, 0) of - '$done' -> []; - Row when is_tuple(Row) -> - [F(Row) | map_s(F, Statement)] + '$done' -> []; + Row when is_tuple(Row) -> + [F(Row) | map_s(F, Statement)] end; map_s(F, Statement) when is_function(F, 2) -> ColumnNames = column_names(Statement), case try_step(Statement, 0) of - '$done' -> []; - Row when is_tuple(Row) -> - [F(ColumnNames, Row) | map_s(F, Statement)] + '$done' -> []; + Row when is_tuple(Row) -> + [F(ColumnNames, Row) | map_s(F, Statement)] end. %% fetchone(Statement) -> case try_step(Statement, 0) of - '$done' -> ok; - Row when is_tuple(Row) -> - Row + '$done' -> ok; + Row when is_tuple(Row) -> + Row end. %% fetchall(Statement) -> case try_step(Statement, 0) of - '$done' -> - []; - Row when is_tuple(Row) -> - [Row | fetchall(Statement)] + '$done' -> + []; + Row when is_tuple(Row) -> + [Row | fetchall(Statement)] end. %% Try the step, when the database is busy, @@ -133,13 +133,13 @@ try_step(_Statement, Tries) when Tries > 5 -> throw(too_many_tries); try_step(Statement, Tries) -> case esqlite3:step(Statement) of - '$busy' -> - timer:sleep(100 * Tries), - try_step(Statement, Tries + 1); - Something -> - Something + '$busy' -> + timer:sleep(100 * Tries), + try_step(Statement, Tries + 1); + Something -> + Something end. - + %% @doc Execute Sql statement, returns the number of affected rows. %% %% @spec exec(iolist(), connection()) -> integer() | {error, error_message()} @@ -226,12 +226,12 @@ add_eos(IoList) -> receive_answer(Ref, Timeout) -> receive - {Ref, Resp} -> - Resp; - Other -> - throw(Other) + {Ref, Resp} -> + Resp; + Other -> + throw(Other) after Timeout -> - throw({error, timeout, Ref}) + throw({error, timeout, Ref}) end. diff --git a/src/esqlite3_nif.erl b/src/esqlite3_nif.erl index 8fdc38e..8bfdfd9 100644 --- a/src/esqlite3_nif.erl +++ b/src/esqlite3_nif.erl @@ -22,14 +22,14 @@ %% low-level exports -export([start/0, - open/4, - exec/4, - prepare/4, - step/3, - finalize/3, - bind/4, - column_names/3, - close/3 + open/4, + exec/4, + prepare/4, + step/3, + finalize/3, + bind/4, + column_names/3, + close/3 ]). -on_load(init/0).