314 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			314 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_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;
 | |
| }
 | 
