diff --git a/mysql-test/suite/compat/oracle/r/sp.result b/mysql-test/suite/compat/oracle/r/sp.result index 0b4c990f988ac..5dd628da39dab 100644 --- a/mysql-test/suite/compat/oracle/r/sp.result +++ b/mysql-test/suite/compat/oracle/r/sp.result @@ -2152,6 +2152,81 @@ END' at line 1 # End of MDEV-10577 sql_mode=ORACLE: %TYPE in variable declarations # # +# MDEV-12089 sql_mode=ORACLE: Understand optional routine name after the END keyword +# +CREATE FUNCTION f1 RETURN INT AS +BEGIN +RETURN 10; +END f1; +$$ +DROP FUNCTION f1; +CREATE FUNCTION test.f1 RETURN INT AS +BEGIN +RETURN 10; +END test.f1; +$$ +DROP FUNCTION f1; +CREATE FUNCTION test.f1 RETURN INT AS +BEGIN +RETURN 10; +END test2.f1; +$$ +ERROR HY000: END identifier 'test2.f1' does not match 'test.f1' +CREATE FUNCTION test.f1 RETURN INT AS +BEGIN +RETURN 10; +END test.f2; +$$ +ERROR HY000: END identifier 'test.f2' does not match 'test.f1' +CREATE FUNCTION f1 RETURN INT AS +BEGIN +RETURN 10; +END test.f2; +$$ +ERROR HY000: END identifier 'test.f2' does not match 'test.f1' +CREATE FUNCTION f1 RETURN INT AS +BEGIN +RETURN 10; +END test2.f1; +$$ +ERROR HY000: END identifier 'test2.f1' does not match 'test.f1' +CREATE PROCEDURE p1 AS +BEGIN +NULL; +END p1; +$$ +DROP PROCEDURE p1; +CREATE PROCEDURE test.p1 AS +BEGIN +NULL; +END test.p1; +$$ +DROP PROCEDURE p1; +CREATE PROCEDURE test.p1 AS +BEGIN +NULL; +END test2.p1; +$$ +ERROR HY000: END identifier 'test2.p1' does not match 'test.p1' +CREATE PROCEDURE test.p1 AS +BEGIN +NULL; +END test.p2; +$$ +ERROR HY000: END identifier 'test.p2' does not match 'test.p1' +CREATE PROCEDURE p1 AS +BEGIN +NULL; +END test.p2; +$$ +ERROR HY000: END identifier 'test.p2' does not match 'test.p1' +CREATE PROCEDURE p1 AS +BEGIN +NULL; +END test2.p1; +$$ +ERROR HY000: END identifier 'test2.p1' does not match 'test.p1' +# # MDEV-12107 sql_mode=ORACLE: Inside routines the CALL keywoard is optional # CREATE OR REPLACE PROCEDURE p1(a INT) AS diff --git a/mysql-test/suite/compat/oracle/t/sp.test b/mysql-test/suite/compat/oracle/t/sp.test index a4cdb1940b172..9e1374058787b 100644 --- a/mysql-test/suite/compat/oracle/t/sp.test +++ b/mysql-test/suite/compat/oracle/t/sp.test @@ -1973,6 +1973,119 @@ DELIMITER ;$$ --echo # +--echo # +--echo # MDEV-12089 sql_mode=ORACLE: Understand optional routine name after the END keyword +--echo # + +DELIMITER $$; +CREATE FUNCTION f1 RETURN INT AS +BEGIN + RETURN 10; +END f1; +$$ +DELIMITER ;$$ +DROP FUNCTION f1; + +DELIMITER $$; +CREATE FUNCTION test.f1 RETURN INT AS +BEGIN + RETURN 10; +END test.f1; +$$ +DELIMITER ;$$ +DROP FUNCTION f1; + +DELIMITER $$; +--error ER_END_IDENTIFIER_DOES_NOT_MATCH +CREATE FUNCTION test.f1 RETURN INT AS +BEGIN + RETURN 10; +END test2.f1; +$$ +DELIMITER ;$$ + +DELIMITER $$; +--error ER_END_IDENTIFIER_DOES_NOT_MATCH +CREATE FUNCTION test.f1 RETURN INT AS +BEGIN + RETURN 10; +END test.f2; +$$ +DELIMITER ;$$ + +DELIMITER $$; +--error ER_END_IDENTIFIER_DOES_NOT_MATCH +CREATE FUNCTION f1 RETURN INT AS +BEGIN + RETURN 10; +END test.f2; +$$ +DELIMITER ;$$ + +DELIMITER $$; +--error ER_END_IDENTIFIER_DOES_NOT_MATCH +CREATE FUNCTION f1 RETURN INT AS +BEGIN + RETURN 10; +END test2.f1; +$$ +DELIMITER ;$$ + + +DELIMITER $$; +CREATE PROCEDURE p1 AS +BEGIN + NULL; +END p1; +$$ +DELIMITER ;$$ +DROP PROCEDURE p1; + +DELIMITER $$; +CREATE PROCEDURE test.p1 AS +BEGIN + NULL; +END test.p1; +$$ +DELIMITER ;$$ +DROP PROCEDURE p1; + +DELIMITER $$; +--error ER_END_IDENTIFIER_DOES_NOT_MATCH +CREATE PROCEDURE test.p1 AS +BEGIN + NULL; +END test2.p1; +$$ +DELIMITER ;$$ + +DELIMITER $$; +--error ER_END_IDENTIFIER_DOES_NOT_MATCH +CREATE PROCEDURE test.p1 AS +BEGIN + NULL; +END test.p2; +$$ +DELIMITER ;$$ + +DELIMITER $$; +--error ER_END_IDENTIFIER_DOES_NOT_MATCH +CREATE PROCEDURE p1 AS +BEGIN + NULL; +END test.p2; +$$ +DELIMITER ;$$ + +DELIMITER $$; +--error ER_END_IDENTIFIER_DOES_NOT_MATCH +CREATE PROCEDURE p1 AS +BEGIN + NULL; +END test2.p1; +$$ +DELIMITER ;$$ + --echo # --echo # MDEV-12107 sql_mode=ORACLE: Inside routines the CALL keywoard is optional --echo # diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index 49ade235910ff..385a69adee38a 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -7464,3 +7464,5 @@ ER_UNKNOWN_STRUCTURED_VARIABLE eng "Unknown structured system variable or ROW routine variable '%-.*s'" ER_ROW_VARIABLE_DOES_NOT_HAVE_FIELD eng "Row variable '%-.192s' does not have a field '%-.192s'" +ER_END_IDENTIFIER_DOES_NOT_MATCH + eng "END identifier '%-.192s' does not match '%-.192s'" diff --git a/sql/sql_class.h b/sql/sql_class.h index be997a2c89659..974596910b233 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -5916,6 +5916,21 @@ class Database_qualified_name m_name.length= name_length; } + bool eq(const Database_qualified_name *other) const + { + CHARSET_INFO *cs= lower_case_table_names ? + &my_charset_utf8_general_ci : + &my_charset_utf8_bin; + return + m_db.length == other->m_db.length && + m_name.length == other->m_name.length && + !my_strnncoll(cs, + (const uchar *) m_db.str, m_db.length, + (const uchar *) other->m_db.str, other->m_db.length) && + !my_strnncoll(cs, + (const uchar *) m_name.str, m_name.length, + (const uchar *) other->m_name.str, other->m_name.length); + } // Export db and name as a qualified name string: 'db.name' size_t make_qname(char *dst, size_t dstlen) const { diff --git a/sql/sql_yacc_ora.yy b/sql/sql_yacc_ora.yy index abc52c71260ee..716f2e3ad0a7f 100644 --- a/sql/sql_yacc_ora.yy +++ b/sql/sql_yacc_ora.yy @@ -1315,6 +1315,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); opt_serial_attribute opt_serial_attribute_list serial_attribute explainable_command set_assign + sf_tail_standalone + sp_tail_standalone END_OF_INPUT %type call sp_proc_stmts sp_proc_stmts1 sp_proc_stmt @@ -1342,7 +1344,7 @@ END_OF_INPUT %type sp_instr_addr %type sp_cursor_name_and_offset %type opt_exception_clause exception_handlers -%type sp_name +%type sp_name opt_sp_name %type sp_param_name sp_param_name_and_type %type sp_for_loop_index_and_bounds %type sp_for_loop_bounds @@ -2219,6 +2221,11 @@ sp_name: } ; +opt_sp_name: + /* Empty */ { $$= NULL; } + | sp_name { $$= $1; } + ; + sp_a_chistics: /* Empty */ {} | sp_a_chistics sp_chistic {} @@ -16352,16 +16359,16 @@ view_or_trigger_or_sp_or_event: definer_tail: view_tail | trigger_tail - | sp_tail - | sf_tail + | sp_tail_standalone + | sf_tail_standalone | event_tail ; no_definer_tail: view_tail | trigger_tail - | sp_tail - | sf_tail + | sp_tail_standalone + | sf_tail_standalone | udf_tail | event_tail ; @@ -16713,6 +16720,26 @@ sp_tail: } ; +sf_tail_standalone: + sf_tail opt_sp_name + { + if ($2 && !$2->eq(Lex->sphead)) + my_yyabort_error((ER_END_IDENTIFIER_DOES_NOT_MATCH, MYF(0), + ErrConvDQName($2).ptr(), + ErrConvDQName(Lex->sphead).ptr())); + } + ; + +sp_tail_standalone: + sp_tail opt_sp_name + { + if ($2 && !$2->eq(Lex->sphead)) + my_yyabort_error((ER_END_IDENTIFIER_DOES_NOT_MATCH, MYF(0), + ErrConvDQName($2).ptr(), + ErrConvDQName(Lex->sphead).ptr())); + } + ; + sp_tail_is: IS | AS