diff options
Diffstat (limited to 'lib')
37 files changed, 939 insertions, 490 deletions
diff --git a/lib/edoc/src/edoc_specs.erl b/lib/edoc/src/edoc_specs.erl index 519ade726f..79a5d142bc 100644 --- a/lib/edoc/src/edoc_specs.erl +++ b/lib/edoc/src/edoc_specs.erl @@ -305,8 +305,6 @@ d2e({ann_type,_,[V, T0]}) -> %% layout module. T = d2e(T0), ?add_t_ann(T, element(3, V)); -d2e({type,_,no_return,[]}) -> - #t_type{name = #t_name{name = none}}; d2e({remote_type,_,[{atom,_,M},{atom,_,F},Ts0]}) -> Ts = d2e(Ts0), typevar_anno(#t_type{name = #t_name{module = M, name = F}, args = Ts}, Ts); diff --git a/lib/edoc/src/edoc_types.erl b/lib/edoc/src/edoc_types.erl index 1ded63dffe..e784b3359a 100644 --- a/lib/edoc/src/edoc_types.erl +++ b/lib/edoc/src/edoc_types.erl @@ -51,6 +51,7 @@ is_predefined(list, 0) -> true; is_predefined(list, 1) -> true; is_predefined(nil, 0) -> true; is_predefined(none, 0) -> true; +is_predefined(no_return, 0) -> true; is_predefined(number, 0) -> true; is_predefined(pid, 0) -> true; is_predefined(port, 0) -> true; diff --git a/lib/edoc/src/edoc_wiki.erl b/lib/edoc/src/edoc_wiki.erl index 9a31bc9a82..ba33198787 100644 --- a/lib/edoc/src/edoc_wiki.erl +++ b/lib/edoc/src/edoc_wiki.erl @@ -360,10 +360,7 @@ par_text(Cs, As, Bs, E, Es) -> [] -> Bs; _ -> [#xmlElement{name = p, content = Es1} | Bs] end, - Bs1 = case Ss of - [] -> Bs0; - _ -> [#xmlText{value = Ss} | Bs0] - end, + Bs1 = [#xmlText{value = Ss} | Bs0], case Cs2 of [] -> par(Es, [], Bs1); diff --git a/lib/kernel/src/inet_dns_record_adts.pl b/lib/kernel/src/inet_dns_record_adts.pl index b1d8fab939..da50c7114f 100644 --- a/lib/kernel/src/inet_dns_record_adts.pl +++ b/lib/kernel/src/inet_dns_record_adts.pl @@ -2,7 +2,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2009. All Rights Reserved. +# Copyright Ericsson AB 2009-2011. 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 @@ -73,6 +73,10 @@ while( my ($Name, $r) = each(%Names)) { # "@Values" = "V1,V2"...",VN" my @D = @DATA; foreach my $line (@D) { + # Ignore !name lines + if ($line =~ s/^\!(\S+)\s+//) { + next if $1 eq $Name; + } my $m = 1; # For leading * iterate $n times, otherwise once $line =~ s/^\s*[*]// and $m = $n; @@ -155,9 +159,9 @@ make_Name() -> \ make_Name(L) when is_list(L) -> \ make_Name(#Record{}, L). -%% Generate #Record{} with one updated field -%% -*make_Name(Field, Value) -> \ +!dns_rr_opt %% Generate #Record{} with one updated field +!dns_rr_opt %% +!dns_rr_opt *make_Name(Field, Value) -> \ #Record{Field=Value}; %% %% Update #Record{} from property list diff --git a/lib/kernel/vsn.mk b/lib/kernel/vsn.mk index e7b71cc168..8be265e79d 100644 --- a/lib/kernel/vsn.mk +++ b/lib/kernel/vsn.mk @@ -1 +1 @@ -KERNEL_VSN = 2.14.4 +KERNEL_VSN = 2.14.5 diff --git a/lib/odbc/c_src/odbcserver.c b/lib/odbc/c_src/odbcserver.c index d61ce940c3..3dd7da08b9 100644 --- a/lib/odbc/c_src/odbcserver.c +++ b/lib/odbc/c_src/odbcserver.c @@ -173,7 +173,7 @@ static db_result_msg encode_row_count(SQLINTEGER num_of_rows, db_state *state); static void encode_column_dyn(db_column column, int column_nr, db_state *state); -static void encode_data_type(SQLINTEGER sql_type, SQLINTEGER size, +static void encode_data_type(SQLSMALLINT sql_type, SQLINTEGER size, SQLSMALLINT decimal_digits, db_state *state); static Boolean decode_params(db_state *state, byte *buffer, int *index, param_array **params, int i, int j); @@ -221,7 +221,7 @@ static void init_param_column(param_array *params, byte *buffer, int *index, int num_param_values, db_state* state); static void init_param_statement(int cols, - int num_param_values, + SQLLEN num_param_values, db_state *state, param_status *status); @@ -435,7 +435,7 @@ static db_result_msg db_connect(byte *args, db_state *state) diagnos diagnos; byte *connStrIn; int erl_auto_commit_mode, erl_trace_driver, - use_srollable_cursors, tuple_row_state, binary_strings; + use_srollable_cursors, tuple_row_state, binary_strings; erl_auto_commit_mode = args[0]; erl_trace_driver = args[1]; @@ -757,8 +757,9 @@ static db_result_msg db_select(byte *args, db_state *state) static db_result_msg db_param_query(byte *buffer, db_state *state) { byte *sql; - db_result_msg msg; - int i, num_param_values, ver = 0, + db_result_msg msg; + SQLLEN num_param_values; + int i, ver = 0, erl_type = 0, index = 0, size = 0, cols = 0; long long_num_param_values; param_status param_status; @@ -785,7 +786,7 @@ static db_result_msg db_param_query(byte *buffer, db_state *state) ei_decode_long(buffer, &index, &long_num_param_values); - num_param_values = (int)long_num_param_values; + num_param_values = (SQLLEN)long_num_param_values; ei_decode_list_header(buffer, &index, &cols); @@ -1002,12 +1003,16 @@ static db_result_msg encode_result(db_state *state) db_result_msg msg; int elements, update, num_of_rows = 0; char *atom; + diagnos diagnos; msg = encode_empty_message(); if(!sql_success(SQLNumResultCols(statement_handle(state), &num_of_columns))) { - DO_EXIT(EXIT_COLS); + diagnos = get_diagnos(SQL_HANDLE_STMT, statement_handle(state)); + msg = encode_error_message(diagnos.error_msg); + clean_state(state); + return msg; } if (num_of_columns == 0) { @@ -1021,7 +1026,10 @@ static db_result_msg encode_result(db_state *state) } if(!sql_success(SQLRowCount(statement_handle(state), &RowCountPtr))) { - DO_EXIT(EXIT_ROWS); + diagnos = get_diagnos(SQL_HANDLE_STMT, statement_handle(state)); + msg = encode_error_message(diagnos.error_msg); + clean_state(state); + return msg; } if(param_query(state) && update) { @@ -1452,7 +1460,7 @@ static void encode_column_dyn(db_column column, int column_nr, } } -static void encode_data_type(SQLINTEGER sql_type, SQLINTEGER size, +static void encode_data_type(SQLSMALLINT sql_type, SQLINTEGER size, SQLSMALLINT decimal_digits, db_state *state) { switch(sql_type) { @@ -2007,7 +2015,7 @@ static void init_driver(int erl_auto_commit_mode, int erl_trace_driver, db_state *state) { - int auto_commit_mode, trace_driver; + SQLLEN auto_commit_mode, trace_driver; if(erl_auto_commit_mode == ON) { auto_commit_mode = SQL_AUTOCOMMIT_ON; @@ -2057,7 +2065,7 @@ static void init_param_column(param_array *params, byte *buffer, int *index, ei_decode_long(buffer, index, &user_type); - params->type.strlen_or_indptr = (SQLINTEGER)NULL; + params->type.strlen_or_indptr = (SQLLEN)NULL; params->type.strlen_or_indptr_array = NULL; params->type.decimal_digits = (SQLINTEGER)0; @@ -2206,7 +2214,7 @@ static void init_param_column(param_array *params, byte *buffer, int *index, } -static void init_param_statement(int cols, int num_param_values, +static void init_param_statement(int cols, SQLLEN num_param_values, db_state *state, param_status *status) { int i; @@ -2234,11 +2242,11 @@ static void init_param_statement(int cols, int num_param_values, DO_EXIT(EXIT_PARAM_ARRAY); } - /* Note the (int *) cast is correct as the API function SQLSetStmtAttr + /* Note the (SQLLEN *) cast is correct as the API function SQLSetStmtAttr takes either an interger or a pointer depending on the attribute */ if(!sql_success(SQLSetStmtAttr(statement_handle(state), SQL_ATTR_PARAMSET_SIZE, - (int *)num_param_values, + (SQLLEN *)num_param_values, 0))) { DO_EXIT(EXIT_PARAM_ARRAY); } @@ -2308,21 +2316,21 @@ static db_result_msg map_sql_2_c_column(db_column* column) case SQL_DECIMAL: map_dec_num_2_c_column(&(column -> type), column -> type.col_size, column -> type.decimal_digits); - column -> type.strlen_or_indptr = (SQLINTEGER)NULL; + column -> type.strlen_or_indptr = (SQLLEN)NULL; break; case SQL_TINYINT: case SQL_INTEGER: case SQL_SMALLINT: column -> type.len = sizeof(SQLINTEGER); column -> type.c = SQL_C_SLONG; - column -> type.strlen_or_indptr = (SQLINTEGER)NULL; + column -> type.strlen_or_indptr = (SQLLEN)NULL; break; case SQL_REAL: case SQL_FLOAT: case SQL_DOUBLE: column -> type.len = sizeof(double); column -> type.c = SQL_C_DOUBLE; - column -> type.strlen_or_indptr = (SQLINTEGER)NULL; + column -> type.strlen_or_indptr = (SQLLEN)NULL; break; case SQL_TYPE_DATE: case SQL_TYPE_TIME: @@ -2334,17 +2342,17 @@ static db_result_msg map_sql_2_c_column(db_column* column) case SQL_TYPE_TIMESTAMP: column -> type.len = sizeof(TIMESTAMP_STRUCT); column -> type.c = SQL_C_TYPE_TIMESTAMP; - column -> type.strlen_or_indptr = (SQLINTEGER)NULL; + column -> type.strlen_or_indptr = (SQLLEN)NULL; break; case SQL_BIGINT: column -> type.len = DEC_NUM_LENGTH; column -> type.c = SQL_C_CHAR; - column -> type.strlen_or_indptr = (SQLINTEGER)NULL; + column -> type.strlen_or_indptr = (SQLLEN)NULL; break; case SQL_BIT: column -> type.len = sizeof(byte); column -> type.c = SQL_C_BIT; - column -> type.strlen_or_indptr = (SQLINTEGER)NULL; + column -> type.strlen_or_indptr = (SQLLEN)NULL; break; case SQL_UNKNOWN_TYPE: msg = encode_error_message("Unknown column type"); diff --git a/lib/odbc/src/odbc.erl b/lib/odbc/src/odbc.erl index 83d9f33102..2634450d4a 100644 --- a/lib/odbc/src/odbc.erl +++ b/lib/odbc/src/odbc.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2010. All Rights Reserved. +%% Copyright Ericsson AB 1999-2011. 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 @@ -431,7 +431,7 @@ init(Args) -> erlang:monitor(process, ClientPid), - Inet = case gen_tcp:listen(0, [inet6]) of + Inet = case gen_tcp:listen(0, [inet6, {ip, loopback}]) of {ok, Dummyport} -> gen_tcp:close(Dummyport), inet6; diff --git a/lib/odbc/test/Makefile b/lib/odbc/test/Makefile index ec2bcc67b5..bc6449242e 100644 --- a/lib/odbc/test/Makefile +++ b/lib/odbc/test/Makefile @@ -34,7 +34,8 @@ MODULES= \ odbc_test_lib \ oracle \ sqlserver \ - postgres + postgres \ + mysql EBIN = . diff --git a/lib/odbc/test/mysql.erl b/lib/odbc/test/mysql.erl new file mode 100644 index 0000000000..76ffd3ecc9 --- /dev/null +++ b/lib/odbc/test/mysql.erl @@ -0,0 +1,266 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2011-2011. 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(mysql). + +%% Note: This directive should only be used in test suites. +-compile(export_all). + +%------------------------------------------------------------------------- +connection_string() -> + "DSN=MySQL;Database=odbctest;Uid=odbctest;Pwd=gurka;CHARSET=utf8;SSTMT=SET NAMES 'utf8';". + +%------------------------------------------------------------------------- +insert_result() -> + {selected,["ID","DATA"],[{1,"bar"}]}. + +update_result() -> + {selected,["ID","DATA"],[{1,"foo"}]}. + +selected_ID(N, next) -> + {selected,["ID"],[{N}]}; + +selected_ID(_, _) -> + {error, driver_does_not_support_function}. + +selected_next_N(1)-> + {selected,["ID"], + [{1}, + {2}, + {3}]}; + +selected_next_N(2)-> + {selected,["ID"], + [{4}, + {5}]}. + +selected_relative_N(_)-> + {error, driver_does_not_support_function}. + +selected_absolute_N(_)-> + {error, driver_does_not_support_function}. + +selected_list_rows() -> + {selected,["ID", "DATA"],[[1, "bar"],[2,"foo"]]}. + +first_list_rows() -> + {error, driver_does_not_support_function}. +last_list_rows() -> + {error, driver_does_not_support_function}. +prev_list_rows() -> + {error, driver_does_not_support_function}. +next_list_rows() -> + {selected,["ID","DATA"],[[1,"bar"]]}. + +multiple_select()-> + [{selected,["ID", "DATA"],[{1, "bar"},{2, "foo"}]}, + {selected,["ID"],[{"foo"}]}]. + +multiple_mix()-> + [{updated, 1},{updated, 1}, + {selected,["ID", "DATA"],[{1, "foobar"},{2, "foo"}]}, + {updated, 1}, {selected,["DATA"],[{"foo"}]}]. + +%------------------------------------------------------------------------- +var_char_min() -> + 0. +var_char_max() -> + 65535. + +create_var_char_table(Size) -> + " (FIELD varchar(" ++ integer_to_list(Size) ++ "))". + +%------------------------------------------------------------------------- +text_min() -> + 1. +text_max() -> + 2147483646. % 2147483647. %% 2^31 - 1 + +create_text_table() -> + " (FIELD text)". + +%------------------------------------------------------------------------- +create_unicode_table() -> + " (FIELD text)". + +%------------------------------------------------------------------------- +create_timestamp_table() -> + " (FIELD TIMESTAMP)". + +%------------------------------------------------------------------------- +tiny_int_min() -> + -128. +tiny_int_max() -> + 127. + +create_tiny_int_table() -> + " (FIELD tinyint)". + +tiny_int_min_selected() -> + {selected,["FIELD"],[{tiny_int_min()}]}. + +tiny_int_max_selected() -> + {selected,["FIELD"], [{tiny_int_max()}]}. + +%------------------------------------------------------------------------- +small_int_min() -> + -32768. +small_int_max() -> + 32767. + +create_small_int_table() -> + " (FIELD smallint)". + +small_int_min_selected() -> + {selected,["FIELD"],[{-32768}]}. + +small_int_max_selected() -> + {selected,["FIELD"], [{32767}]}. + +%------------------------------------------------------------------------- +int_min() -> + -2147483648. +int_max() -> + 2147483647. + +create_int_table() -> + " (FIELD int)". + +int_min_selected() -> + {selected,["FIELD"],[{-2147483648}]}. + +int_max_selected() -> + {selected,["FIELD"], [{2147483647}]}. + +%------------------------------------------------------------------------- +big_int_min() -> + -9223372036854775808. + +big_int_max() -> + 9223372036854775807. + +create_big_int_table() -> + " (FIELD bigint )". + +big_int_min_selected() -> + {selected,["FIELD"], [{"-9223372036854775808"}]}. + +big_int_max_selected() -> + {selected,["FIELD"], [{"9223372036854775807"}]}. + +%------------------------------------------------------------------------- +bit_false() -> + 0. +bit_true() -> + 1. + +create_bit_table() -> + " (FIELD bit)". + +bit_false_selected() -> + {selected,["FIELD"],[{"0"}]}. + +bit_true_selected() -> + {selected,["FIELD"], [{"1"}]}. + +%------------------------------------------------------------------------- + +%% Do not test float min/max as value is only theoretical defined in +%% mysql and may vary depending on hardware. + +create_float_table() -> + " (FIELD float)". + +float_zero_selected() -> + {selected,["FIELD"],[{0.00000e+0}]}. + +%------------------------------------------------------------------------- +real_min() -> + -3.40e+38. +real_max() -> + 3.40e+38. + +real_underflow() -> + "-3.41e+38". + +real_overflow() -> + "3.41e+38". + +create_real_table() -> + " (FIELD real)". + +real_zero_selected() -> + {selected,["FIELD"],[{0.00000e+0}]}. + +%------------------------------------------------------------------------- +param_select_small_int() -> + {selected,["FIELD"],[{1}, {2}]}. + +param_select_int() -> + Int = small_int_max() + 1, + {selected,["FIELD"],[{1}, {Int}]}. + +param_select_decimal() -> + {selected,["FIELD"],[{1},{2}]}. + +param_select_numeric() -> + {selected,["FIELD"],[{1},{2}]}. + +param_select_float() -> + {selected,["FIELD"],[{1.30000},{1.20000}]}. + +param_select_real() -> + {selected,["FIELD"],[{1.30000},{1.20000}]}. + +param_select_double() -> + {selected,["FIELD"],[{1.30000},{1.20000}]}. + +param_select_mix() -> + {selected,["ID","DATA"],[{1, "foo"}, {2, "bar"}]}. + +param_update() -> + {selected,["ID","DATA"],[{1, "foobar"}, {2, "foobar"}, {3, "baz"}]}. + +param_delete() -> + {selected,["ID","DATA"],[{3, "baz"}]}. + +param_select() -> + {selected,["ID","DATA"],[{1, "foo"},{3, "foo"}]}. + +%------------------------------------------------------------------------- +describe_integer() -> + {ok,[{"myint1",sql_smallint}, + {"myint2",sql_integer}, + {"myint3",sql_integer}]}. + +describe_string() -> + {ok,[{"str1",{sql_char,10}}, + {"str2",{sql_char,10}}, + {"str3",{sql_varchar,10}}, + {"str4",{sql_varchar,10}}]}. + +describe_floating() -> + {ok,[{"f",sql_real},{"r",sql_double},{"d",sql_double}]}. +describe_dec_num() -> + {ok,[{"mydec",{sql_decimal,9,3}},{"mynum",{sql_decimal,9,2}}]}. + +describe_timestamp() -> + {ok, [{"FIELD", sql_timestamp}]}. diff --git a/lib/odbc/test/odbc.dynspec b/lib/odbc/test/odbc.dynspec deleted file mode 100644 index bb15edceed..0000000000 --- a/lib/odbc/test/odbc.dynspec +++ /dev/null @@ -1,31 +0,0 @@ -%% -*- erlang -*- -%% You can test this file using this command. -%% file:script("odbc.dynspec", [{'Os',"Unix"}]). - -Exists = -fun() -> - case code:lib_dir(odbc) of - {error,bad_name} -> - false; - P -> - %% Make sure that the odbc directory really - %% contains the application (and not only documentation). - case filelib:is_file(filename:join(P, "ebin/odbc.beam")) of - false -> false; - true -> - %% We know that we don't have any odbc libraries - %% installed on this computer. - {ok,Host} = inet:gethostname(), - Host =/= "netsim200" - end - end -end, -case Exists() of - false -> - NoOdbc = "No odbc application", - [{skip, {odbc_connect_SUITE, NoOdbc}}, - {skip, {odbc_data_type_SUITE, NoOdbc}}, - {skip, {odbc_query_SUITE, NoOdbc}}]; - true -> - [] -end. diff --git a/lib/odbc/test/odbc.spec b/lib/odbc/test/odbc.spec index edaf821c91..653f1a780e 100644 --- a/lib/odbc/test/odbc.spec +++ b/lib/odbc/test/odbc.spec @@ -1,25 +1 @@ {suites,"../odbc_test",all}. -{skip_cases,"../odbc_test",odbc_data_type_SUITE, - [varchar_upper_limit], - "Known bug in database"}. -{skip_cases,"../odbc_test",odbc_data_type_SUITE, - [text_upper_limit], - "Consumes too much resources"}. -{skip_cases,"../odbc_test",odbc_data_type_SUITE, - [bit_true], - "Not supported by driver"}. -{skip_cases,"../odbc_test",odbc_data_type_SUITE, - [bit_false], - "Not supported by driver"}. -{skip_cases,"../odbc_test",odbc_query_SUITE, - [multiple_select_result_sets], - "Not supported by driver"}. -{skip_cases,"../odbc_test",odbc_query_SUITE, - [multiple_mix_result_sets], - "Not supported by driver"}. -{skip_cases,"../odbc_test",odbc_query_SUITE, - [multiple_result_sets_error], - "Not supported by driver"}. -{skip_cases,"../odbc_test",odbc_query_SUITE, - [param_insert_tiny_int], - "Not supported by driver"}. diff --git a/lib/odbc/test/odbc.spec.win b/lib/odbc/test/odbc.spec.win deleted file mode 100644 index 1fd349d2c3..0000000000 --- a/lib/odbc/test/odbc.spec.win +++ /dev/null @@ -1,5 +0,0 @@ -{topcase, {dir, "../odbc_test"}}. -{skip, {odbc_data_type_SUITE, big_int_lower_limit, "Not supported by sqlserver 7.0"}}. -{skip, {odbc_data_type_SUITE, big_int_upper_limit, "Not supported by sqlserver7.0"}}. -{skip, {odbc_data_type_SUITE, text_upper_limit, "Consumes too much resources"}}. - diff --git a/lib/odbc/test/odbc_connect_SUITE.erl b/lib/odbc/test/odbc_connect_SUITE.erl index 6a2268f40e..6eaf3a81c4 100644 --- a/lib/odbc/test/odbc_connect_SUITE.erl +++ b/lib/odbc/test/odbc_connect_SUITE.erl @@ -77,14 +77,18 @@ end_per_group(_GroupName, Config) -> %% variable, but should NOT alter/remove any existing entries. %%-------------------------------------------------------------------- init_per_suite(Config) -> - application:start(odbc), - case catch 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"} + case (catch odbc:start()) of + ok -> + case catch 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; + _ -> + {skip,"ODBC not startable"} end. %%-------------------------------------------------------------------- %% Function: end_per_suite(Config) -> _ @@ -93,8 +97,7 @@ init_per_suite(Config) -> %% Description: Cleanup after the whole suite %%-------------------------------------------------------------------- end_per_suite(_Config) -> - application:stop(odbc), - ok. + application:stop(odbc). %%-------------------------------------------------------------------- %% Function: init_per_testcase(Case, Config) -> Config @@ -113,6 +116,12 @@ init_per_testcase(_TestCase, Config) -> Dog = test_server:timetrap(?default_timeout), Temp = lists:keydelete(connection_ref, 1, Config), NewConfig = lists:keydelete(watchdog, 1, Temp), + %% 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), [{watchdog, Dog} | NewConfig]. %%-------------------------------------------------------------------- @@ -124,15 +133,8 @@ init_per_testcase(_TestCase, Config) -> %% 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_server:timetrap_cancel(Dog). %%------------------------------------------------------------------------- %% Test cases starts here. @@ -145,10 +147,12 @@ commit(Config) -> [{auto_commit, off}]), Table = ?config(tableName, Config), + TransStr = transaction_support_str(?RDBMS), + {updated, _} = odbc:sql_query(Ref, "CREATE TABLE " ++ Table ++ - " (ID integer, DATA varchar(10))"), + " (ID integer, DATA varchar(10))" ++ TransStr), {updated, 1} = odbc:sql_query(Ref, "INSERT INTO " ++ Table ++" VALUES(1,'bar')"), @@ -173,50 +177,44 @@ commit(Config) -> {'EXIT', {function_clause, _}} = (catch odbc:commit(Ref, commit, -1)), - ok = odbc:disconnect(Ref), - - ok. + ok = odbc:disconnect(Ref). %%------------------------------------------------------------------------- rollback(doc)-> ["Test the use of explicit rollback"]; rollback(suite) -> []; rollback(Config) -> - {ok, Ref} = odbc:connect(?RDBMS:connection_string(), - [{auto_commit, off}]), - + {ok, Ref} = odbc:connect(?RDBMS:connection_string(), [{auto_commit, off}]), Table = ?config(tableName, Config), + TransStr = transaction_support_str(?RDBMS), - {updated, _} = - odbc:sql_query(Ref, + {updated, _} = + odbc:sql_query(Ref, "CREATE TABLE " ++ Table ++ - " (ID integer, DATA varchar(10))"), - {updated, 1} = + " (ID integer, DATA varchar(10))" ++ TransStr), + {updated, 1} = odbc:sql_query(Ref, "INSERT INTO " ++ Table ++ " VALUES(1,'bar')"), ok = odbc:commit(Ref, commit), - {updated, 1} = + {updated, 1} = odbc:sql_query(Ref, "UPDATE " ++ Table ++ - " SET DATA = 'foo' WHERE ID = 1"), + " SET DATA = 'foo' WHERE ID = 1"), ok = odbc:commit(Ref, rollback), InsertResult = ?RDBMS:insert_result(), - InsertResult = + InsertResult = odbc:sql_query(Ref, "SELECT * FROM " ++ Table), - - {updated, 1} = + {updated, 1} = odbc:sql_query(Ref, "UPDATE " ++ Table ++ - " SET DATA = 'foo' WHERE ID = 1"), + " SET DATA = 'foo' WHERE ID = 1"), ok = odbc:commit(Ref, rollback, ?TIMEOUT), InsertResult = ?RDBMS:insert_result(), - InsertResult = + InsertResult = odbc:sql_query(Ref, "SELECT * FROM " ++ Table), + {'EXIT', {function_clause, _}} = + (catch odbc:commit(Ref, rollback, -1)), - {'EXIT', {function_clause, _}} = - (catch odbc:commit(Ref, rollback, -1)), - - ok = odbc:disconnect(Ref), - ok. + ok = odbc:disconnect(Ref). %%------------------------------------------------------------------------- not_explicit_commit(doc) -> @@ -226,8 +224,7 @@ not_explicit_commit(_Config) -> {ok, Ref} = odbc:connect(?RDBMS:connection_string(), [{auto_commit, on}]), {error, _} = odbc:commit(Ref, commit), - ok = odbc:disconnect(Ref), - ok. + ok = odbc:disconnect(Ref). %%------------------------------------------------------------------------- not_exist_db(doc) -> @@ -236,8 +233,7 @@ 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. + test_server:sleep(100). %%------------------------------------------------------------------------- no_c_node(doc) -> @@ -275,9 +271,8 @@ port_dies(_Config) -> %% 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. + test_server:sleep(10000), + undefined = process_info(Ref, status). %%------------------------------------------------------------------------- control_process_dies(doc) -> @@ -289,12 +284,10 @@ control_process_dies(_Config) -> 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), + test_server:sleep(500), + undefined = erlang:port_info(Port, connected). %% Check for c-program still running, how? - ok. -%%------------------------------------------------------------------------- %%------------------------------------------------------------------------- client_dies_normal(doc) -> @@ -399,6 +392,8 @@ connect_timeout(suite) -> []; connect_timeout(Config) when is_list(Config) -> {'EXIT',timeout} = (catch odbc:connect(?RDBMS:connection_string(), [{timeout, 0}])), + %% Need to return ok here "{'EXIT',timeout} return value" will + %% be interpreted as that the testcase has timed out. ok. %%------------------------------------------------------------------------- timeout(doc) -> @@ -411,10 +406,12 @@ timeout(Config) when is_list(Config) -> [{auto_commit, off}]), Table = ?config(tableName, Config), + TransStr = transaction_support_str(?RDBMS), + {updated, _} = odbc:sql_query(Ref, "CREATE TABLE " ++ Table ++ - " (ID integer, DATA varchar(10), PRIMARY KEY(ID))"), + " (ID integer, DATA varchar(10), PRIMARY KEY(ID))" ++ TransStr), {updated, 1} = odbc:sql_query(Ref, "INSERT INTO " ++ Table ++ " VALUES(1,'bar')"), @@ -446,9 +443,7 @@ timeout(Config) when is_list(Config) -> ["DATA"] = odbc_test_lib:to_upper(Fields), ok = odbc:commit(Ref, commit), - ok = odbc:disconnect(Ref), - ok. - + ok = odbc:disconnect(Ref). update_table_timeout(Table, TimeOut, Pid) -> @@ -474,15 +469,16 @@ update_table_timeout(Table, TimeOut, Pid) -> 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), + %% Do not check {updated, 1} as some drivers will return 0 + %% even though the update is done, which is checked by the test + %% case when the altered message is recived. + {updated, _} = odbc:sql_query(Ref, UpdateQuery, TimeOut), ok = odbc:commit(Ref, commit), Pid ! altered, - ok = odbc:disconnect(Ref), - - ok. + ok = odbc:disconnect(Ref). %%------------------------------------------------------------------------- many_timeouts(doc) -> ["Tests that many consecutive timeouts lead to that the connection " @@ -493,11 +489,12 @@ many_timeouts(Config) when is_list(Config) -> [{auto_commit, off}]), Table = ?config(tableName, Config), + TransStr = transaction_support_str(?RDBMS), {updated, _} = odbc:sql_query(Ref, "CREATE TABLE " ++ Table ++ - " (ID integer, DATA varchar(10), PRIMARY KEY(ID))"), + " (ID integer, DATA varchar(10), PRIMARY KEY(ID))" ++ TransStr), {updated, 1} = odbc:sql_query(Ref, "INSERT INTO " ++ Table ++ " VALUES(1,'bar')"), @@ -517,8 +514,7 @@ many_timeouts(Config) when is_list(Config) -> end, ok = odbc:commit(Ref, commit), - ok = odbc:disconnect(Ref), - ok. + ok = odbc:disconnect(Ref). update_table_many_timeouts(Table, TimeOut, Pid) -> @@ -531,8 +527,7 @@ update_table_many_timeouts(Table, TimeOut, Pid) -> Pid ! many_timeouts_occurred, - ok = odbc:disconnect(Ref), - ok. + ok = odbc:disconnect(Ref). loop_many_timouts(Ref, UpdateQuery, TimeOut) -> @@ -546,18 +541,19 @@ loop_many_timouts(Ref, UpdateQuery, TimeOut) -> end. %%------------------------------------------------------------------------- timeout_reset(doc) -> - ["Check that the number of consecutive timouts is reset to 0 when " + ["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), + TransStr = transaction_support_str(?RDBMS), {updated, _} = odbc:sql_query(Ref, "CREATE TABLE " ++ Table ++ - " (ID integer, DATA varchar(10), PRIMARY KEY(ID))"), + " (ID integer, DATA varchar(10), PRIMARY KEY(ID))" ++ TransStr), {updated, 1} = odbc:sql_query(Ref, "INSERT INTO " ++ Table ++ " VALUES(1,'bar')"), @@ -593,8 +589,7 @@ timeout_reset(Config) when is_list(Config) -> ["DATA"] = odbc_test_lib:to_upper(Fields), ok = odbc:commit(Ref, commit), - ok = odbc:disconnect(Ref), - ok. + ok = odbc:disconnect(Ref). update_table_timeout_reset(Table, TimeOut, Pid) -> @@ -616,15 +611,16 @@ update_table_timeout_reset(Table, TimeOut, Pid) -> 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), + %% Do not check {updated, 1} as some drivers will return 0 + %% even though the update is done, which is checked by the test + %% case when the altered message is recived. + {updated, _} = odbc:sql_query(Ref, UpdateQuery, TimeOut), ok = odbc:commit(Ref, commit), Pid ! altered, - ok = odbc:disconnect(Ref), - - ok. + ok = odbc:disconnect(Ref). loop_timout_reset(_, _, _, 0) -> ok; @@ -650,11 +646,12 @@ disconnect_on_timeout(Config) when is_list(Config) -> {ok, Ref} = odbc:connect(?RDBMS:connection_string(), [{auto_commit, off}]), Table = ?config(tableName, Config), + TransStr = transaction_support_str(?RDBMS), {updated, _} = odbc:sql_query(Ref, "CREATE TABLE " ++ Table ++ - " (ID integer, DATA varchar(10), PRIMARY KEY(ID))"), + " (ID integer, DATA varchar(10), PRIMARY KEY(ID))" ++ TransStr), {updated, 1} = odbc:sql_query(Ref, "INSERT INTO " ++ Table ++ " VALUES(1,'bar')"), @@ -714,8 +711,7 @@ connection_closed(Config) when is_list(Config) -> {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. + {error, connection_closed} = odbc:commit(Ref, commit). %%------------------------------------------------------------------------- disable_scrollable_cursors(doc) -> @@ -753,8 +749,7 @@ disable_scrollable_cursors(Config) when is_list(Config) -> {error, scrollable_cursors_disabled} = odbc:select(Ref, {absolute, 2}, 5), - {selected, _ColNames,[]} = odbc:select(Ref, next, 1), - ok. + {selected, _ColNames,[]} = odbc:select(Ref, next, 1). %%------------------------------------------------------------------------- return_rows_as_lists(doc)-> @@ -792,8 +787,7 @@ return_rows_as_lists(Config) when is_list(Config) -> Last = odbc:last(Ref), Prev = odbc:prev(Ref), First = odbc:first(Ref), - Next = odbc:next(Ref), - ok. + Next = odbc:next(Ref). %%------------------------------------------------------------------------- @@ -818,6 +812,9 @@ api_missuse(Config) when is_list(Config)-> %% Could be an innocent misstake the connection lives. Ref3 ! foobar, test_server:sleep(10), - {status, _} = process_info(Ref3, status), - ok. + {status, _} = process_info(Ref3, status). +transaction_support_str(mysql) -> + "ENGINE = InnoDB"; +transaction_support_str(_) -> + "". diff --git a/lib/odbc/test/odbc_data_type_SUITE.erl b/lib/odbc/test/odbc_data_type_SUITE.erl index bfb1e4b329..3585446ec8 100644 --- a/lib/odbc/test/odbc_data_type_SUITE.erl +++ b/lib/odbc/test/odbc_data_type_SUITE.erl @@ -44,24 +44,29 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> case odbc_test_lib:odbc_check() of ok -> - [{group, char}, {group, int}, {group, floats}, + [{group, char},{group, fixed_char}, {group, binary_char}, + {group, fixed_binary_char}, + {group, int}, {group, floats}, {group, dec_and_num}, timestamp]; Other -> {skip, Other} end. groups() -> [{char, [], - [char_fixed_lower_limit, char_fixed_upper_limit, - char_fixed_padding, varchar_lower_limit, + [varchar_lower_limit, varchar_upper_limit, varchar_no_padding, text_lower_limit, text_upper_limit, unicode]}, + {fixed_char, [], + [char_fixed_lower_limit, char_fixed_upper_limit, + char_fixed_padding]}, {binary_char, [], - [binary_char_fixed_lower_limit, - binary_char_fixed_upper_limit, - binary_char_fixed_padding, binary_varchar_lower_limit, + [binary_varchar_lower_limit, binary_varchar_upper_limit, binary_varchar_no_padding, binary_text_lower_limit, binary_text_upper_limit, unicode]}, + {fixed_binary_char, [], [binary_char_fixed_lower_limit, + binary_char_fixed_upper_limit, + binary_char_fixed_padding]}, {int, [], [tiny_int_lower_limit, tiny_int_upper_limit, small_int_lower_limit, small_int_upper_limit, @@ -74,6 +79,15 @@ groups() -> [dec_long, dec_double, dec_bignum, num_long, num_double, num_bignum]}]. +init_per_group(GroupName, Config) when GroupName == fixed_char; + GroupName == fixed_binary_char -> + case ?RDBMS of + mysql -> + {skip, "No supported by MYSQL"}; + _ -> + Config + end; + init_per_group(_GroupName, Config) -> Config. @@ -92,8 +106,12 @@ end_per_group(_GroupName, Config) -> %% variable, but should NOT alter/remove any existing entries. %%-------------------------------------------------------------------- init_per_suite(Config) -> - application:start(odbc), - [{tableName, odbc_test_lib:unique_table_name()} | Config]. + case (catch odbc:start()) of + ok -> + [{tableName, odbc_test_lib:unique_table_name()} | Config]; + _ -> + {skip, "ODBC not startable"} + end. %%-------------------------------------------------------------------- %% Function: end_per_suite(Config) -> _ @@ -117,7 +135,54 @@ end_per_suite(_Config) -> %% 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(Case, Config) when Case == varchar_upper_limit; + Case == binary_varchar_upper_limit; + Case == varchar_no_padding; + Case == binary_varchar_no_padding -> + case is_fixed_upper_limit(?RDBMS) of + true -> + common_init_per_testcase(Case, Config); + false -> + {skip, "Upper limit is not fixed in" ++ atom_to_list(?RDBMS)} + end; + +init_per_testcase(text_upper_limit, _Config) -> + {skip, "Consumes too much resources"}; + +init_per_testcase(Case, Config) when Case == bit_true; Case == bit_false -> + case is_supported_bit(?RDBMS) of + true -> + common_init_per_testcase(Case, Config); + false -> + {skip, "Not supported by driver"} + end; + +init_per_testcase(param_insert_tiny_int = Case, Config) -> + case is_supported_tinyint(?RDBMS) of + true -> + common_init_per_testcase(Case, Config); + false -> + {skip, "Not supported by driver"} + end; init_per_testcase(Case, Config) -> + common_init_per_testcase(Case, Config). + +is_supported_tinyint(sqlserver) -> + true; +is_supported_tinyint(_) -> + false. + +is_supported_bit(sqlserver) -> + true; +is_supported_bit(_) -> + false. + +is_fixed_upper_limit(mysql) -> + false; +is_fixed_upper_limit(_) -> + true. + +common_init_per_testcase(Case, Config) -> case atom_to_list(Case) of "binary" ++ _ -> {ok, Ref} = odbc:connect(?RDBMS:connection_string(), @@ -128,6 +193,7 @@ init_per_testcase(Case, Config) -> _ -> {ok, Ref} = odbc:connect(?RDBMS:connection_string(), []) end, + odbc_test_lib:strict(Ref, ?RDBMS), Dog = test_server:timetrap(?default_timeout), Temp = lists:keydelete(connection_ref, 1, Config), NewConfig = lists:keydelete(watchdog, 1, Temp), @@ -169,18 +235,18 @@ char_fixed_lower_limit(Config) when is_list(Config) -> {error, _} = odbc:sql_query(Ref, "CREATE TABLE " ++ Table ++ - ?RDBMS:create_fixed_char_table( + ?RDBMS:create_fixed_char_table( (?RDBMS:fixed_char_min() - 1))), %% Lower limit {updated, _} = % Value == 0 || -1 driver dependent! odbc:sql_query(Ref, "CREATE TABLE " ++ Table ++ - ?RDBMS:create_fixed_char_table( - ?RDBMS:fixed_char_min())), + ?RDBMS:create_fixed_char_table( + ?RDBMS:fixed_char_min())), %% Right length data {updated, _} = odbc:sql_query(Ref, "INSERT INTO " ++ Table ++" VALUES(" ++ - "'" ++ string:chars($a, ?RDBMS:fixed_char_min()) + "'" ++ string:chars($a, ?RDBMS:fixed_char_min()) ++ "')"), %% Select data {selected, Fields,[{"a"}]} = @@ -191,11 +257,11 @@ char_fixed_lower_limit(Config) when is_list(Config) -> %% Too long data {error, _} = odbc:sql_query(Ref,"INSERT INTO " ++ Table ++" VALUES(" ++ - "'" ++ string:chars($a, - (?RDBMS:fixed_char_min() - + 1)) - ++ "')"), - ok. + "'" ++ string:chars($a, + (?RDBMS:fixed_char_min() + + 1)) + ++ "')"). + %%------------------------------------------------------------------------- char_fixed_upper_limit(doc) -> @@ -243,8 +309,7 @@ char_fixed_upper_limit(Config) when is_list(Config) -> {error, _} = odbc:sql_query(Ref, "CREATE TABLE " ++ Table ++ ?RDBMS:create_fixed_char_table( - (?RDBMS:fixed_char_max() + 1))), - ok + (?RDBMS:fixed_char_max() + 1))) end. %%------------------------------------------------------------------------- @@ -261,20 +326,20 @@ char_fixed_padding(Config) when is_list(Config) -> %% Data should be padded with blanks {updated, _} = % Value == 0 || -1 driver dependent! odbc:sql_query(Ref, "CREATE TABLE " ++ Table ++ - ?RDBMS:create_fixed_char_table( - ?RDBMS:fixed_char_max())), + ?RDBMS:create_fixed_char_table( + ?RDBMS:fixed_char_max())), - {updated, _} = + {updated, _} = odbc:sql_query(Ref, "INSERT INTO " ++ Table ++" VALUES(" ++ - "'" ++ string:chars($a, - ?RDBMS:fixed_char_min()) + "'" ++ string:chars($a, + ?RDBMS:fixed_char_min()) ++ "')"), {selected, Fields, [{CharStr}]} = odbc:sql_query(Ref,"SELECT FIELD FROM " ++ Table), true = length(CharStr) == ?RDBMS:fixed_char_max(), - ["FIELD"] = odbc_test_lib:to_upper(Fields), - ok. + ["FIELD"] = odbc_test_lib:to_upper(Fields). + %%------------------------------------------------------------------------- varchar_lower_limit(doc) -> @@ -287,33 +352,33 @@ varchar_lower_limit(Config) when is_list(Config) -> %% Below limit {error, _} = - odbc:sql_query(Ref, "CREATE TABLE " ++ Table ++ - ?RDBMS:create_var_char_table( - ?RDBMS:var_char_min() - 1)), + odbc:sql_query(Ref, "CREATE TABLE " ++ Table ++ + ?RDBMS:create_var_char_table( + ?RDBMS:var_char_min() - 1)), %% Lower limit {updated, _} = % Value == 0 || -1 driver dependent! odbc:sql_query(Ref, "CREATE TABLE " ++ Table ++ - ?RDBMS:create_var_char_table( - ?RDBMS:var_char_min())), + ?RDBMS:create_var_char_table( + ?RDBMS:var_char_min())), + + Str = string:chars($a, ?RDBMS:var_char_min()), %% Right length data {updated, _} = odbc:sql_query(Ref, "INSERT INTO " ++ Table ++" VALUES(" ++ - "'" ++ string:chars($a, ?RDBMS:var_char_min()) - ++ "')"), + "'" ++ Str ++ "')"), %% Select data - {selected, Fields, [{"a"}]} = + {selected, Fields, [{Str}]} = odbc:sql_query(Ref,"SELECT FIELD FROM " ++ Table), ["FIELD"] = odbc_test_lib:to_upper(Fields), - %% Too long data - {error, _} = - odbc:sql_query(Ref, "INSERT INTO " ++ Table ++" VALUES(" ++ - "'" ++ string:chars($a, - (?RDBMS:var_char_min()+1)) - ++ "')"), - ok. + %% Too long datae + {error, _} = + odbc:sql_query(Ref, "INSERT INTO " ++ Table ++" VALUES(" ++ + "'" ++ string:chars($a, + (?RDBMS:var_char_min()+1)) + ++ "')"). %%------------------------------------------------------------------------- @@ -389,8 +454,7 @@ varchar_no_padding(Config) when is_list(Config) -> {selected, Fields, [{CharStr}]} = odbc:sql_query(Ref,"SELECT FIELD FROM " ++ Table), true = length(CharStr) /= ?RDBMS:var_char_max(), - ["FIELD"] = odbc_test_lib:to_upper(Fields), - ok. + ["FIELD"] = odbc_test_lib:to_upper(Fields). %%------------------------------------------------------------------------- @@ -413,8 +477,7 @@ text_lower_limit(Config) when is_list(Config) -> {selected, Fields, [{"a"}]} = odbc:sql_query(Ref,"SELECT FIELD FROM " ++ Table), - ["FIELD"] = odbc_test_lib:to_upper(Fields), - ok. + ["FIELD"] = odbc_test_lib:to_upper(Fields). %%------------------------------------------------------------------------- @@ -444,8 +507,7 @@ text_upper_limit(Config) when is_list(Config) -> %% {error, _} = %% odbc:sql_query(Ref, "INSERT INTO " ++ Table ++" VALUES(" ++ %% "'" ++ string:chars($a, (?RDBMS:text_max()+1)) -%% ++ "')"), -%% ok. +%% ++ "')"). %%------------------------------------------------------------------------- @@ -469,13 +531,18 @@ binary_char_fixed_lower_limit(Config) when is_list(Config) -> ?RDBMS:create_fixed_char_table( ?RDBMS:fixed_char_min())), + Str = string:chars($a, ?RDBMS:fixed_char_min()), + %% Right length data {updated, _} = odbc:sql_query(Ref, "INSERT INTO " ++ Table ++" VALUES(" ++ - "'" ++ string:chars($a, ?RDBMS:fixed_char_min()) + "'" ++ Str ++ "')"), + + Bin = list_to_binary(Str), + %% Select data - {selected, Fields,[{<<"a">>}]} = + {selected, Fields,[{Bin}]} = odbc:sql_query(Ref,"SELECT FIELD FROM " ++ Table), ["FIELD"] = odbc_test_lib:to_upper(Fields), @@ -486,8 +553,7 @@ binary_char_fixed_lower_limit(Config) when is_list(Config) -> "'" ++ string:chars($a, (?RDBMS:fixed_char_min() + 1)) - ++ "')"), - ok. + ++ "')"). %%------------------------------------------------------------------------- binary_char_fixed_upper_limit(doc) -> @@ -565,8 +631,8 @@ binary_char_fixed_padding(Config) when is_list(Config) -> {selected, Fields, [{CharBin}]} = odbc:sql_query(Ref,"SELECT FIELD FROM " ++ Table), true = size(CharBin) == ?RDBMS:fixed_char_max(), - ["FIELD"] = odbc_test_lib:to_upper(Fields), - ok. + ["FIELD"] = odbc_test_lib:to_upper(Fields). + %%------------------------------------------------------------------------- binary_varchar_lower_limit(doc) -> @@ -588,13 +654,17 @@ binary_varchar_lower_limit(Config) when is_list(Config) -> ?RDBMS:create_var_char_table( ?RDBMS:var_char_min())), + Str = string:chars($a, ?RDBMS:var_char_min()), + %% Right length data {updated, _} = odbc:sql_query(Ref, "INSERT INTO " ++ Table ++" VALUES(" ++ - "'" ++ string:chars($a, ?RDBMS:var_char_min()) + "'" ++ Str ++ "')"), + BinStr = list_to_binary(Str), + %% Select data - {selected, Fields, [{<<"a">>}]} = + {selected, Fields, [{BinStr}]} = odbc:sql_query(Ref,"SELECT FIELD FROM " ++ Table), ["FIELD"] = odbc_test_lib:to_upper(Fields), @@ -604,8 +674,7 @@ binary_varchar_lower_limit(Config) when is_list(Config) -> odbc:sql_query(Ref, "INSERT INTO " ++ Table ++" VALUES(" ++ "'" ++ string:chars($a, (?RDBMS:var_char_min()+1)) - ++ "')"), - ok. + ++ "')"). %%------------------------------------------------------------------------- @@ -654,8 +723,7 @@ binary_varchar_upper_limit(Config) when is_list(Config) -> {error, _} = odbc:sql_query(Ref, "CREATE TABLE " ++ Table ++ ?RDBMS:create_var_char_table( - (?RDBMS:var_char_max() + 1))), - ok + (?RDBMS:var_char_max() + 1))) end. %%------------------------------------------------------------------------- @@ -681,8 +749,7 @@ binary_varchar_no_padding(Config) when is_list(Config) -> {selected, Fields, [{CharBin}]} = odbc:sql_query(Ref,"SELECT FIELD FROM " ++ Table), true = size(CharBin) /= ?RDBMS:var_char_max(), - ["FIELD"] = odbc_test_lib:to_upper(Fields), - ok. + ["FIELD"] = odbc_test_lib:to_upper(Fields). %%------------------------------------------------------------------------- @@ -705,8 +772,7 @@ binary_text_lower_limit(Config) when is_list(Config) -> {selected, Fields, [{<<"a">>}]} = odbc:sql_query(Ref,"SELECT FIELD FROM " ++ Table), - ["FIELD"] = odbc_test_lib:to_upper(Fields), - ok. + ["FIELD"] = odbc_test_lib:to_upper(Fields). %%------------------------------------------------------------------------- @@ -736,11 +802,7 @@ binary_text_upper_limit(Config) when is_list(Config) -> %% {error, _} = %% odbc:sql_query(Ref, "INSERT INTO " ++ Table ++" VALUES(" ++ %% "'" ++ string:chars($a, (?RDBMS:text_max()+1)) -%% ++ "')"), -%% ok. - - -%%------------------------------------------------------------------------- +%% ++ "')"). %%------------------------------------------------------------------------- @@ -774,8 +836,7 @@ tiny_int_lower_limit(Config) when is_list(Config) -> odbc:sql_query(Ref, "INSERT INTO " ++ Table ++" VALUES(" ++ "'" ++ integer_to_list(?RDBMS:tiny_int_min() - 1) - ++ "')"), - ok + ++ "')") end. %%------------------------------------------------------------------------- @@ -809,8 +870,7 @@ tiny_int_upper_limit(Config) when is_list(Config) -> odbc:sql_query(Ref, "INSERT INTO " ++ Table ++" VALUES(" ++ "'" ++ integer_to_list(?RDBMS:tiny_int_max() + 1) - ++ "')"), - ok + ++ "')") end. %%------------------------------------------------------------------------- @@ -840,8 +900,7 @@ small_int_lower_limit(Config) when is_list(Config) -> odbc:sql_query(Ref, "INSERT INTO " ++ Table ++" VALUES(" ++ "'" ++ integer_to_list(?RDBMS:small_int_min() - 1) - ++ "')"), - ok. + ++ "')"). %%------------------------------------------------------------------------- @@ -870,8 +929,7 @@ small_int_upper_limit(Config) when is_list(Config) -> odbc:sql_query(Ref,"INSERT INTO " ++ Table ++" VALUES(" ++ "'" ++ integer_to_list(?RDBMS:small_int_max() + 1) - ++ "')"), - ok. + ++ "')"). %%------------------------------------------------------------------------- int_lower_limit(doc) -> @@ -898,8 +956,7 @@ int_lower_limit(Config) when is_list(Config) -> {error, _} = odbc:sql_query(Ref, "INSERT INTO " ++ Table ++" VALUES(" ++ "'" ++ integer_to_list(?RDBMS:int_min() - 1) - ++ "')"), - ok. + ++ "')"). %%------------------------------------------------------------------------- @@ -927,8 +984,7 @@ int_upper_limit(Config) when is_list(Config) -> {error, _} = odbc:sql_query(Ref, "INSERT INTO " ++ Table ++" VALUES(" ++ "'" ++ integer_to_list(?RDBMS:int_max() + 1) - ++ "')"), - ok. + ++ "')"). %%------------------------------------------------------------------------- @@ -957,8 +1013,7 @@ big_int_lower_limit(Config) when is_list(Config) -> odbc:sql_query(Ref, "INSERT INTO " ++ Table ++" VALUES(" ++ "'" ++ integer_to_list(?RDBMS:big_int_min() - 1) - ++ "')"), - ok. + ++ "')"). %%------------------------------------------------------------------------- @@ -987,8 +1042,7 @@ big_int_upper_limit(Config) when is_list(Config) -> odbc:sql_query(Ref, "INSERT INTO " ++ Table ++" VALUES(" ++ "'" ++ integer_to_list(?RDBMS:big_int_max() + 1) - ++ "')"), - ok. + ++ "')"). %%------------------------------------------------------------------------- bit_false(doc) -> @@ -1020,8 +1074,7 @@ bit_false(Config) when is_list(Config) -> {error, _} = odbc:sql_query(Ref, "INSERT INTO " ++ Table ++" VALUES(" ++ "'" ++ integer_to_list(-1) - ++ "')"), - ok + ++ "')") end. %%------------------------------------------------------------------------- @@ -1056,14 +1109,10 @@ bit_true(Config) when is_list(Config) -> {error, _} = odbc:sql_query(Ref, "INSERT INTO " ++ Table ++" VALUES(" ++ "'" ++ integer_to_list(-1) - ++ "')"), - ok + ++ "')") end. %%------------------------------------------------------------------------- - - -%%------------------------------------------------------------------------- float_lower_limit(doc) -> [""]; float_lower_limit(suite) -> @@ -1073,44 +1122,45 @@ float_lower_limit(Config) when is_list(Config) -> Ref = ?config(connection_ref, Config), Table = ?config(tableName, Config), - {updated, _} = % Value == 0 || -1 driver dependent! - odbc:sql_query(Ref, "CREATE TABLE " ++ Table ++ - ?RDBMS:create_float_table()), - - {updated, _} = - odbc:sql_query(Ref, "INSERT INTO " ++ Table ++" VALUES(" ++ - "'" ++ float_to_list( - ?RDBMS:float_min()) - ++ "')"), - {selected,[_ColName],[{MinFloat}]} = - odbc:sql_query(Ref,"SELECT FIELD FROM " ++ Table), - - true = ?RDBMS:float_min() == MinFloat, - case ?RDBMS of - oracle -> - {updated, _} = % Value == 0 || -1 driver dependent! - odbc:sql_query(Ref, "DROP TABLE " ++ Table), - + mysql -> + {skip, "Not clearly defined in MYSQL"}; + _ -> {updated, _} = % Value == 0 || -1 driver dependent! odbc:sql_query(Ref, "CREATE TABLE " ++ Table ++ - ?RDBMS:create_float_table()), + ?RDBMS:create_float_table()), {updated, _} = - odbc:sql_query(Ref, - "INSERT INTO " ++ Table ++" VALUES(" ++ - ?RDBMS:float_underflow() ++ ")"), - - SelectResult = ?RDBMS:float_zero_selected(), - SelectResult = - odbc:sql_query(Ref,"SELECT FIELD FROM " ++ Table); - _ -> - {error, _} = odbc:sql_query(Ref, "INSERT INTO " ++ Table ++" VALUES(" ++ - ?RDBMS:float_underflow() ++ ")") - end, - ok. + "'" ++ float_to_list( + ?RDBMS:float_min()) + ++ "')"), + {selected,[_ColName],[{MinFloat}]} = + odbc:sql_query(Ref,"SELECT FIELD FROM " ++ Table), + true = ?RDBMS:float_min() == MinFloat, + + case ?RDBMS of + oracle -> + {updated, _} = % Value == 0 || -1 driver dependent! + odbc:sql_query(Ref, "DROP TABLE " ++ Table), + + {updated, _} = % Value == 0 || -1 driver dependent! + odbc:sql_query(Ref, "CREATE TABLE " ++ Table ++ + ?RDBMS:create_float_table()), + {updated, _} = + odbc:sql_query(Ref, + "INSERT INTO " ++ Table ++" VALUES(" ++ + ?RDBMS:float_underflow() ++ ")"), + SelectResult = ?RDBMS:float_zero_selected(), + SelectResult = + odbc:sql_query(Ref,"SELECT FIELD FROM " ++ Table); + _ -> + {error, _} = + odbc:sql_query(Ref, "INSERT INTO " ++ Table ++" VALUES(" ++ + ?RDBMS:float_underflow() ++ ")") + end + end. %%------------------------------------------------------------------------- float_upper_limit(doc) -> @@ -1121,26 +1171,28 @@ float_upper_limit(Config) when is_list(Config) -> Ref = ?config(connection_ref, Config), Table = ?config(tableName, Config), - {updated, _} = % Value == 0 || -1 driver dependent! - odbc:sql_query(Ref, "CREATE TABLE " ++ Table ++ - ?RDBMS:create_float_table()), - - {updated, _} = - odbc:sql_query(Ref, "INSERT INTO " ++ Table ++" VALUES(" ++ - "'" ++ float_to_list( - ?RDBMS:float_max()) - ++ "')"), - + case ?RDBMS of + mysql -> + {skip, "Not clearly defined in MYSQL"}; + _-> + {updated, _} = % Value == 0 || -1 driver dependent! + odbc:sql_query(Ref, "CREATE TABLE " ++ Table ++ + ?RDBMS:create_float_table()), - {selected,[_ColName],[{MaxFloat}]} - = odbc:sql_query(Ref,"SELECT FIELD FROM " ++ Table), + {updated, _} = + odbc:sql_query(Ref, "INSERT INTO " ++ Table ++" VALUES(" ++ + "'" ++ float_to_list( + ?RDBMS:float_max()) + ++ "')"), + {selected,[_ColName],[{MaxFloat}]} + = odbc:sql_query(Ref,"SELECT FIELD FROM " ++ Table), - true = ?RDBMS:float_max() == MaxFloat, + true = ?RDBMS:float_max() == MaxFloat, - {error, _} = - odbc:sql_query(Ref, "INSERT INTO " ++ Table ++" VALUES(" ++ - ?RDBMS:float_overflow() ++ ")"), - ok. + {error, _} = + odbc:sql_query(Ref, "INSERT INTO " ++ Table ++" VALUES(" ++ + ?RDBMS:float_overflow() ++ ")") + end. %%------------------------------------------------------------------------- float_zero(doc) -> @@ -1160,8 +1212,7 @@ float_zero(Config) when is_list(Config) -> SelectResult = ?RDBMS:float_zero_selected(), SelectResult = - odbc:sql_query(Ref,"SELECT FIELD FROM " ++ Table), - ok. + odbc:sql_query(Ref,"SELECT FIELD FROM " ++ Table). %%------------------------------------------------------------------------- real_zero(doc) -> ["Test the real value zero."]; @@ -1185,10 +1236,8 @@ real_zero(Config) when is_list(Config) -> SelectResult = ?RDBMS:real_zero_selected(), SelectResult = - odbc:sql_query(Ref,"SELECT FIELD FROM " ++ Table), - ok + odbc:sql_query(Ref,"SELECT FIELD FROM " ++ Table) end. -%%------------------------------------------------------------------------- %%------------------------------------------------------------------------ dec_long(doc) -> [""]; @@ -1207,8 +1256,7 @@ dec_long(Config) when is_list(Config) -> {selected, Fields, [{2}]} = odbc:sql_query(Ref,"SELECT FIELD FROM " ++ Table), - ["FIELD"] = odbc_test_lib:to_upper(Fields), - ok. + ["FIELD"] = odbc_test_lib:to_upper(Fields). %%------------------------------------------------------------------------ dec_double(doc) -> [""]; @@ -1255,8 +1303,7 @@ dec_double(Config) when is_list(Config) -> {selected, Fields2, [{1.60000}]} = odbc:sql_query(Ref,"SELECT FIELD FROM " ++ Table), - ["FIELD"] = odbc_test_lib:to_upper(Fields2), - ok. + ["FIELD"] = odbc_test_lib:to_upper(Fields2). %%------------------------------------------------------------------------ dec_bignum(doc) -> @@ -1289,8 +1336,7 @@ dec_bignum(Config) when is_list(Config) -> {selected, Fields1, [{"1.6"}]} = odbc:sql_query(Ref,"SELECT FIELD FROM " ++ Table), - ["FIELD"] = odbc_test_lib:to_upper(Fields1), - ok. + ["FIELD"] = odbc_test_lib:to_upper(Fields1). %%------------------------------------------------------------------------ num_long(doc) -> [""]; @@ -1309,8 +1355,7 @@ num_long(Config) when is_list(Config) -> {selected, Fields, [{2}]} = odbc:sql_query(Ref,"SELECT FIELD FROM " ++ Table), - ["FIELD"] = odbc_test_lib:to_upper(Fields), - ok. + ["FIELD"] = odbc_test_lib:to_upper(Fields). %%------------------------------------------------------------------------ num_double(doc) -> [""]; @@ -1356,8 +1401,7 @@ num_double(Config) when is_list(Config) -> {selected, Fields2, [{1.6000}]} = odbc:sql_query(Ref,"SELECT FIELD FROM " ++ Table), - ["FIELD"] = odbc_test_lib:to_upper(Fields2), - ok. + ["FIELD"] = odbc_test_lib:to_upper(Fields2). %%------------------------------------------------------------------------ num_bignum(doc) -> [""]; @@ -1389,8 +1433,7 @@ num_bignum(Config) when is_list(Config) -> {selected, Fields1, [{"1.6"}]} = odbc:sql_query(Ref,"SELECT FIELD FROM " ++ Table), - ["FIELD"] = odbc_test_lib:to_upper(Fields1), - ok. + ["FIELD"] = odbc_test_lib:to_upper(Fields1). %%------------------------------------------------------------------------ unicode(doc) -> @@ -1422,6 +1465,8 @@ unicode(Config) when is_list(Config) -> w_char_support_win(Ref, Table, Latin1Data); postgres -> direct_utf8(Ref, Table, Latin1Data); + mysql -> + direct_utf8(Ref, Table, Latin1Data); oracle -> {skip, "not currently supported"} end. diff --git a/lib/odbc/test/odbc_query_SUITE.erl b/lib/odbc/test/odbc_query_SUITE.erl index 8b8d1e7a40..6dee588076 100644 --- a/lib/odbc/test/odbc_query_SUITE.erl +++ b/lib/odbc/test/odbc_query_SUITE.erl @@ -47,15 +47,17 @@ all() -> select_next, select_relative, select_absolute, create_table_twice, delete_table_twice, duplicate_key, not_connection_owner, no_result_set, query_error, - multiple_select_result_sets, multiple_mix_result_sets, - multiple_result_sets_error, + {group, multiple_result_sets}, {group, parameterized_queries}, {group, describe_table}, delete_nonexisting_row]; Other -> {skip, Other} end. groups() -> - [{parameterized_queries, [], + [{multiple_result_sets, [], [multiple_select_result_sets, + multiple_mix_result_sets, + multiple_result_sets_error]}, + {parameterized_queries, [], [{group, param_integers}, param_insert_decimal, param_insert_numeric, {group, param_insert_string}, param_insert_float, param_insert_real, @@ -72,15 +74,18 @@ groups() -> [describe_integer, describe_string, describe_floating, describe_dec_num, describe_no_such_table]}]. -init_per_group(_GroupName, Config) -> +init_per_group(multiple_result_sets, Config) -> + case is_supported_multiple_resultsets(?RDBMS) of + true -> + Config; + false -> + {skip, "Not supported by " ++ atom_to_list(?RDBMS) ++ "driver"} + end; +init_per_group(_, Config) -> Config. - end_per_group(_GroupName, Config) -> Config. - - - %%-------------------------------------------------------------------- %% Function: init_per_suite(Config) -> Config %% Config - [tuple()] @@ -91,8 +96,12 @@ end_per_group(_GroupName, Config) -> %% variable, but should NOT alter/remove any existing entries. %%-------------------------------------------------------------------- init_per_suite(Config) when is_list(Config) -> - application:start(odbc), - [{tableName, odbc_test_lib:unique_table_name()}| Config]. + case (catch odbc:start()) of + ok -> + [{tableName, odbc_test_lib:unique_table_name()}| Config]; + _ -> + {skip, "ODBC not startable"} + end. %%-------------------------------------------------------------------- %% Function: end_per_suite(Config) -> _ @@ -118,6 +127,7 @@ end_per_suite(_Config) -> %%-------------------------------------------------------------------- init_per_testcase(_Case, Config) -> {ok, Ref} = odbc:connect(?RDBMS:connection_string(), []), + odbc_test_lib:strict(Ref, ?RDBMS), Dog = test_server:timetrap(?default_timeout), Temp = lists:keydelete(connection_ref, 1, Config), NewConfig = lists:keydelete(watchdog, 1, Temp), @@ -663,9 +673,6 @@ multiple_result_sets_error(Config) when is_list(Config) -> end. %%------------------------------------------------------------------------- - -%%------------------------------------------------------------------------- -%%------------------------------------------------------------------------- param_insert_tiny_int(doc)-> ["Test insertion of tiny ints by parameterized queries."]; param_insert_tiny_int(suite) -> @@ -901,8 +908,6 @@ param_insert_numeric(Config) when is_list(Config) -> ok. %%------------------------------------------------------------------------- - -%%------------------------------------------------------------------------- param_insert_char(doc)-> ["Test insertion of fixed length string by parameterized queries."]; param_insert_char(suite) -> @@ -1325,8 +1330,6 @@ param_select(Config) when is_list(Config) -> ok. %%------------------------------------------------------------------------- - -%%------------------------------------------------------------------------- describe_integer(doc) -> ["Test describe_table/[2,3] for integer columns."]; describe_integer(suite) -> @@ -1338,7 +1341,7 @@ describe_integer(Config) when is_list(Config) -> {updated, _} = odbc:sql_query(Ref, "CREATE TABLE " ++ Table ++ - " (int1 SMALLINT, int2 INT, int3 INTEGER)"), + " (myint1 SMALLINT, myint2 INT, myint3 INTEGER)"), Decs = ?RDBMS:describe_integer(), %% Make sure to test timeout clause @@ -1399,7 +1402,7 @@ describe_dec_num(Config) when is_list(Config) -> {updated, _} = odbc:sql_query(Ref, "CREATE TABLE " ++ Table ++ - " (dec DECIMAL(9,3), num NUMERIC(9,2))"), + " (mydec DECIMAL(9,3), mynum NUMERIC(9,2))"), Decs = ?RDBMS:describe_dec_num(), @@ -1451,3 +1454,7 @@ is_driver_error(Error) -> false -> test_server:fail(Error) end. +is_supported_multiple_resultsets(sqlserver) -> + true; +is_supported_multiple_resultsets(_) -> + false. diff --git a/lib/odbc/test/odbc_test.hrl b/lib/odbc/test/odbc_test.hrl index 87f50043db..7d2522d667 100644 --- a/lib/odbc/test/odbc_test.hrl +++ b/lib/odbc/test/odbc_test.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2002-2010. All Rights Reserved. +%% Copyright Ericsson AB 2002-2011. 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 @@ -27,7 +27,7 @@ {unix, sunos} -> postgres; {unix,linux} -> - postgres; + mysql; {win32, _} -> sqlserver end). diff --git a/lib/odbc/test/odbc_test_lib.erl b/lib/odbc/test/odbc_test_lib.erl index 012eb96e43..9956d74d24 100644 --- a/lib/odbc/test/odbc_test_lib.erl +++ b/lib/odbc/test/odbc_test_lib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2002-2010. All Rights Reserved. +%% Copyright Ericsson AB 2002-2011. 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 @@ -75,3 +75,8 @@ check_row_count(Expected, Count) -> to_upper(List) -> lists:map(fun(Str) -> string:to_upper(Str) end, List). + +strict(Ref, mysql) -> + odbc:sql_query(Ref, "SET sql_mode='STRICT_ALL_TABLES,STRICT_TRANS_TABLES';"); +strict(_,_) -> + ok. diff --git a/lib/odbc/test/oracle.erl b/lib/odbc/test/oracle.erl index ebf6dbb6bf..786280701d 100644 --- a/lib/odbc/test/oracle.erl +++ b/lib/odbc/test/oracle.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2002-2010. All Rights Reserved. +%% Copyright Ericsson AB 2002-2011. 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 @@ -231,8 +231,8 @@ param_select() -> %------------------------------------------------------------------------- describe_integer() -> - {ok,[{"INT1",{sql_decimal,38,0}},{"INT2",{sql_decimal,38,0}}, - {"INT3",{sql_decimal,38,0}}]}. + {ok,[{"MYINT1",{sql_decimal,38,0}},{"MYINT2",{sql_decimal,38,0}}, + {"MYINT3",{sql_decimal,38,0}}]}. describe_string() -> {ok,[{"STR1",{sql_char,10}}, @@ -243,4 +243,4 @@ describe_string() -> describe_floating() -> {ok,[{"F",sql_double},{"R",sql_double},{"D",sql_double}]}. describe_dec_num() -> - {ok,[{"DEC",{sql_decimal,9,3}},{"NUM",{sql_decimal,9,2}}]}. + {ok,[{"MYDEC",{sql_decimal,9,3}},{"MYNUM",{sql_decimal,9,2}}]}. diff --git a/lib/odbc/test/postgres.erl b/lib/odbc/test/postgres.erl index 169ca26e43..9c7eed271f 100644 --- a/lib/odbc/test/postgres.erl +++ b/lib/odbc/test/postgres.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2006-2010. All Rights Reserved. +%% Copyright Ericsson AB 2006-2011. 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 @@ -275,9 +275,9 @@ param_select() -> %------------------------------------------------------------------------- describe_integer() -> - {ok,[{"int1",sql_smallint}, - {"int2",sql_integer}, - {"int3",sql_integer}]}. + {ok,[{"myint1",sql_smallint}, + {"myint2",sql_integer}, + {"myint3",sql_integer}]}. describe_string() -> {ok,[{"str1",{sql_char,10}}, @@ -288,7 +288,7 @@ describe_string() -> describe_floating() -> {ok,[{"f",sql_real},{"r",sql_real},{"d",{sql_float,15}}]}. describe_dec_num() -> - {ok,[{"dec",{sql_numeric,9,3}},{"num",{sql_numeric,9,2}}]}. + {ok,[{"mydec",{sql_numeric,9,3}},{"mynum",{sql_numeric,9,2}}]}. describe_timestamp() -> {ok, [{"field", sql_timestamp}]}. diff --git a/lib/odbc/test/sqlserver.erl b/lib/odbc/test/sqlserver.erl index e3fe30e0bc..13930cd5ae 100644 --- a/lib/odbc/test/sqlserver.erl +++ b/lib/odbc/test/sqlserver.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2002-2010. All Rights Reserved. +%% Copyright Ericsson AB 2002-2011. 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 @@ -279,8 +279,8 @@ param_select() -> %------------------------------------------------------------------------- describe_integer() -> - {ok,[{"int1", sql_smallint},{"int2", sql_integer}, - {"int3", sql_integer}]}. + {ok,[{"myint1", sql_smallint},{"myint2", sql_integer}, + {"myint3", sql_integer}]}. describe_string() -> {ok,[{"str1",{sql_char,10}}, @@ -292,7 +292,7 @@ describe_floating() -> {ok,[{"f", sql_real},{"r", sql_real}, {"d", {sql_float, 53}}]}. describe_dec_num() -> - {ok,[{"dec",{sql_decimal,9,3}},{"num",{sql_numeric,9,2}}]}. + {ok,[{"mydec",{sql_decimal,9,3}},{"mynum",{sql_numeric,9,2}}]}. describe_timestamp() -> {ok, [{"field", sql_timestamp}]}. diff --git a/lib/parsetools/doc/src/leex.xml b/lib/parsetools/doc/src/leex.xml index 12abfd244f..1fa426a79e 100644 --- a/lib/parsetools/doc/src/leex.xml +++ b/lib/parsetools/doc/src/leex.xml @@ -79,6 +79,10 @@ Token = tuple()</code> <item><p>Causes warnings to be printed as they occur. Default is <c>true</c>.</p> </item> + <tag><c>warnings_as_errors</c></tag> + <item> + <p>Causes warnings to be treated as errors.</p> + </item> <tag><c>{report, bool()}</c></tag> <item><p>This is a short form for both <c>report_errors</c> and <c>report_warnings</c>.</p> diff --git a/lib/parsetools/doc/src/yecc.xml b/lib/parsetools/doc/src/yecc.xml index 81f1550b0a..c712609cf4 100644 --- a/lib/parsetools/doc/src/yecc.xml +++ b/lib/parsetools/doc/src/yecc.xml @@ -95,6 +95,10 @@ <item>This is a short form for both <c>report_errors</c> and <c>report_warnings</c>. </item> + <tag><c>warnings_as_errors</c></tag> + <item> + <p>Causes warnings to be treated as errors.</p> + </item> <tag><c>{return_errors, bool()}</c>.</tag> <item>If this flag is set, <c>{error, Errors, Warnings}</c> is returned when there are errors. Default is diff --git a/lib/parsetools/src/leex.erl b/lib/parsetools/src/leex.erl index d0b4b9efe7..942e9928b1 100644 --- a/lib/parsetools/src/leex.erl +++ b/lib/parsetools/src/leex.erl @@ -35,7 +35,7 @@ -export([compile/3,file/1,file/2,format_error/1]). -import(lists, [member/2,reverse/1,sort/1,delete/2, - keysort/2,keydelete/3,keyfind/3, + keysort/2,keydelete/3, map/2,foldl/3,foreach/2,flatmap/2]). -import(string, [substr/2,substr/3,span/2]). -import(ordsets, [is_element/2,add_element/2,union/2]). @@ -58,7 +58,7 @@ gfile=[], % Graph file module, % Module name opts=[], % Options - posix=false, % POSIX regular expressions + % posix=false, % POSIX regular expressions errors=[], warnings=[] }). @@ -107,10 +107,15 @@ file(File, Opts0) -> St = try {ok,REAs,Actions,Code,St2} = parse_file(St1), {DFA,DF} = make_dfa(REAs, St2), - St3 = out_file(St2, DFA, DF, Actions, Code), - case lists:member(dfa_graph, St3#leex.opts) of - true -> out_dfa_graph(St3, DFA, DF); - false -> St3 + case werr(St2) of + false -> + St3 = out_file(St2, DFA, DF, Actions, Code), + case lists:member(dfa_graph, St3#leex.opts) of + true -> out_dfa_graph(St3, DFA, DF); + false -> St3 + end; + true -> + St2 end catch #leex{}=St4 -> St4 @@ -131,8 +136,8 @@ format_error({regexp,E})-> "unterminated " ++ Cs; {illegal_char,Cs} -> "illegal character " ++ Cs; - {posix_cc,What} -> - ["illegal POSIX character class ",io_lib:write_string(What)]; +%% {posix_cc,What} -> +%% ["illegal POSIX character class ",io_lib:write_string(What)]; {char_class,What} -> ["illegal character class ",io_lib:write_string(What)] end, @@ -163,7 +168,8 @@ options(Options0) when is_list(Options0) -> (T) -> [T] end, Options0), options(Options, [scannerfile,includefile,report_errors, - report_warnings,return_errors,return_warnings, + report_warnings,warnings_as_errors, + return_errors,return_warnings, verbose,dfa_graph], []) catch error: _ -> badarg end; @@ -217,6 +223,7 @@ default_option(dfa_graph) -> false; default_option(includefile) -> []; default_option(report_errors) -> true; default_option(report_warnings) -> true; +default_option(warnings_as_errors) -> false; default_option(return_errors) -> false; default_option(return_warnings) -> false; default_option(scannerfile) -> []; @@ -225,6 +232,7 @@ default_option(verbose) -> false. atom_option(dfa_graph) -> {dfa_graph,true}; atom_option(report_errors) -> {report_errors,true}; atom_option(report_warnings) -> {report_warnings,true}; +atom_option(warnings_as_errors) -> {warnings_as_errors,true}; atom_option(return_errors) -> {return_errors,true}; atom_option(return_warnings) -> {return_warnings,true}; atom_option(verbose) -> {verbose,true}; @@ -251,19 +259,29 @@ leex_ret(St) -> report_warnings(St), Es = pack_errors(St#leex.errors), Ws = pack_warnings(St#leex.warnings), + Werr = werr(St), if + Werr -> + do_error_return(St, Es, Ws); Es =:= [] -> case member(return_warnings, St#leex.opts) of true -> {ok, St#leex.efile, Ws}; false -> {ok, St#leex.efile} end; - true -> - case member(return_errors, St#leex.opts) of - true -> {error, Es, Ws}; - false -> error - end + true -> + do_error_return(St, Es, Ws) end. +do_error_return(St, Es, Ws) -> + case member(return_errors, St#leex.opts) of + true -> {error, Es, Ws}; + false -> error + end. + +werr(St) -> + member(warnings_as_errors, St#leex.opts) + andalso length(St#leex.warnings) > 0. + pack_errors([{File,_} | _] = Es) -> [{File, flatmap(fun({_,E}) -> [E] end, sort(Es))}]; pack_errors([]) -> @@ -296,6 +314,7 @@ report_warnings(St) -> end, sort(St#leex.warnings)) end, report_warnings, St#leex.opts). +-spec add_error(_, #leex{}) -> no_return(). add_error(E, St) -> add_error(St#leex.xfile, E, St). @@ -644,14 +663,14 @@ re_repeat1([$*|Cs], Sn, S, St) -> re_repeat1(Cs, Sn, {kclosure,S}, St); re_repeat1([$+|Cs], Sn, S, St) -> re_repeat1(Cs, Sn, {pclosure,S}, St); re_repeat1([$?|Cs], Sn, S, St) -> re_repeat1(Cs, Sn, {optional,S}, St); %% { only starts interval when ere is true, otherwise normal character. -re_repeat1([${|Cs0], Sn, S, #leex{posix=true}=St) -> % $} - case re_interval_range(Cs0) of - {Min,Max,[$}|Cs1]} when is_integer(Min), is_integer(Max), Min =< Max -> - re_repeat1(Cs1, Sn, {interval,S,Min,Max}, St); - {Min,Max,[$}|Cs1]} when is_integer(Min), is_atom(Max) -> - re_repeat1(Cs1, Sn, {interval,S,Min,Max}, St); - {_,_,Cs1} -> parse_error({interval_range,string_between([${|Cs0], Cs1)}) - end; +%% re_repeat1([${|Cs0], Sn, S, #leex{posix=true}=St) -> % $} +%% case re_interval_range(Cs0) of +%% {Min,Max,[$}|Cs1]} when is_integer(Min), is_integer(Max), Min =< Max -> +%% re_repeat1(Cs1, Sn, {interval,S,Min,Max}, St); +%% {Min,Max,[$}|Cs1]} when is_integer(Min), is_atom(Max) -> +%% re_repeat1(Cs1, Sn, {interval,S,Min,Max}, St); +%% {_,_,Cs1} -> parse_error({interval_range,string_between([${|Cs0], Cs1)}) +%% end; re_repeat1(Cs, Sn, S, _) -> {S,Sn,Cs}. %% re_single(Chars, SubNumber, State) -> {RegExp,SubNumber,Chars}. @@ -733,7 +752,7 @@ special_char($|, _) -> true; special_char($*, _) -> true; special_char($+, _) -> true; special_char($?, _) -> true; -special_char(${, #leex{posix=true}) -> true; % Only when POSIX set +%% special_char(${, #leex{posix=true}) -> true; % Only when POSIX set special_char($\\, _) -> true; special_char(_, _) -> false. @@ -744,12 +763,12 @@ re_char_class([$]|Cs], St) -> % Must special case this. re_char_class(Cs, [$]], St); re_char_class(Cs, St) -> re_char_class(Cs, [], St). -re_char_class("[:" ++ Cs0, Cc, #leex{posix=true}=St) -> - %% POSIX char class only. - case posix_cc(Cs0) of - {Pcl,":]" ++ Cs1} -> re_char_class(Cs1, [{posix,Pcl}|Cc], St); - {_,Cs1} -> parse_error({posix_cc,string_between(Cs0, Cs1)}) - end; +%% re_char_class("[:" ++ Cs0, Cc, #leex{posix=true}=St) -> +%% %% POSIX char class only. +%% case posix_cc(Cs0) of +%% {Pcl,":]" ++ Cs1} -> re_char_class(Cs1, [{posix,Pcl}|Cc], St); +%% {_,Cs1} -> parse_error({posix_cc,string_between(Cs0, Cs1)}) +%% end; re_char_class([C1|Cs0], Cc, St) when C1 =/= $] -> case re_char(C1, Cs0) of {Cf,[$-,C2|Cs1]} when C2 =/= $] -> @@ -766,19 +785,19 @@ re_char_class(Cs, Cc, _) -> {reverse(Cc),Cs}. % Preserve order %% posix_cc(String) -> {PosixClass,RestString}. %% Handle POSIX character classes. -posix_cc("alnum" ++ Cs) -> {alnum,Cs}; -posix_cc("alpha" ++ Cs) -> {alpha,Cs}; -posix_cc("blank" ++ Cs) -> {blank,Cs}; -posix_cc("cntrl" ++ Cs) -> {cntrl,Cs}; -posix_cc("digit" ++ Cs) -> {digit,Cs}; -posix_cc("graph" ++ Cs) -> {graph,Cs}; -posix_cc("lower" ++ Cs) -> {lower,Cs}; -posix_cc("print" ++ Cs) -> {print,Cs}; -posix_cc("punct" ++ Cs) -> {punct,Cs}; -posix_cc("space" ++ Cs) -> {space,Cs}; -posix_cc("upper" ++ Cs) -> {upper,Cs}; -posix_cc("xdigit" ++ Cs) -> {xdigit,Cs}; -posix_cc(Cs) -> parse_error({posix_cc,substr(Cs, 1, 5)}). +%% posix_cc("alnum" ++ Cs) -> {alnum,Cs}; +%% posix_cc("alpha" ++ Cs) -> {alpha,Cs}; +%% posix_cc("blank" ++ Cs) -> {blank,Cs}; +%% posix_cc("cntrl" ++ Cs) -> {cntrl,Cs}; +%% posix_cc("digit" ++ Cs) -> {digit,Cs}; +%% posix_cc("graph" ++ Cs) -> {graph,Cs}; +%% posix_cc("lower" ++ Cs) -> {lower,Cs}; +%% posix_cc("print" ++ Cs) -> {print,Cs}; +%% posix_cc("punct" ++ Cs) -> {punct,Cs}; +%% posix_cc("space" ++ Cs) -> {space,Cs}; +%% posix_cc("upper" ++ Cs) -> {upper,Cs}; +%% posix_cc("xdigit" ++ Cs) -> {xdigit,Cs}; +%% posix_cc(Cs) -> parse_error({posix_cc,substr(Cs, 1, 5)}). escape_char($n) -> $\n; % \n = LF escape_char($r) -> $\r; % \r = CR @@ -797,24 +816,24 @@ escape_char(C) -> C. % Pass it straight through %% Int, -> Int,any %% Int1,Int2 -> Int1,Int2 -re_interval_range(Cs0) -> - case re_number(Cs0) of - {none,Cs1} -> {none,none,Cs1}; - {N,[$,|Cs1]} -> - case re_number(Cs1) of - {none,Cs2} -> {N,any,Cs2}; - {M,Cs2} -> {N,M,Cs2} - end; - {N,Cs1} -> {N,none,Cs1} - end. +%% re_interval_range(Cs0) -> +%% case re_number(Cs0) of +%% {none,Cs1} -> {none,none,Cs1}; +%% {N,[$,|Cs1]} -> +%% case re_number(Cs1) of +%% {none,Cs2} -> {N,any,Cs2}; +%% {M,Cs2} -> {N,M,Cs2} +%% end; +%% {N,Cs1} -> {N,none,Cs1} +%% end. -re_number([C|Cs]) when C >= $0, C =< $9 -> - re_number(Cs, C - $0); -re_number(Cs) -> {none,Cs}. +%% re_number([C|Cs]) when C >= $0, C =< $9 -> +%% re_number(Cs, C - $0); +%% re_number(Cs) -> {none,Cs}. -re_number([C|Cs], Acc) when C >= $0, C =< $9 -> - re_number(Cs, 10*Acc + (C - $0)); -re_number(Cs, Acc) -> {Acc,Cs}. +%% re_number([C|Cs], Acc) when C >= $0, C =< $9 -> +%% re_number(Cs, 10*Acc + (C - $0)); +%% re_number(Cs, Acc) -> {Acc,Cs}. string_between(Cs1, Cs2) -> substr(Cs1, 1, length(Cs1)-length(Cs2)). diff --git a/lib/parsetools/src/yecc.erl b/lib/parsetools/src/yecc.erl index 4119e2631b..72cff3af92 100644 --- a/lib/parsetools/src/yecc.erl +++ b/lib/parsetools/src/yecc.erl @@ -278,8 +278,8 @@ options(Options0) when is_list(Options0) -> (T) -> [T] end, Options0), options(Options, [file_attributes, includefile, parserfile, - report_errors, report_warnings, return_errors, - return_warnings, time, verbose], []) + report_errors, report_warnings, warnings_as_errors, + return_errors, return_warnings, time, verbose], []) catch error: _ -> badarg end; options(Option) -> @@ -333,6 +333,7 @@ default_option(includefile) -> []; default_option(parserfile) -> []; default_option(report_errors) -> true; default_option(report_warnings) -> true; +default_option(warnings_as_errors) -> false; default_option(return_errors) -> false; default_option(return_warnings) -> false; default_option(time) -> false; @@ -341,6 +342,7 @@ default_option(verbose) -> false. atom_option(file_attributes) -> {file_attributes, true}; atom_option(report_errors) -> {report_errors, true}; atom_option(report_warnings) -> {report_warnings, true}; +atom_option(warnings_as_errors) -> {warnings_as_errors,true}; atom_option(return_errors) -> {return_errors, true}; atom_option(return_warnings) -> {return_warnings, true}; atom_option(time) -> {time, true}; @@ -409,12 +411,16 @@ infile(Parent, Infilex, Options) -> {error, Reason} -> add_error(St0#yecc.infile, none, {file_error, Reason}, St0) end, - case St#yecc.errors of - [] -> ok; + case {St#yecc.errors, werr(St)} of + {[], false} -> ok; _ -> _ = file:delete(St#yecc.outfile) end, Parent ! {self(), yecc_ret(St)}. +werr(St) -> + member(warnings_as_errors, St#yecc.options) + andalso length(St#yecc.warnings) > 0. + outfile(St0) -> case file:open(St0#yecc.outfile, [write, delayed_write]) of {ok, Outport} -> @@ -777,17 +783,23 @@ yecc_ret(St0) -> report_warnings(St), Es = pack_errors(St#yecc.errors), Ws = pack_warnings(St#yecc.warnings), + Werr = werr(St), if + Werr -> + do_error_return(St, Es, Ws); Es =:= [] -> case member(return_warnings, St#yecc.options) of true -> {ok, St#yecc.outfile, Ws}; false -> {ok, St#yecc.outfile} end; true -> - case member(return_errors, St#yecc.options) of - true -> {error, Es, Ws}; - false -> error - end + do_error_return(St, Es, Ws) + end. + +do_error_return(St, Es, Ws) -> + case member(return_errors, St#yecc.options) of + true -> {error, Es, Ws}; + false -> error end. check_expected(St0) -> diff --git a/lib/parsetools/test/leex_SUITE.erl b/lib/parsetools/test/leex_SUITE.erl index 23ad16f98d..48312445ef 100644 --- a/lib/parsetools/test/leex_SUITE.erl +++ b/lib/parsetools/test/leex_SUITE.erl @@ -152,6 +152,19 @@ file(Config) when is_list(Config) -> ?line writable(Dotfile), file:delete(Dotfile), + Warn = <<"Definitions.1998\n" + "D = [0-9]\n" + "Rules.\n" + "{L}+ : {token,{word,TokenLine,TokenChars}}.\n" + "Erlang code.\n">>, + ok = file:write_file(Filename, Warn), + error = leex:file(Filename, [warnings_as_errors]), + error = leex:file(Filename, [return_warnings,warnings_as_errors]), + {ok,Scannerfile,[{Filename,[{1,leex,ignored_characters}]}]} = + leex:file(Filename, [return_warnings]), + {error,_,[{Filename,[{1,leex,ignored_characters}]}]} = + leex:file(Filename, [return_errors,warnings_as_errors]), + file:delete(Filename), ok. @@ -551,7 +564,7 @@ ex2(Config) when is_list(Config) -> <<" %%% File : erlang_scan.xrl %%% Author : Robert Virding -%%% Purpose : Tkoen definitions for Erlang. +%%% Purpose : Token definitions for Erlang. Definitions. O = [0-7] diff --git a/lib/parsetools/test/yecc_SUITE.erl b/lib/parsetools/test/yecc_SUITE.erl index 1de87b3bff..0133524950 100644 --- a/lib/parsetools/test/yecc_SUITE.erl +++ b/lib/parsetools/test/yecc_SUITE.erl @@ -247,6 +247,14 @@ syntax(Config) when is_list(Config) -> ?line {ok,_,[{_,[{2,yecc,bad_declaration}]}]} = yecc:file(Filename, Ret), + %% Bad declaration with warnings_as_errors. + error = yecc:file(Filename, [warnings_as_errors]), + error = yecc:file(Filename, [return_warnings,warnings_as_errors]), + {ok,_,[{_,[{2,yecc,bad_declaration}]}]} = + yecc:file(Filename, [return_warnings]), + {error,_,[{_,[{2,yecc,bad_declaration}]}]} = + yecc:file(Filename, [return_errors,warnings_as_errors]), + %% Bad declaration. ?line ok = file:write_file(Filename, <<"Nonterminals nt. Terminals t. diff --git a/lib/ssl/src/ssl.appup.src b/lib/ssl/src/ssl.appup.src index cf8867245b..29674f30da 100644 --- a/lib/ssl/src/ssl.appup.src +++ b/lib/ssl/src/ssl.appup.src @@ -1,6 +1,7 @@ %% -*- erlang -*- {"%VSN%", [ + {"4.1.5", [{restart_application, ssl}]}, {"4.1.4", [{restart_application, ssl}]}, {"4.1.3", [{restart_application, ssl}]}, {"4.1.2", [{restart_application, ssl}]}, @@ -9,6 +10,7 @@ {"4.0.1", [{restart_application, ssl}]} ], [ + {"4.1.5", [{restart_application, ssl}]}, {"4.1.4", [{restart_application, ssl}]}, {"4.1.3", [{restart_application, ssl}]}, {"4.1.2", [{restart_application, ssl}]}, diff --git a/lib/ssl/src/ssl_manager.erl b/lib/ssl/src/ssl_manager.erl index 1bbb03bdde..541ca1e918 100644 --- a/lib/ssl/src/ssl_manager.erl +++ b/lib/ssl/src/ssl_manager.erl @@ -265,19 +265,22 @@ handle_cast({register_session, Port, Session}, CacheCb:update(Cache, {Port, NewSession#session.session_id}, NewSession), {noreply, State}; -handle_cast({invalidate_session, Host, Port, +%%% When a session is invalidated we need to wait a while before deleting +%%% it as there might be pending connections that rightfully needs to look +%%% up the session data but new connections should not get to use this session. +handle_cast({invalidate_session, Host, Port, #session{session_id = ID} = Session}, #state{session_cache = Cache, session_cache_cb = CacheCb} = State) -> CacheCb:update(Cache, {{Host, Port}, ID}, Session#session{is_resumable = false}), - timer:apply_after(?CLEAN_SESSION_DB, CacheCb, delete, [{{Host, Port}, ID}]), + timer:send_after(delay_time(), self(), {delayed_clean_session, {{Host, Port}, ID}}), {noreply, State}; handle_cast({invalidate_session, Port, #session{session_id = ID} = Session}, #state{session_cache = Cache, session_cache_cb = CacheCb} = State) -> CacheCb:update(Cache, {Port, ID}, Session#session{is_resumable = false}), - timer:apply_after(?CLEAN_SESSION_DB, CacheCb, delete, [{Port, ID}]), + timer:send_after(delay_time(), self(), {delayed_clean_session, {Port, ID}}), {noreply, State}; handle_cast({recache_pem, File, LastWrite, Pid, From}, @@ -312,6 +315,12 @@ handle_info(validate_sessions, #state{session_cache_cb = CacheCb, start_session_validator(Cache, CacheCb, LifeTime), {noreply, State#state{session_validation_timer = Timer}}; +handle_info({delayed_clean_session, Key}, #state{session_cache = Cache, + session_cache_cb = CacheCb + } = State) -> + CacheCb:delete(Cache, Key), + {noreply, State}; + handle_info({'EXIT', _, _}, State) -> %% Session validator died!! Do we need to take any action? %% maybe error log @@ -411,3 +420,11 @@ cache_pem_file(File, LastWrite) -> [] -> call({cache_pem, File, LastWrite}) end. + +delay_time() -> + case application:get_env(ssl, session_delay_cleanup_time) of + {ok, Time} when is_integer(Time) -> + Time; + _ -> + ?CLEAN_SESSION_DB + end. diff --git a/lib/ssl/src/ssl_record.erl b/lib/ssl/src/ssl_record.erl index f1c0073965..4c3c0b9c58 100644 --- a/lib/ssl/src/ssl_record.erl +++ b/lib/ssl/src/ssl_record.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2010. All Rights Reserved. +%% Copyright Ericsson AB 2007-2011. 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 @@ -62,6 +62,8 @@ -compile(inline). +-define(INITIAL_BYTES, 5). + %%==================================================================== %% Internal application API %%==================================================================== @@ -360,16 +362,20 @@ get_tls_records_aux(<<1:1, Length0:15, Data0:Length0/binary, Rest/binary>>, get_tls_records_aux(<<0:1, _CT:7, ?BYTE(_MajVer), ?BYTE(_MinVer), ?UINT16(Length), _/binary>>, - _Acc) when Length > ?MAX_CIPHER_TEXT_LENGTH-> + _Acc) when Length > ?MAX_CIPHER_TEXT_LENGTH -> ?ALERT_REC(?FATAL, ?RECORD_OVERFLOW); get_tls_records_aux(<<1:1, Length0:15, _/binary>>,_Acc) - when Length0 > ?MAX_CIPHER_TEXT_LENGTH-> + when Length0 > ?MAX_CIPHER_TEXT_LENGTH -> ?ALERT_REC(?FATAL, ?RECORD_OVERFLOW); get_tls_records_aux(Data, Acc) -> - {lists:reverse(Acc), Data}. - + case size(Data) =< ?MAX_CIPHER_TEXT_LENGTH + ?INITIAL_BYTES of + true -> + {lists:reverse(Acc), Data}; + false -> + ?ALERT_REC(?FATAL, ?UNEXPECTED_MESSAGE) + end. %%-------------------------------------------------------------------- -spec protocol_version(tls_atom_version() | tls_version()) -> tls_version() | tls_atom_version(). diff --git a/lib/ssl/src/ssl_session_cache.erl b/lib/ssl/src/ssl_session_cache.erl index 823bf7acfa..c1be6691be 100644 --- a/lib/ssl/src/ssl_session_cache.erl +++ b/lib/ssl/src/ssl_session_cache.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. 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 diff --git a/lib/ssl/test/Makefile b/lib/ssl/test/Makefile index 53b2223035..5be07cad2c 100644 --- a/lib/ssl/test/Makefile +++ b/lib/ssl/test/Makefile @@ -61,8 +61,10 @@ HRL_FILES = ssl_test_MACHINE.hrl HRL_FILES_SRC = \ ssl_int.hrl \ + ssl_internal.hrl\ ssl_alert.hrl \ - ssl_handshake.hrl + ssl_handshake.hrl \ + ssl_record.hrl HRL_FILES_INC = diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl index 4f0907027f..ecb5228a8b 100644 --- a/lib/ssl/test/ssl_basic_SUITE.erl +++ b/lib/ssl/test/ssl_basic_SUITE.erl @@ -30,6 +30,8 @@ -include("ssl_alert.hrl"). -include("ssl_int.hrl"). +-include("ssl_internal.hrl"). +-include("ssl_record.hrl"). -define('24H_in_sec', 86400). -define(TIMEOUT, 60000). @@ -209,7 +211,7 @@ all() -> controller_dies, client_closes_socket, peercert, connect_dist, peername, sockname, socket_options, misc_ssl_options, versions, cipher_suites, upgrade, - upgrade_with_timeout, tcp_connect, ipv6, ekeyfile, + upgrade_with_timeout, tcp_connect, tcp_connect_big, ipv6, ekeyfile, ecertfile, ecacertfile, eoptions, shutdown, shutdown_write, shutdown_both, shutdown_error, ciphers_rsa_signed_certs, ciphers_rsa_signed_certs_ssl3, @@ -1097,6 +1099,41 @@ tcp_connect(Config) when is_list(Config) -> end end. +tcp_connect_big(doc) -> + ["Test what happens when a tcp tries to connect, i,e. a bad big (ssl) packet is sent first"]; + +tcp_connect_big(suite) -> + []; + +tcp_connect_big(Config) when is_list(Config) -> + ServerOpts = ?config(server_opts, Config), + {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + TcpOpts = [binary, {reuseaddr, true}], + + Server = ssl_test_lib:start_upgrade_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {timeout, 5000}, + {mfa, {?MODULE, dummy, []}}, + {tcp_options, TcpOpts}, + {ssl_options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + + {ok, Socket} = gen_tcp:connect(Hostname, Port, [binary, {packet, 0}]), + test_server:format("Testcase ~p connected to Server ~p ~n", [self(), Server]), + + Rand = crypto:rand_bytes(?MAX_CIPHER_TEXT_LENGTH+1), + gen_tcp:send(Socket, <<?BYTE(0), + ?BYTE(3), ?BYTE(1), ?UINT16(?MAX_CIPHER_TEXT_LENGTH), Rand/binary>>), + + receive + {tcp_closed, Socket} -> + receive + {Server, {error, timeout}} -> + test_server:fail("hangs"); + {Server, {error, Error}} -> + test_server:format("Error ~p", [Error]) + end + end. dummy(_Socket) -> %% Should not happen as the ssl connection will not be established @@ -1659,7 +1696,7 @@ reuse_session(Config) when is_list(Config) -> Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, - {mfa, {?MODULE, session_info_result, []}}, + {mfa, {ssl_test_lib, session_info_result, []}}, {options, ServerOpts}]), Port = ssl_test_lib:inet_port(Server), Client0 = @@ -1681,7 +1718,7 @@ reuse_session(Config) when is_list(Config) -> Client1 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, - {mfa, {?MODULE, session_info_result, []}}, + {mfa, {ssl_test_lib, session_info_result, []}}, {from, self()}, {options, ClientOpts}]), receive {Client1, SessionInfo} -> @@ -1697,7 +1734,7 @@ reuse_session(Config) when is_list(Config) -> Client2 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, - {mfa, {?MODULE, session_info_result, []}}, + {mfa, {ssl_test_lib, session_info_result, []}}, {from, self()}, {options, [{reuse_sessions, false} | ClientOpts]}]), receive @@ -1713,7 +1750,7 @@ reuse_session(Config) when is_list(Config) -> Server1 = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, - {mfa, {?MODULE, session_info_result, []}}, + {mfa, {ssl_test_lib, session_info_result, []}}, {options, [{reuse_sessions, false} | ServerOpts]}]), Port1 = ssl_test_lib:inet_port(Server1), @@ -1737,7 +1774,7 @@ reuse_session(Config) when is_list(Config) -> Client4 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port1}, {host, Hostname}, - {mfa, {?MODULE, session_info_result, []}}, + {mfa, {ssl_test_lib, session_info_result, []}}, {from, self()}, {options, ClientOpts}]), receive @@ -1756,9 +1793,6 @@ reuse_session(Config) when is_list(Config) -> ssl_test_lib:close(Client3), ssl_test_lib:close(Client4). -session_info_result(Socket) -> - ssl:session_info(Socket). - %%-------------------------------------------------------------------- reuse_session_expired(doc) -> ["Test sessions is not reused when it has expired"]; @@ -1774,7 +1808,7 @@ reuse_session_expired(Config) when is_list(Config) -> Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, - {mfa, {?MODULE, session_info_result, []}}, + {mfa, {ssl_test_lib, session_info_result, []}}, {options, ServerOpts}]), Port = ssl_test_lib:inet_port(Server), Client0 = @@ -1796,7 +1830,7 @@ reuse_session_expired(Config) when is_list(Config) -> Client1 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, - {mfa, {?MODULE, session_info_result, []}}, + {mfa, {ssl_test_lib, session_info_result, []}}, {from, self()}, {options, ClientOpts}]), receive {Client1, SessionInfo} -> @@ -1815,7 +1849,7 @@ reuse_session_expired(Config) when is_list(Config) -> Client2 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, - {mfa, {?MODULE, session_info_result, []}}, + {mfa, {ssl_test_lib, session_info_result, []}}, {from, self()}, {options, ClientOpts}]), receive {Client2, SessionInfo} -> @@ -1844,7 +1878,7 @@ server_does_not_want_to_reuse_session(Config) when is_list(Config) -> Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, - {mfa, {?MODULE, session_info_result, []}}, + {mfa, {ssl_test_lib, session_info_result, []}}, {options, [{reuse_session, fun(_,_,_,_) -> false end} | @@ -1870,7 +1904,7 @@ server_does_not_want_to_reuse_session(Config) when is_list(Config) -> Client1 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, - {mfa, {?MODULE, session_info_result, []}}, + {mfa, {ssl_test_lib, session_info_result, []}}, {from, self()}, {options, ClientOpts}]), receive {Client1, SessionInfo} -> @@ -3179,7 +3213,7 @@ no_reuses_session_server_restart_new_cert(Config) when is_list(Config) -> Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, - {mfa, {?MODULE, session_info_result, []}}, + {mfa, {ssl_test_lib, session_info_result, []}}, {options, ServerOpts}]), Port = ssl_test_lib:inet_port(Server), Client0 = @@ -3207,7 +3241,7 @@ no_reuses_session_server_restart_new_cert(Config) when is_list(Config) -> Client1 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, - {mfa, {?MODULE, session_info_result, []}}, + {mfa, {ssl_test_lib, session_info_result, []}}, {from, self()}, {options, ClientOpts}]), receive {Client1, SessionInfo} -> @@ -3238,7 +3272,7 @@ no_reuses_session_server_restart_new_cert_file(Config) when is_list(Config) -> Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, - {mfa, {?MODULE, session_info_result, []}}, + {mfa, {ssl_test_lib, session_info_result, []}}, {options, NewServerOpts}]), Port = ssl_test_lib:inet_port(Server), Client0 = @@ -3268,7 +3302,7 @@ no_reuses_session_server_restart_new_cert_file(Config) when is_list(Config) -> Client1 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, - {mfa, {?MODULE, session_info_result, []}}, + {mfa, {ssl_test_lib, session_info_result, []}}, {from, self()}, {options, ClientOpts}]), receive {Client1, SessionInfo} -> diff --git a/lib/ssl/test/ssl_session_cache_SUITE.erl b/lib/ssl/test/ssl_session_cache_SUITE.erl index a43b9ab586..5d96b457ed 100644 --- a/lib/ssl/test/ssl_session_cache_SUITE.erl +++ b/lib/ssl/test/ssl_session_cache_SUITE.erl @@ -29,6 +29,7 @@ -define(SLEEP, 500). -define(TIMEOUT, 60000). -define(LONG_TIMEOUT, 600000). + -behaviour(ssl_session_cache_api). %% For the session cache tests @@ -95,6 +96,16 @@ init_per_testcase(session_cache_process_mnesia, Config) -> mnesia:start(), init_customized_session_cache(mnesia, Config); +init_per_testcase(session_cleanup, Config0) -> + Config = lists:keydelete(watchdog, 1, Config0), + Dog = test_server:timetrap(?TIMEOUT), + ssl:stop(), + application:load(ssl), + application:set_env(ssl, session_lifetime, 5), + application:set_env(ssl, session_delay_cleanup_time, ?SLEEP), + ssl:start(), + [{watchdog, Dog} | Config]; + init_per_testcase(_TestCase, Config0) -> Config = lists:keydelete(watchdog, 1, Config0), Dog = test_server:timetrap(?TIMEOUT), @@ -128,6 +139,10 @@ end_per_testcase(session_cache_process_mnesia, Config) -> ssl:stop(), ssl:start(), end_per_testcase(default_action, Config); +end_per_testcase(session_cleanup, Config) -> + application:unset_env(ssl, session_delay_cleanup_time), + application:unset_env(ssl, session_lifetime), + end_per_testcase(default_action, Config); end_per_testcase(_TestCase, Config) -> Dog = ?config(watchdog, Config), case Dog of @@ -148,7 +163,8 @@ end_per_testcase(_TestCase, Config) -> suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - [session_cache_process_list, + [session_cleanup, + session_cache_process_list, session_cache_process_mnesia]. groups() -> @@ -159,7 +175,67 @@ init_per_group(_GroupName, Config) -> end_per_group(_GroupName, Config) -> Config. +%%-------------------------------------------------------------------- +session_cleanup(doc) -> + ["Test that sessions are cleand up eventually, so that the session table " + "does grow and grow ..."]; +session_cleanup(suite) -> + []; +session_cleanup(Config)when is_list(Config) -> + process_flag(trap_exit, true), + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Server = + ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, session_info_result, []}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + Client = + ssl_test_lib:start_client([{node, ClientNode}, + {port, Port}, {host, Hostname}, + {mfa, {ssl_test_lib, no_result, []}}, + {from, self()}, {options, ClientOpts}]), + SessionInfo = + receive + {Server, Info} -> + Info + end, + + %% Make sure session is registered + test_server:sleep(?SLEEP), + + {status, _, _, StatusInfo} = sys:get_status(whereis(ssl_manager)), + [_, _,_, _, Prop] = StatusInfo, + State = state(Prop), + Cache = element(2, State), + + Id = proplists:get_value(session_id, SessionInfo), + CSession = ssl_session_cache:lookup(Cache, {{Hostname, Port}, Id}), + SSession = ssl_session_cache:lookup(Cache, {Port, Id}), + + true = CSession =/= undefined, + true = SSession =/= undefined, + + %% Make sure session has expired and been cleaned up + test_server:sleep(5000), %% Expire time + test_server:sleep((?SLEEP*20), %% Clean up delay (very small in this test case) + some extra time + + undefined = ssl_session_cache:lookup(Cache, {{Hostname, Port}, Id}), + undefined = ssl_session_cache:lookup(Cache, {Port, Id}), + + process_flag(trap_exit, false), + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +state([{data,[{"State", State}]} | _]) -> + State; +state([_ | Rest]) -> + state(Rest). +%%-------------------------------------------------------------------- session_cache_process_list(doc) -> ["Test reuse of sessions (short handshake)"]; diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl index 40bbdf1dbd..b7916b96eb 100644 --- a/lib/ssl/test/ssl_test_lib.erl +++ b/lib/ssl/test/ssl_test_lib.erl @@ -670,3 +670,6 @@ cipher_result(Socket, Result) -> Other -> {unexpected, Other} end. + +session_info_result(Socket) -> + ssl:session_info(Socket). diff --git a/lib/ssl/vsn.mk b/lib/ssl/vsn.mk index 0e80e42637..8286201df4 100644 --- a/lib/ssl/vsn.mk +++ b/lib/ssl/vsn.mk @@ -1 +1 @@ -SSL_VSN = 4.1.5 +SSL_VSN = 4.1.6 diff --git a/lib/stdlib/src/erl_tar.erl b/lib/stdlib/src/erl_tar.erl index fd85c7aef5..306834e845 100644 --- a/lib/stdlib/src/erl_tar.erl +++ b/lib/stdlib/src/erl_tar.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% Copyright Ericsson AB 1997-2011. 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 @@ -798,30 +798,10 @@ set_extracted_file_info(Name, #tar_header{mode=Mode, mtime=Mtime}) -> %% Makes all directories leading up to the file. -make_dirs(Name, Type) -> - make_dirs1(filename:split(Name), Type). - -make_dirs1([Dir, Next|Rest], Type) -> - case file:read_file_info(Dir) of - {ok, #file_info{type=directory}} -> - make_dirs1([filename:join(Dir, Next)|Rest], Type); - {ok, #file_info{}} -> - throw({error, enotdir}); - {error, _} -> - case file:make_dir(Dir) of - ok -> - make_dirs1([filename:join(Dir, Next)|Rest], Type); - {error, Reason} -> - throw({error, Reason}) - end - end; -make_dirs1([_], file) -> ok; -make_dirs1([Dir], dir) -> - file:make_dir(Dir); -make_dirs1([], _) -> - %% There must be something wrong here. The list was not supposed - %% to be empty. - throw({error, enoent}). +make_dirs(Name, file) -> + filelib:ensure_dir(Name); +make_dirs(Name, dir) -> + filelib:ensure_dir(filename:join(Name,"*")). %% Prints the message on if the verbose option is given (for reading). diff --git a/lib/stdlib/vsn.mk b/lib/stdlib/vsn.mk index c0956030cf..9d4ed17774 100644 --- a/lib/stdlib/vsn.mk +++ b/lib/stdlib/vsn.mk @@ -1 +1 @@ -STDLIB_VSN = 1.17.4 +STDLIB_VSN = 1.17.5 |