251 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			251 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)
 | 
						|
{
 | 
						|
  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(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;
 | 
						|
}
 |