1141 lines
		
	
	
		
			43 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1141 lines
		
	
	
		
			43 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.
 | |
|  */
 | |
| 
 | |
| #define USING_LOG_PREFIX SQL_REWRITE
 | |
| 
 | |
| #include <stdlib.h>
 | |
| #include <iostream>
 | |
| #include <gtest/gtest.h>
 | |
| #include <sys/time.h>
 | |
| #include "lib/utility/ob_test_util.h"
 | |
| #include "lib/json/ob_json.h"
 | |
| #include "common/ob_common_utility.h"
 | |
| #include "sql/ob_sql_init.h"
 | |
| #include "../test_sql_utils.h"
 | |
| #include "sql/parser/ob_parser.h"
 | |
| #include "sql/resolver/ob_schema_checker.h"
 | |
| #include "sql/rewrite/ob_transform_view_merge.h"
 | |
| #include "sql/rewrite/ob_transform_where_subquery_pullup.h"
 | |
| #include "sql/rewrite/ob_transform_eliminate_outer_join.h"
 | |
| #include "sql/rewrite/ob_transformer_impl.h"
 | |
| #include "sql/rewrite/ob_transform_query_push_down.h"
 | |
| #include "sql/rewrite/ob_transform_aggregate.h"
 | |
| #include "sql/rewrite/ob_transform_simplify.h"
 | |
| #include "../optimizer/test_optimizer_utils.h"
 | |
| #include "test_trans_utils.h"
 | |
| #include "observer/ob_req_time_service.h"
 | |
| //#include "../rewrite/test_trans_utils.h"
 | |
| 
 | |
| using namespace oceanbase::lib;
 | |
| using namespace oceanbase::common;
 | |
| using namespace oceanbase::sql;
 | |
| using namespace oceanbase::share;
 | |
| using namespace oceanbase::share::schema;
 | |
| using namespace oceanbase::obrpc;
 | |
| using oceanbase::sql::ObTableLocation;
 | |
| using namespace oceanbase::json;
 | |
