[FEAT MERGE]implement user-defined rewrite rules

This commit is contained in:
obdev
2022-12-30 08:10:42 +00:00
committed by ob-robot
parent 21c0bac716
commit 9dcc0a529e
100 changed files with 5540 additions and 315 deletions

View File

@ -12,6 +12,7 @@
#define USING_LOG_PREFIX SQL_PARSER
#include "ob_fast_parser.h"
#include "sql/udr/ob_udr_struct.h"
#include "share/ob_define.h"
#include "lib/ash/ob_active_session_guard.h"
#include "lib/worker.h"
@ -30,24 +31,22 @@ do { \
} while (0)
int ObFastParser::parse(const common::ObString &stmt,
const bool enable_batched_multi_stmt,
const FPContext &fp_ctx,
common::ObIAllocator &allocator,
char *&no_param_sql,
int64_t &no_param_sql_len,
ParamList *&param_list,
int64_t &param_num,
ObCollationType connection_collation,
common::ObIAllocator &allocator,
ObSQLMode sql_mode /* default = 0*/)
int64_t &param_num)
{
ObActiveSessionGuard::get_stat().in_parse_ = true;
int ret = OB_SUCCESS;
if (!lib::is_oracle_mode()) {
ObFastParserMysql fp(allocator, connection_collation, enable_batched_multi_stmt, sql_mode);
ObFastParserMysql fp(allocator, fp_ctx);
if (OB_FAIL(fp.parse(stmt, no_param_sql, no_param_sql_len, param_list, param_num))) {
LOG_WARN("failed to fast parser", K(stmt));
}
} else {
ObFastParserOracle fp(allocator, connection_collation, enable_batched_multi_stmt);
ObFastParserOracle fp(allocator, fp_ctx);
if (OB_FAIL(fp.parse(stmt, no_param_sql, no_param_sql_len, param_list, param_num))) {
LOG_WARN("failed to fast parser", K(stmt));
}
@ -56,6 +55,36 @@ int ObFastParser::parse(const common::ObString &stmt,
return ret;
}
int ObFastParser::parse(const common::ObString &stmt,
const FPContext &fp_ctx,
common::ObIAllocator &allocator,
char *&no_param_sql,
int64_t &no_param_sql_len,
ParamList *&param_list,
int64_t &param_num,
ObQuestionMarkCtx &ctx)
{
ObActiveSessionGuard::get_stat().in_parse_ = true;
int ret = OB_SUCCESS;
if (!lib::is_oracle_mode()) {
ObFastParserMysql fp(allocator, fp_ctx);
if (OB_FAIL(fp.parse(stmt, no_param_sql, no_param_sql_len, param_list, param_num))) {
LOG_WARN("failed to fast parser", K(stmt));
} else {
ctx = fp.get_question_mark_ctx();
}
} else {
ObFastParserOracle fp(allocator, fp_ctx);
if (OB_FAIL(fp.parse(stmt, no_param_sql, no_param_sql_len, param_list, param_num))) {
LOG_WARN("failed to fast parser", K(stmt));
} else {
ctx = fp.get_question_mark_ctx();
}
}
ObActiveSessionGuard::get_stat().in_parse_ = false;
return ret;
}
inline int64_t ObFastParserBase::ObRawSql::strncasecmp(
int64_t pos, const char *str, const int64_t size)
{
@ -75,11 +104,12 @@ inline int64_t ObFastParserBase::ObRawSql::strncasecmp(
ObFastParserBase::ObFastParserBase(
ObIAllocator &allocator,
const ObCollationType connection_collation,
const bool enable_batched_multi_stmt) :
const FPContext fp_ctx) :
no_param_sql_(nullptr), no_param_sql_len_(0),
param_num_(0), is_oracle_mode_(false),
is_batched_multi_stmt_split_on_(enable_batched_multi_stmt),
is_batched_multi_stmt_split_on_(fp_ctx.enable_batched_multi_stmt_),
is_udr_mode_(fp_ctx.is_udr_mode_),
def_name_ctx_(fp_ctx.def_name_ctx_),
is_mysql_compatible_comment_(false),
cur_token_begin_pos_(0), copy_begin_pos_(0), copy_end_pos_(0),
tmp_buf_(nullptr), tmp_buf_len_(0), last_escape_check_pos_(0),
@ -88,11 +118,12 @@ ObFastParserBase::ObFastParserBase(
parse_next_token_func_(nullptr), process_idf_func_(nullptr)
{
question_mark_ctx_.count_ = 0;
question_mark_ctx_.capacity_ = 0;
question_mark_ctx_.by_ordinal_ = false;
question_mark_ctx_.by_name_ = false;
question_mark_ctx_.name_ = nullptr;
charset_type_ = ObCharset::charset_type_by_coll(connection_collation);
charset_info_ = ObCharset::get_charset(connection_collation);
charset_type_ = ObCharset::charset_type_by_coll(fp_ctx.conn_coll_);
charset_info_ = ObCharset::get_charset(fp_ctx.conn_coll_);
}
int ObFastParserBase::parse(const ObString &stmt,
@ -850,6 +881,25 @@ int64_t ObFastParserBase::get_question_mark(ObQuestionMarkCtx *ctx,
return idx;
}
int64_t ObFastParserBase::get_question_mark_by_defined_name(QuestionMarkDefNameCtx *ctx,
const char *name,
const int64_t name_len)
{
int64_t idx = -1;
if (OB_UNLIKELY(NULL == ctx || NULL == name)) {
(void)fprintf(stderr, "ERROR question mark ctx or name is NULL\n");
} else if (ctx->name_ != NULL) {
for (int64_t i = 0; -1 == idx && i < ctx->count_; ++i) {
if (NULL == ctx->name_[i]) {
(void)fprintf(stderr, "ERROR name_ in question mark ctx is null\n");
} else if (0 == STRNCASECMP(ctx->name_[i], name, name_len)) {
idx = i;
}
}
}
return idx;
}
inline char* ObFastParserBase::parse_strndup(const char *str, size_t nbyte, char *buf)
{
MEMMOVE(buf, str, nbyte);
@ -1293,8 +1343,11 @@ int ObFastParserBase::process_question_mark()
cur_token_type_ = PARAM_TOKEN;
int64_t need_mem_size = FIEXED_PARAM_NODE_SIZE;
int64_t text_len = raw_sql_.cur_pos_ - cur_token_begin_pos_;
// allocate all the memory needed at once
if (OB_ISNULL(buf = static_cast<char *>(allocator_.alloc(need_mem_size)))) {
if (question_mark_ctx_.by_name_) {
ret = OB_ERR_PARSER_SYNTAX;
LOG_WARN("parser syntax error", K(ret), K(raw_sql_.to_string()), K_(raw_sql_.cur_pos));
} else if (OB_ISNULL(buf = static_cast<char *>(allocator_.alloc(need_mem_size)))) {
// allocate all the memory needed at once
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("fail to alloc memory", K(ret), K(need_mem_size));
} else {
@ -1309,6 +1362,72 @@ int ObFastParserBase::process_question_mark()
return ret;
}
int ObFastParserBase::process_ps_statement()
{
int ret = OB_SUCCESS;
char *buf = nullptr;
cur_token_type_ = PARAM_TOKEN;
char ch = raw_sql_.char_at(raw_sql_.cur_pos_);
bool is_num = is_digit(ch) ? true : false;
if (is_num) { // ":"{int_num}
ch = raw_sql_.scan();
while (is_digit(ch)) {
ch = raw_sql_.scan();
}
} else {
int64_t next_idf_pos = raw_sql_.cur_pos_;
while (-1 != (next_idf_pos = is_identifier_flags(next_idf_pos))) {
raw_sql_.cur_pos_ = next_idf_pos;
}
}
int64_t need_mem_size = FIEXED_PARAM_NODE_SIZE;
int64_t text_len = raw_sql_.cur_pos_ - cur_token_begin_pos_;
need_mem_size += (text_len + 1);
if (question_mark_ctx_.by_ordinal_) {
ret = OB_ERR_PARSER_SYNTAX;
LOG_WARN("parser syntax error", K(ret), K(raw_sql_.to_string()), K_(raw_sql_.cur_pos));
} else if (OB_ISNULL(buf = static_cast<char *>(allocator_.alloc(need_mem_size)))) {
// allocate all the memory needed at once
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("fail to alloc memory", K(ret), K(need_mem_size));
} else {
ParseNode *node = new_node(buf, T_QUESTIONMARK);
node->text_len_ = text_len;
node->raw_text_ = raw_sql_.ptr(cur_token_begin_pos_);
if (is_num) {
if (is_udr_mode_) {
ret = OB_NOT_SUPPORTED;
LOG_USER_ERROR(OB_NOT_SUPPORTED, "question mark by number");
LOG_WARN("question mark by number not supported", K(ret));
} else {
node->value_ = strtoll(&node->raw_text_[1], NULL, 10);
}
} else {
int64_t ind = -1;
if (is_udr_mode_ && nullptr != def_name_ctx_) {
ind = get_question_mark_by_defined_name(def_name_ctx_, node->raw_text_, text_len);
} else {
ind = get_question_mark(&question_mark_ctx_, &allocator_,
node->raw_text_, text_len, buf);
}
node->value_ = ind;
// buf points to the beginning of the next available memory
buf += text_len + 1;
question_mark_ctx_.by_name_ = true;
}
if (OB_SUCC(ret)) {
if (node->value_ < 0) {
ret = OB_ERR_PARSER_SYNTAX;
LOG_WARN("parser syntax error", K(ret), K(raw_sql_.to_string()), K_(raw_sql_.cur_pos));
} else {
node->raw_sql_offset_ = cur_token_begin_pos_;
lex_store_param(node, buf);
}
}
}
return ret;
}
// Used to process '`' and keep all characters before the next '`'
int ObFastParserBase::process_backtick()
{
@ -1750,42 +1869,6 @@ inline void ObFastParserBase::append_no_param_sql()
no_param_sql_[no_param_sql_len_] = '\0';
}
int ObFastParserMysql::process_ps_statement()
{
int ret = OB_SUCCESS;
char *buf = nullptr;
cur_token_type_ = PARAM_TOKEN;
char ch = raw_sql_.char_at(raw_sql_.cur_pos_);
while (is_digit(ch)) {
ch = raw_sql_.scan();
}
int64_t need_mem_size = FIEXED_PARAM_NODE_SIZE;
int64_t text_len = raw_sql_.cur_pos_ - cur_token_begin_pos_;
need_mem_size += (text_len + 1);
// allocate all the memory needed at once
if (OB_ISNULL(buf = static_cast<char *>(allocator_.alloc(need_mem_size)))) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("fail to alloc memory", K(ret), K(need_mem_size));
} else {
ParseNode *node = new_node(buf, T_QUESTIONMARK);
node->text_len_ = text_len;
node->raw_text_ = raw_sql_.ptr(cur_token_begin_pos_);
int64_t ind = get_question_mark(&question_mark_ctx_, &allocator_,
node->raw_text_, text_len, buf);
if (-1 == ind) {
ret = OB_ERR_PARSER_SYNTAX;
LOG_WARN("parser syntax error", K(ret), K(raw_sql_.to_string()), K_(raw_sql_.cur_pos));
} else {
// buf points to the beginning of the next available memory
buf += text_len + 1;
node->value_ = ind;
node->raw_sql_offset_ = cur_token_begin_pos_;
lex_store_param(node, buf);
}
}
return ret;
}
int ObFastParserMysql::process_zero_identifier()
{
int ret = OB_SUCCESS;
@ -2174,7 +2257,7 @@ int ObFastParserMysql::parse_next_token()
}
case ':': {
// [":"{int_num}]
if (is_digit(raw_sql_.peek())) {
if (-1 != is_first_identifier_flags(raw_sql_.cur_pos_ + 1) || is_digit(raw_sql_.peek())) {
raw_sql_.scan();
OZ (process_ps_statement());
} else {
@ -2233,58 +2316,6 @@ int ObFastParserMysql::parse_next_token()
return ret;
}
int ObFastParserOracle::process_ps_statement()
{
int ret = OB_SUCCESS;
char *buf = nullptr;
cur_token_type_ = PARAM_TOKEN;
char ch = raw_sql_.char_at(raw_sql_.cur_pos_);
bool is_num = is_digit(ch) ? true : false;
if (is_num) { // ":"{int_num}
ch = raw_sql_.scan();
while (is_digit(ch)) {
ch = raw_sql_.scan();
}
} else {
int64_t next_idf_pos = raw_sql_.cur_pos_;
while (-1 != (next_idf_pos = is_identifier_flags(next_idf_pos))) {
raw_sql_.cur_pos_ = next_idf_pos;
}
}
int64_t need_mem_size = FIEXED_PARAM_NODE_SIZE;
int64_t text_len = raw_sql_.cur_pos_ - cur_token_begin_pos_;
need_mem_size += (text_len + 1);
// allocate all the memory needed at once
if (OB_ISNULL(buf = static_cast<char *>(allocator_.alloc(need_mem_size)))) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("fail to alloc memory", K(ret), K(need_mem_size));
} else {
ParseNode *node = new_node(buf, T_QUESTIONMARK);
node->text_len_ = text_len;
node->raw_text_ = raw_sql_.ptr(cur_token_begin_pos_);
if (is_num) {
node->value_ = strtoll(&node->raw_text_[1], NULL, 10);
} else {
int64_t ind = get_question_mark(&question_mark_ctx_, &allocator_,
node->raw_text_, text_len, buf);
if (-1 == ind) {
ret = OB_ERR_PARSER_SYNTAX;
LOG_WARN("parser syntax error", K(ret), K(raw_sql_.to_string()), K_(raw_sql_.cur_pos));
} else {
question_mark_ctx_.by_name_ = true;
node->value_ = ind;
// buf points to the beginning of the next available memory
buf += text_len + 1;
}
}
if (OB_SUCC(ret)) {
node->raw_sql_offset_ = cur_token_begin_pos_;
lex_store_param(node, buf);
}
}
return ret;
}
/**
* @param [in] : if in_q_quote is true, means that the current token
* starts with ("N"|"n")?("Q"|"q"){sqbegin}