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;
|
|
}
|