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:
@@ -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);
|
||||
|
Reference in New Issue
Block a user