/** * 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_base.h" #define YY_EXTRA_TYPE void * #define yyconst const typedef void* yyscan_t; typedef struct yy_buffer_state *YY_BUFFER_STATE; extern int obsql_mysql_yylex_init_extra(YY_EXTRA_TYPE yy_user_defined,yyscan_t* ptr_yy_globals ); extern int obsql_mysql_yyparse(ParseResult *result); extern int obsql_mysql_multi_fast_parse(ParseResult *p); extern int obsql_mysql_multi_values_parse(ParseResult *p); extern int obsql_mysql_fast_parse(ParseResult *p); extern int obsql_mysql_yylex_destroy (yyscan_t yyscanner ); extern YY_BUFFER_STATE obsql_mysql_yy_scan_bytes (yyconst char *bytes,int len ,yyscan_t yyscanner ); extern void obsql_mysql_yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner ); extern void obsql_mysql_yy_delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner ); int parse_init(ParseResult *p) { int ret = 0; // can not include C++ file "ob_define.h" static __thread char error_msg[MAX_ERROR_MSG] = {'\0'}; p->error_msg_ = error_msg; if (OB_UNLIKELY(NULL == p || NULL == p->malloc_pool_)) { ret = -1; if (NULL != p) { (void)snprintf(p->error_msg_, MAX_ERROR_MSG, "malloc_pool_ must be set"); } } if (OB_LIKELY( 0 == ret)) { ret = obsql_mysql_yylex_init_extra(p, &(p->yyscan_info_)); } return ret; } int parse_terminate(ParseResult *p) { int ret = 0; if (OB_LIKELY(NULL != p->yyscan_info_)) { ret = obsql_mysql_yylex_destroy(p->yyscan_info_); } return ret; } int parse_sql(ParseResult *p, const char *buf, size_t len) { int ret = OB_PARSER_ERR_PARSE_SQL; if (OB_UNLIKELY(NULL == p)) { } else if (OB_UNLIKELY(NULL == buf || len <= 0)) { snprintf(p->error_msg_, MAX_ERROR_MSG, "Input SQL can not be empty"); ret = OB_PARSER_ERR_EMPTY_QUERY; } else { p->input_sql_ = buf; p->input_sql_len_ = len; p->start_col_ = 1; p->end_col_ = 1; p->line_ = 1; p->yycolumn_ = 1; p->yylineno_ = 1; #ifdef SQL_PARSER_COMPILATION p->realloc_cnt_ = p->realloc_cnt_ <= 0 ? 10 : p->realloc_cnt_; p->comment_cap_ = p->realloc_cnt_; p->comment_cnt_ = 0; p->stop_add_comment_ = false; #endif if (false == p->pl_parse_info_.is_pl_parse_) {//如果是PLParse调用的该接口,不去重置 p->question_mark_ctx_.count_ = 0; } // 删除SQL语句末尾的空格 (外层已做) // while (len > 0 && ISSPACE(buf[len - 1])) { // --len; // } //if (OB_UNLIKELY(len <= 0)) { // (void)snprintf(p->error_msg_, MAX_ERROR_MSG, "Input SQL can not be white space only"); // ret = OB_PARSER_ERR_EMPTY_QUERY; // } else { { static __thread jmp_buf jmp_buf_; p->jmp_buf_ = &jmp_buf_; int val = setjmp(*(p->jmp_buf_)); if (val) { if (p->extra_errno_ == OB_PARSER_ERR_NO_MEMORY) { // for error other than NO_MEMORY, we return OB_PARSER_ERR_PARSE_SQL to avoid lost connection. ret = OB_PARSER_ERR_NO_MEMORY; } else { ret = OB_PARSER_ERR_PARSE_SQL; } #ifdef SQL_PARSER_COMPILATION } else if (OB_ISNULL(p->comment_list_ = (TokenPosInfo*)(parse_malloc( p->realloc_cnt_ * sizeof(TokenPosInfo), p->malloc_pool_)))) { ret = OB_PARSER_ERR_NO_MEMORY; #endif } else { YY_BUFFER_STATE bp = obsql_mysql_yy_scan_bytes(buf, len, p->yyscan_info_); obsql_mysql_yy_switch_to_buffer(bp, p->yyscan_info_); int tmp_ret = -1; if (p->is_fp_) { tmp_ret = obsql_mysql_fast_parse(p); } else if (p->is_multi_query_) { tmp_ret = obsql_mysql_multi_fast_parse(p); } else if (p->is_multi_values_parser_) { tmp_ret = obsql_mysql_multi_values_parse(p); } else { tmp_ret = obsql_mysql_yyparse(p); } if (0 == tmp_ret) { ret = OB_PARSER_SUCCESS; } else if (2 == tmp_ret) { ret = OB_PARSER_ERR_NO_MEMORY; } else { if (0 != p->extra_errno_) { ret = p->extra_errno_; } else { ret = OB_PARSER_ERR_PARSE_SQL; } } obsql_mysql_yy_delete_buffer(bp, p->yyscan_info_); } } } return ret; } int parse_sql_stmt(ParseResult *parse_result) { int ret = -1; if (0 != (ret = parse_init(parse_result))) { // fix bug #16298144 // fprintf(stderr, "init parse result failed, ret=%d\n", ret); } else if (0 != (ret = parse_sql(parse_result, parse_result->input_sql_, parse_result->input_sql_len_))) { // fix bug #16298144 // fprintf(stderr, "parse sql failed, ret=%d, input_sql=%.*s\n", ret, parse_result->input_sql_len_, parse_result->input_sql_); } return ret; } void setup_token_pos_info(ParseNode *node, int off, int len) { #ifdef SQL_PARSER_COMPILATION node->token_off_ = off; node->token_len_ = len; #else // do nothing #endif } int setup_token_pos_info_and_dup_string(ParseNode *node, ParseResult *result, int start, int end) { int ret = OB_PARSER_SUCCESS; #ifdef SQL_PARSER_COMPILATION node->token_off_ = start - 1; node->token_len_ = end - start + 1; if (start > end) { ret = OB_PARSER_ERR_UNEXPECTED; } else if (OB_UNLIKELY((NULL == (node->str_value_ = copy_expr_string(result, start, end))))) { ret = OB_PARSER_ERR_NO_MEMORY; } else { node->str_len_ = end - start + 1; } #else // do nothing #endif return ret; } #ifdef SQL_PARSER_COMPILATION int add_comment_list(ParseResult *p, const TokenPosInfo *info) { int ret = OB_PARSER_SUCCESS; if (OB_ISNULL(p) || OB_ISNULL(info)) { ret = OB_PARSER_ERR_UNEXPECTED; } if (OB_PARSER_SUCCESS == ret && p->comment_cnt_ + 1 >= p->comment_cap_) { int alloc_cnt = p->comment_cnt_ + p->realloc_cnt_; char *buf = parse_malloc(sizeof(TokenPosInfo) * alloc_cnt, p->malloc_pool_); if (OB_ISNULL(buf)) { ret = OB_PARSER_ERR_NO_MEMORY; } else { memset(buf, 0, sizeof(TokenPosInfo) * alloc_cnt); memcpy(buf, (void*)(p->comment_list_), sizeof(TokenPosInfo) * p->comment_cnt_); p->comment_list_ = (TokenPosInfo*)buf; p->comment_cap_ += p->realloc_cnt_; } } if (OB_PARSER_SUCCESS == ret) { p->comment_list_[p->comment_cnt_].token_off_ = info->token_off_; p->comment_list_[p->comment_cnt_].token_len_ = info->token_len_; p->comment_cnt_ += 1; } return ret; } #endif void REPUT_NEG_SIGN(ParseResult *p) { if (p->minus_ctx_.has_minus_) { int start_pos = p->no_param_sql_len_; int end_pos = p->minus_ctx_.pos_; for (; start_pos > end_pos; start_pos--) { p->no_param_sql_[start_pos] = p->no_param_sql_[start_pos - 1]; } p->no_param_sql_[end_pos] = '-'; p->no_param_sql_[++p->no_param_sql_len_] = '\0'; p->minus_ctx_.pos_ = -1; p->minus_ctx_.raw_sql_offset_ = -1; p->minus_ctx_.has_minus_ = false; } } int STORE_PARAM_NODE_NEED_PARAMETERIZE(ParamList *param, struct _ParseNode *node, ParseResult *p, const int first_column) { if (p->minus_ctx_.has_minus_ && p->minus_ctx_.is_cur_numeric_) { p->no_param_sql_[p->minus_ctx_.pos_] = '?'; p->no_param_sql_len_ = p->minus_ctx_.pos_ + 1; } else { REPUT_NEG_SIGN(p); p->no_param_sql_[p->no_param_sql_len_++] = '?'; } p->no_param_sql_[p->no_param_sql_len_] = '\0'; node->pos_ = p->no_param_sql_len_ - 1; node->raw_sql_offset_ = (p->minus_ctx_.has_minus_ && p->minus_ctx_.is_cur_numeric_) ? p->minus_ctx_.raw_sql_offset_ : first_column - 1; param->node_ = node; param->next_ = NULL; if (NULL == p->param_nodes_) { p->param_nodes_ = param; } else { p->tail_param_node_->next_ = param; } p->tail_param_node_ = param; p->param_node_num_++; p->token_num_++; p->minus_ctx_.has_minus_ = false; p->minus_ctx_.pos_ = -1; p->minus_ctx_.is_cur_numeric_ = false; p->minus_ctx_.raw_sql_offset_ = -1; return 0; } int add_alias_name(ParseNode *node, ParseResult *result, int end) { int ret = OB_PARSER_SUCCESS; if (NULL == node || NULL == result || NULL == node->str_value_) { ret = OB_PARSER_ERR_UNEXPECTED; } else { int need_len = strlen(" as ") + node->str_len_ + 2 * strlen("\""); if (end > result->pl_parse_info_.last_pl_symbol_pos_) { need_len += end - result->pl_parse_info_.last_pl_symbol_pos_; } for (int i = 0; i < node->str_len_; ++i) { if ('\"' == node->str_value_[i] && !(i > 0 && '\\' == node->str_value_[i - 1])) { need_len++; } } if (result->no_param_sql_len_ + need_len >= result->no_param_sql_buf_len_) { char *buf = parse_malloc(result->no_param_sql_buf_len_ * 2, result->malloc_pool_); if (OB_UNLIKELY(NULL == buf)) { ret = OB_PARSER_ERR_NO_MEMORY; } else { memmove(buf, result->no_param_sql_, result->no_param_sql_len_); result->no_param_sql_ = buf; result->no_param_sql_buf_len_ = result->no_param_sql_buf_len_ * 2; } } if (OB_PARSER_SUCCESS == ret) { if (end > result->pl_parse_info_.last_pl_symbol_pos_) { memmove(result->no_param_sql_ + result->no_param_sql_len_, result->input_sql_ + result->pl_parse_info_.last_pl_symbol_pos_, end - result->pl_parse_info_.last_pl_symbol_pos_); result->no_param_sql_len_ += end - result->pl_parse_info_.last_pl_symbol_pos_; result->pl_parse_info_.last_pl_symbol_pos_ = end; } result->no_param_sql_len_ += sprintf(result->no_param_sql_ + result->no_param_sql_len_, "%.*s", (int)strlen(" as "), " as "); result->no_param_sql_len_ += sprintf(result->no_param_sql_ + result->no_param_sql_len_, "%.*s", (int)strlen("\""), "\""); int index1 = 0; int index2 = 0; char *trans_buf = parse_malloc((int)node->str_len_ * 2, result->malloc_pool_); if (OB_UNLIKELY(NULL == trans_buf)) { ret = OB_PARSER_ERR_NO_MEMORY; } else { for (; index1 < node->str_len_; index1++) { if ('\"' == node->str_value_[index1] && !(index1 > 0 && '\\' == node->str_value_[index1 - 1])) { trans_buf[index2++] = '\\'; trans_buf[index2++] = '\"'; } else { trans_buf[index2++] = node->str_value_[index1]; } } result->no_param_sql_len_ += sprintf(result->no_param_sql_ + result->no_param_sql_len_, "%.*s", index2, trans_buf); result->no_param_sql_len_ += sprintf(result->no_param_sql_ + result->no_param_sql_len_, "%.*s", (int)strlen("\""), "\""); } } } return ret; }