/** * Copyright (c) 2021 OceanBase * OceanBase CE is licensed under Mulan PubL v2. * You can use this software according to the terms and conditions of the Mulan PubL v2. * You may obtain a copy of Mulan PubL v2 at: * http://license.coscl.org.cn/MulanPubL-2.0 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PubL v2 for more details. */ #define USING_LOG_PREFIX SQL_OPT #include "observer/ob_server.h" #include "election/ob_election_async_log.h" #include "clog/ob_clog_history_reporter.h" #include "sql/optimizer/ob_opt_est_cost.h" #include "sql/optimizer/ob_opt_est_utils.h" #include "observer/ob_req_time_service.h" #include #define BUF_LEN 102400 // 100K using std::cout; using namespace oceanbase::lib; using namespace oceanbase::json; using oceanbase::sql::ObTableLocation; using namespace oceanbase::sql; using namespace oceanbase::observer; namespace test { class TestOptimizer :public TestOptimizerUtils { public: TestOptimizer(){} ~TestOptimizer(){} }; ////// insert, update, delete, select for update // TEST_F(TestOptimizer, ob_optimizer_hierarchical_query) // { // const char* test_file = "./test_optimizer_hierarchical_query.sql"; // const char* result_file = "./test_optimizer_hierarchical_query.result"; // const char* tmp_file = "./test_optimizer_hierarchical_query.tmp"; // ASSERT_NO_FATAL_FAILURE(run_test(test_file, result_file, tmp_file)); // } //TEST_F(TestOptimizer, ob_optimizer_merg) //{ // const char* test_file = "./test_optimizer_merge.sql"; // const char* result_file = "./test_optimizer_merge.result"; // const char* tmp_file = "./test_optimizer_merge.tmp"; // ASSERT_NO_FATAL_FAILURE(run_test(test_file, result_file, tmp_file)); //} TEST_F(TestOptimizer, ob_optimizer_dml) { const char* test_file = "./test_optimizer_dml.sql"; const char* result_file = "./test_optimizer_dml.result"; const char* tmp_file = "./test_optimizer_dml.tmp"; ASSERT_NO_FATAL_FAILURE(run_test(test_file, result_file, tmp_file)); } // select TEST_F(TestOptimizer, ob_optimizer_select) { const char* test_file = "./test_optimizer_select.sql"; const char* result_file = "./test_optimizer_select.result"; const char* tmp_file = "./test_optimizer_select.tmp"; ASSERT_NO_FATAL_FAILURE(run_test(test_file, result_file, tmp_file)); } // explain format=json TEST_F(TestOptimizer, ob_optimizer_explain_json) { const char* test_file = "./test_optimizer_explain_json.sql"; const char* result_file = "./test_optimizer_explain_json.result"; const char* tmp_file = "./test_optimizer_explain_json.tmp"; ASSERT_NO_FATAL_FAILURE(run_test(test_file, result_file, tmp_file)); } // explain extended TEST_F(TestOptimizer, ob_optimizer_explain_extended) { const char* test_file = "./test_optimizer_explain_extended.sql"; const char* result_file = "./test_optimizer_explain_extended.result"; const char* tmp_file = "./test_optimizer_explain_extended.tmp"; ASSERT_NO_FATAL_FAILURE(run_test(test_file, result_file, tmp_file)); } // filter before index back extended TEST_F(TestOptimizer, ob_optimizer_filter_before_indexback) { const char* test_file = "./test_filter_before_indexback.sql"; const char* result_file = "./test_filter_before_indexback.result"; const char* tmp_file = "./test_filter_before_indexback.tmp"; ASSERT_NO_FATAL_FAILURE(run_test(test_file, result_file, tmp_file)); } TEST_F(TestOptimizer, ob_default_stat_est) { const char* test_file = "./test_optimizer_default_stat.sql"; const char* result_file = "./test_optimizer_default_stat.result"; const char* tmp_file = "./test_optimizer_default_stat.tmp"; ASSERT_NO_FATAL_FAILURE(run_test(test_file, result_file, tmp_file, true)); } inline bool double_eq(ObObj a, double b, double eps) { return fabs(a.get_double() - b) <= eps; } TEST_F(TestOptimizer, string_scalar_convert) { int ret = OB_SUCCESS; ObObj min, max, start, end; ObObj mins, maxs, starts, ends; //Standard case : number only, base = 10 min.set_varchar("123400000"); max.set_varchar("123500000"); start.set_varchar("123450000"); end.set_varchar("123470000"); ASSERT_TRUE(OB_SUCC(ObOptEstObjToScalar::convert_objs_to_scalars( &min, &max, &start, &end, &mins, &maxs, &starts, &ends))); ASSERT_TRUE(double_eq(mins, 0.4, 0.0001)); ASSERT_TRUE(double_eq(maxs, 0.5, 0.0001)); ASSERT_TRUE(double_eq(starts, 0.45, 0.0001)); ASSERT_TRUE(double_eq(ends, 0.47, 0.0001)); min.set_varchar("123"); max.set_varchar("123500000"); start.set_varchar("123450000"); end.set_varchar("123470000"); ASSERT_TRUE(OB_SUCC(ObOptEstObjToScalar::convert_objs_to_scalars( &min, &max, &start, &end, &mins, &maxs, &starts, &ends))); ASSERT_TRUE(double_eq(mins, 0, 0.0001)); ASSERT_TRUE(double_eq(maxs, 0.5, 0.0001)); ASSERT_TRUE(double_eq(starts, 0.45, 0.0001)); ASSERT_TRUE(double_eq(ends, 0.47, 0.0001)); min.set_varchar("1"); max.set_varchar("123500000"); start.set_varchar("123450000"); end.set_varchar("123470000"); ASSERT_TRUE(OB_SUCC(ObOptEstObjToScalar::convert_objs_to_scalars( &min, &max, &start, &end, &mins, &maxs, &starts, &ends))); ASSERT_TRUE(double_eq(mins, 0, 0.0001)); ASSERT_TRUE(double_eq(maxs, 0.235, 0.00001)); ASSERT_TRUE(double_eq(starts, 0.2345, 0.00001)); ASSERT_TRUE(double_eq(ends, 0.2347, 0.00001)); min.set_varchar("123400000"); max.set_varchar("123500000"); start.set_varchar("120000"); end.set_varchar("123470000"); ASSERT_TRUE(OB_SUCC(ObOptEstObjToScalar::convert_objs_to_scalars( &min, &max, &start, &end, &mins, &maxs, &starts, &ends))); ASSERT_TRUE(double_eq(mins, 0.34, 0.0001)); ASSERT_TRUE(double_eq(maxs, 0.35, 0.00001)); ASSERT_TRUE(double_eq(starts, 0, 0.00001)); ASSERT_TRUE(double_eq(ends, 0.347, 0.00001)); // upper character : base = 26 min.set_varchar("AAAA"); max.set_varchar("KKKK"); start.set_varchar("CCCC"); end.set_varchar("FFFF"); ASSERT_TRUE(OB_SUCC(ObOptEstObjToScalar::convert_objs_to_scalars( &min, &max, &start, &end, &mins, &maxs, &starts, &ends))); ASSERT_TRUE(double_eq(mins, 0, 0.00001)); ASSERT_TRUE(double_eq(maxs, 0.4, 0.00001)); ASSERT_TRUE(double_eq(starts, 0.08, 0.00001)); ASSERT_TRUE(double_eq(ends, 0.2, 0.00001)); // lower character : base = 26 min.set_varchar("aaaa"); //a = 97 max.set_varchar("kkkk"); //k = 107 start.set_varchar("cccc"); //c = 99 end.set_varchar("ffff");//f = 102 ASSERT_TRUE(OB_SUCC(ObOptEstObjToScalar::convert_objs_to_scalars( &min, &max, &start, &end, &mins, &maxs, &starts, &ends))); ASSERT_TRUE(double_eq(mins, 0, 0.00001)); ASSERT_TRUE(double_eq(maxs, 0.4, 0.00001)); ASSERT_TRUE(double_eq(starts, 0.08, 0.00001)); ASSERT_TRUE(double_eq(ends, 0.2, 0.00001)); // lower character number mixed : base = 122 - 48 + 1 = 75 min.set_varchar("a7aa"); //a = 97 max.set_varchar("kk1k"); //k = 107 start.set_varchar("c0cc"); //c = 99 end.set_varchar("fff6");//f = 102 ASSERT_TRUE(OB_SUCC(ObOptEstObjToScalar::convert_objs_to_scalars( &min, &max, &start, &end, &mins, &maxs, &starts, &ends))); ASSERT_TRUE(double_eq(mins, 0.654695, 0.00001)); ASSERT_TRUE(double_eq(maxs, 0.797160, 0.00001)); ASSERT_TRUE(double_eq(starts, 0.680123, 0.00001)); ASSERT_TRUE(double_eq(ends, 0.729728, 0.00001)); // other char number mixed, base = width([0-9] union [CHAR_OCCURED]) start.set_varchar("123@4.56"); //. = 46 @ = 64 base = 19 end.set_varchar("123123@4.56"); ASSERT_TRUE(OB_SUCC(ObOptEstObjToScalar::convert_objs_to_scalars( NULL, NULL, &start, &end, NULL, NULL, &starts, &ends))); ASSERT_TRUE(double_eq(starts, 0.964046, 0.00001)); ASSERT_TRUE(double_eq(ends, 0.169845, 0.00001)); } TEST_F(TestOptimizer, sort_cost) { int ret = OB_SUCCESS; //Sort cost test //default row-shape : 10 ints, sort 3 ints double rows = 1000.0; ObExprResType t_int; double cost = 0.0; t_int.set_int(); ObSEArray row_types; double width = 4 * 10; ObSEArray sort_types; for (int64_t i = 0; i < 10; ++i) { row_types.push_back(t_int); } for (int64_t i = 0; i < 3; ++i) { sort_types.push_back(t_int); } const char* tmp_file = "./test_optimizer_sort_cost.tmp"; const char* result_file = "./test_optimizer_sort_cost.result"; ObSEArray order_items; std::ofstream of_result(tmp_file); ASSERT_TRUE(of_result.is_open()); ObSortCostInfo cost_info(rows, width, 0, order_items, false); ret = ObOptEstCost::cost_sort(cost_info, cost, ObOptEstCost::VECTOR_MODEL); //add_cost=348.846000000000, get_cost=422.466000000000, real_sort_cost=262.178013484400 ASSERT_TRUE(OB_SUCCESS == ret); of_result << cost << std::endl; //ASSERT_TRUE(1048 == cost); rows = 10000.0; cost_info.rows_ = rows; //add_cost=3398.460000000000, get_cost=4206.660000000000, real_sort_cost=3495.706846458661 ret = ObOptEstCost::cost_sort(cost_info, cost, ObOptEstCost::VECTOR_MODEL); ASSERT_TRUE(OB_SUCCESS == ret); of_result << cost << std::endl; //ASSERT_TRUE(11115 == cost); rows = 100000.0; cost_info.rows_ = rows; //add_cost=33894.599999999999, get_cost=42048.599999999999, real_sort_cost=43696.335580733263 ret = ObOptEstCost::cost_sort(cost_info, cost, ObOptEstCost::VECTOR_MODEL); ASSERT_TRUE(OB_SUCCESS == ret); of_result << cost << std::endl; //ASSERT_TRUE(119654 == cost); rows = 1000000.0; cost_info.rows_ = rows; //We see that even at rows = 1000000, row_store cost is still larger than real sort cost, even not //counting cost of cache/TLB miss //add_cost=338856.000000000000, get_cost=420467.999999999942, real_sort_cost=524356.026968799182 ret = ObOptEstCost::cost_sort(cost_info, cost, ObOptEstCost::VECTOR_MODEL); ASSERT_TRUE(OB_SUCCESS == ret); of_result << cost << std::endl; //ASSERT_TRUE(1283695 == cost); //Test for mixed types ObExprResType t_vc; t_vc.set_varchar(); t_vc.set_length(255); ObExprResType t_num; t_num.set_number(); ObExprResType t_ts; t_ts.set_timestamp(); row_types.push_back(t_vc); row_types.push_back(t_vc); row_types.push_back(t_vc); row_types.push_back(t_num); row_types.push_back(t_num); row_types.push_back(t_ts); row_types.push_back(t_ts); sort_types.reset(); sort_types.push_back(t_vc); sort_types.push_back(t_num); sort_types.push_back(t_int); sort_types.push_back(t_ts); rows = 1000.0; width = 255 + 16 + 16; cost_info.rows_ = rows; cost_info.width_ = width; //add_cost=1792.210480000000, get_cost=699.636980000000, real_sort_cost=558.160103197957 ret = ObOptEstCost::cost_sort(cost_info, cost, ObOptEstCost::VECTOR_MODEL); ASSERT_TRUE(OB_SUCCESS == ret); of_result << cost << std::endl; //ASSERT_TRUE(3065 == cost); rows = 10000.0; cost_info.rows_ = rows; //add_cost=17832.104800000001, get_cost=6978.369799999999, real_sort_cost=7442.134709306095 ret = ObOptEstCost::cost_sort(cost_info, cost, ObOptEstCost::VECTOR_MODEL); ASSERT_TRUE(OB_SUCCESS == ret); of_result << cost << std::endl; //ASSERT_TRUE(32267 == cost); rows = 100000.0; //add_cost=178231.048000000039, get_cost=69765.697999999989, real_sort_cost=93026.683866326173 cost_info.rows_ = rows; ret = ObOptEstCost::cost_sort(cost_info, cost, ObOptEstCost::VECTOR_MODEL); ASSERT_TRUE(OB_SUCCESS == ret); of_result << cost << std::endl; //ASSERT_TRUE(341038 == cost); rows = 1000000.0; cost_info.rows_ = rows; //add_cost=1782220.480000000214, get_cost=697638.979999999865, real_sort_cost=1116320.206395914080 ret = ObOptEstCost::cost_sort(cost_info, cost, ObOptEstCost::VECTOR_MODEL); ASSERT_TRUE(OB_SUCCESS == ret); of_result << cost << std::endl; //ASSERT_TRUE(3596194 == cost); of_result.close(); //std::cout << "diff -u " << tmp_file << " " << result_file << std::endl; TestSqlUtils::is_equal_content(tmp_file, result_file); } TEST_F(TestOptimizer, scan_cost) { ObCostTableScanInfo est_cost_info(OB_INVALID_ID, OB_INVALID_ID, OB_INVALID_ID); ObTableMetaInfo table_meta_info(OB_INVALID_ID); est_cost_info.table_meta_info_ = &table_meta_info; double STANDARD_SCHEMA_COL_COUNT = 50; est_cost_info.table_meta_info_->micro_block_size_ = 16384; est_cost_info.table_meta_info_->table_rowkey_count_ = 3; est_cost_info.table_meta_info_->table_row_count_ = 100000; est_cost_info.table_meta_info_->part_count_ = 1; est_cost_info.index_meta_info_.index_part_size_ = OB_EST_DEFAULT_DATA_SIZE; est_cost_info.index_meta_info_.index_micro_block_size_ = 16384; est_cost_info.batch_type_ = common::ObSimpleBatch::T_SCAN; bool index_back = false; int64_t column_count = 0; double access_row_count = 0.0; double cost = 0; double index_back_cost = 0; //Temporary:if a scan has a full open range(min to max), it will be given a small increase of //cost, leading optimizer to prefer access paths with ranges. 2 conditions to trigger. //condition 1 : scan without range est_cost_info.index_meta_info_.index_column_count_ = static_cast(STANDARD_SCHEMA_COL_COUNT); column_count = 10; access_row_count = 500.0; index_back = false; ObOptEstCost::cost_table(est_cost_info, 1, access_row_count, access_row_count, cost, index_back_cost, ObOptEstCost::VECTOR_MODEL); //std::cout << type << ',' << access_row_count << ',' << column_count << ',' << cost << std::endl; // ASSERT_TRUE(1266 == cost); est_cost_info.index_meta_info_.index_column_count_ = static_cast(STANDARD_SCHEMA_COL_COUNT); column_count = 10; access_row_count = 500.0; index_back = false; ObOptEstCost::cost_table(est_cost_info, 1, access_row_count, access_row_count, cost, index_back_cost, ObOptEstCost::VECTOR_MODEL); //std::cout << type << ',' << access_row_count << ',' << column_count << ',' << cost << std::endl; // ASSERT_TRUE(502 == cost); //condition 2 : scan more than 5 blocks est_cost_info.index_meta_info_.index_column_count_ = static_cast(STANDARD_SCHEMA_COL_COUNT); column_count = 10; access_row_count = 1000.0; index_back = false; ObOptEstCost::cost_table(est_cost_info, 1, access_row_count, access_row_count, cost, index_back_cost, ObOptEstCost::VECTOR_MODEL); //std::cout << type << ',' << access_row_count << ',' << column_count << ',' << cost << std::endl; // ASSERT_TRUE(1718 == cost); //the more rows, the bigger cost is access_row_count = 10000.0; ObOptEstCost::cost_table(est_cost_info, 1, access_row_count, access_row_count, cost, index_back_cost, ObOptEstCost::VECTOR_MODEL); //std::cout << type << ',' << access_row_count << ',' << column_count << ',' << cost << std::endl; // ASSERT_TRUE(9845 == cost); //the more rows, the bigger cost is access_row_count = 100000.0; ObOptEstCost::cost_table(est_cost_info, 1, access_row_count, access_row_count, cost, index_back_cost, ObOptEstCost::VECTOR_MODEL); //std::cout << type << ',' << access_row_count << ',' << column_count << ',' << cost << std::endl; // ASSERT_TRUE(97496 == cost); //the more columns, the bigger cost is column_count = 20; ObOptEstCost::cost_table(est_cost_info, 1, access_row_count, access_row_count, cost, index_back_cost, ObOptEstCost::VECTOR_MODEL); //std::cout << type << ',' << access_row_count << ',' << column_count << ',' << cost << std::endl; // ASSERT_TRUE(126709 == cost); //the wider the table is, the bigger cost is est_cost_info.index_meta_info_.index_column_count_ = 2 * static_cast(STANDARD_SCHEMA_COL_COUNT); ObOptEstCost::cost_table(est_cost_info, 1, access_row_count, access_row_count, cost, index_back_cost, ObOptEstCost::VECTOR_MODEL); //std::cout << type << ',' << access_row_count << ',' << column_count << ',' << cost << std::endl; // ASSERT_TRUE(182992 == cost); //scan index back index_back = true; est_cost_info.postfix_filter_sel_ = 0.1; ObOptEstCost::cost_table(est_cost_info, 1, access_row_count, access_row_count, cost, index_back_cost, ObOptEstCost::VECTOR_MODEL); //std::cout << type << ',' << access_row_count << ',' << column_count << ',' << cost << std::endl; // ASSERT_TRUE(283235 == cost); //get est_cost_info.batch_type_ = common::ObSimpleBatch::T_GET; est_cost_info.postfix_filter_sel_ = 1.0; est_cost_info.index_meta_info_.index_column_count_ = static_cast(STANDARD_SCHEMA_COL_COUNT); column_count = 10; access_row_count = 500.0; index_back = false; ObOptEstCost::cost_table(est_cost_info, 1, access_row_count, access_row_count, cost, index_back_cost, ObOptEstCost::VECTOR_MODEL); //std::cout << type << ',' << access_row_count << ',' << column_count << ',' << cost << std::endl; // ASSERT_TRUE(6751 == cost); //the more rows, the bigger cost is access_row_count = 1000; ObOptEstCost::cost_table(est_cost_info, 1, access_row_count, access_row_count, cost, index_back_cost, ObOptEstCost::VECTOR_MODEL); //std::cout << type << ',' << access_row_count << ',' << column_count << ',' << cost << std::endl; // ASSERT_TRUE(13503 == cost); //Compare of scan and get at 1000 rows //cost of get is roughly 10 times bigger than cost of scan at same row count est_cost_info.batch_type_ = common::ObSimpleBatch::T_SCAN; ObOptEstCost::cost_table(est_cost_info, 1, access_row_count, access_row_count, cost, index_back_cost, ObOptEstCost::VECTOR_MODEL); //std::cout << type << ',' << access_row_count << ',' << column_count << ',' << cost << std::endl; // ASSERT_TRUE(1718 == cost); est_cost_info.batch_type_ = common::ObSimpleBatch::T_GET; //the more columns, the bigger cost is column_count = 20; ObOptEstCost::cost_table(est_cost_info, 1, access_row_count, access_row_count, cost, index_back_cost, ObOptEstCost::VECTOR_MODEL); //std::cout << type << ',' << access_row_count << ',' << column_count << ',' << cost << std::endl; // ASSERT_TRUE(14041 == cost); //get index back index_back = true; ObOptEstCost::cost_table(est_cost_info, 1, access_row_count, access_row_count, cost, index_back_cost, ObOptEstCost::VECTOR_MODEL); //std::cout << type << ',' << access_row_count << ',' << column_count << ',' << cost << std::endl; // ASSERT_TRUE(27168 == cost); } //TEST_F(TestOptimizer, ob_optimizer_failed) //{ // const char* test_file = "./test_optimizer_failed.sql"; // ASSERT_NO_FATAL_FAILURE(run_fail_test(test_file)); //} // hint TEST_F(TestOptimizer, ob_optimizer_hint) { const char* test_file = "./test_optimizer_hint.sql"; const char* result_file = "./test_optimizer_hint.result"; const char* tmp_file = "./test_optimizer_hint.tmp"; explain_type_ = EXPLAIN_OUTLINE; ASSERT_NO_FATAL_FAILURE(run_test(test_file, result_file, tmp_file)); } TEST_F(TestOptimizer, ob_optimizer_outline) { const char* test_file = "./test_optimizer_outline.sql"; const char* result_file = "./test_optimizer_outline.result"; const char* tmp_file = "./test_optimizer_outline.tmp"; explain_type_ = EXPLAIN_OUTLINE; ASSERT_NO_FATAL_FAILURE(run_test(test_file, result_file, tmp_file)); } TEST_F(TestOptimizer, ob_optimizer_used_hint) { const char* test_file = "./test_optimizer_used_hint.sql"; const char* result_file = "./test_optimizer_used_hint.result"; const char* tmp_file = "./test_optimizer_used_hint.tmp"; explain_type_ = EXPLAIN_EXTENDED; ASSERT_NO_FATAL_FAILURE(run_test(test_file, result_file, tmp_file)); } /* todo(@ banliu.zyd): 功能还没有测全,暂时注释 TEST_F(TestOptimizer, ob_optimizer_hualong) { const char* test_file = "./test_optimizer_hualong.sql"; const char* result_file = "./test_optimizer_hualong.result"; const char* tmp_file = "./test_optimizer_hualong.tmp"; ASSERT_NO_FATAL_FAILURE(run_test(test_file, result_file, tmp_file)); } TEST_F(TestOptimizer, ob_optimizer_hualong_default) { const char* test_file = "./test_optimizer_hualong.sql"; const char* result_file = "./test_optimizer_hualong.result"; const char* tmp_file = "./test_optimizer_hualong.tmp"; ASSERT_NO_FATAL_FAILURE(run_test(test_file, result_file, tmp_file, true)); } */ TEST_F(TestOptimizer, ob_optimizer_topk) { const char* test_file = "./test_optimizer_topk.sql"; const char* result_file = "./test_optimizer_topk.result"; const char* tmp_file = "./test_optimizer_topk.tmp"; explain_type_ = EXPLAIN_EXTENDED; ASSERT_NO_FATAL_FAILURE(run_test(test_file, result_file, tmp_file)); } } int main(int argc, char **argv) { //char c; //std::cout<<"Press any key to continue..."<>c; set_memory_limit(10L << 30); system("rm -rf test_optimizer.log"); observer::ObReqTimeGuard req_timeinfo_guard; OB_LOGGER.set_log_level("INFO"); OB_LOGGER.set_file_name("test_optimizer.log", true); ObServerOptions opts; opts.cluster_id_ = 1; opts.rs_list_ = "127.0.0.1:1"; opts.zone_ = "test1"; opts.data_dir_ = "/tmp"; opts.mysql_port_ = 23000 + getpid() % 1000; opts.rpc_port_ = 24000 + getpid() % 1000; system("mkdir -p /tmp/sstable /tmp/clog /tmp/slog"); GCONF.datafile_size = 41943040; //ObServer::get_instance().init(opts); oceanbase::sql::init_sql_factories(); ::testing::InitGoogleTest(&argc,argv); if(argc >= 2) { if (strcmp("DEBUG", argv[1]) == 0 || strcmp("WARN", argv[1]) == 0) OB_LOGGER.set_log_level(argv[1]); } test::parse_cmd_line_param(argc, argv, test::clp); int ret = RUN_ALL_TESTS(); OB_LOGGER.set_log_level("ERROR"); return ret; }