From 47ef78b5ed53604e2629d33a549993a4bffe9a32 Mon Sep 17 00:00:00 2001 From: Alexey Romanov Date: Mon, 13 Oct 2014 09:53:14 +0400 Subject: [PATCH] Formatting --- c_src/sqlite3_drv.c | 195 ++++++++++++++++++++---------------------- c_src/sqlite3_drv.h | 2 +- src/sqlite3.erl | 50 +++++------ src/sqlite3_lib.erl | 66 +++++++------- test/sqlite3_test.erl | 108 +++++++++++------------ 5 files changed, 207 insertions(+), 214 deletions(-) diff --git a/c_src/sqlite3_drv.c b/c_src/sqlite3_drv.c index 8963da6..59319d7 100644 --- a/c_src/sqlite3_drv.c +++ b/c_src/sqlite3_drv.c @@ -4,7 +4,7 @@ // MSVC needs "__inline" instead of "inline" in C-source files. #if defined(_MSC_VER) -# define inline __inline +#define inline __inline #endif #ifdef DEBUG @@ -75,8 +75,7 @@ static inline int sql_is_insert(const char *sql) { int i; char *insert = "insert"; for (i = 0; i < 6; i++) { - if ((tolower(sql[i]) != insert[i]) && (sql[i] != ' ')) - return 0; + if ((tolower(sql[i]) != insert[i]) && (sql[i] != ' ')) { return 0; } } return 1; } @@ -87,37 +86,37 @@ static void fprint_dataset(FILE* log, ErlDrvTermData* dataset, int term_count); // required because driver_free(_binary) are macros in Windows static void driver_free_fun(void *ptr) { - driver_free(ptr); + driver_free(ptr); } static void driver_free_binary_fun(void *ptr) { - driver_free_binary((ErlDrvBinary *) ptr); + driver_free_binary((ErlDrvBinary *) ptr); } static ErlDrvEntry sqlite3_driver_entry = { - NULL, /* init */ - start, /* startup (defined below) */ - stop, /* shutdown (defined below) */ - NULL, /* output */ - NULL, /* ready_input */ - NULL, /* ready_output */ - "sqlite3_drv", /* the name of the driver */ - NULL, /* finish */ - NULL, /* handle */ - control, /* control */ - NULL, /* timeout */ - NULL, /* outputv */ - ready_async, /* ready_async (defined below) */ - NULL, /* flush */ - NULL, /* call */ - NULL, /* event */ - ERL_DRV_EXTENDED_MARKER, /* ERL_DRV_EXTENDED_MARKER */ - ERL_DRV_EXTENDED_MAJOR_VERSION, /* ERL_DRV_EXTENDED_MAJOR_VERSION */ - ERL_DRV_EXTENDED_MINOR_VERSION, /* ERL_DRV_EXTENDED_MINOR_VERSION */ - ERL_DRV_FLAG_USE_PORT_LOCKING, /* ERL_DRV_FLAGs */ - NULL /* handle2 */, - NULL /* process_exit */, - NULL /* stop_select */ + NULL, /* init */ + start, /* startup (defined below) */ + stop, /* shutdown (defined below) */ + NULL, /* output */ + NULL, /* ready_input */ + NULL, /* ready_output */ + "sqlite3_drv", /* the name of the driver */ + NULL, /* finish */ + NULL, /* handle */ + control, /* control */ + NULL, /* timeout */ + NULL, /* outputv */ + ready_async, /* ready_async (defined below) */ + NULL, /* flush */ + NULL, /* call */ + NULL, /* event */ + ERL_DRV_EXTENDED_MARKER, /* ERL_DRV_EXTENDED_MARKER */ + ERL_DRV_EXTENDED_MAJOR_VERSION, /* ERL_DRV_EXTENDED_MAJOR_VERSION */ + ERL_DRV_EXTENDED_MINOR_VERSION, /* ERL_DRV_EXTENDED_MINOR_VERSION */ + ERL_DRV_FLAG_USE_PORT_LOCKING, /* ERL_DRV_FLAGs */ + NULL /* handle2 */, + NULL /* process_exit */, + NULL /* stop_select */ }; DRIVER_INIT(sqlite3_driver) { @@ -204,29 +203,27 @@ static ErlDrvData start(ErlDrvPort port, char* cmd) { // Driver Stop static void stop(ErlDrvData handle) { - sqlite3_drv_t* driver_data = (sqlite3_drv_t*) handle; + sqlite3_drv_t* drv = (sqlite3_drv_t*) handle; unsigned int i; int close_result; - if (driver_data->prepared_stmts) { - for (i = 0; i < driver_data->prepared_count; i++) { - sqlite3_finalize(driver_data->prepared_stmts[i]); + if (drv->prepared_stmts) { + for (i = 0; i < drv->prepared_count; i++) { + sqlite3_finalize(drv->prepared_stmts[i]); } - driver_free(driver_data->prepared_stmts); + driver_free(drv->prepared_stmts); } - close_result = sqlite3_close(driver_data->db); + close_result = sqlite3_close(drv->db); if (close_result != SQLITE_OK) { - //ERROR((driver_data->log, - // "ERROR: Failed to close DB, some resources aren't finalized!")); - fprintf(stderr, "ERROR: Failed to close DB, some resources aren't finalized!\n"); + fprintf(stderr, "Failed to close DB %s, some resources aren't finalized!", sqlite3_db_filename(drv->db, "main")); } - if (driver_data->log && (driver_data->log != stderr)) { - fclose(driver_data->log); + if (drv->log && (drv->log != stderr)) { + fclose(drv->log); } - driver_free(driver_data); + driver_free(drv); } static inline int output_error(sqlite3_drv_t *drv, int error_code, const char *error); @@ -235,46 +232,46 @@ static inline int output_error(sqlite3_drv_t *drv, int error_code, const char *e static ErlDrvSSizeT control( ErlDrvData drv_data, unsigned int command, char *buf, ErlDrvSizeT len, char **rbuf, ErlDrvSizeT rlen) { - sqlite3_drv_t* driver_data = (sqlite3_drv_t*) drv_data; + sqlite3_drv_t* drv = (sqlite3_drv_t*) drv_data; if (len > INT_MAX) { - output_error(driver_data, SQLITE_MISUSE, "Command size doesn't fit into int type"); + output_error(drv, SQLITE_MISUSE, "Command size doesn't fit into int type"); } else { switch (command) { case CMD_SQL_EXEC: - sql_exec(driver_data, buf, (int) len); + sql_exec(drv, buf, (int) len); break; case CMD_SQL_BIND_AND_EXEC: - sql_bind_and_exec(driver_data, buf, (int) len); + sql_bind_and_exec(drv, buf, (int) len); break; case CMD_PREPARE: - prepare(driver_data, buf, (int) len); + prepare(drv, buf, (int) len); break; case CMD_PREPARED_BIND: - prepared_bind(driver_data, buf, (int) len); + prepared_bind(drv, buf, (int) len); break; case CMD_PREPARED_STEP: - prepared_step(driver_data, buf, (int) len); + prepared_step(drv, buf, (int) len); break; case CMD_PREPARED_RESET: - prepared_reset(driver_data, buf, (int) len); + prepared_reset(drv, buf, (int) len); break; case CMD_PREPARED_CLEAR_BINDINGS: - prepared_clear_bindings(driver_data, buf, (int) len); + prepared_clear_bindings(drv, buf, (int) len); break; case CMD_PREPARED_FINALIZE: - prepared_finalize(driver_data, buf, (int) len); + prepared_finalize(drv, buf, (int) len); break; case CMD_PREPARED_COLUMNS: - prepared_columns(driver_data, buf, (int) len); + prepared_columns(drv, buf, (int) len); break; case CMD_SQL_EXEC_SCRIPT: - sql_exec_script(driver_data, buf, (int) len); + sql_exec_script(drv, buf, (int) len); break; case CMD_ENABLE_LOAD_EXTENSION: - enable_load_extension(driver_data, buf, (int) len); + enable_load_extension(drv, buf, (int) len); break; default: - unknown(driver_data, buf, (int) len); + unknown(drv, buf, (int) len); } } return 0; @@ -295,7 +292,7 @@ static inline int return_error( ERL_DRV_TUPLE, (ErlDrvTermData) 3); // int i; // for (i = 0; i < *term_count_p; i++) { -// printf("%d\n", (*dataset_p)[i]); +// printf("%d\n", (*dataset_p)[i]); // } return 0; } @@ -333,7 +330,7 @@ static inline int output_ok(sqlite3_drv_t *drv) { ERL_DRV_ATOM, drv->atom_ok, ERL_DRV_TUPLE, 2 }; - return + return #ifdef PRE_R16B driver_output_term(drv->port, #else @@ -362,7 +359,7 @@ static int enable_load_extension(sqlite3_drv_t* drv, char *buf, int len) { static inline async_sqlite3_command *make_async_command_statement( sqlite3_drv_t *drv, sqlite3_stmt *statement, int finalize) { 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)); result->driver_data = drv; @@ -375,7 +372,7 @@ static inline async_sqlite3_command *make_async_command_statement( static inline async_sqlite3_command *make_async_command_script( sqlite3_drv_t *drv, char *script, int script_length) { async_sqlite3_command *result = - (async_sqlite3_command *) driver_alloc(sizeof(async_sqlite3_command)); + (async_sqlite3_command *) driver_alloc(sizeof(async_sqlite3_command)); char *script_copy = driver_alloc(sizeof(char) * script_length); memset(result, 0, sizeof(async_sqlite3_command)); memcpy(script_copy, script, sizeof(char) * script_length); @@ -464,8 +461,7 @@ static inline int decode_and_bind_param( ei_decode_atom(buffer, p_index, char_buf_val); if (strncmp(char_buf_val, "null", 5) == 0) { result = sqlite3_bind_null(statement, param_index); - } - else { + } else { output_error(drv, SQLITE_MISUSE, "Non-null atom as parameter"); return 1; } @@ -518,6 +514,7 @@ static int bind_parameters( long param_index_long; char param_name[MAXATOMLEN + 1]; // parameter names shouldn't be longer than 256! char *acc_string; + result = ei_decode_list_header(buffer, p_index, &cur_list_size); if (result) { // probably all parameters are integers between 0 and 255 @@ -535,11 +532,13 @@ static int bind_parameters( driver_free(acc_string); return 0; } + for (i = 0; i < cur_list_size; i++) { if (*p_index >= buffer_size) { return output_error(drv, SQLITE_ERROR, "error while binding parameters"); } + ei_get_type(buffer, p_index, p_type, p_size); if (*p_type == ERL_SMALL_TUPLE_EXT) { int old_index = *p_index; @@ -567,8 +566,7 @@ static int bind_parameters( *p_index = old_index; param_indices_are_explicit = 0; goto IMPLICIT_INDEX; // yuck - } - else { + } else { param_index = sqlite3_bind_parameter_index(statement, param_name); } break; @@ -582,12 +580,11 @@ static int bind_parameters( param_index = sqlite3_bind_parameter_index(statement, param_name); break; default: - return output_error( - drv, SQLITE_MISMATCH, - "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, p_index, statement, param_index, p_type, p_size); + drv, buffer, p_index, statement, param_index, p_type, p_size); if (result != SQLITE_OK) { return result; // error has already been output } @@ -595,13 +592,12 @@ static int bind_parameters( else { IMPLICIT_INDEX: if (param_indices_are_explicit) { - return output_error( - drv, SQLITE_MISUSE, - "parameters without indices shouldn't follow indexed or named parameters"); + return output_error(drv, SQLITE_MISUSE, + "parameters without indices shouldn't follow indexed or named parameters"); } result = decode_and_bind_param( - drv, buffer, p_index, statement, param_index, p_type, p_size); + drv, buffer, p_index, statement, param_index, p_type, p_size); if (result != SQLITE_OK) { return result; // error has already been output } @@ -683,7 +679,7 @@ static int sql_bind_and_exec(sqlite3_drv_t *drv, char *buffer, int buffer_size) static void sql_free_async(void *_async_command) { async_sqlite3_command *async_command = - (async_sqlite3_command *) _async_command; + (async_sqlite3_command *) _async_command; driver_free(async_command->dataset); async_command->driver_data->async_handle = 0; @@ -722,7 +718,7 @@ static int sql_exec_one_statement( append_to_dataset(2, *dataset_p, *term_count_p, ERL_DRV_ATOM, drv->atom_columns); base_term_count = *term_count_p; get_columns( - drv, statement, column_count, base_term_count, term_count_p, term_allocated_p, ptrs_p, dataset_p); + drv, statement, column_count, base_term_count, term_count_p, term_allocated_p, ptrs_p, dataset_p); EXTEND_DATASET_PTR(4); append_to_dataset(4, *dataset_p, base_term_count + column_count * 3 + 7, ERL_DRV_TUPLE, (ErlDrvTermData) 2, ERL_DRV_ATOM, drv->atom_rows); @@ -794,15 +790,15 @@ static int sql_exec_one_statement( } if (next_row != SQLITE_DONE) { - 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) { + 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) { @@ -842,8 +838,7 @@ static int sql_exec_one_statement( } 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 = NULL; int result; @@ -906,8 +901,7 @@ static void sql_exec_async(void *_async_command) { } static void sql_step_async(void *_async_command) { - async_sqlite3_command *async_command = - (async_sqlite3_command *) _async_command; + async_sqlite3_command *async_command = (async_sqlite3_command *) _async_command; int term_count = 0; int term_allocated = 0; ErlDrvTermData *dataset = NULL; @@ -1024,11 +1018,10 @@ POPULATE_COMMAND: } static void ready_async(ErlDrvData drv_data, ErlDrvThreadData thread_data) { - async_sqlite3_command *async_command = - (async_sqlite3_command *) thread_data; + async_sqlite3_command *async_command = (async_sqlite3_command *) thread_data; sqlite3_drv_t *drv = async_command->driver_data; - int res = + int res = #ifdef PRE_R16B driver_output_term(drv->port, #else @@ -1063,10 +1056,10 @@ static int prepare(sqlite3_drv_t *drv, char *command, int command_size) { if (drv->prepared_count >= drv->prepared_alloc) { drv->prepared_alloc = - (drv->prepared_alloc != 0) ? 2*drv->prepared_alloc : 4; + (drv->prepared_alloc != 0) ? 2*drv->prepared_alloc : 4; drv->prepared_stmts = - driver_realloc(drv->prepared_stmts, - drv->prepared_alloc * sizeof(sqlite3_stmt *)); + driver_realloc(drv->prepared_stmts, + drv->prepared_alloc * sizeof(sqlite3_stmt *)); } drv->prepared_stmts[drv->prepared_count] = statement; drv->prepared_count++; @@ -1077,7 +1070,7 @@ static int prepare(sqlite3_drv_t *drv, char *command, int command_size) { spec[3] = drv->prepared_count - 1; spec[4] = ERL_DRV_TUPLE; spec[5] = 2; - return + return #ifdef PRE_R16B driver_output_term(drv->port, #else @@ -1108,7 +1101,7 @@ static int prepared_bind(sqlite3_drv_t *drv, char *buffer, int buffer_size) { statement = drv->prepared_stmts[prepared_index]; result = - bind_parameters(drv, buffer, buffer_size, &index, statement, &type, &size); + bind_parameters(drv, buffer, buffer_size, &index, statement, &type, &size); if (result == SQLITE_OK) { return output_ok(drv); } else { @@ -1146,7 +1139,7 @@ static int prepared_columns(sqlite3_drv_t *drv, char *buffer, int buffer_size) { column_count = sqlite3_column_count(statement); get_columns( - drv, statement, column_count, 2, &term_count, &term_allocated, &ptrs, &dataset); + drv, statement, column_count, 2, &term_count, &term_allocated, &ptrs, &dataset); EXTEND_DATASET_DIRECT(2); append_to_dataset(2, dataset, term_count, ERL_DRV_TUPLE, (ErlDrvTermData) 2); @@ -1270,15 +1263,15 @@ static int prepared_finalize(sqlite3_drv_t *drv, char *buffer, int buffer_size) // Unknown Command static int unknown(sqlite3_drv_t *drv, char *command, int command_size) { - // Return {Port, error, unknown_command} + // Return {Port, error, -1, unknown_command} ErlDrvTermData spec[] = { - ERL_DRV_PORT, driver_mk_port(drv->port), - ERL_DRV_ATOM, drv->atom_error, - ERL_DRV_INT, (ErlDrvTermData) ((ErlDrvSInt) -1), - ERL_DRV_ATOM, drv->atom_unknown_cmd, - ERL_DRV_TUPLE, 4 + ERL_DRV_PORT, driver_mk_port(drv->port), + ERL_DRV_ATOM, drv->atom_error, + ERL_DRV_INT, (ErlDrvTermData) ((ErlDrvSInt) -1), + ERL_DRV_ATOM, drv->atom_unknown_cmd, + ERL_DRV_TUPLE, 4 }; - return + return #ifdef PRE_R16B driver_output_term(drv->port, #else diff --git a/c_src/sqlite3_drv.h b/c_src/sqlite3_drv.h index 98d1ab9..ea7bdd3 100644 --- a/c_src/sqlite3_drv.h +++ b/c_src/sqlite3_drv.h @@ -106,7 +106,7 @@ typedef struct async_sqlite3_command { static ErlDrvData start(ErlDrvPort port, char* cmd); static void stop(ErlDrvData handle); static ErlDrvSSizeT control(ErlDrvData drv_data, unsigned int command, char *buf, - ErlDrvSizeT len, char **rbuf, ErlDrvSizeT rlen); + ErlDrvSizeT len, char **rbuf, ErlDrvSizeT rlen); static int sql_exec(sqlite3_drv_t *drv, char *buf, int len); static int sql_bind_and_exec(sqlite3_drv_t *drv, char *buf, int len); static int sql_exec_script(sqlite3_drv_t *drv, char *buf, int len); diff --git a/src/sqlite3.erl b/src/sqlite3.erl index 38acb72..ac41edb 100644 --- a/src/sqlite3.erl +++ b/src/sqlite3.erl @@ -100,11 +100,11 @@ open(DbName) -> %% @doc %% Opens a sqlite3 database creating one if necessary. By default the database %% will be called DbName.db in the current path (unless Db is 'anonymous', see below). -%% This can be changed by passing the option {file, DbFile :: string()}. DbFile +%% This can be changed by passing the option {file, DbFile :: string()}. DbFile %% must be the full path to the sqlite3 db file. Can be used to open multiple sqlite3 %% databases per node. Must be use in conjunction with stop/1, sql_exec/2, %% create_table/3, list_tables/1, table_info/2, write/3, read/3, delete/3 -%% and drop_table/2. If the name is an atom other than 'anonymous', it's used for +%% and drop_table/2. If the name is an atom other than 'anonymous', it's used for %% registering the gen_server and must be unique. If the name is 'anonymous', %% the process isn't registered. %% @end @@ -477,7 +477,7 @@ write(Db, Tbl, Data) -> %% @end %%-------------------------------------------------------------------- -spec write_timeout(db(), table_id(), [{column_id(), sql_value()}], timeout()) -> - sql_non_query_result(). + sql_non_query_result(). write_timeout(Db, Tbl, Data, Timeout) -> gen_server:call(Db, {write, Tbl, Data}, Timeout). @@ -508,7 +508,7 @@ write_many(Db, Tbl, Data) -> %% @end %%-------------------------------------------------------------------- -spec write_many_timeout(db(), table_id(), [[{column_id(), sql_value()}]], timeout()) -> - [sql_result()]. + [sql_result()]. write_many_timeout(Db, Tbl, Data, Timeout) -> gen_server:call(Db, {write_many, Tbl, Data}, Timeout). @@ -519,7 +519,7 @@ write_many_timeout(Db, Tbl, Data, Timeout) -> %% @end %%-------------------------------------------------------------------- -spec update(table_id(), {column_id(), sql_value()}, [{column_id(), sql_value()}]) -> - sql_non_query_result(). + sql_non_query_result(). update(Tbl, {Key, Value}, Data) -> update(?MODULE, Tbl, {Key, Value}, Data). @@ -875,8 +875,8 @@ handle_call({write, Tbl, Data}, _From, State) -> {reply, {error, Exception}, State} end; handle_call({write_many, Tbl, DataList}, _From, State) -> - SQLScript = ["SAVEPOINT 'erlang-sqlite3-write_many';", - [sqlite3_lib:write_sql(Tbl, Data) || Data <- DataList], + SQLScript = ["SAVEPOINT 'erlang-sqlite3-write_many';", + [sqlite3_lib:write_sql(Tbl, Data) || Data <- DataList], "RELEASE SAVEPOINT 'erlang-sqlite3-write_many';"], Reply = do_sql_exec_script(SQLScript, State), {reply, Reply, State}; @@ -1106,7 +1106,7 @@ exec(Port, {bind, Index, Params}) -> exec(Port, {enable_load_extension, Value}) -> % Payload is 1 if enabling extension loading, % 0 if disabling - Payload = case Value of + Payload = case Value of true -> 1; _ when is_integer(Value) -> Value; false -> 0; @@ -1137,10 +1137,10 @@ wait_result(Port) -> end. parse_table_info(Info) -> - Info1 = re:replace(Info, <<"CHECK \\('(bin|lst|am)'='(bin|lst|am)'\\)\\)">>, "", [{return, list}]), + Info1 = re:replace(Info, <<"CHECK \\('(bin|lst|am)'='(bin|lst|am)'\\)\\)">>, "", [{return, list}]), {_, [$(|Rest]} = lists:splitwith(fun(C) -> C =/= $( end, Info1), - %% remove ) at the end - Rest1 = list_init(Rest), + %% remove ) at the end + Rest1 = list_init(Rest), Cols = string:tokens(Rest1, ","), build_table_info(lists:map(fun(X) -> string:tokens(X, " ") @@ -1159,14 +1159,14 @@ build_constraints(["PRIMARY", "KEY" | Tail]) -> {Constraint, Rest} = build_primary_key_constraint(Tail), [Constraint | build_constraints(Rest)]; build_constraints(["UNIQUE" | Tail]) -> - [unique | build_constraints(Tail)]; + [unique | build_constraints(Tail)]; build_constraints(["NOT", "NULL" | Tail]) -> - [not_null | build_constraints(Tail)]; + [not_null | build_constraints(Tail)]; build_constraints(["DEFAULT", DefaultValue | Tail]) -> - [{default, sqlite3_lib:sql_to_value(DefaultValue)} | build_constraints(Tail)]; + [{default, sqlite3_lib:sql_to_value(DefaultValue)} | build_constraints(Tail)]; build_constraints(["CHECK", _ | Tail]) -> - %% currently ignored - build_constraints(Tail). + %% currently ignored + build_constraints(Tail). % build_constraints(["REFERENCES", Check | Tail]) -> ... build_primary_key_constraint(Tokens) -> build_primary_key_constraint(Tokens, []). @@ -1184,15 +1184,15 @@ build_primary_key_constraint(Tail, Acc) -> cast_table_name(Bin, SQL) -> case re:run(SQL,<<"CHECK \\('(bin|lst|am)'='(bin|lst|am)'\\)\\)">>,[{capture,all_but_first,binary}]) of - {match, [<<"bin">>, <<"bin">>]} -> - Bin; - {match, [<<"lst">>, <<"lst">>]} -> - unicode:characters_to_list(Bin, latin1); - {match, [<<"am">>, <<"am">>]} -> - binary_to_atom(Bin, latin1); - _ -> - %% backwards compatible - binary_to_atom(Bin, latin1) + {match, [<<"bin">>, <<"bin">>]} -> + Bin; + {match, [<<"lst">>, <<"lst">>]} -> + unicode:characters_to_list(Bin, latin1); + {match, [<<"am">>, <<"am">>]} -> + binary_to_atom(Bin, latin1); + _ -> + %% backwards compatible + binary_to_atom(Bin, latin1) end. list_init([_]) -> []; diff --git a/src/sqlite3_lib.erl b/src/sqlite3_lib.erl index 7a4aa6a..7f543d1 100644 --- a/src/sqlite3_lib.erl +++ b/src/sqlite3_lib.erl @@ -1,7 +1,7 @@ %%%------------------------------------------------------------------- %%% File : sqlite3_lib.erl %%% @author Tee Teoh -%%% @copyright 21 Jun 2008 by Tee Teoh +%%% @copyright 21 Jun 2008 by Tee Teoh %%% @version 1.0.0 %%% @doc Library module for sqlite3 %%% @@ -15,7 +15,7 @@ -export([col_type_to_atom/1]). -export([value_to_sql/1, value_to_sql_unsafe/1, sql_to_value/1, escape/1, bin_to_hex/1]). -export([write_value_sql/1, write_col_sql/1]). --export([create_table_sql/2, create_table_sql/3, drop_table_sql/1]). +-export([create_table_sql/2, create_table_sql/3, drop_table_sql/1]). -export([add_columns_sql/2]). -export([write_sql/2, update_sql/4, update_set_sql/1, delete_sql/3]). -export([read_sql/1, read_sql/2, read_sql/3, read_sql/4, read_cols_sql/1]). @@ -61,12 +61,12 @@ col_type_to_atom(String) -> %%-------------------------------------------------------------------- -%% @doc +%% @doc %% Converts an Erlang term to an SQL string. -%% Currently supports integers, floats, 'null' atom, and iodata +%% Currently supports integers, floats, 'null' atom, and iodata %% (binaries and iolists) which are treated as SQL strings. %% -%% Note that it opens opportunity for injection if an iolist includes +%% Note that it opens opportunity for injection if an iolist includes %% single quotes! Replace all single quotes (') with '' manually, or %% use value_to_sql/1 if you are not sure if your strings contain %% single quotes (e.g. can be entered by users). @@ -86,9 +86,9 @@ value_to_sql_unsafe(X) -> end. %%-------------------------------------------------------------------- -%% @doc +%% @doc %% Converts an Erlang term to an SQL string. -%% Currently supports integers, floats, 'null' atom, and iodata +%% Currently supports integers, floats, 'null' atom, and iodata %% (binaries and iolists) which are treated as SQL strings. %% %% All single quotes (') will be replaced with ''. @@ -108,7 +108,7 @@ value_to_sql(X) -> end. %%-------------------------------------------------------------------- -%% @doc +%% @doc %% Converts an SQL value to an Erlang term. %% @end %%-------------------------------------------------------------------- @@ -130,7 +130,7 @@ sql_to_value(String) -> end. %%-------------------------------------------------------------------- -%% @doc +%% @doc %% Creates the values portion of the sql stmt. %% @end %%-------------------------------------------------------------------- @@ -163,7 +163,7 @@ escape(IoData) -> re:replace(IoData, "'", "''", [global, unicode]). bin_to_hex(Binary) -> << <<(half_byte_to_hex(X)):8>> || <> <= Binary>>. %%-------------------------------------------------------------------- -%% @doc +%% @doc %% Creates update set stmt. %% Currently supports integer, double/float and strings. %% @end @@ -172,7 +172,7 @@ bin_to_hex(Binary) -> << <<(half_byte_to_hex(X)):8>> || <> <= Binary>>. update_set_sql(Data) -> ColValueToSqlFun = fun({Col, Value}) -> - [atom_to_list(Col), " = ", value_to_sql(Value)] + [atom_to_list(Col), " = ", value_to_sql(Value)] end, map_intersperse(ColValueToSqlFun, Data, ", "). @@ -205,7 +205,7 @@ create_table_sql(Tbl, Columns, TblConstraints) -> {Type, TName} = encode_table_id(Tbl), ["CREATE TABLE ", TName, " (", map_intersperse(fun column_sql_for_create_table/1, Columns, ", "), ", ", - table_constraint_sql(TblConstraints), + table_constraint_sql(TblConstraints), ", CHECK ('", Type, "'='", Type, "'));"]. %%-------------------------------------------------------------------- @@ -219,16 +219,16 @@ add_columns_sql(Tbl, Columns) -> map_intersperse(fun column_sql_for_create_table/1, Columns, ", "),";"]. %%-------------------------------------------------------------------- -%% @doc -%% Using Key as the column name and Data as list of column names -%% and values pairs it creates the proper update SQL stmt for the +%% @doc +%% Using Key as the column name and Data as list of column names +%% and values pairs it creates the proper update SQL stmt for the %% record with matching Value. %% @end %%-------------------------------------------------------------------- -spec update_sql(table_id(), column_id(), sql_value(), [{column_id(), sql_value()}]) -> iolist(). update_sql(Tbl, Key, Value, Data) -> {_, TName} = encode_table_id(Tbl), - ["UPDATE ", TName, " SET ", update_set_sql(Data), + ["UPDATE ", TName, " SET ", update_set_sql(Data), " WHERE ", to_iolist(Key), " = ", value_to_sql(Value), ";"]. %%-------------------------------------------------------------------- @@ -239,7 +239,7 @@ update_sql(Tbl, Key, Value, Data) -> -spec write_sql(table_id(), [{column_id(), sql_value()}]) -> iolist(). write_sql(Tbl, Data) -> {Cols, Values} = lists:unzip(Data), - ["INSERT INTO ", to_iolist(Tbl), " (", write_col_sql(Cols), + ["INSERT INTO ", to_iolist(Tbl), " (", write_col_sql(Cols), ") values (", write_value_sql(Values), ");"]. %%-------------------------------------------------------------------- @@ -267,7 +267,7 @@ read_sql(Tbl, Columns) -> %%-------------------------------------------------------------------- -spec read_sql(table_id(), column_id(), sql_value()) -> iolist(). read_sql(Tbl, Key, Value) -> - ["SELECT * FROM ", to_iolist(Tbl), " WHERE ", to_iolist(Key), + ["SELECT * FROM ", to_iolist(Tbl), " WHERE ", to_iolist(Key), " = ", value_to_sql(Value), ";"]. %%-------------------------------------------------------------------- @@ -279,7 +279,7 @@ read_sql(Tbl, Key, Value) -> -spec read_sql(table_id(), column_id(), sql_value(), [column_id()]) -> iolist(). read_sql(Tbl, Key, Value, Columns) -> ["SELECT ", read_cols_sql(Columns), " FROM ", - to_iolist(Tbl), " WHERE ", to_iolist(Key), " = ", + to_iolist(Tbl), " WHERE ", to_iolist(Key), " = ", value_to_sql(Value), ";"]. %%-------------------------------------------------------------------- @@ -289,7 +289,7 @@ read_sql(Tbl, Key, Value, Columns) -> %%-------------------------------------------------------------------- -spec delete_sql(table_id(), column_id(), sql_value()) -> iolist(). delete_sql(Tbl, Key, Value) -> - ["DELETE FROM ", to_iolist(Tbl), " WHERE ", to_iolist(Key), + ["DELETE FROM ", to_iolist(Tbl), " WHERE ", to_iolist(Key), " = ", value_to_sql(Value), ";"]. %%-------------------------------------------------------------------- @@ -317,7 +317,7 @@ half_byte_to_hex(X) -> $a + X - 10. -spec sql_number(string()) -> number() | {error, not_a_number}. sql_number(NumberStr) -> case string:to_integer(NumberStr) of - {Int, []} -> + {Int, []} -> Int; _ -> case string:to_float(NumberStr) of @@ -330,15 +330,15 @@ sql_number(NumberStr) -> -spec sql_string(string()) -> binary(). sql_string(StringWithEscapedQuotes) -> - Res1 = re:replace(StringWithEscapedQuotes, "''", "'", + Res1 = re:replace(StringWithEscapedQuotes, "''", "'", [global, {return, binary}, unicode]), erlang:binary_part(Res1, 0, byte_size(Res1) - 1). -spec sql_blob(string()) -> binary(). sql_blob([$' | Tail]) -> hex_str_to_bin(Tail, <<>>). -hex_str_to_bin("'", Acc) -> - Acc; %% single quote at the end of blob literal +hex_str_to_bin("'", Acc) -> + Acc; %% single quote at the end of blob literal hex_str_to_bin([X, Y | Tail], Acc) -> hex_str_to_bin(Tail, <>). @@ -360,7 +360,7 @@ pk_constraint_sql(Constraint) -> constraint_sql(Constraint) -> case Constraint of primary_key -> "PRIMARY KEY"; - {primary_key, C} -> ["PRIMARY KEY ", pk_constraint_sql(C)]; + {primary_key, C} -> ["PRIMARY KEY ", pk_constraint_sql(C)]; unique -> "UNIQUE"; not_null -> "NOT NULL"; {default, DefaultValue} -> ["DEFAULT ", value_to_sql(DefaultValue)]; @@ -371,11 +371,11 @@ constraint_sql(Constraint) -> -spec table_constraint_sql(table_constraints()) -> iolist(). table_constraint_sql(TableConstraint) -> case TableConstraint of - {primary_key, Columns} -> - ["PRIMARY KEY(", + {primary_key, Columns} -> + ["PRIMARY KEY(", map_intersperse(fun indexed_column_sql/1, Columns, ", "), ")"]; - {unique, Columns} -> - ["UNIQUE(", + {unique, Columns} -> + ["UNIQUE(", map_intersperse(fun indexed_column_sql/1, Columns, ", "), ")"]; %% TODO: foreign key {raw, S} when is_list(S) -> S; @@ -406,7 +406,7 @@ to_iolist(B) when is_binary(B) -> %%-------------------------------------------------------------------- %% @type sql_value() = number() | 'null' | iodata(). -%% +%% %% Values accepted in SQL statements include numbers, atom 'null', %% and io:iolist(). %% @end @@ -418,7 +418,7 @@ to_iolist(B) when is_binary(B) -> -ifdef(TEST). -include_lib("eunit/include/eunit.hrl"). --define(assertFlat(Expected, Value), +-define(assertFlat(Expected, Value), ?assertEqual(iolist_to_binary(Expected), iolist_to_binary(Value))). quote_test() -> @@ -448,8 +448,8 @@ create_table_sql_test() -> create_table_sql("user", [{id, integer, [{primary_key, desc}]}, {name, text}])), ?assertFlat( "CREATE TABLE user (id INTEGER, name TEXT, PRIMARY KEY(id), CHECK ('am'='am'));", - create_table_sql(user, - [{id, integer}, {name, text}], + create_table_sql(user, + [{id, integer}, {name, text}], [{primary_key, [id]}])). update_sql_test() -> diff --git a/test/sqlite3_test.erl b/test/sqlite3_test.erl index bda4fb2..d281e25 100644 --- a/test/sqlite3_test.erl +++ b/test/sqlite3_test.erl @@ -11,7 +11,7 @@ %% API %% ==================================================================== %% -------------------------------------------------------------------- -%% Function: +%% Function: %% Description: %% -------------------------------------------------------------------- -include_lib("eunit/include/eunit.hrl"). @@ -75,9 +75,9 @@ basic_functionality() -> Columns = ["id", "name", "age", "wage"], AllRows = [{1, <<"abby">>, 20, 2000}, {2, <<"marge">>, 30, 2000}], AbbyOnly = [{1, <<"abby">>, 20, 2000}], - TableInfo = [{id, integer, [{primary_key, [asc, autoincrement]}]}, - {name, text, [not_null, unique]}, - {age, integer, not_null}, + TableInfo = [{id, integer, [{primary_key, [asc, autoincrement]}]}, + {name, text, [not_null, unique]}, + {age, integer, not_null}, {wage, integer}], TableInfo1 = lists:keyreplace(age, 1, TableInfo, {age, integer, [not_null]}), drop_all_tables(ct), @@ -85,50 +85,50 @@ basic_functionality() -> {error, 21, _}, sqlite3:sql_exec(ct, "-- Comment")), ?assertEqual( - [], + [], sqlite3:list_tables(ct)), ok = sqlite3:create_table(ct, user, TableInfo), ?assertEqual( - [user, sqlite_sequence], + [user, sqlite_sequence], sqlite3:list_tables(ct)), ?assertEqual( - TableInfo1, + TableInfo1, sqlite3:table_info(ct, user)), ?assertEqual( - {rowid, 1}, + {rowid, 1}, sqlite3:write(ct, user, [{name, "abby"}, {age, 20}, {<<"wage">>, 2000}])), ?assertEqual( - {rowid, 2}, + {rowid, 2}, sqlite3:write(ct, user, [{name, "marge"}, {age, 30}, {wage, 2000}])), ?assertMatch( - {error, 19, _}, + {error, 19, _}, sqlite3:write(ct, user, [{name, "marge"}, {age, 30}, {wage, 2000}])), ?assertEqual( - [{columns, Columns}, {rows, AllRows}], + [{columns, Columns}, {rows, AllRows}], sqlite3:sql_exec(ct, "select * from user;")), ?assertEqual( - [{columns, Columns}, {rows, AllRows}], + [{columns, Columns}, {rows, AllRows}], sqlite3:read_all(ct, user)), ?assertEqual( - [{columns, ["name"]}, {rows, [{<<"abby">>}, {<<"marge">>}]}], + [{columns, ["name"]}, {rows, [{<<"abby">>}, {<<"marge">>}]}], sqlite3:read_all(ct, user, [name])), ?assertEqual( - [{columns, Columns}, {rows, AbbyOnly}], + [{columns, Columns}, {rows, AbbyOnly}], sqlite3:read(ct, user, {name, "abby"})), ?assertEqual( - [{columns, Columns}, {rows, AllRows}], + [{columns, Columns}, {rows, AllRows}], sqlite3:read(ct, user, {wage, 2000})), ?assertEqual( - ok, + ok, sqlite3:delete(ct, user, {name, "marge"})), ?assertEqual( - ok, + ok, sqlite3:update(ct, user, {name, "abby"}, [{wage, 3000}])), ?assertEqual( - [{columns, Columns}, {rows, [{1, <<"abby">>, 20, 3000}]}], + [{columns, Columns}, {rows, [{1, <<"abby">>, 20, 3000}]}], sqlite3:sql_exec(ct, "select * from user;")), ?assertEqual( - ok, + ok, sqlite3:drop_table(ct, user)). parametrized() -> @@ -142,22 +142,22 @@ parametrized() -> {error, _, _}, sqlite3:sql_exec(ct, "INSERT INTO user1 (id, name) VALUES (?, ?)", [4, bad_sql_value])), ?assertEqual( - [{columns, ["id", "name"]}, - {rows, [{1, <<"john">>}, {2, <<"joe">>}, {3, <<"jack">>}, {4, <<"james">>}]}], + [{columns, ["id", "name"]}, + {rows, [{1, <<"john">>}, {2, <<"joe">>}, {3, <<"jack">>}, {4, <<"james">>}]}], sqlite3:read_all(ct, user1)), sqlite3:drop_table(ct, user1), sqlite3:create_table(ct, user1, [{i, integer}, {d, double}, {b, blob}]), - sqlite3:sql_exec(ct, "INSERT INTO user1 (i, d, b) VALUES (?, ?, ?)", + sqlite3:sql_exec(ct, "INSERT INTO user1 (i, d, b) VALUES (?, ?, ?)", [null, 1.0, {blob, <<1,0,0>>}]), ?assertEqual( - [{columns, ["i", "d", "b"]}, + [{columns, ["i", "d", "b"]}, {rows, [{null, 1.0, {blob, <<1,0,0>>}}]}], sqlite3:read_all(ct, user1)). negative() -> drop_table_if_exists(ct, negative), sqlite3:create_table(ct, negative, [{id, int}]), - ?assertEqual({error, badarg}, + ?assertEqual({error, badarg}, sqlite3:write(ct, negative, [{id, bad_sql_value}])). blob() -> @@ -165,7 +165,7 @@ blob() -> sqlite3:create_table(ct, blobs, [{blob_col, blob}]), sqlite3:write(ct, blobs, [{blob_col, {blob, <<0,255,1,2>>}}]), ?assertEqual( - [{columns, ["blob_col"]}, {rows, [{{blob, <<0,255,1,2>>}}]}], + [{columns, ["blob_col"]}, {rows, [{{blob, <<0,255,1,2>>}}]}], sqlite3:read_all(ct, blobs)). escaping() -> @@ -176,7 +176,7 @@ escaping() -> ExpectedRows = [{list_to_binary(String)} || String <- Strings], sqlite3:write_many(ct, escaping, Input), ?assertEqual( - [{columns, ["str"]}, {rows, ExpectedRows}], + [{columns, ["str"]}, {rows, ExpectedRows}], sqlite3:read_all(ct, escaping)). select_many_records() -> @@ -186,15 +186,15 @@ select_many_records() -> sqlite3:write_many(ct, many_records, [[{id, X}, {name, "bar"}] || X <- lists:seq(1, N)]), Columns = ["id", "name"], ?assertEqual( - [{columns, Columns}, {rows, [{1, <<"bar">>}]}], + [{columns, Columns}, {rows, [{1, <<"bar">>}]}], sqlite3:read(ct, many_records, {id, 1})), [?assertEqual( - M, + M, length(rows(sqlite3:sql_exec( ct, io_lib:format("select * from many_records limit ~p;", [M]))))) || M <- [10, 100, 1000]], ?assertEqual( - N, + N, length(rows(sqlite3:sql_exec(ct, "select * from many_records;")))). %% note that inserts are actually serialized by gen_server @@ -238,7 +238,7 @@ unicode() -> drop_table_if_exists(ct, unicode), sqlite3:create_table(ct, unicode, [{str, text}]), sqlite3:write(ct, unicode, [{str, UnicodeString}]), - ?assertEqual([{unicode:characters_to_binary(UnicodeString)}], rows(sqlite3:read_all(ct, unicode))). + ?assertEqual([{unicode:characters_to_binary(UnicodeString)}], rows(sqlite3:read_all(ct, unicode))). acc_string_encoding() -> ?assertEqual([{62}], rows(sqlite3:sql_exec(ct, "SELECT ? + ?", [30,32]))). @@ -283,17 +283,17 @@ script_test() -> " " ], "\n"), ?assertEqual( - [ok, ok, ok], + [ok, ok, ok], sqlite3:sql_exec_script(script, Script)), ?assertEqual( - [{columns,["id"]},{rows,[{1},{2}]}], + [{columns,["id"]},{rows,[{1},{2}]}], sqlite3:read_all(script, person)), - Script2 = "select * from person; update person set id=3 where id=2", + Script2 = "select * from person; update person set id=3 where id=2", ?assertEqual( - [[{columns,["id"]},{rows,[{1},{2}]}], ok], + [[{columns,["id"]},{rows,[{1},{2}]}], ok], sqlite3:sql_exec_script(script, Script2)), ?assertEqual( - [{columns,["id"]},{rows,[{1},{3}]}], + [{columns,["id"]},{rows,[{1},{3}]}], sqlite3:read_all(script, person)), BadScript = string:join( ["CREATE TABLE person2(", @@ -306,31 +306,31 @@ script_test() -> " " ], "\n"), ?assertEqual( - [ok, {error, 1, "near \"SYNTAX\": syntax error"}], + [ok, {error, 1, "near \"SYNTAX\": syntax error"}], 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}]), - ?assertMatch( - [{columns, ["id"]}, {rows, []}, {error, 20, _}], - sqlite3:sql_exec(ct, "select * from large_offset limit 1 offset 9223372036854775808")). + drop_table_if_exists(ct, large_offset), + ok = sqlite3:create_table(ct, large_offset, [{id, integer}]), + ?assertMatch( + [{columns, ["id"]}, {rows, []}, {error, 20, _}], + sqlite3:sql_exec(ct, "select * from large_offset limit 1 offset 9223372036854775808")). issue13() -> - drop_table_if_exists(ct, issue13), - ok = sqlite3:create_table(ct, issue13, [{foo, integer}]), - sqlite3:write_many(ct, issue13, - [[{foo, X}] || X <- [-1, 0, 127, 128, 255, 256]]), - ?assertEqual( - [{columns, ["foo"]}, {rows, [{255}, {256}]}], - sqlite3:sql_exec(ct, "select foo from issue13 where foo > 128;")), - ?assertEqual( - [{columns, ["foo"]}, {rows, [{255}, {256}]}], - sqlite3:sql_exec(ct, "select foo from issue13 where foo > ?;", [128.0])), - ?assertEqual( - [{columns, ["foo"]}, {rows, [{255}, {256}]}], - sqlite3:sql_exec(ct, "select foo from issue13 where foo > ?;", [128])). + drop_table_if_exists(ct, issue13), + ok = sqlite3:create_table(ct, issue13, [{foo, integer}]), + sqlite3:write_many(ct, issue13, + [[{foo, X}] || X <- [-1, 0, 127, 128, 255, 256]]), + ?assertEqual( + [{columns, ["foo"]}, {rows, [{255}, {256}]}], + sqlite3:sql_exec(ct, "select foo from issue13 where foo > 128;")), + ?assertEqual( + [{columns, ["foo"]}, {rows, [{255}, {256}]}], + sqlite3:sql_exec(ct, "select foo from issue13 where foo > ?;", [128.0])), + ?assertEqual( + [{columns, ["foo"]}, {rows, [{255}, {256}]}], + sqlite3:sql_exec(ct, "select foo from issue13 where foo > ?;", [128])). enable_load_extension() -> ?assertEqual(ok, sqlite3:enable_load_extension(ct, 1)).