Merge branch 'master' of github.com:alexeyr/erlang-sqlite3
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -17,3 +17,5 @@ TEST*.xml
|
|||||||
*.dll
|
*.dll
|
||||||
rebar.cross_compile.config
|
rebar.cross_compile.config
|
||||||
config.tmp
|
config.tmp
|
||||||
|
*.beam
|
||||||
|
*.so
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ test:
|
|||||||
$(REBAR_COMPILE) eunit
|
$(REBAR_COMPILE) eunit
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
-rm -rf deps ebin priv doc/* .eunit c_src/*.o config.tmp
|
-rm -rf deps ebin priv/*.so doc/* .eunit/* c_src/*.o config.tmp
|
||||||
|
|
||||||
docs:
|
docs:
|
||||||
$(REBAR_COMPILE) doc
|
$(REBAR_COMPILE) doc
|
||||||
|
|||||||
@@ -162,6 +162,9 @@ static int control(
|
|||||||
case CMD_PREPARED_COLUMNS:
|
case CMD_PREPARED_COLUMNS:
|
||||||
prepared_columns(driver_data, buf, len);
|
prepared_columns(driver_data, buf, len);
|
||||||
break;
|
break;
|
||||||
|
case CMD_SQL_EXEC_SCRIPT:
|
||||||
|
sql_exec_script(driver_data, buf, len);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
unknown(driver_data, buf, len);
|
unknown(driver_data, buf, len);
|
||||||
}
|
}
|
||||||
@@ -193,7 +196,7 @@ static inline int output_error(
|
|||||||
int term_count;
|
int term_count;
|
||||||
return_error(drv, error_code, error, &dataset, &term_count);
|
return_error(drv, error_code, error, &dataset, &term_count);
|
||||||
driver_output_term(drv->port, dataset, term_count);
|
driver_output_term(drv->port, dataset, term_count);
|
||||||
return 0;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int output_db_error(sqlite3_drv_t *drv) {
|
static inline int output_db_error(sqlite3_drv_t *drv) {
|
||||||
@@ -210,6 +213,16 @@ static inline int output_ok(sqlite3_drv_t *drv) {
|
|||||||
return driver_output_term(drv->port, spec, sizeof(spec) / sizeof(spec[0]));
|
return driver_output_term(drv->port, spec, sizeof(spec) / sizeof(spec[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int output_done(sqlite3_drv_t *drv) {
|
||||||
|
// Return {Port, ok}
|
||||||
|
ErlDrvTermData spec[] = {
|
||||||
|
ERL_DRV_PORT, driver_mk_port(drv->port),
|
||||||
|
ERL_DRV_ATOM, drv->atom_done,
|
||||||
|
ERL_DRV_TUPLE, 2
|
||||||
|
};
|
||||||
|
return driver_output_term(drv->port, spec, sizeof(spec) / sizeof(spec[0]));
|
||||||
|
}
|
||||||
|
|
||||||
static inline async_sqlite3_command *make_async_command(
|
static inline async_sqlite3_command *make_async_command(
|
||||||
sqlite3_drv_t *drv, sqlite3_stmt *statement) {
|
sqlite3_drv_t *drv, sqlite3_stmt *statement) {
|
||||||
async_sqlite3_command *result =
|
async_sqlite3_command *result =
|
||||||
@@ -242,22 +255,50 @@ static inline int sql_exec_statement(
|
|||||||
|
|
||||||
static int sql_exec(sqlite3_drv_t *drv, char *command, int command_size) {
|
static int sql_exec(sqlite3_drv_t *drv, char *command, int command_size) {
|
||||||
int result;
|
int result;
|
||||||
char *rest = NULL;
|
const char *rest;
|
||||||
sqlite3_stmt *statement;
|
sqlite3_stmt *statement;
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
fprintf(drv->log, "Preexec: %.*s\n", command_size, command);
|
fprintf(drv->log, "Preexec: %.*s\n", command_size, command);
|
||||||
fflush(drv->log);
|
fflush(drv->log);
|
||||||
#endif
|
#endif
|
||||||
result = sqlite3_prepare_v2(drv->db, command, command_size, &statement,
|
result = sqlite3_prepare_v2(drv->db, command, command_size, &statement, &rest);
|
||||||
(const char **) &rest);
|
|
||||||
if (result != SQLITE_OK) {
|
if (result != SQLITE_OK) {
|
||||||
return output_db_error(drv);
|
return output_db_error(drv);
|
||||||
|
} else if (statement == NULL) {
|
||||||
|
return output_error(drv, SQLITE_MISUSE, "empty statement");
|
||||||
}
|
}
|
||||||
|
|
||||||
return sql_exec_statement(drv, statement);
|
return sql_exec_statement(drv, statement);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int sql_exec_script(sqlite3_drv_t *drv, char *command, int command_size) {
|
||||||
|
int result;
|
||||||
|
const char *rest = command;
|
||||||
|
const char *end = command + command_size;
|
||||||
|
sqlite3_stmt *statement;
|
||||||
|
|
||||||
|
while (rest < end) {
|
||||||
|
result = sqlite3_prepare_v2(drv->db, command, end - command, &statement, &rest);
|
||||||
|
command = (char *) rest; // won't actually mutate!
|
||||||
|
if (result != SQLITE_OK) {
|
||||||
|
output_db_error(drv);
|
||||||
|
break;
|
||||||
|
} else if (statement == NULL) {
|
||||||
|
output_error(drv, SQLITE_MISUSE, "empty statement");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = sql_exec_statement(drv, statement);
|
||||||
|
if (result) {
|
||||||
|
// there was an error, bail out
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
output_done(drv);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
static inline int decode_and_bind_param(
|
static inline int decode_and_bind_param(
|
||||||
sqlite3_drv_t *drv, char *buffer, int *p_index,
|
sqlite3_drv_t *drv, char *buffer, int *p_index,
|
||||||
sqlite3_stmt *statement, int param_index, int *p_type, int *p_size) {
|
sqlite3_stmt *statement, int param_index, int *p_type, int *p_size) {
|
||||||
@@ -441,7 +482,7 @@ static int sql_bind_and_exec(sqlite3_drv_t *drv, char *buffer, int buffer_size)
|
|||||||
int result;
|
int result;
|
||||||
int index = 0;
|
int index = 0;
|
||||||
int type, size;
|
int type, size;
|
||||||
char *rest = NULL;
|
const char *rest;
|
||||||
sqlite3_stmt *statement;
|
sqlite3_stmt *statement;
|
||||||
long bin_size;
|
long bin_size;
|
||||||
char *command;
|
char *command;
|
||||||
@@ -469,12 +510,13 @@ static int sql_bind_and_exec(sqlite3_drv_t *drv, char *buffer, int buffer_size)
|
|||||||
command = driver_alloc(size * sizeof(char));
|
command = driver_alloc(size * sizeof(char));
|
||||||
ei_decode_binary(buffer, &index, command, &bin_size);
|
ei_decode_binary(buffer, &index, command, &bin_size);
|
||||||
// assert(bin_size == size)
|
// assert(bin_size == size)
|
||||||
result = sqlite3_prepare_v2(drv->db, command, size, &statement,
|
result = sqlite3_prepare_v2(drv->db, command, size, &statement, &rest);
|
||||||
(const char **) &rest);
|
|
||||||
driver_free(command);
|
driver_free(command);
|
||||||
|
|
||||||
if (result != SQLITE_OK) {
|
if (result != SQLITE_OK) {
|
||||||
return output_db_error(drv);
|
return output_db_error(drv);
|
||||||
|
} else if (statement == NULL) {
|
||||||
|
return output_error(drv, SQLITE_MISUSE, "empty statement");
|
||||||
}
|
}
|
||||||
|
|
||||||
result = bind_parameters(drv, buffer, buffer_size, &index, statement, &type, &size);
|
result = bind_parameters(drv, buffer, buffer_size, &index, statement, &type, &size);
|
||||||
@@ -917,7 +959,7 @@ static void ready_async(ErlDrvData drv_data, ErlDrvThreadData thread_data) {
|
|||||||
|
|
||||||
static int prepare(sqlite3_drv_t *drv, char *command, int command_size) {
|
static int prepare(sqlite3_drv_t *drv, char *command, int command_size) {
|
||||||
int result;
|
int result;
|
||||||
char *rest = NULL;
|
const char *rest;
|
||||||
sqlite3_stmt *statement;
|
sqlite3_stmt *statement;
|
||||||
ErlDrvTermData spec[6];
|
ErlDrvTermData spec[6];
|
||||||
|
|
||||||
@@ -925,10 +967,11 @@ static int prepare(sqlite3_drv_t *drv, char *command, int command_size) {
|
|||||||
fprintf(drv->log, "Preparing statement: %.*s\n", command_size, command);
|
fprintf(drv->log, "Preparing statement: %.*s\n", command_size, command);
|
||||||
fflush(drv->log);
|
fflush(drv->log);
|
||||||
#endif
|
#endif
|
||||||
result = sqlite3_prepare_v2(drv->db, command, command_size, &statement,
|
result = sqlite3_prepare_v2(drv->db, command, command_size, &statement, &rest);
|
||||||
(const char **) &rest);
|
|
||||||
if (result != SQLITE_OK) {
|
if (result != SQLITE_OK) {
|
||||||
return output_db_error(drv);
|
return output_db_error(drv);
|
||||||
|
} else if (statement == NULL) {
|
||||||
|
return output_error(drv, SQLITE_MISUSE, "empty statement");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (drv->prepared_count >= drv->prepared_alloc) {
|
if (drv->prepared_count >= drv->prepared_alloc) {
|
||||||
|
|||||||
@@ -34,6 +34,7 @@
|
|||||||
#define CMD_PREPARED_CLEAR_BINDINGS 9
|
#define CMD_PREPARED_CLEAR_BINDINGS 9
|
||||||
#define CMD_PREPARED_FINALIZE 10
|
#define CMD_PREPARED_FINALIZE 10
|
||||||
#define CMD_PREPARED_COLUMNS 11
|
#define CMD_PREPARED_COLUMNS 11
|
||||||
|
#define CMD_SQL_EXEC_SCRIPT 12
|
||||||
|
|
||||||
// Number of bytes for each key
|
// Number of bytes for each key
|
||||||
// (160 bits for SHA1 hash)
|
// (160 bits for SHA1 hash)
|
||||||
@@ -84,6 +85,7 @@ static int control(ErlDrvData drv_data, unsigned int command, char *buf,
|
|||||||
int len, char **rbuf, int rlen);
|
int len, char **rbuf, int rlen);
|
||||||
static int sql_exec(sqlite3_drv_t *drv, char *buf, int len);
|
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_bind_and_exec(sqlite3_drv_t *drv, char *buf, int len);
|
||||||
|
static int sql_exec_script(sqlite3_drv_t *drv, char *buf, int len);
|
||||||
static int prepare(sqlite3_drv_t *drv, char *buf, int len);
|
static int prepare(sqlite3_drv_t *drv, char *buf, int len);
|
||||||
static int prepared_bind(sqlite3_drv_t *drv, char *buf, int len);
|
static int prepared_bind(sqlite3_drv_t *drv, char *buf, int len);
|
||||||
static int prepared_step(sqlite3_drv_t *drv, char *buf, int len);
|
static int prepared_step(sqlite3_drv_t *drv, char *buf, int len);
|
||||||
|
|||||||
350
src/sqlite3.erl
350
src/sqlite3.erl
@@ -14,19 +14,26 @@
|
|||||||
%% API
|
%% API
|
||||||
-export([open/1, open/2]).
|
-export([open/1, open/2]).
|
||||||
-export([start_link/1, start_link/2]).
|
-export([start_link/1, start_link/2]).
|
||||||
-export([stop/0, close/1]).
|
-export([stop/0, close/1, close_timeout/2]).
|
||||||
-export([sql_exec/1, sql_exec/2, sql_exec/3]).
|
-export([sql_exec/1, sql_exec/2, sql_exec_timeout/3,
|
||||||
|
sql_exec_script/2, sql_exec_script_timeout/3,
|
||||||
|
sql_exec/3, sql_exec_timeout/4]).
|
||||||
-export([prepare/2, bind/3, next/2, reset/2, clear_bindings/2, finalize/2,
|
-export([prepare/2, bind/3, next/2, reset/2, clear_bindings/2, finalize/2,
|
||||||
columns/2]).
|
columns/2, prepare_timeout/3, bind_timeout/4, next_timeout/3,
|
||||||
-export([create_table/2, create_table/3, create_table/4]).
|
reset_timeout/3, clear_bindings_timeout/3, finalize_timeout/3,
|
||||||
-export([list_tables/0, list_tables/1, table_info/1, table_info/2]).
|
columns_timeout/3]).
|
||||||
-export([write/2, write/3, write_many/2, write_many/3]).
|
-export([create_table/2, create_table/3, create_table/4, create_table_timeout/4,
|
||||||
-export([update/3, update/4]).
|
create_table_timeout/5]).
|
||||||
-export([read_all/2, read_all/3, read/2, read/3, read/4]).
|
-export([list_tables/0, list_tables/1, list_tables_timeout/2,
|
||||||
-export([delete/2, delete/3]).
|
table_info/1, table_info/2, table_info_timeout/3]).
|
||||||
-export([drop_table/1, drop_table/2]).
|
-export([write/2, write/3, write_timeout/4, write_many/2, write_many/3,
|
||||||
-export([begin_transaction/1, commit_transaction/1, rollback_transaction/1]).
|
write_many_timeout/4]).
|
||||||
-export([vacuum/0, vacuum/1]).
|
-export([update/3, update/4, update_timeout/5]).
|
||||||
|
-export([read_all/2, read_all/3, read_all_timeout/3, read_all_timeout/4,
|
||||||
|
read/2, read/3, read/4, read_timeout/4, read_timeout/5]).
|
||||||
|
-export([delete/2, delete/3, delete_timeout/4]).
|
||||||
|
-export([drop_table/1, drop_table/2, drop_table_timeout/3]).
|
||||||
|
-export([vacuum/0, vacuum/1, vacuum_timeout/2]).
|
||||||
|
|
||||||
%% -export([create_function/3]).
|
%% -export([create_function/3]).
|
||||||
|
|
||||||
@@ -127,6 +134,16 @@ open(Db, Options) ->
|
|||||||
close(Db) ->
|
close(Db) ->
|
||||||
gen_server:call(Db, close).
|
gen_server:call(Db, close).
|
||||||
|
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% @spec close_timeout(Db :: atom(), Timeout :: timeout()) -> ok
|
||||||
|
%% @doc
|
||||||
|
%% Closes the Db sqlite3 database.
|
||||||
|
%% @end
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
-spec close_timeout(atom(), timeout()) -> 'ok'.
|
||||||
|
close_timeout(Db, Timeout) ->
|
||||||
|
gen_server:call(Db, close, Timeout).
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% @spec stop() -> ok
|
%% @spec stop() -> ok
|
||||||
%% @doc
|
%% @doc
|
||||||
@@ -166,10 +183,63 @@ sql_exec(Db, SQL) ->
|
|||||||
%% database. Returns the result of the Sql call.
|
%% database. Returns the result of the Sql call.
|
||||||
%% @end
|
%% @end
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
-spec sql_exec(atom(), iodata(), [sql_value() | {atom() | string() | integer(), sql_value()}]) -> sql_result().
|
-spec sql_exec(atom(), iodata(), [sql_value() | {atom() | string() | integer(), sql_value()}]) ->
|
||||||
|
sql_result().
|
||||||
sql_exec(Db, SQL, Params) ->
|
sql_exec(Db, SQL, Params) ->
|
||||||
gen_server:call(Db, {sql_bind_and_exec, SQL, Params}).
|
gen_server:call(Db, {sql_bind_and_exec, SQL, Params}).
|
||||||
|
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% @spec sql_exec_timeout(Db :: atom(), Sql :: iodata()) -> sql_result()
|
||||||
|
%% @doc
|
||||||
|
%% Executes the Sql statement directly on the Db database. Returns the
|
||||||
|
%% result of the Sql call.
|
||||||
|
%% @end
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
-spec sql_exec_timeout(atom(), iodata(), timeout()) -> sql_result().
|
||||||
|
sql_exec_timeout(Db, SQL, Timeout) ->
|
||||||
|
gen_server:call(Db, {sql_exec, SQL}, Timeout).
|
||||||
|
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% @spec sql_exec_timeout(Db :: atom(), Sql :: iodata(), Params) -> sql_result()
|
||||||
|
%% Params = [sql_value() | {atom() | string() | integer(), sql_value()}]
|
||||||
|
%% @doc
|
||||||
|
%% Executes the Sql statement with parameters Params directly on the Db
|
||||||
|
%% database. Returns the result of the Sql call.
|
||||||
|
%% @end
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
-spec sql_exec_timeout(atom(), iodata(), [sql_value() | {atom() | string() | integer(), sql_value()}], timeout()) ->
|
||||||
|
sql_result().
|
||||||
|
sql_exec_timeout(Db, SQL, Params, Timeout) ->
|
||||||
|
gen_server:call(Db, {sql_bind_and_exec, SQL, Params}, Timeout).
|
||||||
|
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% @spec sql_exec_script(Db :: atom(), Sql :: iodata()) -> [sql_result()]
|
||||||
|
%% @doc
|
||||||
|
%% Executes the Sql script (consisting of semicolon-separated statements)
|
||||||
|
%% directly on the Db database. Returns the list of their results (same as
|
||||||
|
%% if sql_exec/2 was called for all of them in order, but more efficient).
|
||||||
|
%% Note that any whitespace or comments after the last semicolon will be
|
||||||
|
%% considered an empty statement and produce the corresponding error.
|
||||||
|
%% @end
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
-spec sql_exec_script(atom(), iodata()) -> [sql_result()].
|
||||||
|
sql_exec_script(Db, SQL) ->
|
||||||
|
gen_server:call(Db, {sql_exec_script, SQL}).
|
||||||
|
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% @spec sql_exec_script_timeout(Db :: atom(), Sql :: iodata(), Timeout :: timeout()) -> [sql_result()]
|
||||||
|
%% @doc
|
||||||
|
%% Executes the Sql script (consisting of semicolon-separated statements)
|
||||||
|
%% directly on the Db database. Returns the list of their results (same as
|
||||||
|
%% if sql_exec/3 was called for all of them in order, but more efficient).
|
||||||
|
%% Note that any whitespace or comments after the last semicolon will be
|
||||||
|
%% considered an empty statement and produce the corresponding error.
|
||||||
|
%% @end
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
-spec sql_exec_script_timeout(atom(), iodata(), timeout()) -> [sql_result()].
|
||||||
|
sql_exec_script_timeout(Db, SQL, Timeout) ->
|
||||||
|
gen_server:call(Db, {sql_exec_script, SQL}, Timeout).
|
||||||
|
|
||||||
-spec prepare(atom(), iodata()) -> {ok, reference()} | sqlite_error().
|
-spec prepare(atom(), iodata()) -> {ok, reference()} | sqlite_error().
|
||||||
prepare(Db, SQL) ->
|
prepare(Db, SQL) ->
|
||||||
gen_server:call(Db, {prepare, SQL}).
|
gen_server:call(Db, {prepare, SQL}).
|
||||||
@@ -198,6 +268,34 @@ finalize(Db, Ref) ->
|
|||||||
columns(Db, Ref) ->
|
columns(Db, Ref) ->
|
||||||
gen_server:call(Db, {columns, Ref}).
|
gen_server:call(Db, {columns, Ref}).
|
||||||
|
|
||||||
|
-spec prepare_timeout(atom(), iodata(), timeout()) -> {ok, reference()} | sqlite_error().
|
||||||
|
prepare_timeout(Db, SQL, Timeout) ->
|
||||||
|
gen_server:call(Db, {prepare, SQL}, Timeout).
|
||||||
|
|
||||||
|
-spec bind_timeout(atom(), reference(), sql_params(), timeout()) -> sql_non_query_result().
|
||||||
|
bind_timeout(Db, Ref, Params, Timeout) ->
|
||||||
|
gen_server:call(Db, {bind, Ref, Params}, Timeout).
|
||||||
|
|
||||||
|
-spec next_timeout(atom(), reference(), timeout()) -> tuple() | done | sqlite_error().
|
||||||
|
next_timeout(Db, Ref, Timeout) ->
|
||||||
|
gen_server:call(Db, {next, Ref}, Timeout).
|
||||||
|
|
||||||
|
-spec reset_timeout(atom(), reference(), timeout()) -> sql_non_query_result().
|
||||||
|
reset_timeout(Db, Ref, Timeout) ->
|
||||||
|
gen_server:call(Db, {reset, Ref}, Timeout).
|
||||||
|
|
||||||
|
-spec clear_bindings_timeout(atom(), reference(), timeout()) -> sql_non_query_result().
|
||||||
|
clear_bindings_timeout(Db, Ref, Timeout) ->
|
||||||
|
gen_server:call(Db, {clear_bindings, Ref}, Timeout).
|
||||||
|
|
||||||
|
-spec finalize_timeout(atom(), reference(), timeout()) -> sql_non_query_result().
|
||||||
|
finalize_timeout(Db, Ref, Timeout) ->
|
||||||
|
gen_server:call(Db, {finalize, Ref}, Timeout).
|
||||||
|
|
||||||
|
-spec columns_timeout(atom(), reference(), timeout()) -> sql_non_query_result().
|
||||||
|
columns_timeout(Db, Ref, Timeout) ->
|
||||||
|
gen_server:call(Db, {columns, Ref}, Timeout).
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% @spec create_table(Tbl :: atom(), TblInfo :: [{atom(), atom()}]) -> sql_non_query_result()
|
%% @spec create_table(Tbl :: atom(), TblInfo :: [{atom(), atom()}]) -> sql_non_query_result()
|
||||||
%% @doc
|
%% @doc
|
||||||
@@ -227,6 +325,21 @@ create_table(Tbl, Columns) ->
|
|||||||
create_table(Db, Tbl, Columns) ->
|
create_table(Db, Tbl, Columns) ->
|
||||||
gen_server:call(Db, {create_table, Tbl, Columns}).
|
gen_server:call(Db, {create_table, Tbl, Columns}).
|
||||||
|
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% @spec create_table_timeout(Db :: atom(), Tbl :: atom(), Columns, Timeout :: timeout()) -> sql_non_query_result()
|
||||||
|
%% Columns = [{atom(), atom()}]
|
||||||
|
%% @doc
|
||||||
|
%% Creates the Tbl table in Db using Columns as the table structure.
|
||||||
|
%% The table structure is a list of {column name, column type} pairs.
|
||||||
|
%% e.g. [{name, text}, {age, integer}]
|
||||||
|
%%
|
||||||
|
%% Returns the result of the create table call.
|
||||||
|
%% @end
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
-spec create_table_timeout(atom(), atom(), [{atom(), atom()}], timeout()) -> sql_non_query_result().
|
||||||
|
create_table_timeout(Db, Tbl, Columns, Timeout) ->
|
||||||
|
gen_server:call(Db, {create_table, Tbl, Columns}, Timeout).
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% @spec create_table(Db :: atom(), Tbl :: atom(), TblInfo, Constraints) -> sql_non_query_result()
|
%% @spec create_table(Db :: atom(), Tbl :: atom(), TblInfo, Constraints) -> sql_non_query_result()
|
||||||
%% Columns = [{atom(), atom()}]
|
%% Columns = [{atom(), atom()}]
|
||||||
@@ -244,6 +357,23 @@ create_table(Db, Tbl, Columns) ->
|
|||||||
create_table(Db, Tbl, Columns, Constraints) ->
|
create_table(Db, Tbl, Columns, Constraints) ->
|
||||||
gen_server:call(Db, {create_table, Tbl, Columns, Constraints}).
|
gen_server:call(Db, {create_table, Tbl, Columns, Constraints}).
|
||||||
|
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% @spec create_table_timeout(Db :: atom(), Tbl :: atom(), TblInfo, Constraints, Timeout) -> sql_non_query_result()
|
||||||
|
%% Columns = [{atom(), atom()}]
|
||||||
|
%% Constraints = [term()]
|
||||||
|
%% @doc
|
||||||
|
%% Creates the Tbl table in Db using Columns as the table structure and
|
||||||
|
%% Constraints as table constraints.
|
||||||
|
%% The table structure is a list of {column name, column type} pairs.
|
||||||
|
%% e.g. [{name, text}, {age, integer}]
|
||||||
|
%%
|
||||||
|
%% Returns the result of the create table call.
|
||||||
|
%% @end
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
-spec create_table_timeout(atom(), atom(), [{atom(), atom()}], [any()], timeout()) -> sql_non_query_result().
|
||||||
|
create_table_timeout(Db, Tbl, Columns, Constraints, Timeout) ->
|
||||||
|
gen_server:call(Db, {create_table, Tbl, Columns, Constraints}, Timeout).
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% @spec list_tables() -> [atom()]
|
%% @spec list_tables() -> [atom()]
|
||||||
%% @doc
|
%% @doc
|
||||||
@@ -264,6 +394,16 @@ list_tables() ->
|
|||||||
list_tables(Db) ->
|
list_tables(Db) ->
|
||||||
gen_server:call(Db, list_tables).
|
gen_server:call(Db, list_tables).
|
||||||
|
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% @spec list_tables_timeout(Db :: atom(), Timeout :: timeout()) -> [atom()]
|
||||||
|
%% @doc
|
||||||
|
%% Returns a list of tables for Db.
|
||||||
|
%% @end
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
-spec list_tables_timeout(atom(), timeout()) -> [atom()].
|
||||||
|
list_tables_timeout(Db, Timeout) ->
|
||||||
|
gen_server:call(Db, list_tables, Timeout).
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% @spec table_info(Tbl :: atom()) -> [any()]
|
%% @spec table_info(Tbl :: atom()) -> [any()]
|
||||||
%% @doc
|
%% @doc
|
||||||
@@ -284,6 +424,16 @@ table_info(Tbl) ->
|
|||||||
table_info(Db, Tbl) ->
|
table_info(Db, Tbl) ->
|
||||||
gen_server:call(Db, {table_info, Tbl}).
|
gen_server:call(Db, {table_info, Tbl}).
|
||||||
|
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% @spec table_info_timeout(Db :: atom(), Tbl :: atom()) -> [any()]
|
||||||
|
%% @doc
|
||||||
|
%% Returns table schema for Tbl in Db.
|
||||||
|
%% @end
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
-spec table_info_timeout(atom(), atom(), timeout()) -> [any()].
|
||||||
|
table_info_timeout(Db, Tbl, Timeout) ->
|
||||||
|
gen_server:call(Db, {table_info, Tbl}, Timeout).
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% @spec write(Tbl :: atom(), Data) -> sql_non_query_result()
|
%% @spec write(Tbl :: atom(), Data) -> sql_non_query_result()
|
||||||
%% Data = [{Column :: atom(), Value :: sql_value()}]
|
%% Data = [{Column :: atom(), Value :: sql_value()}]
|
||||||
@@ -308,6 +458,18 @@ write(Tbl, Data) ->
|
|||||||
write(Db, Tbl, Data) ->
|
write(Db, Tbl, Data) ->
|
||||||
gen_server:call(Db, {write, Tbl, Data}).
|
gen_server:call(Db, {write, Tbl, Data}).
|
||||||
|
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% @spec write_timeout(Db :: atom(), Tbl :: atom(), Data) -> sql_non_query_result()
|
||||||
|
%% Data = [{Column :: atom(), Value :: sql_value()}]
|
||||||
|
%% @doc
|
||||||
|
%% Write Data into Tbl table in Db database. Value must be of the
|
||||||
|
%% same type as determined from table_info/3.
|
||||||
|
%% @end
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
-spec write_timeout(atom(), atom(), [{atom(), sql_value()}], timeout()) -> sql_non_query_result().
|
||||||
|
write_timeout(Db, Tbl, Data, Timeout) ->
|
||||||
|
gen_server:call(Db, {write, Tbl, Data}, Timeout).
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% @spec write_many(Tbl :: atom(), Data) -> sql_non_query_result()
|
%% @spec write_many(Tbl :: atom(), Data) -> sql_non_query_result()
|
||||||
%% Data = [[{Column :: atom(), Value :: sql_value()}]]
|
%% Data = [[{Column :: atom(), Value :: sql_value()}]]
|
||||||
@@ -332,6 +494,18 @@ write_many(Tbl, Data) ->
|
|||||||
write_many(Db, Tbl, Data) ->
|
write_many(Db, Tbl, Data) ->
|
||||||
gen_server:call(Db, {write_many, Tbl, Data}).
|
gen_server:call(Db, {write_many, Tbl, Data}).
|
||||||
|
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% @spec write_many_timeout(Db :: atom(), Tbl :: atom(), Data) -> sql_non_query_result()
|
||||||
|
%% Data = [[{Column :: atom(), Value :: sql_value()}]]
|
||||||
|
%% @doc
|
||||||
|
%% Write all records in Data into table Tbl in database Db. Value
|
||||||
|
%% must be of the same type as determined from table_info/3.
|
||||||
|
%% @end
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
-spec write_many_timeout(atom(), atom(), [[{atom(), sql_value()}]], timeout()) -> sql_non_query_result().
|
||||||
|
write_many_timeout(Db, Tbl, Data, Timeout) ->
|
||||||
|
gen_server:call(Db, {write_many, Tbl, Data}, Timeout).
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% @spec update(Tbl :: atom(), {Key :: atom(), Value}, Data) -> sql_non_query_result()
|
%% @spec update(Tbl :: atom(), {Key :: atom(), Value}, Data) -> sql_non_query_result()
|
||||||
%% Value = any()
|
%% Value = any()
|
||||||
@@ -358,6 +532,19 @@ update(Tbl, {Key, Value}, Data) ->
|
|||||||
update(Db, Tbl, {Key, Value}, Data) ->
|
update(Db, Tbl, {Key, Value}, Data) ->
|
||||||
gen_server:call(Db, {update, Tbl, Key, Value, Data}).
|
gen_server:call(Db, {update, Tbl, Key, Value, Data}).
|
||||||
|
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% @spec update_timeout(Db :: atom(), Tbl :: atom(), {Key :: atom(), Value}, Data) -> sql_non_query_result()
|
||||||
|
%% Value = sql_value()
|
||||||
|
%% Data = [{Column :: atom(), Value :: sql_value()}]
|
||||||
|
%% @doc
|
||||||
|
%% Updates rows into Tbl table in Db database such that the Value
|
||||||
|
%% matches the value in Key with Data.
|
||||||
|
%% @end
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
-spec update_timeout(atom(), atom(), {atom(), sql_value()}, [{atom(), sql_value()}], timeout()) -> sql_non_query_result().
|
||||||
|
update_timeout(Db, Tbl, {Key, Value}, Data, Timeout) ->
|
||||||
|
gen_server:call(Db, {update, Tbl, Key, Value, Data}, Timeout).
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% @spec read_all(Db :: atom(), Table :: atom()) -> sql_result()
|
%% @spec read_all(Db :: atom(), Table :: atom()) -> sql_result()
|
||||||
%% @doc
|
%% @doc
|
||||||
@@ -368,6 +555,16 @@ update(Db, Tbl, {Key, Value}, Data) ->
|
|||||||
read_all(Db, Tbl) ->
|
read_all(Db, Tbl) ->
|
||||||
gen_server:call(Db, {read, Tbl}).
|
gen_server:call(Db, {read, Tbl}).
|
||||||
|
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% @spec read_all_timeout(Db :: atom(), Table :: atom()) -> sql_result()
|
||||||
|
%% @doc
|
||||||
|
%% Reads all rows from Table in Db.
|
||||||
|
%% @end
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
-spec read_all_timeout(atom(), atom(), timeout()) -> sql_result().
|
||||||
|
read_all_timeout(Db, Tbl, Timeout) ->
|
||||||
|
gen_server:call(Db, {read, Tbl}, Timeout).
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% @spec read_all(Db :: atom(), Table :: atom(), Columns :: [atom()]) -> sql_result()
|
%% @spec read_all(Db :: atom(), Table :: atom(), Columns :: [atom()]) -> sql_result()
|
||||||
%% @doc
|
%% @doc
|
||||||
@@ -378,6 +575,16 @@ read_all(Db, Tbl) ->
|
|||||||
read_all(Db, Tbl, Columns) ->
|
read_all(Db, Tbl, Columns) ->
|
||||||
gen_server:call(Db, {read, Tbl, Columns}).
|
gen_server:call(Db, {read, Tbl, Columns}).
|
||||||
|
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% @spec read_all_timeout(Db :: atom(), Table :: atom(), Columns :: [atom()]) -> sql_result()
|
||||||
|
%% @doc
|
||||||
|
%% Reads Columns in all rows from Table in Db.
|
||||||
|
%% @end
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
-spec read_all_timeout(atom(), atom(), [atom()], timeout()) -> sql_result().
|
||||||
|
read_all_timeout(Db, Tbl, Columns, Timeout) ->
|
||||||
|
gen_server:call(Db, {read, Tbl, Columns}, Timeout).
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% @spec read(Tbl :: atom(), Key) -> sql_result()
|
%% @spec read(Tbl :: atom(), Key) -> sql_result()
|
||||||
%% Key = {Column :: atom(), Value :: sql_value()}
|
%% Key = {Column :: atom(), Value :: sql_value()}
|
||||||
@@ -420,6 +627,35 @@ read(Db, Tbl, {Column, Value}) ->
|
|||||||
read(Db, Tbl, {Key, Value}, Columns) ->
|
read(Db, Tbl, {Key, Value}, Columns) ->
|
||||||
gen_server:call(Db, {read, Tbl, Key, Value, Columns}).
|
gen_server:call(Db, {read, Tbl, Key, Value, Columns}).
|
||||||
|
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% @spec read_timeout(Db :: atom(), Tbl :: atom(), Key) -> sql_result()
|
||||||
|
%% Key = {Column :: atom(), Value :: sql_value()}
|
||||||
|
%% @doc
|
||||||
|
%% Reads a row from Tbl table in Db database such that the Value
|
||||||
|
%% matches the value in Column. ColValue must have the same type
|
||||||
|
%% as determined from table_info/3.
|
||||||
|
%% @end
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
-spec read_timeout(atom(), atom(), {atom(), sql_value()}, timeout()) -> sql_result().
|
||||||
|
read_timeout(Db, Tbl, {Column, Value}, Timeout) ->
|
||||||
|
gen_server:call(Db, {read, Tbl, Column, Value}, Timeout).
|
||||||
|
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% @spec read_timeout(Db, Tbl, Key, Columns) -> [any()]
|
||||||
|
%% Db = atom()
|
||||||
|
%% Tbl = atom()
|
||||||
|
%% Key = {Column :: atom(), Value :: sql_value()}
|
||||||
|
%% Columns = [atom()]
|
||||||
|
%% @doc
|
||||||
|
%% Reads a row from Tbl table in Db database such that the Value
|
||||||
|
%% matches the value in Column. Value must have the same type as
|
||||||
|
%% determined from table_info/3.
|
||||||
|
%% @end
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
-spec read_timeout(atom(), atom(), {atom(), sql_value()}, [atom()], timeout()) -> sql_result().
|
||||||
|
read_timeout(Db, Tbl, {Key, Value}, Columns, Timeout) ->
|
||||||
|
gen_server:call(Db, {read, Tbl, Key, Value, Columns}, Timeout).
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% @spec delete(Tbl :: atom(), Key) -> any()
|
%% @spec delete(Tbl :: atom(), Key) -> any()
|
||||||
%% Key = {Column :: atom(), Value :: sql_value()}
|
%% Key = {Column :: atom(), Value :: sql_value()}
|
||||||
@@ -433,6 +669,19 @@ read(Db, Tbl, {Key, Value}, Columns) ->
|
|||||||
delete(Tbl, Key) ->
|
delete(Tbl, Key) ->
|
||||||
delete(?MODULE, Tbl, Key).
|
delete(?MODULE, Tbl, Key).
|
||||||
|
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% @spec delete_timeout(Db :: atom(), Tbl :: atom(), Key) -> sql_non_query_result()
|
||||||
|
%% Key = {Column :: atom(), Value :: sql_value()}
|
||||||
|
%% @doc
|
||||||
|
%% Delete a row from Tbl table in Db database such that the Value
|
||||||
|
%% matches the value in Column.
|
||||||
|
%% Value must have the same type as determined from table_info/3.
|
||||||
|
%% @end
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
-spec delete_timeout(atom(), atom(), {atom(), any()}, timeout()) -> sql_non_query_result().
|
||||||
|
delete_timeout(Db, Tbl, Key, Timeout) ->
|
||||||
|
gen_server:call(Db, {delete, Tbl, Key}, Timeout).
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% @spec delete(Db :: atom(), Tbl :: atom(), Key) -> sql_non_query_result()
|
%% @spec delete(Db :: atom(), Tbl :: atom(), Key) -> sql_non_query_result()
|
||||||
%% Key = {Column :: atom(), Value :: sql_value()}
|
%% Key = {Column :: atom(), Value :: sql_value()}
|
||||||
@@ -466,6 +715,16 @@ drop_table(Tbl) ->
|
|||||||
drop_table(Db, Tbl) ->
|
drop_table(Db, Tbl) ->
|
||||||
gen_server:call(Db, {drop_table, Tbl}).
|
gen_server:call(Db, {drop_table, Tbl}).
|
||||||
|
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% @spec drop_table_timeout(Db :: atom(), Tbl :: atom()) -> sql_non_query_result()
|
||||||
|
%% @doc
|
||||||
|
%% Drop the table Tbl from Db database.
|
||||||
|
%% @end
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
-spec drop_table_timeout(atom(), atom(), timeout()) -> sql_non_query_result().
|
||||||
|
drop_table_timeout(Db, Tbl, Timeout) ->
|
||||||
|
gen_server:call(Db, {drop_table, Tbl}, Timeout).
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% @spec vacuum() -> sql_non_query_result()
|
%% @spec vacuum() -> sql_non_query_result()
|
||||||
%% @doc
|
%% @doc
|
||||||
@@ -486,6 +745,16 @@ vacuum() ->
|
|||||||
vacuum(Db) ->
|
vacuum(Db) ->
|
||||||
gen_server:call(Db, vacuum).
|
gen_server:call(Db, vacuum).
|
||||||
|
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% @spec vacuum_timeout(Db :: atom()) -> sql_non_query_result()
|
||||||
|
%% @doc
|
||||||
|
%% Vacuum the Db database.
|
||||||
|
%% @end
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
-spec vacuum_timeout(atom(), timeout()) -> sql_non_query_result().
|
||||||
|
vacuum_timeout(Db, Timeout) ->
|
||||||
|
gen_server:call(Db, vacuum, Timeout).
|
||||||
|
|
||||||
%% %%--------------------------------------------------------------------
|
%% %%--------------------------------------------------------------------
|
||||||
%% %% @spec create_function(Db :: atom(), FunctionName :: atom(), Function :: function()) -> term()
|
%% %% @spec create_function(Db :: atom(), FunctionName :: atom(), Function :: function()) -> term()
|
||||||
%% %% @doc
|
%% %% @doc
|
||||||
@@ -497,39 +766,6 @@ vacuum(Db) ->
|
|||||||
%% create_function(Db, FunctionName, Function) ->
|
%% create_function(Db, FunctionName, Function) ->
|
||||||
%% gen_server:call(Db, {create_function, FunctionName, Function}).
|
%% gen_server:call(Db, {create_function, FunctionName, Function}).
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% @spec begin_transaction(Db :: atom()) -> sql_non_query_result()
|
|
||||||
%% @doc
|
|
||||||
%% Begins a transaction in Db.
|
|
||||||
%% @end
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
-spec begin_transaction(atom()) -> sql_non_query_result().
|
|
||||||
begin_transaction(Db) ->
|
|
||||||
SQL = "BEGIN;",
|
|
||||||
sql_exec(Db, SQL).
|
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% @spec commit_transaction(Db :: atom()) -> sql_non_query_result()
|
|
||||||
%% @doc
|
|
||||||
%% Commits the current transaction in Db.
|
|
||||||
%% @end
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
-spec commit_transaction(atom()) -> sql_non_query_result().
|
|
||||||
commit_transaction(Db) ->
|
|
||||||
SQL = "COMMIT;",
|
|
||||||
sql_exec(Db, SQL).
|
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% @spec rollback_transaction(Db :: atom()) -> sql_non_query_result()
|
|
||||||
%% @doc
|
|
||||||
%% Rolls back the current transaction in Db.
|
|
||||||
%% @end
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
-spec rollback_transaction(atom()) -> sql_non_query_result().
|
|
||||||
rollback_transaction(Db) ->
|
|
||||||
SQL = "ROLLBACK;",
|
|
||||||
sql_exec(Db, SQL).
|
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% @spec value_to_sql_unsafe(Value :: sql_value()) -> iolist()
|
%% @spec value_to_sql_unsafe(Value :: sql_value()) -> iolist()
|
||||||
%% @doc
|
%% @doc
|
||||||
@@ -643,6 +879,9 @@ handle_call({sql_exec, SQL}, _From, State) ->
|
|||||||
handle_call({sql_bind_and_exec, SQL, Params}, _From, State) ->
|
handle_call({sql_bind_and_exec, SQL, Params}, _From, State) ->
|
||||||
Reply = do_sql_bind_and_exec(SQL, Params, State),
|
Reply = do_sql_bind_and_exec(SQL, Params, State),
|
||||||
{reply, Reply, State};
|
{reply, Reply, State};
|
||||||
|
handle_call({sql_exec_script, SQL}, _From, State) ->
|
||||||
|
Reply = do_sql_exec_script(SQL, State),
|
||||||
|
{reply, Reply, State};
|
||||||
handle_call({create_table, Tbl, Columns}, _From, State) ->
|
handle_call({create_table, Tbl, Columns}, _From, State) ->
|
||||||
SQL = sqlite3_lib:create_table_sql(Tbl, Columns),
|
SQL = sqlite3_lib:create_table_sql(Tbl, Columns),
|
||||||
do_handle_call_sql_exec(SQL, State);
|
do_handle_call_sql_exec(SQL, State);
|
||||||
@@ -813,6 +1052,7 @@ get_priv_dir() ->
|
|||||||
-define(PREPARED_CLEAR_BINDINGS, 9).
|
-define(PREPARED_CLEAR_BINDINGS, 9).
|
||||||
-define(PREPARED_FINALIZE, 10).
|
-define(PREPARED_FINALIZE, 10).
|
||||||
-define(PREPARED_COLUMNS, 11).
|
-define(PREPARED_COLUMNS, 11).
|
||||||
|
-define(SQL_EXEC_SCRIPT, 12).
|
||||||
|
|
||||||
create_port_cmd(DbFile) ->
|
create_port_cmd(DbFile) ->
|
||||||
atom_to_list(?DRIVER_NAME) ++ " " ++ DbFile.
|
atom_to_list(?DRIVER_NAME) ++ " " ++ DbFile.
|
||||||
@@ -829,6 +1069,10 @@ do_sql_bind_and_exec(SQL, Params, #state{port = Port}) ->
|
|||||||
?dbg("SQL: ~s; Parameters: ~p~n", [SQL, Params]),
|
?dbg("SQL: ~s; Parameters: ~p~n", [SQL, Params]),
|
||||||
exec(Port, {sql_bind_and_exec, SQL, Params}).
|
exec(Port, {sql_bind_and_exec, SQL, Params}).
|
||||||
|
|
||||||
|
do_sql_exec_script(SQL, #state{port = Port}) ->
|
||||||
|
?dbg("SQL: ~s~n", [SQL]),
|
||||||
|
exec(Port, {sql_exec_script, SQL}).
|
||||||
|
|
||||||
exec(_Port, {create_function, _FunctionName, _Function}) ->
|
exec(_Port, {create_function, _FunctionName, _Function}) ->
|
||||||
error_logger:error_report([{application, sqlite3}, "NOT IMPL YET"]);
|
error_logger:error_report([{application, sqlite3}, "NOT IMPL YET"]);
|
||||||
%port_control(Port, ?SQL_CREATE_FUNCTION, list_to_binary(Cmd)),
|
%port_control(Port, ?SQL_CREATE_FUNCTION, list_to_binary(Cmd)),
|
||||||
@@ -840,6 +1084,9 @@ exec(Port, {sql_bind_and_exec, SQL, Params}) ->
|
|||||||
Bin = term_to_binary({iolist_to_binary(SQL), Params}),
|
Bin = term_to_binary({iolist_to_binary(SQL), Params}),
|
||||||
port_control(Port, ?SQL_BIND_AND_EXEC_COMMAND, Bin),
|
port_control(Port, ?SQL_BIND_AND_EXEC_COMMAND, Bin),
|
||||||
wait_result(Port);
|
wait_result(Port);
|
||||||
|
exec(Port, {sql_exec_script, SQL}) ->
|
||||||
|
port_control(Port, ?SQL_EXEC_SCRIPT, SQL),
|
||||||
|
many_results_loop(Port);
|
||||||
exec(Port, {prepare, SQL}) ->
|
exec(Port, {prepare, SQL}) ->
|
||||||
port_control(Port, ?PREPARE, SQL),
|
port_control(Port, ?PREPARE, SQL),
|
||||||
wait_result(Port);
|
wait_result(Port);
|
||||||
@@ -876,6 +1123,17 @@ wait_result(Port) ->
|
|||||||
{error, -1, Reason}
|
{error, -1, Reason}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
many_results_loop(Port) ->
|
||||||
|
do_many_results_loop(Port, []).
|
||||||
|
|
||||||
|
do_many_results_loop(Port, Acc) ->
|
||||||
|
case wait_result(Port) of
|
||||||
|
done ->
|
||||||
|
lists:reverse(Acc);
|
||||||
|
Reply ->
|
||||||
|
do_many_results_loop(Port, [Reply | Acc])
|
||||||
|
end.
|
||||||
|
|
||||||
parse_table_info(Info) ->
|
parse_table_info(Info) ->
|
||||||
[_, Tail] = string:tokens(Info, "()"),
|
[_, Tail] = string:tokens(Info, "()"),
|
||||||
Cols = string:tokens(Tail, ","),
|
Cols = string:tokens(Tail, ","),
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
-include_lib("eunit/include/eunit.hrl").
|
-include_lib("eunit/include/eunit.hrl").
|
||||||
|
|
||||||
-define(FuncTest(Name), {??Name, fun Name/0}).
|
-define(FuncTest(Name), {??Name, fun Name/0}).
|
||||||
|
-define(WARN_ERROR_MESSAGE, io:format(user, "Error message should be shown...~n", [])).
|
||||||
|
|
||||||
drop_all_tables(Db) ->
|
drop_all_tables(Db) ->
|
||||||
Tables = sqlite3:list_tables(Db),
|
Tables = sqlite3:list_tables(Db),
|
||||||
@@ -61,6 +62,10 @@ basic_functionality() ->
|
|||||||
AbbyOnly = [{1, <<"abby">>, 20, 2000}],
|
AbbyOnly = [{1, <<"abby">>, 20, 2000}],
|
||||||
TableInfo = [{id, integer, [primary_key]}, {name, text, [not_null, unique]}, {age, integer}, {wage, integer}],
|
TableInfo = [{id, integer, [primary_key]}, {name, text, [not_null, unique]}, {age, integer}, {wage, integer}],
|
||||||
drop_all_tables(ct),
|
drop_all_tables(ct),
|
||||||
|
?WARN_ERROR_MESSAGE,
|
||||||
|
?assertEqual(
|
||||||
|
{error, 21, "empty statement"},
|
||||||
|
sqlite3:sql_exec(ct, "-- Comment")),
|
||||||
?assertEqual(
|
?assertEqual(
|
||||||
[],
|
[],
|
||||||
sqlite3:list_tables(ct)),
|
sqlite3:list_tables(ct)),
|
||||||
@@ -77,7 +82,7 @@ basic_functionality() ->
|
|||||||
?assertEqual(
|
?assertEqual(
|
||||||
{rowid, 2},
|
{rowid, 2},
|
||||||
sqlite3:write(ct, user, [{name, "marge"}, {age, 30}, {wage, 2000}])),
|
sqlite3:write(ct, user, [{name, "marge"}, {age, 30}, {wage, 2000}])),
|
||||||
?debugMsg("Error message \"sqlite3 driver error: constraint failed\" should be shown..."),
|
?WARN_ERROR_MESSAGE,
|
||||||
?assertEqual(
|
?assertEqual(
|
||||||
{error, 19, "constraint failed"},
|
{error, 19, "constraint failed"},
|
||||||
sqlite3:write(ct, user, [{name, "marge"}, {age, 30}, {wage, 2000}])),
|
sqlite3:write(ct, user, [{name, "marge"}, {age, 30}, {wage, 2000}])),
|
||||||
@@ -229,6 +234,41 @@ prepared_test() ->
|
|||||||
?assertEqual(ok, sqlite3:finalize(prepared, Ref2)),
|
?assertEqual(ok, sqlite3:finalize(prepared, Ref2)),
|
||||||
sqlite3:close(prepared).
|
sqlite3:close(prepared).
|
||||||
|
|
||||||
|
script_test() ->
|
||||||
|
sqlite3:open(script, [in_memory]),
|
||||||
|
Script = string:join(
|
||||||
|
["CREATE TABLE person(",
|
||||||
|
"id INTEGER",
|
||||||
|
");",
|
||||||
|
" ",
|
||||||
|
"-- Comment",
|
||||||
|
"INSERT INTO person (id) VALUES (1);",
|
||||||
|
"INSERT INTO person (id) VALUES (2);",
|
||||||
|
" "
|
||||||
|
], "\n"),
|
||||||
|
?WARN_ERROR_MESSAGE,
|
||||||
|
?assertEqual(
|
||||||
|
[ok, ok, ok, {error, 21, "empty statement"}],
|
||||||
|
sqlite3:sql_exec_script(script, Script)),
|
||||||
|
?assertEqual(
|
||||||
|
[{columns,["id"]},{rows,[{1},{2}]}],
|
||||||
|
sqlite3:read_all(script, person)),
|
||||||
|
BadScript = string:join(
|
||||||
|
["CREATE TABLE person2(",
|
||||||
|
"id INTEGER",
|
||||||
|
");",
|
||||||
|
" ",
|
||||||
|
"-- Comment",
|
||||||
|
"SYNTAX ERROR;",
|
||||||
|
"INSERT INTO person (id) VALUES (2);",
|
||||||
|
" "
|
||||||
|
], "\n"),
|
||||||
|
?WARN_ERROR_MESSAGE,
|
||||||
|
?assertEqual(
|
||||||
|
[ok, {error, 1, "near \"SYNTAX\": syntax error"}],
|
||||||
|
sqlite3:sql_exec_script(script, BadScript)),
|
||||||
|
sqlite3:close(script).
|
||||||
|
|
||||||
% create, read, update, delete
|
% create, read, update, delete
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
%% Internal functions
|
%% Internal functions
|
||||||
|
|||||||
Reference in New Issue
Block a user