Formatting
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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([_]) -> [];
|
||||
|
||||
@@ -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>> || <<X:4>> <= 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>> || <<X:4>> <= 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, <<Acc/binary, (X * 16 + Y)>>).
|
||||
|
||||
@@ -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() ->
|
||||
|
||||
@@ -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)).
|
||||
|
||||
Reference in New Issue
Block a user