From f5855ba03deef188516453b71e56d4239f74a653 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Sun, 11 Nov 2018 09:35:05 +0400 Subject: [PATCH] MDEV-17664 Add sql_mode specific tokens for ':' and '%' --- sql/sql_lex.cc | 40 ++++++++++++++++- sql/sql_lex.h | 14 ++++++ sql/sql_yacc.yy | 74 ++++++++++++++++++++++++------- sql/sql_yacc_ora.yy | 105 +++++++++++++++++--------------------------- 4 files changed, 151 insertions(+), 82 deletions(-) diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index a80c6485cf0..254889ac414 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1423,6 +1423,13 @@ int Lex_input_stream::lex_one_token(YYSTYPE *yylval, THD *thd) } /* Fall through */ case MY_LEX_CHAR: // Unknown or single char token + { + if (c == '%' && (m_thd->variables.sql_mode & MODE_ORACLE)) + { + next_state= MY_LEX_START; + return PERCENT_ORACLE_SYM; + } + } case MY_LEX_SKIP: // This should not happen if (c != ')') next_state= MY_LEX_START; // Allow signed numbers @@ -1861,8 +1868,13 @@ int Lex_input_stream::lex_one_token(YYSTYPE *yylval, THD *thd) case MY_LEX_SET_VAR: // Check if ':=' if (yyPeek() != '=') { - state= MY_LEX_CHAR; // Return ':' - break; + next_state= MY_LEX_START; + if (m_thd->variables.sql_mode & MODE_ORACLE) + { + yylval->kwd.set_keyword(m_tok_start, 1); + return COLON_ORACLE_SYM; + } + return (int) ':'; } yySkip(); return (SET_VAR); @@ -6655,6 +6667,30 @@ Item *LEX::make_item_colon_ident_ident(THD *thd, } +Item *LEX::make_item_plsql_cursor_attr(THD *thd, const LEX_CSTRING *name, + plsql_cursor_attr_t attr) +{ + uint offset; + if (unlikely(!spcont || !spcont->find_cursor(name, &offset, false))) + { + my_error(ER_SP_CURSOR_MISMATCH, MYF(0), name->str); + return NULL; + } + switch (attr) { + case PLSQL_CURSOR_ATTR_ISOPEN: + return new (thd->mem_root) Item_func_cursor_isopen(thd, name, offset); + case PLSQL_CURSOR_ATTR_FOUND: + return new (thd->mem_root) Item_func_cursor_found(thd, name, offset); + case PLSQL_CURSOR_ATTR_NOTFOUND: + return new (thd->mem_root) Item_func_cursor_notfound(thd, name, offset); + case PLSQL_CURSOR_ATTR_ROWCOUNT: + return new (thd->mem_root) Item_func_cursor_rowcount(thd, name, offset); + } + DBUG_ASSERT(0); + return NULL; +} + + Item *LEX::make_item_sysvar(THD *thd, enum_var_type type, const LEX_CSTRING *name, diff --git a/sql/sql_lex.h b/sql/sql_lex.h index ea2f61c3992..dbd201d2d7c 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -182,6 +182,16 @@ enum enum_view_suid VIEW_SUID_DEFAULT= 2 }; + +enum plsql_cursor_attr_t +{ + PLSQL_CURSOR_ATTR_ISOPEN, + PLSQL_CURSOR_ATTR_FOUND, + PLSQL_CURSOR_ATTR_NOTFOUND, + PLSQL_CURSOR_ATTR_ROWCOUNT +}; + + /* These may not be declared yet */ class Table_ident; class sql_exchange; @@ -3642,6 +3652,10 @@ public: Item *make_item_colon_ident_ident(THD *thd, const Lex_ident_cli_st *a, const Lex_ident_cli_st *b); + // PLSQL: cursor%ISOPEN etc + Item *make_item_plsql_cursor_attr(THD *thd, const LEX_CSTRING *name, + plsql_cursor_attr_t attr); + // For "SELECT @@var", "SELECT @@var.field" Item *make_item_sysvar(THD *thd, enum_var_type type, diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 3b694a9cc81..8aea71b44ba 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -790,11 +790,6 @@ Virtual_column_info *add_virtual_expression(THD *thd, Item *expr) Lex_for_loop_st for_loop; Lex_for_loop_bounds_st for_loop_bounds; Lex_trim_st trim; - struct - { - LEX_CSTRING name; - uint offset; - } sp_cursor_name_and_offset; vers_history_point_t vers_history_point; /* pointers */ @@ -878,6 +873,7 @@ Virtual_column_info *add_virtual_expression(THD *thd, Item *expr) DDL_options_st object_ddl_options; enum vers_sys_type_t vers_range_unit; enum Column_definition::enum_column_versioning vers_column_versioning; + enum plsql_cursor_attr_t plsql_cursor_attr; } %{ @@ -1104,6 +1100,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); %token PARAM_MARKER %token PARSE_VCOL_EXPR_SYM %token PARTITION_SYM /* SQL-2003-R */ +%token PERCENT_ORACLE_SYM /* INTERNAL */ %token PERCENT_RANK_SYM %token PERCENTILE_CONT_SYM %token PERCENTILE_DISC_SYM @@ -1278,6 +1275,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); %token COALESCE /* SQL-2003-N */ %token CODE_SYM %token COLLATION_SYM /* SQL-2003-N */ +%token COLON_ORACLE_SYM /* INTERNAL */ %token COLUMNS %token COLUMN_ADD_SYM %token COLUMN_CHECK_SYM @@ -1933,7 +1931,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); geometry_function signed_literal expr_or_literal opt_escape sp_opt_default - simple_ident_nospvar simple_ident_q simple_ident_q2 + simple_ident_nospvar field_or_var limit_option part_func_expr window_func_expr @@ -1942,6 +1940,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); inverse_distribution_function percentile_function inverse_distribution_function_def + explicit_cursor_attr function_call_keyword function_call_keyword_timestamp function_call_nonkeyword @@ -2144,6 +2143,8 @@ END_OF_INPUT %type view_algorithm view_check_option %type view_suid opt_view_suid +%type plsql_cursor_attr + %type sp_decl_idents sp_decl_idents_init_vars %type sp_handler_type sp_hcond_list %type sp_cond sp_hcond sqlstate signal_value opt_signal_value @@ -10095,6 +10096,23 @@ dyncall_create_list: } ; + +plsql_cursor_attr: + ISOPEN_SYM { $$= PLSQL_CURSOR_ATTR_ISOPEN; } + | FOUND_SYM { $$= PLSQL_CURSOR_ATTR_FOUND; } + | NOTFOUND_SYM { $$= PLSQL_CURSOR_ATTR_NOTFOUND; } + | ROWCOUNT_SYM { $$= PLSQL_CURSOR_ATTR_ROWCOUNT; } + ; + +explicit_cursor_attr: + ident PERCENT_ORACLE_SYM plsql_cursor_attr + { + if (unlikely(!($$= Lex->make_item_plsql_cursor_attr(thd, &$1, $3)))) + MYSQL_YYABORT; + } + ; + + trim_operands: expr { $$.set(TRIM_BOTH, $1); } | LEADING expr FROM expr { $$.set(TRIM_LEADING, $2, $4); } @@ -10258,6 +10276,7 @@ column_default_non_parenthesized_expr: primary_expr: column_default_non_parenthesized_expr + | explicit_cursor_attr | '(' parenthesized_expr ')' { $$= $2; } ; @@ -10444,6 +10463,14 @@ function_call_keyword: if (unlikely($$ == NULL)) MYSQL_YYABORT; } + | SQL_SYM PERCENT_ORACLE_SYM ROWCOUNT_SYM + { + $$= new (thd->mem_root) Item_func_oracle_sql_rowcount(thd); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_FUNCTION); + Lex->safe_to_cache_query= 0; + } | TIME_SYM '(' expr ')' { $$= new (thd->mem_root) Item_time_typecast(thd, $3, @@ -14956,6 +14983,19 @@ param_marker: YYLIP->get_tok_start() + 1)))) MYSQL_YYABORT; } + | COLON_ORACLE_SYM ident_cli + { + if (unlikely(!($$= Lex->add_placeholder(thd, &null_clex_str, + $1.pos(), $2.end())))) + MYSQL_YYABORT; + } + | COLON_ORACLE_SYM NUM + { + if (unlikely(!($$= Lex->add_placeholder(thd, &null_clex_str, + $1.pos(), + YYLIP->get_ptr())))) + MYSQL_YYABORT; + } ; signed_literal: @@ -15265,6 +15305,11 @@ simple_ident: if (unlikely(!($$= Lex->create_item_ident(thd, &$1, &$3, &$5)))) MYSQL_YYABORT; } + | COLON_ORACLE_SYM ident_cli '.' ident_cli + { + if (unlikely(!($$= Lex->make_item_colon_ident_ident(thd, &$2, &$4)))) + MYSQL_YYABORT; + } ; simple_ident_nospvar: @@ -15273,20 +15318,17 @@ simple_ident_nospvar: if (unlikely(!($$= Lex->create_item_ident_nosp(thd, &$1)))) MYSQL_YYABORT; } - | simple_ident_q { $$= $1; } - ; - -simple_ident_q: - ident '.' ident + | ident '.' ident { if (unlikely(!($$= Lex->create_item_ident_nospvar(thd, &$1, &$3)))) MYSQL_YYABORT; } - | simple_ident_q2 - ; - -simple_ident_q2: - '.' ident '.' ident + | COLON_ORACLE_SYM ident_cli '.' ident_cli + { + if (unlikely(!($$= Lex->make_item_colon_ident_ident(thd, &$2, &$4)))) + MYSQL_YYABORT; + } + | '.' ident '.' ident { Lex_ident_sys none; if (unlikely(!($$= Lex->create_item_ident(thd, &none, &$2, &$4)))) diff --git a/sql/sql_yacc_ora.yy b/sql/sql_yacc_ora.yy index a58af90922c..e465e3a19b6 100644 --- a/sql/sql_yacc_ora.yy +++ b/sql/sql_yacc_ora.yy @@ -183,11 +183,6 @@ void ORAerror(THD *thd, const char *s) Lex_for_loop_st for_loop; Lex_for_loop_bounds_st for_loop_bounds; Lex_trim_st trim; - struct - { - LEX_CSTRING name; - uint offset; - } sp_cursor_name_and_offset; vers_history_point_t vers_history_point; /* pointers */ @@ -272,6 +267,7 @@ void ORAerror(THD *thd, const char *s) DDL_options_st object_ddl_options; enum vers_sys_type_t vers_range_unit; enum Column_definition::enum_column_versioning vers_column_versioning; + enum plsql_cursor_attr_t plsql_cursor_attr; } %{ @@ -498,6 +494,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); %token PARAM_MARKER %token PARSE_VCOL_EXPR_SYM %token PARTITION_SYM /* SQL-2003-R */ +%token PERCENT_ORACLE_SYM /* INTERNAL */ %token PERCENT_RANK_SYM %token PERCENTILE_CONT_SYM %token PERCENTILE_DISC_SYM @@ -672,6 +669,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); %token COALESCE /* SQL-2003-N */ %token CODE_SYM %token COLLATION_SYM /* SQL-2003-N */ +%token COLON_ORACLE_SYM /* INTERNAL */ %token COLUMNS %token COLUMN_ADD_SYM %token COLUMN_CHECK_SYM @@ -1081,7 +1079,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); %left '&' %left SHIFT_LEFT SHIFT_RIGHT %left '-' '+' ORACLE_CONCAT_SYM -%left '*' '/' DIV_SYM MOD_SYM +%left '*' '/' '%' DIV_SYM MOD_SYM %left '^' %left MYSQL_CONCAT_SYM %left NEG '~' NOT2_SYM BINARY @@ -1242,7 +1240,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); remember_name remember_end remember_end_opt remember_tok_start remember_tok_end wild_and_where - colon_with_pos %type field_length opt_field_length opt_field_length_default_1 @@ -1551,6 +1548,8 @@ END_OF_INPUT %type view_algorithm view_check_option %type view_suid opt_view_suid + +%type plsql_cursor_attr %type sp_suid %type sp_decl_idents sp_decl_idents_init_vars @@ -1568,7 +1567,6 @@ END_OF_INPUT %type sp_block_statements_and_exceptions %type package_implementation_executable_section %type sp_instr_addr -%type sp_cursor_name_and_offset %type opt_exception_clause exception_handlers %type remember_lex package_routine_lex package_specification_function @@ -3058,22 +3056,22 @@ sp_param_name_and_type: if (unlikely(Lex->sp_param_fill_definition($$= $1))) MYSQL_YYABORT; } - | sp_param_name sp_decl_ident '.' ident '%' TYPE_SYM + | sp_param_name sp_decl_ident '.' ident PERCENT_ORACLE_SYM TYPE_SYM { if (unlikely(Lex->sphead->spvar_fill_type_reference(thd, $$= $1, $2, $4))) MYSQL_YYABORT; } - | sp_param_name sp_decl_ident '.' ident '.' ident '%' TYPE_SYM + | sp_param_name sp_decl_ident '.' ident '.' ident PERCENT_ORACLE_SYM TYPE_SYM { if (unlikely(Lex->sphead->spvar_fill_type_reference(thd, $$= $1, $2, $4, $6))) MYSQL_YYABORT; } - | sp_param_name sp_decl_ident '%' ROWTYPE_ORACLE_SYM + | sp_param_name sp_decl_ident PERCENT_ORACLE_SYM ROWTYPE_ORACLE_SYM { if (unlikely(Lex->sphead->spvar_fill_table_rowtype_reference(thd, $$= $1, $2))) MYSQL_YYABORT; } - | sp_param_name sp_decl_ident '.' ident '%' ROWTYPE_ORACLE_SYM + | sp_param_name sp_decl_ident '.' ident PERCENT_ORACLE_SYM ROWTYPE_ORACLE_SYM { if (unlikely(Lex->sphead->spvar_fill_table_rowtype_reference(thd, $$= $1, $2, $4))) MYSQL_YYABORT; @@ -3103,25 +3101,25 @@ sp_pdparam: if (unlikely(Lex->sp_param_fill_definition($1))) MYSQL_YYABORT; } - | sp_param_name sp_opt_inout sp_decl_ident '.' ident '%' TYPE_SYM + | sp_param_name sp_opt_inout sp_decl_ident '.' ident PERCENT_ORACLE_SYM TYPE_SYM { $1->mode= $2; if (unlikely(Lex->sphead->spvar_fill_type_reference(thd, $1, $3, $5))) MYSQL_YYABORT; } - | sp_param_name sp_opt_inout sp_decl_ident '.' ident '.' ident '%' TYPE_SYM + | sp_param_name sp_opt_inout sp_decl_ident '.' ident '.' ident PERCENT_ORACLE_SYM TYPE_SYM { $1->mode= $2; if (unlikely(Lex->sphead->spvar_fill_type_reference(thd, $1, $3, $5, $7))) MYSQL_YYABORT; } - | sp_param_name sp_opt_inout sp_decl_ident '%' ROWTYPE_ORACLE_SYM + | sp_param_name sp_opt_inout sp_decl_ident PERCENT_ORACLE_SYM ROWTYPE_ORACLE_SYM { $1->mode= $2; if (unlikely(Lex->sphead->spvar_fill_table_rowtype_reference(thd, $1, $3))) MYSQL_YYABORT; } - | sp_param_name sp_opt_inout sp_decl_ident '.' ident '%' ROWTYPE_ORACLE_SYM + | sp_param_name sp_opt_inout sp_decl_ident '.' ident PERCENT_ORACLE_SYM ROWTYPE_ORACLE_SYM { $1->mode= $2; if (unlikely(Lex->sphead->spvar_fill_table_rowtype_reference(thd, $1, $3, $5))) @@ -3326,7 +3324,7 @@ sp_decl_vars: $$.init_using_vars($1); } | sp_decl_idents_init_vars - optionally_qualified_column_ident '%' TYPE_SYM + optionally_qualified_column_ident PERCENT_ORACLE_SYM TYPE_SYM sp_opt_default { if (unlikely(Lex->sp_variable_declarations_with_ref_finalize(thd, $1, $2, $5))) @@ -3334,7 +3332,7 @@ sp_decl_vars: $$.init_using_vars($1); } | sp_decl_idents_init_vars - optionally_qualified_column_ident '%' ROWTYPE_ORACLE_SYM + optionally_qualified_column_ident PERCENT_ORACLE_SYM ROWTYPE_ORACLE_SYM sp_opt_default { if (unlikely(Lex->sp_variable_declarations_rowtype_finalize(thd, $1, $2, $5))) @@ -9496,13 +9494,6 @@ select_item: } ; -colon_with_pos: - ':' - { - $$= (char *) YYLIP->get_tok_start(); - } - ; - remember_tok_start: { $$= (char*) YYLIP->get_tok_start(); @@ -9932,6 +9923,12 @@ bit_expr: if (unlikely($$ == NULL)) MYSQL_YYABORT; } + | bit_expr '%' bit_expr %prec '%' + { + $$= new (thd->mem_root) Item_func_mod(thd, $1, $3); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } | bit_expr DIV_SYM bit_expr %prec DIV_SYM { $$= new (thd->mem_root) Item_func_int_div(thd, $1, $3); @@ -10068,44 +10065,23 @@ dyncall_create_list: } ; -sp_cursor_name_and_offset: - ident - { - LEX *lex= Lex; - $$.name= $1; - if (unlikely(!lex->spcont || - !lex->spcont->find_cursor(&$1, &$$.offset, false))) - my_yyabort_error((ER_SP_CURSOR_MISMATCH, MYF(0), $1.str)); - } + +plsql_cursor_attr: + ISOPEN_SYM { $$= PLSQL_CURSOR_ATTR_ISOPEN; } + | FOUND_SYM { $$= PLSQL_CURSOR_ATTR_FOUND; } + | NOTFOUND_SYM { $$= PLSQL_CURSOR_ATTR_NOTFOUND; } + | ROWCOUNT_SYM { $$= PLSQL_CURSOR_ATTR_ROWCOUNT; } ; explicit_cursor_attr: - sp_cursor_name_and_offset '%' ISOPEN_SYM + ident PERCENT_ORACLE_SYM plsql_cursor_attr { - if (unlikely(!($$= new (thd->mem_root) - Item_func_cursor_isopen(thd, &$1.name, $1.offset)))) - MYSQL_YYABORT; - } - | sp_cursor_name_and_offset '%' FOUND_SYM - { - if (unlikely(!($$= new (thd->mem_root) - Item_func_cursor_found(thd, &$1.name, $1.offset)))) - MYSQL_YYABORT; - } - | sp_cursor_name_and_offset '%' NOTFOUND_SYM - { - if (unlikely(!($$= new (thd->mem_root) - Item_func_cursor_notfound(thd, &$1.name, $1.offset)))) - MYSQL_YYABORT; - } - | sp_cursor_name_and_offset '%' ROWCOUNT_SYM - { - if (unlikely(!($$= new (thd->mem_root) - Item_func_cursor_rowcount(thd, &$1.name, $1.offset)))) + if (unlikely(!($$= Lex->make_item_plsql_cursor_attr(thd, &$1, $3)))) MYSQL_YYABORT; } ; + trim_operands: expr { $$.set(TRIM_BOTH, $1); } | LEADING expr FROM expr { $$.set(TRIM_LEADING, $2, $4); } @@ -10456,7 +10432,7 @@ function_call_keyword: if (unlikely($$ == NULL)) MYSQL_YYABORT; } - | SQL_SYM '%' ROWCOUNT_SYM + | SQL_SYM PERCENT_ORACLE_SYM ROWCOUNT_SYM { $$= new (thd->mem_root) Item_func_oracle_sql_rowcount(thd); if (unlikely($$ == NULL)) @@ -15006,16 +14982,17 @@ param_marker: YYLIP->get_tok_start() + 1)))) MYSQL_YYABORT; } - | colon_with_pos ident_cli + | COLON_ORACLE_SYM ident_cli { if (unlikely(!($$= Lex->add_placeholder(thd, &null_clex_str, - $1, $2.end())))) + $1.pos(), $2.end())))) MYSQL_YYABORT; } - | colon_with_pos NUM + | COLON_ORACLE_SYM NUM { if (unlikely(!($$= Lex->add_placeholder(thd, &null_clex_str, - $1, YYLIP->get_ptr())))) + $1.pos(), + YYLIP->get_ptr())))) MYSQL_YYABORT; } ; @@ -15327,7 +15304,7 @@ simple_ident: if (unlikely(!($$= Lex->create_item_ident(thd, &$1, &$3, &$5)))) MYSQL_YYABORT; } - | colon_with_pos ident_cli '.' ident_cli + | COLON_ORACLE_SYM ident_cli '.' ident_cli { if (unlikely(!($$= Lex->make_item_colon_ident_ident(thd, &$2, &$4)))) MYSQL_YYABORT; @@ -15345,7 +15322,7 @@ simple_ident_nospvar: if (unlikely(!($$= Lex->create_item_ident_nospvar(thd, &$1, &$3)))) MYSQL_YYABORT; } - | colon_with_pos ident_cli '.' ident_cli + | COLON_ORACLE_SYM ident_cli '.' ident_cli { if (unlikely(!($$= Lex->make_item_colon_ident_ident(thd, &$2, &$4)))) MYSQL_YYABORT; @@ -16252,12 +16229,12 @@ set_assign: unlikely(lex->sphead->restore_lex(thd))) MYSQL_YYABORT; } - | colon_with_pos ident '.' ident SET_VAR + | COLON_ORACLE_SYM ident '.' ident SET_VAR { LEX *lex= Lex; if (unlikely(!lex->is_trigger_new_or_old_reference(&$2))) { - thd->parse_error(ER_SYNTAX_ERROR, $1); + thd->parse_error(ER_SYNTAX_ERROR, $1.pos()); MYSQL_YYABORT; } lex->set_stmt_init();