summaryrefslogtreecommitdiff
path: root/sql/sp_head.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sp_head.cc')
-rw-r--r--sql/sp_head.cc657
1 files changed, 411 insertions, 246 deletions
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 02c006d01ee..26d76804fca 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -126,16 +126,47 @@ sp_prepare_func_item(THD* thd, Item **it_addr)
}
-/* Evaluate a (presumed) func item. Always returns an item, the parameter
-** if nothing else.
+/* Macro to switch arena in sp_eval_func_item */
+#define CREATE_ON_CALLERS_ARENA(new_command, condition, backup_arena) do\
+ {\
+ if (condition) \
+ thd->set_n_backup_item_arena(thd->spcont->callers_arena,\
+ backup_arena);\
+ new_command;\
+ if (condition)\
+ thd->restore_backup_item_arena(thd->spcont->callers_arena,\
+ &backup_current_arena);\
+ } while(0)
+
+/*
+ Evaluate an item and store it in the returned item
+
+ SYNOPSIS
+ sp_eval_func_item()
+ name - current thread object
+ it_addr - pointer to the item to evaluate
+ type - type of the item we evaluating
+ reuse - used if we would like to reuse existing item
+ instead of allocation of the new one
+ use_callers_arena - TRUE if we want to use caller's arena
+ rather then current one.
+ DESCRIPTION
+ We use this function to evaluate result for stored functions
+ and stored procedure parameters. It is also used to evaluate and
+ (re) allocate variables.
+
+ RETURN VALUES
+ Evaluated item is returned
*/
+
Item *
sp_eval_func_item(THD *thd, Item **it_addr, enum enum_field_types type,
- Item *reuse)
+ Item *reuse, bool use_callers_arena)
{
DBUG_ENTER("sp_eval_func_item");
Item *it= sp_prepare_func_item(thd, it_addr);
uint rsize;
+ Query_arena backup_current_arena;
DBUG_PRINT("info", ("type: %d", type));
if (!it)
@@ -145,91 +176,100 @@ sp_eval_func_item(THD *thd, Item **it_addr, enum enum_field_types type,
/* QQ How do we do this? Is there some better way? */
if (type == MYSQL_TYPE_NULL)
- it= new(reuse, &rsize) Item_null();
- else
- {
- switch (sp_map_result_type(type)) {
- case INT_RESULT:
- {
- longlong i= it->val_int();
+ goto return_null_item;
- if (it->null_value)
- {
- DBUG_PRINT("info", ("INT_RESULT: null"));
- it= new(reuse, &rsize) Item_null();
- }
- else
- {
- DBUG_PRINT("info", ("INT_RESULT: %d", i));
- it= new(reuse, &rsize) Item_int(i);
- }
- break;
+ switch (sp_map_result_type(type)) {
+ case INT_RESULT:
+ {
+ longlong i= it->val_int();
+
+ if (it->null_value)
+ {
+ DBUG_PRINT("info", ("INT_RESULT: null"));
+ goto return_null_item;
}
- case REAL_RESULT:
+ else
{
- double d= it->val_real();
+ DBUG_PRINT("info", ("INT_RESULT: %d", i));
+ CREATE_ON_CALLERS_ARENA(it= new(reuse, &rsize) Item_int(i),
+ use_callers_arena, &backup_current_arena);
+ }
+ break;
+ }
+ case REAL_RESULT:
+ {
+ double d= it->val_real();
- if (it->null_value)
- {
- DBUG_PRINT("info", ("REAL_RESULT: null"));
- it= new(reuse, &rsize) Item_null();
- }
- else
- {
- /* There's some difference between Item::new_item() and the
- * constructor; the former crashes, the latter works... weird. */
- uint8 decimals= it->decimals;
- uint32 max_length= it->max_length;
- DBUG_PRINT("info", ("REAL_RESULT: %g", d));
- it= new(reuse, &rsize) Item_float(d);
- it->decimals= decimals;
- it->max_length= max_length;
- }
- break;
+ if (it->null_value)
+ {
+ DBUG_PRINT("info", ("REAL_RESULT: null"));
+ goto return_null_item;
}
- case DECIMAL_RESULT:
+ else
{
- my_decimal value, *val= it->val_decimal(&value);
- if (it->null_value)
- it= new(reuse, &rsize) Item_null();
- else
- it= new(reuse, &rsize) Item_decimal(val);
+ /* There's some difference between Item::new_item() and the
+ * constructor; the former crashes, the latter works... weird. */
+ uint8 decimals= it->decimals;
+ uint32 max_length= it->max_length;
+ DBUG_PRINT("info", ("REAL_RESULT: %g", d));
+ CREATE_ON_CALLERS_ARENA(it= new(reuse, &rsize) Item_float(d),
+ use_callers_arena, &backup_current_arena);
+ it->decimals= decimals;
+ it->max_length= max_length;
+ }
+ break;
+ }
+ case DECIMAL_RESULT:
+ {
+ my_decimal value, *val= it->val_decimal(&value);
+ if (it->null_value)
+ goto return_null_item;
+ else
+ CREATE_ON_CALLERS_ARENA(it= new(reuse, &rsize) Item_decimal(val),
+ use_callers_arena, &backup_current_arena);
#ifndef DBUG_OFF
- char dbug_buff[DECIMAL_MAX_STR_LENGTH+1];
- DBUG_PRINT("info", ("DECIMAL_RESULT: %s", dbug_decimal_as_string(dbug_buff, val)));
+ char dbug_buff[DECIMAL_MAX_STR_LENGTH+1];
+ DBUG_PRINT("info", ("DECIMAL_RESULT: %s", dbug_decimal_as_string(dbug_buff, val)));
#endif
- break;
+ break;
+ }
+ case STRING_RESULT:
+ {
+ char buffer[MAX_FIELD_WIDTH];
+ String tmp(buffer, sizeof(buffer), it->collation.collation);
+ String *s= it->val_str(&tmp);
+
+ if (it->null_value)
+ {
+ DBUG_PRINT("info", ("default result: null"));
+ goto return_null_item;
}
- case STRING_RESULT:
+ else
{
- char buffer[MAX_FIELD_WIDTH];
- String tmp(buffer, sizeof(buffer), it->collation.collation);
- String *s= it->val_str(&tmp);
-
- if (it->null_value)
- {
- DBUG_PRINT("info", ("default result: null"));
- it= new(reuse, &rsize) Item_null();
- }
- else
- {
- DBUG_PRINT("info",("default result: %*s",
- s->length(), s->c_ptr_quick()));
- it= new(reuse, &rsize) Item_string(thd->strmake(s->ptr(),
- s->length()),
- s->length(),
- it->collation.collation);
- }
- break;
+ DBUG_PRINT("info",("default result: %*s",
+ s->length(), s->c_ptr_quick()));
+ CREATE_ON_CALLERS_ARENA(it= new(reuse, &rsize)
+ Item_string(thd->strmake(s->ptr(),
+ s->length()), s->length(),
+ it->collation.collation),
+ use_callers_arena, &backup_current_arena);
}
- case ROW_RESULT:
- default:
- DBUG_ASSERT(0);
+ break;
}
+ case ROW_RESULT:
+ default:
+ DBUG_ASSERT(0);
}
it->rsize= rsize;
DBUG_RETURN(it);
+
+return_null_item:
+ CREATE_ON_CALLERS_ARENA(it= new(reuse, &rsize) Item_null(),
+ use_callers_arena, &backup_current_arena);
+ it->rsize= rsize;
+
+ DBUG_RETURN(it);
}
@@ -545,23 +585,14 @@ Field *
sp_head::make_field(uint max_length, const char *name, TABLE *dummy)
{
Field *field;
- MEM_ROOT *tmp_mem_root;
- THD *thd;
DBUG_ENTER("sp_head::make_field");
- thd= current_thd;
- tmp_mem_root= thd->mem_root;
- if (thd->spcont && thd->spcont->callers_mem_root)
- thd->mem_root= thd->spcont->callers_mem_root;
- else
- thd->mem_root= &thd->main_mem_root;
field= ::make_field((char *)0,
!m_returns_len ? max_length : m_returns_len,
(uchar *)"", 0, m_returns_pack, m_returns, m_returns_cs,
(enum Field::geometry_type)0, Field::NONE,
m_returns_typelib,
name ? name : (const char *)m_name.str, dummy);
- thd->mem_root= tmp_mem_root;
DBUG_RETURN(field);
}
@@ -574,13 +605,22 @@ sp_head::execute(THD *thd)
sp_rcontext *ctx;
int ret= 0;
uint ip= 0;
+ ulong save_sql_mode;
Query_arena *old_arena;
+ /* per-instruction arena */
+ MEM_ROOT execute_mem_root;
+ Query_arena execute_arena(&execute_mem_root, INITIALIZED_FOR_SP),
+ execute_backup_arena;
query_id_t old_query_id;
TABLE *old_derived_tables;
LEX *old_lex;
Item_change_list old_change_list;
String old_packet;
+ /* init per-instruction memroot */
+ init_alloc_root(&execute_mem_root, MEM_ROOT_BLOCK_SIZE, 0);
+
+
/* Use some extra margin for possible SP recursion and functions */
if (check_stack_overrun(thd, 4*STACK_MIN_SIZE, olddb))
{
@@ -626,6 +666,8 @@ sp_head::execute(THD *thd)
old_query_id= thd->query_id;
old_derived_tables= thd->derived_tables;
thd->derived_tables= 0;
+ save_sql_mode= thd->variables.sql_mode;
+ thd->variables.sql_mode= m_sql_mode;
/*
It is also more efficient to save/restore current thd->lex once when
do it in each instruction
@@ -647,6 +689,18 @@ sp_head::execute(THD *thd)
*/
old_packet.swap(thd->packet);
+ /*
+ Switch to per-instruction arena here. We can do it since we cleanup
+ arena after every instruction.
+ */
+ thd->set_n_backup_item_arena(&execute_arena, &execute_backup_arena);
+
+ /*
+ Save callers arena in order to store instruction results and out
+ parameters in it later during sp_eval_func_item()
+ */
+ thd->spcont->callers_arena= &execute_backup_arena;
+
do
{
sp_instr *i;
@@ -656,7 +710,9 @@ sp_head::execute(THD *thd)
if (i == NULL)
break;
DBUG_PRINT("execute", ("Instruction %u", ip));
- thd->set_time(); // Make current_time() et al work
+ /* Don't change NOW() in FUNCTION or TRIGGER */
+ if (!thd->in_sub_stmt)
+ thd->set_time(); // Make current_time() et al work
/*
We have to set thd->current_arena before executing the instruction
to store in the instruction free_list all new items, created
@@ -665,6 +721,7 @@ sp_head::execute(THD *thd)
*/
thd->current_arena= i;
ret= i->execute(thd, &ip);
+
/*
If this SP instruction have sent eof, it has caused no_send_error to be
set. Clear it back to allow the next instruction to send error. (multi-
@@ -675,23 +732,30 @@ sp_head::execute(THD *thd)
cleanup_items(i->free_list);
i->state= Query_arena::EXECUTED;
- // Check if an exception has occurred and a handler has been found
- // Note: We havo to check even if ret==0, since warnings (and some
- // errors don't return a non-zero value.
- // We also have to check even if thd->killed != 0, since some
- // errors return with this even when a handler has been found
- // (e.g. "bad data").
+ /* we should cleanup free_list and memroot, used by instruction */
+ thd->free_items();
+ free_root(&execute_mem_root, MYF(0));
+
+ /*
+ Check if an exception has occurred and a handler has been found
+ Note: We havo to check even if ret==0, since warnings (and some
+ errors don't return a non-zero value.
+ We also have to check even if thd->killed != 0, since some
+ errors return with this even when a handler has been found
+ (e.g. "bad data").
+ */
if (ctx)
{
uint hf;
- switch (ctx->found_handler(&hip, &hf))
- {
+ switch (ctx->found_handler(&hip, &hf)) {
case SP_HANDLER_NONE:
break;
case SP_HANDLER_CONTINUE:
- ctx->save_variables(hf);
- ctx->push_hstack(ip);
+ thd->restore_backup_item_arena(&execute_arena, &execute_backup_arena);
+ ctx->save_variables(hf);
+ thd->set_n_backup_item_arena(&execute_arena, &execute_backup_arena);
+ ctx->push_hstack(ip);
// Fall through
default:
ip= hip;
@@ -705,6 +769,9 @@ sp_head::execute(THD *thd)
}
} while (ret == 0 && !thd->killed);
+ thd->restore_backup_item_arena(&execute_arena, &execute_backup_arena);
+
+
/* Restore all saved */
old_packet.swap(thd->packet);
DBUG_ASSERT(thd->change_list.is_empty());
@@ -715,6 +782,7 @@ sp_head::execute(THD *thd)
thd->query_id= old_query_id;
DBUG_ASSERT(!thd->derived_tables);
thd->derived_tables= old_derived_tables;
+ thd->variables.sql_mode= save_sql_mode;
thd->current_arena= old_arena;
state= EXECUTED;
@@ -730,7 +798,7 @@ sp_head::execute(THD *thd)
if (dbchanged)
{
if (! thd->killed)
- ret= sp_change_db(thd, olddb, 0);
+ ret= mysql_change_db(thd, olddb, 0);
}
m_is_invoked= FALSE;
DBUG_RETURN(ret);
@@ -750,28 +818,25 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp)
sp_rcontext *nctx = NULL;
uint i;
int ret;
- MEM_ROOT call_mem_root;
- Query_arena call_arena(&call_mem_root, INITIALIZED_FOR_SP), backup_arena;
if (argcount != params)
{
- // Need to use my_printf_error here, or it will not terminate the
- // invoking query properly.
+ /*
+ Need to use my_printf_error here, or it will not terminate the
+ invoking query properly.
+ */
my_error(ER_SP_WRONG_NO_OF_ARGS, MYF(0),
"FUNCTION", m_qname.str, params, argcount);
DBUG_RETURN(-1);
}
- init_alloc_root(&call_mem_root, MEM_ROOT_BLOCK_SIZE, 0);
-
// QQ Should have some error checking here? (types, etc...)
nctx= new sp_rcontext(csize, hmax, cmax);
- nctx->callers_mem_root= thd->mem_root;
for (i= 0 ; i < argcount ; i++)
{
sp_pvar_t *pvar = m_pcont->find_pvar(i);
- Item *it= sp_eval_func_item(thd, argp++, pvar->type, NULL);
+ Item *it= sp_eval_func_item(thd, argp++, pvar->type, NULL, FALSE);
if (it)
nctx->push_item(it);
@@ -780,9 +845,11 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp)
DBUG_RETURN(-1);
}
}
- // The rest of the frame are local variables which are all IN.
- // Default all variables to null (those with default clauses will
- // be set by an set instruction).
+ /*
+ The rest of the frame are local variables which are all IN.
+ Default all variables to null (those with default clauses will
+ be set by an set instruction).
+ */
{
Item_null *nit= NULL; // Re-use this, and only create if needed
for (; i < csize ; i++)
@@ -793,24 +860,16 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp)
}
}
thd->spcont= nctx;
- thd->set_n_backup_item_arena(&call_arena, &backup_arena);
- /* mem_root was moved to backup_arena */
- DBUG_ASSERT(nctx->callers_mem_root == backup_arena.mem_root);
ret= execute(thd);
- // Partially restore context now.
- // We still need the call mem root and free list for processing
- // of the result.
- thd->restore_backup_item_arena(&call_arena, &backup_arena);
-
if (m_type == TYPE_ENUM_FUNCTION && ret == 0)
{
/* We need result only in function but not in trigger */
Item *it= nctx->get_result();
if (it)
- *resp= sp_eval_func_item(thd, &it, m_returns, NULL);
+ *resp= sp_eval_func_item(thd, &it, m_returns, NULL, FALSE);
else
{
my_error(ER_SP_NORETURNEND, MYF(0), m_name.str);
@@ -819,12 +878,9 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp)
}
nctx->pop_all_cursors(); // To avoid memory leaks after an error
+ delete nctx;
thd->spcont= octx;
- // Now get rid of the rest of the callee context
- call_arena.free_items();
- free_root(&call_mem_root, MYF(0));
-
DBUG_RETURN(ret);
}
@@ -853,9 +909,7 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
uint cmax = m_pcont->max_cursors();
sp_rcontext *octx = thd->spcont;
sp_rcontext *nctx = NULL;
- my_bool tmp_octx = FALSE; // True if we have allocated a temporary octx
- MEM_ROOT call_mem_root;
- Query_arena call_arena(&call_mem_root, INITIALIZED_FOR_SP), backup_arena;
+ my_bool is_tmp_octx = FALSE; // True if we have allocated a temporary octx
if (args->elements != params)
{
@@ -864,7 +918,17 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
DBUG_RETURN(-1);
}
- init_alloc_root(&call_mem_root, MEM_ROOT_BLOCK_SIZE, 0);
+ if (! octx)
+ { // Create a temporary old context
+ octx= new sp_rcontext(csize, hmax, cmax);
+ is_tmp_octx= TRUE;
+ thd->spcont= octx;
+
+ /* set callers_arena to thd, for upper-level function to work */
+ thd->spcont->callers_arena= thd;
+ }
+
+ nctx= new sp_rcontext(csize, hmax, cmax);
if (csize > 0 || hmax > 0 || cmax > 0)
{
@@ -873,13 +937,10 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
List_iterator<Item> li(*args);
Item *it;
- nctx= new sp_rcontext(csize, hmax, cmax);
- if (! octx)
- { // Create a temporary old context
- octx= new sp_rcontext(csize, hmax, cmax);
- tmp_octx= TRUE;
- }
+
+ /* Evaluate SP arguments (i.e. get the values passed as parameters) */
// QQ: Should do type checking?
+ DBUG_PRINT("info",(" %.*s: eval args", m_name.length, m_name.str));
for (i = 0 ; (it= li++) && i < params ; i++)
{
sp_pvar_t *pvar= m_pcont->find_pvar(i);
@@ -903,7 +964,7 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
}
else
{
- Item *it2= sp_eval_func_item(thd, li.ref(), pvar->type, NULL);
+ Item *it2= sp_eval_func_item(thd, li.ref(), pvar->type, NULL, FALSE);
if (it2)
nctx->push_item(it2); // IN or INOUT
@@ -916,32 +977,50 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
}
}
- // The rest of the frame are local variables which are all IN.
- // Default all variables to null (those with default clauses will
- // be set by an set instruction).
+ /*
+ Okay, got values for all arguments. Close tables that might be used by
+ arguments evaluation. If arguments evaluation required prelocking mode,
+ we'll leave it here.
+ */
+ if (!thd->in_sub_stmt)
+ close_thread_tables(thd, 0, 0);
+
+ DBUG_PRINT("info",(" %.*s: eval args done", m_name.length, m_name.str));
+ /*
+ The rest of the frame are local variables which are all IN.
+ Default all variables to null (those with default clauses will
+ be set by an set instruction).
+ */
for (; i < csize ; i++)
{
if (! nit)
nit= new Item_null();
nctx->push_item(nit);
}
- thd->spcont= nctx;
}
+ thd->spcont= nctx;
+
if (! ret)
- {
- thd->set_n_backup_item_arena(&call_arena, &backup_arena);
ret= execute(thd);
- thd->restore_backup_item_arena(&call_arena, &backup_arena);
- }
+
+ /*
+ In the case when we weren't able to employ reuse mechanism for
+ OUT/INOUT paranmeters, we should reallocate memory. This
+ allocation should be done on the arena which will live through
+ all execution of calling routine.
+ */
+ thd->spcont->callers_arena= octx->callers_arena;
if (!ret && csize > 0)
{
List_iterator<Item> li(*args);
Item *it;
- // Copy back all OUT or INOUT values to the previous frame, or
- // set global user variables
+ /*
+ Copy back all OUT or INOUT values to the previous frame, or
+ set global user variables
+ */
for (uint i = 0 ; (it= li++) && i < params ; i++)
{
sp_pvar_t *pvar= m_pcont->find_pvar(i);
@@ -956,12 +1035,20 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
Item *val= nctx->get_item(i);
Item *orig= octx->get_item(offset);
Item *o_item_next;
- Item *o_free_list= thd->free_list;
+ /* we'll use callers_arena in sp_eval_func_item */
+ Item *o_free_list= thd->spcont->callers_arena->free_list;
+
LINT_INIT(o_item_next);
if (orig)
o_item_next= orig->next;
- copy= sp_eval_func_item(thd, &val, pvar->type, orig); // Copy
+
+ /*
+ We might need to allocate new item if we weren't able to
+ employ reuse mechanism. Then we should do it on the callers arena.
+ */
+ copy= sp_eval_func_item(thd, &val, pvar->type, orig, TRUE); // Copy
+
if (!copy)
{
ret= -1;
@@ -971,9 +1058,11 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
octx->set_item(offset, copy);
if (orig && copy == orig)
{
- // A reused item slot, where the constructor put it in the
- // free_list, so we have to restore the list.
- thd->free_list= o_free_list;
+ /*
+ A reused item slot, where the constructor put it in the
+ free_list, so we have to restore the list.
+ */
+ thd->spcont->callers_arena->free_list= o_free_list;
copy->next= o_item_next;
}
}
@@ -1001,16 +1090,15 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
}
}
- if (tmp_octx)
+ if (is_tmp_octx)
+ {
+ delete octx; /* call destructor */
octx= NULL;
- if (nctx)
- nctx->pop_all_cursors(); // To avoid memory leaks after an error
- thd->spcont= octx;
+ }
- // Now get rid of the rest of the callee context
- call_arena.free_items();
- thd->lex->unit.cleanup();
- free_root(&call_mem_root, MYF(0));
+ nctx->pop_all_cursors(); // To avoid memory leaks after an error
+ delete nctx;
+ thd->spcont= octx;
DBUG_RETURN(ret);
}
@@ -1245,8 +1333,6 @@ sp_head::show_create_procedure(THD *thd)
String buffer(buff, sizeof(buff), system_charset_info);
int res;
List<Item> field_list;
- ulong old_sql_mode;
- sys_var *sql_mode_var;
byte *sql_mode_str;
ulong sql_mode_len;
bool full_access;
@@ -1258,19 +1344,13 @@ sp_head::show_create_procedure(THD *thd)
if (check_show_routine_access(thd, this, &full_access))
return 1;
-
- old_sql_mode= thd->variables.sql_mode;
- thd->variables.sql_mode= m_sql_mode;
- sql_mode_var= find_sys_var("SQL_MODE", 8);
- if (sql_mode_var)
- {
- sql_mode_str= sql_mode_var->value_ptr(thd, OPT_SESSION, 0);
- sql_mode_len= strlen((char*) sql_mode_str);
- }
+ sql_mode_str=
+ sys_var_thd_sql_mode::symbolic_mode_representation(thd,
+ m_sql_mode,
+ &sql_mode_len);
field_list.push_back(new Item_empty_string("Procedure", NAME_LEN));
- if (sql_mode_var)
- field_list.push_back(new Item_empty_string("sql_mode", sql_mode_len));
+ field_list.push_back(new Item_empty_string("sql_mode", sql_mode_len));
// 1024 is for not to confuse old clients
field_list.push_back(new Item_empty_string("Create Procedure",
max(buffer.length(), 1024)));
@@ -1282,15 +1362,13 @@ sp_head::show_create_procedure(THD *thd)
}
protocol->prepare_for_resend();
protocol->store(m_name.str, m_name.length, system_charset_info);
- if (sql_mode_var)
- protocol->store((char*) sql_mode_str, sql_mode_len, system_charset_info);
+ protocol->store((char*) sql_mode_str, sql_mode_len, system_charset_info);
if (full_access)
protocol->store(m_defstr.str, m_defstr.length, system_charset_info);
res= protocol->write();
send_eof(thd);
done:
- thd->variables.sql_mode= old_sql_mode;
DBUG_RETURN(res);
}
@@ -1326,8 +1404,6 @@ sp_head::show_create_function(THD *thd)
String buffer(buff, sizeof(buff), system_charset_info);
int res;
List<Item> field_list;
- ulong old_sql_mode;
- sys_var *sql_mode_var;
byte *sql_mode_str;
ulong sql_mode_len;
bool full_access;
@@ -1339,18 +1415,12 @@ sp_head::show_create_function(THD *thd)
if (check_show_routine_access(thd, this, &full_access))
return 1;
- old_sql_mode= thd->variables.sql_mode;
- thd->variables.sql_mode= m_sql_mode;
- sql_mode_var= find_sys_var("SQL_MODE", 8);
- if (sql_mode_var)
- {
- sql_mode_str= sql_mode_var->value_ptr(thd, OPT_SESSION, 0);
- sql_mode_len= strlen((char*) sql_mode_str);
- }
-
+ sql_mode_str=
+ sys_var_thd_sql_mode::symbolic_mode_representation(thd,
+ m_sql_mode,
+ &sql_mode_len);
field_list.push_back(new Item_empty_string("Function",NAME_LEN));
- if (sql_mode_var)
- field_list.push_back(new Item_empty_string("sql_mode", sql_mode_len));
+ field_list.push_back(new Item_empty_string("sql_mode", sql_mode_len));
field_list.push_back(new Item_empty_string("Create Function",
max(buffer.length(),1024)));
if (protocol->send_fields(&field_list,
@@ -1361,15 +1431,13 @@ sp_head::show_create_function(THD *thd)
}
protocol->prepare_for_resend();
protocol->store(m_name.str, m_name.length, system_charset_info);
- if (sql_mode_var)
- protocol->store((char*) sql_mode_str, sql_mode_len, system_charset_info);
+ protocol->store((char*) sql_mode_str, sql_mode_len, system_charset_info);
if (full_access)
protocol->store(m_defstr.str, m_defstr.length, system_charset_info);
res= protocol->write();
send_eof(thd);
done:
- thd->variables.sql_mode= old_sql_mode;
DBUG_RETURN(res);
}
@@ -1424,8 +1492,6 @@ sp_head::opt_mark(uint ip)
ip= i->opt_mark(this);
}
-// ------------------------------------------------------------------
-
/*
Prepare LEX and thread for execution of instruction, if requested open
@@ -1480,8 +1546,27 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp,
implemented at the same time as ability not to store LEX for
instruction if it is not really used.
*/
- reinit_stmt_before_use(thd, m_lex);
+ if (thd->prelocked_mode == NON_PRELOCKED)
+ {
+ /*
+ This statement will enter/leave prelocked mode on its own.
+ Entering prelocked mode changes table list and related members
+ of LEX, so we'll need to restore them.
+ */
+ if (lex_query_tables_own_last)
+ {
+ /*
+ We've already entered/left prelocked mode with this statement.
+ Attach the list of tables that need to be prelocked and mark m_lex
+ as having such list attached.
+ */
+ *lex_query_tables_own_last= prelocking_tables;
+ m_lex->mark_as_requiring_prelocking(lex_query_tables_own_last);
+ }
+ }
+
+ reinit_stmt_before_use(thd, m_lex);
/*
If requested check whenever we have access to tables in LEX's table list
and open and lock them before executing instructtions core function.
@@ -1498,7 +1583,28 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp,
thd->proc_info="closing tables";
close_thread_tables(thd);
+ thd->proc_info= 0;
+ if (m_lex->query_tables_own_last)
+ {
+ /*
+ We've entered and left prelocking mode when executing statement
+ stored in m_lex.
+ m_lex->query_tables(->next_global)* list now has a 'tail' - a list
+ of tables that are added for prelocking. (If this is the first
+ execution, the 'tail' was added by open_tables(), otherwise we've
+ attached it above in this function).
+ Now we'll save the 'tail', and detach it.
+ */
+ DBUG_ASSERT(!lex_query_tables_own_last ||
+ lex_query_tables_own_last == m_lex->query_tables_own_last &&
+ prelocking_tables == *(m_lex->query_tables_own_last));
+
+ lex_query_tables_own_last= m_lex->query_tables_own_last;
+ prelocking_tables= *lex_query_tables_own_last;
+ *lex_query_tables_own_last= NULL;
+ m_lex->mark_as_requiring_prelocking(NULL);
+ }
thd->rollback_item_tree_changes();
/*
@@ -1514,9 +1620,10 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp,
}
-//
-// sp_instr
-//
+/*
+ sp_instr class functions
+*/
+
int sp_instr::exec_core(THD *thd, uint *nextp)
{
DBUG_ASSERT(0);
@@ -1524,9 +1631,10 @@ int sp_instr::exec_core(THD *thd, uint *nextp)
}
-//
-// sp_instr_stmt
-//
+/*
+ sp_instr_stmt class functions
+*/
+
int
sp_instr_stmt::execute(THD *thd, uint *nextp)
{
@@ -1571,9 +1679,11 @@ sp_instr_stmt::exec_core(THD *thd, uint *nextp)
return res;
}
-//
-// sp_instr_set
-//
+
+/*
+ sp_instr_set class functions
+*/
+
int
sp_instr_set::execute(THD *thd, uint *nextp)
{
@@ -1583,6 +1693,7 @@ sp_instr_set::execute(THD *thd, uint *nextp)
DBUG_RETURN(m_lex_keeper.reset_lex_and_exec_core(thd, nextp, TRUE, this));
}
+
int
sp_instr_set::exec_core(THD *thd, uint *nextp)
{
@@ -1603,9 +1714,10 @@ sp_instr_set::print(String *str)
}
-//
-// sp_instr_set_trigger_field
-//
+/*
+ sp_instr_set_trigger_field class functions
+*/
+
int
sp_instr_set_trigger_field::execute(THD *thd, uint *nextp)
{
@@ -1636,9 +1748,11 @@ sp_instr_set_trigger_field::print(String *str)
value->print(str);
}
-//
-// sp_instr_jump
-//
+
+/*
+ sp_instr_jump class functions
+*/
+
int
sp_instr_jump::execute(THD *thd, uint *nextp)
{
@@ -1697,9 +1811,10 @@ sp_instr_jump::opt_move(uint dst, List<sp_instr> *bp)
m_ip= dst;
}
-//
-// sp_instr_jump_if
-//
+
+/*
+ sp_instr_jump_if class functions
+*/
int
sp_instr_jump_if::execute(THD *thd, uint *nextp)
@@ -1755,9 +1870,11 @@ sp_instr_jump_if::opt_mark(sp_head *sp)
return m_ip+1;
}
-//
-// sp_instr_jump_if_not
-//
+
+/*
+ sp_instr_jump_if_not class functions
+*/
+
int
sp_instr_jump_if_not::execute(THD *thd, uint *nextp)
{
@@ -1788,6 +1905,7 @@ sp_instr_jump_if_not::exec_core(THD *thd, uint *nextp)
return res;
}
+
void
sp_instr_jump_if_not::print(String *str)
{
@@ -1798,6 +1916,7 @@ sp_instr_jump_if_not::print(String *str)
m_expr->print(str);
}
+
uint
sp_instr_jump_if_not::opt_mark(sp_head *sp)
{
@@ -1813,9 +1932,10 @@ sp_instr_jump_if_not::opt_mark(sp_head *sp)
return m_ip+1;
}
-//
-// sp_instr_freturn
-//
+
+/*
+ sp_instr_freturn class functions
+*/
int
sp_instr_freturn::execute(THD *thd, uint *nextp)
@@ -1831,7 +1951,7 @@ sp_instr_freturn::exec_core(THD *thd, uint *nextp)
Item *it;
int res;
- it= sp_eval_func_item(thd, &m_value, m_type, NULL);
+ it= sp_eval_func_item(thd, &m_value, m_type, NULL, TRUE);
if (! it)
res= -1;
else
@@ -1854,9 +1974,10 @@ sp_instr_freturn::print(String *str)
m_value->print(str);
}
-//
-// sp_instr_hpush_jump
-//
+/*
+ sp_instr_hpush_jump class functions
+*/
+
int
sp_instr_hpush_jump::execute(THD *thd, uint *nextp)
{
@@ -1900,9 +2021,11 @@ sp_instr_hpush_jump::opt_mark(sp_head *sp)
return m_ip+1;
}
-//
-// sp_instr_hpop
-//
+
+/*
+ sp_instr_hpop class functions
+*/
+
int
sp_instr_hpop::execute(THD *thd, uint *nextp)
{
@@ -1927,9 +2050,10 @@ sp_instr_hpop::backpatch(uint dest, sp_pcontext *dst_ctx)
}
-//
-// sp_instr_hreturn
-//
+/*
+ sp_instr_hreturn class functions
+*/
+
int
sp_instr_hreturn::execute(THD *thd, uint *nextp)
{
@@ -1945,6 +2069,7 @@ sp_instr_hreturn::execute(THD *thd, uint *nextp)
DBUG_RETURN(0);
}
+
void
sp_instr_hreturn::print(String *str)
{
@@ -1955,6 +2080,7 @@ sp_instr_hreturn::print(String *str)
str->qs_append(m_dest);
}
+
uint
sp_instr_hreturn::opt_mark(sp_head *sp)
{
@@ -1968,27 +2094,45 @@ sp_instr_hreturn::opt_mark(sp_head *sp)
}
-//
-// sp_instr_cpush
-//
+/*
+ sp_instr_cpush class functions
+*/
+
int
sp_instr_cpush::execute(THD *thd, uint *nextp)
{
+ Query_arena backup_current_arena;
DBUG_ENTER("sp_instr_cpush::execute");
+
+ /*
+ We should create cursors in the callers arena, as
+ it could be (and usually is) used in several instructions.
+ */
+ thd->set_n_backup_item_arena(thd->spcont->callers_arena,
+ &backup_current_arena);
+
thd->spcont->push_cursor(&m_lex_keeper, this);
+
+ thd->restore_backup_item_arena(thd->spcont->callers_arena,
+ &backup_current_arena);
+
*nextp= m_ip+1;
+
DBUG_RETURN(0);
}
+
void
sp_instr_cpush::print(String *str)
{
str->append("cpush");
}
-//
-// sp_instr_cpop
-//
+
+/*
+ sp_instr_cpop class functions
+*/
+
int
sp_instr_cpop::execute(THD *thd, uint *nextp)
{
@@ -1998,6 +2142,7 @@ sp_instr_cpop::execute(THD *thd, uint *nextp)
DBUG_RETURN(0);
}
+
void
sp_instr_cpop::print(String *str)
{
@@ -2012,9 +2157,11 @@ sp_instr_cpop::backpatch(uint dest, sp_pcontext *dst_ctx)
m_count= m_ctx->diff_cursors(dst_ctx);
}
-//
-// sp_instr_copen
-//
+
+/*
+ sp_instr_copen class functions
+*/
+
int
sp_instr_copen::execute(THD *thd, uint *nextp)
{
@@ -2082,9 +2229,11 @@ sp_instr_copen::print(String *str)
str->qs_append(m_cursor);
}
-//
-// sp_instr_cclose
-//
+
+/*
+ sp_instr_cclose class functions
+*/
+
int
sp_instr_cclose::execute(THD *thd, uint *nextp)
{
@@ -2100,6 +2249,7 @@ sp_instr_cclose::execute(THD *thd, uint *nextp)
DBUG_RETURN(res);
}
+
void
sp_instr_cclose::print(String *str)
{
@@ -2108,24 +2258,35 @@ sp_instr_cclose::print(String *str)
str->qs_append(m_cursor);
}
-//
-// sp_instr_cfetch
-//
+
+/*
+ sp_instr_cfetch class functions
+*/
+
int
sp_instr_cfetch::execute(THD *thd, uint *nextp)
{
sp_cursor *c= thd->spcont->get_cursor(m_cursor);
int res;
+ Query_arena backup_current_arena;
DBUG_ENTER("sp_instr_cfetch::execute");
if (! c)
res= -1;
else
+ {
+ thd->set_n_backup_item_arena(thd->spcont->callers_arena,
+ &backup_current_arena);
res= c->fetch(thd, &m_varlist);
+ thd->restore_backup_item_arena(thd->spcont->callers_arena,
+ &backup_current_arena);
+ }
+
*nextp= m_ip+1;
DBUG_RETURN(res);
}
+
void
sp_instr_cfetch::print(String *str)
{
@@ -2143,9 +2304,11 @@ sp_instr_cfetch::print(String *str)
}
}
-//
-// sp_instr_error
-//
+
+/*
+ sp_instr_error class functions
+*/
+
int
sp_instr_error::execute(THD *thd, uint *nextp)
{
@@ -2156,6 +2319,7 @@ sp_instr_error::execute(THD *thd, uint *nextp)
DBUG_RETURN(-1);
}
+
void
sp_instr_error::print(String *str)
{
@@ -2164,12 +2328,12 @@ sp_instr_error::print(String *str)
str->qs_append(m_errcode);
}
-/* ------------------------------------------------------------------ */
+/* ------------------------------------------------------------------ */
-//
-// Security context swapping
-//
+/*
+ Security context swapping
+*/
#ifndef NO_EMBEDDED_ACCESS_CHECKS
void
@@ -2418,11 +2582,12 @@ sp_head::add_used_tables_to_table_list(THD *thd,
DBUG_RETURN(result);
}
+
/*
- * Simple function for adding an explicetly named (systems) table to
- * the global table list, e.g. "mysql", "proc".
- *
- */
+ Simple function for adding an explicetly named (systems) table to
+ the global table list, e.g. "mysql", "proc".
+*/
+
TABLE_LIST *
sp_add_to_query_tables(THD *thd, LEX *lex,
const char *db, const char *name,