diff options
Diffstat (limited to 'lib/odbc/test/odbc_connect_SUITE.erl')
-rw-r--r-- | lib/odbc/test/odbc_connect_SUITE.erl | 816 |
1 files changed, 816 insertions, 0 deletions
diff --git a/lib/odbc/test/odbc_connect_SUITE.erl b/lib/odbc/test/odbc_connect_SUITE.erl new file mode 100644 index 0000000000..4d37a8f543 --- /dev/null +++ b/lib/odbc/test/odbc_connect_SUITE.erl @@ -0,0 +1,816 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2002-2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% + +-module(odbc_connect_SUITE). + +%% Note: This directive should only be used in test suites. +-compile(export_all). + +-include("test_server.hrl"). +-include("test_server_line.hrl"). +-include("odbc_test.hrl"). + +-define(MAX_SEQ_TIMEOUTS, 10). + +%%-------------------------------------------------------------------- +%% all(Arg) -> [Doc] | [Case] | {skip, Comment} +%% Arg - doc | suite +%% Doc - string() +%% Case - atom() +%% Name of a test case function. +%% Comment - string() +%% Description: Returns documentation/test cases in this test suite +%% or a skip tuple if the platform is not supported. +%%-------------------------------------------------------------------- +all(doc) -> + ["Tests the ability to connect and disconnet to/from the database"]; +all(suite) -> + case odbc_test_lib:odbc_check() of + ok -> all(); + Other -> {skip, Other} + end. + +all() -> + [not_exist_db, commit, rollback, not_explicit_commit, + no_c_node, port_dies, control_process_dies, client_dies, + connect_timeout, timeout, many_timeouts, timeout_reset, + disconnect_on_timeout, connection_closed, + disable_scrollable_cursors, return_rows_as_lists, api_missuse]. + +%%-------------------------------------------------------------------- +%% Function: init_per_suite(Config) -> Config +%% Config - [tuple()] +%% A list of key/value pairs, holding the test case configuration. +%% Description: Initiation before the whole suite +%% +%% Note: This function is free to add any key/value pairs to the Config +%% variable, but should NOT alter/remove any existing entries. +%%-------------------------------------------------------------------- +init_per_suite(Config) -> + application:start(odbc), + case odbc:connect(?RDBMS:connection_string(), + [{auto_commit, off}]) of + {ok, Ref} -> + odbc:disconnect(Ref), + [{tableName, odbc_test_lib:unique_table_name()} | Config]; + _ -> + {skip, "ODBC is not properly setup"} + end. +%%-------------------------------------------------------------------- +%% Function: end_per_suite(Config) -> _ +%% Config - [tuple()] +%% A list of key/value pairs, holding the test case configuration. +%% Description: Cleanup after the whole suite +%%-------------------------------------------------------------------- +end_per_suite(_Config) -> + application:stop(odbc), + ok. + +%%-------------------------------------------------------------------- +%% Function: init_per_testcase(Case, Config) -> Config +%% Case - atom() +%% Name of the test case that is about to be run. +%% Config - [tuple()] +%% A list of key/value pairs, holding the test case configuration. +%% +%% Description: Initiation before each test case +%% +%% Note: This function is free to add any key/value pairs to the Config +%% variable, but should NOT alter/remove any existing entries. +%%-------------------------------------------------------------------- +init_per_testcase(_TestCase, Config) -> + test_server:format("ODBCINI = ~p~n", [os:getenv("ODBCINI")]), + Dog = test_server:timetrap(?default_timeout), + Temp = lists:keydelete(connection_ref, 1, Config), + NewConfig = lists:keydelete(watchdog, 1, Temp), + [{watchdog, Dog} | NewConfig]. + +%%-------------------------------------------------------------------- +%% Function: end_per_testcase(Case, Config) -> _ +%% Case - atom() +%% Name of the test case that is about to be run. +%% Config - [tuple()] +%% A list of key/value pairs, holding the test case configuration. +%% Description: Cleanup after each test case +%%-------------------------------------------------------------------- +end_per_testcase(_TestCase, Config) -> + %% Clean up if needed + Table = ?config(tableName, Config), + {ok, Ref} = odbc:connect(?RDBMS:connection_string(), []), + Result = odbc:sql_query(Ref, "DROP TABLE " ++ Table), + io:format("Drop table: ~p ~p~n", [Table, Result]), + odbc:disconnect(Ref), + Dog = ?config(watchdog, Config), + test_server:timetrap_cancel(Dog), + ok. + +%%------------------------------------------------------------------------- +%% Test cases starts here. +%%------------------------------------------------------------------------- +commit(doc)-> + ["Test the use of explicit commit"]; +commit(suite) -> []; +commit(Config) -> + {ok, Ref} = odbc:connect(?RDBMS:connection_string(), + [{auto_commit, off}]), + + Table = ?config(tableName, Config), + {updated, _} = + odbc:sql_query(Ref, + "CREATE TABLE " ++ Table ++ + " (ID integer, DATA varchar(10))"), + + {updated, 1} = + odbc:sql_query(Ref, "INSERT INTO " ++ Table ++" VALUES(1,'bar')"), + + {updated, 1} = + odbc:sql_query(Ref, "UPDATE " ++ Table ++ + " SET DATA = 'foo' WHERE ID = 1"), + + ok = odbc:commit(Ref, commit), + UpdateResult = ?RDBMS:update_result(), + UpdateResult = + odbc:sql_query(Ref, "SELECT * FROM " ++ Table), + + {updated, 1} = + odbc:sql_query(Ref, "UPDATE " ++ Table ++ + " SET DATA = 'bar' WHERE ID = 1"), + ok = odbc:commit(Ref, commit, ?TIMEOUT), + InsertResult = ?RDBMS:insert_result(), + InsertResult = + odbc:sql_query(Ref, "SELECT * FROM " ++ Table), + + {'EXIT', {function_clause, _}} = + (catch odbc:commit(Ref, commit, -1)), + + ok = odbc:disconnect(Ref), + + ok. +%%------------------------------------------------------------------------- + +rollback(doc)-> + ["Test the use of explicit rollback"]; +rollback(suite) -> []; +rollback(Config) -> + {ok, Ref} = odbc:connect(?RDBMS:connection_string(), + [{auto_commit, off}]), + + Table = ?config(tableName, Config), + + {updated, _} = + odbc:sql_query(Ref, + "CREATE TABLE " ++ Table ++ + " (ID integer, DATA varchar(10))"), + {updated, 1} = + odbc:sql_query(Ref, "INSERT INTO " ++ Table ++ " VALUES(1,'bar')"), + ok = odbc:commit(Ref, commit), + + {updated, 1} = + odbc:sql_query(Ref, "UPDATE " ++ Table ++ + " SET DATA = 'foo' WHERE ID = 1"), + ok = odbc:commit(Ref, rollback), + InsertResult = ?RDBMS:insert_result(), + InsertResult = + odbc:sql_query(Ref, "SELECT * FROM " ++ Table), + + {updated, 1} = + odbc:sql_query(Ref, "UPDATE " ++ Table ++ + " SET DATA = 'foo' WHERE ID = 1"), + ok = odbc:commit(Ref, rollback, ?TIMEOUT), + InsertResult = ?RDBMS:insert_result(), + InsertResult = + odbc:sql_query(Ref, "SELECT * FROM " ++ Table), + + + {'EXIT', {function_clause, _}} = + (catch odbc:commit(Ref, rollback, -1)), + + ok = odbc:disconnect(Ref), + ok. + +%%------------------------------------------------------------------------- +not_explicit_commit(doc) -> + ["Test what happens if you try using commit on a auto_commit connection."]; +not_explicit_commit(suite) -> []; +not_explicit_commit(_Config) -> + {ok, Ref} = + odbc:connect(?RDBMS:connection_string(), [{auto_commit, on}]), + {error, _} = odbc:commit(Ref, commit), + ok = odbc:disconnect(Ref), + ok. + +%%------------------------------------------------------------------------- +not_exist_db(doc) -> + ["Tests valid data format but invalid data in the connection parameters."]; +not_exist_db(suite) -> []; +not_exist_db(_Config) -> + {error, _} = odbc:connect("DSN=foo;UID=bar;PWD=foobar", []), + %% So that the odbc control server can be stoped "in the correct way" + test_server:sleep(100), + ok. + +%%------------------------------------------------------------------------- +no_c_node(doc) -> + "Test what happens if the port-program can not be found"; +no_c_node(suite) -> []; +no_c_node(_Config) -> + process_flag(trap_exit, true), + Dir = filename:nativename(filename:join(code:priv_dir(odbc), + "bin")), + FileName1 = filename:nativename(os:find_executable("odbcserver", + Dir)), + FileName2 = filename:nativename(filename:join(Dir, "odbcsrv")), + ok = file:rename(FileName1, FileName2), + Result = + case catch odbc:connect(?RDBMS:connection_string(), []) of + {error, port_program_executable_not_found} -> + ok; + Else -> + Else + end, + + ok = file:rename(FileName2, FileName1), + ok = Result. +%%------------------------------------------------------------------------ + +port_dies(doc) -> + "Tests what happens if the port program dies"; +port_dies(suite) -> []; +port_dies(_Config) -> + {ok, Ref} = odbc:connect(?RDBMS:connection_string(), []), + {status, _} = process_info(Ref, status), + process_flag(trap_exit, true), + Port = lists:last(erlang:ports()), + exit(Port, kill), + %% Wait for exit_status from port 5000 ms (will not get a exit + %% status in this case), then wait a little longer to make sure + %% the port and the controlprocess has had time to terminate. + test_server:sleep(7000), + undefined = process_info(Ref, status), + ok. + +%%------------------------------------------------------------------------- +control_process_dies(doc) -> + "Tests what happens if the Erlang control process dies"; +control_process_dies(suite) -> []; +control_process_dies(_Config) -> + {ok, Ref} = odbc:connect(?RDBMS:connection_string(), []), + process_flag(trap_exit, true), + Port = lists:last(erlang:ports()), + {connected, Ref} = erlang:port_info(Port, connected), + exit(Ref, kill), + test_server:sleep(100), + undefined = erlang:port_info(Port, connected), + %% Check for c-program still running, how? + ok. + +%%------------------------------------------------------------------------- +client_dies(doc) -> + ["Test that the odbc process is terminated when the client process " + "dies"]; +client_dies(suite) -> + [client_dies_normal, client_dies_timeout, client_dies_error]. + +%%------------------------------------------------------------------------- +client_dies_normal(doc) -> + ["Client dies with reason normal."]; +client_dies_normal(suite) -> []; +client_dies_normal(Config) when is_list(Config) -> + Pid = spawn(?MODULE, client_normal, [self()]), + + MonitorReference = + receive + {dbRef, Ref} -> + MRef = erlang:monitor(process, Ref), + Pid ! continue, + MRef + end, + + receive + {'DOWN', MonitorReference, _Type, _Object, _Info} -> + ok + after 5000 -> + test_server:fail(control_process_not_stopped) + end. + +client_normal(Pid) -> + {ok, Ref} = odbc:connect(?RDBMS:connection_string(), []), + Pid ! {dbRef, Ref}, + receive + continue -> + ok + end, + exit(self(), normal). + + +%%------------------------------------------------------------------------- +client_dies_timeout(doc) -> + ["Client dies with reason timeout."]; +client_dies_timeout(suite) -> []; +client_dies_timeout(Config) when is_list(Config) -> + Pid = spawn(?MODULE, client_timeout, [self()]), + + MonitorReference = + receive + {dbRef, Ref} -> + MRef = erlang:monitor(process, Ref), + Pid ! continue, + MRef + end, + + receive + {'DOWN', MonitorReference, _Type, _Object, _Info} -> + ok + after 5000 -> + test_server:fail(control_process_not_stopped) + end. + +client_timeout(Pid) -> + {ok, Ref} = odbc:connect(?RDBMS:connection_string(), []), + Pid ! {dbRef, Ref}, + receive + continue -> + ok + end, + exit(self(), timeout). + + +%%------------------------------------------------------------------------- +client_dies_error(doc) -> + ["Client dies with reason error."]; +client_dies_error(suite) -> []; +client_dies_error(Config) when is_list(Config) -> + Pid = spawn(?MODULE, client_error, [self()]), + + MonitorReference = + receive + {dbRef, Ref} -> + MRef = erlang:monitor(process, Ref), + Pid ! continue, + MRef + end, + + receive + {'DOWN', MonitorReference, _Type, _Object, _Info} -> + ok + after 5000 -> + test_server:fail(control_process_not_stopped) + end. + +client_error(Pid) -> + {ok, Ref} = odbc:connect(?RDBMS:connection_string(), []), + Pid ! {dbRef, Ref}, + receive + continue -> + ok + end, + exit(self(), error). + + +%%------------------------------------------------------------------------- +connect_timeout(doc) -> + ["Test the timeout for the connect function."]; +connect_timeout(suite) -> []; +connect_timeout(Config) when is_list(Config) -> + {'EXIT',timeout} = (catch odbc:connect(?RDBMS:connection_string(), + [{timeout, 0}])), + ok. +%%------------------------------------------------------------------------- +timeout(doc) -> + ["Test that timeouts don't cause unwanted behavior sush as receiving" + " an anwser to a previously tiemed out query."]; +timeout(suite) -> []; +timeout(Config) when is_list(Config) -> + + {ok, Ref} = odbc:connect(?RDBMS:connection_string(), + [{auto_commit, off}]), + Table = ?config(tableName, Config), + + {updated, _} = + odbc:sql_query(Ref, + "CREATE TABLE " ++ Table ++ + " (ID integer, DATA varchar(10), PRIMARY KEY(ID))"), + + {updated, 1} = + odbc:sql_query(Ref, "INSERT INTO " ++ Table ++ " VALUES(1,'bar')"), + + ok = odbc:commit(Ref, commit), + + {updated, 1} = + odbc:sql_query(Ref, "UPDATE " ++ Table ++ + " SET DATA = 'foo' WHERE ID = 1"), + + {updated, 1} = + odbc:sql_query(Ref, "INSERT INTO " ++ Table ++ " VALUES(2,'baz')"), + + Pid = spawn_link(?MODULE, update_table_timeout, [Table, 5000, self()]), + + receive + timout_occurred -> + ok = odbc:commit(Ref, commit), + Pid ! continue + end, + + receive + altered -> + ok + end, + + {selected, Fields, [{"foobar"}]} = + odbc:sql_query(Ref, "SELECT DATA FROM " ++ Table ++ " WHERE ID = 1"), + ["DATA"] = odbc_test_lib:to_upper(Fields), + + ok = odbc:commit(Ref, commit), + ok = odbc:disconnect(Ref), + ok. + + +update_table_timeout(Table, TimeOut, Pid) -> + + {ok, Ref} = odbc:connect(?RDBMS:connection_string(), + [{auto_commit, off}]), + UpdateQuery = "UPDATE " ++ Table ++ " SET DATA = 'foobar' WHERE ID = 1", + + case catch odbc:sql_query(Ref, UpdateQuery, TimeOut) of + {'EXIT', timeout} -> + Pid ! timout_occurred; + {updated, 1} -> + test_server:fail(database_locker_failed) + end, + + receive + continue -> + ok + end, + + %% Make sure we receive the correct result and not the answer + %% to the previous query. + {selected, Fields, [{"baz"}]} = + odbc:sql_query(Ref, "SELECT DATA FROM " ++ Table ++ " WHERE ID = 2"), + ["DATA"] = odbc_test_lib:to_upper(Fields), + + {updated, 1} = odbc:sql_query(Ref, UpdateQuery, TimeOut), + + ok = odbc:commit(Ref, commit), + + Pid ! altered, + + ok = odbc:disconnect(Ref), + + ok. +%%------------------------------------------------------------------------- +many_timeouts(doc) -> + ["Tests that many consecutive timeouts lead to that the connection " + "is shutdown."]; +many_timeouts(suite) -> []; +many_timeouts(Config) when is_list(Config) -> + {ok, Ref} = odbc:connect(?RDBMS:connection_string(), + [{auto_commit, off}]), + + Table = ?config(tableName, Config), + + {updated, _} = + odbc:sql_query(Ref, + "CREATE TABLE " ++ Table ++ + " (ID integer, DATA varchar(10), PRIMARY KEY(ID))"), + + {updated, 1} = + odbc:sql_query(Ref, "INSERT INTO " ++ Table ++ " VALUES(1,'bar')"), + + ok = odbc:commit(Ref, commit), + + {updated, 1} = + odbc:sql_query(Ref, "UPDATE " ++ Table ++ + " SET DATA = 'foo' WHERE ID = 1"), + + _Pid = spawn_link(?MODULE, update_table_many_timeouts, + [Table, 5000, self()]), + + receive + many_timeouts_occurred -> + ok + end, + + ok = odbc:commit(Ref, commit), + ok = odbc:disconnect(Ref), + ok. + + +update_table_many_timeouts(Table, TimeOut, Pid) -> + + {ok, Ref} = odbc:connect(?RDBMS:connection_string(), + [{auto_commit, off}]), + UpdateQuery = "UPDATE " ++ Table ++ " SET DATA = 'foobar' WHERE ID = 1", + + ok = loop_many_timouts(Ref, UpdateQuery, TimeOut), + + Pid ! many_timeouts_occurred, + + ok = odbc:disconnect(Ref), + ok. + + +loop_many_timouts(Ref, UpdateQuery, TimeOut) -> + case catch odbc:sql_query(Ref, UpdateQuery, TimeOut) of + {'EXIT',timeout} -> + loop_many_timouts(Ref, UpdateQuery, TimeOut); + {updated, 1} -> + test_server:fail(database_locker_failed); + {error, connection_closed} -> + ok + end. +%%------------------------------------------------------------------------- +timeout_reset(doc) -> + ["Check that the number of consecutive timouts is reset to 0 when " + "a successful call to the database is made."]; +timeout_reset(suite) -> []; +timeout_reset(Config) when is_list(Config) -> + {ok, Ref} = odbc:connect(?RDBMS:connection_string(), + [{auto_commit, off}]), + Table = ?config(tableName, Config), + + {updated, _} = + odbc:sql_query(Ref, + "CREATE TABLE " ++ Table ++ + " (ID integer, DATA varchar(10), PRIMARY KEY(ID))"), + + {updated, 1} = + odbc:sql_query(Ref, "INSERT INTO " ++ Table ++ " VALUES(1,'bar')"), + + ok = odbc:commit(Ref, commit), + + {updated, 1} = + odbc:sql_query(Ref, "UPDATE " ++ Table ++ + " SET DATA = 'foo' WHERE ID = 1"), + + {updated, 1} = + odbc:sql_query(Ref, "INSERT INTO " ++ Table ++ " VALUES(2,'baz')"), + + + Pid = spawn_link(?MODULE, update_table_timeout_reset, + [Table, 5000, self()]), + + receive + many_timeouts_occurred -> + ok + end, + + ok = odbc:commit(Ref, commit), + Pid ! continue, + + receive + altered -> + ok + end, + + {selected, Fields, [{"foobar"}]} = + odbc:sql_query(Ref, "SELECT DATA FROM " ++ Table ++ " WHERE ID = 1"), + ["DATA"] = odbc_test_lib:to_upper(Fields), + + ok = odbc:commit(Ref, commit), + ok = odbc:disconnect(Ref), + ok. + +update_table_timeout_reset(Table, TimeOut, Pid) -> + + {ok, Ref} = odbc:connect(?RDBMS:connection_string(), + [{auto_commit, off}]), + UpdateQuery = "UPDATE " ++ Table ++ " SET DATA = 'foobar' WHERE ID = 1", + + ok = loop_timout_reset(Ref, UpdateQuery, TimeOut, + ?MAX_SEQ_TIMEOUTS-1), + + Pid ! many_timeouts_occurred, + + receive + continue -> + ok + end, + + {selected, Fields, [{"baz"}]} = + odbc:sql_query(Ref, "SELECT DATA FROM " ++ Table ++ " WHERE ID = 2"), + ["DATA"] = odbc_test_lib:to_upper(Fields), + + {updated,1} = odbc:sql_query(Ref, UpdateQuery, TimeOut), + + ok = odbc:commit(Ref, commit), + + Pid ! altered, + + ok = odbc:disconnect(Ref), + + ok. + +loop_timout_reset(_, _, _, 0) -> + ok; + +loop_timout_reset(Ref, UpdateQuery, TimeOut, NumTimeouts) -> + case catch odbc:sql_query(Ref, UpdateQuery, TimeOut) of + {'EXIT',timeout} -> + loop_timout_reset(Ref, UpdateQuery, + TimeOut, NumTimeouts - 1); + {updated, 1} -> + test_server:fail(database_locker_failed); + {error, connection_closed} -> + test_server:fail(connection_closed_premature) + end. + +%%------------------------------------------------------------------------- + +disconnect_on_timeout(doc) -> + ["Check that disconnect after a time out works properly"]; +disconnect_on_timeout(suite) -> []; +disconnect_on_timeout(Config) when is_list(Config) -> + + {ok, Ref} = odbc:connect(?RDBMS:connection_string(), + [{auto_commit, off}]), + Table = ?config(tableName, Config), + + {updated, _} = + odbc:sql_query(Ref, + "CREATE TABLE " ++ Table ++ + " (ID integer, DATA varchar(10), PRIMARY KEY(ID))"), + + {updated, 1} = + odbc:sql_query(Ref, "INSERT INTO " ++ Table ++ " VALUES(1,'bar')"), + + ok = odbc:commit(Ref, commit), + + {updated, 1} = + odbc:sql_query(Ref, "UPDATE " ++ Table ++ + " SET DATA = 'foo' WHERE ID = 1"), + + + _Pid = spawn_link(?MODULE, update_table_disconnect_on_timeout, + [Table, 5000, self()]), + receive + ok -> + ok = odbc:commit(Ref, commit); + nok -> + test_server:fail(database_locker_failed) + end. + +update_table_disconnect_on_timeout(Table, TimeOut, Pid) -> + + {ok, Ref} = odbc:connect(?RDBMS:connection_string(), + [{auto_commit, off}]), + UpdateQuery = "UPDATE " ++ Table ++ " SET DATA = 'foobar' WHERE ID = 1", + + case catch odbc:sql_query(Ref, UpdateQuery, TimeOut) of + {'EXIT', timeout} -> + ok = odbc:disconnect(Ref), + Pid ! ok; + {updated, 1} -> + Pid ! nok + end. + +%%------------------------------------------------------------------------- +connection_closed(doc) -> + ["Checks that you get an appropriate error message if you try to" + " use a connection that has been closed"]; +connection_closed(suite) -> []; +connection_closed(Config) when is_list(Config) -> + {ok, Ref} = odbc:connect(?RDBMS:connection_string(), []), + + Table = ?config(tableName, Config), + {updated, _} = + odbc:sql_query(Ref, + "CREATE TABLE " ++ Table ++ + " (ID integer, DATA char(10), PRIMARY KEY(ID))"), + + ok = odbc:disconnect(Ref), + + {error, connection_closed} = + odbc:sql_query(Ref, "INSERT INTO " ++ Table ++ " VALUES(1,'bar')"), + {error, connection_closed} = + odbc:select_count(Ref, "SELECT * FROM " ++ Table), + {error, connection_closed} = odbc:first(Ref), + {error, connection_closed} = odbc:last(Ref), + {error, connection_closed} = odbc:next(Ref), + {error, connection_closed} = odbc:prev(Ref), + {error, connection_closed} = odbc:select(Ref, next, 3), + {error, connection_closed} = odbc:commit(Ref, commit), + ok. + +%%------------------------------------------------------------------------- +disable_scrollable_cursors(doc) -> + ["Test disabling of scrollable cursors."]; +disable_scrollable_cursors(suite) -> []; +disable_scrollable_cursors(Config) when is_list(Config) -> + {ok, Ref} = odbc:connect(?RDBMS:connection_string(), + [{scrollable_cursors, off}]), + + Table = ?config(tableName, Config), + + {updated, _} = + odbc:sql_query(Ref, + "CREATE TABLE " ++ Table ++ + " (ID integer, DATA varchar(10), PRIMARY KEY(ID))"), + + {updated, _} = + odbc:sql_query(Ref, "INSERT INTO " ++ Table ++ " VALUES(1,'bar')"), + + {ok, _} = odbc:select_count(Ref, "SELECT ID FROM " ++ Table), + + NextResult = ?RDBMS:selected_ID(1, next), + + test_server:format("Expected: ~p~n", [NextResult]), + + Result = odbc:next(Ref), + test_server:format("Got: ~p~n", [Result]), + NextResult = Result, + + {error, scrollable_cursors_disabled} = odbc:first(Ref), + {error, scrollable_cursors_disabled} = odbc:last(Ref), + {error, scrollable_cursors_disabled} = odbc:prev(Ref), + {error, scrollable_cursors_disabled} = + odbc:select(Ref, {relative, 2}, 5), + {error, scrollable_cursors_disabled} = + odbc:select(Ref, {absolute, 2}, 5), + + {selected, _ColNames,[]} = odbc:select(Ref, next, 1), + ok. + +%%------------------------------------------------------------------------- +return_rows_as_lists(doc)-> + ["Test the option that a row may be returned as a list instead " + "of a tuple. Too be somewhat backward compatible."]; +return_rows_as_lists(suite) -> []; +return_rows_as_lists(Config) when is_list(Config) -> + {ok, Ref} = odbc:connect(?RDBMS:connection_string(), + [{tuple_row, off}]), + + Table = ?config(tableName, Config), + + {updated, _} = + odbc:sql_query(Ref, + "CREATE TABLE " ++ Table ++ + " (ID integer, DATA varchar(10), PRIMARY KEY(ID))"), + + {updated, _} = + odbc:sql_query(Ref, "INSERT INTO " ++ Table ++ " VALUES(1,'bar')"), + + {updated, _} = + odbc:sql_query(Ref, "INSERT INTO " ++ Table ++ " VALUES(2,'foo')"), + + ListRows = ?RDBMS:selected_list_rows(), + ListRows = + odbc:sql_query(Ref, "SELECT * FROM " ++ Table), + + {ok, _} = odbc:select_count(Ref, "SELECT * FROM " ++ Table), + + First = ?RDBMS:first_list_rows(), + Last = ?RDBMS:last_list_rows(), + Prev = ?RDBMS:prev_list_rows(), + Next = ?RDBMS:next_list_rows(), + + Last = odbc:last(Ref), + Prev = odbc:prev(Ref), + First = odbc:first(Ref), + Next = odbc:next(Ref), + ok. + +%%------------------------------------------------------------------------- + +api_missuse(doc)-> + ["Test that behaviour of the control process if the api is abused"]; +api_missuse(suite) -> []; +api_missuse(Config) when is_list(Config)-> + + {ok, Ref} = odbc:connect(?RDBMS:connection_string(), []), + %% Serious programming fault, connetion will be shut down + gen_server:call(Ref, {self(), foobar, 10}, infinity), + test_server:sleep(10), + undefined = process_info(Ref, status), + + {ok, Ref2} = odbc:connect(?RDBMS:connection_string(), []), + %% Serious programming fault, connetion will be shut down + gen_server:cast(Ref2, {self(), foobar, 10}), + test_server:sleep(10), + undefined = process_info(Ref2, status), + + {ok, Ref3} = odbc:connect(?RDBMS:connection_string(), []), + %% Could be an innocent misstake the connection lives. + Ref3 ! foobar, + test_server:sleep(10), + {status, _} = process_info(Ref3, status), + ok. + |