diff --git a/mysql-test/main/sp_validation.result b/mysql-test/main/sp_validation.result index 9ef644482d5..0808fd7cd78 100644 --- a/mysql-test/main/sp_validation.result +++ b/mysql-test/main/sp_validation.result @@ -1993,4 +1993,96 @@ f1() # Clean up DROP FUNCTION f1; DROP TABLE t1; +# +# MDEV-36390: Minor refactoring of the method get_expr_query at the classes sp_instr_cpush/sp_instr_cursor_copy_struct +# +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1); +CREATE OR REPLACE PROCEDURE p1() +BEGIN +DECLARE va INT; +# Check that the TAB character after the clause FOR is skipped and +# the body of cursor is remembered correctly for subsequent re-parsing +DECLARE cur CURSOR FOR SELECT a FROM t1; +OPEN cur; +FETCH cur INTO va; +SELECT va; +CLOSE cur; +END; +$ +CREATE OR REPLACE PROCEDURE p2() +BEGIN +DECLARE va INT; +# Check that the newline character after the clause FOR is skipped and +# the body of cursor is remembered correctly for subsequent re-parsing +DECLARE cur CURSOR FOR +SELECT a FROM t1; +OPEN cur; +FETCH cur INTO va; +SELECT va; +CLOSE cur; +END; +$ +CREATE OR REPLACE PROCEDURE p3() +BEGIN +DECLARE va INT; +# Check that C-style comment and the newline character after +# the clause FOR is skipped and the body of cursor is remembered +# correctly for subsequent re-parsing +DECLARE cur CURSOR FOR /* Explicit comment */ +SELECT a FROM t1; +OPEN cur; +FETCH cur INTO va; +SELECT va; +CLOSE cur; +END; +$ +CREATE OR REPLACE PROCEDURE p4() +BEGIN +DECLARE va INT; +# Check that SQL-style comment and the newline character after +# the clause FOR is skipped and the body of cursor is remembered +# correctly for subsequent re-parsing +DECLARE cur CURSOR FOR -- Explicit comment +SELECT a FROM t1; +OPEN cur; +FETCH cur INTO va; +SELECT va; +CLOSE cur; +END; +$ +CALL p1(); +va +1 +CALL p2(); +va +1 +CALL p3(); +va +1 +CALL p4(); +va +1 +ALTER TABLE t1 COMMENT 'The Comment 1'; +# The following statements will run re-parsing of +# cursor declaration statements inside the stored +# procedures p1, p2, p3, p4. +CALL p1(); +va +1 +CALL p2(); +va +1 +CALL p3(); +va +1 +CALL p4(); +va +1 +# Clean up +DROP PROCEDURE p1; +DROP PROCEDURE p2; +DROP PROCEDURE p3; +DROP PROCEDURE p4; +DROP TABLE t1; SET sql_mode = default; diff --git a/mysql-test/main/sp_validation.test b/mysql-test/main/sp_validation.test index 6f095710e2c..bf1f147deec 100644 --- a/mysql-test/main/sp_validation.test +++ b/mysql-test/main/sp_validation.test @@ -2795,5 +2795,96 @@ SELECT f1(); DROP FUNCTION f1; DROP TABLE t1; +--echo # +--echo # MDEV-36390: Minor refactoring of the method get_expr_query at the classes sp_instr_cpush/sp_instr_cursor_copy_struct +--echo # +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1); + +--delimiter $ + +CREATE OR REPLACE PROCEDURE p1() +BEGIN + DECLARE va INT; + # Check that the TAB character after the clause FOR is skipped and + # the body of cursor is remembered correctly for subsequent re-parsing + DECLARE cur CURSOR FOR SELECT a FROM t1; + + OPEN cur; + FETCH cur INTO va; + SELECT va; + CLOSE cur; +END; +$ + +CREATE OR REPLACE PROCEDURE p2() +BEGIN + DECLARE va INT; + # Check that the newline character after the clause FOR is skipped and + # the body of cursor is remembered correctly for subsequent re-parsing + DECLARE cur CURSOR FOR + SELECT a FROM t1; + + OPEN cur; + FETCH cur INTO va; + SELECT va; + CLOSE cur; +END; +$ + +CREATE OR REPLACE PROCEDURE p3() +BEGIN + DECLARE va INT; + # Check that C-style comment and the newline character after + # the clause FOR is skipped and the body of cursor is remembered + # correctly for subsequent re-parsing + DECLARE cur CURSOR FOR /* Explicit comment */ + SELECT a FROM t1; + + OPEN cur; + FETCH cur INTO va; + SELECT va; + CLOSE cur; +END; +$ + +CREATE OR REPLACE PROCEDURE p4() +BEGIN + DECLARE va INT; + # Check that SQL-style comment and the newline character after + # the clause FOR is skipped and the body of cursor is remembered + # correctly for subsequent re-parsing + DECLARE cur CURSOR FOR -- Explicit comment + SELECT a FROM t1; + + OPEN cur; + FETCH cur INTO va; + SELECT va; + CLOSE cur; +END; +$ + +--delimiter ; + +CALL p1(); +CALL p2(); +CALL p3(); +CALL p4(); +ALTER TABLE t1 COMMENT 'The Comment 1'; +--echo # The following statements will run re-parsing of +--echo # cursor declaration statements inside the stored +--echo # procedures p1, p2, p3, p4. +CALL p1(); +CALL p2(); +CALL p3(); +CALL p4(); + +--echo # Clean up +DROP PROCEDURE p1; +DROP PROCEDURE p2; +DROP PROCEDURE p3; +DROP PROCEDURE p4; +DROP TABLE t1; + SET sql_mode = default; --enable_ps2_protocol diff --git a/sql/sp_instr.h b/sql/sp_instr.h index 5d5af0a18f0..3bd2963648a 100644 --- a/sql/sp_instr.h +++ b/sql/sp_instr.h @@ -1227,6 +1227,32 @@ public: }; // class sp_instr_hreturn : public sp_instr_jump +/** + Get a query text associated with the cursor. +*/ + +static inline LEX_CSTRING get_cursor_query(const LEX_CSTRING &cursor_stmt) +{ + /* + Lexer on processing the clause CURSOR FOR / CURSOR IS doesn't + move a pointer on cpp_buf after the token FOR/IS so skip it explicitly + in order to get correct value of cursor's query string. + */ + + if (strncasecmp(cursor_stmt.str, "FOR", 3) == 0 && + my_isspace(current_thd->variables.character_set_client, + cursor_stmt.str[3])) + return LEX_CSTRING{cursor_stmt.str + 4, cursor_stmt.length - 4}; + + if (strncasecmp(cursor_stmt.str, "IS", 2) == 0 && + my_isspace(current_thd->variables.character_set_client, + cursor_stmt.str[2])) + return LEX_CSTRING{cursor_stmt.str + 3, cursor_stmt.length - 3}; + + return cursor_stmt; +} + + /** This is DECLARE CURSOR */ @@ -1287,16 +1313,7 @@ public: protected: LEX_CSTRING get_expr_query() const override { - /* - Lexer on processing the clause CURSOR FOR / CURSOR IS doesn't - move a pointer on cpp_buf after the token FOR/IS so skip it explicitly - in order to get correct value of cursor's query string. - */ - if (strncasecmp(m_cursor_stmt.str, "FOR ", 4) == 0) - return LEX_CSTRING{m_cursor_stmt.str + 4, m_cursor_stmt.length - 4}; - if (strncasecmp(m_cursor_stmt.str, "IS ", 3) == 0) - return LEX_CSTRING{m_cursor_stmt.str + 3, m_cursor_stmt.length - 3}; - return m_cursor_stmt; + return get_cursor_query(m_cursor_stmt); } bool on_after_expr_parsing(THD *) override @@ -1428,16 +1445,7 @@ public: protected: LEX_CSTRING get_expr_query() const override { - /* - Lexer on processing the clause CURSOR FOR / CURSOR IS doesn't - move a pointer on cpp_buf after the token FOR/IS so skip it explicitly - in order to get correct value of cursor's query string. - */ - if (strncasecmp(m_cursor_stmt.str, "FOR ", 4) == 0) - return LEX_CSTRING{m_cursor_stmt.str + 4, m_cursor_stmt.length - 4}; - if (strncasecmp(m_cursor_stmt.str, "IS ", 3) == 0) - return LEX_CSTRING{m_cursor_stmt.str + 3, m_cursor_stmt.length - 3}; - return m_cursor_stmt; + return get_cursor_query(m_cursor_stmt); } bool on_after_expr_parsing(THD *) override