1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-08 11:22:35 +03:00

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.
This commit is contained in:
Alexander Barkov
2017-03-08 23:20:39 +04:00
parent 1b8a0c879d
commit f429b5a834
20 changed files with 2447 additions and 85 deletions

View File

@@ -5297,6 +5297,9 @@ LEX::sp_variable_declarations_rowtype_finalize(THD *thd, int nvars,
Qualified_column_ident *ref,
Item *def)
{
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)))
@@ -5307,24 +5310,41 @@ LEX::sp_variable_declarations_rowtype_finalize(THD *thd, int nvars,
bool last= i == num_vars - 1;
uint var_idx= spcont->var_context2runtime(i);
sp_variable *spvar= spcont->find_context_variable(i);
/*
When parsing a qualified identifier chain, the parser does not know yet
if it's going to be a qualified column name (for %TYPE),
or a qualified table name (for %ROWTYPE). So it collects the chain
into Qualified_column_ident.
Now we know that it was actually a qualified table name (%ROWTYPE).
Create a new Table_ident from Qualified_column_ident,
shifting fields as follows:
- ref->m_column becomes table_ref->table
- ref->table becomes table_ref->db
*/
Table_ident *table_ref;
if (!(table_ref= new (thd->mem_root) Table_ident(thd,
ref->table,
ref->m_column,
false)))
return true;
spvar->field_def.set_table_rowtype_ref(table_ref);
if (pcursor)
{
Cursor_rowtype *ref;
if (!(ref= new (thd->mem_root) Cursor_rowtype(coffp)))
return true;
spvar->field_def.set_cursor_rowtype_ref(ref);
sp_instr_cursor_copy_struct *instr=
new (thd->mem_root) sp_instr_cursor_copy_struct(sphead->instructions(),
spcont, pcursor->lex(),
spvar->offset);
if (instr == NULL || sphead->add_instr(instr))
return true;
}
else
{
/*
When parsing a qualified identifier chain, the parser does not know yet
if it's going to be a qualified column name (for %TYPE),
or a qualified table name (for %ROWTYPE). So it collects the chain
into Qualified_column_ident.
Now we know that it was actually a qualified table name (%ROWTYPE).
Create a new Table_ident from Qualified_column_ident,
shifting fields as follows:
- ref->m_column becomes table_ref->table
- ref->table becomes table_ref->db
*/
Table_ident *table_ref;
if (!(table_ref= new (thd->mem_root) Table_ident(thd,
ref->table,
ref->m_column,
false)))
return true;
spvar->field_def.set_table_rowtype_ref(table_ref);
}
spvar->field_def.field_name= spvar->name.str;
spvar->default_value= def;
/* The last instruction is responsible for freeing LEX. */
@@ -5485,7 +5505,8 @@ bool LEX::sp_for_loop_finalize(THD *thd, const Lex_for_loop_st &loop)
/***************************************************************************/
bool LEX::sp_declare_cursor(THD *thd, const LEX_STRING name, LEX *cursor_stmt,
bool LEX::sp_declare_cursor(THD *thd, const LEX_STRING name,
sp_lex_cursor *cursor_stmt,
sp_pcontext *param_ctx)
{
uint offp;
@@ -5501,7 +5522,7 @@ bool LEX::sp_declare_cursor(THD *thd, const LEX_STRING name, LEX *cursor_stmt,
spcont->current_cursor_count());
return i == NULL ||
sphead->add_instr(i) ||
spcont->add_cursor(name, param_ctx);
spcont->add_cursor(name, param_ctx, cursor_stmt);
}
@@ -6178,7 +6199,8 @@ Item_splocal *LEX::create_item_spvar_row_field(THD *thd,
}
Item_splocal *item;
if (spv->field_def.is_table_rowtype_ref())
if (spv->field_def.is_table_rowtype_ref() ||
spv->field_def.is_cursor_rowtype_ref())
{
if (!(item= new (thd->mem_root)
Item_splocal_row_field_by_name(thd, a, b, spv->offset,
@@ -6406,7 +6428,8 @@ bool LEX::set_variable(const LEX_STRING &name1,
sp_variable *spv;
if (spcont && (spv= spcont->find_variable(name1, false)))
{
if (spv->field_def.is_table_rowtype_ref())
if (spv->field_def.is_table_rowtype_ref() ||
spv->field_def.is_cursor_rowtype_ref())
return sphead->set_local_variable_row_field_by_name(thd, spcont,
spv, name2,
item, this);