summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/create_options.cc3
-rw-r--r--sql/field.cc74
-rw-r--r--sql/field.h2
-rw-r--r--sql/item.cc69
-rw-r--r--sql/item.h6
-rw-r--r--sql/log_event.cc5
-rw-r--r--sql/opt_subselect.cc6
-rw-r--r--sql/rpl_parallel.cc11
-rw-r--r--sql/sp_head.cc134
-rw-r--r--sql/sp_head.h7
-rw-r--r--sql/sp_rcontext.cc135
-rw-r--r--sql/sp_rcontext.h9
-rw-r--r--sql/sql_acl.cc3
-rw-r--r--sql/sql_bootstrap.cc6
-rw-r--r--sql/sql_class.h46
-rw-r--r--sql/sql_parse.cc1
-rw-r--r--sql/sql_repl.cc7
-rw-r--r--sql/sql_select.cc66
-rw-r--r--sql/sql_select.h42
-rw-r--r--sql/table.cc7
20 files changed, 372 insertions, 267 deletions
diff --git a/sql/create_options.cc b/sql/create_options.cc
index d010b73c222..d0a155c097f 100644
--- a/sql/create_options.cc
+++ b/sql/create_options.cc
@@ -613,7 +613,8 @@ uchar *engine_option_value::frm_image(uchar *buff)
{
if (value.str)
{
- *buff++= name.length;
+ DBUG_ASSERT(name.length <= 0xff);
+ *buff++= (uchar)name.length;
memcpy(buff, name.str, name.length);
buff+= name.length;
int2store(buff, value.length | (quoted_value ? FRM_QUOTED_VALUE : 0));
diff --git a/sql/field.cc b/sql/field.cc
index 8de823cee7c..8ac7eeafd5c 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -1267,6 +1267,45 @@ bool Field::load_data_set_null(THD *thd)
}
+bool Field::sp_prepare_and_store_item(THD *thd, Item **value)
+{
+ DBUG_ENTER("Field::sp_prepare_and_store_item");
+ DBUG_ASSERT(value);
+
+ Item *expr_item;
+
+ if (!(expr_item= thd->sp_prepare_func_item(value, 1)))
+ goto error;
+
+ /*
+ expr_item is now fixed, it's safe to call cmp_type()
+ */
+ if (expr_item->cmp_type() == ROW_RESULT)
+ {
+ my_error(ER_OPERAND_COLUMNS, MYF(0), 1);
+ goto error;
+ }
+
+ /* Save the value in the field. Convert the value if needed. */
+
+ expr_item->save_in_field(this, 0);
+
+ if (!thd->is_error())
+ DBUG_RETURN(false);
+
+error:
+ /*
+ In case of error during evaluation, leave the result field set to NULL.
+ Sic: we can't do it in the beginning of the function because the
+ result field might be needed for its own re-evaluation, e.g. case of
+ set x = x + 1;
+ */
+ set_null();
+ DBUG_ASSERT(thd->is_error());
+ DBUG_RETURN(true);
+}
+
+
/**
Numeric fields base class constructor.
*/
@@ -2341,6 +2380,41 @@ Field_row::~Field_row()
}
+bool Field_row::sp_prepare_and_store_item(THD *thd, Item **value)
+{
+ DBUG_ENTER("Field_row::sp_prepare_and_store_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.
+ */
+ m_table->set_all_fields_to_null();
+ DBUG_RETURN(false);
+ }
+
+ /**
+ - In case if we're assigning a ROW variable from another ROW variable,
+ value[0] points to Item_splocal. sp_fix_func_item() will return the
+ fixed underlying Item_field pointing to Field_row.
+ - 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= thd->sp_fix_func_item(value)) ||
+ src->cmp_type() != ROW_RESULT ||
+ src->cols() != m_table->s->fields)
+ {
+ my_error(ER_OPERAND_COLUMNS, MYF(0), m_table->s->fields);
+ m_table->set_all_fields_to_null();
+ DBUG_RETURN(true);
+ }
+
+ DBUG_RETURN(m_table->sp_set_all_fields_from_item(thd, src));
+}
+
+
/****************************************************************************
Functions for the Field_decimal class
This is an number stored as a pre-space (or pre-zero) string
diff --git a/sql/field.h b/sql/field.h
index 2da66bae8bc..e1017f04c27 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -1572,6 +1572,7 @@ public:
{
return NULL;
}
+ virtual bool sp_prepare_and_store_item(THD *thd, Item **value);
friend int cre_myisam(char * name, register TABLE *form, uint options,
ulonglong auto_increment_value);
@@ -4063,6 +4064,7 @@ public:
{}
~Field_row();
Virtual_tmp_table **virtual_tmp_table_addr() { return &m_table; }
+ bool sp_prepare_and_store_item(THD *thd, Item **value);
};
diff --git a/sql/item.cc b/sql/item.cc
index d916e4328d7..bcea8180e05 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -1973,14 +1973,11 @@ bool Item_splocal_row_field::set_value(THD *thd, sp_rcontext *ctx, Item **it)
bool Item_splocal_row_field_by_name::fix_fields(THD *thd, Item **it)
{
m_thd= thd;
- Item *item, *row= m_thd->spcont->get_item(m_var_idx);
- if (row->element_index_by_name(&m_field_idx, m_field_name))
- {
- my_error(ER_ROW_VARIABLE_DOES_NOT_HAVE_FIELD, MYF(0),
- m_name.str, m_field_name.str);
+ if (thd->spcont->find_row_field_by_name_or_error(&m_field_idx,
+ m_var_idx,
+ m_field_name))
return true;
- }
- item= row->element_index(m_field_idx);
+ Item *item= thd->spcont->get_item(m_var_idx)->element_index(m_field_idx);
set_handler(item->type_handler());
return fix_fields_from_item(thd, it, item);
}
@@ -5712,7 +5709,7 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference)
*/
Name_resolution_context *last_checked_context= context;
Item **ref= (Item **) not_found_item;
- SELECT_LEX *current_sel= (SELECT_LEX *) thd->lex->current_select;
+ SELECT_LEX *current_sel= thd->lex->current_select;
Name_resolution_context *outer_context= 0;
SELECT_LEX *select= 0;
/* Currently derived tables cannot be correlated */
@@ -6046,8 +6043,9 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
DBUG_ASSERT(fixed == 0);
Field *from_field= (Field *)not_found_field;
bool outer_fixed= false;
+ SELECT_LEX *select= thd->lex->current_select;
- if (thd->lex->current_select->in_tvc)
+ if (select && select->in_tvc)
{
my_error(ER_FIELD_REFERENCE_IN_TVC, MYF(0),
full_name(), thd->where);
@@ -6075,13 +6073,14 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
not_found_field)
{
int ret;
+
/* Look up in current select's item_list to find aliased fields */
- if (thd->lex->current_select->is_item_list_lookup)
+ if (select && select->is_item_list_lookup)
{
uint counter;
enum_resolution_type resolution;
Item** res= find_item_in_list(this,
- thd->lex->current_select->item_list,
+ select->item_list,
&counter, REPORT_EXCEPT_NOT_FOUND,
&resolution);
if (!res)
@@ -6113,7 +6112,7 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
We can not "move" aggregate function in the place where
its arguments are not defined.
*/
- set_max_sum_func_level(thd, thd->lex->current_select);
+ set_max_sum_func_level(thd, select);
set_field(new_field);
return 0;
}
@@ -6132,7 +6131,6 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
if (err)
return TRUE;
- SELECT_LEX *select= thd->lex->current_select;
thd->change_item_tree(reference,
select->context_analysis_place == IN_GROUP_BY &&
alias_name_used ? *rf->ref : rf);
@@ -6141,11 +6139,17 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
We can not "move" aggregate function in the place where
its arguments are not defined.
*/
- set_max_sum_func_level(thd, thd->lex->current_select);
+ set_max_sum_func_level(thd, select);
return FALSE;
}
}
}
+
+ if (!select)
+ {
+ my_error(ER_BAD_FIELD_ERROR, MYF(0), full_name(), thd->where);
+ goto error;
+ }
if ((ret= fix_outer_field(thd, &from_field, reference)) < 0)
goto error;
outer_fixed= TRUE;
@@ -6174,9 +6178,9 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
if (thd->lex->in_sum_func &&
thd->lex->in_sum_func->nest_level ==
- thd->lex->current_select->nest_level)
+ select->nest_level)
set_if_bigger(thd->lex->in_sum_func->max_arg_level,
- thd->lex->current_select->nest_level);
+ select->nest_level);
/*
if it is not expression from merged VIEW we will set this field.
@@ -6242,11 +6246,12 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
fix_session_vcol_expr_for_read(thd, field, field->vcol_info);
if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY &&
!outer_fixed && !thd->lex->in_sum_func &&
- thd->lex->current_select->cur_pos_in_select_list != UNDEF_POS &&
- thd->lex->current_select->join)
+ select &&
+ select->cur_pos_in_select_list != UNDEF_POS &&
+ select->join)
{
- thd->lex->current_select->join->non_agg_fields.push_back(this, thd->mem_root);
- marker= thd->lex->current_select->cur_pos_in_select_list;
+ select->join->non_agg_fields.push_back(this, thd->mem_root);
+ marker= select->cur_pos_in_select_list;
}
mark_non_agg_field:
/*
@@ -6283,7 +6288,7 @@ mark_non_agg_field:
if (outer_fixed)
thd->lex->in_sum_func->outer_fields.push_back(this, thd->mem_root);
else if (thd->lex->in_sum_func->nest_level !=
- thd->lex->current_select->nest_level)
+ select->nest_level)
select_lex->set_non_agg_field_used(true);
}
}
@@ -7696,26 +7701,6 @@ void Item_field::print(String *str, enum_query_type query_type)
}
-bool Item_field_row::element_index_by_name(uint *idx,
- const LEX_CSTRING &name) const
-{
- Field *field;
- for (uint i= 0; (field= get_row_field(i)); i++)
- {
- // Use the same comparison style with sp_context::find_variable()
- if (!my_strnncoll(system_charset_info,
- (const uchar *) field->field_name.str,
- field->field_name.length,
- (const uchar *) name.str, name.length))
- {
- *idx= i;
- return false;
- }
- }
- return true;
-}
-
-
void Item_temptable_field::print(String *str, enum_query_type query_type)
{
/*
@@ -9562,7 +9547,7 @@ void Item_trigger_field::set_required_privilege(bool rw)
bool Item_trigger_field::set_value(THD *thd, sp_rcontext * /*ctx*/, Item **it)
{
- Item *item= sp_prepare_func_item(thd, it);
+ Item *item= thd->sp_prepare_func_item(it);
if (!item)
return true;
diff --git a/sql/item.h b/sql/item.h
index d178d9f97d6..82dfa3f8930 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -1733,10 +1733,6 @@ public:
// Row emulation
virtual uint cols() const { return 1; }
virtual Item* element_index(uint i) { return this; }
- virtual bool element_index_by_name(uint *idx, const LEX_CSTRING &name) const
- {
- return true; // Error
- }
virtual Item** addr(uint i) { return 0; }
virtual bool check_cols(uint c);
bool check_type_traditional_scalar(const char *opname) const;
@@ -2980,7 +2976,6 @@ public:
const Type_handler *type_handler() const { return &type_handler_row; }
uint cols() const { return arg_count; }
- bool element_index_by_name(uint *idx, const LEX_CSTRING &name) const;
Item* element_index(uint i) { return arg_count ? args[i] : this; }
Item** addr(uint i) { return arg_count ? args + i : NULL; }
bool check_cols(uint c)
@@ -2993,7 +2988,6 @@ public:
return false;
}
bool row_create_items(THD *thd, List<Spvar_definition> *list);
- Field *get_row_field(uint i) const;
};
diff --git a/sql/log_event.cc b/sql/log_event.cc
index c40e3be94c8..b959b804dea 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -1733,6 +1733,8 @@ bool Log_event::write_header(ulong event_data_length)
*/
log_pos= writer->pos() + data_written;
+
+ DBUG_EXECUTE_IF("dbug_master_binlog_over_2GB", log_pos += (1ULL <<31););
}
now= get_time(); // Query start time
@@ -12313,7 +12315,8 @@ int Table_map_log_event::rewrite_db(const char* new_db, size_t new_len,
cnt += header_len;
// Write new db name length and new name
- *ptr++ = new_len;
+ DBUG_ASSERT(new_len < 0xff);
+ *ptr++ = (char)new_len;
memcpy(ptr, new_db, new_len + 1);
ptr += new_len + 1;
cnt += m_dblen + 2;
diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc
index 9d6b67e845e..de8fb0fd8b5 100644
--- a/sql/opt_subselect.cc
+++ b/sql/opt_subselect.cc
@@ -2662,8 +2662,8 @@ void advance_sj_state(JOIN *join, table_map remaining_tables, uint idx,
LooseScan detector in best_access_path)
*/
remaining_tables &= ~new_join_tab->table->map;
- table_map dups_producing_tables, prev_dups_producing_tables,
- prev_sjm_lookup_tables;
+ table_map dups_producing_tables, UNINIT_VAR(prev_dups_producing_tables),
+ UNINIT_VAR(prev_sjm_lookup_tables);
if (idx == join->const_tables)
dups_producing_tables= 0;
@@ -2674,7 +2674,7 @@ void advance_sj_state(JOIN *join, table_map remaining_tables, uint idx,
if ((emb_sj_nest= new_join_tab->emb_sj_nest))
dups_producing_tables |= emb_sj_nest->sj_inner_tables;
- Semi_join_strategy_picker **strategy, **prev_strategy;
+ Semi_join_strategy_picker **strategy, **prev_strategy= 0;
if (idx == join->const_tables)
{
/* First table, initialize pickers */
diff --git a/sql/rpl_parallel.cc b/sql/rpl_parallel.cc
index 9ebd19a90e2..dd8d71dd49b 100644
--- a/sql/rpl_parallel.cc
+++ b/sql/rpl_parallel.cc
@@ -1622,10 +1622,19 @@ int rpl_parallel_resize_pool_if_no_slaves(void)
}
+/**
+ Resize pool if not active or busy (in which case we may be in
+ resize to 0
+*/
+
int
rpl_parallel_activate_pool(rpl_parallel_thread_pool *pool)
{
- if (!pool->count)
+ bool resize;
+ mysql_mutex_lock(&pool->LOCK_rpl_thread_pool);
+ resize= !pool->count || pool->busy;
+ mysql_mutex_unlock(&pool->LOCK_rpl_thread_pool);
+ if (resize)
return rpl_parallel_change_thread_count(pool, opt_slave_parallel_threads,
0);
return 0;
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index e86a35f4b27..b30d0954cb2 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -27,6 +27,7 @@
#include "sql_array.h" // Dynamic_array
#include "log_event.h" // Query_log_event
#include "sql_derived.h" // mysql_handle_derived
+#include "sql_select.h" // Virtual_tmp_table
#ifdef USE_PRAGMA_IMPLEMENTATION
#pragma implementation
@@ -337,8 +338,8 @@ sp_get_flags_for_command(LEX *lex)
/**
Prepare an Item for evaluation (call of fix_fields).
- @param thd thread handler
@param it_addr pointer on item refernce
+ @param cols expected number of elements (1 for scalar, >=1 for ROWs)
@retval
NULL error
@@ -346,21 +347,32 @@ sp_get_flags_for_command(LEX *lex)
non-NULL prepared item
*/
-Item *
-sp_prepare_func_item(THD* thd, Item **it_addr, uint cols)
+Item *THD::sp_prepare_func_item(Item **it_addr, uint cols)
{
- DBUG_ENTER("sp_prepare_func_item");
+ DBUG_ENTER("THD::sp_prepare_func_item");
+ Item *res= sp_fix_func_item(it_addr);
+ if (res && res->check_cols(cols))
+ DBUG_RETURN(NULL);
+ DBUG_RETURN(res);
+}
+
+
+/**
+ Fix an Item for evaluation for SP.
+*/
+Item *THD::sp_fix_func_item(Item **it_addr)
+{
+ DBUG_ENTER("THD::sp_fix_func_item");
if (!(*it_addr)->fixed &&
- (*it_addr)->fix_fields(thd, it_addr))
+ (*it_addr)->fix_fields(this, it_addr))
{
DBUG_PRINT("info", ("fix_fields() failed"));
DBUG_RETURN(NULL);
}
- it_addr= (*it_addr)->this_item_addr(thd, it_addr);
+ it_addr= (*it_addr)->this_item_addr(this, it_addr);
- if ((!(*it_addr)->fixed &&
- (*it_addr)->fix_fields(thd, it_addr)) ||
- (*it_addr)->check_cols(cols))
+ if (!(*it_addr)->fixed &&
+ (*it_addr)->fix_fields(this, it_addr))
{
DBUG_PRINT("info", ("fix_fields() failed"));
DBUG_RETURN(NULL);
@@ -372,7 +384,6 @@ sp_prepare_func_item(THD* thd, Item **it_addr, uint cols)
/**
Evaluate an expression and store the result in the field.
- @param thd current thread object
@param result_field the field to store the result
@param expr_item_ptr the root item of the expression
@@ -382,67 +393,13 @@ sp_prepare_func_item(THD* thd, Item **it_addr, uint cols)
TRUE on error
*/
-bool
-sp_eval_expr(THD *thd, Item *result_item, Field *result_field,
- Item **expr_item_ptr)
+bool THD::sp_eval_expr(Field *result_field, Item **expr_item_ptr)
{
- Item *expr_item;
- enum_check_fields save_count_cuted_fields= thd->count_cuted_fields;
- bool save_abort_on_warning= thd->abort_on_warning;
- bool save_stmt_modified_non_trans_table=
- thd->transaction.stmt.modified_non_trans_table;
-
- DBUG_ENTER("sp_eval_expr");
-
- if (!*expr_item_ptr)
- goto error;
-
- if (!(expr_item= sp_prepare_func_item(thd, expr_item_ptr,
- result_item ? result_item->cols() : 1)))
- goto error;
-
- /*
- expr_item is now fixed, it's safe to call cmp_type()
- If result_item is NULL, then we're setting the RETURN value.
- */
- if ((!result_item || result_item->cmp_type() != ROW_RESULT) &&
- expr_item->cmp_type() == ROW_RESULT)
- {
- my_error(ER_OPERAND_COLUMNS, MYF(0), 1);
- goto error;
- }
-
- /*
- Set THD flags to emit warnings/errors in case of overflow/type errors
- during saving the item into the field.
-
- Save original values and restore them after save.
- */
-
- thd->count_cuted_fields= CHECK_FIELD_ERROR_FOR_NULL;
- thd->abort_on_warning= thd->is_strict_mode();
- thd->transaction.stmt.modified_non_trans_table= FALSE;
-
+ DBUG_ENTER("THD::sp_eval_expr");
+ DBUG_ASSERT(*expr_item_ptr);
+ Sp_eval_expr_state state(this);
/* Save the value in the field. Convert the value if needed. */
-
- expr_item->save_in_field(result_field, 0);
-
- thd->count_cuted_fields= save_count_cuted_fields;
- thd->abort_on_warning= save_abort_on_warning;
- thd->transaction.stmt.modified_non_trans_table= save_stmt_modified_non_trans_table;
-
- if (!thd->is_error())
- DBUG_RETURN(FALSE);
-
-error:
- /*
- In case of error during evaluation, leave the result field set to NULL.
- Sic: we can't do it in the beginning of the function because the
- result field might be needed for its own re-evaluation, e.g. case of
- set x = x + 1;
- */
- result_field->set_null();
- DBUG_RETURN (TRUE);
+ DBUG_RETURN(result_field->sp_prepare_and_store_item(this, expr_item_ptr));
}
@@ -3428,19 +3385,7 @@ int
sp_instr_set::exec_core(THD *thd, uint *nextp)
{
int res= thd->spcont->set_variable(thd, m_offset, &m_value);
-
- if (res)
- {
- /* Failed to evaluate the value. Reset the variable to NULL. */
-
- if (thd->spcont->set_variable(thd, m_offset, 0))
- {
- /* If this also failed, let's abort. */
- my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR));
- }
- }
delete_explain_query(thd->lex);
-
*nextp = m_ip+1;
return res;
}
@@ -3479,11 +3424,6 @@ sp_instr_set_row_field::exec_core(THD *thd, uint *nextp)
{
int res= thd->spcont->set_variable_row_field(thd, m_offset, m_field_offset,
&m_value);
- if (res)
- {
- /* Failed to evaluate the value. Reset the variable to NULL. */
- thd->spcont->set_variable_row_field_to_null(thd, m_offset, m_field_offset);
- }
delete_explain_query(thd->lex);
*nextp= m_ip + 1;
return res;
@@ -3527,23 +3467,9 @@ sp_instr_set_row_field::print(String *str)
int
sp_instr_set_row_field_by_name::exec_core(THD *thd, uint *nextp)
{
- int res;
- uint idx;
- Item_field_row *row= (Item_field_row*) thd->spcont->get_item(m_offset);
- if ((res= row->element_index_by_name(&idx, m_field_name)))
- {
- sp_variable *var= m_ctx->find_variable(m_offset);
- my_error(ER_ROW_VARIABLE_DOES_NOT_HAVE_FIELD, MYF(0),
- var->name.str, m_field_name.str);
- goto error;
- }
- res= thd->spcont->set_variable_row_field(thd, m_offset, idx, &m_value);
- if (res)
- {
- /* Failed to evaluate the value. Reset the variable to NULL. */
- thd->spcont->set_variable_row_field_to_null(thd, m_offset, idx);
- }
-error:
+ int res= thd->spcont->set_variable_row_field_by_name(thd, m_offset,
+ m_field_name,
+ &m_value);
delete_explain_query(thd->lex);
*nextp= m_ip + 1;
return res;
@@ -3707,7 +3633,7 @@ sp_instr_jump_if_not::exec_core(THD *thd, uint *nextp)
Item *it;
int res;
- it= sp_prepare_func_item(thd, &m_expr);
+ it= thd->sp_prepare_func_item(&m_expr);
if (! it)
{
res= -1;
diff --git a/sql/sp_head.h b/sql/sp_head.h
index 04b67941226..539ccf823d1 100644
--- a/sql/sp_head.h
+++ b/sql/sp_head.h
@@ -1944,13 +1944,6 @@ sp_add_to_query_tables(THD *thd, LEX *lex,
thr_lock_type locktype,
enum_mdl_type mdl_type);
-Item *
-sp_prepare_func_item(THD* thd, Item **it_addr, uint cols= 1);
-
-bool
-sp_eval_expr(THD *thd, Item *result_item, Field *result_field,
- Item **expr_item_ptr);
-
/**
@} (end of group Stored_Routines)
*/
diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc
index 3a2348b8cc5..825141d4a5b 100644
--- a/sql/sp_rcontext.cc
+++ b/sql/sp_rcontext.cc
@@ -387,22 +387,13 @@ bool Item_field_row::row_create_items(THD *thd, List<Spvar_definition> *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);
}
@@ -611,84 +602,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));
}
@@ -696,15 +634,32 @@ int sp_rcontext::set_variable_row(THD *thd, uint var_idx, List<Item> &items)
{
DBUG_ENTER("sp_rcontext::set_variable_row");
DBUG_ASSERT(get_item(var_idx)->cols() == items.elements);
- List_iterator<Item> 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);
}
@@ -727,7 +682,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;
diff --git a/sql/sp_rcontext.h b/sql/sp_rcontext.h
index 0999271ebde..ab1238c5f25 100644
--- a/sql/sp_rcontext.h
+++ b/sql/sp_rcontext.h
@@ -192,9 +192,11 @@ public:
/////////////////////////////////////////////////////////////////////////
int set_variable(THD *thd, uint var_idx, Item **value);
- void set_variable_row_field_to_null(THD *thd, uint var_idx, uint field_idx);
int set_variable_row_field(THD *thd, uint var_idx, uint field_idx,
Item **value);
+ int set_variable_row_field_by_name(THD *thd, uint var_idx,
+ const LEX_CSTRING &field_name,
+ Item **value);
int set_variable_row(THD *thd, uint var_idx, List<Item> &items);
Item *get_item(uint var_idx) const
{ return m_var_items[var_idx]; }
@@ -202,6 +204,9 @@ public:
Item **get_item_addr(uint var_idx) const
{ return m_var_items.array() + var_idx; }
+ bool find_row_field_by_name_or_error(uint *field_idx, uint var_idx,
+ const LEX_CSTRING &field_name);
+
bool set_return_value(THD *thd, Item **return_value_item);
bool is_return_value_set() const
@@ -365,6 +370,8 @@ private:
/// @return Pointer to valid object on success, or NULL in case of error.
Item_cache *create_case_expr_holder(THD *thd, const Item *item) const;
+ Virtual_tmp_table *virtual_tmp_table_for_row(uint idx);
+
private:
/// Top-level (root) parsing context for this runtime context.
const sp_pcontext *m_root_parsing_ctx;
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index d3edaa2b56a..3dd27622da8 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -3025,7 +3025,8 @@ exit:
(entry= (acl_entry*) malloc(sizeof(acl_entry)+key_length)))
{
entry->access=(db_access & host_access);
- entry->length=key_length;
+ DBUG_ASSERT(key_length < 0xffff);
+ entry->length=(uint16)key_length;
memcpy((uchar*) entry->key,key,key_length);
acl_cache->add(entry);
}
diff --git a/sql/sql_bootstrap.cc b/sql/sql_bootstrap.cc
index ce7d7a9fc93..9fb22c6b4d4 100644
--- a/sql/sql_bootstrap.cc
+++ b/sql/sql_bootstrap.cc
@@ -82,14 +82,14 @@ int read_bootstrap_query(char *query, int *query_length,
*/
if (query_len + len + 1 >= MAX_BOOTSTRAP_QUERY_SIZE)
{
- int new_len= MAX_BOOTSTRAP_QUERY_SIZE - query_len - 1;
+ size_t new_len= MAX_BOOTSTRAP_QUERY_SIZE - query_len - 1;
if ((new_len > 0) && (query_len < MAX_BOOTSTRAP_QUERY_SIZE))
{
memcpy(query + query_len, line, new_len);
query_len+= new_len;
}
query[query_len]= '\0';
- *query_length= query_len;
+ *query_length= (int)query_len;
return READ_BOOTSTRAP_QUERY_SIZE;
}
@@ -111,7 +111,7 @@ int read_bootstrap_query(char *query, int *query_length,
Return the query found.
*/
query[query_len]= '\0';
- *query_length= query_len;
+ *query_length= (int)query_len;
return READ_BOOTSTRAP_SUCCESS;
}
}
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 7bcb6a632d4..f081edaa67a 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -4707,6 +4707,10 @@ public:
*/
bool restore_from_local_lex_to_old_lex(LEX *oldlex);
+ Item *sp_fix_func_item(Item **it_addr);
+ Item *sp_prepare_func_item(Item **it_addr, uint cols= 1);
+ bool sp_eval_expr(Field *result_field, Item **expr_item_ptr);
+
inline void prepare_logs_for_admin_command()
{
enable_slow_log&= !MY_TEST(variables.log_slow_disabled_statements &
@@ -6412,6 +6416,48 @@ public:
};
+/*
+ A helper class to set THD flags to emit warnings/errors in case of
+ overflow/type errors during assigning values into the SP variable fields.
+ Saves original flags values in constructor.
+ Restores original flags in destructor.
+*/
+class Sp_eval_expr_state
+{
+ THD *m_thd;
+ enum_check_fields m_count_cuted_fields;
+ bool m_abort_on_warning;
+ bool m_stmt_modified_non_trans_table;
+ void start()
+ {
+ m_thd->count_cuted_fields= CHECK_FIELD_ERROR_FOR_NULL;
+ m_thd->abort_on_warning= m_thd->is_strict_mode();
+ m_thd->transaction.stmt.modified_non_trans_table= false;
+ }
+ void stop()
+ {
+ m_thd->count_cuted_fields= m_count_cuted_fields;
+ m_thd->abort_on_warning= m_abort_on_warning;
+ m_thd->transaction.stmt.modified_non_trans_table=
+ m_stmt_modified_non_trans_table;
+ }
+public:
+ Sp_eval_expr_state(THD *thd)
+ :m_thd(thd),
+ m_count_cuted_fields(thd->count_cuted_fields),
+ m_abort_on_warning(thd->abort_on_warning),
+ m_stmt_modified_non_trans_table(thd->transaction.stmt.
+ modified_non_trans_table)
+ {
+ start();
+ }
+ ~Sp_eval_expr_state()
+ {
+ stop();
+ }
+};
+
+
#ifndef DBUG_OFF
void dbug_serve_apcs(THD *thd, int n_calls);
#endif
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index b7e2430ffb0..3b9ceea9da5 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -2914,6 +2914,7 @@ static bool do_execute_sp(THD *thd, sp_head *sp)
result of previous parsing.
*/
thd->lex->current_select= NULL;
+ thd->lex->in_sum_func= 0; // For Item_field::fix_fields()
/*
We never write CALL statements into binlog:
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index 7db9f49f25e..e4a39401b04 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -1933,11 +1933,8 @@ send_event_to_slave(binlog_send_info *info, Log_event_type event_type,
*/
if (info->thd->variables.option_bits & OPTION_SKIP_REPLICATION)
{
- /*
- The first byte of the packet is a '\0' to distinguish it from an error
- packet. So the actual event starts at offset +1.
- */
- uint16 event_flags= uint2korr(&((*packet)[FLAGS_OFFSET+1]));
+ uint16 event_flags= uint2korr(&((*packet)[FLAGS_OFFSET + ev_offset]));
+
if (event_flags & LOG_EVENT_SKIP_REPLICATION_F)
return NULL;
}
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index d2fd2ce9bb6..db8d1c66419 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -3395,6 +3395,7 @@ JOIN::create_postjoin_aggr_table(JOIN_TAB *tab, List<Item> *table_fields,
THD_STAGE_INFO(thd, stage_sorting_for_group);
if (ordered_index_usage != ordered_index_group_by &&
+ !only_const_tables() &&
(join_tab + const_tables)->type != JT_CONST && // Don't sort 1 row
!implicit_grouping &&
add_sorting_to_table(join_tab + const_tables, group_list))
@@ -3428,6 +3429,7 @@ JOIN::create_postjoin_aggr_table(JOIN_TAB *tab, List<Item> *table_fields,
THD_STAGE_INFO(thd, stage_sorting_for_order);
if (ordered_index_usage != ordered_index_order_by &&
+ !only_const_tables() &&
add_sorting_to_table(join_tab + const_tables, order))
goto err;
order= NULL;
@@ -17995,6 +17997,70 @@ bool Virtual_tmp_table::open()
}
+bool Virtual_tmp_table::sp_find_field_by_name(uint *idx,
+ const LEX_CSTRING &name) const
+{
+ Field *f;
+ for (uint i= 0; (f= field[i]); i++)
+ {
+ // Use the same comparison style with sp_context::find_variable()
+ if (!my_strnncoll(system_charset_info,
+ (const uchar *) f->field_name.str,
+ f->field_name.length,
+ (const uchar *) name.str, name.length))
+ {
+ *idx= i;
+ return false;
+ }
+ }
+ return true;
+}
+
+
+bool
+Virtual_tmp_table::sp_find_field_by_name_or_error(uint *idx,
+ const LEX_CSTRING &var_name,
+ const LEX_CSTRING &field_name)
+ const
+{
+ if (sp_find_field_by_name(idx, field_name))
+ {
+ my_error(ER_ROW_VARIABLE_DOES_NOT_HAVE_FIELD, MYF(0),
+ var_name.str, field_name.str);
+ return true;
+ }
+ return false;
+}
+
+
+bool Virtual_tmp_table::sp_set_all_fields_from_item_list(THD *thd,
+ List<Item> &items)
+{
+ DBUG_ASSERT(s->fields == items.elements);
+ List_iterator<Item> it(items);
+ Item *item;
+ for (uint i= 0 ; (item= it++) ; i++)
+ {
+ if (field[i]->sp_prepare_and_store_item(thd, &item))
+ return true;
+ }
+ return false;
+}
+
+
+bool Virtual_tmp_table::sp_set_all_fields_from_item(THD *thd, Item *value)
+{
+ DBUG_ASSERT(value->fixed);
+ DBUG_ASSERT(value->cols() == s->fields);
+ for (uint i= 0; i < value->cols(); i++)
+ {
+ if (field[i]->sp_prepare_and_store_item(thd, value->addr(i)))
+ return true;
+ }
+ return false;
+}
+
+
bool open_tmp_table(TABLE *table)
{
int error;
diff --git a/sql/sql_select.h b/sql/sql_select.h
index 298097f1b98..0ae6d20a6e6 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -2184,6 +2184,48 @@ public:
@return true - on error (e.g. could not allocate the record buffer).
*/
bool open();
+
+ void set_all_fields_to_null()
+ {
+ for (uint i= 0; i < s->fields; i++)
+ field[i]->set_null();
+ }
+ /**
+ Set all fields from a compatible item list.
+ The number of fields in "this" must be equal to the number
+ of elements in "value".
+ */
+ bool sp_set_all_fields_from_item_list(THD *thd, List<Item> &items);
+
+ /**
+ Set all fields from a compatible item.
+ The number of fields in "this" must be the same with the number
+ of elements in "value".
+ */
+ bool sp_set_all_fields_from_item(THD *thd, Item *value);
+
+ /**
+ Find a ROW element index by its name
+ Assumes that "this" is used as a storage for a ROW-type SP variable.
+ @param [OUT] idx - the index of the found field is returned here
+ @param [IN] field_name - find a field with this name
+ @return true - on error (the field was not found)
+ @return false - on success (idx[0] was set to the field index)
+ */
+ bool sp_find_field_by_name(uint *idx, const LEX_CSTRING &name) const;
+
+ /**
+ Find a ROW element index by its name.
+ If the element is not found, and error is issued.
+ @param [OUT] idx - the index of the found field is returned here
+ @param [IN] var_name - the name of the ROW variable (for error reporting)
+ @param [IN] field_name - find a field with this name
+ @return true - on error (the field was not found)
+ @return false - on success (idx[0] was set to the field index)
+ */
+ bool sp_find_field_by_name_or_error(uint *idx,
+ const LEX_CSTRING &var_name,
+ const LEX_CSTRING &field_name) const;
};
diff --git a/sql/table.cc b/sql/table.cc
index e6b6ea63e0e..10d1d737222 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -1174,7 +1174,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
char *keynames, *names, *comment_pos;
const uchar *forminfo, *extra2;
const uchar *frm_image_end = frm_image + frm_length;
- uchar *record, *null_flags, *null_pos, *mysql57_vcol_null_pos= 0;
+ uchar *record, *null_flags, *null_pos, *UNINIT_VAR(mysql57_vcol_null_pos);
const uchar *disk_buff, *strpos;
ulong pos, record_offset;
ulong rec_buff_length;
@@ -2520,7 +2520,10 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
reg_field= share->field[field_nr];
}
else
- reg_field= 0; // Safety
+ {
+ reg_field= 0;
+ DBUG_ASSERT(name_length);
+ }
vcol_screen_pos+= FRM_VCOL_NEW_HEADER_SIZE;
vcol_info->set_vcol_type((enum_vcol_info_type) type);