diff options
Diffstat (limited to 'sql/sp_head.cc')
-rw-r--r-- | sql/sp_head.cc | 148 |
1 files changed, 95 insertions, 53 deletions
diff --git a/sql/sp_head.cc b/sql/sp_head.cc index bd02762f5ab..28e4442dd0c 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -999,6 +999,12 @@ sp_head::execute(THD *thd, bool merge_da_on_success) bool err_status= FALSE; uint ip= 0; sql_mode_t save_sql_mode; + + // TODO(cvicentiu) See if you can drop this bit. This is used to resume + // execution from where we left off. + if (m_chistics.agg_type == GROUP_AGGREGATE) + ip= thd->spcont->instr_ptr; + bool save_abort_on_warning; Query_arena *old_arena; /* per-instruction arena */ @@ -1022,6 +1028,19 @@ sp_head::execute(THD *thd, bool merge_da_on_success) if (check_stack_overrun(thd, 7 * STACK_MIN_SIZE, (uchar*)&old_packet)) DBUG_RETURN(TRUE); + /* + Normally the counter is not reset between parsing and first execution, + but it is possible in case of error to have parsing on one CALL and + first execution (where VIEW will be parsed and added). So we store the + counter after parsing and restore it before execution just to avoid + repeating SELECT numbers. + + Other problem is that it can be more SELECTs parsed in case of fixing + error causes previous interruption of the SP. So it is save not just + assign old value but add it. + */ + thd->select_number+= m_select_number; + /* init per-instruction memroot */ init_sql_alloc(&execute_mem_root, MEM_ROOT_BLOCK_SIZE, 0, MYF(0)); @@ -1163,6 +1182,7 @@ sp_head::execute(THD *thd, bool merge_da_on_success) #if defined(ENABLED_PROFILING) thd->profiling.discard_current_query(); #endif + thd->spcont->quit_func= TRUE; break; } @@ -1232,7 +1252,8 @@ sp_head::execute(THD *thd, bool merge_da_on_success) /* Reset sp_rcontext::end_partial_result_set flag. */ ctx->end_partial_result_set= FALSE; - } while (!err_status && !thd->killed && !thd->is_fatal_error); + } while (!err_status && !thd->killed && !thd->is_fatal_error && + !thd->spcont->pause_state); #if defined(ENABLED_PROFILING) thd->profiling.finish_current_query(); @@ -1248,9 +1269,14 @@ sp_head::execute(THD *thd, bool merge_da_on_success) thd->restore_active_arena(&execute_arena, &backup_arena); - thd->spcont->pop_all_cursors(); // To avoid memory leaks after an error + /* Only pop cursors when we're done with group aggregate running. */ + if (m_chistics.agg_type != GROUP_AGGREGATE || + (m_chistics.agg_type == GROUP_AGGREGATE && thd->spcont->quit_func)) + thd->spcont->pop_all_cursors(); // To avoid memory leaks after an error /* Restore all saved */ + if (m_chistics.agg_type == GROUP_AGGREGATE) + thd->spcont->instr_ptr= ip; thd->server_status= (thd->server_status & ~status_backup_mask) | old_server_status; old_packet.swap(thd->packet); DBUG_ASSERT(thd->change_list.is_empty()); @@ -1361,6 +1387,16 @@ sp_head::execute(THD *thd, bool merge_da_on_success) m_recursion_level + 1)); m_first_instance->m_first_free_instance= this; + /* + This execution of the SP was aborted with an error (e.g. "Table not + found"). However it might still have consumed some numbers from the + thd->select_number counter. The next sp->exec() call must not use the + consumed numbers, so we remember the first free number (We know that + nobody will use it as this execution has stopped with an error). + */ + if (err_status) + set_select_number(thd->select_number); + DBUG_RETURN(err_status); } @@ -1652,18 +1688,16 @@ err_with_cleanup: bool sp_head::execute_function(THD *thd, Item **argp, uint argcount, - Field *return_value_fld) + Field *return_value_fld, sp_rcontext **func_ctx, + Query_arena *call_arena) { ulonglong UNINIT_VAR(binlog_save_options); bool need_binlog_call= FALSE; uint arg_no; sp_rcontext *octx = thd->spcont; - sp_rcontext *nctx = NULL; char buf[STRING_BUFFER_USUAL_SIZE]; String binlog_buf(buf, sizeof(buf), &my_charset_bin); bool err_status= FALSE; - MEM_ROOT call_mem_root; - Query_arena call_arena(&call_mem_root, Query_arena::STMT_INITIALIZED_FOR_SP); Query_arena backup_arena; DBUG_ENTER("sp_head::execute_function"); DBUG_PRINT("info", ("function %s", m_name.str)); @@ -1696,23 +1730,25 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, TODO: we should create sp_rcontext once per command and reuse it on subsequent executions of a function/trigger. */ - init_sql_alloc(&call_mem_root, MEM_ROOT_BLOCK_SIZE, 0, MYF(0)); - thd->set_n_backup_active_arena(&call_arena, &backup_arena); - - if (!(nctx= rcontext_create(thd, return_value_fld, argp, argcount))) + if (!(*func_ctx)) { - thd->restore_active_arena(&call_arena, &backup_arena); - err_status= TRUE; - goto err_with_cleanup; - } + thd->set_n_backup_active_arena(call_arena, &backup_arena); - /* - We have to switch temporarily back to callers arena/memroot. - Function arguments belong to the caller and so the may reference - memory which they will allocate during calculation long after - this function call will be finished (e.g. in Item::cleanup()). - */ - thd->restore_active_arena(&call_arena, &backup_arena); + if (!(*func_ctx= rcontext_create(thd, return_value_fld, argp, argcount))) + { + thd->restore_active_arena(call_arena, &backup_arena); + err_status= TRUE; + goto err_with_cleanup; + } + + /* + We have to switch temporarily back to callers arena/memroot. + Function arguments belong to the caller and so the may reference + memory which they will allocate during calculation long after + this function call will be finished (e.g. in Item::cleanup()). + */ + thd->restore_active_arena(call_arena, &backup_arena); + } /* Pass arguments. */ for (arg_no= 0; arg_no < argcount; arg_no++) @@ -1720,7 +1756,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, /* Arguments must be fixed in Item_func_sp::fix_fields */ DBUG_ASSERT(argp[arg_no]->fixed); - if ((err_status= nctx->set_variable(thd, arg_no, &(argp[arg_no])))) + if ((err_status= (*func_ctx)->set_variable(thd, arg_no, &(argp[arg_no])))) goto err_with_cleanup; } @@ -1752,7 +1788,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, if (arg_no) binlog_buf.append(','); - Item *item= nctx->get_item(arg_no); + Item *item= (*func_ctx)->get_item(arg_no); str_value= item->type_handler()->print_item_value(thd, item, &str_value_holder); if (str_value) @@ -1762,7 +1798,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, } binlog_buf.append(')'); } - thd->spcont= nctx; + thd->spcont= *func_ctx; #ifndef NO_EMBEDDED_ACCESS_CHECKS Security_context *save_security_ctx; @@ -1803,11 +1839,11 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, sp_rcontext and allocate all these objects (and sp_rcontext itself) on it directly rather than juggle with arenas. */ - thd->set_n_backup_active_arena(&call_arena, &backup_arena); + thd->set_n_backup_active_arena(call_arena, &backup_arena); err_status= execute(thd, TRUE); - thd->restore_active_arena(&call_arena, &backup_arena); + thd->restore_active_arena(call_arena, &backup_arena); if (need_binlog_call) { @@ -1833,11 +1869,11 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, } } - if (!err_status) + if (!err_status && thd->spcont->quit_func) { /* We need result only in function but not in trigger */ - if (!nctx->is_return_value_set()) + if (!(*func_ctx)->is_return_value_set()) { my_error(ER_SP_NORETURNEND, MYF(0), m_name.str); err_status= TRUE; @@ -1849,9 +1885,6 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, #endif err_with_cleanup: - delete nctx; - call_arena.free_items(); - free_root(&call_mem_root, MYF(0)); thd->spcont= octx; /* @@ -2065,26 +2098,7 @@ sp_head::execute_procedure(THD *thd, List<Item> *args) if (!err_status) { - /* - Normally the counter is not reset between parsing and first execution, - but it is possible in case of error to have parsing on one CALL and - first execution (where VIEW will be parsed and added). So we store the - counter after parsing and restore it before execution just to avoid - repeating SELECT numbers. - */ - thd->select_number= m_select_number; - err_status= execute(thd, TRUE); - DBUG_PRINT("info", ("execute returned %d", (int) err_status)); - /* - This execution of the SP was aborted with an error (e.g. "Table not - found"). However it might still have consumed some numbers from the - thd->select_number counter. The next sp->exec() call must not use the - consumed numbers, so we remember the first free number (We know that - nobody will use it as this execution has stopped with an error). - */ - if (err_status) - set_select_number(thd->select_number); } if (save_log_general) @@ -2481,7 +2495,6 @@ sp_head::set_chistics(const st_sp_chistics &chistics) m_chistics.comment.length); } - void sp_head::set_info(longlong created, longlong modified, const st_sp_chistics &chistics, sql_mode_t sql_mode) @@ -4178,7 +4191,7 @@ sp_instr_cfetch::execute(THD *thd, uint *nextp) Query_arena backup_arena; DBUG_ENTER("sp_instr_cfetch::execute"); - res= c ? c->fetch(thd, &m_varlist) : -1; + res= c ? c->fetch(thd, &m_varlist, m_error_on_no_data) : -1; *nextp= m_ip+1; DBUG_RETURN(res); @@ -4217,6 +4230,35 @@ sp_instr_cfetch::print(String *str) } } +int +sp_instr_agg_cfetch::execute(THD *thd, uint *nextp) +{ + DBUG_ENTER("sp_instr_cfetch::execute"); + int res= 0; + if (!thd->spcont->instr_ptr) + { + *nextp= m_ip+1; + thd->spcont->instr_ptr= m_ip + 1; + } + else if (!thd->spcont->pause_state) + thd->spcont->pause_state= TRUE; + else + { + thd->spcont->pause_state= FALSE; + if (thd->server_status == SERVER_STATUS_LAST_ROW_SENT) + { + my_message(ER_SP_FETCH_NO_DATA, + ER_THD(thd, ER_SP_FETCH_NO_DATA), MYF(0)); + res= -1; + thd->spcont->quit_func= TRUE; + } + else + *nextp= m_ip + 1; + } + DBUG_RETURN(res); +} + + /* sp_instr_cursor_copy_struct class functions @@ -4778,7 +4820,7 @@ bool sp_head::add_for_loop_open_cursor(THD *thd, sp_pcontext *spcont, sp_instr_cfetch *instr_cfetch= new (thd->mem_root) sp_instr_cfetch(instructions(), - spcont, coffset); + spcont, coffset, false); if (instr_cfetch == NULL || add_instr(instr_cfetch)) return true; instr_cfetch->add_to_varlist(index); |