From e1cff0ac5dd583732bb693b1d6eca3376e41f69a Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Wed, 5 Apr 2017 10:52:31 +0400 Subject: [PATCH] MDEV-12441 Variables declared after cursors with parameters lose values Parse context frames (sp_pcontext) can have holes in variable run-time offsets, the missing offsets reside on the children contexts in such cases. Example: CREATE PROCEDURE p1() AS x0 INT:=100; -- context 0, position 0, run-time 0 CURSOR cur( p0 INT, -- context 1, position 0, run-time 1 p1 INT -- context 1, position 1, run-time 2 ) IS SELECT p0, p1; x1 INT:=101; -- context 0, position 1, run-time 3 BEGIN ... END; Fixing a few methods to take this into account: - sp_pcontext::find_variable() - sp_pcontext::retrieve_field_definitions() - LEX::sp_variable_declarations_init() - LEX::sp_variable_declarations_finalize() - LEX::sp_variable_declarations_rowtype_finalize() - LEX::sp_variable_declarations_with_ref_finalize() Adding a convenience method: sp_pcontext::get_last_context_variable(uint offset_from_the_end); to access variables from the end, rather than from the beginning. This helps to loop through the context variable array (m_vars) on the fragment that does not have any holes. Additionally, renaming sp_pcontext::find_context_variable() to sp_pcontext::get_context_variable(). This method simply returns the variable by its index. So let's rename to avoid assumptions that some heavy lookup is going on inside. --- .../suite/compat/oracle/r/sp-code.result | 133 ++++++++++++++++++ .../suite/compat/oracle/r/sp-cursor.result | 89 ++++++++++++ mysql-test/suite/compat/oracle/t/sp-code.test | 84 +++++++++++ .../suite/compat/oracle/t/sp-cursor.test | 96 +++++++++++++ sql/sp_head.cc | 2 +- sql/sp_head.h | 2 +- sql/sp_pcontext.cc | 79 ++++++++++- sql/sp_pcontext.h | 14 +- sql/sql_lex.cc | 31 ++-- 9 files changed, 499 insertions(+), 31 deletions(-) diff --git a/mysql-test/suite/compat/oracle/r/sp-code.result b/mysql-test/suite/compat/oracle/r/sp-code.result index 4ac4b6115fff9..9d1b2e3f3f513 100644 --- a/mysql-test/suite/compat/oracle/r/sp-code.result +++ b/mysql-test/suite/compat/oracle/r/sp-code.result @@ -1348,3 +1348,136 @@ rec1.a rec2.a 11 DROP PROCEDURE p1; +# +# MDEV-12441 Variables declared after cursors with parameters lose values +# +CREATE PROCEDURE p1() AS +x0 INT:=100; +CURSOR cur(cp1 INT, cp2 INT) IS SELECT cp1+cp2; +x1 INT:=101; +BEGIN +OPEN cur(10,11); +CLOSE cur; +SELECT x0, x1; +END; +$$ +SHOW PROCEDURE CODE p1; +Pos Instruction +0 set x0@0 100 +1 set x1@3 101 +2 cpush cur@0 +3 set cp1@1 10 +4 set cp2@2 11 +5 copen cur@0 +6 cclose cur@0 +7 stmt 0 "SELECT x0, x1" +8 cpop 1 +CALL p1(); +x0 x1 +100 101 +DROP PROCEDURE p1; +CREATE PROCEDURE p1() AS +x0 INT:=100; +CURSOR cur0(cp1 INT, cp2 INT) IS SELECT cp1+cp2; +x1 INT:=101; +CURSOR cur1(cp1 INT, cp2 INT) IS SELECT cp1+cp2; +x2 INT:=102; +CURSOR cur2(cp1 INT, cp2 INT) IS SELECT cp1+cp2; +x3 INT:=103; +BEGIN +OPEN cur0(0,1); +CLOSE cur0; +SELECT x0, x1, x2, x3; +OPEN cur1(10,11); +CLOSE cur1; +SELECT x0, x1, x2, x3; +OPEN cur2(20,21); +CLOSE cur2; +SELECT x0, x1, x2, x3; +END; +$$ +SHOW PROCEDURE CODE p1; +Pos Instruction +0 set x0@0 100 +1 set x1@3 101 +2 set x2@6 102 +3 set x3@9 103 +4 cpush cur0@0 +5 cpush cur1@1 +6 cpush cur2@2 +7 set cp1@1 0 +8 set cp2@2 1 +9 copen cur0@0 +10 cclose cur0@0 +11 stmt 0 "SELECT x0, x1, x2, x3" +12 set cp1@4 10 +13 set cp2@5 11 +14 copen cur1@1 +15 cclose cur1@1 +16 stmt 0 "SELECT x0, x1, x2, x3" +17 set cp1@7 20 +18 set cp2@8 21 +19 copen cur2@2 +20 cclose cur2@2 +21 stmt 0 "SELECT x0, x1, x2, x3" +22 cpop 3 +CALL p1(); +x0 x1 x2 x3 +100 101 102 103 +x0 x1 x2 x3 +100 101 102 103 +x0 x1 x2 x3 +100 101 102 103 +DROP PROCEDURE p1; +CREATE TABLE t1 (a INT); +CREATE PROCEDURE p1() AS +x0 INT:=100; +CURSOR cur(cp1 INT, cp2 INT) IS SELECT cp1+cp2; +x1 t1.a%TYPE:=101; +BEGIN +OPEN cur(10,11); +CLOSE cur; +SELECT x0, x1; +END; +$$ +SHOW PROCEDURE CODE p1; +Pos Instruction +0 set x0@0 100 +1 set x1@3 101 +2 cpush cur@0 +3 set cp1@1 10 +4 set cp2@2 11 +5 copen cur@0 +6 cclose cur@0 +7 stmt 0 "SELECT x0, x1" +8 cpop 1 +CALL p1(); +x0 x1 +100 101 +DROP PROCEDURE p1; +DROP TABLE t1; +CREATE PROCEDURE p1() AS +x0 INT:=100; +CURSOR cur(cp1 INT, cp2 INT) IS SELECT cp1+cp2; +x1 ROW(a INT,b INT):=ROW(101,102); +BEGIN +OPEN cur(10,11); +CLOSE cur; +SELECT x0, x1.a, x1.b; +END; +$$ +SHOW PROCEDURE CODE p1; +Pos Instruction +0 set x0@0 100 +1 set x1@3 (101,102) +2 cpush cur@0 +3 set cp1@1 10 +4 set cp2@2 11 +5 copen cur@0 +6 cclose cur@0 +7 stmt 0 "SELECT x0, x1.a, x1.b" +8 cpop 1 +CALL p1(); +x0 x1.a x1.b +100 101 102 +DROP PROCEDURE p1; diff --git a/mysql-test/suite/compat/oracle/r/sp-cursor.result b/mysql-test/suite/compat/oracle/r/sp-cursor.result index bfade1963c915..f50fb2c84e1d7 100644 --- a/mysql-test/suite/compat/oracle/r/sp-cursor.result +++ b/mysql-test/suite/compat/oracle/r/sp-cursor.result @@ -838,3 +838,92 @@ c rec=(30,b30) DROP PROCEDURE p1; DROP TABLE t1; +# +# MDEV-12441 Variables declared after cursors with parameters lose values +# +CREATE PROCEDURE p1() AS +x0 INT:=100; +CURSOR cur(cp1 INT, cp2 INT) IS SELECT cp1+cp2; +x1 INT:=101; +BEGIN +OPEN cur(10,11); +CLOSE cur; +SELECT x0, x1; +END; +$$ +CALL p1(); +x0 x1 +100 101 +DROP PROCEDURE p1; +CREATE TABLE t1 (a INT); +CREATE PROCEDURE p1() AS +x0 INT:=100; +CURSOR cur(cp1 INT, cp2 INT) IS SELECT cp1+cp2; +x1 t1.a%TYPE:=101; +BEGIN +OPEN cur(10,11); +CLOSE cur; +SELECT x0, x1; +END; +$$ +CALL p1(); +x0 x1 +100 101 +DROP PROCEDURE p1; +DROP TABLE t1; +CREATE PROCEDURE p1() AS +x0 INT:=100; +CURSOR cur(cp1 INT, cp2 INT) IS SELECT cp1+cp2; +x1 ROW(a INT,b INT):=ROW(101,102); +BEGIN +OPEN cur(10,11); +CLOSE cur; +SELECT x0, x1.a, x1.b; +END; +$$ +CALL p1(); +x0 x1.a x1.b +100 101 102 +DROP PROCEDURE p1; +CREATE TABLE t1 (a INT, b VARCHAR(10)); +INSERT INTO t1 VALUES (10,'Tbl-t1.b0'); +CREATE PROCEDURE p1() AS +x0 INT:=100; +CURSOR cur(cp1 INT, cp2 INT) IS SELECT a,b FROM t1; +x1 t1%ROWTYPE:=ROW(101,'Var-x1.b0'); +BEGIN +SELECT x0, x1.a, x1.b; +OPEN cur(10,11); +FETCH cur INTO x1; +CLOSE cur; +SELECT x0, x1.a, x1.b; +END; +$$ +CALL p1(); +x0 x1.a x1.b +100 101 Var-x1.b0 +x0 x1.a x1.b +100 10 Tbl-t1.b0 +DROP PROCEDURE p1; +DROP TABLE t1; +CREATE TABLE t1 (a INT, b VARCHAR(10)); +INSERT INTO t1 VALUES (10,'Tbl-t1.b0'); +CREATE PROCEDURE p1() AS +x0 INT:=100; +CURSOR cur(cp1 INT, cp2 INT) IS SELECT a,b FROM t1; +x1 cur%ROWTYPE:=ROW(101,'Var-x1.b0'); +BEGIN +SELECT x0, x1.a, x1.b; +OPEN cur(10,11); +FETCH cur INTO x1; +CLOSE cur; +SELECT x0, x1.a, x1.b; +END; +$$ +CALL p1(); +x0 x1.a x1.b +100 101 Var-x1.b0 +x0 x1.a x1.b +100 10 Tbl-t1.b0 +DROP PROCEDURE p1; +DROP TABLE t1; diff --git a/mysql-test/suite/compat/oracle/t/sp-code.test b/mysql-test/suite/compat/oracle/t/sp-code.test index ce2cb011fdaa2..9a1f64e54b455 100644 --- a/mysql-test/suite/compat/oracle/t/sp-code.test +++ b/mysql-test/suite/compat/oracle/t/sp-code.test @@ -971,3 +971,87 @@ DELIMITER ;$$ SHOW PROCEDURE CODE p1; CALL p1(); DROP PROCEDURE p1; + + +--echo # +--echo # MDEV-12441 Variables declared after cursors with parameters lose values +--echo # + +DELIMITER $$; +CREATE PROCEDURE p1() AS + x0 INT:=100; + CURSOR cur(cp1 INT, cp2 INT) IS SELECT cp1+cp2; + x1 INT:=101; +BEGIN + OPEN cur(10,11); + CLOSE cur; + SELECT x0, x1; +END; +$$ +DELIMITER ;$$ +SHOW PROCEDURE CODE p1; +CALL p1(); +DROP PROCEDURE p1; + + +DELIMITER $$; +CREATE PROCEDURE p1() AS + x0 INT:=100; + CURSOR cur0(cp1 INT, cp2 INT) IS SELECT cp1+cp2; + x1 INT:=101; + CURSOR cur1(cp1 INT, cp2 INT) IS SELECT cp1+cp2; + x2 INT:=102; + CURSOR cur2(cp1 INT, cp2 INT) IS SELECT cp1+cp2; + x3 INT:=103; +BEGIN + OPEN cur0(0,1); + CLOSE cur0; + SELECT x0, x1, x2, x3; + OPEN cur1(10,11); + CLOSE cur1; + SELECT x0, x1, x2, x3; + OPEN cur2(20,21); + CLOSE cur2; + SELECT x0, x1, x2, x3; +END; +$$ +DELIMITER ;$$ +SHOW PROCEDURE CODE p1; +CALL p1(); +DROP PROCEDURE p1; + + +CREATE TABLE t1 (a INT); +DELIMITER $$; +CREATE PROCEDURE p1() AS + x0 INT:=100; + CURSOR cur(cp1 INT, cp2 INT) IS SELECT cp1+cp2; + x1 t1.a%TYPE:=101; +BEGIN + OPEN cur(10,11); + CLOSE cur; + SELECT x0, x1; +END; +$$ +DELIMITER ;$$ +SHOW PROCEDURE CODE p1; +CALL p1(); +DROP PROCEDURE p1; +DROP TABLE t1; + + +DELIMITER $$; +CREATE PROCEDURE p1() AS + x0 INT:=100; + CURSOR cur(cp1 INT, cp2 INT) IS SELECT cp1+cp2; + x1 ROW(a INT,b INT):=ROW(101,102); +BEGIN + OPEN cur(10,11); + CLOSE cur; + SELECT x0, x1.a, x1.b; +END; +$$ +DELIMITER ;$$ +SHOW PROCEDURE CODE p1; +CALL p1(); +DROP PROCEDURE p1; diff --git a/mysql-test/suite/compat/oracle/t/sp-cursor.test b/mysql-test/suite/compat/oracle/t/sp-cursor.test index 0be76053f88c8..ff9ad78e680fc 100644 --- a/mysql-test/suite/compat/oracle/t/sp-cursor.test +++ b/mysql-test/suite/compat/oracle/t/sp-cursor.test @@ -833,3 +833,99 @@ DELIMITER ;$$ CALL p1(); DROP PROCEDURE p1; DROP TABLE t1; + + +--echo # +--echo # MDEV-12441 Variables declared after cursors with parameters lose values +--echo # + +DELIMITER $$; +CREATE PROCEDURE p1() AS + x0 INT:=100; + CURSOR cur(cp1 INT, cp2 INT) IS SELECT cp1+cp2; + x1 INT:=101; +BEGIN + OPEN cur(10,11); + CLOSE cur; + SELECT x0, x1; +END; +$$ +DELIMITER ;$$ +CALL p1(); +DROP PROCEDURE p1; + + +CREATE TABLE t1 (a INT); +DELIMITER $$; +CREATE PROCEDURE p1() AS + x0 INT:=100; + CURSOR cur(cp1 INT, cp2 INT) IS SELECT cp1+cp2; + x1 t1.a%TYPE:=101; +BEGIN + OPEN cur(10,11); + CLOSE cur; + SELECT x0, x1; +END; +$$ +DELIMITER ;$$ +CALL p1(); +DROP PROCEDURE p1; +DROP TABLE t1; + + +DELIMITER $$; +CREATE PROCEDURE p1() AS + x0 INT:=100; + CURSOR cur(cp1 INT, cp2 INT) IS SELECT cp1+cp2; + x1 ROW(a INT,b INT):=ROW(101,102); +BEGIN + OPEN cur(10,11); + CLOSE cur; + SELECT x0, x1.a, x1.b; +END; +$$ +DELIMITER ;$$ +CALL p1(); +DROP PROCEDURE p1; + + +CREATE TABLE t1 (a INT, b VARCHAR(10)); +INSERT INTO t1 VALUES (10,'Tbl-t1.b0'); +DELIMITER $$; +CREATE PROCEDURE p1() AS + x0 INT:=100; + CURSOR cur(cp1 INT, cp2 INT) IS SELECT a,b FROM t1; + x1 t1%ROWTYPE:=ROW(101,'Var-x1.b0'); +BEGIN + SELECT x0, x1.a, x1.b; + OPEN cur(10,11); + FETCH cur INTO x1; + CLOSE cur; + SELECT x0, x1.a, x1.b; +END; +$$ +DELIMITER ;$$ +CALL p1(); +DROP PROCEDURE p1; +DROP TABLE t1; + + +CREATE TABLE t1 (a INT, b VARCHAR(10)); +INSERT INTO t1 VALUES (10,'Tbl-t1.b0'); +DELIMITER $$; +CREATE PROCEDURE p1() AS + x0 INT:=100; + CURSOR cur(cp1 INT, cp2 INT) IS SELECT a,b FROM t1; + x1 cur%ROWTYPE:=ROW(101,'Var-x1.b0'); +BEGIN + SELECT x0, x1.a, x1.b; + OPEN cur(10,11); + FETCH cur INTO x1; + CLOSE cur; + SELECT x0, x1.a, x1.b; +END; +$$ +DELIMITER ;$$ +CALL p1(); +DROP PROCEDURE p1; +DROP TABLE t1; diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 9bd10aac47335..a9c89aef0a874 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -4746,7 +4746,7 @@ sp_head::add_set_for_loop_cursor_param_variables(THD *thd, See more comments in LEX::sp_for_loop_cursor_declarations in sql_lex.cc. */ bool last= idx + 1 == parameters->argument_count(); - sp_variable *spvar= param_spcont->find_context_variable(idx); + sp_variable *spvar= param_spcont->get_context_variable(idx); if (set_local_variable(thd, param_spcont, spvar, parameters->arguments()[idx], param_lex, last)) diff --git a/sql/sp_head.h b/sql/sp_head.h index 9f42ad151aafb..78ec6e0e5b011 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -399,7 +399,7 @@ class sp_head :private Query_arena, sp_assignment_lex *prm) { DBUG_ASSERT(idx < param_spcont->context_var_count()); - sp_variable *spvar= param_spcont->find_context_variable(idx); + sp_variable *spvar= param_spcont->get_context_variable(idx); /* add_instr() gets free_list from m_thd->free_list. Initialize it before the set_local_variable() call. diff --git a/sql/sp_pcontext.cc b/sql/sp_pcontext.cc index dd70c444d4ebf..93d7bc1128167 100644 --- a/sql/sp_pcontext.cc +++ b/sql/sp_pcontext.cc @@ -222,10 +222,46 @@ sp_variable *sp_pcontext::find_variable(LEX_STRING name, } +/* + Find a variable by its run-time offset. + If the variable with a desired run-time offset is not found in this + context frame, it's recursively searched on parent context frames. + + Note, context frames can have holes: + CREATE PROCEDURE p1() AS + x0 INT:=100; + CURSOR cur(p0 INT, p1 INT) IS SELECT p0, p1; + x1 INT:=101; + BEGIN + ... + END; + The variables (x0 and x1) and the cursor parameters (p0 and p1) + reside in separate parse context frames. + + The variables reside on the top level parse context frame: + - x0 has frame offset 0 and run-time offset 0 + - x1 has frame offset 1 and run-time offset 3 + + The cursor parameters reside on the second level parse context frame: + - p0 has frame offset 0 and run-time offset 1 + - p1 has frame offset 1 and run-time offset 2 + + Run-time offsets on a frame can have holes, but offsets monotonocally grow, + so run-time offsets of all variables are not greater than the run-time offset + of the very last variable in this frame. +*/ sp_variable *sp_pcontext::find_variable(uint offset) const { - if (m_var_offset <= offset && offset < m_var_offset + m_vars.elements()) - return m_vars.at(offset - m_var_offset); // This frame + if (m_var_offset <= offset && + m_vars.elements() && + offset <= get_last_context_variable()->offset) + { + for (uint i= 0; i < m_vars.elements(); i++) + { + if (m_vars.at(i)->offset == offset) + return m_vars.at(i); // This frame + } + } return m_parent ? m_parent->find_variable(offset) : // Some previous frame @@ -236,7 +272,7 @@ sp_variable *sp_pcontext::find_variable(uint offset) const sp_variable *sp_pcontext::add_variable(THD *thd, LEX_STRING name) { sp_variable *p= - new (thd->mem_root) sp_variable(name, current_var_count()); + new (thd->mem_root) sp_variable(name, m_var_offset + m_max_var_index); if (!p) return NULL; @@ -593,16 +629,49 @@ void sp_pcontext::retrieve_field_definitions( { /* Put local/context fields in the result list. */ + size_t next_child= 0; for (size_t i= 0; i < m_vars.elements(); ++i) { sp_variable *var_def= m_vars.at(i); + /* + The context can have holes in run-time offsets, + the missing offsets reside on the children contexts in such cases. + Example: + CREATE PROCEDURE p1() AS + x0 INT:=100; -- context 0, position 0, run-time 0 + CURSOR cur( + p0 INT, -- context 1, position 0, run-time 1 + p1 INT -- context 1, position 1, run-time 2 + ) IS SELECT p0, p1; + x1 INT:=101; -- context 0, position 1, run-time 3 + BEGIN + ... + END; + See more comments in sp_pcontext::find_variable(). + We must retrieve the definitions in the order of their run-time offsets. + Check that there are children that should go before the current variable. + */ + for ( ; next_child < m_children.elements(); next_child++) + { + sp_pcontext *child= m_children.at(next_child); + if (!child->context_var_count() || + child->get_context_variable(0)->offset > var_def->offset) + break; + /* + All variables on the embedded context (that fills holes of the parent) + should have the run-time offset strictly less than var_def. + */ + DBUG_ASSERT(child->get_context_variable(0)->offset < var_def->offset); + DBUG_ASSERT(child->get_last_context_variable()->offset < var_def->offset); + child->retrieve_field_definitions(field_def_lst); + } field_def_lst->push_back(&var_def->field_def); } - /* Put the fields of the enclosed contexts in the result list. */ + /* Put the fields of the remaining enclosed contexts in the result list. */ - for (size_t i= 0; i < m_children.elements(); ++i) + for (size_t i= next_child; i < m_children.elements(); ++i) m_children.at(i)->retrieve_field_definitions(field_def_lst); } diff --git a/sql/sp_pcontext.h b/sql/sp_pcontext.h index 98ab49551980d..c6c8084fee298 100644 --- a/sql/sp_pcontext.h +++ b/sql/sp_pcontext.h @@ -440,15 +440,21 @@ class sp_pcontext : public Sql_alloc { return m_vars.elements(); } /// return the i-th variable on the current context - sp_variable *find_context_variable(uint i) const + sp_variable *get_context_variable(uint i) const { DBUG_ASSERT(i < m_vars.elements()); return m_vars.at(i); } - /// @return map index in this parsing context to runtime offset. - uint var_context2runtime(uint i) const - { return m_var_offset + i; } + /* + Return the i-th last context variable. + If i is 0, then return the very last variable in m_vars. + */ + sp_variable *get_last_context_variable(uint i= 0) const + { + DBUG_ASSERT(i < m_vars.elements()); + return m_vars.at(m_vars.elements() - i - 1); + } /// Add SP-variable to the parsing context. /// diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index f79acbffa40dd..38a6e84f509a2 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -5211,10 +5211,7 @@ bool LEX::init_default_internal_variable(struct sys_var_with_base *variable, void LEX::sp_variable_declarations_init(THD *thd, int nvars) { - // get the last variable: - uint num_vars= spcont->context_var_count(); - uint var_idx= spcont->var_context2runtime(num_vars - 1); - sp_variable *spvar= spcont->find_variable(var_idx); + sp_variable *spvar= spcont->get_last_context_variable(); sphead->reset_lex(thd); spcont->declare_var_boundary(nvars); @@ -5227,8 +5224,6 @@ bool LEX::sp_variable_declarations_finalize(THD *thd, int nvars, Row_definition_list *row, Item *dflt_value_item) { - uint num_vars= spcont->context_var_count(); - if (!dflt_value_item && !(dflt_value_item= new (thd->mem_root) Item_null(thd))) return true; @@ -5248,11 +5243,10 @@ bool LEX::sp_variable_declarations_finalize(THD *thd, int nvars, if (row && sphead->row_fill_field_definitions(thd, row)) return true; - for (uint i= num_vars - nvars ; i < num_vars ; i++) + for (uint i= 0 ; i < (uint) nvars ; i++) { - uint var_idx= spcont->var_context2runtime(i); - sp_variable *spvar= spcont->find_variable(var_idx); - bool last= i == num_vars - 1; + sp_variable *spvar= spcont->get_last_context_variable((uint) nvars - 1 - i); + bool last= i + 1 == (uint) nvars; if (!spvar) return true; @@ -5271,7 +5265,7 @@ bool LEX::sp_variable_declarations_finalize(THD *thd, int nvars, /* The last instruction is responsible for freeing LEX. */ sp_instr_set *is= new (this->thd->mem_root) sp_instr_set(sphead->instructions(), - spcont, var_idx, dflt_value_item, + spcont, spvar->offset, dflt_value_item, this, last); if (is == NULL || sphead->add_instr(is)) return true; @@ -5299,17 +5293,15 @@ LEX::sp_variable_declarations_rowtype_finalize(THD *thd, int nvars, uint coffp; const sp_pcursor *pcursor= ref->table.str && ref->db.str ? NULL : spcont->find_cursor(ref->m_column, &coffp, false); - uint num_vars= spcont->context_var_count(); if (!def && !(def= new (thd->mem_root) Item_null(thd))) return true; // Loop through all variables in the same declaration - for (uint i= num_vars - nvars; i < num_vars; i++) + for (uint i= 0 ; i < (uint) nvars; i++) { - bool last= i == num_vars - 1; - uint var_idx= spcont->var_context2runtime(i); - sp_variable *spvar= spcont->find_context_variable(i); + bool last= i + 1 == (uint) nvars; + sp_variable *spvar= spcont->get_last_context_variable((uint) nvars - 1 - i); if (pcursor) { @@ -5347,7 +5339,7 @@ LEX::sp_variable_declarations_rowtype_finalize(THD *thd, int nvars, /* The last instruction is responsible for freeing LEX. */ sp_instr_set *is= new (this->thd->mem_root) sp_instr_set(sphead->instructions(), - spcont, var_idx, def, + spcont, spvar->offset, def, this, last); if (is == NULL || sphead->add_instr(is)) return true; @@ -5364,10 +5356,9 @@ LEX::sp_variable_declarations_with_ref_finalize(THD *thd, int nvars, Qualified_column_ident *ref, Item *def) { - uint num_vars= spcont->context_var_count(); - for (uint i= num_vars - nvars; i < num_vars; i++) + for (uint i= 0 ; i < (uint) nvars; i++) { - sp_variable *spvar= spcont->find_context_variable(i); + sp_variable *spvar= spcont->get_last_context_variable((uint) nvars - 1 - i); spvar->field_def.set_column_type_ref(ref); spvar->field_def.field_name= spvar->name.str; }