From b12430adc716be51810953920448563c87fe0521 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Mon, 29 Jan 2018 12:01:17 +0400 Subject: MDEV-15107 Add virtual Field::sp_prepare_and_store_item(), make sp_rcontext symmetric for scalar and ROW After MDEV-14212, the Virtual_tmp_table instance that stores a ROW variable elements is accessible from the underlying Field_row (rather than Item_field_row). This patch makes some further changes by moving the code from sp_instr_xxx, sp_rcontext, Item_xxx to Virtual_tmp_table and Field_xxx. The data type specific code (scalar vs ROW) now resides in a new virtual method Field_xxx::sp_prepare_and_store_item(). The the code in sp_rcontext::set_variable() and sp_eval_expr() is now symmetric for scalar and ROW values. The code in sp_rcontext::set_variable_row_field(), sp_rcontext::set_variable_row_field(), sp_rcontext::set_variable_row() is now symmetric for ROW elements (i.e. scalar and ROW elements inside a ROW). Rationale: Prepare the code to implement these tasks soon easier: - MDEV-12252 ROW data type for stored function return values - MDEV-12307 ROW data type for built-in function return values - MDEV-6121 Data type: Array - MDEV-10593 sql_mode=ORACLE: TYPE .. AS OBJECT: basic functionality - ROW with ROW fields (no MDEV yet) Details: 1. Moving the code in sp_eval_expr() responsible to backup/restore thd->count_cuted_fields, thd->abort_on_warning, thd->transaction.stmt.modified_non_trans_table into a new helper class Sp_eval_expr_state, to reuse it easier. Fixing sp_eval_expr() to use this new class. 2. Moving sp_eval_expr() and sp_prepare_func_item() from public functions to methods in THD, so they can be reused in *.cc files easier without a need to include "sp_head.h". Splitting sp_prepare_func_item() into two parts. Adding a new function sp_fix_func_item(), which fixes the underlying items, but does not do check_cols() for them. Reusing sp_fix_func_item() in Field_row::sp_prepare_and_store_item(). 3. Moving the code to find ROW fields by name from Item to Virtual_tmp_table Moving the code searching for ROW fields by their names from Item_field_row::element_index_by_name() to a new method Item_field_row to Virtual_tmp_table::sp_find_field_by_name(). Adding wrapper methods sp_rcontext::find_row_field_by_name() and find_row_field_by_name_or_error(), to search for a ROW variable fields by the variable offset and its field name. Changing Item_splocal_row_field_by_name::fix_fields() to do use sp_rcontext::find_row_field_by_name_or_error(). Removing virtual Item::element_index_by_name(). 4. Splitting sp_rcontext::set_variable() Adding a new virtual method Field::sp_prepare_and_store_item(). Spliting the two branches of the code in sp_rcontext::set_variable() into two virtual implementations of Field::sp_prepare_and_store_item(), (for Field and for Field_row). Moving the former part of sp_rcontext::set_variable() with the loop doing set_null() for all ROW fields into a new method Virtual_tmp_table::set_all_fields_to_null() and using it in Field_row::sp_prepare_and_store_item(). Moving the former part of sp_rcontext::set_variable() with the loop doing set_variable_row_field() into a new method Virtual_tmp_table::set_all_fields_from_item() and using it in Field_row::sp_prepare_and_store_item(). The loop in the new method now uses sp_prepare_and_store_item() instead of set_variable_row_field(), because saving/restoring THD flags is now done on the upper level. No needs to save/restore on every iteration. 5. Fixing sp_eval_expr() to simply do two things: - backup/restore THD flags - call result_field->sp_prepare_and_store_item() So now sp_eval_expr() can be used for both scalar and ROW variables. Reusing it in sp_rcontext::set_variable*(). 6. Moving the loop in sp_rcontext::set_variable_row() into a new method Virtual_tmp_table::sp_set_all_fields_from_item_list(). Changing the loop body to call field->sp_prepare_and_store_item() instead of doing set_variable_row_field(). This removes saving/restoring of the THD flags from every interation. Instead, adding the code to save/restore the flags around the entire loop in set_variable_row(), using Sp_eval_expr_state. So now saving/restoring is done only once for the entire ROW (a slight performance improvement). 7. Removing the code in sp_instr_set::exec_core() that sets a variable to NULL if the value evaluation failed. sp_rcontext::set_variable() now makes sure to reset the variable properly by effectively calling sp_eval_expr(), which calls virtual Field::sp_prepare_and_store_item(). Removing the similar code from sp_instr_set_row_field::exec_core() and sp_instr_set_row_field_by_name::exec_core(). Removing the method sp_rcontext::set_variable_row_field_to_null(), as it's not used any more. 8. Removing the call for sp_prepare_func_item() from sp_rcontext::set_variable_row_field(), as it was duplicate: it was done inside sp_eval_expr(). Now it's done inside virtual Field::sp_prepare_and_store_item(). 9. Moving the code from sp_instr_set_row_field_by_name::exec_core() into sp_rcontext::set_variable_row_field_by_name(), for symmetry with other sp_instr_set*::exec_core()/sp_rcontext::set_variable*() pairs. Now sp_instr_set_row_field_by_name::exec_core() calls sp_rcontext::set_variable_row_field_by_name(). 10. Misc: - Adding a helper private method sp_rcontext::virtual_tmp_table_for_row(), reusing it in a new sp_rcontext methods. - Removing Item_field_row::get_row_field(), as it's not used any more. - Removing the "Item *result_item" from sp_eval_expr(), as it's not needed any more. --- sql/sp_rcontext.cc | 135 ++++++++++++++++++----------------------------------- 1 file changed, 45 insertions(+), 90 deletions(-) (limited to 'sql/sp_rcontext.cc') diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc index 62b5439d84d..43d033ad83e 100644 --- a/sql/sp_rcontext.cc +++ b/sql/sp_rcontext.cc @@ -388,22 +388,13 @@ bool Item_field_row::row_create_items(THD *thd, List *list) } -Field *Item_field_row::get_row_field(uint i) const -{ - DBUG_ASSERT(field); - Virtual_tmp_table **ptable= field->virtual_tmp_table_addr(); - DBUG_ASSERT(ptable); - return ptable[0]->field[i]; -} - - bool sp_rcontext::set_return_value(THD *thd, Item **return_value_item) { DBUG_ASSERT(m_return_value_fld); m_return_value_set = true; - return sp_eval_expr(thd, NULL, m_return_value_fld, return_value_item); + return thd->sp_eval_expr(m_return_value_fld, return_value_item); } @@ -612,84 +603,31 @@ uint sp_rcontext::exit_handler(Diagnostics_area *da) int sp_rcontext::set_variable(THD *thd, uint idx, Item **value) { - Field *field= m_var_table->field[idx]; - if (!value) - { - field->set_null(); - return 0; - } - Item *dst= m_var_items[idx]; - - if (dst->cmp_type() != ROW_RESULT) - return sp_eval_expr(thd, dst, m_var_table->field[idx], value); - - DBUG_ASSERT(dst->type() == Item::FIELD_ITEM); - if (value[0]->type() == Item::NULL_ITEM) - { - /* - We're in a auto-generated sp_inst_set, to assign - the explicit default NULL value to a ROW variable. - */ - for (uint i= 0; i < dst->cols(); i++) - { - Item_field_row *item_field_row= (Item_field_row*) dst; - item_field_row->get_row_field(i)->set_null(); - } - return false; - } - - /** - - In case if we're assigning a ROW variable from another ROW variable, - value[0] points to Item_splocal. sp_prepare_func_item() will return the - fixed underlying Item_field_spvar with ROW members in its aguments(). - - In case if we're assigning from a ROW() value, src and value[0] will - point to the same Item_row. - */ - Item *src; - if (!(src= sp_prepare_func_item(thd, value, dst->cols())) || - src->cmp_type() != ROW_RESULT) - { - my_error(ER_OPERAND_COLUMNS, MYF(0), dst->cols()); - return true; - } - DBUG_ASSERT(dst->cols() == src->cols()); - for (uint i= 0; i < src->cols(); i++) - set_variable_row_field(thd, idx, i, src->addr(i)); - return false; -} - - -void sp_rcontext::set_variable_row_field_to_null(THD *thd, - uint var_idx, - uint field_idx) -{ - Item *dst= get_item(var_idx); - DBUG_ASSERT(dst->type() == Item::FIELD_ITEM); - DBUG_ASSERT(dst->cmp_type() == ROW_RESULT); - Item_field_row *item_field_row= (Item_field_row*) dst; - item_field_row->get_row_field(field_idx)->set_null(); + DBUG_ENTER("sp_rcontext::set_variable"); + DBUG_ASSERT(value); + DBUG_RETURN(thd->sp_eval_expr(m_var_table->field[idx], value)); } int sp_rcontext::set_variable_row_field(THD *thd, uint var_idx, uint field_idx, Item **value) { + DBUG_ENTER("sp_rcontext::set_variable_row_field"); DBUG_ASSERT(value); - Item *dst= get_item(var_idx); - DBUG_ASSERT(dst->type() == Item::FIELD_ITEM); - DBUG_ASSERT(dst->cmp_type() == ROW_RESULT); - Item_field_row *item_field_row= (Item_field_row*) dst; + Virtual_tmp_table *vtable= virtual_tmp_table_for_row(var_idx); + DBUG_RETURN(thd->sp_eval_expr(vtable->field[field_idx], value)); +} - Item *expr_item= sp_prepare_func_item(thd, value); - if (!expr_item) - { - DBUG_ASSERT(thd->is_error()); - return true; - } - return sp_eval_expr(thd, - item_field_row->arguments()[field_idx], - item_field_row->get_row_field(field_idx), - value); + +int sp_rcontext::set_variable_row_field_by_name(THD *thd, uint var_idx, + const LEX_CSTRING &field_name, + Item **value) +{ + DBUG_ENTER("sp_rcontext::set_variable_row_field_by_name"); + uint field_idx; + if (find_row_field_by_name_or_error(&field_idx, var_idx, field_name)) + DBUG_RETURN(1); + DBUG_RETURN(set_variable_row_field(thd, var_idx, field_idx, value)); } @@ -697,15 +635,32 @@ int sp_rcontext::set_variable_row(THD *thd, uint var_idx, List &items) { DBUG_ENTER("sp_rcontext::set_variable_row"); DBUG_ASSERT(get_item(var_idx)->cols() == items.elements); - List_iterator it(items); - Item *item; - for (uint i= 0 ; (item= it++) ; i++) - { - int rc; - if ((rc= set_variable_row_field(thd, var_idx, i, &item))) - DBUG_RETURN(rc); - } - DBUG_RETURN(0); + Virtual_tmp_table *vtable= virtual_tmp_table_for_row(var_idx); + Sp_eval_expr_state state(thd); + DBUG_RETURN(vtable->sp_set_all_fields_from_item_list(thd, items)); +} + + +Virtual_tmp_table *sp_rcontext::virtual_tmp_table_for_row(uint var_idx) +{ + DBUG_ASSERT(get_item(var_idx)->type() == Item::FIELD_ITEM); + DBUG_ASSERT(get_item(var_idx)->cmp_type() == ROW_RESULT); + Field *field= m_var_table->field[var_idx]; + Virtual_tmp_table **ptable= field->virtual_tmp_table_addr(); + DBUG_ASSERT(ptable); + DBUG_ASSERT(ptable[0]); + return ptable[0]; +} + + +bool sp_rcontext::find_row_field_by_name_or_error(uint *field_idx, + uint var_idx, + const LEX_CSTRING &field_name) +{ + Virtual_tmp_table *vtable= virtual_tmp_table_for_row(var_idx); + Field *row= m_var_table->field[var_idx]; + return vtable->sp_find_field_by_name_or_error(field_idx, + row->field_name, field_name); } @@ -728,7 +683,7 @@ Item_cache *sp_rcontext::create_case_expr_holder(THD *thd, bool sp_rcontext::set_case_expr(THD *thd, int case_expr_id, Item **case_expr_item_ptr) { - Item *case_expr_item= sp_prepare_func_item(thd, case_expr_item_ptr); + Item *case_expr_item= thd->sp_prepare_func_item(case_expr_item_ptr); if (!case_expr_item) return true; -- cgit v1.2.1