summaryrefslogtreecommitdiff
path: root/sql/sp_head.cc
diff options
context:
space:
mode:
authorJon Olav Hauglid <jon.hauglid@sun.com>2010-06-06 13:19:29 +0200
committerJon Olav Hauglid <jon.hauglid@sun.com>2010-06-06 13:19:29 +0200
commit142a162c665704ce5b4d5b671d05a068661c088a (patch)
treedef1ebab09889a8f09a9fcd074c8a672689376af /sql/sp_head.cc
parentcbf4019a1b3ec82bdcd9a65db114908a920fb01c (diff)
parent60a9d9bbb94ac03159bcc2d75b649abb1c9dc956 (diff)
downloadmariadb-git-142a162c665704ce5b4d5b671d05a068661c088a.tar.gz
manual merge from mysql-trunk-bugfixing
Conflicts: Text conflict in mysql-test/r/archive.result Contents conflict in mysql-test/r/innodb_bug38231.result Text conflict in mysql-test/r/mdl_sync.result Text conflict in mysql-test/suite/binlog/t/disabled.def Text conflict in mysql-test/suite/rpl_ndb/r/rpl_ndb_binlog_format_errors.result Text conflict in mysql-test/t/archive.test Contents conflict in mysql-test/t/innodb_bug38231.test Text conflict in mysql-test/t/mdl_sync.test Text conflict in sql/sp_head.cc Text conflict in sql/sql_show.cc Text conflict in sql/table.cc Text conflict in sql/table.h
Diffstat (limited to 'sql/sp_head.cc')
-rw-r--r--sql/sp_head.cc234
1 files changed, 113 insertions, 121 deletions
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 2d5b648e82e..61f00fdf59a 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -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);
@@ -747,21 +747,12 @@ create_typelib(MEM_ROOT *mem_root, Create_field *field_def, List<String> *src)
sp_head::~sp_head()
{
+ LEX *lex;
+ sp_instr *i;
DBUG_ENTER("sp_head::~sp_head");
- destroy();
- delete m_next_cached_sp;
- if (m_thd)
- restore_thd_mem_root(m_thd);
- DBUG_VOID_RETURN;
-}
-void
-sp_head::destroy()
-{
- sp_instr *i;
- LEX *lex;
- DBUG_ENTER("sp_head::destroy");
- DBUG_PRINT("info", ("name: %s", m_name.str));
+ /* sp_head::restore_thd_mem_root() must already have been called. */
+ DBUG_ASSERT(m_thd == NULL);
for (uint ip = 0 ; (i = get_instr(ip)) ; ip++)
delete i;
@@ -772,21 +763,22 @@ sp_head::destroy()
/*
If we have non-empty LEX stack then we just came out of parser with
error. Now we should delete all auxilary LEXes and restore original
- THD::lex (In this case sp_head::restore_thd_mem_root() was not called
- too, so m_thd points to the current thread context).
- It is safe to not update LEX::ptr because further query string parsing
- and execution will be stopped anyway.
+ THD::lex. It is safe to not update LEX::ptr because further query
+ string parsing and execution will be stopped anyway.
*/
- DBUG_ASSERT(m_lex.is_empty() || m_thd);
while ((lex= (LEX *)m_lex.pop()))
{
- lex_end(m_thd->lex);
- delete m_thd->lex;
- m_thd->lex= lex;
+ THD *thd= lex->thd;
+ lex_end(thd->lex);
+ delete thd->lex;
+ thd->lex= lex;
}
my_hash_free(&m_sptabs);
my_hash_free(&m_sroutines);
+
+ delete m_next_cached_sp;
+
DBUG_VOID_RETURN;
}
@@ -823,7 +815,7 @@ sp_head::create_result_field(uint field_max_length, const char *field_name,
if (field)
field->init(table);
-
+
DBUG_RETURN(field);
}
@@ -852,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
@@ -865,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
@@ -874,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)
@@ -914,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.
@@ -951,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)"
*/
@@ -963,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++)
{
@@ -973,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)
@@ -1006,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);
@@ -1032,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)
@@ -1061,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
@@ -1225,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.
@@ -1237,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)
@@ -1248,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
@@ -1259,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;
@@ -1271,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.
*/
@@ -1284,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
@@ -1299,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);
@@ -1308,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;
@@ -1359,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)
@@ -1847,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
@@ -1888,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
@@ -2155,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);
@@ -2308,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;
@@ -2318,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;
}
@@ -2360,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;
}
@@ -2369,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;
@@ -2385,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
@@ -2517,8 +2511,6 @@ sp_head::show_create_routine(THD *thd, int type)
}
-
-
/**
Add instruction to SP.
@@ -2578,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);
@@ -2677,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.
*/
@@ -2740,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.
@@ -2902,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);
@@ -3007,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();
@@ -3051,6 +3042,7 @@ int
sp_instr_set_trigger_field::execute(THD *thd, uint *nextp)
{
DBUG_ENTER("sp_instr_set_trigger_field::execute");
+ thd->count_cuted_fields= CHECK_FIELD_ERROR_FOR_NULL;
DBUG_RETURN(m_lex_keeper.reset_lex_and_exec_core(thd, nextp, TRUE, this));
}
@@ -3110,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;
@@ -3140,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;
}
@@ -3415,7 +3407,7 @@ uint
sp_instr_hreturn::opt_mark(sp_head *sp, List<sp_instr> *leads)
{
marked= 1;
-
+
if (m_dest)
{
/*
@@ -3423,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.
@@ -3740,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();
@@ -3913,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
@@ -3932,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;
}
}