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.
Implementing cursor%ROWTYPE variables, according to the task description.
This patch includes a refactoring in how sp_instr_cpush and sp_instr_copen
work. This is needed to implement MDEV-10598 later easier, to allow variable
declarations go after cursor declarations (which is currently not allowed).
Before this patch, sp_instr_cpush worked as a Query_arena associated with
the cursor. sp_instr_copen::execute() switched to the sp_instr_cpush's
Query_arena when executing the cursor SELECT statement.
Now the Query_arena associated with the cursor is stored inside an instance
of a new class sp_lex_cursor (a LEX descendand) that contains the cursor SELECT
statement.
This simplifies the implementation, because:
- It's easier to follow the code when everything related to execution
of the cursor SELECT statement is stored inside the same sp_lex_cursor
object (rather than distributed between LEX and sp_instr_cpush).
- It's easier to link an sp_instr_cursor_copy_struct to
sp_lex_cursor rather than to sp_instr_cpush.
- Also, it allows to perform sp_instr_cursor_copy_struct::exec_core()
without having a pointer to sp_instr_cpush, using a pointer to sp_lex_cursor
instead. This will be important for MDEV-10598, because sp_instr_cpush will
happen *after* sp_instr_cursor_copy_struct.
After MDEV-10598 is done, this declaration:
DECLARE
CURSOR cur IS SELECT * FROM t1;
rec cur%ROWTYPE;
BEGIN
OPEN cur;
FETCH cur INTO rec;
CLOSE cur;
END;
will generate about this code:
+-----+--------------------------+
| Pos | Instruction |
+-----+--------------------------+
| 0 | cursor_copy_struct rec@0 | Points to sp_cursor_lex through m_lex_keeper
| 1 | set rec@0 NULL |
| 2 | cpush cur@0 | Points to sp_cursor_lex through m_lex_keeper
| 3 | copen cur@0 | Points to sp_cursor_lex through m_cursor
| 4 | cfetch cur@0 rec@0 |
| 5 | cclose cur@0 |
| 6 | cpop 1 |
+-----+--------------------------+
Notice, "cursor_copy_struct" and "set" will go before "cpush".
Instructions at positions 0, 2, 3 point to the same sp_cursor_lex instance.
Fixed that the ITERATE statement inside a FOR LOOP statement did not
increment the index variable before jumping to the beginning
of the loop, which caused the loop to repeat endlessly.
Part 5: EXIT statement
Adding unconditional EXIT statement:
EXIT [ label ]
Conditional EXIT statements with WHERE clause
will be added in a separate patch.
- Part 9: EXCEPTION handlers
The top-most stored routine blocks now support EXCEPTION clause
in its correct place:
AS [ declarations ]
BEGIN statements
[ EXCEPTION exceptions ]
END
Inner block will be done in a separate commit.
- Part 14: IN OUT instead of INOUT (in SP parameter declarations)