Skip to content

Commit

Permalink
MDEV-12209 sql_mode=ORACLE: Syntax error in a OPEN cursor with parame…
Browse files Browse the repository at this point in the history
…ters makes the server crash

The bug was introduced in the patch for "MDEV-10597 Cursors with parameters".
The LEX created in assignment_source_expr was not put into
thd->lex->sphead->m_lex (the stack of LEX'es), so syntax error in "expr"
caused a wrong memory cleanup in sp_head::~sp_head().

The fix changes the code to use sp_head::push_lex() followed by
sp_head::restore_lex(), like it happens in all other similar cases.
  • Loading branch information
Alexander Barkov committed Apr 5, 2017
1 parent 7ca2f81 commit 400de20
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 14 deletions.
26 changes: 26 additions & 0 deletions mysql-test/suite/compat/oracle/r/sp-cursor.result
Expand Up @@ -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));
Expand Down
23 changes: 23 additions & 0 deletions mysql-test/suite/compat/oracle/t/sp-cursor.test
Expand Up @@ -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
Expand Down
17 changes: 10 additions & 7 deletions sql/sp_head.cc
Expand Up @@ -2144,20 +2144,23 @@ sp_head::execute_procedure(THD *thd, List<Item> *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);
}


Expand Down
3 changes: 3 additions & 0 deletions sql/sp_head.h
Expand Up @@ -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.
Expand Down
15 changes: 8 additions & 7 deletions sql/sql_yacc_ora.yy
Expand Up @@ -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;
}
;

Expand Down

0 comments on commit 400de20

Please sign in to comment.