| namespace test {
 | |
| 
 | |
| /* update the result file
 | |
|  *             TEMP FILe                                  RESULT FILE
 | |
|  *cp  test_:
 | |
|  *cp  test_transformer_plan_after_el.tmp           test_transformer_plan_after_el.result
 | |
|  *cp  test_transformer_plan_after_or_expand.tmp    test_transformer_plan_after_or_expand.result
 | |
|  *cp  test_transformer_plan_after_where_pullup.tmp test_transformer_plan_after_where_pullup.result
 | |
|  *cp  test_transform_impl_after_plan.tmp           test_transform_impl_after_plan.result
 | |
|  *
 | |
|  *
 | |
|  *
 | |
|  * */
 | |
| 
 | |
| test::TestTransUtils::CmdLineParam param;
 | |
| 
 | |
| class TestRewrite : public TestOptimizerUtils {
 | |
| public:
 | |
|   TestRewrite();
 | |
|   virtual ~TestRewrite();
 | |
| 
 | |
| private:
 | |
|   void virtual SetUp();
 | |
|   // disallow copy
 | |
|   DISALLOW_COPY_AND_ASSIGN(TestRewrite);
 | |
| 
 | |
| protected:
 | |
|   // function members
 | |
|   int parse_resolve_transform(std::ofstream& of_result, ObTransformerImpl& trans_util, ObString& sql, ObDMLStmt*& stmt,
 | |
|       ObLogPlan*& logical_plan, bool do_transform, bool do_gen_plan, ObIAllocator* allocator);
 | |
|   void transform_sql(ObTransformerImpl& trans_util, const char* query_str, std::ofstream& of_result, ObDMLStmt*& stmt,
 | |
|       ObLogPlan*& logical_plan, bool do_transform, bool do_gen_plan, ObIAllocator* allocator);
 | |
|   void run_test(ObTransformerImpl& trans_util, const char* test_file, const char* stmt_result_file,
 | |
|       const char* stmt_after_trans_file, const char* stmt_no_trans_file, const char* plan_result_file,
 | |
|       const char* plan_after_tans_file, const char* plan_no_trans_file, bool print_sql_in_file = true,
 | |
|       // ExplainType type = EXPLAIN_EXTENDED);
 | |
|       ExplainType type = EXPLAIN_TRADITIONAL, bool always_rewrite = false);
 | |
|   int gen_stmt_and_plan(ObTransformerImpl& trans_util, const char* query_str, ObDMLStmt*& stmt,
 | |
|       ObLogPlan*& logical_plan, bool do_transform, bool do_gen_plan);
 | |
|   void multi_thread_test();
 | |
|   void test_from_cmd(uint64_t rules);
 | |
|   int parse_resolve(ObString& query_str, ObDMLStmt*& stmt);
 | |
|   int transform(ObTransformerImpl& trans_util, ObDMLStmt*& stmt);
 | |
|   int optimize(ObDMLStmt*& stmt, ObLogPlan*& logical_plan);
 | |
|   bool do_loop_test;
 | |
| 
 | |
| protected:
 | |
|   ObTransformerCtx ctx_;
 | |
|   ObSchemaChecker schema_checker_;
 | |
| };
 | |
| 
 | |
| class TestStackCheck : public TestOptimizerUtils {
 | |
| public:
 | |
|   TestStackCheck()
 | |
|   {
 | |
|     memset(schema_file_path_, '\0', 128);
 | |
|     memcpy(schema_file_path_, "./schema.sql", strlen("./schema.sql"));
 | |
|   }
 | |
|   virtual ~TestStackCheck()
 | |
|   {}
 | |
| };
 | |
| 
 | |
| //#define tmptest
 | |
| 
 | |
| TestRewrite::TestRewrite()
 | |
| {
 | |
|   ctx_.allocator_ = &allocator_;
 | |
|   ctx_.exec_ctx_ = &exec_ctx_;
 | |
|   ctx_.expr_factory_ = &expr_factory_;
 | |
|   ctx_.stmt_factory_ = &stmt_factory_;
 | |
|   ctx_.partition_location_cache_ = &part_cache_;
 | |
|   ctx_.stat_mgr_ = &stat_manager_;
 | |
|   ctx_.partition_service_ = &partition_service_;
 | |
|   ctx_.sql_schema_guard_ = &sql_schema_guard_;
 | |
|   ctx_.self_addr_ = &(const_cast<ObAddr&>(exec_ctx_.get_addr()));
 | |
|   ctx_.merged_version_ = OB_MERGED_VERSION_INIT;
 | |
|   memset(schema_file_path_, '\0', 128);
 | |
|   memcpy(schema_file_path_, "./schema.sql", strlen("./schema.sql"));
 | |
|   do_loop_test = false;
 | |
| }
 | |
| 
 | |
| void TestRewrite::SetUp()
 | |
| {
 | |
|   init();
 | |
|   int ret = OB_SUCCESS;
 | |
|   if (OB_FAIL(schema_checker_.init(sql_schema_guard_))) {
 | |
|     LOG_ERROR("fail to init schema_checker", K(ret));
 | |
|   } else {
 | |
|     session_info_.update_sys_variable_by_name(ObString::make_string(OB_SV_PARALLEL_MAX_SERVERS), 10);
 | |
|     session_info_.set_user_session();
 | |
|     ctx_.schema_checker_ = &schema_checker_;
 | |
|     ctx_.session_info_ = &session_info_;
 | |
|     exec_ctx_.get_task_executor_ctx()->set_min_cluster_version(CLUSTER_VERSION_2100);
 | |
|     LOG_INFO("set min cluster version", K(CLUSTER_VERSION_2100));
 | |
|   }
 | |
| }
 | |
| 
 | |
| TestRewrite::~TestRewrite()
 | |
| {}
 | |
| 
 | |
| int TestRewrite::parse_resolve_transform(std::ofstream& of_result, ObTransformerImpl& trans_util, ObString& query_str,
 | |
|     ObDMLStmt*& stmt, ObLogPlan*& logical_plan, bool do_transform, bool do_gen_plan, ObIAllocator* allocator)
 | |
| {
 | |
|   OB_ASSERT(NULL != allocator);
 | |
|   int ret = OB_SUCCESS;
 | |
|   //
 | |
|   ParamStore& param_store = exec_ctx_.get_physical_plan_ctx()->get_param_store_for_update();
 | |
|   param_store.reuse();
 | |
|   ObSQLMode mode = SMO_DEFAULT;
 | |
|   ObParser parser(*allocator, mode);
 | |
|   ParseResult parse_result;
 | |
|   int64_t time_1 = get_usec();
 | |
|   int64_t time_2 = 0;
 | |
|   int64_t time_3 = 0;
 | |
|   int64_t time_4 = 0;
 | |
|   int64_t time_5 = 0;
 | |
|   /**
 | |
|    *  2. set resolver context
 | |
|    */
 | |
|   /**
 | |
|    *  2. set resolver context
 | |
|    */
 | |
|   ObSchemaChecker schema_checker;
 | |
|   // if (OB_ISNULL(schema_mgr_)) {
 | |
|   //  ret = OB_ERR_UNEXPECTED;
 | |
|   //  LOG_WARN("schema_mgr_ is NULL", K(ret));
 | |
|   if (OB_FAIL(schema_checker.init(sql_schema_guard_))) {
 | |
|     LOG_WARN("fail to init schema_checker", K(ret));
 | |
|   } else {
 | |
|     /**
 | |
|      *  3. set resolver context
 | |
|      */
 | |
|     ObResolverParams resolver_ctx;
 | |
|     resolver_ctx.allocator_ = allocator;
 | |
|     resolver_ctx.schema_checker_ = &schema_checker;
 | |
|     resolver_ctx.session_info_ = &session_info_;
 | |
|     resolver_ctx.database_id_ = 1024;
 | |
|     resolver_ctx.param_list_ = ¶m_store;
 | |
|     resolver_ctx.expr_factory_ = &expr_factory_;
 | |
|     resolver_ctx.stmt_factory_ = &stmt_factory_;
 | |
|     resolver_ctx.query_ctx_ = stmt_factory_.get_query_ctx();
 | |
| 
 | |
|     LOG_INFO("begin parse sql", K(query_str));
 | |
|     ObAddr addr;
 | |
|     LOG_DEBUG("setting local address to 1.1.1.1");
 | |
|     addr.set_ip_addr("1.1.1.1", 8888);
 | |
| 
 | |
|     time_1 = get_usec();
 | |
|     if (OB_FAIL(parser.parse(query_str, parse_result))) {
 | |
|       LOG_WARN("failed to parse", K(ret));
 | |
|     } else {
 | |
|       time_2 = get_usec();
 | |
|       SqlInfo not_param_info;
 | |
|       ParseNode* root = parse_result.result_tree_->children_[0];
 | |
|       ObMaxConcurrentParam::FixParamStore fixed_param_store;
 | |
|       bool is_transform_outline = false;
 | |
|       if (T_SELECT == root->type_ || T_INSERT == root->type_ || T_UPDATE == root->type_ || T_DELETE == root->type_) {
 | |
|         if (OB_FAIL(ObSqlParameterization::transform_syntax_tree(allocator_,
 | |
|                 session_info_,
 | |
|                 NULL,
 | |
|                 0,
 | |
|                 parse_result.result_tree_,
 | |
|                 not_param_info,
 | |
|                 param_store,
 | |
|                 NULL,
 | |
|                 fixed_param_store,
 | |
|                 is_transform_outline))) {
 | |
|           LOG_WARN("failed to parameterized", K(ret));
 | |
|         }
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     if (OB_SUCC(ret)) {
 | |
|       resolver_ctx.query_ctx_->question_marks_count_ = param_store.count();
 | |
|       ObResolver resolver(resolver_ctx);
 | |
| 
 | |
|       ObStmt* stmt_tree = NULL;
 | |
|       if (OB_FAIL(resolver.resolve(
 | |
|               ObResolver::IS_NOT_PREPARED_STMT, *parse_result.result_tree_->children_[0], stmt_tree))) {
 | |
|         LOG_WARN("failed to resolve", K(ret));
 | |
|       } else {
 | |
|         time_3 = get_usec();
 | |
|         if (NULL == (stmt = dynamic_cast<ObDMLStmt*>(stmt_tree))) {
 | |
|           _LOG_WARN("Generate stmt error, query=%.*s", parse_result.input_sql_len_, parse_result.input_sql_);
 | |
|           ret = OB_ERR_UNEXPECTED;
 | |
|         } else {
 | |
|           stmt->set_sql_stmt(parse_result.input_sql_, parse_result.input_sql_len_);
 | |
|           LOG_INFO("Generate stmt success", "query", stmt->get_sql_stmt());
 | |
|         }
 | |
|       }
 | |
|       if (OB_SUCC(ret)) {
 | |
|         ret = get_hidden_column_value(resolver_ctx, param_store);
 | |
|       }
 | |
|       if (OB_SUCC(ret)) {
 | |
|         if (OB_FAIL(ObSql::replace_stmt_bool_filter(exec_ctx_, stmt))) {
 | |
|           LOG_WARN("Failed to replace stmt bool filer", K(ret));
 | |
|         }
 | |
|       }
 | |
|       /*
 | |
|        * Transform different util use different transform util
 | |
|        */
 | |
|       if (OB_SUCC(ret)) {
 | |
|         if (do_transform) {
 | |
|           if (OB_ISNULL(trans_util.get_trans_ctx())) {
 | |
|             ret = OB_ERR_UNEXPECTED;
 | |
|             LOG_WARN("unexpect null ctx", K(ret));
 | |
|           } else if (OB_FALSE_IT(trans_util.get_trans_ctx()->ignore_semi_infos_.reset())) {
 | |
|           } else if (OB_SUCCESS != (ret = trans_util.transform(stmt))) {
 | |
|             LOG_WARN("failed to do transform", K(ret));
 | |
|           } else if (OB_FAIL(stmt->formalize_stmt(&session_info_))) {
 | |
|             LOG_WARN("failed to formalize stmt", K(ret));
 | |
|           } else {
 | |
|             time_4 = get_usec();
 | |
|             //_OB_LOG(INFO, "%s", CSJ(*stmt));
 | |
|             stmt_tree = static_cast<ObStmt*>(stmt);
 | |
|             OB_ASSERT(NULL != stmt_tree);
 | |
|             OB_ASSERT((static_cast<ObStmt*>(stmt) == stmt_tree));
 | |
|             _OB_LOG(INFO, "finish to try to transform");
 | |
|           }
 | |
|         }
 | |
|         LOG_DEBUG("stmt to optimize", K(do_transform), K(*stmt));
 | |
|         of_result << CSJ(*stmt) << std::endl;
 | |
| 
 | |
|         if (OB_SUCC(ret)) {
 | |
|           if (OB_FAIL(stmt->check_and_convert_hint(session_info_))) {
 | |
|             LOG_WARN("Failed to check and convert hint", K(ret));
 | |
|           }
 | |
|         }
 | |
| 
 | |
|         if (OB_SUCC(ret)) {
 | |
|           if (do_gen_plan) {
 | |
|             ObDMLStmt* dml_stmt = static_cast<ObDMLStmt*>(stmt_tree);
 | |
|             ObPhysicalPlanCtx* pctx = exec_ctx_.get_physical_plan_ctx();
 | |
|             if (NULL == pctx) {
 | |
|               ret = OB_ERR_UNEXPECTED;
 | |
|               LOG_WARN("physical plan ctx is NULL", K(ret));
 | |
|             } else if (NULL != dml_stmt) {
 | |
|               ObQueryHint query_hint = dml_stmt->get_stmt_hint().get_query_hint();
 | |
|               ObOptimizerContext* ctx_ptr =
 | |
|                   static_cast<ObOptimizerContext*>(allocator_.alloc(sizeof(ObOptimizerContext)));
 | |
|               exec_ctx_.get_sql_ctx()->session_info_ = &session_info_;
 | |
|               optctx_ = new (ctx_ptr) ObOptimizerContext(&session_info_,
 | |
|                   &exec_ctx_,
 | |
|                   &sql_schema_guard_,
 | |
|                   &stat_manager_,  // statistics manager
 | |
|                   NULL,
 | |
|                   &partition_service_,
 | |
|                   static_cast<ObIAllocator&>(allocator_),
 | |
|                   &part_cache_,
 | |
|                   ¶m_store,
 | |
|                   addr,
 | |
|                   NULL,
 | |
|                   OB_MERGED_VERSION_INIT,
 | |
|                   query_hint,
 | |
|                   expr_factory_,
 | |
|                   dml_stmt);
 | |
|               ObTableLocation table_location;
 | |
|               ret = optctx_->get_table_location_list().push_back(table_location);
 | |
|               LOG_INFO("setting local address to 1.1.1.1");
 | |
|               optctx_->set_local_server_ipv4_addr("1.1.1.1", 8888);
 | |
|               ObOptimizer optimizer(*optctx_);
 | |
| 
 | |
|               if (OB_FAIL(optimizer.optimize(*dml_stmt, logical_plan))) {
 | |
|                 LOG_WARN("failed to optimize", "SQL", stmt);
 | |
|               } else {
 | |
|                 time_5 = get_usec();
 | |
|                 LOG_DEBUG("succ to generate logical plan");
 | |
|               }
 | |
|             }
 | |
|           }
 | |
|         } else {
 | |
|           logical_plan = NULL;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   if (OB_SUCC(ret)) {
 | |
|     std::cout << "<<<<<<<<<<<<<<<<<<<<<<<<<<<<" << std::endl;
 | |
|     std::cout << "SQL: " << query_str.ptr() << std::endl;
 | |
|     std::cout << "parse:     " << time_2 - time_1 << std::endl;
 | |
|     std::cout << "resolve:   " << time_3 - time_2 << std::endl;
 | |
|     if (do_transform) {
 | |
|       std::cout << "transform:   " << time_4 - time_3 << std::endl;
 | |
|     }
 | |
|     if (do_gen_plan) {
 | |
|       std::cout << "optimize:  " << time_5 - time_4 << std::endl;
 | |
|     }
 | |
|     std::cout << ">>>>>>>>>>>>>>>>>>>>>>>>>>>>" << std::endl;
 | |
|   }
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| // new
 | |
| int TestRewrite::parse_resolve(ObString& query_str, ObDMLStmt*& stmt)
 | |
| {
 | |
|   int ret = OB_SUCCESS;
 | |
|   //
 | |
|   ParamStore& param_store = exec_ctx_.get_physical_plan_ctx()->get_param_store_for_update();
 | |
|   param_store.reuse();
 | |
|   ObSQLMode mode = SMO_DEFAULT;
 | |
|   ObParser parser(allocator_, mode);
 | |
|   ParseResult parse_result;
 | |
|   /**
 | |
|    *  2. set resolver context
 | |
|    */
 | |
|   /**
 | |
|    *  2. set resolver context
 | |
|    */
 | |
|   ObSchemaChecker schema_checker;
 | |
|   // if (OB_ISNULL(schema_mgr_)) {
 | |
|   //  ret = OB_ERR_UNEXPECTED;
 | |
|   //  LOG_WARN("schema_mgr_ is NULL", K(ret));
 | |
|   if (OB_FAIL(schema_checker.init(sql_schema_guard_))) {
 | |
|     LOG_WARN("fail to init schema_checker", K(ret));
 | |
|   } else {
 | |
|     /**
 | |
|      *  3. set resolver context
 | |
|      */
 | |
|     ObResolverParams resolver_ctx;
 | |
|     resolver_ctx.allocator_ = &allocator_;
 | |
|     resolver_ctx.schema_checker_ = &schema_checker;
 | |
|     resolver_ctx.session_info_ = &session_info_;
 | |
|     resolver_ctx.database_id_ = 1024;
 | |
|     resolver_ctx.param_list_ = ¶m_store;
 | |
|     resolver_ctx.expr_factory_ = &expr_factory_;
 | |
|     resolver_ctx.stmt_factory_ = &stmt_factory_;
 | |
|     resolver_ctx.query_ctx_ = stmt_factory_.get_query_ctx();
 | |
|     LOG_INFO("begin parse sql", K(query_str));
 | |
| 
 | |
|     if (OB_FAIL(parser.parse(query_str, parse_result))) {
 | |
|       LOG_WARN("failed to parse", K(ret));
 | |
|     } else {
 | |
|       SqlInfo not_param_info;
 | |
|       ParseNode* root = parse_result.result_tree_->children_[0];
 | |
|       ObMaxConcurrentParam::FixParamStore fixed_param_store(
 | |
|           OB_MALLOC_NORMAL_BLOCK_SIZE, ObWrapperAllocator(&allocator_));
 | |
|       bool is_transform_outline = false;
 | |
|       if (T_SELECT == root->type_ || T_INSERT == root->type_ || T_UPDATE == root->type_ || T_DELETE == root->type_) {
 | |
|         if (OB_FAIL(ObSqlParameterization::transform_syntax_tree(allocator_,
 | |
|                 session_info_,
 | |
|                 NULL,
 | |
|                 0,
 | |
|                 parse_result.result_tree_,
 | |
|                 not_param_info,
 | |
|                 param_store,
 | |
|                 NULL,
 | |
|                 fixed_param_store,
 | |
|                 is_transform_outline))) {
 | |
|           LOG_WARN("failed to parameterized", K(ret));
 | |
|         }
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     if (OB_SUCC(ret)) {
 | |
|       resolver_ctx.query_ctx_->question_marks_count_ = param_store.count();
 | |
|       ObResolver resolver(resolver_ctx);
 | |
| 
 | |
|       ObStmt* stmt_tree = NULL;
 | |
|       if (OB_FAIL(resolver.resolve(
 | |
|               ObResolver::IS_NOT_PREPARED_STMT, *parse_result.result_tree_->children_[0], stmt_tree))) {
 | |
|         LOG_WARN("failed to resolve", K(ret));
 | |
|       } else {
 | |
|         if (NULL == (stmt = dynamic_cast<ObDMLStmt*>(stmt_tree))) {
 | |
|           _LOG_WARN("Generate stmt error, query=%.*s", parse_result.input_sql_len_, parse_result.input_sql_);
 | |
|           ret = OB_ERR_UNEXPECTED;
 | |
|         } else {
 | |
|           stmt->set_sql_stmt(parse_result.input_sql_, parse_result.input_sql_len_);
 | |
|           LOG_INFO("Generate stmt success", "query", stmt->get_sql_stmt());
 | |
|         }
 | |
|       }
 | |
|       if (OB_SUCC(ret)) {
 | |
|         ret = get_hidden_column_value(resolver_ctx, param_store);
 | |
|       }
 | |
|       if (OB_SUCC(ret)) {
 | |
|         if (OB_FAIL(ObSql::replace_stmt_bool_filter(exec_ctx_, stmt))) {
 | |
|           LOG_WARN("Failed to replace stmt bool filer", K(ret));
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| int TestRewrite::transform(ObTransformerImpl& trans_util, ObDMLStmt*& stmt)
 | |
| {
 | |
|   int ret = OB_SUCCESS;
 | |
|   /*
 | |
|    * Transform different util use different transform util
 | |
|    */
 | |
|   if (OB_SUCC(ret)) {
 | |
|     // std::cout << "begin to do transform------" << std::endl;
 | |
|     exec_ctx_.get_sql_ctx()->session_info_ = &session_info_;
 | |
|     if (OB_ISNULL(trans_util.get_trans_ctx())) {
 | |
|       ret = OB_ERR_UNEXPECTED;
 | |
|       LOG_WARN("unexpect null ctx", K(ret));
 | |
|     } else if (OB_FALSE_IT(trans_util.get_trans_ctx()->ignore_semi_infos_.reset())) {
 | |
|     } else if (OB_SUCCESS != (ret = trans_util.transform(stmt))) {
 | |
|       LOG_WARN("failed to do transform", K(ret));
 | |
|     } else if (OB_FAIL(stmt->formalize_stmt(&session_info_))) {
 | |
|       LOG_WARN("failed to formalize stmt", K(ret));
 | |
|     }
 | |
| 
 | |
|     if (OB_FAIL(ret)) {
 | |
|     } else if (OB_FAIL(stmt->distribute_hint_in_query_ctx(&allocator_))) {
 | |
|       LOG_WARN("Failed to distribute hint in query ctx", K(ret));
 | |
|     } else if (OB_FAIL(stmt->check_and_convert_hint(session_info_))) {
 | |
|       LOG_WARN("Failed to check and convert hint", K(ret));
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| int TestRewrite::optimize(ObDMLStmt*& stmt, ObLogPlan*& logical_plan)
 | |
| {
 | |
|   int ret = OB_SUCCESS;
 | |
| 
 | |
|   ObDMLStmt* dml_stmt = static_cast<ObDMLStmt*>(stmt);
 | |
|   ObPhysicalPlanCtx* pctx = exec_ctx_.get_physical_plan_ctx();
 | |
|   if (NULL == pctx) {
 | |
|     ret = OB_ERR_UNEXPECTED;
 | |
|     LOG_WARN("physical plan ctx is NULL", K(ret));
 | |
|   } else if (NULL != dml_stmt) {
 | |
|     ObAddr addr;
 | |
|     addr.set_ip_addr("1.1.1.1", 8888);
 | |
|     ParamStore& param_store = exec_ctx_.get_physical_plan_ctx()->get_param_store_for_update();
 | |
|     ObQueryHint query_hint = dml_stmt->get_stmt_hint().get_query_hint();
 | |
|     ObOptimizerContext* ctx_ptr = static_cast<ObOptimizerContext*>(allocator_.alloc(sizeof(ObOptimizerContext)));
 | |
|     exec_ctx_.get_sql_ctx()->session_info_ = &session_info_;
 | |
|     optctx_ = new (ctx_ptr) ObOptimizerContext(&session_info_,
 | |
|         &exec_ctx_,
 | |
|         &sql_schema_guard_,
 | |
|         &stat_manager_,  // statistics manager
 | |
|         NULL,
 | |
|         &partition_service_,
 | |
|         static_cast<ObIAllocator&>(allocator_),
 | |
|         &part_cache_,
 | |
|         ¶m_store,
 | |
|         addr,
 | |
|         NULL,
 | |
|         OB_MERGED_VERSION_INIT,
 | |
|         query_hint,
 | |
|         expr_factory_,
 | |
|         dml_stmt);
 | |
|     // note that we can't mock a table location when applying cost based transformation. Without
 | |
|     // that, estimating cost of plan will use default statistics. And this may cause a situation
 | |
|     // that the lower cost plan is different when use default statistics and mock statistics.
 | |
|     ObTableLocation table_location;
 | |
|     ret = optctx_->get_table_location_list().push_back(table_location);
 | |
|     LOG_INFO("setting local address to 1.1.1.1");
 | |
|     optctx_->set_local_server_ipv4_addr("1.1.1.1", 8888);
 | |
|     ObOptimizer optimizer(*optctx_);
 | |
| 
 | |
|     if (OB_FAIL(optimizer.optimize(*dml_stmt, logical_plan))) {
 | |
|       LOG_WARN("failed to optimize", "SQL", stmt);
 | |
|     }
 | |
|   }
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| int TestRewrite::gen_stmt_and_plan(ObTransformerImpl& trans_util, const char* query_str, ObDMLStmt*& stmt,
 | |
|     ObLogPlan*& logical_plan, bool do_transform, bool do_gen_plan)
 | |
| {
 | |
|   ObString sql = ObString::make_string(query_str);
 | |
|   int ret = parse_resolve(sql, stmt);
 | |
|   if (OB_SUCC(ret) && do_transform) {
 | |
|     ret = transform(trans_util, stmt);
 | |
|   }
 | |
|   if (OB_SUCC(ret) && do_gen_plan) {
 | |
|     ret = optimize(stmt, logical_plan);
 | |
|   }
 | |
|   if (OB_FAIL(ret)) {
 | |
|     LOG_INFO("FAILED SQL", K(query_str));
 | |
|   }
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| void TestRewrite::transform_sql(ObTransformerImpl& trans_util, const char* query_str, std::ofstream& of_result,
 | |
|     ObDMLStmt*& stmt, ObLogPlan*& logical_plan, bool do_transform, bool do_gen_plan, ObIAllocator* allocator)
 | |
| {
 | |
|   OB_ASSERT(NULL != allocator);
 | |
|   of_result << "***************   Case " << case_id_ << "   ***************" << std::endl;
 | |
|   of_result << std::endl;
 | |
|   ObString sql = ObString::make_string(query_str);
 | |
|   of_result << "SQL: " << query_str << std::endl;
 | |
|   int ret =
 | |
|       parse_resolve_transform(of_result, trans_util, sql, stmt, logical_plan, do_transform, do_gen_plan, allocator);
 | |
|   if (ret != OB_SUCCESS) {
 | |
|     LOG_INFO("SQL", K(query_str));
 | |
|   }
 | |
|   ASSERT_EQ(OB_SUCCESS, ret);
 | |
| }
 | |
| 
 | |
| #define T(query)                                \
 | |
|   do {                                          \
 | |
|     transform_sql(query, of_result, of_expect); \
 | |
|   } while (0)
 | |
| 
 | |
| // params
 | |
| // trans_util            : which rule to apply to the sql
 | |
| // test_file             : input sql file
 | |
| // stmt_after_trans_file : stmt_result_file after transform after this run
 | |
| // stmt_no_trans_file    : stmt_no_trans_file no transform after this run
 | |
| // plan_result_file      : logical_plan after transform result file
 | |
| // plan_after_tans_file  : logical_plan after transform result file this run
 | |
| // plan_no_trans_file    : logical_plan no transform after this run
 | |
| // print_sql_in_file     : print sql in the plan file or not, default true
 | |
| //                        sometimes we may need to consider the two plans
 | |
| //                        completely the same generated by the complex and simple sql
 | |
| //                        thus compare the two plan file by str.eg or_expand test
 | |
| // every run turn, we do generate two plans, a complex sql needed to transform,
 | |
| // a simple sql that equals the complex, we print the two plans to compare so
 | |
| // we will see the result of transform and debug.
 | |
| void TestRewrite::run_test(ObTransformerImpl& trans_util, const char* test_file, const char* stmt_result_file,
 | |
|     const char* stmt_after_trans_file, const char* stmt_no_trans_file, const char* plan_result_file,
 | |
|     const char* plan_after_tans_file, const char* plan_no_trans_file, bool print_sql_in_file,
 | |
|     ExplainType type /*EXPLAIN_TRADITIONAL*/, bool always_rewrite)
 | |
| {
 | |
|   UNUSED(print_sql_in_file);
 | |
|   std::ofstream of_stmt_after_trans(stmt_after_trans_file);
 | |
|   ASSERT_TRUE(of_stmt_after_trans.is_open());
 | |
|   std::ofstream of_stmt_no_trans(stmt_no_trans_file);
 | |
|   ASSERT_TRUE(of_stmt_no_trans.is_open());
 | |
|   std::ofstream of_plan_after_trans(plan_after_tans_file);
 | |
|   ASSERT_TRUE(of_plan_after_trans.is_open());
 | |
|   std::ofstream of_plan_no_trans(plan_no_trans_file);
 | |
|   ASSERT_TRUE(of_plan_no_trans.is_open());
 | |
|   std::ifstream if_tests(test_file);
 | |
|   ASSERT_TRUE(if_tests.is_open());
 | |
|   std::string line;
 | |
|   std::string total_line;
 | |
|   bool do_generate_plan = true;
 | |
|   ObSchemaChecker schema_checker;
 | |
|   ASSERT_EQ(OB_SUCCESS, schema_checker.init(sql_schema_guard_));
 | |
|   stat_manager_.set_schema_checker(&schema_checker);
 | |
|   while (std::getline(if_tests, line)) {
 | |
|     // allow human readable formatting
 | |
|     if (line.size() <= 0)
 | |
|       continue;
 | |
|     std::size_t begin = line.find_first_not_of('\t');
 | |
|     if (line.at(begin) == '#')
 | |
|       continue;
 | |
|     std::size_t end = line.find_last_not_of('\t');
 | |
|     std::string exact_line = line.substr(begin, end - begin + 1);
 | |
|     total_line += exact_line;
 | |
|     total_line += " ";
 | |
|     if (exact_line.at(exact_line.length() - 1) != ';')
 | |
|       continue;
 | |
|     else {
 | |
|       _OB_LOG(INFO, "case number is %lu", case_id_);
 | |
|       _OB_LOG(INFO, "query_str is %s", total_line.c_str());
 | |
|       for (int i = 0; i < 2; ++i) {
 | |
|         bool do_trans = 1 == i % 2;
 | |
|         ObDMLStmt* stmt = NULL;
 | |
|         ObLogPlan* logical_plan = NULL;
 | |
| 
 | |
|         ObString sql = ObString::make_string(total_line.c_str());
 | |
|         // parser & resolve
 | |
|         ASSERT_EQ(OB_SUCCESS, parse_resolve(sql, stmt));
 | |
|         // rewerite
 | |
|         if (do_trans || always_rewrite) {
 | |
|           SQL_LOG(INFO, "before rewrite", "query", CSJ(*stmt));
 | |
|           ASSERT_EQ(OB_SUCCESS, transform(trans_util, stmt));
 | |
|           SQL_LOG(INFO, "after rewrite", "query", CSJ(*stmt));
 | |
|         }
 | |
|         // to file and diff
 | |
|         std::ofstream* stmt_stream = !do_trans ? &of_stmt_no_trans : &of_stmt_after_trans;
 | |
|         *stmt_stream << "***************   Case " << case_id_ << "   ***************" << std::endl;
 | |
|         *stmt_stream << "SQL: " << total_line << std::endl;
 | |
|         *stmt_stream << CSJ(*stmt) << std::endl;
 | |
|         stmt_stream->flush();
 | |
|         // optimize
 | |
|         if (do_generate_plan) {
 | |
|           ASSERT_EQ(OB_SUCCESS, optimize(stmt, logical_plan));
 | |
|         }
 | |
|         // std::cout << "SQL: " << total_line << std::endl;
 | |
|         // std::cout << "stmt: " << CSJ(stmt) << std::endl;
 | |
|         char buf[BUF_LEN];
 | |
|         memset(buf, '\0', BUF_LEN);
 | |
|         if (do_generate_plan) {
 | |
|           logical_plan->to_string(buf, BUF_LEN, type);
 | |
|           // std::cout << "plan: " << buf << std::endl;
 | |
|         }
 | |
| 
 | |
|         if (do_generate_plan) {
 | |
|           std::ofstream* plan_stream = !do_trans ? &of_plan_no_trans : &of_plan_after_trans;
 | |
|           *plan_stream << "***************   Case " << case_id_ << "   ***************" << std::endl;
 | |
|           *plan_stream << "SQL: " << total_line << std::endl;
 | |
|           *plan_stream << buf << std::endl;
 | |
|           plan_stream->flush();
 | |
|         }
 | |
| 
 | |
|         // release the memory allocated
 | |
|         stmt_factory_.destory();
 | |
|         expr_factory_.destory();
 | |
|         log_plan_factory_.destroy();
 | |
|       }
 | |
|       ++case_id_;
 | |
|       total_line = "";
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   std::cout << "diff -u " << plan_after_tans_file << " " << plan_result_file << std::endl;
 | |
|   is_equal_content(plan_after_tans_file, plan_result_file);
 | |
|   std::cout << "diff -u " << stmt_after_trans_file << " " << stmt_result_file << std::endl;
 | |
|   is_equal_content(stmt_after_trans_file, stmt_result_file);
 | |
| }
 | |
| 
 | |
| TEST_F(TestRewrite, test_from_cmd)
 | |
| {
 | |
|   if (param.use_it_) {
 | |
|     test_from_cmd(param.rules_);
 | |
|     exit(0);
 | |
|   }
 | |
| }
 | |
| TEST_F(TestRewrite, transform_simply)
 | |
| {
 | |
|   // result has the transformed stmt and plan
 | |
|   const char* test_file = "./test_transformer_simplify.sql";
 | |
|   const char* stmt_after_trans_simplify_result_file = "./result/test_transformer_stmt_after_trans_simplify.result";
 | |
|   const char* stmt_after_trans_simplify_file = "./result/test_transformer_stmt_after_trans_simplify.tmp";
 | |
|   const char* stmt_no_trans_simplify_file = "./tmp/test_transformer_stmt_no_trans_simplify.tmp";
 | |
|   const char* plan_after_trans_simplify_result_file = "./result/test_transformer_plan_after_trans_simplify.result";
 | |
|   const char* plan_after_trans_simplify_file = "./result/test_transformer_plan_after_trans_simplify.tmp";
 | |
|   const char* plan_no_trans_simplify_file = "./tmp/test_transformer_plan_no_trans_simplify.tmp";
 | |
| 
 | |
|   int ret = OB_SUCCESS;
 | |
| 
 | |
|   ObPhysicalPlan* phy_plan = NULL;
 | |
|   ObCodeGeneratorImpl code_generator(exec_ctx_.get_min_cluster_version());
 | |
|   if (OB_FAIL(ObCacheObjectFactory::alloc(phy_plan, session_info_.get_effective_tenant_id()))) {
 | |
|   } else if (OB_ISNULL(phy_plan)) {
 | |
|     ret = OB_ERR_UNEXPECTED;
 | |
|     LOG_WARN("Failed to allocate phy plan", K(ret));
 | |
|   } else {
 | |
|     ctx_.phy_plan_ = phy_plan;
 | |
| 
 | |
|     ObTransformerImpl trans(&ctx_);
 | |
|     trans.set_needed_types(SIMPLIFY);
 | |
| 
 | |
|     run_test(trans,
 | |
|         test_file,
 | |
|         stmt_after_trans_simplify_result_file,
 | |
|         stmt_after_trans_simplify_file,
 | |
|         stmt_no_trans_simplify_file,
 | |
|         plan_after_trans_simplify_result_file,
 | |
|         plan_after_trans_simplify_file,
 | |
|         plan_no_trans_simplify_file,
 | |
|         true,
 | |
|         EXPLAIN_TRADITIONAL,
 | |
|         true);
 | |
|   }
 | |
|   OK(ret);
 | |
| }
 | |
| 
 | |
| TEST_F(TestRewrite, transform_set_op)
 | |
| {
 | |
|   // result has the transformed stmt and plan
 | |
|   const char* test_file = "./test_transformer_set_op.sql";
 | |
|   const char* stmt_after_trans_set_op_result_file = "./result/test_transformer_stmt_after_trans_set_op.result";
 | |
|   const char* stmt_after_trans_set_op_file = "./result/test_transformer_stmt_after_trans_set_op.tmp";
 | |
|   const char* stmt_no_trans_set_op_file = "./tmp/test_transformer_stmt_no_trans_set_op.tmp";
 | |
|   const char* plan_after_trans_set_op_result_file = "./result/test_transformer_plan_after_trans_set_op.result";
 | |
|   const char* plan_after_trans_set_op_file = "./result/test_transformer_plan_after_trans_set_op.tmp";
 | |
|   const char* plan_no_trans_set_op_file = "./tmp/test_transformer_plan_no_trans_set_op.tmp";
 | |
|   int ret = OB_SUCCESS;
 | |
| 
 | |
|   ObPhysicalPlan* phy_plan = NULL;
 | |
|   ObCodeGeneratorImpl code_generator(exec_ctx_.get_min_cluster_version());
 | |
|   if (OB_FAIL(ObCacheObjectFactory::alloc(phy_plan, session_info_.get_effective_tenant_id()))) {
 | |
|   } else if (OB_ISNULL(phy_plan)) {
 | |
|     ret = OB_ERR_UNEXPECTED;
 | |
|     LOG_WARN("Failed to allocate phy plan", K(ret));
 | |
|   } else {
 | |
|     ctx_.phy_plan_ = phy_plan;
 | |
| 
 | |
|     ObTransformerImpl trans(&ctx_);
 | |
|     trans.set_needed_types(SIMPLIFY | SET_OP);
 | |
| 
 | |
|     run_test(trans,
 | |
|         test_file,
 | |
|         stmt_after_trans_set_op_result_file,
 | |
|         stmt_after_trans_set_op_file,
 | |
|         stmt_no_trans_set_op_file,
 | |
|         plan_after_trans_set_op_result_file,
 | |
|         plan_after_trans_set_op_file,
 | |
|         plan_no_trans_set_op_file,
 | |
|         true,
 | |
|         EXPLAIN_TRADITIONAL,
 | |
|         true);
 | |
|   }
 | |
|   OK(ret);
 | |
| }
 | |
| 
 | |
| #ifndef tmptest
 | |
| 
 | |
| TEST_F(TestRewrite, transform_aggregate)
 | |
| {
 | |
|   // result has the transformed stmt and plan
 | |
|   const char* test_file = "./test_transformer_aggregate.sql";
 | |
|   const char* stmt_after_trans_aggr_result = "./result/test_transformer_stmt_after_trans_aggr.result";
 | |
|   const char* stmt_after_trans_aggr_file = "./result/test_transformer_stmt_after_trans_aggr.tmp";
 | |
|   const char* stmt_no_trans_aggr_file = "./tmp/test_transformer_stmt_no_trans_aggr.tmp";
 | |
|   const char* plan_after_trans_aggr_result_file = "./result/test_transformer_plan_after_trans_aggr.result";
 | |
|   const char* plan_after_trans_aggr_file = "./result/test_transformer_plan_after_trans_aggr.tmp";
 | |
|   const char* plan_no_trans_aggr_file = "./tmp/test_transformer_plan_no_trans_aggr.tmp";
 | |
|   int ret = OB_SUCCESS;
 | |
| 
 | |
|   ObPhysicalPlan* phy_plan = NULL;
 | |
|   ObCodeGeneratorImpl code_generator(exec_ctx_.get_min_cluster_version());
 | |
|   if (OB_FAIL(ObCacheObjectFactory::alloc(phy_plan, session_info_.get_effective_tenant_id()))) {
 | |
|   } else if (OB_ISNULL(phy_plan)) {
 | |
|     ret = OB_ERR_UNEXPECTED;
 | |
|     LOG_WARN("Failed to allocate phy plan", K(ret));
 | |
|   } else {
 | |
|     ctx_.phy_plan_ = phy_plan;
 | |
| 
 | |
|     ObTransformerImpl trans(&ctx_);
 | |
|     run_test(trans,
 | |
|         test_file,
 | |
|         stmt_after_trans_aggr_result,
 | |
|         stmt_after_trans_aggr_file,
 | |
|         stmt_no_trans_aggr_file,
 | |
|         plan_after_trans_aggr_result_file,
 | |
|         plan_after_trans_aggr_file,
 | |
|         plan_no_trans_aggr_file,
 | |
|         true,
 | |
|         EXPLAIN_TRADITIONAL);
 | |
|   }
 | |
|   OK(ret);
 | |
| }
 | |
| 
 | |
| // TEST_F(TestRewrite, view_merge) {
 | |
| //  // result has the transformed stmt and plan
 | |
| //  const char* test_file = "test_transformer_vm.sql";
 | |
| //  const char* stmt_merge_file = "./tmp/test_transformer_stmt_after_merge.tmp";
 | |
| //  const char* stmt_no_merge_file = "./tmp/test_transformer_stmt_no_merge.tmp";
 | |
| //  const char* plan_result_file = "./result/test_transformer_plan_after_view_merge.result";
 | |
| //  const char* plan_after_merge_file = "./result/test_transformer_plan_after_merge.tmp";
 | |
| //  const char* plan_no_merge_file = "./tmp/test_transformer_plan_no_merge.tmp";
 | |
| //  //do elimination and view merge together
 | |
| //  //ObTransformerImpl trans_all;
 | |
| //
 | |
| //  ObTransformerImpl trans(&ctx_);
 | |
| //  trans.clear_needed_type();
 | |
| //  trans.set_type_needed(SIMPLIFY);
 | |
| //  trans.set_type_needed(VIEW_MERGE);
 | |
| //
 | |
| //  run_test(trans, test_file, stmt_merge_file, stmt_no_merge_file,
 | |
| //      plan_result_file, plan_after_merge_file, plan_no_merge_file);
 | |
| //}
 | |
| 
 | |
| TEST_F(TestRewrite, query_push_down)
 | |
| {
 | |
|   // result has the transformed stmt and plan
 | |
|   const char* test_file = "test_transformer_query_push_down.sql";
 | |
|   const char* stmt_merge_result_file = "./result/test_transformer_stmt_after_query_push_down.result";
 | |
|   const char* stmt_merge_file = "./result/test_transformer_stmt_after_query_push_down.tmp";
 | |
|   const char* stmt_no_merge_file = "./tmp/test_transformer_stmt_no_query_push_down.tmp";
 | |
|   const char* plan_result_file = "./result/test_transformer_plan_after_query_push_down.result";
 | |
|   const char* plan_after_merge_file = "./result/test_transformer_plan_after_query_push_down.tmp";
 | |
|   const char* plan_no_merge_file = "./tmp/test_transformer_plan_no_query_push_down.tmp";
 | |
|   // do elimination and view merge together
 | |
|   // ObTransformerImpl trans_all;
 | |
|   int ret = OB_SUCCESS;
 | |
| 
 | |
|   ObPhysicalPlan* phy_plan = NULL;
 | |
|   ObCodeGeneratorImpl code_generator(exec_ctx_.get_min_cluster_version());
 | |
|   if (OB_FAIL(ObCacheObjectFactory::alloc(phy_plan, session_info_.get_effective_tenant_id()))) {
 | |
|   } else if (OB_ISNULL(phy_plan)) {
 | |
|     ret = OB_ERR_UNEXPECTED;
 | |
|     LOG_WARN("Failed to allocate phy plan", K(ret));
 | |
|   } else {
 | |
|     ctx_.phy_plan_ = phy_plan;
 | |
| 
 | |
|     ObTransformerImpl trans(&ctx_);
 | |
|     trans.set_needed_types(SIMPLIFY | QUERY_PUSH_DOWN);
 | |
|     run_test(trans,
 | |
|         test_file,
 | |
|         stmt_merge_result_file,
 | |
|         stmt_merge_file,
 | |
|         stmt_no_merge_file,
 | |
|         plan_result_file,
 | |
|         plan_after_merge_file,
 | |
|         plan_no_merge_file,
 | |
|         true,
 | |
|         EXPLAIN_TRADITIONAL);
 | |
|   }
 | |
|   OK(ret);
 | |
| }
 | |
| 
 | |
| /*
 | |
| static int pure_recusive_test(int64_t level, int64_t reserved_size = 10000000)
 | |
| {
 | |
|   int ret = OB_SUCCESS;
 | |
|   if (level < 1000) {
 | |
|     bool is_stack_overflow = false;
 | |
|     if (OB_FAIL(check_stack_overflow(is_stack_overflow, reserved_size))) {
 | |
|       LOG_WARN("failed to check", K(ret));
 | |
|     } else if (is_stack_overflow) {
 | |
|       ret = OB_SIZE_OVERFLOW;
 | |
|       LOG_WARN("stack overflow", K(ret), K(is_stack_overflow), K(level));
 | |
|     } else {
 | |
|       int64_t cur_level = level + 1;
 | |
|       char stack_mem[10 * 1000]; //test 10k/level stack mem
 | |
|       stack_mem[5000] = 'a';
 | |
|       UNUSED(stack_mem);
 | |
|       ret = pure_recusive_test(cur_level, reserved_size);
 | |
|     }
 | |
|   } else {
 | |
|     int64_t cur_level = level + 1;
 | |
|     LOG_INFO("leaf node quit", K(cur_level));
 | |
|   }
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| TEST_F(TestStackCheck, test_stack_check)
 | |
| {
 | |
|   const char* test_file = "./test_stack_check.sql";
 | |
|   size_t stack_size = 0;
 | |
|   pthread_attr_t attr;
 | |
|   void *stack_start = NULL;
 | |
|   OB_ASSERT(0 == pthread_getattr_np(pthread_self(), &attr));
 | |
|   OB_ASSERT(0 == pthread_attr_getstack(&attr, &stack_start, &stack_size));
 | |
|   LOG_INFO("stack size", K(stack_size));
 | |
|   int64_t original_reserved_stack_size = get_reserved_stack_size();
 | |
|   int64_t reserved_size = (static_cast<int64_t>(stack_size)) - 80 * 1000;
 | |
|   set_reserved_stack_size(reserved_size); //set stack limit to 80kb = 10485760 - 10405760;
 | |
|   run_fail_test_ret_as(test_file, OB_SIZE_OVERFLOW);
 | |
|   int sret = pure_recusive_test(1, reserved_size);
 | |
|   LOG_INFO("pure recursive output ", K(sret));
 | |
|   OB_ASSERT(OB_SIZE_OVERFLOW == sret);
 | |
|   set_reserved_stack_size(original_reserved_stack_size);
 | |
| }*/
 | |
| 
 | |
| /*
 | |
| TEST_F(TestStackCheck, test_resursive_level_check)
 | |
| {
 | |
|   const char* test_file = "./test_stack_level_check.sql";
 | |
|   int64 original_level = ObTransformer::get_max_recursive_level();
 | |
|   ObTransformer::set_max_recursive_level(10);
 | |
|   run_fail_test_ret_as(test_file, OB_NOT_SUPPORTED);
 | |
|   ObTransformer::set_max_recursive_level(original_level);
 | |
| } */
 | |
| 
 | |
| TEST_F(TestRewrite, eliminate_outer_join)
 | |
| {
 | |
|   const char* test_file = "./el.sql";
 | |
|   const char* stmt_el_result_file = "./result/test_transformer_stmt_after_el.result";
 | |
|   const char* stmt_el_file = "./result/test_transformer_stmt_after_el.tmp";
 | |
|   const char* stmt_no_el_file = "./tmp/test_transformer_stmt_no_el.tmp";
 | |
|   const char* plan_result_file = "./result/test_transformer_plan_after_el.result";
 | |
|   const char* plan_after_el_file = "./result/test_transformer_plan_after_el.tmp";
 | |
|   const char* plan_no_el_file = "./tmp/test_transformer_plan_no_el.tmp";
 | |
| 
 | |
|   int ret = OB_SUCCESS;
 | |
| 
 | |
|   ObPhysicalPlan* phy_plan = NULL;
 | |
|   ObCodeGeneratorImpl code_generator(exec_ctx_.get_min_cluster_version());
 | |
|   if (OB_FAIL(ObCacheObjectFactory::alloc(phy_plan, session_info_.get_effective_tenant_id()))) {
 | |
|   } else if (OB_ISNULL(phy_plan)) {
 | |
|     ret = OB_ERR_UNEXPECTED;
 | |
|     LOG_WARN("Failed to allocate phy plan", K(ret));
 | |
|   } else {
 | |
|     ctx_.phy_plan_ = phy_plan;
 | |
| 
 | |
|     ObTransformerImpl trans(&ctx_);
 | |
|     trans.set_needed_types(SIMPLIFY | ELIMINATE_OJ);
 | |
|     // ObTransformEliminateOuterJoin el_join(&ctx_);
 | |
|     run_test(trans,
 | |
|         test_file,
 | |
|         stmt_el_result_file,
 | |
|         stmt_el_file,
 | |
|         stmt_no_el_file,
 | |
|         plan_result_file,
 | |
|         plan_after_el_file,
 | |
|         plan_no_el_file,
 | |
|         true,
 | |
|         EXPLAIN_TRADITIONAL,
 | |
|         true);
 | |
|   }
 | |
|   OK(ret);
 | |
| }
 | |
| 
 | |
| TEST_F(TestRewrite, test_together)
 | |
| {
 | |
|   // test the transformimpl using outer-join elimination view merge and where pull up
 | |
|   const char* test_file = "./test_transformer_impl.sql";
 | |
|   const char* stmt_after_trans_result = "./result/test_transformer_stmt_after_together.result";
 | |
|   const char* stmt_after_trans = "./result/test_transformer_stmt_after_together.tmp";
 | |
|   const char* stmt_no_trans = "./tmp/test_transformer_stmt_no_together.tmp";
 | |
|   const char* plan_result_file = "./result/test_transformer_plan_after_together.result";
 | |
|   const char* plan_after_trans = "./result/test_transformer_plan_after_together.tmp";
 | |
|   const char* plan_no_trans = "./tmp/test_transformer_plan_no_together.tmp";
 | |
|   int ret = OB_SUCCESS;
 | |
| 
 | |
|   ObPhysicalPlan* phy_plan = NULL;
 | |
|   ObCodeGeneratorImpl code_generator(exec_ctx_.get_min_cluster_version());
 | |
|   if (OB_FAIL(ObCacheObjectFactory::alloc(phy_plan, session_info_.get_effective_tenant_id()))) {
 | |
|   } else if (OB_ISNULL(phy_plan)) {
 | |
|     ret = OB_ERR_UNEXPECTED;
 | |
|     LOG_WARN("Failed to allocate phy plan", K(ret));
 | |
|   } else {
 | |
|     ctx_.phy_plan_ = phy_plan;
 | |
| 
 | |
|     ObTransformerImpl trans_all(&ctx_);
 | |
|     //  run_test(trans_all, test_file, stmt_after_trans, stmt_no_trans, plan_result_file,
 | |
|     //      plan_after_trans, plan_no_trans);
 | |
|     if (!do_loop_test) {
 | |
|       run_test(trans_all,
 | |
|           test_file,
 | |
|           stmt_after_trans_result,
 | |
|           stmt_after_trans,
 | |
|           stmt_no_trans,
 | |
|           plan_result_file,
 | |
|           plan_after_trans,
 | |
|           plan_no_trans,
 | |
|           true,
 | |
|           EXPLAIN_TRADITIONAL,
 | |
|           true);
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| TEST_F(TestRewrite, transform_outline)
 | |
| {
 | |
|   // result has the transformed stmt and plan
 | |
|   // system("rm -rf test_transformer_outline.sql && cat *.sql > test_transformer_outline.test && mv
 | |
|   // test_transformer_outline.test test_transformer_outline.sql");
 | |
|   system("cat test_transformer_subquery_pullup.sql test_transformer_vm.sql > test_transformer_outline.sql");
 | |
|   const char* test_file = "./test_transformer_outline.sql";
 | |
|   const char* stmt_after_trans_aggr_file_result = "./result/test_transformer_stmt_trans_outline.result";
 | |
|   const char* stmt_after_trans_aggr_file = "./result/test_transformer_stmt_trans_outline.tmp";
 | |
|   const char* stmt_no_trans_aggr_file = "./tmp/test_transformer_stmt_no_trans_outline.tmp";
 | |
|   const char* plan_after_trans_aggr_result_file = "./result/test_transformer_plan_after_trans_outline.result";
 | |
|   const char* plan_after_trans_aggr_file = "./result/test_transformer_plan_after_trans_outline.tmp";
 | |
|   const char* plan_no_trans_aggr_file = "./tmp/test_transformer_plan_no_trans_outline.tmp";
 | |
|   int ret = OB_SUCCESS;
 | |
| 
 | |
|   ObPhysicalPlan* phy_plan = NULL;
 | |
|   ObCodeGeneratorImpl code_generator(exec_ctx_.get_min_cluster_version());
 | |
|   if (OB_FAIL(ObCacheObjectFactory::alloc(phy_plan, session_info_.get_effective_tenant_id()))) {
 | |
|   } else if (OB_ISNULL(phy_plan)) {
 | |
|     ret = OB_ERR_UNEXPECTED;
 | |
|     LOG_WARN("Failed to allocate phy plan", K(ret));
 | |
|   } else {
 | |
|     ctx_.phy_plan_ = phy_plan;
 | |
| 
 | |
|     ObTransformerImpl trans_all(&ctx_);
 | |
|     run_test(trans_all,
 | |
|         test_file,
 | |
|         stmt_after_trans_aggr_file_result,
 | |
|         stmt_after_trans_aggr_file,
 | |
|         stmt_no_trans_aggr_file,
 | |
|         plan_after_trans_aggr_result_file,
 | |
|         plan_after_trans_aggr_file,
 | |
|         plan_no_trans_aggr_file,
 | |
|         true,
 | |
|         EXPLAIN_OUTLINE,
 | |
|         true);
 | |
|   }
 | |
|   OK(ret);
 | |
| }
 | |
| #endif
 | |
| 
 | |
| #ifdef tmptest
 | |
| // TEST_F(TestRewrite, tmp_test)
 | |
| // {
 | |
| //   // test the transformimpl using outer-join elimination view merge and where pull up
 | |
| //   const char* test_file = "./test_transformer_temp_test.sql";
 | |
| //   const char* stmt_after_trans = "./tmp/test_transformer_stmt_after_tmptest.tmp";
 | |
| //   const char* stmt_no_trans = "./tmp/test_transformer_stmt_no_tmptest.tmp";
 | |
| //   const char* plan_result_file = "./result/test_transformer_plan_result_tmptest.tmp";
 | |
| //   const char* plan_after_trans = "./result/test_transformer_plan_after_tmptest.tmp";
 | |
| //   const char* plan_no_trans = "./tmp/test_transformer_plan_no_tmptest.tmp";
 | |
| //   //ObTransformViewMerge trans_all(&allocator_);
 | |
| //   ObTransformerImpl trans(&ctx_);
 | |
| //   trans.clear_needed_type();
 | |
| //   trans.set_type_needed(SIMPLIFY);
 | |
| //   trans.set_type_needed(ELIMINATE_OJ);
 | |
| //   run_test(trans, test_file, stmt_after_trans, stmt_no_trans, plan_result_file,
 | |
| //            plan_after_trans, plan_no_trans);
 | |
| 
 | |
| // }
 | |
| #endif
 | |
| 
 | |
| /*TEST_F(TestRewrite, trans_win_magic)*/
 | |
| //{
 | |
| //// result has the transformed stmt and plan
 | |
| // const char* test_file = "./test_transformer_win_magic.sql";
 | |
| // const char* stmt_win_magic_result_file = "./result/test_transformer_stmt_win_magic.result";
 | |
| // const char* stmt_win_magic_file = "./result/test_transformer_stmt_win_magic.tmp";
 | |
| // const char* stmt_no_win_magic_file = "./tmp/test_transformer_stmt_no_win_magic.tmp";
 | |
| // const char* plan_result_file = "./result/test_transformer_plan_after_win_magic.result";
 | |
| // const char* plan_after_win_magic_file = "./result/test_transformer_plan_after_win_magic.tmp";
 | |
| // const char* plan_no_win_magic_file = "./tmp/test_transformer_plan_no_win_magic.tmp";
 | |
| // ObTransformerImpl trans(&ctx_);
 | |
| // trans.clear_needed_type();
 | |
| // trans.set_type_needed(SIMPLIFY);
 | |
| // trans.set_type_needed(WIN_MAGIC);
 | |
| // run_test(trans, test_file,
 | |
| // stmt_win_magic_result_file,
 | |
| // stmt_win_magic_file,
 | |
| // stmt_no_win_magic_file,
 | |
| // plan_result_file,
 | |
| // plan_after_win_magic_file,
 | |
| // plan_no_win_magic_file,
 | |
| // true,
 | |
| // EXPLAIN_TRADITIONAL,
 | |
| // true);
 | |
| /*}*/
 | |
| 
 | |
| void TestRewrite::test_from_cmd(uint64_t rules)
 | |
| {
 | |
|   while (true) {
 | |
|     int ret = OB_SUCCESS;
 | |
| 
 | |
|     ObPhysicalPlan* phy_plan = NULL;
 | |
|     ObCodeGeneratorImpl code_generator(exec_ctx_.get_min_cluster_version());
 | |
|     if (OB_FAIL(ObCacheObjectFactory::alloc(phy_plan, session_info_.get_effective_tenant_id()))) {
 | |
|     } else if (OB_ISNULL(phy_plan)) {
 | |
|       ret = OB_ERR_UNEXPECTED;
 | |
|       LOG_WARN("Failed to allocate phy plan", K(ret));
 | |
|     } else {
 | |
|       ctx_.phy_plan_ = phy_plan;
 | |
|     }
 | |
| 
 | |
|     ObTransformerImpl trans(&ctx_);
 | |
|     trans.set_needed_types(rules);
 | |
|     std::string sql;
 | |
|     std::cout << "Please Input SQL: \n>";
 | |
|     if (getline(std::cin, sql)) {
 | |
|       std::cout << "SQL=>" << sql.c_str() << std::endl;
 | |
|       bool do_generate_plan = true;
 | |
|       int ret = OB_SUCCESS;
 | |
|       for (int i = 0; i < 2 && OB_SUCC(ret); ++i) {
 | |
|         bool do_trans = 1 == i % 2;
 | |
|         ObDMLStmt* stmt = NULL;
 | |
|         ObLogPlan* logical_plan = NULL;
 | |
|         ret = gen_stmt_and_plan(trans, sql.c_str(), stmt, logical_plan, do_trans, do_generate_plan);
 | |
|         if (OB_SUCC(ret)) {
 | |
|           std::cout << "stmt: " << CSJ(stmt) << std::endl;
 | |
|           if (do_generate_plan) {
 | |
|             char buf[BUF_LEN];
 | |
|             memset(buf, '\0', BUF_LEN);
 | |
|             logical_plan->to_string(buf, BUF_LEN, EXPLAIN_TRADITIONAL);
 | |
|             std::cout << "plan: " << buf << std::endl;
 | |
|           }
 | |
|         } else {
 | |
|           std::cout << "generate failed, do_trans: " << do_trans << std::endl;
 | |
|         }
 | |
|         //        trans.reset();
 | |
|         // release the memory allocated
 | |
|         stmt_factory_.destory();
 | |
|         expr_factory_.destory();
 | |
|         log_plan_factory_.destroy();
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| }  // namespace test
 | |
| 
 | |
| static bool do_tmp_test = false;
 | |
| 
 | |
| int main(int argc, char** argv)
 | |
| {
 | |
|   int ret = 0;
 | |
|   ContextParam param;
 | |
|   param.set_mem_attr(1001, 0, ObCtxIds::WORK_AREA).set_page_size(OB_MALLOC_BIG_BLOCK_SIZE);
 | |
| 
 | |
|   system("rm -rf test_transformer.log");
 | |
|   observer::ObReqTimeGuard req_timeinfo_guard;
 | |
|   OB_LOGGER.set_log_level("INFO");
 | |
|   OB_LOGGER.set_file_name("test_transformer.log", true);
 | |
|   ::testing::InitGoogleTest(&argc, argv);
 | |
|   init_sql_factories();
 | |
|   if (argc >= 2) {
 | |
|     if (strcmp("DEBUG", argv[1]) == 0 || strcmp("WARN", argv[1]) == 0 || strcmp("INFO", argv[1]) == 0) {
 | |
|       OB_LOGGER.set_log_level(argv[1]);
 | |
|     } else if (strcmp("TMP", argv[1]) == 0) {
 | |
|       do_tmp_test = true;
 | |
|     }
 | |
|   } else {
 | |
|     OB_LOGGER.set_log_level("INFO");
 | |
|   }
 | |
|   test::TestTransUtils::parse_cmd(argc, argv, test::param);
 | |
|   std::cout << test::param.rules_ << std::endl;
 | |
| 
 | |
|   CREATE_WITH_TEMP_CONTEXT(param)
 | |
|   {
 | |
|     ret = RUN_ALL_TESTS();
 | |
|   }
 | |
|   return ret;
 | |
| }
 | 
