diff options
author | Alexander Barkov <bar@mariadb.org> | 2017-03-08 23:20:39 +0400 |
---|---|---|
committer | Alexander Barkov <bar@mariadb.org> | 2017-04-05 15:02:59 +0400 |
commit | f429b5a834439e4f0c76e893487e33027d76b74b (patch) | |
tree | a06ec92dad05a2820ecd8a9afe73696b103536a3 /sql/sp_head.h | |
parent | 1b8a0c879d80733e3c684080b8c7719c35642e0d (diff) | |
download | mariadb-git-f429b5a834439e4f0c76e893487e33027d76b74b.tar.gz |
MDEV-12011 sql_mode=ORACLE: cursor%ROWTYPE in variable declarations
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.
Diffstat (limited to 'sql/sp_head.h')
-rw-r--r-- | sql/sp_head.h | 65 |
1 files changed, 65 insertions, 0 deletions
diff --git a/sql/sp_head.h b/sql/sp_head.h index 92f17884285..37ef4b6825f 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -341,6 +341,8 @@ public: bool show_create_routine(THD *thd, int type); + MEM_ROOT *get_main_mem_root() { return &main_mem_root; } + int add_instr(sp_instr *instr); @@ -767,6 +769,42 @@ private: }; // class sp_head : public Sql_alloc +class sp_lex_cursor: public sp_lex_local, public Query_arena +{ +public: + sp_lex_cursor(THD *thd, const LEX *oldlex, MEM_ROOT *mem_root_arg) + :sp_lex_local(thd, oldlex), + Query_arena(mem_root_arg, STMT_INITIALIZED_FOR_SP) + { } + sp_lex_cursor(THD *thd, const LEX *oldlex) + :sp_lex_local(thd, oldlex), + Query_arena(thd->lex->sphead->get_main_mem_root(), STMT_INITIALIZED_FOR_SP) + { } + ~sp_lex_cursor() { free_items(); } + void cleanup_stmt() { } + Query_arena *query_arena() { return this; } + bool validate() + { + DBUG_ASSERT(sql_command == SQLCOM_SELECT); + if (result) + { + my_error(ER_SP_BAD_CURSOR_SELECT, MYF(0)); + return true; + } + return false; + } + bool stmt_finalize(THD *thd) + { + if (validate()) + return true; + sp_lex_in_use= true; + free_list= thd->free_list; + thd->free_list= NULL; + return false; + } +}; + + // // "Instructions"... // @@ -924,6 +962,9 @@ public: int reset_lex_and_exec_core(THD *thd, uint *nextp, bool open_tables, sp_instr* instr); + int cursor_reset_lex_and_exec_core(THD *thd, uint *nextp, bool open_tables, + sp_instr *instr); + inline uint sql_command() const { return (uint)m_lex->sql_command; @@ -1550,6 +1591,30 @@ private: }; // class sp_instr_copen : public sp_instr_stmt +/** + Initialize the structure of a cursor%ROWTYPE variable + from the LEX containing the cursor SELECT statement. +*/ +class sp_instr_cursor_copy_struct: public sp_instr +{ + /**< Prevent use of these */ + sp_instr_cursor_copy_struct(const sp_instr_cursor_copy_struct &); + void operator=(sp_instr_cursor_copy_struct &); + sp_lex_keeper m_lex_keeper; + uint m_var; +public: + sp_instr_cursor_copy_struct(uint ip, sp_pcontext *ctx, + sp_lex_cursor *lex, uint voffs) + : sp_instr(ip, ctx), m_lex_keeper(lex, FALSE), m_var(voffs) + {} + virtual ~sp_instr_cursor_copy_struct() + {} + virtual int execute(THD *thd, uint *nextp); + virtual int exec_core(THD *thd, uint *nextp); + virtual void print(String *str); +}; + + class sp_instr_cclose : public sp_instr { sp_instr_cclose(const sp_instr_cclose &); /**< Prevent use of these */ |