diff --git a/mysql-test/suite/compat/oracle/r/sp-cursor.result b/mysql-test/suite/compat/oracle/r/sp-cursor.result index 025eca9fe06b2..bfade1963c915 100644 --- a/mysql-test/suite/compat/oracle/r/sp-cursor.result +++ b/mysql-test/suite/compat/oracle/r/sp-cursor.result @@ -753,6 +753,32 @@ DROP PROCEDURE p1; # End of MDEV-10597 Cursors with parameters # # +# MDEV-12209 sql_mode=ORACLE: Syntax error in a OPEN cursor with parameters makes the server crash +# +CREATE TABLE t1 (a INT, b VARCHAR(10)); +INSERT INTO t1 VALUES (1,'A'); +CREATE PROCEDURE p1(a INT,b VARCHAR) +AS +CURSOR c (p_a INT, p_b VARCHAR) IS SELECT * FROM t1 WHERE a=p_a; +BEGIN +OPEN c(a+, b); +LOOP +FETCH c INTO a, b; +EXIT WHEN c%NOTFOUND; +SELECT a, b; +END LOOP; +CLOSE c; +END; +$$ +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ' b); +LOOP +FETCH c INTO a, b; +EXIT WHEN c%NOTFOUND; +SELECT a, b; +END LOOP; +CLOSE ' at line 5 +DROP TABLE t1; +# # MDEV-10577 sql_mode=ORACLE: %TYPE in variable declarations # CREATE TABLE t1 (a INT, b VARCHAR(10),c DATETIME(3)); diff --git a/mysql-test/suite/compat/oracle/t/sp-cursor.test b/mysql-test/suite/compat/oracle/t/sp-cursor.test index f73d76d4fe1fe..0be76053f88c8 100644 --- a/mysql-test/suite/compat/oracle/t/sp-cursor.test +++ b/mysql-test/suite/compat/oracle/t/sp-cursor.test @@ -751,6 +751,29 @@ DROP PROCEDURE p1; --echo # End of MDEV-10597 Cursors with parameters --echo # +--echo # +--echo # MDEV-12209 sql_mode=ORACLE: Syntax error in a OPEN cursor with parameters makes the server crash +--echo # +CREATE TABLE t1 (a INT, b VARCHAR(10)); +INSERT INTO t1 VALUES (1,'A'); +DELIMITER $$; +--error ER_PARSE_ERROR +CREATE PROCEDURE p1(a INT,b VARCHAR) +AS + CURSOR c (p_a INT, p_b VARCHAR) IS SELECT * FROM t1 WHERE a=p_a; +BEGIN + OPEN c(a+, b); + LOOP + FETCH c INTO a, b; + EXIT WHEN c%NOTFOUND; + SELECT a, b; + END LOOP; + CLOSE c; +END; +$$ +DELIMITER ;$$ +DROP TABLE t1; + --echo # --echo # MDEV-10577 sql_mode=ORACLE: %TYPE in variable declarations diff --git a/sql/sp_head.cc b/sql/sp_head.cc index a29147b8a7566..0d873124b2d4d 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -2144,20 +2144,23 @@ sp_head::execute_procedure(THD *thd, List *args) */ bool -sp_head::reset_lex(THD *thd) +sp_head::reset_lex(THD *thd, sp_lex_local *sublex) { DBUG_ENTER("sp_head::reset_lex"); LEX *oldlex= thd->lex; - sp_lex_local *sublex= new (thd->mem_root) sp_lex_local(thd, oldlex); - if (sublex == 0) - DBUG_RETURN(TRUE); - thd->set_local_lex(sublex); - (void)m_lex.push_front(oldlex); + DBUG_RETURN(m_lex.push_front(oldlex)); +} - DBUG_RETURN(FALSE); + +bool +sp_head::reset_lex(THD *thd) +{ + DBUG_ENTER("sp_head::reset_lex"); + sp_lex_local *sublex= new (thd->mem_root) sp_lex_local(thd, thd->lex); + DBUG_RETURN(sublex ? reset_lex(thd, sublex) : true); } diff --git a/sql/sp_head.h b/sql/sp_head.h index 257b4d9655e1c..51e1049205060 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -474,6 +474,9 @@ class sp_head :private Query_arena, bool reset_lex(THD *thd); + bool + reset_lex(THD *thd, sp_lex_local *sublex); + /** Merge two LEX instances. @param oldlex - the upper level LEX we're going to restore to. diff --git a/sql/sql_yacc_ora.yy b/sql/sql_yacc_ora.yy index e1bf494425e46..13472dcefb0db 100644 --- a/sql/sql_yacc_ora.yy +++ b/sql/sql_yacc_ora.yy @@ -3290,19 +3290,20 @@ assignment_source_lex: ; assignment_source_expr: - remember_lex assignment_source_lex + assignment_source_lex { DBUG_ASSERT(thd->free_list == NULL); - thd->set_local_lex($2); // This changes thd->lex to $2 + Lex->sphead->reset_lex(thd, $1); } expr { - DBUG_ASSERT($2 == thd->lex); - if (thd->restore_from_local_lex_to_old_lex($1)) // Restores thd->lex - MYSQL_YYABORT; - $$= $2; - $$->set_item_and_free_list($4, thd->free_list); + DBUG_ASSERT($1 == thd->lex); + $$= $1; + $$->sp_lex_in_use= true; + $$->set_item_and_free_list($3, thd->free_list); thd->free_list= NULL; + if ($$->sphead->restore_lex(thd)) + MYSQL_YYABORT; } ;