Better interface for bulk inserts
This commit is contained in:
104
src/sqlite3.erl
104
src/sqlite3.erl
@@ -19,11 +19,12 @@
|
||||
|
||||
-export([create_table/2, create_table/3, create_table/4]).
|
||||
-export([list_tables/0, list_tables/1, table_info/1, table_info/2]).
|
||||
-export([write/2, write/3]).
|
||||
-export([write/2, write/3, write_many/2, write_many/3]).
|
||||
-export([update/4, update/5]).
|
||||
-export([read_all/2, read_all/3, read/2, read/3, read/4]).
|
||||
-export([delete/2, delete/3]).
|
||||
-export([drop_table/1, drop_table/2]).
|
||||
-export([begin_transaction/1, commit_transaction/1, rollback_transaction/1]).
|
||||
|
||||
-export([create_function/3]).
|
||||
|
||||
@@ -261,6 +262,30 @@ write(Tbl, Data) ->
|
||||
write(Db, Tbl, Data) ->
|
||||
gen_server:call(Db, {write, Tbl, Data}).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% @spec write_many(Tbl :: atom(), Data) -> any()
|
||||
%% Data = [[{Column :: atom(), Value :: sql_value()}]]
|
||||
%% @doc
|
||||
%% Write all records in Data into table Tbl. Value must be of the
|
||||
%% same type as determined from table_info/2.
|
||||
%% @end
|
||||
%%--------------------------------------------------------------------
|
||||
-spec write_many(atom(), [[{atom(), sql_value()}]]) -> any().
|
||||
write_many(Tbl, Data) ->
|
||||
write_many(?MODULE, Tbl, Data).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% @spec write_many(Db :: atom(), Tbl :: atom(), Data) -> term()
|
||||
%% 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(atom(), atom(), [[{atom(), sql_value()}]]) -> any().
|
||||
write_many(Db, Tbl, Data) ->
|
||||
gen_server:call(Db, {write_many, Tbl, Data}).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% @spec update(Tbl :: atom(), Key :: atom(), Value, Data) -> Result
|
||||
%% Value = any()
|
||||
@@ -410,6 +435,39 @@ drop_table(Db, Tbl) ->
|
||||
create_function(Db, FunctionName, Function) ->
|
||||
gen_server:call(Db, {create_function, FunctionName, Function}).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% @spec begin_transaction(Db :: atom()) -> term()
|
||||
%% @doc
|
||||
%% Begins a transaction in Db.
|
||||
%% @end
|
||||
%%--------------------------------------------------------------------
|
||||
-spec begin_transaction(atom()) -> any().
|
||||
begin_transaction(Db) ->
|
||||
SQL = "BEGIN;",
|
||||
sql_exec(Db, SQL).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% @spec commit_transaction(Db :: atom()) -> term()
|
||||
%% @doc
|
||||
%% Commits the current transaction in Db.
|
||||
%% @end
|
||||
%%--------------------------------------------------------------------
|
||||
-spec commit_transaction(atom()) -> any().
|
||||
commit_transaction(Db) ->
|
||||
SQL = "COMMIT;",
|
||||
sql_exec(Db, SQL).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% @spec rollback_transaction(Db :: atom()) -> term()
|
||||
%% @doc
|
||||
%% Rolls back the current transaction in Db.
|
||||
%% @end
|
||||
%%--------------------------------------------------------------------
|
||||
-spec rollback_transaction(atom()) -> any().
|
||||
rollback_transaction(Db) ->
|
||||
SQL = "ROLLBACK;",
|
||||
sql_exec(Db, SQL).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% @spec value_to_sql_unsafe(Value :: sql_value()) -> iolist()
|
||||
%% @doc
|
||||
@@ -493,17 +551,17 @@ init(Options) ->
|
||||
handle_call(close, _From, State) ->
|
||||
Reply = ok,
|
||||
{stop, normal, Reply, State};
|
||||
handle_call(list_tables, _From, #state{port = Port} = State) ->
|
||||
handle_call(list_tables, _From, State) ->
|
||||
SQL = "select name from sqlite_master where type='table';",
|
||||
Reply = exec(Port, {sql_exec, SQL}),
|
||||
TableList = proplists:get_value(rows, Reply),
|
||||
Data = do_sql_exec(SQL, State),
|
||||
TableList = proplists:get_value(rows, Data),
|
||||
TableNames = [erlang:list_to_atom(erlang:binary_to_list(Name)) || {Name} <- TableList],
|
||||
{reply, TableNames, State};
|
||||
handle_call({table_info, Tbl}, _From, #state{port = Port} = State) ->
|
||||
handle_call({table_info, Tbl}, _From, State) ->
|
||||
% make sure we only get table info.
|
||||
% SQL Injection warning
|
||||
SQL = io_lib:format("select sql from sqlite_master where tbl_name = '~p' and type='table';", [Tbl]),
|
||||
Data = exec(Port, {sql_exec, SQL}),
|
||||
Data = do_sql_exec(SQL, State),
|
||||
TableSql = proplists:get_value(rows, Data),
|
||||
case TableSql of
|
||||
[{Info}] ->
|
||||
@@ -518,41 +576,45 @@ handle_call({create_function, FunctionName, Function}, _From, #state{port = Port
|
||||
Reply = exec(Port, {create_function, FunctionName, Function}),
|
||||
{reply, Reply, State};
|
||||
handle_call({sql_exec, SQL}, _From, State) ->
|
||||
do_handle_sql_exec(SQL, State);
|
||||
do_handle_call_sql_exec(SQL, State);
|
||||
handle_call({create_table, Tbl, Columns}, _From, State) ->
|
||||
SQL = sqlite3_lib:create_table_sql(Tbl, Columns),
|
||||
do_handle_sql_exec(SQL, State);
|
||||
do_handle_call_sql_exec(SQL, State);
|
||||
handle_call({create_table, Tbl, Columns, Constraints}, _From, State) ->
|
||||
SQL = sqlite3_lib:create_table_sql(Tbl, Columns, Constraints),
|
||||
do_handle_sql_exec(SQL, State);
|
||||
do_handle_call_sql_exec(SQL, State);
|
||||
handle_call({update, Tbl, Key, Value, Data}, _From, State) ->
|
||||
SQL = sqlite3_lib:update_sql(Tbl, Key, Value, Data),
|
||||
do_handle_sql_exec(SQL, State);
|
||||
do_handle_call_sql_exec(SQL, State);
|
||||
handle_call({write, Tbl, Data}, _From, State) ->
|
||||
% insert into t1 (data,num) values ('This is sample data',3);
|
||||
SQL = sqlite3_lib:write_sql(Tbl, Data),
|
||||
do_handle_sql_exec(SQL, State);
|
||||
do_handle_call_sql_exec(SQL, State);
|
||||
handle_call({write_many, Tbl, DataList}, _From, State) ->
|
||||
do_sql_exec("BEGIN;", State),
|
||||
[do_sql_exec(sqlite3_lib:write_sql(Tbl, Data), State) || Data <- DataList],
|
||||
do_handle_call_sql_exec("COMMIT;", State);
|
||||
handle_call({read, Tbl}, _From, State) ->
|
||||
% select * from Tbl where Key = Value;
|
||||
SQL = sqlite3_lib:read_sql(Tbl),
|
||||
do_handle_sql_exec(SQL, State);
|
||||
do_handle_call_sql_exec(SQL, State);
|
||||
handle_call({read, Tbl, Columns}, _From, State) ->
|
||||
SQL = sqlite3_lib:read_sql(Tbl, Columns),
|
||||
do_handle_sql_exec(SQL, State);
|
||||
do_handle_call_sql_exec(SQL, State);
|
||||
handle_call({read, Tbl, Key, Value}, _From, State) ->
|
||||
% select * from Tbl where Key = Value;
|
||||
SQL = sqlite3_lib:read_sql(Tbl, Key, Value),
|
||||
do_handle_sql_exec(SQL, State);
|
||||
do_handle_call_sql_exec(SQL, State);
|
||||
handle_call({read, Tbl, Key, Value, Columns}, _From, State) ->
|
||||
SQL = sqlite3_lib:read_sql(Tbl, Key, Value, Columns),
|
||||
do_handle_sql_exec(SQL, State);
|
||||
do_handle_call_sql_exec(SQL, State);
|
||||
handle_call({delete, Tbl, {Key, Value}}, _From, State) ->
|
||||
% delete from Tbl where Key = Value;
|
||||
SQL = sqlite3_lib:delete_sql(Tbl, Key, Value),
|
||||
do_handle_sql_exec(SQL, State);
|
||||
do_handle_call_sql_exec(SQL, State);
|
||||
handle_call({drop_table, Tbl}, _From, State) ->
|
||||
SQL = sqlite3_lib:drop_table_sql(Tbl),
|
||||
do_handle_sql_exec(SQL, State);
|
||||
do_handle_call_sql_exec(SQL, State);
|
||||
handle_call(_Request, _From, State) ->
|
||||
Reply = ok,
|
||||
{reply, Reply, State}.
|
||||
@@ -621,11 +683,15 @@ code_change(_OldVsn, State, _Extra) ->
|
||||
create_port_cmd(Dbase) ->
|
||||
atom_to_list(?DRIVER_NAME) ++ " " ++ Dbase.
|
||||
|
||||
do_handle_sql_exec(SQL, #state{port = Port} = State) ->
|
||||
do_handle_call_sql_exec(SQL, State) ->
|
||||
?dbg("SQL: ~s~n", [SQL]),
|
||||
Reply = exec(Port, {sql_exec, SQL}),
|
||||
Reply = do_sql_exec(SQL, State),
|
||||
{reply, Reply, State}.
|
||||
|
||||
do_sql_exec(SQL, #state{port = Port}) ->
|
||||
?dbg("SQL: ~s~n", [SQL]),
|
||||
exec(Port, {sql_exec, SQL}).
|
||||
|
||||
exec(_Port, {create_function, _FunctionName, _Function}) ->
|
||||
error_logger:error_report([{application, sqlite3}, "NOT IMPL YET"]);
|
||||
%port_control(Port, ?SQL_CREATE_FUNCTION, list_to_binary(Cmd)),
|
||||
|
||||
@@ -7,14 +7,13 @@
|
||||
%%%-------------------------------------------------------------------
|
||||
-module(sqlite3_test).
|
||||
|
||||
%%====================================================================
|
||||
%% ====================================================================
|
||||
%% API
|
||||
%%====================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% ====================================================================
|
||||
%% --------------------------------------------------------------------
|
||||
%% Function:
|
||||
%% Description:
|
||||
%%--------------------------------------------------------------------
|
||||
-ifdef(TEST).
|
||||
%% --------------------------------------------------------------------
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
drop_all_tables(Db) ->
|
||||
@@ -84,7 +83,10 @@ select_many_records_test() ->
|
||||
sqlite3:open(ct),
|
||||
drop_table_if_exists(ct, many_records),
|
||||
sqlite3:create_table(ct, many_records, [{id, integer}, {name, text}]),
|
||||
[sqlite3:write(ct, many_records, [{id, X}, {name, "bar"}]) || X <- lists:seq(1, 1024)], %% takes very long :(
|
||||
sqlite3:write_many(ct, many_records, [[{id, X}, {name, "bar"}] || X <- lists:seq(1, 1024)]),
|
||||
%% sqlite3:begin_transaction(ct),
|
||||
%% [sqlite3:write(ct, many_records, [{id, X}, {name, "bar"}]) || X <- lists:seq(1, 1024)], %% takes very long :(
|
||||
%% sqlite3:commit_transaction(ct),
|
||||
Columns = ["id", "name"],
|
||||
?assertEqual(
|
||||
[{columns, Columns}, {rows, [{1, <<"bar">>}]}],
|
||||
@@ -108,8 +110,6 @@ nonexistent_table_info_test() ->
|
||||
?assertEqual(table_does_not_exist, sqlite3:table_info(ct, nonexistent)),
|
||||
sqlite3:close(ct).
|
||||
|
||||
-endif.
|
||||
|
||||
% create, read, update, delete
|
||||
%%====================================================================
|
||||
%% Internal functions
|
||||
|
||||
Reference in New Issue
Block a user