summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorSeppo Jaakola <seppo.jaakola@codership.com>2012-08-09 01:47:21 +0300
committerSeppo Jaakola <seppo.jaakola@codership.com>2012-08-09 01:47:21 +0300
commitebfa24b1d24377a241b79883da96969a9150f22c (patch)
treeef1198f9dfb1838cbdbc5056f2b84e399b446bfd /sql
parent1fd2e10736d6fd198e62054cb9006a3dc13fd55e (diff)
parenta7123f507598690ef0fce68b5d8dc58e63635024 (diff)
downloadmariadb-git-ebfa24b1d24377a241b79883da96969a9150f22c.tar.gz
References lp:1034621 - Merge up to mysql-5.5.25 level
merged codership-mysql/5.5 revisions: bzr diff -r3759..3767 merged codership-mysql/5.5 revisions: bzr diff -r3768..3771
Diffstat (limited to 'sql')
-rw-r--r--sql/field.cc4
-rw-r--r--sql/field.h11
-rw-r--r--sql/field_conv.cc4
-rw-r--r--sql/ha_partition.cc127
-rw-r--r--sql/ha_partition.h26
-rw-r--r--sql/handler.cc5
-rw-r--r--sql/handler.h42
-rw-r--r--sql/item.cc2
-rw-r--r--sql/item.h12
-rw-r--r--sql/item_cmpfunc.cc70
-rw-r--r--sql/item_cmpfunc.h7
-rw-r--r--sql/item_func.cc1
-rw-r--r--sql/item_func.h6
-rw-r--r--sql/item_row.cc1
-rw-r--r--sql/item_strfunc.h26
-rw-r--r--sql/item_subselect.cc84
-rw-r--r--sql/item_subselect.h12
-rw-r--r--sql/item_sum.cc3
-rw-r--r--sql/log.cc60
-rw-r--r--sql/log.h11
-rw-r--r--sql/log_event.cc39
-rw-r--r--sql/log_event.h8
-rw-r--r--sql/log_event_old.cc2
-rw-r--r--sql/mysql_install_db.cc6
-rw-r--r--sql/mysqld.cc63
-rw-r--r--sql/opt_range.cc17
-rw-r--r--sql/opt_range.h2
-rw-r--r--sql/opt_subselect.cc47
-rw-r--r--sql/password.c1
-rw-r--r--sql/rpl_rli.cc4
-rw-r--r--sql/rpl_rli.h35
-rw-r--r--sql/rpl_utility.cc67
-rw-r--r--sql/rpl_utility.h20
-rw-r--r--sql/share/errmsg-utf8.txt3
-rw-r--r--sql/signal_handler.cc17
-rw-r--r--sql/slave.cc9
-rw-r--r--sql/spatial.cc4
-rw-r--r--sql/spatial.h2
-rw-r--r--sql/sql_base.cc33
-rw-r--r--sql/sql_cache.cc94
-rw-r--r--sql/sql_cache.h31
-rw-r--r--sql/sql_class.cc20
-rw-r--r--sql/sql_class.h21
-rw-r--r--sql/sql_delete.cc2
-rw-r--r--sql/sql_insert.cc4
-rw-r--r--sql/sql_lex.cc92
-rw-r--r--sql/sql_lex.h14
-rw-r--r--sql/sql_parse.cc47
-rw-r--r--sql/sql_profile.h2
-rw-r--r--sql/sql_repl.cc5
-rw-r--r--sql/sql_select.cc195
-rw-r--r--sql/sql_select.h3
-rw-r--r--sql/sql_show.cc2
-rw-r--r--sql/sql_table.cc108
-rw-r--r--sql/sql_update.cc2
-rw-r--r--sql/sql_yacc.yy4
-rw-r--r--sql/sys_vars.cc25
-rw-r--r--sql/table.cc37
-rw-r--r--sql/table.h2
-rw-r--r--sql/unireg.cc23
-rw-r--r--sql/unireg.h6
-rw-r--r--sql/wsrep_hton.cc2
-rw-r--r--sql/wsrep_mysqld.cc46
-rw-r--r--sql/wsrep_mysqld.h8
-rw-r--r--sql/wsrep_priv.h8
-rw-r--r--sql/wsrep_sst.cc16
-rw-r--r--sql/wsrep_utils.cc3
-rw-r--r--sql/wsrep_var.cc22
68 files changed, 1390 insertions, 347 deletions
diff --git a/sql/field.cc b/sql/field.cc
index 6e1851d89d1..2084c661602 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -1,6 +1,6 @@
/*
- Copyright (c) 2000, 2011, Oracle and/or its affiliates.
- Copyright (c) 2008-2011 Monty Program Ab
+ Copyright (c) 2000, 2012, Oracle and/or its affiliates.
+ Copyright (c) 2008, 2011, Monty Program Ab
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/sql/field.h b/sql/field.h
index c86c0975117..f22bab0409d 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -1,7 +1,7 @@
#ifndef FIELD_INCLUDED
#define FIELD_INCLUDED
-/* Copyright (c) 2000, 2011 Oracle and/or its affiliates.
- Copyright (c) 2008-2011 Monty Program Ab
+/* Copyright (c) 2000, 2012, Oracle and/or its affiliates.
+ Copyright (c) 2008, 2011, Monty Program Ab
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -63,6 +63,9 @@ enum Derivation
#define my_charset_numeric my_charset_latin1
#define MY_REPERTOIRE_NUMERIC MY_REPERTOIRE_ASCII
+/* The length of the header part for each virtual column in the .frm file */
+#define FRM_VCOL_HEADER_SIZE(b) (3 + test(b))
+
struct ha_field_option_struct;
struct st_cache_field;
@@ -2244,6 +2247,10 @@ public:
{
return (flags & (BINCMP_FLAG | BINARY_FLAG)) != 0;
}
+ uint virtual_col_expr_maxlen()
+ {
+ return 255 - FRM_VCOL_HEADER_SIZE(interval != NULL);
+ }
private:
const String empty_set_string;
};
diff --git a/sql/field_conv.cc b/sql/field_conv.cc
index 20da18a129c..6685b334d06 100644
--- a/sql/field_conv.cc
+++ b/sql/field_conv.cc
@@ -1,5 +1,7 @@
/*
- Copyright (c) 2000, 2011, Oracle and/or its affiliates.
+ Copyright (c) 2000, 2012, Oracle and/or its affiliates.
+ Copyright (c) 2010, 2012, Monty Program Ab
+
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc
index b4181fc6d7f..78adbeff623 100644
--- a/sql/ha_partition.cc
+++ b/sql/ha_partition.cc
@@ -2076,6 +2076,133 @@ partition_element *ha_partition::find_partition_element(uint part_id)
return NULL;
}
+uint ha_partition::count_query_cache_dependant_tables(uint8 *tables_type)
+{
+ DBUG_ENTER("ha_partition::count_query_cache_dependant_tables");
+ /* Here we rely on the fact that all tables are of the same type */
+ uint8 type= m_file[0]->table_cache_type();
+ (*tables_type)|= type;
+ DBUG_PRINT("info", ("cnt: %u", (uint)m_tot_parts));
+ /*
+ We need save underlying tables only for HA_CACHE_TBL_ASKTRANSACT:
+ HA_CACHE_TBL_NONTRANSACT - because all changes goes through partition table
+ HA_CACHE_TBL_NOCACHE - because will not be cached
+ HA_CACHE_TBL_TRANSACT - QC need to know that such type present
+ */
+ DBUG_RETURN(type == HA_CACHE_TBL_ASKTRANSACT ? m_tot_parts : 0);
+}
+
+my_bool ha_partition::reg_query_cache_dependant_table(THD *thd,
+ char *key, uint key_len,
+ uint8 type,
+ Query_cache *cache,
+ Query_cache_block_table **block_table,
+ handler *file,
+ uint *n)
+{
+ DBUG_ENTER("ha_partition::reg_query_cache_dependant_table");
+ qc_engine_callback engine_callback;
+ ulonglong engine_data;
+ /* ask undelying engine */
+ if (!file->register_query_cache_table(thd, key,
+ key_len,
+ &engine_callback,
+ &engine_data))
+ {
+ DBUG_PRINT("qcache", ("Handler does not allow caching for %s.%s",
+ key,
+ key + table_share->db.length + 1));
+ /*
+ As this can change from call to call, don't reset set
+ thd->lex->safe_to_cache_query
+ */
+ thd->query_cache_is_applicable= 0; // Query can't be cached
+ DBUG_RETURN(TRUE);
+ }
+ (++(*block_table))->n= ++(*n);
+ if (!cache->insert_table(key_len,
+ key, (*block_table),
+ table_share->db.length,
+ type,
+ engine_callback, engine_data,
+ FALSE))
+ DBUG_RETURN(TRUE);
+ DBUG_RETURN(FALSE);
+}
+
+
+my_bool ha_partition::register_query_cache_dependant_tables(THD *thd,
+ Query_cache *cache,
+ Query_cache_block_table **block_table,
+ uint *n)
+{
+ char *name;
+ uint prefix_length= table_share->table_cache_key.length + 3;
+ uint num_parts= m_part_info->num_parts;
+ uint num_subparts= m_part_info->num_subparts;
+ uint i= 0;
+ List_iterator<partition_element> part_it(m_part_info->partitions);
+ char key[FN_REFLEN];
+
+ DBUG_ENTER("ha_partition::register_query_cache_dependant_tables");
+
+ /* see ha_partition::count_query_cache_dependant_tables */
+ if (m_file[0]->table_cache_type() != HA_CACHE_TBL_ASKTRANSACT)
+ DBUG_RETURN(FALSE); // nothing to register
+
+ /* prepare static part of the key */
+ memmove(key, table_share->table_cache_key.str,
+ table_share->table_cache_key.length);
+
+ name= key + table_share->table_cache_key.length - 1;
+ name[0]= name[2]= '#';
+ name[1]= 'P';
+ name+= 3;
+
+ do
+ {
+ partition_element *part_elem= part_it++;
+ uint part_len= strmov(name, part_elem->partition_name) - name;
+ if (m_is_sub_partitioned)
+ {
+ List_iterator<partition_element> subpart_it(part_elem->subpartitions);
+ partition_element *sub_elem;
+ char *sname= name + part_len;
+ uint j= 0, part;
+ sname[0]= sname[3]= '#';
+ sname[1]= 'S';
+ sname[2]= 'P';
+ sname += 4;
+ do
+ {
+ sub_elem= subpart_it++;
+ part= i * num_subparts + j;
+ uint spart_len= strmov(sname, sub_elem->partition_name) - name + 1;
+ if (reg_query_cache_dependant_table(thd, key,
+ prefix_length + part_len + 4 +
+ spart_len,
+ m_file[part]->table_cache_type(),
+ cache,
+ block_table, m_file[part],
+ n))
+ DBUG_RETURN(TRUE);
+ } while (++j < num_subparts);
+ }
+ else
+ {
+ if (reg_query_cache_dependant_table(thd, key,
+ prefix_length + part_len + 1,
+ m_file[i]->table_cache_type(),
+ cache,
+ block_table, m_file[i],
+ n))
+ DBUG_RETURN(TRUE);
+ }
+ } while (++i < num_parts);
+ DBUG_PRINT("info", ("cnt: %u", (uint)m_tot_parts));
+ DBUG_RETURN(FALSE);
+}
+
/*
Set up table share object before calling create on underlying handler
diff --git a/sql/ha_partition.h b/sql/ha_partition.h
index aa9179f9f69..0f922394ec5 100644
--- a/sql/ha_partition.h
+++ b/sql/ha_partition.h
@@ -544,22 +544,20 @@ public:
virtual int extra(enum ha_extra_function operation);
virtual int extra_opt(enum ha_extra_function operation, ulong cachesize);
virtual int reset(void);
- /*
- Do not allow caching of partitioned tables, since we cannot return
- a callback or engine_data that would work for a generic engine.
- */
- virtual my_bool register_query_cache_table(THD *thd, char *table_key,
- uint key_length,
- qc_engine_callback
- *engine_callback,
- ulonglong *engine_data)
- {
- *engine_callback= NULL;
- *engine_data= 0;
- return FALSE;
- }
+ virtual uint count_query_cache_dependant_tables(uint8 *tables_type);
+ virtual my_bool
+ register_query_cache_dependant_tables(THD *thd,
+ Query_cache *cache,
+ Query_cache_block_table **block,
+ uint *n);
private:
+ my_bool reg_query_cache_dependant_table(THD *thd,
+ char *key, uint key_len, uint8 type,
+ Query_cache *cache,
+ Query_cache_block_table
+ **block_table,
+ handler *file, uint *n);
static const uint NO_CURRENT_PART_ID;
int loop_extra(enum ha_extra_function operation);
void late_extra_cache(uint partition_id);
diff --git a/sql/handler.cc b/sql/handler.cc
index 8b3573eb23e..cb220783e33 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -507,10 +507,6 @@ int ha_initialize_handlerton(st_plugin_int *plugin)
"Assigning value %d.", plugin->plugin->name, idx);
hton->db_type= (enum legacy_db_type) idx;
}
- installed_htons[hton->db_type]= hton;
- tmp= hton->savepoint_offset;
- hton->savepoint_offset= savepoint_alloc_size;
- savepoint_alloc_size+= tmp;
/*
In case a plugin is uninstalled and re-installed later, it should
@@ -1301,6 +1297,7 @@ int ha_commit_trans(THD *thd, bool all)
need_prepare_ordered|= (ht->prepare_ordered != NULL);
need_commit_ordered|= (ht->commit_ordered != NULL);
}
+ DEBUG_SYNC(thd, "ha_commit_trans_after_prepare");
DBUG_EXECUTE_IF("crash_commit_after_prepare", DBUG_SUICIDE(););
#ifdef WITH_WSREP
diff --git a/sql/handler.h b/sql/handler.h
index a2277f8df90..47593845ad6 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -1694,6 +1694,8 @@ public:
virtual ~handler_add_index() {}
};
+class Query_cache;
+struct Query_cache_block_table;
/**
The handler class is the interface for dynamically loadable
storage engines. Do not add ifdefs and take care when adding or
@@ -2527,6 +2529,46 @@ public:
return TRUE;
}
+ /*
+ Count tables invisible from all tables list on which current one built
+ (like myisammrg and partitioned tables)
+
+ tables_type mask for the tables should be added herdde
+
+ returns number of such tables
+ */
+
+ virtual uint count_query_cache_dependant_tables(uint8 *tables_type
+ __attribute__((unused)))
+ {
+ return 0;
+ }
+
+ /*
+ register tables invisible from all tables list on which current one built
+ (like myisammrg and partitioned tables).
+
+ @note they should be counted by method above
+
+ cache Query cache pointer
+ block Query cache block to write the table
+ n Number of the table
+
+ @retval FALSE - OK
+ @retval TRUE - Error
+ */
+
+ virtual my_bool
+ register_query_cache_dependant_tables(THD *thd
+ __attribute__((unused)),
+ Query_cache *cache
+ __attribute__((unused)),
+ Query_cache_block_table **block
+ __attribute__((unused)),
+ uint *n __attribute__((unused)))
+ {
+ return FALSE;
+ }
/*
Check if the primary key (if there is one) is a clustered and a
diff --git a/sql/item.cc b/sql/item.cc
index 3af415fe5c2..3031e90c9b2 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -1265,7 +1265,7 @@ err:
bool Item::get_seconds(ulonglong *sec, ulong *sec_part)
{
- if (result_type() == INT_RESULT)
+ if (decimals == 0)
{ // optimize for an important special case
longlong val= val_int();
bool neg= val < 0 && !unsigned_flag;
diff --git a/sql/item.h b/sql/item.h
index a9c1153d236..f7f3edda384 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -1395,21 +1395,21 @@ public:
{
return cmp_context == IMPOSSIBLE_RESULT || item->cmp_context == cmp_context;
}
- /*
+ /**
Test whether an expression is expensive to compute. Used during
optimization to avoid computing expensive expressions during this
phase. Also used to force temp tables when sorting on expensive
functions.
- TODO:
+ @todo
Normally we should have a method:
cost Item::execution_cost(),
where 'cost' is either 'double' or some structure of various cost
parameters.
- NOTE
- This function is now used to prevent evaluation of materialized IN
- subquery predicates before it is allowed. grep for
- DontEvaluateMaterializedSubqueryTooEarly to see the uses.
+ @note
+ This function is now used to prevent evaluation of expensive subquery
+ predicates during the optimization phase. It also prevents evaluation
+ of predicates that are not computable at this moment.
*/
virtual bool is_expensive()
{
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 5f1a863d8fd..2a0ca19a4e9 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -1504,6 +1504,7 @@ bool Item_in_optimizer::fix_fields(THD *thd, Item **ref)
}
if (args[1]->maybe_null)
maybe_null=1;
+ with_subselect= 1;
with_sum_func= with_sum_func || args[1]->with_sum_func;
with_field= with_field || args[1]->with_field;
used_tables_cache|= args[1]->used_tables();
@@ -3032,6 +3033,11 @@ void Item_func_case::fix_length_and_dec()
nagg++;
if (!(found_types= collect_cmp_types(agg, nagg)))
return;
+
+ Item *date_arg= 0;
+ if (found_types & (1 << TIME_RESULT))
+ date_arg= find_date_time_item(args, arg_count, 0);
+
if (found_types & (1 << STRING_RESULT))
{
/*
@@ -3071,16 +3077,12 @@ void Item_func_case::fix_length_and_dec()
change_item_tree_if_needed(thd, &args[nagg * 2], agg[nagg + 1]);
}
- Item *date_arg= 0;
for (i= 0; i <= (uint)TIME_RESULT; i++)
{
if (found_types & (1 << i) && !cmp_items[i])
{
DBUG_ASSERT((Item_result)i != ROW_RESULT);
- if ((Item_result)i == TIME_RESULT)
- date_arg= find_date_time_item(args, arg_count, 0);
-
if (!(cmp_items[i]=
cmp_item::get_comparator((Item_result)i, date_arg,
cmp_collation.collation)))
@@ -4051,15 +4053,15 @@ void Item_func_in::fix_length_and_dec()
}
else
{
+ if (found_types & (1 << TIME_RESULT))
+ date_arg= find_date_time_item(args, arg_count, 0);
+ if (found_types & (1 << STRING_RESULT) &&
+ agg_arg_charsets_for_comparison(cmp_collation, args, arg_count))
+ return;
for (i= 0; i <= (uint) TIME_RESULT; i++)
{
if (found_types & (1 << i) && !cmp_items[i])
{
- if ((Item_result)i == STRING_RESULT &&
- agg_arg_charsets_for_comparison(cmp_collation, args, arg_count))
- return;
- if ((Item_result)i == TIME_RESULT)
- date_arg= find_date_time_item(args, arg_count, 0);
if (!cmp_items[i] && !(cmp_items[i]=
cmp_item::get_comparator((Item_result)i, date_arg,
cmp_collation.collation)))
@@ -4255,6 +4257,22 @@ Item_cond::fix_fields(THD *thd, Item **ref)
if (abort_on_null)
item->top_level_item();
+ /*
+ replace degraded condition:
+ was: <field>
+ become: <field> = 1
+ */
+ if (item->type() == FIELD_ITEM)
+ {
+ Query_arena backup, *arena;
+ Item *new_item;
+ arena= thd->activate_stmt_arena_if_needed(&backup);
+ if ((new_item= new Item_func_ne(item, new Item_int(0, 1))))
+ li.replace(item= new_item);
+ if (arena)
+ thd->restore_active_arena(arena, &backup);
+ }
+
// item can be substituted in fix_fields
if ((!item->fixed &&
item->fix_fields(thd, li.ref())) ||
@@ -4939,6 +4957,7 @@ Item_func_regex::fix_fields(THD *thd, Item **ref)
return TRUE; /* purecov: inspected */
with_sum_func=args[0]->with_sum_func || args[1]->with_sum_func;
with_field= args[0]->with_field || args[1]->with_field;
+ with_subselect|= args[0]->with_subselect | args[1]->with_subselect;
max_length= 1;
decimals= 0;
@@ -5308,6 +5327,28 @@ Item *Item_func_not::neg_transformer(THD *thd) /* NOT(x) -> x */
}
+bool Item_func_not::fix_fields(THD *thd, Item **ref)
+{
+ if (args[0]->type() == FIELD_ITEM)
+ {
+ /* replace "NOT <field>" with "<filed> == 0" */
+ Query_arena backup, *arena;
+ Item *new_item;
+ bool rc= TRUE;
+ arena= thd->activate_stmt_arena_if_needed(&backup);
+ if ((new_item= new Item_func_eq(args[0], new Item_int(0, 1))))
+ {
+ new_item->name= name;
+ rc= (*ref= new_item)->fix_fields(thd, ref);
+ }
+ if (arena)
+ thd->restore_active_arena(arena, &backup);
+ return rc;
+ }
+ return Item_func::fix_fields(thd, ref);
+}
+
+
Item *Item_bool_rowready_func2::neg_transformer(THD *thd)
{
Item *item= negated_item();
@@ -5540,7 +5581,15 @@ void Item_equal::add_const(Item *c, Item *f)
else
{
Item_func_eq *func= new Item_func_eq(c, const_item);
- func->set_cmp_func();
+ if (func->set_cmp_func())
+ {
+ /*
+ Setting a comparison function fails when trying to compare
+ incompatible charsets. Charset compatibility is checked earlier,
+ except for constant subqueries where we may do it here.
+ */
+ return;
+ }
func->quick_fix_field();
cond_false= !func->val_int();
}
@@ -5730,6 +5779,7 @@ bool Item_equal::fix_fields(THD *thd, Item **ref)
used_tables_cache|= item->used_tables();
tmp_table_map= item->not_null_tables();
not_null_tables_cache|= tmp_table_map;
+ DBUG_ASSERT(!item->with_sum_func && !item->with_subselect);
if (item->maybe_null)
maybe_null= 1;
if (!item->get_item_equal())
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index de62bc49930..34d1a0bd0ae 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -371,9 +371,9 @@ public:
Item_bool_func2(Item *a,Item *b)
:Item_int_func(a,b), cmp(tmp_arg, tmp_arg+1), abort_on_null(FALSE) {}
void fix_length_and_dec();
- void set_cmp_func()
+ int set_cmp_func()
{
- cmp.set_cmp_func(this, tmp_arg, tmp_arg+1, TRUE);
+ return cmp.set_cmp_func(this, tmp_arg, tmp_arg+1, TRUE);
}
optimize_type select_optimize() const { return OPTIMIZE_OP; }
virtual enum Functype rev_functype() const { return UNKNOWN_FUNC; }
@@ -442,6 +442,7 @@ public:
enum Functype functype() const { return NOT_FUNC; }
const char *func_name() const { return "not"; }
Item *neg_transformer(THD *thd);
+ bool fix_fields(THD *, Item **);
virtual void print(String *str, enum_query_type query_type);
};
@@ -508,6 +509,8 @@ public:
longlong val_int();
enum Functype functype() const { return NOT_ALL_FUNC; }
const char *func_name() const { return "<not>"; }
+ bool fix_fields(THD *thd, Item **ref)
+ {return Item_func::fix_fields(thd, ref);}
virtual void print(String *str, enum_query_type query_type);
void set_sum_test(Item_sum_hybrid *item) { test_sum_item= item; };
void set_sub_test(Item_maxmin_subselect *item) { test_sub_item= item; };
diff --git a/sql/item_func.cc b/sql/item_func.cc
index b9bab372500..4691ee10e49 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -3350,6 +3350,7 @@ udf_handler::fix_fields(THD *thd, Item_result_field *func,
func->maybe_null=1;
func->with_sum_func= func->with_sum_func || item->with_sum_func;
func->with_field= func->with_field || item->with_field;
+ func->with_subselect|= item->with_subselect;
used_tables_cache|=item->used_tables();
const_item_cache&=item->const_item();
f_args.arg_type[i]=item->result_type();
diff --git a/sql/item_func.h b/sql/item_func.h
index f91107c5445..cb9c1929d7d 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -1941,6 +1941,11 @@ public:
return str;
}
+ void update_null_value()
+ {
+ execute();
+ }
+
virtual bool change_context_processor(uchar *cntx)
{ context= (Name_resolution_context *)cntx; return FALSE; }
@@ -1955,6 +1960,7 @@ public:
{
return sp_result_field;
}
+
bool check_vcol_func_processor(uchar *int_arg)
{
return trace_unsupported_by_check_vcol_func_processor(func_name());
diff --git a/sql/item_row.cc b/sql/item_row.cc
index 530a40c55dc..2c4a628075e 100644
--- a/sql/item_row.cc
+++ b/sql/item_row.cc
@@ -95,6 +95,7 @@ bool Item_row::fix_fields(THD *thd, Item **ref)
maybe_null|= item->maybe_null;
with_sum_func= with_sum_func || item->with_sum_func;
with_field= with_field || item->with_field;
+ with_subselect|= item->with_subselect;
}
fixed= 1;
return FALSE;
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index ad854b02765..9ed2627a518 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -829,7 +829,7 @@ public:
{
DBUG_ASSERT(args[0]->fixed);
conv_charset= cs;
- if (cache_if_const && args[0]->const_item() && !args[0]->with_subselect)
+ if (cache_if_const && args[0]->const_item() && !args[0]->is_expensive())
{
uint errors= 0;
String tmp, *str= args[0]->val_str(&tmp);
@@ -854,6 +854,30 @@ public:
}
}
String *val_str(String *);
+ longlong val_int()
+ {
+ if (args[0]->result_type() == STRING_RESULT)
+ return Item_str_func::val_int();
+ return args[0]->val_int();
+ }
+ double val_real()
+ {
+ if (args[0]->result_type() == STRING_RESULT)
+ return Item_str_func::val_real();
+ return args[0]->val_real();
+ }
+ my_decimal *val_decimal(my_decimal *d)
+ {
+ if (args[0]->result_type() == STRING_RESULT)
+ return Item_str_func::val_decimal(d);
+ return args[0]->val_decimal(d);
+ }
+ bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+ {
+ if (args[0]->result_type() == STRING_RESULT)
+ return Item_str_func::get_date(ltime, fuzzydate);
+ return args[0]->get_date(ltime, fuzzydate);
+ }
void fix_length_and_dec();
const char *func_name() const { return "convert"; }
virtual void print(String *str, enum_query_type query_type);
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index 5458a2fb968..49d232d31be 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -1,5 +1,5 @@
-/* Copyright (c) 2002, 2011, Oracle and/or its affiliates.
- Copyright (c) 2010, 2011, Monty Program Ab
+/* Copyright (c) 2002, 2012, Oracle and/or its affiliates.
+ Copyright (c) 2010, 2012, Monty Program Ab
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -287,7 +287,7 @@ bool Item_subselect::fix_fields(THD *thd_param, Item **ref)
else
goto end;
- if ((uncacheable= engine->uncacheable()))
+ if ((uncacheable= engine->uncacheable() & ~UNCACHEABLE_EXPLAIN))
{
const_item_cache= 0;
if (uncacheable & UNCACHEABLE_RAND)
@@ -523,6 +523,48 @@ void Item_subselect::recalc_used_tables(st_select_lex *new_parent,
*/
}
+
+/**
+ Determine if a subquery is expensive to execute during query optimization.
+
+ @details The cost of execution of a subquery is estimated based on an
+ estimate of the number of rows the subquery will access during execution.
+ This measure is used instead of JOIN::read_time, because it is considered
+ to be much more reliable than the cost estimate.
+
+ @return true if the subquery is expensive
+ @return false otherwise
+*/
+bool Item_subselect::is_expensive()
+{
+ double examined_rows= 0;
+
+ for (SELECT_LEX *sl= unit->first_select(); sl; sl= sl->next_select())
+ {
+ JOIN *cur_join= sl->join;
+ if (!cur_join)
+ continue;
+
+ /* If a subquery is not optimized we cannot estimate its cost. */
+ if (!cur_join->join_tab)
+ return true;
+
+ if (sl->first_inner_unit())
+ {
+ /*
+ Subqueries that contain subqueries are considered expensive.
+ @todo: accumulate the cost of subqueries.
+ */
+ return true;
+ }
+
+ examined_rows+= cur_join->get_examined_rows();
+ }
+
+ return (examined_rows > thd->variables.expensive_subquery_limit);
+}
+
+
bool Item_subselect::walk(Item_processor processor, bool walk_subquery,
uchar *argument)
{
@@ -904,6 +946,15 @@ void Item_maxmin_subselect::print(String *str, enum_query_type query_type)
void Item_maxmin_subselect::no_rows_in_result()
{
+ /*
+ Subquery predicates outside of the SELECT list must be evaluated in order
+ to possibly filter the special result row generated for implicit grouping
+ if the subquery is in the HAVING clause.
+ If the predicate is constant, we need its actual value in the only result
+ row for queries with implicit grouping.
+ */
+ if (parsing_place != SELECT_LIST || const_item())
+ return;
value= Item_cache::get_cache(new Item_null());
null_value= 0;
was_values= 0;
@@ -913,6 +964,15 @@ void Item_maxmin_subselect::no_rows_in_result()
void Item_singlerow_subselect::no_rows_in_result()
{
+ /*
+ Subquery predicates outside of the SELECT list must be evaluated in order
+ to possibly filter the special result row generated for implicit grouping
+ if the subquery is in the HAVING clause.
+ If the predicate is constant, we need its actual value in the only result
+ row for queries with implicit grouping.
+ */
+ if (parsing_place != SELECT_LIST || const_item())
+ return;
value= Item_cache::get_cache(new Item_null());
reset();
make_const();
@@ -1375,6 +1435,15 @@ Item* Item_exists_subselect::expr_cache_insert_transformer(uchar *thd_arg)
void Item_exists_subselect::no_rows_in_result()
{
+ /*
+ Subquery predicates outside of the SELECT list must be evaluated in order
+ to possibly filter the special result row generated for implicit grouping
+ if the subquery is in the HAVING clause.
+ If the predicate is constant, we need its actual value in the only result
+ row for queries with implicit grouping.
+ */
+ if (parsing_place != SELECT_LIST || const_item())
+ return;
value= 0;
null_value= 0;
make_const();
@@ -2719,6 +2788,15 @@ void Item_allany_subselect::print(String *str, enum_query_type query_type)
void Item_allany_subselect::no_rows_in_result()
{
+ /*
+ Subquery predicates outside of the SELECT list must be evaluated in order
+ to possibly filter the special result row generated for implicit grouping
+ if the subquery is in the HAVING clause.
+ If the predicate is constant, we need its actual value in the only result
+ row for queries with implicit grouping.
+ */
+ if (parsing_place != SELECT_LIST || const_item())
+ return;
value= 0;
null_value= 0;
was_null= 0;
diff --git a/sql/item_subselect.h b/sql/item_subselect.h
index 0e0f61aedd9..05c4528490f 100644
--- a/sql/item_subselect.h
+++ b/sql/item_subselect.h
@@ -159,8 +159,8 @@ public:
null_value= 1;
}
/**
- Set the subquery result to the default value for the predicate when the
- subquery is known to produce an empty result.
+ Set the subquery result to a default value consistent with the semantics of
+ the result row produced for queries with implicit grouping.
*/
void no_rows_in_result()= 0;
virtual bool select_transformer(JOIN *join);
@@ -209,7 +209,7 @@ public:
*/
bool is_evaluated() const;
bool is_uncacheable() const;
- bool is_expensive() { return TRUE; }
+ bool is_expensive();
/*
Used by max/min subquery to initialize value presence registration
@@ -235,7 +235,7 @@ public:
@retval TRUE if the predicate is expensive
@retval FALSE otherwise
*/
- bool is_expensive_processor(uchar *arg) { return TRUE; }
+ bool is_expensive_processor(uchar *arg) { return is_expensive(); }
/**
Get the SELECT_LEX structure associated with this Item.
@@ -581,6 +581,10 @@ public:
bool fix_fields(THD *thd, Item **ref);
void fix_length_and_dec();
void fix_after_pullout(st_select_lex *new_parent, Item **ref);
+ bool const_item() const
+ {
+ return Item_subselect::const_item() && left_expr->const_item();
+ }
void update_used_tables();
bool setup_mat_engine();
bool init_left_expr_cache();
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index afe4f34bd05..0b21ba92558 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -1135,6 +1135,7 @@ Item_sum_num::fix_fields(THD *thd, Item **ref)
if (args[i]->fix_fields(thd, args + i) || args[i]->check_cols(1))
return TRUE;
set_if_bigger(decimals, args[i]->decimals);
+ with_subselect|= args[i]->with_subselect;
}
result_field=0;
max_length=float_length(decimals);
@@ -1165,6 +1166,7 @@ Item_sum_hybrid::fix_fields(THD *thd, Item **ref)
(item= args[0])->check_cols(1))
return TRUE;
decimals=item->decimals;
+ with_subselect= args[0]->with_subselect;
switch (hybrid_type= item->result_type()) {
case INT_RESULT:
@@ -3319,6 +3321,7 @@ Item_func_group_concat::fix_fields(THD *thd, Item **ref)
args[i]->fix_fields(thd, args + i)) ||
args[i]->check_cols(1))
return TRUE;
+ with_subselect|= args[i]->with_subselect;
}
/* skip charset aggregation for order columns */
diff --git a/sql/log.cc b/sql/log.cc
index 2ef6463aa81..3547877bad8 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -2628,9 +2628,10 @@ void MYSQL_LOG::init_pthread_objects()
SYNOPSIS
close()
- exiting Bitmask. For the slow and general logs the only used bit is
- LOG_CLOSE_TO_BE_OPENED. This is used if we intend to call
- open at once after close.
+ exiting Bitmask. LOG_CLOSE_TO_BE_OPENED is used if we intend to call
+ open at once after close. LOG_CLOSE_DELAYED_CLOSE is used for
+ binlog rotation, to delay actual close of the old file until
+ we have successfully created the new file.
NOTES
One can do an open on the object at once after doing a close.
@@ -2651,7 +2652,8 @@ void MYSQL_LOG::close(uint exiting)
sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno);
}
- if (mysql_file_close(log_file.file, MYF(MY_WME)) && ! write_error)
+ if (!(exiting & LOG_CLOSE_DELAYED_CLOSE) &&
+ mysql_file_close(log_file.file, MYF(MY_WME)) && ! write_error)
{
write_error= 1;
sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno);
@@ -3353,6 +3355,10 @@ bool MYSQL_BIN_LOG::open(const char *log_name,
if (write_file_name_to_index_file)
{
#ifdef HAVE_REPLICATION
+#ifdef ENABLED_DEBUG_SYNC
+ if (current_thd)
+ DEBUG_SYNC(current_thd, "binlog_open_before_update_index");
+#endif
DBUG_EXECUTE_IF("crash_create_critical_before_update_index", DBUG_SUICIDE(););
#endif
@@ -4461,6 +4467,10 @@ int MYSQL_BIN_LOG::new_file_impl(bool need_lock)
{
int error= 0, close_on_error= FALSE;
char new_name[FN_REFLEN], *new_name_ptr, *old_name, *file_to_open;
+ uint close_flag;
+ bool delay_close= false;
+ File old_file;
+ LINT_INIT(old_file);
DBUG_ENTER("MYSQL_BIN_LOG::new_file_impl");
if (!is_open())
@@ -4544,7 +4554,20 @@ int MYSQL_BIN_LOG::new_file_impl(bool need_lock)
}
old_name=name;
name=0; // Don't free name
- close(LOG_CLOSE_TO_BE_OPENED | LOG_CLOSE_INDEX);
+ close_flag= LOG_CLOSE_TO_BE_OPENED | LOG_CLOSE_INDEX;
+ if (!is_relay_log)
+ {
+ /*
+ We need to keep the old binlog file open (and marked as in-use) until
+ the new one is fully created and synced to disk and index. Otherwise we
+ leave a window where if we crash, there is no binlog file marked as
+ crashed for server restart to detect the need for recovery.
+ */
+ old_file= log_file.file;
+ close_flag|= LOG_CLOSE_DELAYED_CLOSE;
+ delay_close= true;
+ }
+ close(close_flag);
if (log_type == LOG_BIN && checksum_alg_reset != BINLOG_CHECKSUM_ALG_UNDEF)
{
DBUG_ASSERT(!is_relay_log);
@@ -4587,6 +4610,12 @@ int MYSQL_BIN_LOG::new_file_impl(bool need_lock)
end:
+ if (delay_close)
+ {
+ clear_inuse_flag_when_closing(old_file);
+ mysql_file_close(old_file, MYF(MY_WME));
+ }
+
if (error && close_on_error /* rotate or reopen failed */)
{
/*
@@ -6493,6 +6522,8 @@ int MYSQL_BIN_LOG::wait_for_update_bin_log(THD* thd,
- LOG_CLOSE_TO_BE_OPENED : if we intend to call open
at once after close.
- LOG_CLOSE_STOP_EVENT : write a 'stop' event to the log
+ - LOG_CLOSE_DELAYED_CLOSE : do not yet close the file and clear the
+ LOG_EVENT_BINLOG_IN_USE_F flag
@note
One can do an open on the object at once after doing a close.
@@ -6522,12 +6553,11 @@ void MYSQL_BIN_LOG::close(uint exiting)
#endif /* HAVE_REPLICATION */
/* don't pwrite in a file opened with O_APPEND - it doesn't work */
- if (log_file.type == WRITE_CACHE && log_type == LOG_BIN)
+ if (log_file.type == WRITE_CACHE && log_type == LOG_BIN
+ && !(exiting & LOG_CLOSE_DELAYED_CLOSE))
{
- my_off_t offset= BIN_LOG_HEADER_SIZE + FLAGS_OFFSET;
my_off_t org_position= mysql_file_tell(log_file.file, MYF(0));
- uchar flags= 0; // clearing LOG_EVENT_BINLOG_IN_USE_F
- mysql_file_pwrite(log_file.file, &flags, 1, offset, MYF(0));
+ clear_inuse_flag_when_closing(log_file.file);
/*
Restore position so that anything we have in the IO_cache is written
to the correct position.
@@ -6562,6 +6592,18 @@ void MYSQL_BIN_LOG::close(uint exiting)
}
+/*
+ Clear the LOG_EVENT_BINLOG_IN_USE_F; this marks the binlog file as cleanly
+ closed and not needing crash recovery.
+*/
+void MYSQL_BIN_LOG::clear_inuse_flag_when_closing(File file)
+{
+ my_off_t offset= BIN_LOG_HEADER_SIZE + FLAGS_OFFSET;
+ uchar flags= 0; // clearing LOG_EVENT_BINLOG_IN_USE_F
+ mysql_file_pwrite(file, &flags, 1, offset, MYF(0));
+}
+
+
void MYSQL_BIN_LOG::set_max_size(ulong max_size_arg)
{
/*
diff --git a/sql/log.h b/sql/log.h
index 2bc4d0e49d7..55782952d21 100644
--- a/sql/log.h
+++ b/sql/log.h
@@ -202,6 +202,7 @@ extern TC_LOG_DUMMY tc_log_dummy;
#define LOG_CLOSE_INDEX 1
#define LOG_CLOSE_TO_BE_OPENED 2
#define LOG_CLOSE_STOP_EVENT 4
+#define LOG_CLOSE_DELAYED_CLOSE 8
/*
Maximum unique log filename extension.
@@ -222,6 +223,11 @@ class Relay_log_info;
extern PSI_mutex_key key_LOG_INFO_lock;
#endif
+/*
+ Note that we destroy the lock mutex in the desctructor here.
+ This means that object instances cannot be destroyed/go out of scope,
+ until we have reset thd->current_linfo to NULL;
+ */
typedef struct st_log_info
{
char log_file_name[FN_REFLEN];
@@ -477,8 +483,8 @@ class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG
void mark_xids_active(uint xid_count);
public:
- MYSQL_LOG::generate_name;
- MYSQL_LOG::is_open;
+ using MYSQL_LOG::generate_name;
+ using MYSQL_LOG::is_open;
/* This is relay log */
bool is_relay_log;
@@ -666,6 +672,7 @@ public:
bool need_mutex);
bool reset_logs(THD* thd);
void close(uint exiting);
+ void clear_inuse_flag_when_closing(File file);
// iterating through the log index file
int find_log_pos(LOG_INFO* linfo, const char* log_name,
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 95ac3fc278c..a679249ae24 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -1,5 +1,6 @@
/*
- Copyright (c) 2000, 2011, Oracle and/or its affiliates.
+ Copyright (c) 2000, 2012, Oracle and/or its affiliates.
+ Copyright (c) 2010, 2012, Monty Program Ab
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -5843,11 +5844,12 @@ void Intvar_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
#endif
+#if defined(HAVE_REPLICATION)&& !defined(MYSQL_CLIENT)
+
/*
Intvar_log_event::do_apply_event()
*/
-#if defined(HAVE_REPLICATION)&& !defined(MYSQL_CLIENT)
int Intvar_log_event::do_apply_event(Relay_log_info const *rli)
{
/*
@@ -5856,6 +5858,9 @@ int Intvar_log_event::do_apply_event(Relay_log_info const *rli)
*/
const_cast<Relay_log_info*>(rli)->set_flag(Relay_log_info::IN_STMT);
+ if (rli->deferred_events_collecting)
+ return rli->deferred_events->add(this);
+
switch (type) {
case LAST_INSERT_ID_EVENT:
thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt= 1;
@@ -5962,6 +5967,9 @@ int Rand_log_event::do_apply_event(Relay_log_info const *rli)
*/
const_cast<Relay_log_info*>(rli)->set_flag(Relay_log_info::IN_STMT);
+ if (rli->deferred_events_collecting)
+ return rli->deferred_events->add(this);
+
thd->rand.seed1= (ulong) seed1;
thd->rand.seed2= (ulong) seed2;
return 0;
@@ -5988,6 +5996,29 @@ Rand_log_event::do_shall_skip(Relay_log_info *rli)
return continue_group(rli);
}
+/**
+ Exec deferred Int-, Rand- and User- var events prefixing
+ a Query-log-event event.
+
+ @param thd THD handle
+
+ @return false on success, true if a failure in an event applying occurred.
+*/
+bool slave_execute_deferred_events(THD *thd)
+{
+ bool res= false;
+ Relay_log_info *rli= thd->rli_slave;
+
+ DBUG_ASSERT(rli && (!rli->deferred_events_collecting || rli->deferred_events));
+
+ if (!rli->deferred_events_collecting || rli->deferred_events->is_empty())
+ return res;
+
+ res= rli->deferred_events->execute(rli);
+
+ return res;
+}
+
#endif /* !MYSQL_CLIENT */
@@ -6426,6 +6457,10 @@ int User_var_log_event::do_apply_event(Relay_log_info const *rli)
{
Item *it= 0;
CHARSET_INFO *charset;
+
+ if (rli->deferred_events_collecting)
+ return rli->deferred_events->add(this);
+
if (!(charset= get_charset(charset_number, MYF(MY_WME))))
return 1;
LEX_STRING user_var_name;
diff --git a/sql/log_event.h b/sql/log_event.h
index 78dccb3cac1..cccab93e0d5 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -4258,6 +4258,14 @@ private:
const char* log_ident;
uint ident_len;
};
+
+/**
+ The function is called by slave applier in case there are
+ active table filtering rules to force gathering events associated
+ with Query-log-event into an array to execute
+ them once the fate of the Query is determined for execution.
+*/
+bool slave_execute_deferred_events(THD *thd);
#endif
int append_query_string(THD *thd, CHARSET_INFO *csinfo,
diff --git a/sql/log_event_old.cc b/sql/log_event_old.cc
index 040b35d28f1..8f2c515e11c 100644
--- a/sql/log_event_old.cc
+++ b/sql/log_event_old.cc
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007, 2010, Oracle and/or its affiliates.
+/* Copyright (c) 2007, 2012, Oracle and/or its affiliates.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/sql/mysql_install_db.cc b/sql/mysql_install_db.cc
index 364dca9120a..6e2c6ec07f3 100644
--- a/sql/mysql_install_db.cc
+++ b/sql/mysql_install_db.cc
@@ -119,8 +119,8 @@ static void die(const char *fmt, ...)
fprintf(stderr,
"http://kb.askmonty.org/v/installation-issues-on-windows contains some help\n"
"for solving the most common problems. If this doesn't help you, please\n"
- "leave a comment in the knowledge base or file a bug report at\n"
- "https://bugs.launchpad.net/maria");
+ "leave a comment in the Knowledgebase or file a bug report at\n"
+ "http://mariadb.org/jira");
}
fflush(stderr);
va_end(args);
@@ -247,7 +247,7 @@ static char *init_bootstrap_command_line(char *cmdline, size_t size)
"\"\"%s\" --no-defaults --bootstrap"
" \"--language=%s\\share\\english\""
" --basedir=. --datadir=. --default-storage-engine=myisam"
- " --max_allowed_packet=9M --loose-skip-innodb --loose-skip-pbxt"
+ " --max_allowed_packet=9M --loose-skip-innodb"
" --net-buffer-length=16k\"", mysqld_path, basedir);
return cmdline;
}
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index eaaff295ae0..dfdf1c41c0f 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -110,7 +110,7 @@ ulong wsrep_running_threads = 0; // # of currently running wsrep threads
/* We have HAVE_valgrind below as this speeds up the shutdown of MySQL */
-#if defined(HAVE_DEC_3_2_THREADS) || defined(SIGNALS_DONT_BREAK_READ) || defined(HAVE_valgrind) && defined(__linux__)
+#if defined(SIGNALS_DONT_BREAK_READ) || defined(HAVE_valgrind) && defined(__linux__)
#define HAVE_CLOSE_SERVER_SOCK 1
#endif
@@ -694,6 +694,7 @@ mysql_cond_t COND_wsrep_rollback;
wsrep_aborting_thd_t wsrep_aborting_thd= NULL;
mysql_mutex_t LOCK_wsrep_replaying;
mysql_cond_t COND_wsrep_replaying;
+mysql_mutex_t LOCK_wsrep_slave_threads;
int wsrep_replaying= 0;
static void wsrep_close_threads(THD* thd);
#endif
@@ -768,7 +769,8 @@ PSI_mutex_key key_BINLOG_LOCK_index, key_BINLOG_LOCK_prep_xids,
#ifdef WITH_WSREP
PSI_mutex_key key_LOCK_wsrep_rollback, key_LOCK_wsrep_thd,
key_LOCK_wsrep_replaying, key_LOCK_wsrep_ready, key_LOCK_wsrep_sst,
- key_LOCK_wsrep_sst_thread, key_LOCK_wsrep_sst_init;
+ key_LOCK_wsrep_sst_thread, key_LOCK_wsrep_sst_init,
+ key_LOCK_wsrep_slave_threads;
#endif
PSI_mutex_key key_RELAYLOG_LOCK_index;
@@ -846,6 +848,7 @@ static PSI_mutex_info all_server_mutexes[]=
{ &key_LOCK_wsrep_rollback, "LOCK_wsrep_rollback", PSI_FLAG_GLOBAL},
{ &key_LOCK_wsrep_thd, "THD::LOCK_wsrep_thd", 0},
{ &key_LOCK_wsrep_replaying, "LOCK_wsrep_replaying", PSI_FLAG_GLOBAL},
+ { &key_LOCK_wsrep_slave_threads, "LOCK_wsrep_slave_threads", PSI_FLAG_GLOBAL},
#endif
{ &key_PARTITION_LOCK_auto_inc, "HA_DATA_PARTITION::LOCK_auto_inc", 0}
};
@@ -2047,6 +2050,7 @@ static void clean_up_mutexes()
(void) mysql_cond_destroy(&COND_wsrep_rollback);
(void) mysql_mutex_destroy(&LOCK_wsrep_replaying);
(void) mysql_cond_destroy(&COND_wsrep_replaying);
+ (void) mysql_mutex_destroy(&LOCK_wsrep_slave_threads);
#endif
mysql_mutex_destroy(&LOCK_server_started);
mysql_cond_destroy(&COND_server_started);
@@ -3051,11 +3055,9 @@ static void start_signal_handler(void)
DBUG_ENTER("start_signal_handler");
(void) pthread_attr_init(&thr_attr);
-#if !defined(HAVE_DEC_3_2_THREADS)
pthread_attr_setscope(&thr_attr,PTHREAD_SCOPE_SYSTEM);
(void) pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED);
(void) my_setstacksize(&thr_attr,my_thread_stack_size);
-#endif
mysql_mutex_lock(&LOCK_thread_count);
if ((error= mysql_thread_create(key_thread_signal_hand,
@@ -3542,14 +3544,23 @@ static int init_common_variables()
return 1;
#ifdef HAVE_TZNAME
- {
- struct tm tm_tmp;
- localtime_r(&server_start_time,&tm_tmp);
- strmake(system_time_zone, tzname[tm_tmp.tm_isdst != 0 ? 1 : 0],
- sizeof(system_time_zone)-1);
+ struct tm tm_tmp;
+ localtime_r(&server_start_time,&tm_tmp);
+ const char *tz_name= tzname[tm_tmp.tm_isdst != 0 ? 1 : 0];
+#ifdef _WIN32
+ /*
+ Time zone name may be localized and contain non-ASCII characters,
+ Convert from ANSI encoding to UTF8.
+ */
+ wchar_t wtz_name[sizeof(system_time_zone)];
+ mbstowcs(wtz_name, tz_name, sizeof(system_time_zone)-1);
+ WideCharToMultiByte(CP_UTF8,0, wtz_name, -1, system_time_zone,
+ sizeof(system_time_zone) - 1, NULL, NULL);
+#else
+ strmake(system_time_zone, tz_name, sizeof(system_time_zone)-1);
+#endif /* _WIN32 */
+#endif /* HAVE_TZNAME */
- }
-#endif
/*
We set SYSTEM time zone as reasonable default and
also for failure of my_tz_init() and bootstrap mode.
@@ -4065,6 +4076,8 @@ static int init_thread_environment()
mysql_mutex_init(key_LOCK_wsrep_replaying,
&LOCK_wsrep_replaying, MY_MUTEX_INIT_FAST);
mysql_cond_init(key_COND_wsrep_replaying, &COND_wsrep_replaying, NULL);
+ mysql_mutex_init(key_LOCK_wsrep_slave_threads,
+ &LOCK_wsrep_slave_threads, MY_MUTEX_INIT_FAST);
#endif
return 0;
}
@@ -5002,9 +5015,7 @@ void wsrep_close_client_connections(my_bool wait_to_end)
void wsrep_close_applier(THD *thd)
{
- if (wsrep_debug)
- WSREP_INFO("closing applier %ld", thd->thread_id);
-
+ WSREP_DEBUG("closing applier %ld", thd->thread_id);
wsrep_close_thread(thd);
}
@@ -5021,10 +5032,30 @@ static void wsrep_close_threads(THD *thd)
/* We skip slave threads & scheduler on this first loop through. */
if (tmp->wsrep_applier && tmp != thd)
{
- if (wsrep_debug)
- WSREP_INFO("closing wsrep thread %ld", tmp->thread_id);
+ WSREP_DEBUG("closing wsrep thread %ld", tmp->thread_id);
wsrep_close_thread (tmp);
+ }
+ }
+ mysql_mutex_unlock(&LOCK_thread_count);
+}
+
+void wsrep_close_applier_threads(int count)
+{
+ THD *tmp;
+ mysql_mutex_lock(&LOCK_thread_count); // For unlink from list
+
+ I_List_iterator<THD> it(threads);
+ while ((tmp=it++) && count)
+ {
+ DBUG_PRINT("quit",("Informing thread %ld that it's time to die",
+ tmp->thread_id));
+ /* We skip slave threads & scheduler on this first loop through. */
+ if (tmp->wsrep_applier)
+ {
+ WSREP_DEBUG("closing wsrep applier thread %ld", tmp->thread_id);
+ tmp->wsrep_applier_closing= TRUE;
+ count--;
}
}
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index 0390ac1101e..da328063e56 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -2008,7 +2008,7 @@ int QUICK_RANGE_SELECT::init_ror_merged_scan(bool reuse_handler)
if (reuse_handler)
{
DBUG_PRINT("info", ("Reusing handler 0x%lx", (long) file));
- if (init() || reset())
+ if (init())
{
DBUG_RETURN(1);
}
@@ -2043,7 +2043,7 @@ int QUICK_RANGE_SELECT::init_ror_merged_scan(bool reuse_handler)
if (file->ha_external_lock(thd, F_RDLCK))
goto failure;
- if (init() || reset())
+ if (init())
{
file->ha_external_lock(thd, F_UNLCK);
file->ha_close();
@@ -2090,7 +2090,18 @@ end:
head->key_read= org_key_read;
bitmap_copy(&column_bitmap, head->read_set);
head->column_bitmaps_set(&column_bitmap, &column_bitmap);
-
+
+ if (reset())
+ {
+ if (!reuse_handler)
+ {
+ file->ha_external_lock(thd, F_UNLCK);
+ file->ha_close();
+ goto failure;
+ }
+ else
+ DBUG_RETURN(1);
+ }
DBUG_RETURN(0);
failure:
diff --git a/sql/opt_range.h b/sql/opt_range.h
index 545e9e3c7b8..efb45f96345 100644
--- a/sql/opt_range.h
+++ b/sql/opt_range.h
@@ -990,7 +990,7 @@ class SQL_SELECT :public Sql_alloc {
key_map quick_keys; // Possible quick keys
key_map needed_reg; // Possible quick keys after prev tables.
table_map const_tables,read_tables;
- bool free_cond;
+ bool free_cond; /* Currently not used and always FALSE */
SQL_SELECT();
~SQL_SELECT();
diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc
index a5a68d0d306..8d1cbeba5f4 100644
--- a/sql/opt_subselect.cc
+++ b/sql/opt_subselect.cc
@@ -4894,7 +4894,43 @@ static void remove_subq_pushed_predicates(JOIN *join, Item **where)
bool JOIN::optimize_unflattened_subqueries()
{
- return select_lex->optimize_unflattened_subqueries();
+ return select_lex->optimize_unflattened_subqueries(false);
+}
+
+/**
+ Optimize all constant subqueries of a query that were not flattened into
+ a semijoin.
+
+ @details
+ Similar to other constant conditions, constant subqueries can be used in
+ various constant optimizations. Having optimized constant subqueries before
+ these constant optimizations, makes it possible to estimate if a subquery
+ is "cheap" enough to be executed during the optimization phase.
+
+ Constant subqueries can be optimized and evaluated independent of the outer
+ query, therefore if const_only = true, this method can be called early in
+ the optimization phase of the outer query.
+
+ @return Operation status
+ @retval FALSE success.
+ @retval TRUE error occurred.
+*/
+
+bool JOIN::optimize_constant_subqueries()
+{
+ ulonglong save_options= select_lex->options;
+ bool res;
+ /*
+ Constant subqueries may be executed during the optimization phase.
+ In EXPLAIN mode the optimizer doesn't initialize many of the data structures
+ needed for execution. In order to make it possible to execute subqueries
+ during optimization, constant subqueries must be optimized for execution,
+ not for EXPLAIN.
+ */
+ select_lex->options&= ~SELECT_DESCRIBE;
+ res= select_lex->optimize_unflattened_subqueries(true);
+ select_lex->options= save_options;
+ return res;
}
@@ -5295,7 +5331,14 @@ bool JOIN::choose_subquery_plan(table_map join_tables)
by the IN predicate.
*/
outer_join= unit->outer_select() ? unit->outer_select()->join : NULL;
- if (outer_join && outer_join->table_count > 0)
+ /*
+ Get the cost of the outer join if:
+ (1) It has at least one table, and
+ (2) It has been already optimized (if there is no join_tab, then the
+ outer join has not been optimized yet).
+ */
+ if (outer_join && outer_join->table_count > 0 && // (1)
+ outer_join->join_tab) // (2)
{
/*
TODO:
diff --git a/sql/password.c b/sql/password.c
index 1a12a81f7c6..947620ddf7a 100644
--- a/sql/password.c
+++ b/sql/password.c
@@ -1,5 +1,6 @@
/*
Copyright (c) 2000, 2011, Oracle and/or its affiliates.
+ Copyright (c) 2012, Monty Program Ab
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc
index 940fc201bae..252b4f3f5b9 100644
--- a/sql/rpl_rli.cc
+++ b/sql/rpl_rli.cc
@@ -52,8 +52,8 @@ Relay_log_info::Relay_log_info(bool is_slave_recovery)
inited(0), abort_slave(0), slave_running(0), until_condition(UNTIL_NONE),
until_log_pos(0), retried_trans(0),
tables_to_lock(0), tables_to_lock_count(0),
- last_event_start_time(0), m_flags(0), row_stmt_start_timestamp(0),
- long_find_row_note_printed(false),
+ last_event_start_time(0), deferred_events(NULL),m_flags(0),
+ row_stmt_start_timestamp(0), long_find_row_note_printed(false),
m_annotate_event(0)
{
DBUG_ENTER("Relay_log_info::Relay_log_info");
diff --git a/sql/rpl_rli.h b/sql/rpl_rli.h
index 958002561bc..b989283deb4 100644
--- a/sql/rpl_rli.h
+++ b/sql/rpl_rli.h
@@ -389,6 +389,41 @@ public:
*/
time_t last_event_start_time;
+ /*
+ A container to hold on Intvar-, Rand-, Uservar- log-events in case
+ the slave is configured with table filtering rules.
+ The withhold events are executed when their parent Query destiny is
+ determined for execution as well.
+ */
+ Deferred_log_events *deferred_events;
+
+ /*
+ State of the container: true stands for IRU events gathering,
+ false does for execution, either deferred or direct.
+ */
+ bool deferred_events_collecting;
+
+ /*
+ Returns true if the argument event resides in the containter;
+ more specifically, the checking is done against the last added event.
+ */
+ bool is_deferred_event(Log_event * ev)
+ {
+ return deferred_events_collecting ? deferred_events->is_last(ev) : false;
+ };
+ /* The general cleanup that slave applier may need at the end of query. */
+ inline void cleanup_after_query()
+ {
+ if (deferred_events)
+ deferred_events->rewind();
+ };
+ /* The general cleanup that slave applier may need at the end of session. */
+ void cleanup_after_session()
+ {
+ if (deferred_events)
+ delete deferred_events;
+ };
+
/**
Helper function to do after statement completion.
diff --git a/sql/rpl_utility.cc b/sql/rpl_utility.cc
index 71fa5c8909c..388a6c9f9bb 100644
--- a/sql/rpl_utility.cc
+++ b/sql/rpl_utility.cc
@@ -19,6 +19,7 @@
#ifndef MYSQL_CLIENT
#include "unireg.h" // REQUIRED by later includes
#include "rpl_rli.h"
+#include "log_event.h"
#include "sql_select.h"
/**
@@ -1057,6 +1058,7 @@ table_def::~table_def()
#endif
}
+
/**
@param even_buf point to the buffer containing serialized event
@param event_len length of the event accounting possible checksum alg
@@ -1112,3 +1114,68 @@ bool event_checksum_test(uchar *event_buf, ulong event_len, uint8 alg)
}
return DBUG_EVALUATE_IF("simulate_checksum_test_failure", TRUE, res);
}
+
+
+#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
+
+Deferred_log_events::Deferred_log_events(Relay_log_info *rli) : last_added(NULL)
+{
+ my_init_dynamic_array(&array, sizeof(Log_event *), 32, 16);
+}
+
+Deferred_log_events::~Deferred_log_events()
+{
+ delete_dynamic(&array);
+}
+
+int Deferred_log_events::add(Log_event *ev)
+{
+ last_added= ev;
+ insert_dynamic(&array, (uchar*) &ev);
+ return 0;
+}
+
+bool Deferred_log_events::is_empty()
+{
+ return array.elements == 0;
+}
+
+bool Deferred_log_events::execute(Relay_log_info *rli)
+{
+ bool res= false;
+
+ DBUG_ASSERT(rli->deferred_events_collecting);
+
+ rli->deferred_events_collecting= false;
+ for (uint i= 0; !res && i < array.elements; i++)
+ {
+ Log_event *ev= (* (Log_event **)
+ dynamic_array_ptr(&array, i));
+ res= ev->apply_event(rli);
+ }
+ rli->deferred_events_collecting= true;
+ return res;
+}
+
+void Deferred_log_events::rewind()
+{
+ /*
+ Reset preceeding Query log event events which execution was
+ deferred because of slave side filtering.
+ */
+ if (!is_empty())
+ {
+ for (uint i= 0; i < array.elements; i++)
+ {
+ Log_event *ev= *(Log_event **) dynamic_array_ptr(&array, i);
+ delete ev;
+ }
+ if (array.elements > array.max_element)
+ freeze_size(&array);
+ reset_dynamic(&array);
+ }
+ last_added= NULL;
+}
+
+#endif
+
diff --git a/sql/rpl_utility.h b/sql/rpl_utility.h
index 1f5577d8b8b..9046891e27f 100644
--- a/sql/rpl_utility.h
+++ b/sql/rpl_utility.h
@@ -29,7 +29,7 @@
#include "mysql_com.h"
class Relay_log_info;
-
+class Log_event;
/**
A table definition from the master.
@@ -262,6 +262,24 @@ CPP_UNNAMED_NS_START
};
CPP_UNNAMED_NS_END
+
+class Deferred_log_events
+{
+private:
+ DYNAMIC_ARRAY array;
+ Log_event *last_added;
+
+public:
+ Deferred_log_events(Relay_log_info *rli);
+ ~Deferred_log_events();
+ /* queue for exection at Query-log-event time prior the Query */;
+ int add(Log_event *ev);
+ bool is_empty();
+ bool execute(Relay_log_info *rli);
+ void rewind();
+ bool is_last(Log_event *ev) { return ev == last_added; };
+};
+
#endif
// NB. number of printed bit values is limited to sizeof(buf) - 1
diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt
index 140220dfa9c..923e8e73bc7 100644
--- a/sql/share/errmsg-utf8.txt
+++ b/sql/share/errmsg-utf8.txt
@@ -6501,6 +6501,9 @@ ER_TABLE_IN_FK_CHECK
ER_UNUSED_1
eng "You should never see it"
+ER_BINLOG_UNSAFE_AUTOINC_NOT_FIRST
+ eng "INSERT into autoincrement field which is not the first part in the composed primary key is unsafe."
+
#
# End of 5.5 error messages.
#
diff --git a/sql/signal_handler.cc b/sql/signal_handler.cc
index 37f28844a7c..edc33c4d63b 100644
--- a/sql/signal_handler.cc
+++ b/sql/signal_handler.cc
@@ -138,23 +138,6 @@ extern "C" sig_handler handle_fatal_signal(int sig)
my_safe_printf_stderr("%s",
"Hope that's ok; if not, decrease some variables in the equation.\n\n");
-#if defined(HAVE_LINUXTHREADS)
-#define UNSAFE_DEFAULT_LINUX_THREADS 200
- if (sizeof(char*) == 4 && thread_count > UNSAFE_DEFAULT_LINUX_THREADS)
- {
- my_safe_printf_stderr(
- "You seem to be running 32-bit Linux and have "
- "%d concurrent connections.\n"
- "If you have not changed STACK_SIZE in LinuxThreads "
- "and built the binary \n"
- "yourself, LinuxThreads is quite likely to steal "
- "a part of the global heap for\n"
- "the thread stack. Please read "
- "http://dev.mysql.com/doc/mysql/en/linux-installation.html\n\n"
- thread_count);
- }
-#endif /* HAVE_LINUXTHREADS */
-
#ifdef HAVE_STACKTRACE
thd= current_thd;
diff --git a/sql/slave.cc b/sql/slave.cc
index 94a485cbe29..2b387012f85 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -2797,7 +2797,8 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli)
/* fall through */
default:
DBUG_PRINT("info", ("Deleting the event after it has been executed"));
- delete ev;
+ if (!rli->is_deferred_event(ev))
+ delete ev;
break;
}
@@ -3461,6 +3462,12 @@ pthread_handler_t handle_slave_sql(void *arg)
goto err_during_init;
}
thd->init_for_queries();
+ thd->rli_slave= rli;
+ if ((rli->deferred_events_collecting= rpl_filter->is_on()))
+ {
+ rli->deferred_events= new Deferred_log_events(rli);
+ }
+
thd->temporary_tables = rli->save_temporary_tables; // restore temp tables
set_thd_in_use_temporary_tables(rli); // (re)set sql_thd in use for saved temp tables
/*
diff --git a/sql/spatial.cc b/sql/spatial.cc
index 1616f93241d..e82eec26fdb 100644
--- a/sql/spatial.cc
+++ b/sql/spatial.cc
@@ -1,6 +1,6 @@
/*
- Copyright (c) 2002, 2011, Oracle and/or its affiliates.
- Copyright (c) 2011, Monty Program Ab
+ Copyright (c) 2002, 2012, Oracle and/or its affiliates.
+ Copyright (c) 2011, 2012, Monty Program Ab
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/sql/spatial.h b/sql/spatial.h
index 0d0560656f0..07675d59040 100644
--- a/sql/spatial.h
+++ b/sql/spatial.h
@@ -554,5 +554,5 @@ public:
struct Geometry_buffer : public
my_aligned_storage<sizeof(Gis_point), MY_ALIGNOF(Gis_point)> {};
-#endif /*HAVE_SPATAIAL*/
+#endif /*HAVE_SPATIAL*/
#endif
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index be30e085b05..96cb4d8a045 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -223,6 +223,7 @@ static bool
has_write_table_with_auto_increment(TABLE_LIST *tables);
static bool
has_write_table_with_auto_increment_and_select(TABLE_LIST *tables);
+static bool has_write_table_auto_increment_not_first_in_pk(TABLE_LIST *tables);
uint cached_open_tables(void)
{
@@ -5781,6 +5782,12 @@ bool lock_tables(THD *thd, TABLE_LIST *tables, uint count,
if (thd->variables.binlog_format != BINLOG_FORMAT_ROW && tables &&
has_write_table_with_auto_increment_and_select(tables))
thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_WRITE_AUTOINC_SELECT);
+ /* Todo: merge all has_write_table_auto_inc with decide_logging_format */
+ if (thd->variables.binlog_format != BINLOG_FORMAT_ROW && tables)
+ {
+ if (has_write_table_auto_increment_not_first_in_pk(tables))
+ thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_AUTOINC_NOT_FIRST);
+ }
/*
INSERT...ON DUPLICATE KEY UPDATE on a table with more than one unique keys
@@ -9554,6 +9561,32 @@ has_write_table_with_auto_increment_and_select(TABLE_LIST *tables)
return(has_select && has_auto_increment_tables);
}
+/*
+ Tells if there is a table whose auto_increment column is a part
+ of a compound primary key while is not the first column in
+ the table definition.
+
+ @param tables Table list
+
+ @return true if the table exists, fais if does not.
+*/
+
+static bool
+has_write_table_auto_increment_not_first_in_pk(TABLE_LIST *tables)
+{
+ for (TABLE_LIST *table= tables; table; table= table->next_global)
+ {
+ /* we must do preliminary checks as table->table may be NULL */
+ if (!table->placeholder() &&
+ table->table->found_next_number_field &&
+ (table->lock_type >= TL_WRITE_ALLOW_WRITE)
+ && table->table->s->next_number_keypart != 0)
+ return 1;
+ }
+
+ return 0;
+}
+
/*
diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc
index 96814562757..7edd28446a2 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -1533,7 +1533,7 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d",
unlock();
goto end;
}
- if (!register_all_tables(query_block, tables_used, local_tables))
+ if (!register_all_tables(thd, query_block, tables_used, local_tables))
{
refused++;
DBUG_PRINT("warning", ("tables list including failed"));
@@ -3203,6 +3203,7 @@ Query_cache::invalidate_query_block_list(THD *thd,
SYNOPSIS
Query_cache::register_tables_from_list
+ thd thread handle
tables_used given table list
counter number current position in table of tables of block
block_table pointer to current position in tables table of block
@@ -3213,24 +3214,24 @@ Query_cache::invalidate_query_block_list(THD *thd,
*/
TABLE_COUNTER_TYPE
-Query_cache::register_tables_from_list(TABLE_LIST *tables_used,
+Query_cache::register_tables_from_list(THD *thd, TABLE_LIST *tables_used,
TABLE_COUNTER_TYPE counter,
- Query_cache_block_table *block_table)
+ Query_cache_block_table **block_table)
{
TABLE_COUNTER_TYPE n;
DBUG_ENTER("Query_cache::register_tables_from_list");
for (n= counter;
tables_used;
- tables_used= tables_used->next_global, n++, block_table++)
+ tables_used= tables_used->next_global, n++, (*block_table)++)
{
if (tables_used->is_anonymous_derived_table())
{
DBUG_PRINT("qcache", ("derived table skipped"));
n--;
- block_table--;
+ (*block_table)--;
continue;
}
- block_table->n= n;
+ (*block_table)->n= n;
if (tables_used->view)
{
char key[MAX_DBKEY_LENGTH];
@@ -3243,9 +3244,9 @@ Query_cache::register_tables_from_list(TABLE_LIST *tables_used,
/*
There are not callback function for for VIEWs
*/
- if (!insert_table(key_length, key, block_table,
+ if (!insert_table(key_length, key, (*block_table),
tables_used->view_db.length + 1,
- HA_CACHE_TBL_NONTRANSACT, 0, 0))
+ HA_CACHE_TBL_NONTRANSACT, 0, 0, TRUE))
DBUG_RETURN(0);
/*
We do not need to register view tables here because they are already
@@ -3264,42 +3265,17 @@ Query_cache::register_tables_from_list(TABLE_LIST *tables_used,
if (!insert_table(tables_used->table->s->table_cache_key.length,
tables_used->table->s->table_cache_key.str,
- block_table,
+ (*block_table),
tables_used->db_length,
tables_used->table->file->table_cache_type(),
tables_used->callback_func,
- tables_used->engine_data))
+ tables_used->engine_data,
+ TRUE))
DBUG_RETURN(0);
-#ifdef WITH_MYISAMMRG_STORAGE_ENGINE
- /*
- XXX FIXME: Some generic mechanism is required here instead of this
- MYISAMMRG-specific implementation.
- */
- if (tables_used->table->s->db_type()->db_type == DB_TYPE_MRG_MYISAM)
- {
- ha_myisammrg *handler = (ha_myisammrg *) tables_used->table->file;
- MYRG_INFO *file = handler->myrg_info();
- for (MYRG_TABLE *table = file->open_tables;
- table != file->end_table ;
- table++)
- {
- char key[MAX_DBKEY_LENGTH];
- uint32 db_length;
- uint key_length= filename_2_table_key(key, table->table->filename,
- &db_length);
- (++block_table)->n= ++n;
- /*
- There are not callback function for for MyISAM, and engine data
- */
- if (!insert_table(key_length, key, block_table,
- db_length,
- tables_used->table->file->table_cache_type(),
- 0, 0))
- DBUG_RETURN(0);
- }
- }
-#endif
+ if (tables_used->table->file->
+ register_query_cache_dependant_tables(thd, this, block_table, &n))
+ DBUG_RETURN(0);
}
}
DBUG_RETURN(n - counter);
@@ -3310,12 +3286,14 @@ Query_cache::register_tables_from_list(TABLE_LIST *tables_used,
SYNOPSIS
register_all_tables()
+ thd Thread handle
block Store tables in this block
tables_used List if used tables
tables_arg Not used ?
*/
-my_bool Query_cache::register_all_tables(Query_cache_block *block,
+my_bool Query_cache::register_all_tables(THD *thd,
+ Query_cache_block *block,
TABLE_LIST *tables_used,
TABLE_COUNTER_TYPE tables_arg)
{
@@ -3326,7 +3304,7 @@ my_bool Query_cache::register_all_tables(Query_cache_block *block,
Query_cache_block_table *block_table = block->table(0);
- n= register_tables_from_list(tables_used, 0, block_table);
+ n= register_tables_from_list(thd, tables_used, 0, &block_table);
if (n==0)
{
@@ -3335,6 +3313,8 @@ my_bool Query_cache::register_all_tables(Query_cache_block *block,
tmp != block_table;
tmp++)
unlink_table(tmp);
+ if (block_table->parent)
+ unlink_table(block_table);
}
return test(n);
}
@@ -3353,7 +3333,8 @@ Query_cache::insert_table(uint key_len, char *key,
Query_cache_block_table *node,
uint32 db_length, uint8 cache_type,
qc_engine_callback callback,
- ulonglong engine_data)
+ ulonglong engine_data,
+ my_bool hash)
{
DBUG_ENTER("Query_cache::insert_table");
DBUG_PRINT("qcache", ("insert table node 0x%lx, len %d",
@@ -3361,8 +3342,10 @@ Query_cache::insert_table(uint key_len, char *key,
THD *thd= current_thd;
- Query_cache_block *table_block=
- (Query_cache_block *) my_hash_search(&tables, (uchar*) key, key_len);
+ Query_cache_block *table_block=
+ (hash ?
+ (Query_cache_block *) my_hash_search(&tables, (uchar*) key, key_len) :
+ NULL);
if (table_block &&
table_block->table()->engine_data() != engine_data)
@@ -3412,7 +3395,8 @@ Query_cache::insert_table(uint key_len, char *key,
*/
list_root->next= list_root->prev= list_root;
- if (my_hash_insert(&tables, (const uchar *) table_block))
+ if (hash &&
+ my_hash_insert(&tables, (const uchar *) table_block))
{
DBUG_PRINT("qcache", ("Can't insert table to hash"));
// write_block_data return locked block
@@ -3425,6 +3409,7 @@ Query_cache::insert_table(uint key_len, char *key,
header->type(cache_type);
header->callback(callback);
header->engine_data(engine_data);
+ header->set_hashed(hash);
/*
We insert this table without the assumption that it isn't refrenenced by
@@ -3478,7 +3463,9 @@ void Query_cache::unlink_table(Query_cache_block_table *node)
Query_cache_block *table_block= neighbour->block();
double_linked_list_exclude(table_block,
&tables_blocks);
- my_hash_delete(&tables,(uchar *) table_block);
+ Query_cache_table *header= table_block->table();
+ if (header->is_hashed())
+ my_hash_delete(&tables,(uchar *) table_block);
free_memory_block(table_block);
}
DBUG_VOID_RETURN;
@@ -3951,6 +3938,9 @@ Query_cache::process_and_count_tables(THD *thd, TABLE_LIST *tables_used,
table_alias_charset used here because it depends of
lower_case_table_names variable
*/
+ table_count+= tables_used->table->file->
+ count_query_cache_dependant_tables(tables_type);
+
if (tables_used->table->s->tmp_table != NO_TMP_TABLE ||
(*tables_type & HA_CACHE_TBL_NOCACHE) ||
(tables_used->db_length == 5 &&
@@ -3963,18 +3953,6 @@ Query_cache::process_and_count_tables(THD *thd, TABLE_LIST *tables_used,
"other non-cacheable table(s)"));
DBUG_RETURN(0);
}
-#ifdef WITH_MYISAMMRG_STORAGE_ENGINE
- /*
- XXX FIXME: Some generic mechanism is required here instead of this
- MYISAMMRG-specific implementation.
- */
- if (tables_used->table->s->db_type()->db_type == DB_TYPE_MRG_MYISAM)
- {
- ha_myisammrg *handler = (ha_myisammrg *)tables_used->table->file;
- MYRG_INFO *file = handler->myrg_info();
- table_count+= (file->end_table - file->open_tables);
- }
-#endif
}
}
DBUG_RETURN(table_count);
diff --git a/sql/sql_cache.h b/sql/sql_cache.h
index 87291e80a85..7444d444cf9 100644
--- a/sql/sql_cache.h
+++ b/sql/sql_cache.h
@@ -200,6 +200,10 @@ struct Query_cache_table
The number of queries depending of this table.
*/
int32 m_cached_query_count;
+ /**
+ If table included in the table hash to be found by other queries
+ */
+ my_bool hashed;
inline char *db() { return (char *) data(); }
inline char *table() { return tbl; }
@@ -212,6 +216,8 @@ struct Query_cache_table
inline void callback(qc_engine_callback fn){ callback_func= fn; }
inline ulonglong engine_data() { return engine_data_buff; }
inline void engine_data(ulonglong data_arg){ engine_data_buff= data_arg; }
+ inline my_bool is_hashed() { return hashed; }
+ inline void set_hashed(my_bool hash) { hashed= hash; }
inline uchar* data()
{
return (uchar*)(((uchar*)this)+
@@ -343,10 +349,6 @@ protected:
static void double_linked_list_join(Query_cache_block *head_tail,
Query_cache_block *tail_head);
- /* Table key generation */
- static uint filename_2_table_key (char *key, const char *filename,
- uint32 *db_langth);
-
/* The following functions require that structure_guard_mutex is locked */
void flush_cache();
my_bool free_old_query();
@@ -363,17 +365,12 @@ protected:
Query_cache_block_table *list_root);
TABLE_COUNTER_TYPE
- register_tables_from_list(TABLE_LIST *tables_used,
+ register_tables_from_list(THD *thd, TABLE_LIST *tables_used,
TABLE_COUNTER_TYPE counter,
- Query_cache_block_table *block_table);
- my_bool register_all_tables(Query_cache_block *block,
+ Query_cache_block_table **block_table);
+ my_bool register_all_tables(THD *thd, Query_cache_block *block,
TABLE_LIST *tables_used,
TABLE_COUNTER_TYPE tables);
- my_bool insert_table(uint key_len, char *key,
- Query_cache_block_table *node,
- uint32 db_length, uint8 cache_type,
- qc_engine_callback callback,
- ulonglong engine_data);
void unlink_table(Query_cache_block_table *node);
Query_cache_block *get_free_block (ulong len, my_bool not_less,
ulong min);
@@ -491,6 +488,12 @@ protected:
const char *packet,
ulong length,
unsigned pkt_nr);
+ my_bool insert_table(uint key_len, char *key,
+ Query_cache_block_table *node,
+ uint32 db_length, uint8 cache_type,
+ qc_engine_callback callback,
+ ulonglong engine_data,
+ my_bool hash);
void end_of_result(THD *thd);
void abort(Query_cache_tls *query_cache_tls);
@@ -513,6 +516,10 @@ protected:
const char *name);
my_bool in_blocks(Query_cache_block * point);
+ /* Table key generation */
+ static uint filename_2_table_key (char *key, const char *filename,
+ uint32 *db_langth);
+
enum Cache_try_lock_mode {WAIT, TIMEOUT, TRY};
bool try_lock(THD *thd, Cache_try_lock_mode mode= WAIT);
void lock(THD *thd);
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 5fb809c4da3..99d54e437d2 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -1,6 +1,6 @@
/*
- Copyright (c) 2000, 2011, Oracle and/or its affiliates.
- Copyright (c) 2008-2012 Monty Program Ab
+ Copyright (c) 2000, 2012, Oracle and/or its affiliates.
+ Copyright (c) 2008, 2012, Monty Program Ab
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -710,7 +710,7 @@ extern "C" bool wsrep_thd_is_wsrep_on(THD *thd)
extern "C" bool wsrep_consistency_check(void *thd)
{
- return ((THD*)thd)->wsrep_consistency_check;
+ return ((THD*)thd)->wsrep_consistency_check == CONSISTENCY_CHECK_RUNNING;
}
extern "C" void wsrep_thd_set_exec_mode(THD *thd, enum wsrep_exec_mode mode)
@@ -864,7 +864,7 @@ THD::THD()
#endif
:Statement(&main_lex, &main_mem_root, STMT_CONVENTIONAL_EXECUTION,
/* statement id */ 0),
- rli_fake(0),
+ rli_fake(0), rli_slave(NULL),
in_sub_stmt(0), log_all_errors(0),
binlog_unsafe_warning_flags(0),
binlog_table_maps(0),
@@ -890,6 +890,7 @@ THD::THD()
spcont(NULL),
#ifdef WITH_WSREP
wsrep_applier(is_applier),
+ wsrep_applier_closing(FALSE),
wsrep_client_thread(0),
#endif
m_parser_state(NULL),
@@ -1003,7 +1004,7 @@ THD::THD()
wsrep_retry_query = NULL;
wsrep_retry_query_len = 0;
wsrep_retry_command = COM_CONNECT;
- wsrep_consistency_check = false;
+ wsrep_consistency_check = NO_CONSISTENCY_CHECK;
#endif
/* Call to init() below requires fully initialized Open_tables_state. */
reset_open_tables_state(this);
@@ -1356,7 +1357,7 @@ void THD::init(void)
wsrep_rli= NULL;
wsrep_PA_safe= true;
wsrep_seqno_changed= false;
- wsrep_consistency_check = false;
+ wsrep_consistency_check = NO_CONSISTENCY_CHECK;
#endif
if (variables.sql_log_bin)
variables.option_bits|= OPTION_BIN_LOG;
@@ -1593,6 +1594,8 @@ THD::~THD()
}
mysql_audit_free_thd(this);
+ if (rli_slave)
+ rli_slave->cleanup_after_session();
#endif
free_root(&main_mem_root, MYF(0));
@@ -1979,6 +1982,11 @@ void THD::cleanup_after_query()
//wsrep_trx_seqno = 0;
#endif /* WITH_WSREP */
+#ifndef EMBEDDED_LIBRARY
+ if (rli_slave)
+ rli_slave->cleanup_after_query();
+#endif
+
DBUG_VOID_RETURN;
}
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 1dc38539670..844f56fac6f 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -1,6 +1,6 @@
/*
- Copyright (c) 2000, 2011, Oracle and/or its affiliates.
- Copyright (c) 2009-2012, Monty Program Ab
+ Copyright (c) 2000, 2012, Oracle and/or its affiliates.
+ Copyright (c) 2009, 2012, Monty Program Ab
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -45,6 +45,11 @@
REPLAYING,
RETRY_AUTOCOMMIT,
};
+ enum wsrep_consistency_check_mode {
+ NO_CONSISTENCY_CHECK,
+ CONSISTENCY_CHECK_DECLARED,
+ CONSISTENCY_CHECK_RUNNING,
+ };
#endif
#ifdef USE_PRAGMA_INTERFACE
@@ -517,6 +522,7 @@ typedef struct system_variables
ulonglong group_concat_max_len;
ha_rows select_limit;
ha_rows max_join_size;
+ ha_rows expensive_subquery_limit;
ulong auto_increment_increment, auto_increment_offset;
ulong lock_wait_timeout;
ulong join_cache_level;
@@ -1590,6 +1596,8 @@ public:
/* Used to execute base64 coded binlog events in MySQL server */
Relay_log_info* rli_fake;
+ /* Slave applier execution context */
+ Relay_log_info* rli_slave;
void reset_for_next_command(bool calculate_userstat);
/*
@@ -2368,6 +2376,7 @@ public:
#ifdef WITH_WSREP
const bool wsrep_applier; /* dedicated slave applier thread */
+ bool wsrep_applier_closing; /* applier marked to close */
bool wsrep_client_thread; /* to identify client threads*/
enum wsrep_exec_mode wsrep_exec_mode;
query_id_t wsrep_last_query_id;
@@ -2389,7 +2398,8 @@ public:
char* wsrep_retry_query;
size_t wsrep_retry_query_len;
enum enum_server_command wsrep_retry_command;
- bool wsrep_consistency_check;
+ enum wsrep_consistency_check_mode
+ wsrep_consistency_check;
#endif /* WITH_WSREP */
/**
Internal parser state.
@@ -3106,7 +3116,7 @@ public:
if (global_system_variables.log_warnings > threshold)
{
Security_context *sctx= &main_security_ctx;
- sql_print_warning(ER(ER_NEW_ABORTING_CONNECTION),
+ sql_print_warning(ER_THD(this, ER_NEW_ABORTING_CONNECTION),
thread_id, (db ? db : "unconnected"),
sctx->user ? sctx->user : "unauthenticated",
sctx->host_or_ip, reason);
@@ -3603,7 +3613,8 @@ public:
if (copy_field) /* Fix for Intel compiler */
{
delete [] copy_field;
- save_copy_field= copy_field= 0;
+ save_copy_field= copy_field= NULL;
+ save_copy_field_end= copy_field_end= NULL;
}
}
};
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index bde7a082f42..0afd8c2ac3c 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -120,7 +120,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
}
/* Apply the IN=>EXISTS transformation to all subqueries and optimize them. */
- if (select_lex->optimize_unflattened_subqueries())
+ if (select_lex->optimize_unflattened_subqueries(false))
DBUG_RETURN(TRUE);
const_cond= (!conds || conds->const_item());
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index a4eb1e8996f..230384d0a43 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -2785,9 +2785,6 @@ pthread_handler_t handle_delayed_insert(void *arg)
{
int error;
mysql_audit_release(thd);
-#if defined(HAVE_BROKEN_COND_TIMEDWAIT)
- error= mysql_cond_wait(&di->cond, &di->mutex);
-#else
error= mysql_cond_timedwait(&di->cond, &di->mutex, &abstime);
#ifdef EXTRA_DEBUG
if (error && error != EINTR && error != ETIMEDOUT)
@@ -2797,7 +2794,6 @@ pthread_handler_t handle_delayed_insert(void *arg)
error));
}
#endif
-#endif
if (error == ETIMEDOUT || error == ETIME)
thd->killed= KILL_CONNECTION;
}
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 3ffdb1384c1..6efb36c2d7d 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -68,7 +68,8 @@ Query_tables_list::binlog_stmt_unsafe_errcode[BINLOG_STMT_UNSAFE_COUNT] =
ER_BINLOG_UNSAFE_CREATE_REPLACE_SELECT,
ER_BINLOG_UNSAFE_CREATE_SELECT_AUTOINC,
ER_BINLOG_UNSAFE_UPDATE_IGNORE,
- ER_BINLOG_UNSAFE_INSERT_TWO_KEYS
+ ER_BINLOG_UNSAFE_INSERT_TWO_KEYS,
+ ER_BINLOG_UNSAFE_AUTOINC_NOT_FIRST
};
@@ -1556,7 +1557,7 @@ int lex_one_token(void *arg, void *yythd)
if (version == 99997 && thd->wsrep_exec_mode == LOCAL_STATE)
{
WSREP_DEBUG("consistency check: %s", thd->query());
- thd->wsrep_consistency_check= TRUE;
+ thd->wsrep_consistency_check= CONSISTENCY_CHECK_DECLARED;
lip->yySkipn(5);
lip->set_echo(TRUE);
state=MY_LEX_START;
@@ -3417,7 +3418,23 @@ bool st_select_lex::add_index_hint (THD *thd, char *str, uint length)
}
-bool st_select_lex::optimize_unflattened_subqueries()
+/**
+ Optimize all subqueries that have not been flattened into semi-joins.
+
+ @details
+ This functionality is a method of SELECT_LEX instead of JOIN because
+ SQL statements as DELETE/UPDATE do not have a corresponding JOIN object.
+
+ @see JOIN::optimize_unflattened_subqueries
+
+ @param const_only Restrict subquery optimization to constant subqueries
+
+ @return Operation status
+ @retval FALSE success.
+ @retval TRUE error occurred.
+*/
+
+bool st_select_lex::optimize_unflattened_subqueries(bool const_only)
{
for (SELECT_LEX_UNIT *un= first_inner_unit(); un; un= un->next_unit())
{
@@ -3427,12 +3444,19 @@ bool st_select_lex::optimize_unflattened_subqueries()
{
if (subquery_predicate->substype() == Item_subselect::IN_SUBS)
{
- Item_in_subselect *in_subs=(Item_in_subselect*)subquery_predicate;
+ Item_in_subselect *in_subs= (Item_in_subselect*) subquery_predicate;
if (in_subs->is_jtbm_merged)
continue;
}
+ if (const_only && !subquery_predicate->const_item())
+ {
+ /* Skip non-constant subqueries if the caller asked so. */
+ continue;
+ }
+
bool empty_union_result= true;
+ bool is_correlated_unit= false;
/*
If the subquery is a UNION, optimize all the subqueries in the UNION. If
there is no UNION, then the loop will execute once for the subquery.
@@ -3457,6 +3481,8 @@ bool st_select_lex::optimize_unflattened_subqueries()
inner_join->select_options|= SELECT_DESCRIBE;
}
res= inner_join->optimize();
+ sl->update_correlated_cache();
+ is_correlated_unit|= sl->is_correlated;
inner_join->select_options= save_options;
un->thd->lex->current_select= save_select;
if (empty_union_result)
@@ -3472,6 +3498,9 @@ bool st_select_lex::optimize_unflattened_subqueries()
}
if (empty_union_result)
subquery_predicate->no_rows_in_result();
+ if (!is_correlated_unit)
+ un->uncacheable&= ~UNCACHEABLE_DEPENDENT;
+ subquery_predicate->is_correlated= is_correlated_unit;
}
}
return FALSE;
@@ -3841,6 +3870,61 @@ void SELECT_LEX::update_used_tables()
/**
+ @brief
+ Update is_correlated cache for this select
+
+ @details
+*/
+
+void st_select_lex::update_correlated_cache()
+{
+ TABLE_LIST *tl;
+ List_iterator<TABLE_LIST> ti(leaf_tables);
+
+ is_correlated= false;
+
+ while ((tl= ti++))
+ {
+ if (tl->on_expr)
+ is_correlated|= test(tl->on_expr->used_tables() & OUTER_REF_TABLE_BIT);
+ for (TABLE_LIST *embedding= tl->embedding ; embedding ;
+ embedding= embedding->embedding)
+ {
+ if (embedding->on_expr)
+ is_correlated|= test(embedding->on_expr->used_tables() &
+ OUTER_REF_TABLE_BIT);
+ }
+ }
+
+ if (join->conds)
+ is_correlated|= test(join->conds->used_tables() & OUTER_REF_TABLE_BIT);
+
+ if (join->having)
+ is_correlated|= test(join->having->used_tables() & OUTER_REF_TABLE_BIT);
+
+ if (join->tmp_having)
+ is_correlated|= test(join->tmp_having->used_tables() & OUTER_REF_TABLE_BIT);
+
+ Item *item;
+ List_iterator_fast<Item> it(join->fields_list);
+ while ((item= it++))
+ is_correlated|= test(item->used_tables() & OUTER_REF_TABLE_BIT);
+
+ for (ORDER *order= group_list.first; order; order= order->next)
+ is_correlated|= test((*order->item)->used_tables() & OUTER_REF_TABLE_BIT);
+
+ if (!master_unit()->is_union())
+ {
+ for (ORDER *order= order_list.first; order; order= order->next)
+ is_correlated|= test((*order->item)->used_tables() & OUTER_REF_TABLE_BIT);
+ }
+
+ if (!is_correlated)
+ uncacheable&= ~UNCACHEABLE_DEPENDENT;
+}
+
+
+/**
Set the EXPLAIN type for this subquery.
*/
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 7da0cc48298..2f3214646de 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -997,12 +997,7 @@ public:
void clear_index_hints(void) { index_hints= NULL; }
bool is_part_of_union() { return master_unit()->is_union(); }
- /*
- Optimize all subqueries that have not been flattened into semi-joins.
- This functionality is a method of SELECT_LEX instead of JOIN because
- some SQL statements as DELETE do not have a corresponding JOIN object.
- */
- bool optimize_unflattened_subqueries();
+ bool optimize_unflattened_subqueries(bool const_only);
/* Set the EXPLAIN type for this subquery. */
void set_explain_type();
bool handle_derived(LEX *lex, uint phases);
@@ -1023,6 +1018,7 @@ public:
void mark_as_belong_to_derived(TABLE_LIST *derived);
void increase_derived_records(ha_rows records);
void update_used_tables();
+ void update_correlated_cache();
void mark_const_derived(bool empty);
bool save_leaf_tables(THD *thd);
@@ -1433,6 +1429,12 @@ public:
*/
BINLOG_STMT_UNSAFE_INSERT_TWO_KEYS,
+ /**
+ INSERT into auto-inc field which is not the first part of composed
+ primary key.
+ */
+ BINLOG_STMT_UNSAFE_AUTOINC_NOT_FIRST,
+
/* The last element of this enumeration type. */
BINLOG_STMT_UNSAFE_COUNT
};
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index cce1aaf05d4..0ca412be17d 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -2401,6 +2401,11 @@ mysql_execute_command(THD *thd)
}
DBUG_RETURN(0);
}
+ /*
+ Execute deferred events first
+ */
+ if (slave_execute_deferred_events(thd))
+ DBUG_RETURN(-1);
}
else
{
@@ -2447,12 +2452,33 @@ mysql_execute_command(THD *thd)
* allow SET and SHOW queries
*/
if (thd->variables.wsrep_on && !thd->wsrep_applier && !wsrep_ready &&
- lex->sql_command != SQLCOM_SET_OPTION &&
- !is_show_query(lex->sql_command))
- {
+ lex->sql_command != SQLCOM_SET_OPTION &&
+ !is_show_query(lex->sql_command))
+ {
+#if DIRTY_HACK
+ /* Dirty hack for lp:1002714 - trying to recognize mysqldump connection
+ * and allow it to continue. Actuall mysqldump_magic_str may be longer
+ * and is obviously version dependent and may be issued by any client
+ * connection after which connection becomes non-replicating. */
+ static char const mysqldump_magic_str[]=
+"SELECT LOGFILE_GROUP_NAME, FILE_NAME, TOTAL_EXTENTS, INITIAL_SIZE, ENGINE, EXTRA FROM INFORMATION_SCHEMA.FILES WHERE FILE_TYPE = 'UNDO LOG' AND FILE_NAME IS NOT NULL";
+ static const size_t mysqldump_magic_str_len= sizeof(mysqldump_magic_str) -1;
+ if (SQLCOM_SELECT != lex->sql_command ||
+ thd->query_length() < mysqldump_magic_str_len ||
+ strncmp(thd->query(), mysqldump_magic_str, mysqldump_magic_str_len))
+ {
+#endif /* DIRTY_HACK */
my_error(ER_UNKNOWN_COM_ERROR, MYF(0),
"WSREP has not yet prepared node for application use");
goto error;
+#if DIRTY_HACK
+ }
+ else
+ {
+ /* mysqldump connection, allow all further queries to pass */
+ thd->variables.wsrep_on= FALSE;
+ }
+#endif /* DIRTY_HACK */
}
}
#endif /* WITH_WSREP */
@@ -3074,7 +3100,7 @@ end_with_restore_list:
goto error;
#else
{
- if (check_global_access(thd, SUPER_ACL))
+ if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL))
goto error;
res = show_binlogs(thd);
break;
@@ -3348,8 +3374,9 @@ end_with_restore_list:
break;
#ifdef WITH_WSREP
if (lex->sql_command == SQLCOM_INSERT_SELECT &&
- thd->wsrep_consistency_check)
+ thd->wsrep_consistency_check == CONSISTENCY_CHECK_DECLARED)
{
+ thd->wsrep_consistency_check = CONSISTENCY_CHECK_RUNNING;
WSREP_TO_ISOLATION_BEGIN(first_table->db, first_table->table_name, NULL);
}
@@ -4978,7 +5005,7 @@ finish:
close_thread_tables(thd);
#ifdef WITH_WSREP
WSREP_TO_ISOLATION_END
- thd->wsrep_consistency_check= FALSE;
+ thd->wsrep_consistency_check= NO_CONSISTENCY_CHECK;
#endif /* WITH_WSREP */
thd_proc_info(thd, 0);
@@ -6669,6 +6696,7 @@ TABLE_LIST *st_select_lex::end_nested_join(THD *thd)
embedded->embedding= embedding;
join_list->push_front(embedded);
ptr= embedded;
+ embedded->lifted= 1;
}
else if (nested_join->join_list.elements == 0)
{
@@ -8408,11 +8436,16 @@ int wsrep_abort_thd(void *bf_thd_ptr, void *victim_thd_ptr, my_bool signal)
THD *bf_thd = (THD *) bf_thd_ptr;
DBUG_ENTER("wsrep_abort_thd");
- if (WSREP(bf_thd) && victim_thd)
+ if ( (WSREP(bf_thd) ||
+ (WSREP_ON && bf_thd->wsrep_exec_mode == TOTAL_ORDER)) && victim_thd)
{
WSREP_DEBUG("wsrep_abort_thd, by: %llu, victim: %llu", (bf_thd) ?
(long long)bf_thd->real_id : 0, (long long)victim_thd->real_id);
ha_wsrep_abort_transaction(bf_thd, victim_thd, signal);
+ }
+ else
+ {
+ WSREP_DEBUG("wsrep_abort_thd not effective: %p %p", bf_thd, victim_thd);
}
DBUG_RETURN(1);
diff --git a/sql/sql_profile.h b/sql/sql_profile.h
index 2e93912fb25..7705f6ca476 100644
--- a/sql/sql_profile.h
+++ b/sql/sql_profile.h
@@ -287,5 +287,5 @@ public:
int fill_statistics_info(THD *thd, TABLE_LIST *tables, Item *cond);
};
-# endif /* HAVE_PROFILING */
+# endif /* ENABLED_PROFILING */
#endif /* _SQL_PROFILE_H */
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index 816ae57c828..a85e0f2a997 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -1897,6 +1897,8 @@ bool mysql_show_binlog_events(THD* thd)
File file = -1;
MYSQL_BIN_LOG *binary_log= NULL;
int old_max_allowed_packet= thd->variables.max_allowed_packet;
+ LOG_INFO linfo;
+
DBUG_ENTER("mysql_show_binlog_events");
Log_event::init_show_field_list(&field_list);
@@ -1939,7 +1941,6 @@ bool mysql_show_binlog_events(THD* thd)
char search_file_name[FN_REFLEN], *name;
const char *log_file_name = lex_mi->log_file_name;
mysql_mutex_t *log_lock = binary_log->get_log_lock();
- LOG_INFO linfo;
Log_event* ev;
unit->set_limit(thd->lex->current_select);
@@ -2036,6 +2037,8 @@ bool mysql_show_binlog_events(THD* thd)
mysql_mutex_unlock(log_lock);
}
+ // Check that linfo is still on the function scope.
+ DEBUG_SYNC(thd, "after_show_binlog_events");
ret= FALSE;
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 223e5c44fcf..0ed351b720c 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -1,5 +1,5 @@
-/* Copyright (c) 2000, 2010 Oracle and/or its affiliates.
- 2009-2011 Monty Program Ab
+/* Copyright (c) 2000, 2012 Oracle and/or its affiliates.
+ Copyright (c) 2009, 2012, Monty Program Ab
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -271,6 +271,8 @@ Item_equal *find_item_equal(COND_EQUAL *cond_equal, Field *field,
bool *inherited_fl);
JOIN_TAB *first_depth_first_tab(JOIN* join);
JOIN_TAB *next_depth_first_tab(JOIN* join, JOIN_TAB* tab);
+JOIN_TAB *first_breadth_first_tab(JOIN *join);
+JOIN_TAB *next_breadth_first_tab(JOIN *join, JOIN_TAB *tab);
/**
This handles SELECT with and without UNION.
@@ -987,7 +989,10 @@ JOIN::optimize()
}
eval_select_list_used_tables();
-
+
+ if (optimize_constant_subqueries())
+ DBUG_RETURN(1);
+
table_count= select_lex->leaf_tables.elements;
if (setup_ftfuncs(select_lex)) /* should be after having->fix_fields */
@@ -1274,6 +1279,12 @@ JOIN::optimize()
{
conds= substitute_for_best_equal_field(NO_PARTICULAR_TAB, conds,
cond_equal, map2table);
+ if (thd->is_error())
+ {
+ error= 1;
+ DBUG_PRINT("error",("Error from substitute_for_best_equal"));
+ DBUG_RETURN(1);
+ }
conds->update_used_tables();
DBUG_EXECUTE("where",
print_where(conds,
@@ -1294,6 +1305,12 @@ JOIN::optimize()
*tab->on_expr_ref,
tab->cond_equal,
map2table);
+ if (thd->is_error())
+ {
+ error= 1;
+ DBUG_PRINT("error",("Error from substitute_for_best_equal"));
+ DBUG_RETURN(1);
+ }
(*tab->on_expr_ref)->update_used_tables();
}
}
@@ -6615,6 +6632,32 @@ void JOIN::get_prefix_cost_and_fanout(uint n_tables,
/**
+ Estimate the number of rows that query execution will read.
+
+ @todo This is a very pessimistic upper bound. Use join selectivity
+ when available to produce a more realistic number.
+*/
+
+double JOIN::get_examined_rows()
+{
+ ha_rows examined_rows;
+ double prev_fanout= 1;
+ JOIN_TAB *tab= first_breadth_first_tab(this);
+ JOIN_TAB *prev_tab= tab;
+
+ examined_rows= tab->get_examined_rows();
+
+ while ((tab= next_breadth_first_tab(this, tab)))
+ {
+ prev_fanout *= prev_tab->records_read;
+ examined_rows+= tab->get_examined_rows() * prev_fanout;
+ prev_tab= tab;
+ }
+ return examined_rows;
+}
+
+
+/**
Find a good, possibly optimal, query execution plan (QEP) by a possibly
exhaustive search.
@@ -8061,36 +8104,15 @@ JOIN::make_simple_join(JOIN *parent, TABLE *temp_table)
row_limit= unit->select_limit_cnt;
do_send_rows= row_limit ? 1 : 0;
- join_tab->use_join_cache= FALSE;
- join_tab->cache=0; /* No caching */
+ bzero(join_tab, sizeof(JOIN_TAB));
join_tab->table=temp_table;
- join_tab->cache_select= 0;
- join_tab->select=0;
- join_tab->select_cond= 0; // Avoid valgrind warning
join_tab->set_select_cond(NULL, __LINE__);
- join_tab->quick=0;
join_tab->type= JT_ALL; /* Map through all records */
join_tab->keys.init();
join_tab->keys.set_all(); /* test everything in quick */
- join_tab->info=0;
- join_tab->on_expr_ref=0;
- join_tab->last_inner= 0;
- join_tab->first_unmatched= 0;
join_tab->ref.key = -1;
- join_tab->not_used_in_distinct=0;
join_tab->read_first_record= join_init_read_record;
- join_tab->preread_init_done= FALSE;
join_tab->join= this;
- join_tab->ref.key_parts= 0;
- join_tab->keep_current_rowid= FALSE;
- join_tab->flush_weedout_table= join_tab->check_weed_out_table= NULL;
- join_tab->do_firstmatch= NULL;
- join_tab->loosescan_match_tab= NULL;
- join_tab->emb_sj_nest= NULL;
- join_tab->pre_idx_push_select_cond= NULL;
- join_tab->bush_root_tab= NULL;
- join_tab->bush_children= NULL;
- join_tab->last_leaf_in_bush= FALSE;
bzero((char*) &join_tab->read_record,sizeof(join_tab->read_record));
temp_table->status=0;
temp_table->null_row=0;
@@ -10288,6 +10310,51 @@ double JOIN_TAB::scan_time()
return res;
}
+
+/**
+ Estimate the number of rows that a an access method will read from a table.
+
+ @todo: why not use JOIN_TAB::found_records
+*/
+
+ha_rows JOIN_TAB::get_examined_rows()
+{
+ ha_rows examined_rows;
+
+ if (select && select->quick)
+ examined_rows= select->quick->records;
+ else if (type == JT_NEXT || type == JT_ALL ||
+ type == JT_HASH || type ==JT_HASH_NEXT)
+ {
+ if (limit)
+ {
+ /*
+ @todo This estimate is wrong, a LIMIT query may examine much more rows
+ than the LIMIT itself.
+ */
+ examined_rows= limit;
+ }
+ else
+ {
+ if (table->is_filled_at_execution())
+ examined_rows= records;
+ else
+ {
+ /*
+ handler->info(HA_STATUS_VARIABLE) has been called in
+ make_join_statistics()
+ */
+ examined_rows= table->file->stats.records;
+ }
+ }
+ }
+ else
+ examined_rows= (ha_rows) records_read;
+
+ return examined_rows;
+}
+
+
/**
Initialize the join_tab before reading.
Currently only derived table/view materialization is done here.
@@ -10591,6 +10658,22 @@ void JOIN::cleanup(bool full)
tmp_join->tmp_table_param.save_copy_field= 0;
}
tmp_table_param.cleanup();
+
+ if (!join_tab)
+ {
+ List_iterator<TABLE_LIST> li(*join_list);
+ TABLE_LIST *table_ref;
+ while ((table_ref= li++))
+ {
+ if (table_ref->table &&
+ table_ref->jtbm_subselect &&
+ table_ref->jtbm_subselect->is_jtbm_const_tab)
+ {
+ free_tmp_table(thd, table_ref->table);
+ table_ref->table= NULL;
+ }
+ }
+ }
}
DBUG_VOID_RETURN;
}
@@ -11267,9 +11350,9 @@ static bool check_simple_equality(Item *left_item, Item *right_item,
if (!item)
{
Item_func_eq *eq_item;
- if ((eq_item= new Item_func_eq(orig_left_item, orig_right_item)))
+ if (!(eq_item= new Item_func_eq(orig_left_item, orig_right_item)) ||
+ eq_item->set_cmp_func())
return FALSE;
- eq_item->set_cmp_func();
eq_item->quick_fix_field();
item= eq_item;
}
@@ -11362,9 +11445,9 @@ static bool check_row_equality(THD *thd, Item *left_row, Item_row *right_row,
if (!is_converted)
{
Item_func_eq *eq_item;
- if (!(eq_item= new Item_func_eq(left_item, right_item)))
+ if (!(eq_item= new Item_func_eq(left_item, right_item)) ||
+ eq_item->set_cmp_func())
return FALSE;
- eq_item->set_cmp_func();
eq_item->quick_fix_field();
eq_list->push_back(eq_item);
}
@@ -12050,9 +12133,8 @@ Item *eliminate_item_equal(COND *cond, COND_EQUAL *upper_levels,
eq_item= new Item_func_eq(field_item->real_item(), head_item);
- if (!eq_item)
+ if (!eq_item || eq_item->set_cmp_func())
return 0;
- eq_item->set_cmp_func();
eq_item->quick_fix_field();
}
current_sjm= field_sjm;
@@ -12139,7 +12221,7 @@ Item *eliminate_item_equal(COND *cond, COND_EQUAL *upper_levels,
Item_equal::get_first() for details.
@return
- The transformed condition
+ The transformed condition, or NULL in case of error
*/
static COND* substitute_for_best_equal_field(JOIN_TAB *context_tab,
@@ -18594,8 +18676,6 @@ check_reverse_order:
join_read_first:join_read_last;
tab->type=JT_NEXT; // Read with index_first(), index_next()
- if (table->covering_keys.is_set(best_key) && ! table->key_read)
- table->enable_keyread();
if (tab->pre_idx_push_select_cond)
{
tab->set_cond(tab->pre_idx_push_select_cond);
@@ -18606,6 +18686,7 @@ check_reverse_order:
orig_cond= 0;
orig_cond_saved= false;
}
+
table->file->ha_index_or_rnd_end();
if (tab->join->select_options & SELECT_DESCRIBE)
{
@@ -18613,6 +18694,7 @@ check_reverse_order:
tab->ref.key_parts= 0;
if (select_limit < table->file->stats.records)
tab->limit= select_limit;
+ table->disable_keyread();
}
}
else if (tab->type != JT_ALL)
@@ -20214,6 +20296,8 @@ copy_fields(TMP_TABLE_PARAM *param)
Copy_field *ptr=param->copy_field;
Copy_field *end=param->copy_field_end;
+ DBUG_ASSERT((ptr != NULL && end >= ptr) || (ptr == NULL && end == NULL));
+
for (; ptr != end; ptr++)
(*ptr->do_copy)(ptr);
@@ -21354,10 +21438,17 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
}
else
{
- TABLE_LIST *real_table= table->pos_in_table_list;
- item_list.push_back(new Item_string(real_table->alias,
- strlen(real_table->alias),
- cs));
+ TABLE_LIST *real_table= table->pos_in_table_list;
+ /*
+ Internal temporary tables have no corresponding table reference
+ object. Such a table may appear in EXPLAIN when a subquery that needs
+ a temporary table has been executed, and JOIN::exec replaced the
+ original JOIN with a plan to access the data in the temp table
+ (made by JOIN::make_simple_join).
+ */
+ const char *tab_name= real_table ? real_table->alias :
+ "internal_tmp_table";
+ item_list.push_back(new Item_string(tab_name, strlen(tab_name), cs));
}
/* "partitions" column */
if (join->thd->lex->describe & DESCRIBE_PARTITIONS)
@@ -21515,32 +21606,8 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
}
else
{
- ha_rows examined_rows;
- if (tab->select && tab->select->quick)
- examined_rows= tab->select->quick->records;
- else if (tab->type == JT_NEXT || tab->type == JT_ALL || is_hj)
- {
- if (tab->limit)
- examined_rows= tab->limit;
- else
- {
- if (tab->table->is_filled_at_execution())
- {
- examined_rows= tab->records;
- }
- else
- {
- /*
- handler->info(HA_STATUS_VARIABLE) has been called in
- make_join_statistics()
- */
- examined_rows= tab->table->file->stats.records;
- }
- }
- }
- else
- examined_rows=(ha_rows)tab->records_read;
-
+ ha_rows examined_rows= tab->get_examined_rows();
+
item_list.push_back(new Item_int((longlong) (ulonglong) examined_rows,
MY_INT64_NUM_DECIMAL_DIGITS));
diff --git a/sql/sql_select.h b/sql/sql_select.h
index c4553148cc6..0ed976ac36a 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -512,6 +512,7 @@ typedef struct st_join_table {
return (is_hash_join_key_no(key) ? hj_key : table->key_info+key);
}
double scan_time();
+ ha_rows get_examined_rows();
bool preread_init();
bool is_sjm_nest() { return test(bush_children); }
@@ -1281,6 +1282,7 @@ public:
bool alloc_func_list();
bool flatten_subqueries();
bool optimize_unflattened_subqueries();
+ bool optimize_constant_subqueries();
bool make_sum_func_list(List<Item> &all_fields, List<Item> &send_fields,
bool before_group_by, bool recompute= FALSE);
@@ -1380,6 +1382,7 @@ public:
void get_prefix_cost_and_fanout(uint n_tables,
double *read_time_arg,
double *record_count_arg);
+ double get_examined_rows();
/* defined in opt_subselect.cc */
bool transform_max_min_subquery();
/* True if this JOIN is a subquery under an IN predicate. */
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 82647df6756..5eb8c8da039 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2012, Oracle and/or its affiliates.
- Copyright (c) 2009, 2011, Monty Program Ab
+ Copyright (c) 2009, 2012, Monty Program Ab
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index ef05a472ab7..04cf6a479ec 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -238,10 +238,17 @@ uint explain_filename(THD* thd,
{
part_name_len= tmp_p - part_name - 1;
subpart_name= tmp_p + 3;
+ tmp_p+= 3;
+ }
+ else if ((tmp_p[1] == 'Q' || tmp_p[1] == 'q') &&
+ (tmp_p[2] == 'L' || tmp_p[2] == 'l') &&
+ tmp_p[3] == '-')
+ {
+ name_type= TEMP;
+ tmp_p+= 4; /* sql- prefix found */
}
else
res= 2;
- tmp_p+= 3;
break;
case 'T':
case 't':
@@ -1937,6 +1944,49 @@ bool mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists,
/**
+ Find the comment in the query.
+ That's auxiliary function to be used handling DROP TABLE [comment].
+
+ @param thd Thread handler
+ @param comment_pos How many characters to skip before the comment.
+ Can be either 9 for DROP TABLE or
+ 17 for DROP TABLE IF EXISTS
+ @param comment_start returns the beginning of the comment if found.
+
+ @retval 0 no comment found
+ @retval >0 the lenght of the comment found
+
+*/
+static uint32 comment_length(THD *thd, uint32 comment_pos,
+ const char **comment_start)
+{
+ const char *query= thd->query();
+ const char *query_end= query + thd->query_length();
+ const uchar *const state_map= thd->charset()->state_map;
+
+ for (; query < query_end; query++)
+ {
+ if (state_map[*query] == MY_LEX_SKIP)
+ continue;
+ if (comment_pos-- == 0)
+ break;
+ }
+ if (query > query_end - 3 /* comment can't be shorter than 4 */ ||
+ state_map[*query] != MY_LEX_LONG_COMMENT || query[1] != '*')
+ return 0;
+
+ *comment_start= query;
+
+ for (query+= 3; query < query_end; query++)
+ {
+ if (query[-1] == '*' && query[0] == '/')
+ return query - *comment_start + 1;
+ }
+ return 0;
+}
+
+
+/**
Execute the drop of a normal or temporary table.
@param thd Thread handler
@@ -2011,11 +2061,20 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
{
if (!drop_temporary)
{
+ const char *comment_start;
+ uint32 comment_len;
+
built_query.set_charset(system_charset_info);
if (if_exists)
built_query.append("DROP TABLE IF EXISTS ");
else
built_query.append("DROP TABLE ");
+
+ if ((comment_len= comment_length(thd, if_exists ? 17:9, &comment_start)))
+ {
+ built_query.append(comment_start, comment_len);
+ built_query.append(" ");
+ }
}
if (thd->is_current_stmt_binlog_format_row() || if_exists)
@@ -6935,21 +6994,47 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
(void) quick_rm_table(new_db_type, new_db, tmp_name, FN_IS_TMP);
}
else if (mysql_rename_table(new_db_type, new_db, tmp_name, new_db,
- new_alias, FN_FROM_IS_TMP) ||
- ((new_name != table_name || new_db != db) && // we also do rename
- (need_copy_table != ALTER_TABLE_METADATA_ONLY ||
- mysql_rename_table(save_old_db_type, db, table_name, new_db,
- new_alias, NO_FRM_RENAME)) &&
- Table_triggers_list::change_table_name(thd, db, alias, table_name,
- new_db, new_alias)))
+ new_alias, FN_FROM_IS_TMP))
{
/* Try to get everything back. */
- error=1;
- (void) quick_rm_table(new_db_type,new_db,new_alias, 0);
+ error= 1;
(void) quick_rm_table(new_db_type, new_db, tmp_name, FN_IS_TMP);
(void) mysql_rename_table(old_db_type, db, old_name, db, alias,
FN_FROM_IS_TMP);
}
+ else if (new_name != table_name || new_db != db)
+ {
+ if (need_copy_table == ALTER_TABLE_METADATA_ONLY &&
+ mysql_rename_table(save_old_db_type, db, table_name, new_db,
+ new_alias, NO_FRM_RENAME))
+ {
+ /* Try to get everything back. */
+ error= 1;
+ (void) quick_rm_table(new_db_type, new_db, new_alias, 0);
+ (void) mysql_rename_table(old_db_type, db, old_name, db, alias,
+ FN_FROM_IS_TMP);
+ }
+ else if (Table_triggers_list::change_table_name(thd, db, alias,
+ table_name, new_db,
+ new_alias))
+ {
+ /* Try to get everything back. */
+ error= 1;
+ (void) quick_rm_table(new_db_type, new_db, new_alias, 0);
+ (void) mysql_rename_table(old_db_type, db, old_name, db,
+ alias, FN_FROM_IS_TMP);
+ /*
+ If we were performing "fast"/in-place ALTER TABLE we also need
+ to restore old name of table in storage engine as a separate
+ step, as the above rename affects .FRM only.
+ */
+ if (need_copy_table == ALTER_TABLE_METADATA_ONLY)
+ {
+ (void) mysql_rename_table(save_old_db_type, new_db, new_alias,
+ db, table_name, NO_FRM_RENAME);
+ }
+ }
+ }
if (! error)
(void) quick_rm_table(old_db_type, db, old_name, FN_IS_TMP);
@@ -7369,7 +7454,10 @@ err:
thd_progress_next_stage(thd);
if (error > 0)
+ {
+ /* We are going to drop the temporary table */
to->file->extra(HA_EXTRA_PREPARE_FOR_DROP);
+ }
if (errpos >= 3 && to->file->ha_end_bulk_insert() && error <= 0)
{
to->file->print_error(my_errno,MYF(0));
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 53abf1bbe15..2a24f6d2bdf 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -368,7 +368,7 @@ int mysql_update(THD *thd,
}
/* Apply the IN=>EXISTS transformation to all subqueries and optimize them. */
- if (select_lex->optimize_unflattened_subqueries())
+ if (select_lex->optimize_unflattened_subqueries(false))
DBUG_RETURN(TRUE);
if (select_lex->inner_refs_list.elements &&
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index e968dd12ca0..4e3629080be 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -9823,7 +9823,9 @@ table_factor:
lex->nest_level--;
}
else if (($3->select_lex &&
- $3->select_lex->master_unit()->is_union()) || $5)
+ $3->select_lex->master_unit()->is_union() &&
+ ($3->select_lex->master_unit()->first_select() ==
+ $3->select_lex || !$3->lifted)) || $5)
{
/* simple nested joins cannot have aliases or unions */
my_parse_error(ER(ER_SYNTAX_ERROR));
diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc
index 49fc526a16f..b7e5feaa8a2 100644
--- a/sql/sys_vars.cc
+++ b/sql/sys_vars.cc
@@ -2246,7 +2246,7 @@ static char *system_time_zone_ptr;
static Sys_var_charptr Sys_system_time_zone(
"system_time_zone", "The server system time zone",
READ_ONLY GLOBAL_VAR(system_time_zone_ptr), NO_CMD_LINE,
- IN_FS_CHARSET, DEFAULT(system_time_zone));
+ IN_SYSTEM_CHARSET, DEFAULT(system_time_zone));
static Sys_var_ulong Sys_table_def_size(
"table_definition_cache",
@@ -3603,12 +3603,13 @@ static Sys_var_charptr Sys_wsrep_cluster_name(
ON_CHECK(wsrep_cluster_name_check),
ON_UPDATE(wsrep_cluster_name_update));
+static PolyLock_mutex PLock_wsrep_slave_threads(&LOCK_wsrep_slave_threads);
static Sys_var_charptr Sys_wsrep_cluster_address (
"wsrep_cluster_address", "Address to initially connect to cluster",
GLOBAL_VAR(wsrep_cluster_address),
CMD_LINE(REQUIRED_ARG, OPT_WSREP_CLUSTER_ADDRESS),
IN_FS_CHARSET, DEFAULT(wsrep_cluster_address),
- NO_MUTEX_GUARD, NOT_IN_BINLOG,
+ &PLock_wsrep_slave_threads, NOT_IN_BINLOG,
ON_CHECK(wsrep_cluster_address_check),
ON_UPDATE(wsrep_cluster_address_update));
@@ -3637,7 +3638,10 @@ static Sys_var_charptr Sys_wsrep_node_incoming_address(
static Sys_var_ulong Sys_wsrep_slave_threads(
"wsrep_slave_threads", "Number of slave appliers to launch",
GLOBAL_VAR(wsrep_slave_threads), CMD_LINE(REQUIRED_ARG),
- VALID_RANGE(1, 512), DEFAULT(1), BLOCK_SIZE(1));
+ VALID_RANGE(1, 512), DEFAULT(1), BLOCK_SIZE(1),
+ &PLock_wsrep_slave_threads, NOT_IN_BINLOG,
+ ON_CHECK(wsrep_slave_threads_check),
+ ON_UPDATE(wsrep_slave_threads_update));
static Sys_var_charptr Sys_wsrep_dbug_option(
"wsrep_dbug_option", "DBUG options to provider library",
@@ -3674,7 +3678,7 @@ static Sys_var_mybool Sys_wsrep_drupal_282555_workaround(
CMD_LINE(OPT_ARG), DEFAULT(FALSE));
static Sys_var_charptr sys_wsrep_sst_method(
- "wsrep_sst_method", "Snapshot transfer method",
+ "wsrep_sst_method", "State snapshot transfer method",
GLOBAL_VAR(wsrep_sst_method),CMD_LINE(REQUIRED_ARG),
IN_FS_CHARSET, DEFAULT(wsrep_sst_method), NO_MUTEX_GUARD, NOT_IN_BINLOG,
ON_CHECK(wsrep_sst_method_check),
@@ -3704,6 +3708,12 @@ static Sys_var_charptr Sys_wsrep_sst_donor(
ON_CHECK(wsrep_sst_donor_check),
ON_UPDATE(wsrep_sst_donor_update));
+static Sys_var_mybool Sys_wsrep_sst_donor_rejects_queries(
+ "wsrep_sst_donor_rejects_queries", "Reject client queries "
+ "when donating state snapshot transfer",
+ GLOBAL_VAR(wsrep_sst_donor_rejects_queries),
+ CMD_LINE(OPT_ARG), DEFAULT(FALSE));
+
static Sys_var_mybool Sys_wsrep_on (
"wsrep_on", "To enable wsrep replication ",
SESSION_VAR(wsrep_on),
@@ -3971,4 +3981,9 @@ static Sys_var_ulong Sys_debug_binlog_fsync_sleep(
CMD_LINE(REQUIRED_ARG),
VALID_RANGE(0, UINT_MAX), DEFAULT(0), BLOCK_SIZE(1));
#endif
-
+static Sys_var_harows Sys_expensive_subquery_limit(
+ "expensive_subquery_limit",
+ "The maximum number of rows a subquery may examine in order to be "
+ "executed during optimization and used for constant optimization",
+ SESSION_VAR(expensive_subquery_limit), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(0, HA_POS_ERROR), DEFAULT(100), BLOCK_SIZE(1));
diff --git a/sql/table.cc b/sql/table.cc
index 40304dc6fdc..b8161093e9a 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -1439,25 +1439,33 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
{
/*
Get virtual column data stored in the .frm file as follows:
- byte 1 = 1 (always 1 to allow for future extensions)
+ byte 1 = 1 | 2
byte 2 = sql_type
byte 3 = flags (as of now, 0 - no flags, 1 - field is physically stored)
- byte 4-... = virtual column expression (text data)
+ [byte 4] = optional interval_id for sql_type (only if byte 1 == 2)
+ next byte ... = virtual column expression (text data)
*/
vcol_info= new Virtual_column_info();
- if ((uint)vcol_screen_pos[0] != 1)
+ bool opt_interval_id= (uint)vcol_screen_pos[0] == 2;
+ field_type= (enum_field_types) (uchar) vcol_screen_pos[1];
+ if (opt_interval_id)
+ interval_nr= (uint)vcol_screen_pos[3];
+ else if ((uint)vcol_screen_pos[0] != 1)
{
error= 4;
goto err;
}
- field_type= (enum_field_types) (uchar) vcol_screen_pos[1];
fld_stored_in_db= (bool) (uint) vcol_screen_pos[2];
- vcol_expr_length= vcol_info_length-(uint)FRM_VCOL_HEADER_SIZE;
+ vcol_expr_length= vcol_info_length -
+ (uint)(FRM_VCOL_HEADER_SIZE(opt_interval_id));
if (!(vcol_info->expr_str.str=
(char *)memdup_root(&share->mem_root,
- vcol_screen_pos+(uint)FRM_VCOL_HEADER_SIZE,
+ vcol_screen_pos +
+ (uint) FRM_VCOL_HEADER_SIZE(opt_interval_id),
vcol_expr_length)))
goto err;
+ if (opt_interval_id)
+ interval_nr= (uint) vcol_screen_pos[3];
vcol_info->expr_str.length= vcol_expr_length;
vcol_screen_pos+= vcol_info_length;
share->vfields++;
@@ -4536,7 +4544,14 @@ bool TABLE_LIST::check_single_table(TABLE_LIST **table_arg,
tbl;
tbl= tbl->next_local)
{
- if (tbl->table)
+ /*
+ Merged view has also temporary table attached (in 5.2 if it has table
+ then it was real table), so we have filter such temporary tables out
+ by checking that it is not merged view
+ */
+ if (tbl->table &&
+ !(tbl->is_view() &&
+ tbl->is_merged_derived()))
{
if (tbl->table->map & map)
{
@@ -5985,7 +6000,13 @@ void TABLE::use_index(int key_to_save)
bool TABLE::is_filled_at_execution()
{
- return test(pos_in_table_list->jtbm_subselect ||
+ /*
+ pos_in_table_list == NULL for internal temporary tables because they
+ do not have a corresponding table reference. Such tables are filled
+ during execution.
+ */
+ return test(!pos_in_table_list ||
+ pos_in_table_list->jtbm_subselect ||
pos_in_table_list->is_active_sjm());
}
diff --git a/sql/table.h b/sql/table.h
index f3f9d5ac036..87affe984fc 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -1800,6 +1800,8 @@ struct TABLE_LIST
struct st_nested_join *nested_join; /* if the element is a nested join */
TABLE_LIST *embedding; /* nested join containing the table */
List<TABLE_LIST> *join_list;/* join list the table belongs to */
+ bool lifted; /* set to true when the table is moved to
+ the upper level at the parsing stage */
bool cacheable_table; /* stop PS caching */
/* used in multi-upd/views privilege check */
bool table_in_first_from_clause;
diff --git a/sql/unireg.cc b/sql/unireg.cc
index c9b0f91d9f7..edcfe9eb934 100644
--- a/sql/unireg.cc
+++ b/sql/unireg.cc
@@ -726,18 +726,19 @@ static bool pack_header(uchar *forminfo, enum legacy_db_type table_type,
}
if (field->vcol_info)
{
+ uint col_expr_maxlen= field->virtual_col_expr_maxlen();
tmp_len=
system_charset_info->cset->charpos(system_charset_info,
field->vcol_info->expr_str.str,
field->vcol_info->expr_str.str +
field->vcol_info->expr_str.length,
- VIRTUAL_COLUMN_EXPRESSION_MAXLEN);
+ col_expr_maxlen);
if (tmp_len < field->vcol_info->expr_str.length)
{
my_error(ER_WRONG_STRING_LENGTH, MYF(0),
field->vcol_info->expr_str.str,"VIRTUAL COLUMN EXPRESSION",
- (uint) VIRTUAL_COLUMN_EXPRESSION_MAXLEN);
+ col_expr_maxlen);
DBUG_RETURN(1);
}
/*
@@ -746,7 +747,7 @@ static bool pack_header(uchar *forminfo, enum legacy_db_type table_type,
expressions saved in the frm file for virtual columns.
*/
vcol_info_length+= field->vcol_info->expr_str.length+
- (uint)FRM_VCOL_HEADER_SIZE;
+ FRM_VCOL_HEADER_SIZE(field->interval!=NULL);
}
totlength+= field->length;
@@ -949,8 +950,9 @@ static bool pack_fields(File file, List<Create_field> &create_fields,
the additional data saved for the virtual field
*/
buff[12]= cur_vcol_expr_len= field->vcol_info->expr_str.length +
- (uint)FRM_VCOL_HEADER_SIZE;
- vcol_info_length+= cur_vcol_expr_len+(uint)FRM_VCOL_HEADER_SIZE;
+ FRM_VCOL_HEADER_SIZE(field->interval!=NULL);
+ vcol_info_length+= cur_vcol_expr_len +
+ FRM_VCOL_HEADER_SIZE(field->interval!=NULL);
buff[13]= (uchar) MYSQL_TYPE_VIRTUAL;
}
int2store(buff+15, field->comment.length);
@@ -1055,17 +1057,20 @@ static bool pack_fields(File file, List<Create_field> &create_fields,
{
/*
Pack each virtual field as follows:
- byte 1 = 1 (always 1 to allow for future extensions)
+ byte 1 = interval_id == 0 ? 1 : 2
byte 2 = sql_type
byte 3 = flags (as of now, 0 - no flags, 1 - field is physically stored)
- byte 4-... = virtual column expression (text data)
+ [byte 4] = possible interval_id for sql_type
+ next byte ... = virtual column expression (text data)
*/
if (field->vcol_info && field->vcol_info->expr_str.length)
{
- buff[0]= (uchar)1;
+ buff[0]= (uchar)(1 + test(field->interval_id));
buff[1]= (uchar) field->sql_type;
buff[2]= (uchar) field->stored_in_db;
- if (my_write(file, buff, 3, MYF_RW))
+ if (field->interval_id)
+ buff[3]= (uchar) field->interval_id;
+ if (my_write(file, buff, 3 + test(field->interval_id), MYF_RW))
DBUG_RETURN(1);
if (my_write(file,
(uchar*) field->vcol_info->expr_str.str,
diff --git a/sql/unireg.h b/sql/unireg.h
index f8317a89c8c..da510bb4e6d 100644
--- a/sql/unireg.h
+++ b/sql/unireg.h
@@ -161,12 +161,6 @@ typedef struct st_ha_create_information HA_CREATE_INFO;
#define DEFAULT_KEY_CACHE_NAME "default"
-/* The length of the header part for each virtual column in the .frm file */
-#define FRM_VCOL_HEADER_SIZE 3
-
-/* Maximum length of the defining expression for a virtual columns */
-#define VIRTUAL_COLUMN_EXPRESSION_MAXLEN 255 - FRM_VCOL_HEADER_SIZE
-
/* Include prototypes for unireg */
diff --git a/sql/wsrep_hton.cc b/sql/wsrep_hton.cc
index 49b3ea5c0bf..219e0e8a244 100644
--- a/sql/wsrep_hton.cc
+++ b/sql/wsrep_hton.cc
@@ -216,7 +216,7 @@ wsrep_run_wsrep_commit(
if (thd->wsrep_exec_mode != LOCAL_STATE) {
DBUG_RETURN(WSREP_TRX_OK);
}
- if (thd->wsrep_consistency_check) {
+ if (thd->wsrep_consistency_check == CONSISTENCY_CHECK_RUNNING) {
WSREP_DEBUG("commit for consistency check: %s", thd->query());
DBUG_RETURN(WSREP_TRX_OK);
}
diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc
index 0bf0c2294d3..a5d7134a201 100644
--- a/sql/wsrep_mysqld.cc
+++ b/sql/wsrep_mysqld.cc
@@ -326,15 +326,27 @@ out:
local_status.set(new_status, view);
}
+void wsrep_ready_set (my_bool x)
+{
+ WSREP_DEBUG("Setting wsrep_ready to %d", x);
+ if (mysql_mutex_lock (&LOCK_wsrep_ready)) abort();
+ if (wsrep_ready != x)
+ {
+ wsrep_ready= x;
+ mysql_cond_signal (&COND_wsrep_ready);
+ }
+ mysql_mutex_unlock (&LOCK_wsrep_ready);
+}
+
// Wait until wsrep has reached ready state
void wsrep_ready_wait ()
{
if (mysql_mutex_lock (&LOCK_wsrep_ready)) abort();
while (!wsrep_ready)
- {
- WSREP_INFO("Waiting to reach ready state");
- mysql_cond_wait (&COND_wsrep_ready, &LOCK_wsrep_ready);
- }
+ {
+ WSREP_INFO("Waiting to reach ready state");
+ mysql_cond_wait (&COND_wsrep_ready, &LOCK_wsrep_ready);
+ }
WSREP_INFO("ready state reached");
mysql_mutex_unlock (&LOCK_wsrep_ready);
}
@@ -1127,17 +1139,17 @@ void wsrep_to_isolation_end(THD *thd) {
}
}
-#define WSREP_MDL_LOG(severity, msg, req, gra) \
- WSREP_##severity( \
- "%s\n" \
- "request: (%lu \tseqno %lld \tmode %d \tQstate \t%d cmd %d %d \t%s)\n" \
- "granted: (%lu \tseqno %lld \tmode %d \tQstate \t%d cmd %d %d \t%s)", \
- msg, \
- req->thread_id, (long long)req->wsrep_trx_seqno, \
- req->wsrep_exec_mode, req->wsrep_query_state, \
- req->command, req->lex->sql_command, req->query(), \
- gra->thread_id, (long long)gra->wsrep_trx_seqno, \
- gra->wsrep_exec_mode, gra->wsrep_query_state, \
+#define WSREP_MDL_LOG(severity, msg, req, gra) \
+ WSREP_##severity( \
+ "%s\n" \
+ "request: (%lu \tseqno %lld \twsrep (%d, %d, %d) cmd %d %d \t%s)\n" \
+ "granted: (%lu \tseqno %lld \twsrep (%d, %d, %d) cmd %d %d \t%s)", \
+ msg, \
+ req->thread_id, (long long)req->wsrep_trx_seqno, \
+ req->wsrep_exec_mode, req->wsrep_query_state, req->wsrep_conflict_state, \
+ req->command, req->lex->sql_command, req->query(), \
+ gra->thread_id, (long long)gra->wsrep_trx_seqno, \
+ gra->wsrep_exec_mode, gra->wsrep_query_state, gra->wsrep_conflict_state, \
gra->command, gra->lex->sql_command, gra->query());
bool
@@ -1154,7 +1166,7 @@ wsrep_grant_mdl_exception(MDL_context *requestor_ctx,
request_thd->wsrep_exec_mode == REPL_RECV)
{
mysql_mutex_unlock(&request_thd->LOCK_wsrep_thd);
- WSREP_MDL_LOG(DEBUG, "MDL conflict", request_thd, granted_thd);
+ WSREP_MDL_LOG(DEBUG, "MDL conflict ", request_thd, granted_thd);
mysql_mutex_lock(&granted_thd->LOCK_wsrep_thd);
if (granted_thd->wsrep_exec_mode == TOTAL_ORDER ||
@@ -1183,7 +1195,7 @@ wsrep_grant_mdl_exception(MDL_context *requestor_ctx,
mysql_mutex_unlock(&granted_thd->LOCK_wsrep_thd);
wsrep_abort_thd((void*)request_thd, (void*)granted_thd, 1);
return FALSE;
- }
+ }
else
{
WSREP_MDL_LOG(DEBUG, "MDL conflict-> BF abort", request_thd, granted_thd);
diff --git a/sql/wsrep_mysqld.h b/sql/wsrep_mysqld.h
index ebea44c9151..968281a2c98 100644
--- a/sql/wsrep_mysqld.h
+++ b/sql/wsrep_mysqld.h
@@ -50,6 +50,7 @@ extern const char* wsrep_sst_method;
extern const char* wsrep_sst_receive_address;
extern char* wsrep_sst_auth;
extern const char* wsrep_sst_donor;
+extern my_bool wsrep_sst_donor_rejects_queries;
extern const char* wsrep_start_position;
extern long long wsrep_max_ws_size;
extern long wsrep_max_ws_rows;
@@ -129,6 +130,8 @@ extern void wsrep_sst_auth_init INIT_ARGS;
extern bool wsrep_sst_donor_check CHECK_ARGS;
extern bool wsrep_sst_donor_update UPDATE_ARGS;
+extern bool wsrep_slave_threads_check CHECK_ARGS;
+extern bool wsrep_slave_threads_update UPDATE_ARGS;
extern bool wsrep_init_first(); // initialize wsrep before storage
// engines (true) or after (false)
@@ -142,7 +145,8 @@ extern void wsrep_init_startup(bool first);
extern void wsrep_close_client_connections(my_bool wait_to_end);
extern void wsrep_close_applier(THD *thd);
-extern void wsrep_wait_appliers_close(THD *thd);
+extern void wsrep_wait_appliers_close(THD *thd);
+extern void wsrep_close_applier_threads(int count);
extern void wsrep_create_appliers(long threads = wsrep_slave_threads);
extern void wsrep_create_rollbacker();
extern void wsrep_kill_mysql(THD *thd);
@@ -250,6 +254,7 @@ extern long long wsrep_max_ws_size;
extern long wsrep_max_ws_rows;
extern int wsrep_to_isolation;
extern my_bool wsrep_certify_nonPK;
+extern mysql_mutex_t LOCK_wsrep_slave_threads;
extern PSI_mutex_key key_LOCK_wsrep_ready;
extern PSI_mutex_key key_COND_wsrep_ready;
@@ -263,6 +268,7 @@ extern PSI_mutex_key key_LOCK_wsrep_rollback;
extern PSI_cond_key key_COND_wsrep_rollback;
extern PSI_mutex_key key_LOCK_wsrep_replaying;
extern PSI_cond_key key_COND_wsrep_replaying;
+extern PSI_mutex_key key_LOCK_wsrep_slave_threads;
struct TABLE_LIST;
int wsrep_to_isolation_begin(THD *thd, char *db_, char *table_,
diff --git a/sql/wsrep_priv.h b/sql/wsrep_priv.h
index 4db8abf68de..32d0cebfd33 100644
--- a/sql/wsrep_priv.h
+++ b/sql/wsrep_priv.h
@@ -26,6 +26,8 @@
#include <pthread.h>
#include <cstdio>
+extern void wsrep_ready_set (my_bool x);
+
extern ssize_t wsrep_sst_prepare (void** msg);
extern int wsrep_sst_donate_cb (void* app_ctx,
void* recv_ctx,
@@ -38,8 +40,8 @@ extern int wsrep_sst_donate_cb (void* app_ctx,
extern size_t default_ip (char* buf, size_t buf_len);
extern size_t default_address(char* buf, size_t buf_len);
-extern wsrep_uuid_t local_uuid;
-extern wsrep_seqno_t local_seqno;
+extern wsrep_uuid_t local_uuid;
+extern wsrep_seqno_t local_seqno;
/*! SST thread signals init thread about sst completion */
extern void wsrep_sst_complete(wsrep_uuid_t* uuid, wsrep_seqno_t seqno, bool);
@@ -212,7 +214,7 @@ class thd
public:
- thd();
+ thd(my_bool wsrep_on);
~thd();
THD* const ptr;
};
diff --git a/sql/wsrep_sst.cc b/sql/wsrep_sst.cc
index 37779c4b96d..df39db3caa4 100644
--- a/sql/wsrep_sst.cc
+++ b/sql/wsrep_sst.cc
@@ -39,6 +39,8 @@ const char* wsrep_sst_donor = "";
// container for real auth string
static const char* sst_auth_real = NULL;
+my_bool wsrep_sst_donor_rejects_queries = FALSE;
+
static const char *sst_methods[] = {
"mysqldump",
"rsync",
@@ -597,6 +599,13 @@ static int sst_run_shell (const char* cmd_str, int max_tries)
return -ret;
}
+static void sst_reject_queries(my_bool close_conn)
+{
+ wsrep_ready_set (FALSE); // this will be resotred when donor becomes synced
+ WSREP_INFO("Rejecting client queries for the duration of SST.");
+ if (TRUE == close_conn) wsrep_close_client_connections(FALSE);
+}
+
static int sst_mysqldump_check_addr (const char* user, const char* pswd,
const char* host, const char* port)
{
@@ -654,6 +663,8 @@ static int sst_donate_mysqldump (const char* addr,
size_t cmd_len= 1024;
char cmd_str[cmd_len];
+ if (!bypass && wsrep_sst_donor_rejects_queries) sst_reject_queries(TRUE);
+
snprintf (cmd_str, cmd_len,
"wsrep_sst_mysqldump '%s' '%s' '%s' '%s' '%u' '%s' '%lld' '%d'",
user, pswd, host, port, mysqld_port, uuid_str, (long long)seqno,
@@ -781,7 +792,8 @@ static void* sst_donor_thread (void* a)
wsrep_uuid_t ret_uuid= WSREP_UUID_UNDEFINED;
wsrep_seqno_t ret_seqno= WSREP_SEQNO_UNDEFINED; // seqno of complete SST
- wsp::thd thd;
+ wsp::thd thd(FALSE); // we turn off wsrep_on for this THD so that it can
+ // operate with wsrep_ready == OFF
wsp::process proc(arg->cmd, "r");
err= proc.error();
@@ -880,6 +892,8 @@ static int sst_donate_other (const char* method,
return (ret < 0 ? ret : -EMSGSIZE);
}
+ if (!bypass && wsrep_sst_donor_rejects_queries) sst_reject_queries(FALSE);
+
pthread_t tmp;
sst_thread_arg arg(cmd_str);
mysql_mutex_lock (&arg.lock);
diff --git a/sql/wsrep_utils.cc b/sql/wsrep_utils.cc
index a6d7dcdbfc8..00919b3163e 100644
--- a/sql/wsrep_utils.cc
+++ b/sql/wsrep_utils.cc
@@ -289,13 +289,14 @@ process::wait ()
return err_;
}
-thd::thd () : init(), ptr(new THD)
+thd::thd (my_bool won) : init(), ptr(new THD)
{
if (ptr)
{
ptr->thread_stack= (char*) &ptr;
ptr->store_globals();
ptr->variables.option_bits&= ~OPTION_BIN_LOG; // disable binlog
+ ptr->variables.wsrep_on = won;
ptr->security_ctx->master_access= ~(ulong)0;
lex_start(ptr);
}
diff --git a/sql/wsrep_var.cc b/sql/wsrep_var.cc
index 66f0f05c006..fb5c3b339cd 100644
--- a/sql/wsrep_var.cc
+++ b/sql/wsrep_var.cc
@@ -35,6 +35,7 @@ const char* wsrep_node_name = glob_hostname;
static char node_address[256] = { 0, };
const char* wsrep_node_address = node_address;
ulong wsrep_OSU_method_options;
+static int wsrep_thread_change = 0;
int wsrep_init_vars()
{
@@ -419,6 +420,27 @@ void wsrep_node_address_init (const char* value)
wsrep_node_address = (value) ? my_strdup(value, MYF(0)) : NULL;
}
+bool wsrep_slave_threads_check (sys_var *self, THD* thd, set_var* var)
+{
+ mysql_mutex_lock(&LOCK_wsrep_slave_threads);
+ wsrep_thread_change = var->value->val_int() - wsrep_slave_threads;
+ mysql_mutex_unlock(&LOCK_wsrep_slave_threads);
+
+ return 0;
+}
+
+bool wsrep_slave_threads_update (sys_var *self, THD* thd, enum_var_type type)
+{
+ if (wsrep_thread_change > 0)
+ {
+ wsrep_create_appliers(wsrep_thread_change);
+ }
+ else if (wsrep_thread_change < 0)
+ {
+ wsrep_close_applier_threads(-wsrep_thread_change);
+ }
+ return false;
+}
/*
* Status variables stuff below
*/