|
|
|
@ -125,10 +125,10 @@ sp_get_item_value(THD *thd, Item *item, String *str) |
|
|
|
case STRING_RESULT: |
|
|
|
{ |
|
|
|
String *result= item->val_str(str); |
|
|
|
|
|
|
|
|
|
|
|
if (!result) |
|
|
|
return NULL; |
|
|
|
|
|
|
|
|
|
|
|
{ |
|
|
|
char buf_holder[STRING_BUFFER_USUAL_SIZE]; |
|
|
|
String buf(buf_holder, sizeof(buf_holder), result->charset()); |
|
|
|
@ -366,7 +366,7 @@ sp_eval_expr(THD *thd, Field *result_field, Item **expr_item_ptr) |
|
|
|
|
|
|
|
Save original values and restore them after save. |
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
thd->count_cuted_fields= CHECK_FIELD_ERROR_FOR_NULL; |
|
|
|
thd->abort_on_warning= |
|
|
|
thd->variables.sql_mode & |
|
|
|
@ -465,7 +465,7 @@ check_routine_name(LEX_STRING *ident) |
|
|
|
{ |
|
|
|
if (!ident || !ident->str || !ident->str[0] || |
|
|
|
ident->str[ident->length-1] == ' ') |
|
|
|
{ |
|
|
|
{ |
|
|
|
my_error(ER_SP_WRONG_NAME, MYF(0), ident->str); |
|
|
|
return TRUE; |
|
|
|
} |
|
|
|
@ -502,7 +502,7 @@ sp_head::operator new(size_t size) throw() |
|
|
|
DBUG_RETURN(sp); |
|
|
|
} |
|
|
|
|
|
|
|
void |
|
|
|
void |
|
|
|
sp_head::operator delete(void *ptr, size_t size) throw() |
|
|
|
{ |
|
|
|
DBUG_ENTER("sp_head::operator delete"); |
|
|
|
@ -718,7 +718,7 @@ create_typelib(MEM_ROOT *mem_root, Create_field *field_def, List<String> *src) |
|
|
|
String *tmp= it++; |
|
|
|
|
|
|
|
if (String::needs_conversion(tmp->length(), tmp->charset(), |
|
|
|
cs, &dummy)) |
|
|
|
cs, &dummy)) |
|
|
|
{ |
|
|
|
uint cnv_errs; |
|
|
|
conv.copy(tmp->ptr(), tmp->length(), tmp->charset(), cs, &cnv_errs); |
|
|
|
@ -815,7 +815,7 @@ sp_head::create_result_field(uint field_max_length, const char *field_name, |
|
|
|
|
|
|
|
if (field) |
|
|
|
field->init(table); |
|
|
|
|
|
|
|
|
|
|
|
DBUG_RETURN(field); |
|
|
|
} |
|
|
|
|
|
|
|
@ -844,7 +844,7 @@ int cmp_splocal_locations(Item_splocal * const *a, Item_splocal * const *b) |
|
|
|
Statements that have is_update_query(stmt) == FALSE (e.g. SELECTs) are not |
|
|
|
written into binary log. Instead we catch function calls the statement |
|
|
|
makes and write it into binary log separately (see #3). |
|
|
|
|
|
|
|
|
|
|
|
2. PROCEDURE calls |
|
|
|
|
|
|
|
CALL statements are not written into binary log. Instead |
|
|
|
@ -857,8 +857,8 @@ int cmp_splocal_locations(Item_splocal * const *a, Item_splocal * const *b) |
|
|
|
This substitution is done in subst_spvars(). |
|
|
|
|
|
|
|
3. FUNCTION calls |
|
|
|
|
|
|
|
In sp_head::execute_function(), we check |
|
|
|
|
|
|
|
In sp_head::execute_function(), we check |
|
|
|
* If this function invocation is done from a statement that is written |
|
|
|
into the binary log. |
|
|
|
* If there were any attempts to write events to the binary log during |
|
|
|
@ -866,28 +866,28 @@ int cmp_splocal_locations(Item_splocal * const *a, Item_splocal * const *b) |
|
|
|
|
|
|
|
If the answers are No and Yes, we write the function call into the binary |
|
|
|
log as "SELECT spfunc(<param1value>, <param2value>, ...)" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4. Miscellaneous issues. |
|
|
|
|
|
|
|
4.1 User variables. |
|
|
|
|
|
|
|
4.1 User variables. |
|
|
|
|
|
|
|
When we call mysql_bin_log.write() for an SP statement, thd->user_var_events |
|
|
|
must hold set<{var_name, value}> pairs for all user variables used during |
|
|
|
must hold set<{var_name, value}> pairs for all user variables used during |
|
|
|
the statement execution. |
|
|
|
This set is produced by tracking user variable reads during statement |
|
|
|
execution. |
|
|
|
execution. |
|
|
|
|
|
|
|
For SPs, this has the following implications: |
|
|
|
1) thd->user_var_events may contain events from several SP statements and |
|
|
|
needs to be valid after exection of these statements was finished. In |
|
|
|
1) thd->user_var_events may contain events from several SP statements and |
|
|
|
needs to be valid after exection of these statements was finished. In |
|
|
|
order to achieve that, we |
|
|
|
* Allocate user_var_events array elements on appropriate mem_root (grep |
|
|
|
for user_var_events_alloc). |
|
|
|
* Use is_query_in_union() to determine if user_var_event is created. |
|
|
|
|
|
|
|
|
|
|
|
2) We need to empty thd->user_var_events after we have wrote a function |
|
|
|
call. This is currently done by making |
|
|
|
call. This is currently done by making |
|
|
|
reset_dynamic(&thd->user_var_events); |
|
|
|
calls in several different places. (TODO cosider moving this into |
|
|
|
mysql_bin_log.write() function) |
|
|
|
@ -906,7 +906,7 @@ int cmp_splocal_locations(Item_splocal * const *a, Item_splocal * const *b) |
|
|
|
Replace thd->query{_length} with a string that one can write to |
|
|
|
the binlog. |
|
|
|
|
|
|
|
The binlog-suitable string is produced by replacing references to SP local |
|
|
|
The binlog-suitable string is produced by replacing references to SP local |
|
|
|
variables with NAME_CONST('sp_var_name', value) calls. |
|
|
|
|
|
|
|
@param thd Current thread. |
|
|
|
@ -943,11 +943,11 @@ subst_spvars(THD *thd, sp_instr *instr, LEX_STRING *query_str) |
|
|
|
} |
|
|
|
if (!sp_vars_uses.elements()) |
|
|
|
DBUG_RETURN(FALSE); |
|
|
|
|
|
|
|
|
|
|
|
/* Sort SP var refs by their occurences in the query */ |
|
|
|
sp_vars_uses.sort(cmp_splocal_locations); |
|
|
|
|
|
|
|
/*
|
|
|
|
/*
|
|
|
|
Construct a statement string where SP local var refs are replaced |
|
|
|
with "NAME_CONST(name, value)" |
|
|
|
*/ |
|
|
|
@ -955,7 +955,7 @@ subst_spvars(THD *thd, sp_instr *instr, LEX_STRING *query_str) |
|
|
|
cur= query_str->str; |
|
|
|
prev_pos= res= 0; |
|
|
|
thd->query_name_consts= 0; |
|
|
|
|
|
|
|
|
|
|
|
for (Item_splocal **splocal= sp_vars_uses.front(); |
|
|
|
splocal < sp_vars_uses.back(); splocal++) |
|
|
|
{ |
|
|
|
@ -965,13 +965,13 @@ subst_spvars(THD *thd, sp_instr *instr, LEX_STRING *query_str) |
|
|
|
String str_value_holder(str_buffer, sizeof(str_buffer), |
|
|
|
&my_charset_latin1); |
|
|
|
String *str_value; |
|
|
|
|
|
|
|
|
|
|
|
/* append the text between sp ref occurences */ |
|
|
|
res|= qbuf.append(cur + prev_pos, (*splocal)->pos_in_query - prev_pos); |
|
|
|
prev_pos= (*splocal)->pos_in_query + (*splocal)->len_in_query; |
|
|
|
|
|
|
|
|
|
|
|
res|= (*splocal)->fix_fields(thd, (Item **) splocal); |
|
|
|
if (res) |
|
|
|
if (res) |
|
|
|
break; |
|
|
|
|
|
|
|
if ((*splocal)->limit_clause_param) |
|
|
|
@ -998,7 +998,7 @@ subst_spvars(THD *thd, sp_instr *instr, LEX_STRING *query_str) |
|
|
|
res|= qbuf.append(')'); |
|
|
|
if (res) |
|
|
|
break; |
|
|
|
|
|
|
|
|
|
|
|
thd->query_name_consts++; |
|
|
|
} |
|
|
|
res|= qbuf.append(cur + prev_pos, query_str->length - prev_pos); |
|
|
|
@ -1024,16 +1024,14 @@ subst_spvars(THD *thd, sp_instr *instr, LEX_STRING *query_str) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
/**
|
|
|
|
Return appropriate error about recursion limit reaching |
|
|
|
|
|
|
|
SYNOPSIS |
|
|
|
sp_head::recursion_level_error() |
|
|
|
thd Thread handle |
|
|
|
@param thd Thread handle |
|
|
|
|
|
|
|
NOTE |
|
|
|
For functions and triggers we return error about prohibited recursion. |
|
|
|
For stored procedures we return about reaching recursion limit. |
|
|
|
@remark For functions and triggers we return error about |
|
|
|
prohibited recursion. For stored procedures we |
|
|
|
return about reaching recursion limit. |
|
|
|
*/ |
|
|
|
|
|
|
|
void sp_head::recursion_level_error(THD *thd) |
|
|
|
@ -1053,7 +1051,7 @@ void sp_head::recursion_level_error(THD *thd) |
|
|
|
Execute the routine. The main instruction jump loop is there. |
|
|
|
Assume the parameters already set. |
|
|
|
@todo |
|
|
|
- Will write this SP statement into binlog separately |
|
|
|
- Will write this SP statement into binlog separately |
|
|
|
(TODO: consider changing the condition to "not inside event union") |
|
|
|
|
|
|
|
@retval |
|
|
|
@ -1217,10 +1215,10 @@ sp_head::execute(THD *thd) |
|
|
|
do |
|
|
|
{ |
|
|
|
sp_instr *i; |
|
|
|
uint hip; // Handler ip
|
|
|
|
uint hip; |
|
|
|
|
|
|
|
#if defined(ENABLED_PROFILING)
|
|
|
|
/*
|
|
|
|
/*
|
|
|
|
Treat each "instr" of a routine as discrete unit that could be profiled. |
|
|
|
Profiling only records information for segments of code that set the |
|
|
|
source of the query, and almost all kinds of instructions in s-p do not. |
|
|
|
@ -1229,7 +1227,8 @@ sp_head::execute(THD *thd) |
|
|
|
thd->profiling.start_new_query("continuing inside routine"); |
|
|
|
#endif
|
|
|
|
|
|
|
|
i = get_instr(ip); // Returns NULL when we're done.
|
|
|
|
/* get_instr returns NULL when we're done. */ |
|
|
|
i = get_instr(ip); |
|
|
|
if (i == NULL) |
|
|
|
{ |
|
|
|
#if defined(ENABLED_PROFILING)
|
|
|
|
@ -1240,10 +1239,13 @@ sp_head::execute(THD *thd) |
|
|
|
|
|
|
|
DBUG_PRINT("execute", ("Instruction %u", ip)); |
|
|
|
|
|
|
|
/* Don't change NOW() in FUNCTION or TRIGGER */ |
|
|
|
/*
|
|
|
|
Make current_time() et al work. But don't change NOW() in FUNCTION |
|
|
|
or TRIGGER. |
|
|
|
*/ |
|
|
|
if (!thd->in_sub_stmt) |
|
|
|
thd->set_time(); // Make current_time() et al work
|
|
|
|
|
|
|
|
thd->set_time(); |
|
|
|
|
|
|
|
/*
|
|
|
|
We have to set thd->stmt_arena before executing the instruction |
|
|
|
to store in the instruction free_list all new items, created |
|
|
|
@ -1251,10 +1253,10 @@ sp_head::execute(THD *thd) |
|
|
|
items made during other permanent subquery transformations). |
|
|
|
*/ |
|
|
|
thd->stmt_arena= i; |
|
|
|
|
|
|
|
/*
|
|
|
|
Will write this SP statement into binlog separately |
|
|
|
(TODO: consider changing the condition to "not inside event union") |
|
|
|
|
|
|
|
/*
|
|
|
|
Will write this SP statement into binlog separately. |
|
|
|
TODO: consider changing the condition to "not inside event union". |
|
|
|
*/ |
|
|
|
if (thd->locked_tables_mode <= LTM_LOCK_TABLES) |
|
|
|
thd->user_var_events_alloc= thd->mem_root; |
|
|
|
@ -1263,8 +1265,8 @@ sp_head::execute(THD *thd) |
|
|
|
|
|
|
|
if (i->free_list) |
|
|
|
cleanup_items(i->free_list); |
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
/*
|
|
|
|
If we've set thd->user_var_events_alloc to mem_root of this SP |
|
|
|
statement, clean all the events allocated in it. |
|
|
|
*/ |
|
|
|
@ -1276,7 +1278,7 @@ sp_head::execute(THD *thd) |
|
|
|
|
|
|
|
/* we should cleanup free_list and memroot, used by instruction */ |
|
|
|
thd->cleanup_after_query(); |
|
|
|
free_root(&execute_mem_root, MYF(0)); |
|
|
|
free_root(&execute_mem_root, MYF(0)); |
|
|
|
|
|
|
|
/*
|
|
|
|
Check if an exception has occurred and a handler has been found |
|
|
|
@ -1291,7 +1293,7 @@ sp_head::execute(THD *thd) |
|
|
|
|
|
|
|
switch (ctx->found_handler(& hip, & handler_index)) { |
|
|
|
case SP_HANDLER_NONE: |
|
|
|
break; |
|
|
|
break; |
|
|
|
case SP_HANDLER_CONTINUE: |
|
|
|
thd->restore_active_arena(&execute_arena, &backup_arena); |
|
|
|
thd->set_n_backup_active_arena(&execute_arena, &backup_arena); |
|
|
|
@ -1300,15 +1302,15 @@ sp_head::execute(THD *thd) |
|
|
|
default: |
|
|
|
if (ctx->end_partial_result_set) |
|
|
|
thd->protocol->end_partial_result_set(thd); |
|
|
|
ip= hip; |
|
|
|
err_status= FALSE; |
|
|
|
ctx->clear_handler(); |
|
|
|
ctx->enter_handler(hip, handler_index); |
|
|
|
ip= hip; |
|
|
|
err_status= FALSE; |
|
|
|
ctx->clear_handler(); |
|
|
|
ctx->enter_handler(hip, handler_index); |
|
|
|
thd->clear_error(); |
|
|
|
thd->is_fatal_error= 0; |
|
|
|
thd->killed= THD::NOT_KILLED; |
|
|
|
thd->killed= THD::NOT_KILLED; |
|
|
|
thd->mysys_var->abort= 0; |
|
|
|
continue; |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
ctx->end_partial_result_set= FALSE; |
|
|
|
@ -1351,7 +1353,7 @@ sp_head::execute(THD *thd) |
|
|
|
|
|
|
|
done: |
|
|
|
DBUG_PRINT("info", ("err_status: %d killed: %d is_slave_error: %d report_error: %d", |
|
|
|
err_status, thd->killed, thd->is_slave_error, |
|
|
|
err_status, thd->killed, thd->is_slave_error, |
|
|
|
thd->is_error())); |
|
|
|
|
|
|
|
if (thd->killed) |
|
|
|
@ -1839,10 +1841,10 @@ err_with_cleanup: |
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
Execute a procedure. |
|
|
|
Execute a procedure. |
|
|
|
|
|
|
|
The function does the following steps: |
|
|
|
- Set all parameters |
|
|
|
- Set all parameters |
|
|
|
- changes security context for SUID routines |
|
|
|
- call sp_head::execute |
|
|
|
- copy back values of INOUT and OUT parameters |
|
|
|
@ -1880,14 +1882,14 @@ sp_head::execute_procedure(THD *thd, List<Item> *args) |
|
|
|
|
|
|
|
save_spcont= octx= thd->spcont; |
|
|
|
if (! octx) |
|
|
|
{ // Create a temporary old context
|
|
|
|
if (!(octx= new sp_rcontext(m_pcont, NULL, octx)) || |
|
|
|
octx->init(thd)) |
|
|
|
{ |
|
|
|
/* Create a temporary old context. */ |
|
|
|
if (!(octx= new sp_rcontext(m_pcont, NULL, octx)) || octx->init(thd)) |
|
|
|
{ |
|
|
|
delete octx; /* Delete octx if it was init() that failed. */ |
|
|
|
DBUG_RETURN(TRUE); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#ifndef DBUG_OFF
|
|
|
|
octx->sp= 0; |
|
|
|
#endif
|
|
|
|
@ -2147,7 +2149,7 @@ sp_head::restore_lex(THD *thd) |
|
|
|
|
|
|
|
oldlex= (LEX *)m_lex.pop(); |
|
|
|
if (! oldlex) |
|
|
|
DBUG_RETURN(FALSE); // Nothing to restore
|
|
|
|
DBUG_RETURN(FALSE); // Nothing to restore
|
|
|
|
|
|
|
|
oldlex->trg_table_fields.push_back(&sublex->trg_table_fields); |
|
|
|
|
|
|
|
@ -2300,7 +2302,7 @@ sp_head::do_cont_backpatch() |
|
|
|
|
|
|
|
void |
|
|
|
sp_head::set_info(longlong created, longlong modified, |
|
|
|
st_sp_chistics *chistics, ulong sql_mode) |
|
|
|
st_sp_chistics *chistics, ulong sql_mode) |
|
|
|
{ |
|
|
|
m_created= created; |
|
|
|
m_modified= modified; |
|
|
|
@ -2310,8 +2312,8 @@ sp_head::set_info(longlong created, longlong modified, |
|
|
|
m_chistics->comment.str= 0; |
|
|
|
else |
|
|
|
m_chistics->comment.str= strmake_root(mem_root, |
|
|
|
m_chistics->comment.str, |
|
|
|
m_chistics->comment.length); |
|
|
|
m_chistics->comment.str, |
|
|
|
m_chistics->comment.length); |
|
|
|
m_sql_mode= sql_mode; |
|
|
|
} |
|
|
|
|
|
|
|
@ -2352,7 +2354,7 @@ sp_head::reset_thd_mem_root(THD *thd) |
|
|
|
DBUG_PRINT("info", ("mem_root 0x%lx moved to thd mem root 0x%lx", |
|
|
|
(ulong) &mem_root, (ulong) &thd->mem_root)); |
|
|
|
free_list= thd->free_list; // Keep the old list
|
|
|
|
thd->free_list= NULL; // Start a new one
|
|
|
|
thd->free_list= NULL; // Start a new one
|
|
|
|
m_thd= thd; |
|
|
|
DBUG_VOID_RETURN; |
|
|
|
} |
|
|
|
@ -2361,13 +2363,13 @@ void |
|
|
|
sp_head::restore_thd_mem_root(THD *thd) |
|
|
|
{ |
|
|
|
DBUG_ENTER("sp_head::restore_thd_mem_root"); |
|
|
|
Item *flist= free_list; // The old list
|
|
|
|
Item *flist= free_list; // The old list
|
|
|
|
set_query_arena(thd); // Get new free_list and mem_root
|
|
|
|
state= INITIALIZED_FOR_SP; |
|
|
|
|
|
|
|
DBUG_PRINT("info", ("mem_root 0x%lx returned from thd mem root 0x%lx", |
|
|
|
(ulong) &mem_root, (ulong) &thd->mem_root)); |
|
|
|
thd->free_list= flist; // Restore the old one
|
|
|
|
thd->free_list= flist; // Restore the old one
|
|
|
|
thd->mem_root= m_thd_root; |
|
|
|
m_thd= NULL; |
|
|
|
DBUG_VOID_RETURN; |
|
|
|
@ -2377,10 +2379,10 @@ sp_head::restore_thd_mem_root(THD *thd) |
|
|
|
/**
|
|
|
|
Check if a user has access right to a routine. |
|
|
|
|
|
|
|
@param thd Thread handler |
|
|
|
@param sp SP |
|
|
|
@param full_access Set to 1 if the user has SELECT right to the |
|
|
|
'mysql.proc' able or is the owner of the routine |
|
|
|
@param thd Thread handler |
|
|
|
@param sp SP |
|
|
|
@param full_access Set to 1 if the user has SELECT right to the |
|
|
|
'mysql.proc' able or is the owner of the routine |
|
|
|
@retval |
|
|
|
false ok |
|
|
|
@retval |
|
|
|
@ -2509,8 +2511,6 @@ sp_head::show_create_routine(THD *thd, int type) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
Add instruction to SP. |
|
|
|
|
|
|
|
@ -2570,11 +2570,11 @@ void sp_head::optimize() |
|
|
|
if (src != dst) |
|
|
|
{ |
|
|
|
/* Move the instruction and update prev. jumps */ |
|
|
|
sp_instr *ibp; |
|
|
|
List_iterator_fast<sp_instr> li(bp); |
|
|
|
sp_instr *ibp; |
|
|
|
List_iterator_fast<sp_instr> li(bp); |
|
|
|
|
|
|
|
set_dynamic(&m_instr, (uchar*)&i, dst); |
|
|
|
while ((ibp= li++)) |
|
|
|
set_dynamic(&m_instr, (uchar*)&i, dst); |
|
|
|
while ((ibp= li++)) |
|
|
|
{ |
|
|
|
sp_instr_opt_meta *im= static_cast<sp_instr_opt_meta *>(ibp); |
|
|
|
im->set_destination(src, dst); |
|
|
|
@ -2669,7 +2669,7 @@ sp_head::show_routine_code(THD *thd) |
|
|
|
|
|
|
|
for (ip= 0; (i = get_instr(ip)) ; ip++) |
|
|
|
{ |
|
|
|
/*
|
|
|
|
/*
|
|
|
|
Consistency check. If these are different something went wrong |
|
|
|
during optimization. |
|
|
|
*/ |
|
|
|
@ -2732,7 +2732,7 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp, |
|
|
|
int res= 0; |
|
|
|
DBUG_ENTER("reset_lex_and_exec_core"); |
|
|
|
|
|
|
|
/*
|
|
|
|
/*
|
|
|
|
The flag is saved at the entry to the following substatement. |
|
|
|
It's reset further in the common code part. |
|
|
|
It's merged with the saved parent's value at the exit of this func. |
|
|
|
@ -2894,9 +2894,8 @@ sp_instr_stmt::execute(THD *thd, uint *nextp) |
|
|
|
if (unlikely((thd->variables.option_bits & OPTION_LOG_OFF)==0)) |
|
|
|
general_log_write(thd, COM_QUERY, thd->query(), thd->query_length()); |
|
|
|
|
|
|
|
if (query_cache_send_result_to_client(thd, |
|
|
|
thd->query(), |
|
|
|
thd->query_length()) <= 0) |
|
|
|
if (query_cache_send_result_to_client(thd, thd->query(), |
|
|
|
thd->query_length()) <= 0) |
|
|
|
{ |
|
|
|
res= m_lex_keeper.reset_lex_and_exec_core(thd, nextp, FALSE, this); |
|
|
|
|
|
|
|
@ -2999,7 +2998,7 @@ sp_instr_set::exec_core(THD *thd, uint *nextp) |
|
|
|
/* If this also failed, let's abort. */ |
|
|
|
|
|
|
|
sp_rcontext *spcont= thd->spcont; |
|
|
|
|
|
|
|
|
|
|
|
thd->spcont= NULL; /* Avoid handlers */ |
|
|
|
my_error(ER_OUT_OF_RESOURCES, MYF(0)); |
|
|
|
spcont->clear_handler(); |
|
|
|
@ -3103,7 +3102,7 @@ uint |
|
|
|
sp_instr_jump::opt_mark(sp_head *sp, List<sp_instr> *leads) |
|
|
|
{ |
|
|
|
m_dest= opt_shortcut_jump(sp, this); |
|
|
|
if (m_dest != m_ip+1) /* Jumping to following instruction? */ |
|
|
|
if (m_dest != m_ip+1) /* Jumping to following instruction? */ |
|
|
|
marked= 1; |
|
|
|
m_optdest= sp->get_instr(m_dest); |
|
|
|
return m_dest; |
|
|
|
@ -3133,9 +3132,9 @@ void |
|
|
|
sp_instr_jump::opt_move(uint dst, List<sp_instr> *bp) |
|
|
|
{ |
|
|
|
if (m_dest > m_ip) |
|
|
|
bp->push_back(this); // Forward
|
|
|
|
bp->push_back(this); // Forward
|
|
|
|
else if (m_optdest) |
|
|
|
m_dest= m_optdest->m_ip; // Backward
|
|
|
|
m_dest= m_optdest->m_ip; // Backward
|
|
|
|
m_ip= dst; |
|
|
|
} |
|
|
|
|
|
|
|
@ -3408,7 +3407,7 @@ uint |
|
|
|
sp_instr_hreturn::opt_mark(sp_head *sp, List<sp_instr> *leads) |
|
|
|
{ |
|
|
|
marked= 1; |
|
|
|
|
|
|
|
|
|
|
|
if (m_dest) |
|
|
|
{ |
|
|
|
/*
|
|
|
|
@ -3416,7 +3415,7 @@ sp_instr_hreturn::opt_mark(sp_head *sp, List<sp_instr> *leads) |
|
|
|
*/ |
|
|
|
return m_dest; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
This is a CONTINUE handler; next instruction step will come from |
|
|
|
the handler stack and not from opt_mark. |
|
|
|
@ -3733,14 +3732,14 @@ sp_instr_set_case_expr::exec_core(THD *thd, uint *nextp) |
|
|
|
*/ |
|
|
|
|
|
|
|
Item *null_item= new Item_null(); |
|
|
|
|
|
|
|
|
|
|
|
if (!null_item || |
|
|
|
thd->spcont->set_case_expr(thd, m_case_expr_id, &null_item)) |
|
|
|
{ |
|
|
|
/* If this also failed, we have to abort. */ |
|
|
|
|
|
|
|
sp_rcontext *spcont= thd->spcont; |
|
|
|
|
|
|
|
|
|
|
|
thd->spcont= NULL; /* Avoid handlers */ |
|
|
|
my_error(ER_OUT_OF_RESOURCES, MYF(0)); |
|
|
|
spcont->clear_handler(); |
|
|
|
@ -3906,13 +3905,13 @@ sp_head::merge_table_list(THD *thd, TABLE_LIST *table, LEX *lex_for_tmp_check) |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
if (!(tab= (SP_TABLE *)thd->calloc(sizeof(SP_TABLE)))) |
|
|
|
return FALSE; |
|
|
|
if (lex_for_tmp_check->sql_command == SQLCOM_CREATE_TABLE && |
|
|
|
lex_for_tmp_check->query_tables == table && |
|
|
|
lex_for_tmp_check->create_info.options & HA_LEX_CREATE_TMP_TABLE) |
|
|
|
if (!(tab= (SP_TABLE *)thd->calloc(sizeof(SP_TABLE)))) |
|
|
|
return FALSE; |
|
|
|
if (lex_for_tmp_check->sql_command == SQLCOM_CREATE_TABLE && |
|
|
|
lex_for_tmp_check->query_tables == table && |
|
|
|
lex_for_tmp_check->create_info.options & HA_LEX_CREATE_TMP_TABLE) |
|
|
|
{ |
|
|
|
tab->temp= TRUE; |
|
|
|
tab->temp= TRUE; |
|
|
|
tab->qname.length= tlen - alen - 1; |
|
|
|
} |
|
|
|
else |
|
|
|
@ -3925,7 +3924,7 @@ sp_head::merge_table_list(THD *thd, TABLE_LIST *table, LEX *lex_for_tmp_check) |
|
|
|
tab->lock_type= table->lock_type; |
|
|
|
tab->lock_count= tab->query_lock_count= 1; |
|
|
|
tab->trg_event_map= table->trg_event_map; |
|
|
|
if (my_hash_insert(&m_sptabs, (uchar *)tab)) |
|
|
|
if (my_hash_insert(&m_sptabs, (uchar *)tab)) |
|
|
|
return FALSE; |
|
|
|
} |
|
|
|
} |
|
|
|
@ -4032,8 +4031,8 @@ sp_head::add_used_tables_to_table_list(THD *thd, |
|
|
|
|
|
|
|
TABLE_LIST * |
|
|
|
sp_add_to_query_tables(THD *thd, LEX *lex, |
|
|
|
const char *db, const char *name, |
|
|
|
thr_lock_type locktype) |
|
|
|
const char *db, const char *name, |
|
|
|
thr_lock_type locktype) |
|
|
|
{ |
|
|
|
TABLE_LIST *table; |
|
|
|
|
|
|
|
|