Support script execution (no error messages currently)

This commit is contained in:
Alexey Romanov
2011-01-24 14:01:35 +03:00
parent 9d138346cd
commit 9f57f6ae39
4 changed files with 75 additions and 2 deletions

View File

@@ -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) {
@@ -259,6 +262,32 @@ static int sql_exec(sqlite3_drv_t *drv, char *command, int command_size) {
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;
// printf("SQL: %.*s\n", command_size, command);
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) {
return output_db_error(drv);
} else if (statement == NULL) {
return output_error(drv, SQLITE_MISUSE, "empty statement");
}
result = sql_exec_statement(drv, statement);
if (result) {
// there was an error, bail out
return result;
}
}
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) {

View File

@@ -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);

View File

@@ -15,7 +15,8 @@
-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]).
-export([sql_exec/1, sql_exec/2, sql_exec/3]). -export([sql_exec/1, sql_exec/2, sql_exec/3,
sql_exec_script/2]).
-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]).
-export([create_table/2, create_table/3, create_table/4]). -export([create_table/2, create_table/3, create_table/4]).
@@ -170,6 +171,17 @@ sql_exec(Db, SQL) ->
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_script(Db :: atom(), Sql :: iodata()) -> sql_non_query_result()
%% @doc
%% Executes the Sql script (consisting of semicolon-separated statements)
%% directly on the Db database. Returns 'ok' if there were no errors.
%% @end
%%--------------------------------------------------------------------
-spec sql_exec_script(atom(), iodata()) -> sql_non_query_result().
sql_exec_script(Db, SQL) ->
gen_server:call(Db, {sql_exec_script, SQL}).
-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}).
@@ -643,6 +655,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 +828,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 +845,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 +860,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),
wait_result(Port);
exec(Port, {prepare, SQL}) -> exec(Port, {prepare, SQL}) ->
port_control(Port, ?PREPARE, SQL), port_control(Port, ?PREPARE, SQL),
wait_result(Port); wait_result(Port);

View File

@@ -233,6 +233,25 @@ 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"),
?assertEqual(ok, sqlite3:sql_exec_script(script, Script)),
?assertEqual(
[{columns,["id"]},{rows,[{1},{2}]}],
sqlite3:read_all(script, person)),
sqlite3:close(script).
% create, read, update, delete % create, read, update, delete
%%==================================================================== %%====================================================================
%% Internal functions %% Internal functions