[to #40151002] fix user variable type conversion problem in PL

This commit is contained in:
0xacc
2022-12-30 05:15:37 +00:00
committed by ob-robot
parent 1235ea51e6
commit b26f8898e9
3 changed files with 84 additions and 0 deletions

View File

@ -24,6 +24,14 @@ extern "C" {
#endif
extern int obpl_parser_init(ObParseCtx *parse_ctx);
extern int obpl_parser_parse(ObParseCtx *parse_ctx);
int obpl_parser_check_stack_overflow() {
int ret = OB_SUCCESS;
bool is_overflow = true;
if (OB_FAIL(check_stack_overflow(is_overflow))) {
LOG_WARN("failed to check stack overflow status", K(ret));
}
return is_overflow;
}
#ifdef __cplusplus
}
#endif

View File

@ -81,6 +81,74 @@ extern ParseNode *obpl_mysql_read_sql_construct(ObParseCtx *parse_ctx, const cha
extern void obpl_mysql_yyerror(YYLTYPE *yylloc, ObParseCtx *parse_ctx, char *s, ...);
extern void obpl_mysql_parse_fatal_error(int32_t errcode, yyscan_t yyscanner, yyconst char *msg, ...);
int obpl_mysql_check_specific_node(const ParseNode *node, const ObItemType type, int *is_contain) {
int ret = OB_PARSER_SUCCESS;
if (obpl_parser_check_stack_overflow()) {
ret = OB_PARSER_ERR_SIZE_OVERFLOW;
} else if (OB_UNLIKELY(NULL == is_contain)) {
ret = OB_PARSER_ERR_UNEXPECTED;
} else {
*is_contain = false;
}
if (OB_PARSER_SUCCESS == ret && OB_NOT_NULL(node)) {
if (type == node->type_) {
*is_contain = true;
} else {
for (int64_t i = 0; OB_PARSER_SUCCESS == ret && !*is_contain && i < node->num_child_; ++i) {
ret = obpl_mysql_check_specific_node(node->children_[i], type, is_contain);
}
}
}
return ret;
}
int obpl_mysql_wrap_node_into_subquery(ObParseCtx *_parse_ctx, ParseNode *node) {
int ret = OB_PARSER_SUCCESS;
if (OB_NOT_NULL(node)) {
int max_query_len = node->str_len_ + 10;
char *subquery = (char *)parse_malloc(max_query_len, _parse_ctx->mem_pool_);
int len = 0;
if (OB_UNLIKELY(NULL == subquery)) {
ret = OB_PARSER_ERR_NO_MEMORY;
} else if ((len = snprintf(subquery, max_query_len, "(SELECT %s)", node->str_value_)) <= 0) {
ret = OB_PARSER_ERR_UNEXPECTED;
} else {
ParseResult parse_result;
memset(&parse_result, 0, sizeof(ParseResult));
parse_result.input_sql_ = subquery;
parse_result.input_sql_len_ = len;
parse_result.malloc_pool_ = _parse_ctx->mem_pool_;
parse_result.pl_parse_info_.is_pl_parse_ = true;
parse_result.pl_parse_info_.is_pl_parse_expr_ = true;
parse_result.is_for_trigger_ = (1 == _parse_ctx->is_for_trigger_);
parse_result.question_mark_ctx_ = _parse_ctx->question_mark_ctx_;
parse_result.charset_info_ = _parse_ctx->charset_info_;
parse_result.is_not_utf8_connection_ = _parse_ctx->is_not_utf8_connection_;
parse_result.connection_collation_ = _parse_ctx->connection_collation_;
if (0 == parse_sql_stmt(&parse_result)) {
*node = *parse_result.result_tree_->children_[0];
node->str_value_ = subquery;
node->str_len_ = len;
node->str_off_ = -1;
}
}
}
return ret;
}
void obpl_mysql_wrap_get_user_var_into_subquery(ObParseCtx *parse_ctx, ParseNode *node) {
int ret = OB_PARSER_SUCCESS;
int is_contain = false;
if (OB_PARSER_SUCCESS != (ret = obpl_mysql_check_specific_node(node, T_OP_GET_USER_VAR, &is_contain))) {
obpl_mysql_parse_fatal_error(ret, YYLEX_PARAM, "failed to check T_OP_GET_USER_VAR in parse tree");
} else if (is_contain) {
if (OB_PARSER_SUCCESS != (ret = obpl_mysql_wrap_node_into_subquery(parse_ctx, node))) {
obpl_mysql_parse_fatal_error(ret, YYLEX_PARAM, "failed to wrap T_OP_GET_USER_VAR into subquery");
}
}
}
#define YY_FATAL_ERROR(msg, args...) (obpl_mysql_parse_fatal_error(OB_PARSER_ERR_NO_MEMORY, YYLEX_PARAM, msg, ##args))
#define YY_UNEXPECTED_ERROR(msg, args...) (obpl_mysql_parse_fatal_error(OB_PARSER_ERR_UNEXPECTED, YYLEX_PARAM, msg, ##args))
@ -355,6 +423,11 @@ sql_stmt:
{
//read sql query string直到读到token';'或者END_P
do_parse_sql_stmt($$, parse_ctx, @1.first_column, @1.last_column, 2, ';', END_P);
if(OB_UNLIKELY(NULL == $$->children_[0] || NULL == $$->children_[0]->children_[1])){
YY_UNEXPECTED_ERROR("value node in SET statement is NULL");
} else {
obpl_mysql_wrap_get_user_var_into_subquery(parse_ctx, $$->children_[0]->children_[1]);
}
}
| COMMIT
{
@ -1625,6 +1698,7 @@ expr:
{
//same as expr in sql rule, and terminate when read ';'
do_parse_sql_expr_rule($$, parse_ctx, 9, INTO, USING, WHEN, THEN, ';', DO, LIMIT, ',', END_KEY);
obpl_mysql_wrap_get_user_var_into_subquery(parse_ctx, $$);
}
;

View File

@ -370,6 +370,8 @@ extern ParseNode *new_node(void *malloc_pool, ObItemType type, int num);
extern ParseNode *new_non_terminal_node(void *malloc_pool, ObItemType node_tag, int num, ...);
extern ParseNode *new_terminal_node(void *malloc_pool, ObItemType type);
extern int obpl_parser_check_stack_overflow();
int get_deep_copy_size(const ParseNode *node, int64_t *size);
int deep_copy_parse_node(void *malloc_pool, const ParseNode *src, ParseNode *dst);