 f8c5c2647f
			
		
	
	f8c5c2647f
	
	
	
		
			
			Co-authored-by: Charles0429 <xiezhenjiang@gmail.com> Co-authored-by: tino247 <tino247@126.com> Co-authored-by: chaser-ch <chaser.ch@antgroup.com>
		
			
				
	
	
		
			252 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			252 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /**
 | |
|  * Copyright (c) 2021 OceanBase
 | |
|  * OceanBase CE is licensed under Mulan PubL v2.
 | |
|  * You can use this software according to the terms and conditions of the Mulan PubL v2.
 | |
|  * You may obtain a copy of Mulan PubL v2 at:
 | |
|  *          http://license.coscl.org.cn/MulanPubL-2.0
 | |
|  * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 | |
|  * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 | |
|  * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 | |
|  * See the Mulan PubL v2 for more details.
 | |
|  */
 | |
| 
 | |
| #include "sql/parser/ob_parser.h"
 | |
| #include "sql/parser/ob_fast_parser.h"
 | |
| #include <gtest/gtest.h>
 | |
| #include "lib/worker.h"
 | |
| #include "lib/allocator/page_arena.h"
 | |
| #include <fstream>
 | |
| #include <iterator>
 | |
| #include <vector>
 | |
| #include <string>
 | |
| #include <iostream>
 | |
| 
 | |
| using namespace oceanbase;
 | |
| using namespace oceanbase::common;
 | |
| using namespace oceanbase::sql;
 | |
| 
 | |
