1218 lines
		
	
	
		
			45 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1218 lines
		
	
	
		
			45 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /**
 | |
|  * 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.
 | |
|  */
 | |
| 
 | |
| #include <gtest/gtest.h>
 | |
| #define protected public
 | |
| #define private public
 | |
| #include "sql/test_sql_utils.h"
 | |
| #include "lib/utility/ob_test_util.h"
 | |
| #include "sql/rewrite/ob_query_range.h"
 | |
| #include "sql/ob_sql_init.h"
 | |
| #include "sql/resolver/expr/ob_raw_expr_util.h"
 | |
| #include "common/ob_clock_generator.h"
 | |
| #include "lib/json/ob_json_print_utils.h"
 | |
| #include <fstream>
 | |
| #undef protected
 | |
| #undef private
 | |
| using namespace oceanbase;
 | |
| using namespace oceanbase::common;
 | |
| using namespace oceanbase::lib;
 | |
| using namespace oceanbase::sql;
 | |
| using namespace oceanbase::share::schema;
 | |
| 
 | |
| const int64_t BUF_LEN = 102400;
 | |
| class ObQueryRangeTest : public ::testing::Test {
 | |
| public:
 | |
|   ObQueryRangeTest();
 | |
|   virtual ~ObQueryRangeTest();
 | |
|   virtual void SetUp();
 | |
|   virtual void TearDown();
 | |
|   int set_column_info(ColumnItem& column_item, ObObjType data_type, const char* column_name, int64_t pos);
 | |
|   void resolve_condition(
 | |
|       const ColumnIArray& range_columns, const char* expr_str, ObRawExpr*& expr, ParamStore* params = NULL)
 | |
|   {
 | |
|     ObArray<ObQualifiedName> columns;
 | |
|     ObArray<ObVarInfo> sys_vars;
 | |
|     ObArray<ObSubQueryInfo> sub_query_info;
 | |
|     ObArray<ObAggFunRawExpr*> aggr_exprs;
 | |
|     ObArray<ObWinFunRawExpr*> win_exprs;
 | |
|     ObTimeZoneInfo tz_info;
 | |
|     ObNameCaseMode case_mode = OB_NAME_CASE_INVALID;
 | |
|     ObExprResolveContext ctx(expr_factory_, &tz_info, case_mode);
 | |
|     ctx.dest_collation_ = CS_TYPE_UTF8MB4_BIN;
 | |
|     ctx.connection_charset_ = CHARSET_UTF8MB4;
 | |
|     ctx.param_list_ = params;
 | |
|     ObSQLSessionInfo session;
 | |
|     session.set_use_static_typing_engine(false);
 | |
|     ctx.session_info_ = &session;
 | |
| 
 | |
|     OK(ObRawExprUtils::make_raw_expr_from_str(
 | |
|         expr_str, strlen(expr_str), ctx, expr, columns, sys_vars, &sub_query_info, aggr_exprs, win_exprs));
 | |
|     for (int64_t i = 0; i < columns.count(); ++i) {
 | |
|       ObQualifiedName& col = columns.at(i);
 | |
|       col.ref_expr_->set_data_type(ObIntType);
 | |
|       for (int64_t j = 0; j < range_columns.count(); ++j) {
 | |
|         ASSERT_FALSE(NULL == range_columns.at(j).expr_);
 | |
|         if (col.col_name_ == range_columns.at(j).column_name_) {
 | |
|           ObColumnRefRawExpr* b_expr = static_cast<ObColumnRefRawExpr*>(col.ref_expr_);
 | |
|           ASSERT_FALSE(NULL == b_expr);
 | |
|           (*b_expr).assign(*(range_columns.at(j).expr_));
 | |
|           if (!ob_is_string_type(b_expr->get_data_type())) {
 | |
|             b_expr->set_collation_type(CS_TYPE_BINARY);
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     OK(expr->extract_info());
 | |
|     OK(expr->deduce_type(&session));
 | |
|   }
 | |
| 
 | |
|   void split_expr(ObRawExpr* expr, ObIArray<ObRawExpr*>& exprs)
 | |
|   {
 | |
|     if (NULL == expr) {
 | |
| 
 | |
|     } else if (T_OP_AND == expr->get_expr_type()) {
 | |
|       if (T_OP_AND != expr->get_param_expr(0)->get_expr_type()) {
 | |
|         OK(exprs.push_back(expr->get_param_expr(0)));
 | |
|       } else {
 | |
|         split_expr(expr->get_param_expr(0), exprs);
 | |
|       }
 | |
|       if (T_OP_AND != expr->get_param_expr(1)->get_expr_type()) {
 | |
|         OK(exprs.push_back(expr->get_param_expr(1)));
 | |
|       } else {
 | |
|         split_expr(expr->get_param_expr(1), exprs);
 | |
|       }
 | |
|     } else {
 | |
|       OK(exprs.push_back(expr));
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   void resolve_expr(const char* expr_str, ObRawExpr*& expr, ColumnIArray& ob_range_columns, ParamStore& params)
 | |
|   {
 | |
|     resolve_expr(expr_str, expr, ob_range_columns, params, CS_TYPE_UTF8MB4_GENERAL_CI, CS_TYPE_UTF8MB4_GENERAL_CI);
 | |
|   }
 | |
| 
 | |
|   void resolve_expr(const char* expr_str, ObRawExpr*& expr, ColumnIArray& ob_range_columns, ParamStore& params,
 | |
|       ObCollationType con_type, ObCollationType col_type, const int64_t max_cols_num = 100)
 | |
|   {
 | |
|     ObArray<ObQualifiedName> columns;
 | |
|     ObArray<ObVarInfo> sys_vars;
 | |
|     ObArray<ObSubQueryInfo> sub_query_info;
 | |
|     ObArray<ObAggFunRawExpr*> aggr_exprs;
 | |
|     ObArray<ObWinFunRawExpr*> win_exprs;
 | |
|     ObTimeZoneInfo tz_info;
 | |
|     ObArray<ColumnItem> tmp_range_columns;
 | |
|     ObNameCaseMode case_mode = OB_NAME_CASE_INVALID;
 | |
|     ObExprResolveContext ctx(expr_factory_, &tz_info, case_mode);
 | |
|     ctx.dest_collation_ = con_type;
 | |
|     ctx.param_list_ = ¶ms;
 | |
|     ObSQLSessionInfo session;
 | |
|     session.set_use_static_typing_engine(false);
 | |
|     ctx.session_info_ = &session;
 | |
| 
 | |
|     for (int64_t i = 0; i < more_range_columns_.count(); ++i) {
 | |
|       OK(tmp_range_columns.push_back(more_range_columns_.at(i)));
 | |
|     }
 | |
|     OK(ObRawExprUtils::make_raw_expr_from_str(
 | |
|         expr_str, strlen(expr_str), ctx, expr, columns, sys_vars, &sub_query_info, aggr_exprs, win_exprs));
 | |
|     bool init_flag[10] = {false};
 | |
|     for (int64_t i = 0; i < columns.count(); ++i) {
 | |
|       ObQualifiedName& col = columns.at(i);
 | |
|       for (int64_t j = 0; j < more_range_columns_.count(); ++j) {
 | |
|         if (col.col_name_ == more_range_columns_.at(j).column_name_) {
 | |
|           ObColumnRefRawExpr* b_expr = static_cast<ObColumnRefRawExpr*>(col.ref_expr_);
 | |
|           ASSERT_FALSE(NULL == b_expr);
 | |
|           (*b_expr).assign(*(more_range_columns_.at(j).expr_));
 | |
|           if (ob_is_string_type(b_expr->get_data_type())) {
 | |
|             b_expr->set_collation_type(col_type);
 | |
|           } else if (ob_is_float_tc(b_expr->get_data_type())) {
 | |
|             b_expr->set_precision(10);
 | |
|             b_expr->set_scale(5);
 | |
|           }
 | |
|           if (!init_flag[j]) {
 | |
|             init_flag[j] = true;
 | |
|             tmp_range_columns.at(j).table_id_ = b_expr->get_table_id();
 | |
|             tmp_range_columns.at(j).column_id_ = b_expr->get_column_id();
 | |
|             tmp_range_columns.at(j).expr_ = b_expr;
 | |
|             tmp_range_columns.at(j).column_name_ = b_expr->get_column_name();
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     for (int64_t i = 0; i < tmp_range_columns.count() && ob_range_columns.count() < max_cols_num; ++i) {
 | |
|       if (init_flag[i]) {
 | |
|         OK(ob_range_columns.push_back(tmp_range_columns.at(i)));
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     if (100 != max_cols_num && ob_range_columns.count() < max_cols_num) {
 | |
|       for (int64_t i = 0; i < max_cols_num - ob_range_columns.count(); ++i) {
 | |
|         ColumnItem extra_item = ob_range_columns.at(ob_range_columns.count() - 1);
 | |
|         extra_item.column_id_ = extra_item.column_id_ + 1;
 | |
|         OK(ob_range_columns.push_back(extra_item));
 | |
|       }
 | |
|     }
 | |
|     OK(expr->extract_info());
 | |
|     OK(expr->deduce_type(&session));
 | |
|   }
 | |
|   void split_and_condition(ObRawExpr* expr, ObIArray<ObRawExpr*>& and_exprs)
 | |
|   {
 | |
|     OB_ASSERT(expr);
 | |
|     if (expr->get_expr_type() == T_OP_AND) {
 | |
|       ObOpRawExpr* and_expr = static_cast<ObOpRawExpr*>(expr);
 | |
|       for (int64_t i = 0; i < and_expr->get_param_count(); ++i) {
 | |
|         ObRawExpr* sub_expr = and_expr->get_param_expr(i);
 | |
|         OB_ASSERT(sub_expr);
 | |
|         split_and_condition(sub_expr, and_exprs);
 | |
|       }
 | |
|     } else {
 | |
|       OK(and_exprs.push_back(expr));
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   void except_result(const ColumnIArray& range_columns, ParamsIArray& params, const char* condition,
 | |
|       const char* except_range, ObGetMethodArray& except_get_methods)
 | |
|   {
 | |
|     ObQueryRangeArray ranges;
 | |
|     ObGetMethodArray get_methods;
 | |
|     ObQueryRange enc_query_range;
 | |
|     ObQueryRange dec_query_range1;
 | |
|     ObQueryRange dec_query_range2;
 | |
|     ObQueryRange multi_query_range;
 | |
|     ObArenaAllocator allocator(ObModIds::TEST);
 | |
|     const ObDataTypeCastParams dtc_params;
 | |
|     ObRawExpr* expr = NULL;
 | |
|     char buf[512 * 1024] = {'\0'};
 | |
|     int64_t pos = 0;
 | |
|     int64_t data_len = 0;
 | |
|     resolve_condition(range_columns, condition, expr);
 | |
|     OK(enc_query_range.preliminary_extract_query_range(range_columns, expr, NULL));
 | |
|     OK(enc_query_range.serialize(buf, sizeof(buf), pos));
 | |
|     data_len = pos;
 | |
|     pos = 0;
 | |
|     OK(dec_query_range1.deserialize(buf, data_len, pos));
 | |
|     ASSERT_EQ(0, strcmp(to_cstring(enc_query_range), to_cstring(dec_query_range1)));
 | |
|     if (dec_query_range1.need_deep_copy()) {
 | |
|       OK(dec_query_range1.final_extract_query_range(params, NULL));
 | |
|       pos = 0;
 | |
|       OK(dec_query_range1.serialize(buf, sizeof(buf), pos));
 | |
|       data_len = pos;
 | |
|       pos = 0;
 | |
|       OK(dec_query_range2.deserialize(buf, data_len, pos));
 | |
|       ASSERT_EQ(0, strcmp(to_cstring(dec_query_range1), to_cstring(dec_query_range2)));
 | |
|       _OB_LOG(INFO, "serialize_size = %ld\n", dec_query_range1.get_serialize_size());
 | |
|       OK(dec_query_range1.get_tablet_ranges(ranges, get_methods, dtc_params));
 | |
|     } else {
 | |
|       OK(dec_query_range1.get_tablet_ranges(allocator, params, ranges, get_methods, NULL));
 | |
|     }
 | |
|     _OB_LOG(INFO, "ranges: %s, except_range: %s", to_cstring(ranges), except_range);
 | |
| 
 | |
|     ASSERT_EQ(0, strcmp(to_cstring(ranges), except_range));
 | |
|     ASSERT_EQ(get_methods.count(), except_get_methods.count());
 | |
|     for (int64_t j = 0; j < get_methods.count(); ++j) {
 | |
|       EXPECT_EQ(get_methods.at(j), except_get_methods.at(j));
 | |
|     }
 | |
| 
 | |
|     ranges.reset();
 | |
|     get_methods.reset();
 | |
|     OK(dec_query_range2.get_tablet_ranges(ranges, get_methods, dtc_params));
 | |
|     _OB_LOG(DEBUG, "ranges: %s, except_range: %s", to_cstring(ranges), except_range);
 | |
|     ASSERT_EQ(0, strcmp(to_cstring(ranges), except_range));
 | |
|     ASSERT_EQ(get_methods.count(), except_get_methods.count());
 | |
|     for (int64_t j = 0; j < get_methods.count(); ++j) {
 | |
|       EXPECT_EQ(get_methods.at(j), except_get_methods.at(j));
 | |
|     }
 | |
| 
 | |
|     ranges.reset();
 | |
|     get_methods.reset();
 | |
|     ObArray<ObRawExpr*> and_exprs;
 | |
|     split_and_condition(expr, and_exprs);
 | |
|     //    OK(multi_query_range.preliminary_extract_query_range(range_columns, and_exprs, NULL));
 | |
|     //    OK(multi_query_range.final_extract_query_range(params, NULL));
 | |
|     OK(multi_query_range.preliminary_extract_query_range(range_columns, and_exprs, dtc_params));
 | |
|     OK(multi_query_range.final_extract_query_range(params, dtc_params));
 | |
|     OK(multi_query_range.get_tablet_ranges(ranges, get_methods, dtc_params));
 | |
|     _OB_LOG(DEBUG,
 | |
|         "and_exprs_count: %ld, ranges: %s, except_range: %s",
 | |
|         and_exprs.count(),
 | |
|         to_cstring(ranges),
 | |
|         except_range);
 | |
|     ASSERT_EQ(0, strcmp(to_cstring(ranges), except_range));
 | |
|   }
 | |
| 
 | |
|   void reset()
 | |
|   {
 | |
|     allocator_.reset();
 | |
|   }
 | |
| 
 | |
| private:
 | |
|   // disallow copy
 | |
|   ObQueryRangeTest(const ObQueryRangeTest& other);
 | |
|   ObQueryRangeTest& operator=(const ObQueryRangeTest& other);
 | |
| 
 | |
| protected:
 | |
|   // data members
 | |
|   uint64_t table_id_;
 | |
|   uint64_t column_id1_;
 | |
|   uint64_t column_id2_;
 | |
|   uint64_t column_id3_;
 | |
|   ObArenaAllocator allocator_;
 | |
|   ObRawExprFactory expr_factory_;
 | |
|   ParamStore params_;
 | |
|   ObArray<ColumnItem> single_range_columns_;
 | |
|   ObArray<ColumnItem> double_range_columns_;
 | |
|   ObArray<ColumnItem> triple_range_columns_;
 | |
|   ObArray<ColumnItem> more_range_columns_;
 | |
|   ObArray<ColumnItem> extra_range_columns_;
 | |
|   ObColumnRefRawExpr ref_col_;  // a
 | |
|   ObQueryRange query_range;
 | |
|   void get_query_range(const char* expr, const char*& json_expr);
 | |
|   void get_query_range_filter(
 | |
|       const char* sql_expr, const char*& json_expr, char* buf, int64_t& pos, const int64_t cols_num);
 | |
|   void get_query_range_collation(const char* expr, const char*& json_expr, char* buf, int64_t& pos);
 | |
| };
 | |
| 
 | |
| ObQueryRangeTest::ObQueryRangeTest()
 | |
|     : table_id_(3003),
 | |
|       column_id1_(16),
 | |
|       column_id2_(17),
 | |
|       column_id3_(18),
 | |
|       allocator_(ObModIds::TEST),
 | |
|       expr_factory_(allocator_),
 | |
|       params_((ObWrapperAllocator(CURRENT_CONTEXT.get_arena_allocator()))),
 | |
|       ref_col_(table_id_, column_id1_, T_REF_COLUMN)
 | |
| {}
 | |
| 
 | |
| ObQueryRangeTest::~ObQueryRangeTest()
 | |
| {}
 | |
| 
 | |
| const char* get_columns_char(int64_t i)
 | |
| {
 | |
|   const char* ptr = NULL;
 | |
|   switch (i) {
 | |
|     case 0:
 | |
|       ptr = "a";
 | |
|       break;
 | |
|     case 1:
 | |
|       ptr = "b";
 | |
|       break;
 | |
|     case 2:
 | |
|       ptr = "c";
 | |
|       break;
 | |
|     case 3:
 | |
|       ptr = "d";
 | |
|       break;
 | |
|     case 4:
 | |
|       ptr = "e";
 | |
|       break;
 | |
|     case 5:
 | |
|       ptr = "f";
 | |
|       break;
 | |
|     case 6:
 | |
|       ptr = "g";
 | |
|       break;
 | |
|     case 7:
 | |
|       ptr = "h";
 | |
|       break;
 | |
|     case 8:
 | |
|       ptr = "i";
 | |
|       break;
 | |
|     case 9:
 | |
|       ptr = "j";
 | |
|       break;
 | |
|     case 10:
 | |
|       ptr = "k";
 | |
|       break;
 | |
|     case 11:
 | |
|       ptr = "l";
 | |
|       break;
 | |
|     case 12:
 | |
|       ptr = "m";
 | |
|       break;
 | |
|     case 13:
 | |
|       ptr = "n";
 | |
|       break;
 | |
|     case 14:
 | |
|       ptr = "o";
 | |
|       break;
 | |
|   }
 | |
|   return ptr;
 | |
| }
 | |
| 
 | |
| int ObQueryRangeTest::set_column_info(
 | |
|     ColumnItem& column_item, ObObjType data_type, const char* column_name, int64_t pos)
 | |
| {
 | |
|   int ret = OB_SUCCESS;
 | |
|   ObColumnRefRawExpr* col_expr = NULL;
 | |
|   if (OB_FAIL(expr_factory_.create_raw_expr(T_REF_COLUMN, col_expr))) {
 | |
|     SQL_REWRITE_LOG(WARN, "create raw expr failed", K(ret));
 | |
|   } else {
 | |
|     col_expr->add_flag(IS_COLUMN);
 | |
|     col_expr->set_data_type(data_type);
 | |
|     col_expr->set_ref_id(table_id_, column_id1_ + pos);
 | |
|     col_expr->get_column_name() = ObString::make_string(column_name);
 | |
|     if (ob_is_string_type(data_type)) {
 | |
|       ObAccuracy accuracy;
 | |
|       accuracy.set_length(512);
 | |
|       col_expr->set_accuracy(accuracy);
 | |
|       col_expr->set_collation_type(CS_TYPE_UTF8MB4_BIN);
 | |
|     } else {
 | |
|       col_expr->set_collation_type(CS_TYPE_BINARY);
 | |
|     }
 | |
|     column_item.table_id_ = col_expr->get_table_id();
 | |
|     column_item.column_id_ = col_expr->get_column_id();
 | |
|     column_item.expr_ = col_expr;
 | |
|     column_item.column_name_ = col_expr->get_column_name();
 | |
|   }
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| void ObQueryRangeTest::SetUp()
 | |
| {
 | |
|   ColumnItem col;
 | |
|   OK(set_column_info(col, ObIntType, "a", 0));
 | |
|   OK(single_range_columns_.push_back(col));
 | |
|   OK(set_column_info(col, ObIntType, "a", 0));
 | |
|   OK(double_range_columns_.push_back(col));
 | |
|   OK(set_column_info(col, ObIntType, "b", 1));
 | |
|   OK(double_range_columns_.push_back(col));
 | |
|   OK(set_column_info(col, ObIntType, "a", 0));
 | |
|   OK(triple_range_columns_.push_back(col));
 | |
|   OK(set_column_info(col, ObIntType, "b", 1));
 | |
|   OK(triple_range_columns_.push_back(col));
 | |
|   OK(set_column_info(col, ObIntType, "c", 2));
 | |
|   OK(triple_range_columns_.push_back(col));
 | |
| 
 | |
|   ref_col_.add_flag(IS_COLUMN);
 | |
|   for (int64_t i = 0; i < 14; i++) {
 | |
|     if (i < 3) {  // column('a'-'e') is IntType. column('f'-'j') is VarcharType. other type is dealed specially
 | |
|       OK(set_column_info(col, ObIntType, get_columns_char(i), i));
 | |
|     } else if (i == 3) {
 | |
|       OK(set_column_info(col, ObFloatType, get_columns_char(i), i));
 | |
|     } else if (i == 4) {
 | |
|       OK(set_column_info(col, ObUInt64Type, get_columns_char(i), i));
 | |
|     } else {
 | |
|       OK(set_column_info(col, ObVarcharType, get_columns_char(i), i));
 | |
|     }
 | |
|     if (i < 10) {
 | |
|       OK(more_range_columns_.push_back(col));
 | |
|     } else {
 | |
|       OK(extra_range_columns_.push_back(col));
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| void ObQueryRangeTest::TearDown()
 | |
| {}
 | |
| /*
 | |
|  * get final_sql and params from case file : such as (a, b, c) < (?1, ?2, ?3) and (a, b, c) > (?0, ?2, ?3) ->
 | |
|  * final_sql:(a, b, c) > (?, ? ,?)   params : 0,2,3
 | |
|  */
 | |
| void get_final_sql(const char* sql_expr, char* final_sql, ParamStore& params, char (*var)[100])
 | |
| {
 | |
|   memset(var, 0, sizeof(*var));
 | |
|   int64_t val = 0;
 | |
|   int64_t j = 0;
 | |
|   double fval = 0.0;  // test cast
 | |
| 
 | |
|   bool num_flag = false;
 | |
|   bool var_flag = false;
 | |
|   bool is_minus = false;
 | |
|   bool is_float = false;
 | |
|   int len = 0;
 | |
|   int cnt = 0;
 | |
|   int y = 10;
 | |
|   for (int64_t i = 0; i < (int64_t)strlen(sql_expr); ++i) {
 | |
|     if (num_flag) {
 | |
|       if (sql_expr[i] == '}') {
 | |
|         ObObjParam obj;
 | |
|         val = is_minus ? -val : val;
 | |
|         if (is_float) {
 | |
|           is_float = false;
 | |
|           fval = is_minus ? -fval : fval;
 | |
|           fval += static_cast<double>(val);
 | |
|           obj.set_double(fval);
 | |
|         } else {
 | |
|           obj.set_int(val);
 | |
|         }
 | |
|         obj.set_param_meta();
 | |
|         params.push_back(obj);
 | |
|         num_flag = false;
 | |
|         val = 0;
 | |
|       } else if (is_float) {
 | |
|         fval = fval + (sql_expr[i] - '0') * 1.0 / y;
 | |
|         y *= 10;
 | |
|       } else if (sql_expr[i] >= '0' && sql_expr[i] <= '9') {
 | |
|         val = val * 10 + sql_expr[i] - '0';
 | |
|       } else if (sql_expr[i] == '-') {
 | |
|         is_minus = true;
 | |
|       } else if (sql_expr[i] == '.') {
 | |
|         fval = 0.0;
 | |
|         is_float = true;
 | |
|         y = 10;
 | |
|       }
 | |
|     } else if (var_flag) {
 | |
|       if (sql_expr[i] == ']') {
 | |
|         ObObjParam obj;
 | |
|         var[cnt][len] = '\0';
 | |
|         if (0 == strcasecmp(var[cnt], "NULL")) {
 | |
|           obj.set_null();
 | |
|         } else {
 | |
|           obj.set_varchar(var[cnt]);
 | |
|         }
 | |
|         obj.set_collation_level(CS_LEVEL_COERCIBLE);
 | |
|         obj.set_collation_type(CS_TYPE_UTF8MB4_GENERAL_CI);
 | |
|         obj.set_param_meta();
 | |
|         params.push_back(obj);
 | |
|         var_flag = false;
 | |
|         len = 0;
 | |
|         cnt++;
 | |
|       } else {
 | |
|         var[cnt][len++] = sql_expr[i];
 | |
|       }
 | |
|     } else {
 | |
|       if (sql_expr[i] == '{') {
 | |
|         num_flag = true;
 | |
|       } else if (sql_expr[i] == '[') {
 | |
|         var_flag = true;
 | |
|       }
 | |
|     }
 | |
|     if (sql_expr[i] != '{' && sql_expr[i] != '}' && sql_expr[i] != '[' && sql_expr[i] != ']' && !num_flag &&
 | |
|         !var_flag) {
 | |
|       final_sql[j++] = sql_expr[i];
 | |
|     }
 | |
|   }
 | |
|   final_sql[j] = '\0';
 | |
| }
 | |
| 
 | |
| void ObQueryRangeTest::get_query_range(const char* sql_expr, const char*& json_expr)
 | |
| {
 | |
|   char var[100][100];
 | |
|   ObQueryRangeArray ranges;
 | |
|   ObGetMethodArray get_methods;
 | |
|   ObRawExpr* expr = NULL;
 | |
|   ObArray<ColumnItem> range_columns;
 | |
|   ParamStore params((ObWrapperAllocator(CURRENT_CONTEXT.get_arena_allocator())));
 | |
|   ObArenaAllocator allocator(ObModIds::TEST);
 | |
|   const ObDataTypeCastParams dtc_params;
 | |
|   ObQueryRange pre_query_range;
 | |
|   char final_sql[100];
 | |
|   get_final_sql(sql_expr, final_sql, params, var);
 | |
|   resolve_expr(final_sql, expr, range_columns, params, CS_TYPE_UTF8MB4_GENERAL_CI, CS_TYPE_UTF8MB4_GENERAL_CI);
 | |
|   OB_ASSERT(expr);
 | |
|   //_OB_LOG(INFO,"-----%s\n", final_sql);
 | |
|   //_OB_LOG(WARN, "expr: %s", CSJ(expr));
 | |
|   query_range.reset();
 | |
|   OB_LOG(INFO, "get query range sql", K(final_sql));
 | |
|   OK(pre_query_range.preliminary_extract_query_range(range_columns, expr, dtc_params));
 | |
|   char* ser_buf = NULL;
 | |
|   int64_t ser_len = pre_query_range.get_serialize_size();
 | |
|   int64_t pos = 0;
 | |
|   ASSERT_FALSE(NULL == (ser_buf = (char*)allocator.alloc(ser_len)));
 | |
|   OK(pre_query_range.serialize(ser_buf, ser_len, pos));
 | |
|   ASSERT_EQ(ser_len, pos);
 | |
|   pos = 0;
 | |
|   OK(query_range.deserialize(ser_buf, ser_len, pos));
 | |
|   ASSERT_EQ(0, strcmp(to_cstring(pre_query_range), to_cstring(query_range)));
 | |
|   if (query_range.need_deep_copy()) {
 | |
|     query_range.final_extract_query_range(params, NULL);
 | |
|     OK(query_range.get_tablet_ranges(ranges, get_methods, dtc_params));
 | |
|   } else {
 | |
|     OK(query_range.get_tablet_ranges(allocator, params, ranges, get_methods, NULL));
 | |
|   }
 | |
| 
 | |
|   char buf[BUF_LEN];
 | |
|   pos = 0;
 | |
|   bool flag = false;
 | |
|   if (!query_range.need_deep_copy()) {
 | |
|     databuff_printf(buf, BUF_LEN, pos, "query range not need to deep copy\n");
 | |
|     query_range.final_extract_query_range(params, NULL);
 | |
|   } else {
 | |
|     databuff_printf(buf, BUF_LEN, pos, "query range need to deep copy\n");
 | |
|   }
 | |
|   OK(query_range.is_min_to_max_range(flag, NULL));
 | |
|   if (flag) {
 | |
|     databuff_printf(buf, BUF_LEN, pos, "is min_to_max_range\n");
 | |
|   } else {
 | |
|     databuff_printf(buf, BUF_LEN, pos, "is not min_to_max_range\n");
 | |
|   }
 | |
|   databuff_printf(buf, BUF_LEN, pos, "ranges.count() = %ld\n", ranges.count());
 | |
|   databuff_printf(buf, BUF_LEN, pos, "get_methods.count() = %ld\n", get_methods.count());
 | |
|   for (int64_t i = 0; i < get_methods.count(); ++i) {
 | |
|     databuff_printf(buf, BUF_LEN, pos, "get_methods %ld: %d\n", i, get_methods.at(i));
 | |
|   }
 | |
|   for (int64_t i = 0; i < ranges.count(); ++i) {
 | |
|     databuff_printf(buf, BUF_LEN, pos, "star_border_flag[%ld] = %d\n", i, ranges.at(i)->border_flag_.inclusive_start());
 | |
|     databuff_printf(buf, BUF_LEN, pos, "end_border_flag[%ld] = %d\n", i, ranges.at(i)->border_flag_.inclusive_end());
 | |
|   }
 | |
|   databuff_printf(buf, BUF_LEN, pos, "count of rang columns = %ld\n", range_columns.count());
 | |
|   databuff_printf(buf, BUF_LEN, pos, to_cstring(ranges));
 | |
|   databuff_printf(buf, BUF_LEN, pos, "\n");
 | |
|   json_expr = buf;
 | |
|   OK(query_range.get_tablet_ranges(allocator_, params, ranges, flag, NULL));
 | |
|   query_range.reset();
 | |
| }
 | |
| 
 | |
| void ObQueryRangeTest::get_query_range_filter(
 | |
|     const char* sql_expr, const char*& json_expr, char* buf, int64_t& pos, const int64_t cols_num)
 | |
| {
 | |
|   char var[100][100];
 | |
|   ObQueryRangeArray ranges;
 | |
|   ObGetMethodArray get_methods;
 | |
|   ObRawExpr* expr = NULL;
 | |
|   ObArray<ColumnItem> range_columns;
 | |
|   ParamStore params((ObWrapperAllocator(CURRENT_CONTEXT.get_arena_allocator())));
 | |
|   ObArenaAllocator allocator(ObModIds::TEST);
 | |
|   const ObDataTypeCastParams dtc_params;
 | |
|   ObQueryRange pre_query_range;
 | |
|   char final_sql[100];
 | |
|   get_final_sql(sql_expr, final_sql, params, var);
 | |
|   resolve_expr(
 | |
|       final_sql, expr, range_columns, params, CS_TYPE_UTF8MB4_GENERAL_CI, CS_TYPE_UTF8MB4_GENERAL_CI, cols_num);
 | |
|   ObSEArray<ObRawExpr*, 16> exprs;
 | |
|   split_expr(expr, exprs);
 | |
|   OB_ASSERT(expr);
 | |
|   query_range.reset();
 | |
|   OB_LOG(INFO, "get query range sql", K(final_sql));
 | |
|   OK(query_range.preliminary_extract_query_range(range_columns, exprs, dtc_params));
 | |
|   databuff_printf(buf, BUF_LEN, pos, "\n**rowkey num = %ld**  \n", cols_num);
 | |
|   databuff_printf(buf, BUF_LEN, pos, "**filter count = %ld**\n", query_range.get_range_exprs().count());
 | |
| 
 | |
|   bool flag = false;
 | |
|   if (query_range.need_deep_copy()) {
 | |
|     query_range.final_extract_query_range(params, NULL);
 | |
|     OK(query_range.get_tablet_ranges(ranges, get_methods, dtc_params));
 | |
|   } else {
 | |
|     OK(query_range.get_tablet_ranges(allocator, params, ranges, get_methods, NULL));
 | |
|   }
 | |
| 
 | |
|   OK(query_range.is_min_to_max_range(flag, NULL));
 | |
|   if (flag) {
 | |
|     databuff_printf(buf, BUF_LEN, pos, "is min_to_max_range\n");
 | |
|   } else {
 | |
|     databuff_printf(buf, BUF_LEN, pos, "is not min_to_max_range\n");
 | |
|   }
 | |
|   databuff_printf(buf, BUF_LEN, pos, "ranges.count() = %ld\n", ranges.count());
 | |
|   databuff_printf(buf, BUF_LEN, pos, "get_methods.count() = %ld\n", get_methods.count());
 | |
|   for (int64_t i = 0; i < get_methods.count(); ++i) {
 | |
|     databuff_printf(buf, BUF_LEN, pos, "get_methods %ld: %d\n", i, get_methods.at(i));
 | |
|   }
 | |
|   for (int64_t i = 0; i < ranges.count(); ++i) {
 | |
|     databuff_printf(buf, BUF_LEN, pos, "star_border_flag[%ld] = %d\n", i, ranges.at(i)->border_flag_.inclusive_start());
 | |
|     databuff_printf(buf, BUF_LEN, pos, "end_border_flag[%ld] = %d\n", i, ranges.at(i)->border_flag_.inclusive_end());
 | |
|   }
 | |
|   databuff_printf(buf, BUF_LEN, pos, "count of rang columns = %ld\n", range_columns.count());
 | |
|   databuff_printf(buf, BUF_LEN, pos, to_cstring(ranges));
 | |
|   databuff_printf(buf, BUF_LEN, pos, "\n");
 | |
|   json_expr = buf;
 | |
|   OK(query_range.get_tablet_ranges(allocator_, params, ranges, flag, NULL));
 | |
|   query_range.reset();
 | |
| }
 | |
| 
 | |
| void ObQueryRangeTest::get_query_range_collation(const char* sql_expr, const char*& json_expr, char* buf, int64_t& pos)
 | |
| {
 | |
|   char var[100][100];
 | |
|   ObQueryRangeArray ranges;
 | |
|   ObGetMethodArray get_methods;
 | |
|   ParamStore params((ObWrapperAllocator(CURRENT_CONTEXT.get_arena_allocator())));
 | |
|   const ObDataTypeCastParams dtc_params;
 | |
|   char final_sql[100];
 | |
|   get_final_sql(sql_expr, final_sql, params, var);
 | |
|   ObCollationType cs_type[3] = {CS_TYPE_UTF8MB4_GENERAL_CI, CS_TYPE_UTF8MB4_BIN, CS_TYPE_BINARY};
 | |
|   for (int i = 0; i < 3; i++) {
 | |
|     for (int j = 0; j < 3; j++) {
 | |
|       ObArray<ColumnItem> range_columns;
 | |
|       ObRawExpr* expr = NULL;
 | |
|       ObCollationType conn_type = cs_type[i];
 | |
|       ObCollationType col_type = cs_type[j];
 | |
|       resolve_expr(final_sql, expr, range_columns, params, conn_type, col_type);
 | |
|       // conn_type: connection_collation-->collation type of the params
 | |
|       // col_type : the collation type of columns
 | |
|       // each result_type of expr is deduced by param_obj_type and column_type
 | |
|       databuff_printf(buf,
 | |
|           BUF_LEN,
 | |
|           pos,
 | |
|           "%s--------------connection_collation = %d col_type = %d\n",
 | |
|           sql_expr,
 | |
|           conn_type,
 | |
|           col_type);
 | |
|       OB_ASSERT(expr);
 | |
|       OK(query_range.preliminary_extract_query_range(range_columns, expr, dtc_params));
 | |
|       OK(query_range.final_extract_query_range(params, NULL));
 | |
|       OK(query_range.get_tablet_ranges(ranges, get_methods, dtc_params));
 | |
|       bool flag = false;
 | |
|       OK(query_range.is_min_to_max_range(flag, NULL));
 | |
|       if (flag) {
 | |
|         databuff_printf(buf, BUF_LEN, pos, "is min_to_max_range\n");
 | |
|       } else {
 | |
|         databuff_printf(buf, BUF_LEN, pos, "is not min_to_max_range\n");
 | |
|       }
 | |
|       databuff_printf(buf, BUF_LEN, pos, "ranges.count() = %ld\n", ranges.count());
 | |
|       databuff_printf(buf, BUF_LEN, pos, "get_methods.count() = %ld\n", get_methods.count());
 | |
|       for (int64_t i = 0; i < get_methods.count(); ++i) {
 | |
|         databuff_printf(buf, BUF_LEN, pos, "get_methods %ld: %d\n", i, get_methods.at(i));
 | |
|       }
 | |
|       for (int64_t i = 0; i < ranges.count(); ++i) {
 | |
|         databuff_printf(
 | |
|             buf, BUF_LEN, pos, "star_border_flag[%ld] = %d\n", i, ranges.at(i)->border_flag_.inclusive_start());
 | |
|         databuff_printf(
 | |
|             buf, BUF_LEN, pos, "end_border_flag[%ld] = %d\n", i, ranges.at(i)->border_flag_.inclusive_end());
 | |
|       }
 | |
|       databuff_printf(buf, BUF_LEN, pos, "count of rang columns = %ld\n", range_columns.count());
 | |
|       databuff_printf(buf, BUF_LEN, pos, to_cstring(ranges));
 | |
|       databuff_printf(buf, BUF_LEN, pos, "\n");
 | |
|       json_expr = buf;
 | |
| 
 | |
|       OK(query_range.get_tablet_ranges(allocator_, params, ranges, flag, NULL));
 | |
|       query_range.reset();
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * there set 10 columns a-j. if need more, please modify SetUp()
 | |
|  * in case file, only support integer, if have '?', integer must be placed in the back of '?'
 | |
|  * such as  (a, b, c) < (?1, ?2, ?3)
 | |
|  */
 | |
| TEST_F(ObQueryRangeTest, query_test)
 | |
| {
 | |
|   static const char* test_file = "./test_query_range.test";
 | |
|   static const char* tmp_file = "./test_query_range.tmp";
 | |
|   static const char* result_file = "./test_query_range.result";
 | |
| 
 | |
|   std::ifstream if_tests(test_file);
 | |
|   ASSERT_TRUE(if_tests.is_open());
 | |
|   std::string line;
 | |
|   const char* json_expr = NULL;
 | |
|   std::ofstream of_result(tmp_file);
 | |
|   ASSERT_TRUE(of_result.is_open());
 | |
|   int64_t case_id = 0;
 | |
|   while (std::getline(if_tests, line)) {
 | |
|     of_result << '[' << case_id++ << "] " << line << std::endl;
 | |
|     const char* line_ptr = line.c_str();
 | |
|     while (*line_ptr == ' ' && *line_ptr != '\0') {
 | |
|       ++line_ptr;
 | |
|     }
 | |
|     if (*line_ptr != '\0' && *line_ptr == '#') {
 | |
|       continue;
 | |
|     }
 | |
|     get_query_range(line_ptr, json_expr);
 | |
|     of_result << json_expr << std::endl;
 | |
|   }
 | |
|   of_result.close();
 | |
|   // verify results
 | |
|   fprintf(stderr, "If tests failed, use `diff %s %s' to see the differences. \n", result_file, tmp_file);
 | |
|   std::ifstream if_result(tmp_file);
 | |
|   ASSERT_TRUE(if_result.is_open());
 | |
|   std::istream_iterator<std::string> it_result(if_result);
 | |
|   std::ifstream if_expected(result_file);
 | |
|   ASSERT_TRUE(if_expected.is_open());
 | |
|   std::istream_iterator<std::string> it_expected(if_expected);
 | |
|   ASSERT_TRUE(std::equal(it_result, std::istream_iterator<std::string>(), it_expected));
 | |
|   std::remove(tmp_file);
 | |
| }
 | |
| 
 | |
| TEST_F(ObQueryRangeTest, collation_test)
 | |
| {
 | |
|   static const char* test_file = "./test_query_range_collation.test";
 | |
|   static const char* tmp_file = "./test_query_range_collation.tmp";
 | |
|   static const char* result_file = "./test_query_range_collation.result";
 | |
| 
 | |
|   std::ifstream if_tests(test_file);
 | |
|   ASSERT_TRUE(if_tests.is_open());
 | |
|   std::string line;
 | |
|   const char* json_expr = NULL;
 | |
|   std::ofstream of_result(tmp_file);
 | |
|   ASSERT_TRUE(of_result.is_open());
 | |
|   int64_t case_id = 0;
 | |
|   while (std::getline(if_tests, line)) {
 | |
|     of_result << '[' << case_id++ << "] " << line << std::endl;
 | |
|     const char* line_ptr = line.c_str();
 | |
|     while (*line_ptr == ' ' && *line_ptr != '\0') {
 | |
|       ++line_ptr;
 | |
|     }
 | |
|     if (*line_ptr != '\0' && *line_ptr == '#') {
 | |
|       continue;
 | |
|     }
 | |
|     char buf[BUF_LEN];
 | |
|     int64_t pos = 0;
 | |
|     get_query_range_collation(line_ptr, json_expr, buf, pos);
 | |
|     of_result << json_expr << std::endl;
 | |
|   }
 | |
|   of_result.close();
 | |
|   // verify results
 | |
|   fprintf(stderr, "If tests failed, use `diff %s %s' to see the differences. \n", result_file, tmp_file);
 | |
|   std::ifstream if_result(tmp_file);
 | |
|   ASSERT_TRUE(if_result.is_open());
 | |
|   std::istream_iterator<std::string> it_result(if_result);
 | |
|   std::ifstream if_expected(result_file);
 | |
|   ASSERT_TRUE(if_expected.is_open());
 | |
|   std::istream_iterator<std::string> it_expected(if_expected);
 | |
|   ASSERT_TRUE(std::equal(it_result, std::istream_iterator<std::string>(), it_expected));
 | |
|   std::remove(tmp_file);
 | |
| }
 | |
| 
 | |
| TEST_F(ObQueryRangeTest, filter_test)
 | |
| {
 | |
|   static const char* test_file = "./test_query_range_filter.test";
 | |
|   static const char* tmp_file = "./test_query_range_filter.tmp";
 | |
|   static const char* result_file = "./test_query_range_filter.result";
 | |
| 
 | |
|   std::ifstream if_tests(test_file);
 | |
|   ASSERT_TRUE(if_tests.is_open());
 | |
|   std::string line;
 | |
|   const char* json_expr = NULL;
 | |
|   std::ofstream of_result(tmp_file);
 | |
|   ASSERT_TRUE(of_result.is_open());
 | |
|   int64_t case_id = 0;
 | |
|   while (std::getline(if_tests, line)) {
 | |
|     const char* line_ptr = line.c_str();
 | |
|     if (*line_ptr != '\0' && *line_ptr == '#') {
 | |
|       continue;
 | |
|     }
 | |
|     of_result << '[' << case_id++ << "] " << line << std::endl;
 | |
|     while (*line_ptr == ' ' && *line_ptr != '\0') {
 | |
|       ++line_ptr;
 | |
|     }
 | |
|     char buf[BUF_LEN];
 | |
|     int64_t pos = 0;
 | |
|     get_query_range_filter(line_ptr, json_expr, buf, pos, 1);
 | |
|     get_query_range_filter(line_ptr, json_expr, buf, pos, 2);
 | |
|     get_query_range_filter(line_ptr, json_expr, buf, pos, 3);
 | |
|     of_result << json_expr << std::endl;
 | |
|   }
 | |
|   of_result.close();
 | |
|   // verify results
 | |
|   fprintf(stderr, "If tests failed, use `diff %s %s' to see the differences. \n", result_file, tmp_file);
 | |
|   std::ifstream if_result(tmp_file);
 | |
|   ASSERT_TRUE(if_result.is_open());
 | |
|   std::istream_iterator<std::string> it_result(if_result);
 | |
|   std::ifstream if_expected(result_file);
 | |
|   ASSERT_TRUE(if_expected.is_open());
 | |
|   std::istream_iterator<std::string> it_expected(if_expected);
 | |
|   ASSERT_TRUE(std::equal(it_result, std::istream_iterator<std::string>(), it_expected));
 | |
|   std::remove(tmp_file);
 | |
| }
 | |
| 
 | |
| TEST_F(ObQueryRangeTest, test_collation_type)
 | |
| {
 | |
|   _OB_LOG(INFO, "test collation type");
 | |
|   ObQueryRangeArray ranges;
 | |
|   ObGetMethodArray get_methods;
 | |
|   ObQueryRange query_range;
 | |
| 
 | |
|   params_.reset();
 | |
|   for (int i = CS_TYPE_UTF8MB4_GENERAL_CI; i < CS_TYPE_MAX; i++) {}
 | |
| }
 | |
| TEST_F(ObQueryRangeTest, single_filed_key_whole_range1)
 | |
| {
 | |
|   _OB_LOG(INFO, "single filed key and NULL condition");
 | |
|   ObQueryRangeArray ranges;
 | |
|   ObGetMethodArray get_methods;
 | |
|   ObQueryRange query_range;
 | |
|   const ObDataTypeCastParams dtc_params;
 | |
| 
 | |
|   params_.reset();
 | |
|   OK(query_range.preliminary_extract_query_range(single_range_columns_, NULL, NULL));
 | |
|   OK(query_range.final_extract_query_range(params_, NULL));
 | |
|   OK(query_range.get_tablet_ranges(ranges, get_methods, dtc_params));
 | |
|   ASSERT_EQ(0, strcmp(to_cstring(ranges), "[{\"range\":\"table_id:3003,(MIN;MAX)\"}]"));
 | |
| }
 | |
| 
 | |
| TEST_F(ObQueryRangeTest, single_filed_key_whole_range2)
 | |
| {
 | |
|   _OB_LOG(INFO, "single filed key and empty condition array");
 | |
|   ObQueryRangeArray ranges;
 | |
|   ObGetMethodArray get_methods;
 | |
|   ObQueryRange query_range;
 | |
|   ObArray<ObRawExpr*> exprs;
 | |
|   const ObDataTypeCastParams dtc_params;
 | |
| 
 | |
|   params_.reset();
 | |
|   OK(query_range.preliminary_extract_query_range(single_range_columns_, exprs, dtc_params));
 | |
|   OK(query_range.final_extract_query_range(params_, dtc_params));
 | |
|   OK(query_range.get_tablet_ranges(ranges, get_methods, dtc_params));
 | |
|   ASSERT_EQ(0, strcmp(to_cstring(ranges), "[{\"range\":\"table_id:3003,(MIN;MAX)\"}]"));
 | |
| }
 | |
| 
 | |
| TEST_F(ObQueryRangeTest, double_filed_key_whole_range1)
 | |
| {
 | |
|   _OB_LOG(INFO, "double filed key and NULL condition");
 | |
|   ObQueryRangeArray ranges;
 | |
|   ObGetMethodArray get_methods;
 | |
|   ObQueryRange query_range;
 | |
|   const ObDataTypeCastParams dtc_params;
 | |
| 
 | |
|   params_.reset();
 | |
|   OK(query_range.preliminary_extract_query_range(double_range_columns_, NULL, dtc_params));
 | |
|   OK(query_range.final_extract_query_range(params_, dtc_params));
 | |
|   OK(query_range.get_tablet_ranges(ranges, get_methods, dtc_params));
 | |
|   ASSERT_EQ(0, strcmp(to_cstring(ranges), "[{\"range\":\"table_id:3003,(MIN,MIN;MAX,MAX)\"}]"));
 | |
| }
 | |
| 
 | |
| TEST_F(ObQueryRangeTest, double_filed_key_whole_range2)
 | |
| {
 | |
|   _OB_LOG(INFO, "double filed key and empty condition array");
 | |
|   ObQueryRangeArray ranges;
 | |
|   ObGetMethodArray get_methods;
 | |
|   ObQueryRange query_range;
 | |
|   ObArray<ObRawExpr*> exprs;
 | |
|   const ObDataTypeCastParams dtc_params;
 | |
| 
 | |
|   params_.reset();
 | |
|   OK(query_range.preliminary_extract_query_range(double_range_columns_, exprs, dtc_params));
 | |
|   OK(query_range.final_extract_query_range(params_, dtc_params));
 | |
|   OK(query_range.get_tablet_ranges(ranges, get_methods, dtc_params));
 | |
|   ASSERT_EQ(0, strcmp(to_cstring(ranges), "[{\"range\":\"table_id:3003,(MIN,MIN;MAX,MAX)\"}]"));
 | |
| }
 | |
| 
 | |
| TEST_F(ObQueryRangeTest, range_column_with_like)
 | |
| {
 | |
|   _OB_LOG(INFO, "f like 'abc%s'", "%");
 | |
|   ObArray<ColumnItem> single_range_columns;
 | |
|   ObQueryRangeArray ranges;
 | |
|   ObGetMethodArray get_methods;
 | |
|   ObQueryRange query_range;
 | |
|   ObRawExpr* expr = NULL;
 | |
|   const ObDataTypeCastParams dtc_params;
 | |
| 
 | |
|   params_.reset();
 | |
|   ASSERT_EQ(OB_INVALID_ARGUMENT, query_range.preliminary_extract_query_range(single_range_columns, expr, dtc_params));
 | |
|   resolve_expr(
 | |
|       "f like 'abc%'", expr, single_range_columns, params_, CS_TYPE_UTF8MB4_GENERAL_CI, CS_TYPE_UTF8MB4_GENERAL_CI);
 | |
|   OK(query_range.preliminary_extract_query_range(single_range_columns, expr, dtc_params));
 | |
|   OK(query_range.final_extract_query_range(params_, dtc_params));
 | |
|   OK(query_range.get_tablet_ranges(ranges, get_methods, dtc_params));
 | |
|   _OB_LOG(INFO, "range: %s", to_cstring(ranges));
 | |
| 
 | |
|   query_range.reset();
 | |
|   ObConstRawExpr* escape_expr = dynamic_cast<ObConstRawExpr*>(expr->get_param_expr(2));
 | |
|   ObObj escape_obj;
 | |
|   escape_obj.set_null();
 | |
|   escape_expr->set_value(escape_obj);
 | |
|   OK(query_range.preliminary_extract_query_range(single_range_columns, expr, dtc_params));
 | |
|   OK(query_range.final_extract_query_range(params_, dtc_params));
 | |
|   OK(query_range.get_tablet_ranges(ranges, get_methods, dtc_params));
 | |
|   _OB_LOG(INFO, "range: %s", to_cstring(ranges));
 | |
| 
 | |
|   query_range.reset();
 | |
|   resolve_condition(single_range_columns, "'a' like 'a'", expr);
 | |
|   OK(query_range.preliminary_extract_query_range(single_range_columns, expr, dtc_params));
 | |
|   OK(query_range.final_extract_query_range(params_, dtc_params));
 | |
|   OK(query_range.get_tablet_ranges(ranges, get_methods, dtc_params));
 | |
|   _OB_LOG(INFO, "range: %s", to_cstring(ranges));
 | |
| }
 | |
| 
 | |
| TEST_F(ObQueryRangeTest, range_column_with_like_prepare)
 | |
| {
 | |
|   _OB_LOG(INFO, "f like ?");
 | |
|   ObArray<ColumnItem> single_range_columns;
 | |
|   ObQueryRangeArray ranges;
 | |
|   ObGetMethodArray get_methods;
 | |
|   ObQueryRange query_range;
 | |
|   ObRawExpr* expr = NULL;
 | |
|   const ObDataTypeCastParams dtc_params;
 | |
|   params_.reset();
 | |
|   ObObjParam param;
 | |
|   param.set_collation_type(CS_TYPE_UTF8MB4_GENERAL_CI);
 | |
|   param.set_varchar("abc%", static_cast<int32_t>(strlen("abc%")));
 | |
|   param.set_param_meta();
 | |
|   OK(params_.push_back(param));
 | |
|   resolve_expr("a like ?", expr, single_range_columns, params_, CS_TYPE_UTF8MB4_GENERAL_CI, CS_TYPE_UTF8MB4_GENERAL_CI);
 | |
|   OK(query_range.preliminary_extract_query_range(single_range_columns, expr, dtc_params));
 | |
|   OK(query_range.final_extract_query_range(params_, dtc_params));
 | |
|   OK(query_range.get_tablet_ranges(ranges, get_methods, dtc_params));
 | |
|   _OB_LOG(INFO, "range: %s", to_cstring(ranges));
 | |
| }
 | |
| 
 | |
| TEST_F(ObQueryRangeTest, range_column_with_triple_key)
 | |
| {
 | |
|   char in_body[102400] = {'\0'};
 | |
|   char sql_str[102400] = {'\0'};
 | |
|   for (int64_t i = 0; i < 199; ++i) {
 | |
|     strcat(in_body, "(?, ?, ?),");
 | |
|   }
 | |
|   strcat(in_body, "(?, ?, ?)");
 | |
|   snprintf(sql_str, sizeof(sql_str), "(a, b, c) in (%s)", in_body);
 | |
|   _OB_LOG(INFO, "%s", sql_str);
 | |
| 
 | |
|   ObQueryRangeArray ranges;
 | |
|   ObGetMethodArray get_methods;
 | |
|   ObQueryRange query_range;
 | |
|   ObRawExpr* expr = NULL;
 | |
|   int64_t param_array[600];
 | |
|   for (int64_t i = 0; i < 600; ++i) {
 | |
|     if (0 == i % 3) {
 | |
|       param_array[i] = 1003809986;
 | |
|     } else if (1 == i % 3) {
 | |
|       param_array[i] = 1;
 | |
|     } else {
 | |
|       param_array[i] = 3732197360 + i;
 | |
|     }
 | |
|   }
 | |
|   params_.reset();
 | |
|   for (int64_t i = 0; i < 600; ++i) {
 | |
|     ObObjParam param;
 | |
|     param.set_int(param_array[i]);
 | |
|     param.set_param_meta();
 | |
|     OK(params_.push_back(param));
 | |
|   }
 | |
|   const ObDataTypeCastParams dtc_params;
 | |
|   resolve_condition(triple_range_columns_, sql_str, expr, ¶ms_);
 | |
|   int64_t time1 = ObTimeUtility::current_time();
 | |
|   OK(query_range.preliminary_extract_query_range(triple_range_columns_, expr, dtc_params));
 | |
|   int64_t time2 = ObTimeUtility::current_time();
 | |
|   OK(query_range.final_extract_query_range(params_, dtc_params));
 | |
|   int64_t time3 = ObTimeUtility::current_time();
 | |
|   OK(query_range.get_tablet_ranges(ranges, get_methods, dtc_params));
 | |
|   _OB_LOG(INFO, "preliminary_extract_query_range(us): %ld", time2 - time1);
 | |
|   _OB_LOG(INFO, "final_extract_query_range(us): %ld", time3 - time2);
 | |
|   //_OB_LOG(INFO, "ranges: %s", to_cstring(ranges));
 | |
| }
 | |
| 
 | |
| TEST_F(ObQueryRangeTest, simple_row_in)
 | |
| {
 | |
|   _OB_LOG(INFO, "start test: (a, d) in ((1 , 1.5), (2, 2), (1, 3), (2, 3), (0, 0), ('3', 3))");
 | |
|   params_.reset();
 | |
|   ObObjParam param;
 | |
|   param.set_int(1);
 | |
|   param.set_param_meta();
 | |
|   OK(params_.push_back(param));
 | |
|   param.set_double(1.5);
 | |
|   param.set_param_meta();
 | |
|   OK(params_.push_back(param));
 | |
|   //  param.set_int(2);
 | |
|   //  OK(params_.push_back(param));
 | |
|   //  param.set_int(2);
 | |
|   //  OK(params_.push_back(param));
 | |
|   //  param.set_int(1);
 | |
|   //  OK(params_.push_back(param));
 | |
|   //  param.set_int(3);
 | |
|   //  OK(params_.push_back(param));
 | |
|   //  param.set_int(2);
 | |
|   //  OK(params_.push_back(param));
 | |
|   //  param.set_int(3);
 | |
|   //  OK(params_.push_back(param));
 | |
|   //  param.set_int(0);
 | |
|   //  OK(params_.push_back(param));
 | |
|   //  param.set_int(0);
 | |
|   //  OK(params_.push_back(param));
 | |
|   param.set_varchar("3");
 | |
|   param.set_collation_type(CS_TYPE_UTF8MB4_BIN);
 | |
|   param.set_param_meta();
 | |
|   OK(params_.push_back(param));
 | |
|   param.set_int(3);
 | |
|   param.set_param_meta();
 | |
|   OK(params_.push_back(param));
 | |
|   ObRawExpr* condition = NULL;
 | |
|   const ObDataTypeCastParams dtc_params;
 | |
| 
 | |
|   resolve_condition(triple_range_columns_, "(a, d) in ((? , ?)) or (a, d) = (?, ?)", condition, ¶ms_);
 | |
|   OK(query_range.preliminary_extract_query_range(triple_range_columns_, condition, dtc_params));
 | |
| 
 | |
|   _OB_LOG(INFO, "XXXX %s", to_cstring(query_range));
 | |
|   _OB_LOG(INFO, "XXXX params_: %s", to_cstring(params_));
 | |
|   OK(query_range.final_extract_query_range(params_, dtc_params));
 | |
|   _OB_LOG(INFO, "XXXX final: %s", to_cstring(query_range));
 | |
| 
 | |
|   ObQueryRangeArray ranges;
 | |
|   ObGetMethodArray get_methods;
 | |
| 
 | |
|   OK(query_range.get_tablet_ranges(ranges, get_methods, dtc_params));
 | |
|   _OB_LOG(INFO, "ranges: %s", to_cstring(ranges));
 | |
|   //  ASSERT_EQ(1, ranges.count());
 | |
|   //  int64_t value = 0;
 | |
|   //
 | |
|   //  EXPECT_TRUE(get_methods.at(0));
 | |
|   //
 | |
|   //  // expect: ((1, 1, 1), (1, 1, 2))
 | |
|   //  EXPECT_FALSE(ranges.at(0)->border_flag_.inclusive_start());
 | |
|   //  EXPECT_FALSE(ranges.at(0)->border_flag_.inclusive_end());
 | |
|   //  ASSERT_EQ(1, ranges.count());
 | |
|   //  ASSERT_EQ(ranges.at(0)->start_key_.get_obj_ptr()[0].get_int(value), OB_SUCCESS);
 | |
|   //  ASSERT_EQ(1, value);
 | |
|   //  ASSERT_EQ(ranges.at(0)->start_key_.get_obj_ptr()[1].get_int(value), OB_SUCCESS);
 | |
|   //  ASSERT_EQ(1, value);
 | |
|   //  ASSERT_EQ(ranges.at(0)->start_key_.get_obj_ptr()[2].get_int(value), OB_SUCCESS);
 | |
|   //  ASSERT_EQ(1, value);
 | |
|   //
 | |
|   //  ASSERT_EQ(ranges.at(0)->end_key_.get_obj_ptr()[0].get_int(value), OB_SUCCESS);
 | |
|   //  ASSERT_EQ(1, value);
 | |
|   //  ASSERT_EQ(ranges.at(0)->end_key_.get_obj_ptr()[1].get_int(value), OB_SUCCESS);
 | |
|   //  ASSERT_EQ(1, value);
 | |
|   //  ASSERT_EQ(ranges.at(0)->end_key_.get_obj_ptr()[2].get_int(value), OB_SUCCESS);
 | |
|   //  ASSERT_EQ(2, value);
 | |
| }
 | |
| 
 | |
| TEST_F(ObQueryRangeTest, basic_test)
 | |
| {
 | |
|   _OB_LOG(INFO, "start test: ((b = 6 and a < 5.5) or (a > 8 and b = 15))=> (a < 5 and b = 6) or (a > 8 and b = 15)");
 | |
|   params_.reset();
 | |
|   ObGetMethodArray get_methods;
 | |
|   OK(get_methods.push_back(false));
 | |
|   OK(get_methods.push_back(false));
 | |
|   except_result(double_range_columns_,
 | |
|       params_,
 | |
|       "(b = 6 and a < 5) or (a > 8 and b = 15)",
 | |
|       "[{\"range\":\"table_id:3003,({\"NULL\":\"NULL\"},MAX;{\"BIGINT\":5},MIN)\"}, "
 | |
|       "{\"range\":\"table_id:3003,({\"BIGINT\":8},MAX;MAX,{\"BIGINT\":15})\"}]",
 | |
|       get_methods);
 | |
|   query_range.reset();
 | |
| }
 | |
| 
 | |
| TEST_F(ObQueryRangeTest, single_key_cost_time)
 | |
| {
 | |
|   _OB_LOG(INFO, "start test: a=?(500)");
 | |
|   params_.reset();
 | |
| 
 | |
|   const char* condition = "a = ?";
 | |
|   ObRawExpr* expr = NULL;
 | |
|   ObObjParam param;
 | |
|   param.set_int(500);
 | |
|   param.set_param_meta();
 | |
|   OK(params_.push_back(param));
 | |
|   resolve_condition(single_range_columns_, condition, expr, ¶ms_);
 | |
|   const ObDataTypeCastParams dtc_params;
 | |
| 
 | |
|   ObQueryRange pre_query_range;
 | |
|   OK(pre_query_range.preliminary_extract_query_range(single_range_columns_, expr, dtc_params));
 | |
| 
 | |
|   int64_t deep_copy_cost = 0;
 | |
|   int64_t extract_cost = 0;
 | |
|   int64_t get_range_cost = 0;
 | |
|   for (int64_t i = 0; i < 1000; ++i) {
 | |
|     ObQueryRange final_query_range;
 | |
|     ObQueryRangeArray ranges;
 | |
|     ObGetMethodArray get_methods;
 | |
|     int64_t deep_copy_beg = ObTimeUtility::current_time();
 | |
|     OK(final_query_range.deep_copy(pre_query_range));
 | |
|     int64_t deep_copy_end = ObTimeUtility::current_time();
 | |
|     deep_copy_cost += deep_copy_end - deep_copy_beg;
 | |
|     OK(final_query_range.final_extract_query_range(params_, dtc_params));
 | |
|     int64_t extract_end = ObTimeUtility::current_time();
 | |
|     extract_cost += extract_end - deep_copy_end;
 | |
|     OK(final_query_range.get_tablet_ranges(ranges, get_methods, dtc_params));
 | |
|     int64_t get_range_end = ObTimeUtility::current_time();
 | |
|     get_range_cost += get_range_end - extract_end;
 | |
|   }
 | |
|   _OB_LOG(INFO,
 | |
|       "deep_copy_cost: %f, extract_cost: %f, get_range_cost: %f",
 | |
|       (float)deep_copy_cost / (float)1000,
 | |
|       (float)extract_cost / (float)1000,
 | |
|       (float)get_range_cost / (float)1000);
 | |
| 
 | |
|   ObQueryRange query_range2;
 | |
|   OK(query_range2.preliminary_extract_query_range(single_range_columns_, expr, dtc_params));
 | |
|   get_range_cost = 0;
 | |
|   for (int64_t i = 0; i < 1000; ++i) {
 | |
|     ObQueryRangeArray ranges;
 | |
|     ObGetMethodArray get_methods;
 | |
|     int64_t get_range_beg = ObTimeUtility::current_time();
 | |
|     ASSERT_TRUE(false == query_range2.need_deep_copy());
 | |
|     OK(query_range2.get_tablet_ranges(allocator_, params_, ranges, get_methods, dtc_params));
 | |
|     get_range_cost += ObTimeUtility::current_time() - get_range_beg;
 | |
|   }
 | |
|   _OB_LOG(INFO, "get range without deep copy cost time: %f", (float)get_range_cost / (float)1000);
 | |
|   ObQueryRangeArray ranges2;
 | |
|   ObGetMethodArray get_methods2;
 | |
|   ASSERT_TRUE(true == query_range2.is_precise_get());
 | |
|   OK(query_range2.get_tablet_ranges(allocator_, params_, ranges2, get_methods2, dtc_params));
 | |
|   OB_LOG(INFO, "query range pure get", K(ranges2), K(get_methods2));
 | |
| 
 | |
|   int64_t REPEAT_TIMES = 1000000;
 | |
|   int64_t ti = 0;
 | |
|   int64_t get_time_start = ObTimeUtility::current_time();
 | |
|   for (int64_t i = 0; i < REPEAT_TIMES; ++i) {
 | |
|     ti = ObTimeUtility::current_time();
 | |
|     UNUSED(ti);
 | |
|   }
 | |
|   int64_t time_used = ObTimeUtility::current_time() - get_time_start;
 | |
|   OB_LOG(INFO, "system current time cost", K(time_used), K(ti));
 | |
|   OK(ObClockGenerator::init());
 | |
|   get_time_start = ObTimeUtility::current_time();
 | |
|   for (int64_t i = 0; i < REPEAT_TIMES; ++i) {
 | |
|     ti = ObClockGenerator::getClock();
 | |
|     UNUSED(ti);
 | |
|   }
 | |
|   time_used = ObTimeUtility::current_time() - get_time_start;
 | |
|   OB_LOG(INFO, "ClockGenerator current time cost", K(time_used), K(ti));
 | |
| }
 | |
| 
 | |
| // TEST_F(ObQueryRangeTest, insert_test)
 | |
| //{
 | |
| //  ObQueryRangeArray ranges;
 | |
| //  ObGetMethodArray get_methods;
 | |
| //
 | |
| //  ObArray<ObRawExpr*> exprs;
 | |
| //  ObArray<ObObjParam> params;
 | |
| //  ObRawExpr *const_expr1 = NULL;
 | |
| //  ObRawExpr *const_expr2 = NULL;
 | |
| //  ObRawExpr *const_expr3 = NULL;
 | |
| //  ObRawExpr *const_expr4 = NULL;
 | |
| //  resolve_condition(double_range_columns_, "1", const_expr1);
 | |
| //  resolve_condition(double_range_columns_, "2", const_expr2);
 | |
| //  resolve_condition(double_range_columns_, "3", const_expr3);
 | |
| //  resolve_condition(double_range_columns_, "4", const_expr4);
 | |
| //  exprs.push_back(const_expr1);
 | |
| //  exprs.push_back(const_expr2);
 | |
| //  exprs.push_back(const_expr3);
 | |
| //  exprs.push_back(const_expr4);
 | |
| //  query_range.extract_query_range(double_range_columns_, double_range_columns_, exprs, params, NULL);
 | |
| //  bool flag = true;
 | |
| //  OK(query_range.get_tablet_ranges(double_range_columns_, ranges, flag, NULL));
 | |
| //  _OB_LOG(INFO, "insert_query_ranges----------%s", to_cstring(ranges));
 | |
| //  ObQueryRange copy_range(query_range);
 | |
| //  OK(copy_range.get_tablet_ranges(double_range_columns_, ranges, flag, NULL));
 | |
| //  _OB_LOG(INFO, "copy_query_ranges------------%s", to_cstring(ranges));
 | |
| //  OK(query_range.all_single_value_ranges(double_range_columns_, flag, NULL));
 | |
| //  ASSERT_EQ(true, flag);
 | |
| //  query_range.reset();
 | |
| //  ObArray<ObObjParam> question_params;
 | |
| //  ObObjParam obj;
 | |
| //  obj.set_int(1);
 | |
| //  question_params.push_back(obj);
 | |
| //  obj.set_int(2);
 | |
| //  question_params.push_back(obj);
 | |
| //  obj.set_int(3);
 | |
| //  question_params.push_back(obj);
 | |
| //  obj.set_int(4);
 | |
| //  question_params.push_back(obj);
 | |
| //  resolve_condition(double_range_columns_, "?", const_expr1, &question_params);
 | |
| //  resolve_condition(double_range_columns_, "?", const_expr2, &question_params);
 | |
| //  resolve_condition(double_range_columns_, "?", const_expr3, &question_params);
 | |
| //  resolve_condition(double_range_columns_, "?", const_expr4, &question_params);
 | |
| //  ObArray<ObRawExpr*> question_exprs;
 | |
| //  question_exprs.push_back(const_expr1);
 | |
| //  question_exprs.push_back(const_expr2);
 | |
| //  question_exprs.push_back(const_expr3);
 | |
| //  question_exprs.push_back(const_expr4);
 | |
| //  query_range.extract_query_range(double_range_columns_, double_range_columns_, question_exprs, question_params,
 | |
| //  NULL); OK(query_range.get_tablet_ranges(double_range_columns_, ranges, NULL)); _OB_LOG(INFO,
 | |
| //  "insert_query_ranges----------%s", to_cstring(ranges));
 | |
| //}
 | |
| 
 | |
| int main(int argc, char** argv)
 | |
| {
 | |
|   init_sql_factories();
 | |
|   OB_LOGGER.set_log_level("TRACE");
 | |
|   int ret = 0;
 | |
|   ContextParam param;
 | |
|   param.set_mem_attr(1001, 0, ObCtxIds::WORK_AREA).set_page_size(OB_MALLOC_BIG_BLOCK_SIZE);
 | |
| 
 | |
|   ::testing::InitGoogleTest(&argc, argv);
 | |
|   CREATE_WITH_TEMP_CONTEXT(param)
 | |
|   {
 | |
|     ret = RUN_ALL_TESTS();
 | |
|   }
 | |
|   return ret;
 | |
| }
 | 
