mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
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.
This commit is contained in:
@ -1348,3 +1348,136 @@ rec1.a
|
|||||||
rec2.a
|
rec2.a
|
||||||
11
|
11
|
||||||
DROP PROCEDURE p1;
|
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;
|
||||||
|
@ -838,3 +838,92 @@ c
|
|||||||
rec=(30,b30)
|
rec=(30,b30)
|
||||||
DROP PROCEDURE p1;
|
DROP PROCEDURE p1;
|
||||||
DROP TABLE t1;
|
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;
|
||||||
|
@ -971,3 +971,87 @@ DELIMITER ;$$
|
|||||||
SHOW PROCEDURE CODE p1;
|
SHOW PROCEDURE CODE p1;
|
||||||
CALL p1();
|
CALL p1();
|
||||||
DROP PROCEDURE 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;
|
||||||
|
@ -833,3 +833,99 @@ DELIMITER ;$$
|
|||||||
CALL p1();
|
CALL p1();
|
||||||
DROP PROCEDURE p1;
|
DROP PROCEDURE p1;
|
||||||
DROP TABLE t1;
|
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;
|
||||||
|
@ -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.
|
See more comments in LEX::sp_for_loop_cursor_declarations in sql_lex.cc.
|
||||||
*/
|
*/
|
||||||
bool last= idx + 1 == parameters->argument_count();
|
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,
|
if (set_local_variable(thd, param_spcont,
|
||||||
spvar, parameters->arguments()[idx],
|
spvar, parameters->arguments()[idx],
|
||||||
param_lex, last))
|
param_lex, last))
|
||||||
|
@ -399,7 +399,7 @@ private:
|
|||||||
sp_assignment_lex *prm)
|
sp_assignment_lex *prm)
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(idx < param_spcont->context_var_count());
|
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.
|
add_instr() gets free_list from m_thd->free_list.
|
||||||
Initialize it before the set_local_variable() call.
|
Initialize it before the set_local_variable() call.
|
||||||
|
@ -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
|
sp_variable *sp_pcontext::find_variable(uint offset) const
|
||||||
{
|
{
|
||||||
if (m_var_offset <= offset && offset < m_var_offset + m_vars.elements())
|
if (m_var_offset <= offset &&
|
||||||
return m_vars.at(offset - m_var_offset); // This frame
|
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 ?
|
return m_parent ?
|
||||||
m_parent->find_variable(offset) : // Some previous frame
|
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 *sp_pcontext::add_variable(THD *thd, LEX_STRING name)
|
||||||
{
|
{
|
||||||
sp_variable *p=
|
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)
|
if (!p)
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -593,16 +629,49 @@ void sp_pcontext::retrieve_field_definitions(
|
|||||||
{
|
{
|
||||||
/* Put local/context fields in the result list. */
|
/* Put local/context fields in the result list. */
|
||||||
|
|
||||||
|
size_t next_child= 0;
|
||||||
for (size_t i= 0; i < m_vars.elements(); ++i)
|
for (size_t i= 0; i < m_vars.elements(); ++i)
|
||||||
{
|
{
|
||||||
sp_variable *var_def= m_vars.at(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);
|
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);
|
m_children.at(i)->retrieve_field_definitions(field_def_lst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -440,15 +440,21 @@ public:
|
|||||||
{ return m_vars.elements(); }
|
{ return m_vars.elements(); }
|
||||||
|
|
||||||
/// return the i-th variable on the current context
|
/// 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());
|
DBUG_ASSERT(i < m_vars.elements());
|
||||||
return m_vars.at(i);
|
return m_vars.at(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @return map index in this parsing context to runtime offset.
|
/*
|
||||||
uint var_context2runtime(uint i) const
|
Return the i-th last context variable.
|
||||||
{ return m_var_offset + i; }
|
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.
|
/// Add SP-variable to the parsing context.
|
||||||
///
|
///
|
||||||
|
@ -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)
|
void LEX::sp_variable_declarations_init(THD *thd, int nvars)
|
||||||
{
|
{
|
||||||
// get the last variable:
|
sp_variable *spvar= spcont->get_last_context_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);
|
|
||||||
|
|
||||||
sphead->reset_lex(thd);
|
sphead->reset_lex(thd);
|
||||||
spcont->declare_var_boundary(nvars);
|
spcont->declare_var_boundary(nvars);
|
||||||
@ -5227,8 +5224,6 @@ bool LEX::sp_variable_declarations_finalize(THD *thd, int nvars,
|
|||||||
Row_definition_list *row,
|
Row_definition_list *row,
|
||||||
Item *dflt_value_item)
|
Item *dflt_value_item)
|
||||||
{
|
{
|
||||||
uint num_vars= spcont->context_var_count();
|
|
||||||
|
|
||||||
if (!dflt_value_item &&
|
if (!dflt_value_item &&
|
||||||
!(dflt_value_item= new (thd->mem_root) Item_null(thd)))
|
!(dflt_value_item= new (thd->mem_root) Item_null(thd)))
|
||||||
return true;
|
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))
|
if (row && sphead->row_fill_field_definitions(thd, row))
|
||||||
return true;
|
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->get_last_context_variable((uint) nvars - 1 - i);
|
||||||
sp_variable *spvar= spcont->find_variable(var_idx);
|
bool last= i + 1 == (uint) nvars;
|
||||||
bool last= i == num_vars - 1;
|
|
||||||
|
|
||||||
if (!spvar)
|
if (!spvar)
|
||||||
return true;
|
return true;
|
||||||
@ -5271,7 +5265,7 @@ bool LEX::sp_variable_declarations_finalize(THD *thd, int nvars,
|
|||||||
/* The last instruction is responsible for freeing LEX. */
|
/* The last instruction is responsible for freeing LEX. */
|
||||||
sp_instr_set *is= new (this->thd->mem_root)
|
sp_instr_set *is= new (this->thd->mem_root)
|
||||||
sp_instr_set(sphead->instructions(),
|
sp_instr_set(sphead->instructions(),
|
||||||
spcont, var_idx, dflt_value_item,
|
spcont, spvar->offset, dflt_value_item,
|
||||||
this, last);
|
this, last);
|
||||||
if (is == NULL || sphead->add_instr(is))
|
if (is == NULL || sphead->add_instr(is))
|
||||||
return true;
|
return true;
|
||||||
@ -5299,17 +5293,15 @@ LEX::sp_variable_declarations_rowtype_finalize(THD *thd, int nvars,
|
|||||||
uint coffp;
|
uint coffp;
|
||||||
const sp_pcursor *pcursor= ref->table.str && ref->db.str ? NULL :
|
const sp_pcursor *pcursor= ref->table.str && ref->db.str ? NULL :
|
||||||
spcont->find_cursor(ref->m_column, &coffp, false);
|
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)))
|
if (!def && !(def= new (thd->mem_root) Item_null(thd)))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Loop through all variables in the same declaration
|
// 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;
|
bool last= i + 1 == (uint) nvars;
|
||||||
uint var_idx= spcont->var_context2runtime(i);
|
sp_variable *spvar= spcont->get_last_context_variable((uint) nvars - 1 - i);
|
||||||
sp_variable *spvar= spcont->find_context_variable(i);
|
|
||||||
|
|
||||||
if (pcursor)
|
if (pcursor)
|
||||||
{
|
{
|
||||||
@ -5347,7 +5339,7 @@ LEX::sp_variable_declarations_rowtype_finalize(THD *thd, int nvars,
|
|||||||
/* The last instruction is responsible for freeing LEX. */
|
/* The last instruction is responsible for freeing LEX. */
|
||||||
sp_instr_set *is= new (this->thd->mem_root)
|
sp_instr_set *is= new (this->thd->mem_root)
|
||||||
sp_instr_set(sphead->instructions(),
|
sp_instr_set(sphead->instructions(),
|
||||||
spcont, var_idx, def,
|
spcont, spvar->offset, def,
|
||||||
this, last);
|
this, last);
|
||||||
if (is == NULL || sphead->add_instr(is))
|
if (is == NULL || sphead->add_instr(is))
|
||||||
return true;
|
return true;
|
||||||
@ -5364,10 +5356,9 @@ LEX::sp_variable_declarations_with_ref_finalize(THD *thd, int nvars,
|
|||||||
Qualified_column_ident *ref,
|
Qualified_column_ident *ref,
|
||||||
Item *def)
|
Item *def)
|
||||||
{
|
{
|
||||||
uint num_vars= spcont->context_var_count();
|
for (uint i= 0 ; i < (uint) nvars; i++)
|
||||||
for (uint i= num_vars - nvars; i < num_vars; 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.set_column_type_ref(ref);
|
||||||
spvar->field_def.field_name= spvar->name.str;
|
spvar->field_def.field_name= spvar->name.str;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user