| namespace test {
 | |
| class TestFastParser
 | |
| {
 | |
| public:
 | |
|   TestFastParser();
 | |
|   ~TestFastParser();
 | |
|   int load_sql(const std::string file_path, std::vector<std::string> &sql_array);
 | |
|   int parse(const ObString &sql);
 | |
|   bool compare_parser_result(
 | |
|        const ParseResult &parse_result, 
 | |
|        const char *no_param_sql_ptr, 
 | |
|        const int64_t no_param_sql_len,
 | |
|        ParamList *p_list,
 | |
|        const int64_t param_num);
 | |
|     
 | |
| private:
 | |
|   ObArenaAllocator allocator_;
 | |
| private:
 | |
|   DISALLOW_COPY_AND_ASSIGN(TestFastParser);
 | |
| };
 | |
| 
 | |
| TestFastParser::TestFastParser()
 | |
|   : allocator_(ObModIds::TEST)
 | |
| {
 | |
| 
 | |
| }
 | |
| 
 | |
| TestFastParser::~TestFastParser()
 | |
| {
 | |
| 
 | |
| }
 | |
| 
 | |
| 
 | |
| int TestFastParser::load_sql(const std::string file_path, std::vector<std::string> &sql_array)
 | |
| {
 | |
|   int ret = OB_SUCCESS;
 | |
|   std::ifstream in(file_path);
 | |
|   if (!in.is_open()) {
 | |
|     ret = OB_ERROR;
 | |
|     SQL_PC_LOG(ERROR, "failed to open file");
 | |
|   }
 | |
|   std::string line;
 | |
|   while (std::getline(in, line)) {
 | |
|     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 sql = line.substr(begin, end - begin + 1);
 | |
|     sql_array.push_back(sql);
 | |
|   }
 | |
|   in.close();
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| bool TestFastParser::compare_parser_result(
 | |
|      const ParseResult &parse_result, 
 | |
|      const char *no_param_sql_ptr, 
 | |
|      const int64_t no_param_sql_len,
 | |
|      ParamList *p_list,
 | |
|      const int64_t param_num)
 | |
| {
 | |
|   int ret = OB_SUCCESS;
 | |
|   int64_t cmp_param_num = parse_result.param_node_num_;
 | |
|   char *cmp_no_param_sql_ptr = parse_result.no_param_sql_;
 | |
|   int64_t cmp_no_param_sql_len = parse_result.no_param_sql_len_;
 | |
|   ParamList *cmp_p_list = parse_result.param_nodes_;
 | |
|   if (param_num != cmp_param_num) {
 | |
|     SQL_PC_LOG(ERROR, "param_num diff", K(param_num), K(cmp_param_num),
 | |
|     K(ObString(no_param_sql_len, no_param_sql_ptr)),
 | |
|     K(ObString(cmp_no_param_sql_len, cmp_no_param_sql_ptr)));
 | |
|     return false;
 | |
|   } else if (cmp_no_param_sql_len != no_param_sql_len) {
 | |
|     SQL_PC_LOG(ERROR, "param sql len diff", K(no_param_sql_len), K(cmp_no_param_sql_len),
 | |
|     K(ObString(no_param_sql_len, no_param_sql_ptr)),
 | |
|     K(ObString(cmp_no_param_sql_len, cmp_no_param_sql_ptr)));
 | |
|     return false;
 | |
|   } else {
 | |
|     if (0 != (strncmp(no_param_sql_ptr, cmp_no_param_sql_ptr, no_param_sql_len))) {
 | |
|       SQL_PC_LOG(ERROR, "no_param_sql diff",
 | |
|               K(ObString(no_param_sql_len, no_param_sql_ptr)),
 | |
|               K(ObString(cmp_no_param_sql_len, cmp_no_param_sql_ptr)));
 | |
|       return false;
 | |
|     } else {
 | |
|       ParamList *fp_p_list = p_list;
 | |
|       for (int64_t i = 0; i < param_num && NULL != fp_p_list; i++) {
 | |
|         if (fp_p_list->node_->type_ != cmp_p_list->node_->type_) {
 | |
|           SQL_PC_LOG(ERROR, "type diff", K(fp_p_list->node_->type_), K(cmp_p_list->node_->type_), K(i),
 | |
|           K(fp_p_list->node_->value_), K(cmp_p_list->node_->value_));
 | |
|           return false;
 | |
|         } else if (fp_p_list->node_->num_child_ != cmp_p_list->node_->num_child_) {
 | |
|           SQL_PC_LOG(ERROR, "num child diff", K(fp_p_list->node_->num_child_), K(cmp_p_list->node_->num_child_), K(i));
 | |
|           return false;
 | |
|         } else if (fp_p_list->node_->is_neg_ != cmp_p_list->node_->is_neg_) {
 | |
|           SQL_PC_LOG(ERROR, "neg diff", K(fp_p_list->node_->is_neg_), K(cmp_p_list->node_->is_neg_), K(i));
 | |
|           return false;
 | |
|         } else if (fp_p_list->node_->is_hidden_const_ != cmp_p_list->node_->is_hidden_const_) {
 | |
|           SQL_PC_LOG(ERROR, "hidden const diff", K(fp_p_list->node_->is_hidden_const_), K(cmp_p_list->node_->is_hidden_const_), K(i));
 | |
|           return false;
 | |
|         } else if (fp_p_list->node_->is_tree_not_param_ != cmp_p_list->node_->is_tree_not_param_) {
 | |
|           SQL_PC_LOG(ERROR, "not param diff", K(fp_p_list->node_->is_tree_not_param_), K(cmp_p_list->node_->is_tree_not_param_), K(i));
 | |
|           return false;
 | |
|         } else if (fp_p_list->node_->length_semantics_ != cmp_p_list->node_->length_semantics_) {
 | |
|           SQL_PC_LOG(ERROR, "length semantics diff", K(fp_p_list->node_->length_semantics_), K(cmp_p_list->node_->length_semantics_), K(i));
 | |
|           return false;
 | |
|         } else if (fp_p_list->node_->is_val_paramed_item_idx_ != cmp_p_list->node_->is_val_paramed_item_idx_) {
 | |
|           SQL_PC_LOG(ERROR, "val paramed item idx diff", K(fp_p_list->node_->is_val_paramed_item_idx_), K(cmp_p_list->node_->is_val_paramed_item_idx_), K(i));
 | |
|           return false;
 | |
|         } else if (fp_p_list->node_->is_copy_raw_text_ != cmp_p_list->node_->is_copy_raw_text_) {
 | |
|           SQL_PC_LOG(ERROR, "copy row text diff", K(fp_p_list->node_->is_copy_raw_text_), K(cmp_p_list->node_->is_copy_raw_text_), K(i));
 | |
|           return false;
 | |
|         } else if (fp_p_list->node_->is_column_varchar_ != cmp_p_list->node_->is_column_varchar_) {
 | |
|           SQL_PC_LOG(ERROR, "column varchar diff", K(fp_p_list->node_->is_column_varchar_), K(cmp_p_list->node_->is_column_varchar_), K(i));
 | |
|           return false;
 | |
|         } else if (fp_p_list->node_->is_assigned_from_child_ != cmp_p_list->node_->is_assigned_from_child_) {
 | |
|           SQL_PC_LOG(ERROR, "assigned from child diff", K(fp_p_list->node_->is_assigned_from_child_), K(cmp_p_list->node_->is_assigned_from_child_), K(i));
 | |
|           return false;
 | |
|         } else if (fp_p_list->node_->is_trans_from_minus_ != cmp_p_list->node_->is_trans_from_minus_) {
 | |
|           SQL_PC_LOG(ERROR, "is trans from minus diff", K(fp_p_list->node_->is_trans_from_minus_), K(cmp_p_list->node_->is_trans_from_minus_), K(i));
 | |
|           return false;
 | |
|         } else if (fp_p_list->node_->is_num_must_be_pos_ != cmp_p_list->node_->is_num_must_be_pos_) {
 | |
|           SQL_PC_LOG(ERROR, "is num must be pos diff", K(fp_p_list->node_->is_num_must_be_pos_), K(cmp_p_list->node_->is_num_must_be_pos_), K(i));
 | |
|           return false;
 | |
|         } else if (fp_p_list->node_->value_ != cmp_p_list->node_->value_) {
 | |
|           SQL_PC_LOG(ERROR, "value diff", K(fp_p_list->node_->value_), K(cmp_p_list->node_->value_), K(i));
 | |
|           return false;
 | |
|         } else if (fp_p_list->node_->pos_ != cmp_p_list->node_->pos_) {
 | |
|           SQL_PC_LOG(ERROR, "pos diff", K(fp_p_list->node_->pos_), K(cmp_p_list->node_->pos_), K(i));
 | |
|           return false;
 | |
|         } else if (fp_p_list->node_->text_len_ != cmp_p_list->node_->text_len_) {
 | |
|           SQL_PC_LOG(ERROR, "text len diff", K(fp_p_list->node_->text_len_), K(cmp_p_list->node_->text_len_), K(i));
 | |
|           return false;
 | |
|         } else if (0 != strncmp(fp_p_list->node_->raw_text_,
 | |
|                                 cmp_p_list->node_->raw_text_,
 | |
|                                 fp_p_list->node_->text_len_)) {
 | |
|           SQL_PC_LOG(ERROR, "raw_text diff", K(i), K(ObString(fp_p_list->node_->text_len_, fp_p_list->node_->raw_text_)),
 | |
|           K(ObString(fp_p_list->node_->text_len_, cmp_p_list->node_->raw_text_)));
 | |
|           return false;
 | |
|         } else if (fp_p_list->node_->str_len_ != cmp_p_list->node_->str_len_) {
 | |
|           SQL_PC_LOG(ERROR, "str len diff", K(fp_p_list->node_->str_len_), K(cmp_p_list->node_->str_len_), K(i));
 | |
|           return false;
 | |
|         } else if (0 != strncmp(fp_p_list->node_->str_value_,
 | |
|                                 cmp_p_list->node_->str_value_,
 | |
|                                 fp_p_list->node_->str_len_)) {
 | |
|           SQL_PC_LOG(ERROR, "str value diff", K(i), K(ObString(fp_p_list->node_->str_len_, fp_p_list->node_->str_value_)),
 | |
|           K(ObString(fp_p_list->node_->str_len_, cmp_p_list->node_->str_value_)));
 | |
|           return false;
 | |
|         } else if (fp_p_list->node_->raw_param_idx_ != cmp_p_list->node_->raw_param_idx_) {
 | |
|           SQL_PC_LOG(ERROR, "raw param idx diff",
 | |
|                   K(fp_p_list->node_->raw_param_idx_), K(cmp_p_list->node_->raw_param_idx_), K(i));
 | |
|           return false;
 | |
|         } else {
 | |
|           fp_p_list = fp_p_list->next_;
 | |
|           cmp_p_list = cmp_p_list->next_;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| int TestFastParser::parse(const ObString &sql)
 | |
| {
 | |
|   ObSQLMode mode = SMO_DEFAULT;
 | |
|   ParseResult parse_result;
 | |
|   ObCollationType connection_collation = CS_TYPE_UTF8MB4_GENERAL_CI;
 | |
|   if (lib::is_oracle_mode()) {
 | |
|     parse_result.sql_mode_ = (DEFAULT_ORACLE_MODE | SMO_ORACLE);
 | |
|     mode = (DEFAULT_ORACLE_MODE | SMO_ORACLE);
 | |
|   } else {
 | |
|     parse_result.sql_mode_ = DEFAULT_MYSQL_MODE;
 | |
|     mode = DEFAULT_MYSQL_MODE;
 | |
|   }
 | |
|   ObParser parser(allocator_, mode, connection_collation);
 | |
|   MEMSET(&parse_result, 0, sizeof(parse_result));
 | |
|   int ret1 = parser.parse(sql, parse_result, FP_MODE);
 | |
|   int64_t param_num = 0;
 | |
|   char *no_param_sql_ptr = NULL;
 | |
|   int64_t no_param_sql_len = 0;
 | |
|   ParamList *p_list = NULL; 
 | |
|   FPContext fp_ctx(connection_collation);
 | |
|   fp_ctx.enable_batched_multi_stmt_ = false;
 | |
|   fp_ctx.is_udr_mode_ = false;
 | |
|   int ret2 = ObFastParser::parse(sql, fp_ctx, allocator_,
 | |
|     no_param_sql_ptr, no_param_sql_len, p_list, param_num);
 | |
|   if ((OB_SUCCESS == ret1) != (OB_SUCCESS == ret2)) {
 | |
|     SQL_PC_LOG_RET(ERROR, OB_ERROR, "parser results are not equal", K(ret1), K(ret2), K(sql));
 | |
|     return OB_ERROR;
 | |
|   }
 | |
|   if (OB_SUCCESS == ret1) {
 | |
|     bool is_same = compare_parser_result(parse_result, no_param_sql_ptr,
 | |
|                                          no_param_sql_len, p_list, param_num);
 | |
|     return is_same ? OB_SUCCESS : OB_ERROR;
 | |
|   }
 | |
|   return OB_SUCCESS;
 | |
| }
 | |
| 
 | |
| void run()
 | |
| {
 | |
|   int ret = OB_SUCCESS;
 | |
|   const std::string file_path = "test_fast_parser.sql";
 | |
|   std::vector<std::string> sql_array;
 | |
|   TestFastParser fast_parser;
 | |
|   fast_parser.load_sql(file_path, sql_array);
 | |
|   for (uint32_t i = 0; i < sql_array.size(); i++) {
 | |
|     ObString sql = ObString::make_string(sql_array.at(i).c_str());
 | |
|     if (OB_FAIL(fast_parser.parse(sql))) {
 | |
|       SQL_PC_LOG(ERROR, "parser failed", K(sql));
 | |
|     }
 | |
|   }
 | |
| }
 | |
| }
 | |
| 
 | |
| int main(int argc, char **argv)
 | |
| {
 | |
|   UNUSED(argc);
 | |
|   UNUSED(argv);
 | |
|   OB_LOGGER.set_log_level("ERROR");
 | |
|   OB_LOGGER.set_file_name("test_fast_parser.log", false);
 | |
|   set_compat_mode(lib::Worker::CompatMode::MYSQL);
 | |
|   ::test::run();
 | |
|   set_compat_mode(lib::Worker::CompatMode::ORACLE);
 | |
|   ::test::run();
 | |
|   return 0;
 | |
| }
 |