summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/contributors.h1
-rw-r--r--sql/encryption.cc5
-rw-r--r--sql/event_db_repository.cc14
-rw-r--r--sql/field.cc2
-rw-r--r--sql/handler.cc4
-rw-r--r--sql/hostname.cc1
-rw-r--r--sql/item.cc96
-rw-r--r--sql/item.h6
-rw-r--r--sql/item_cmpfunc.cc45
-rw-r--r--sql/item_cmpfunc.h28
-rw-r--r--sql/item_func.cc3
-rw-r--r--sql/item_strfunc.cc30
-rw-r--r--sql/item_strfunc.h129
-rw-r--r--sql/item_subselect.cc25
-rw-r--r--sql/item_sum.h1
-rw-r--r--sql/log.cc19
-rw-r--r--sql/log_event.cc13
-rw-r--r--sql/log_event.h7
-rw-r--r--sql/mysqld.cc21
-rw-r--r--sql/net_serv.cc4
-rw-r--r--sql/opt_range.cc10
-rw-r--r--sql/parse_file.h6
-rw-r--r--sql/rpl_filter.cc3
-rw-r--r--sql/rpl_gtid.cc14
-rw-r--r--sql/rpl_parallel.cc1
-rw-r--r--sql/rpl_rli.cc4
-rw-r--r--sql/share/errmsg-utf8.txt2
-rw-r--r--sql/signal_handler.cc10
-rw-r--r--sql/slave.cc32
-rw-r--r--sql/sql_acl.cc2
-rw-r--r--sql/sql_admin.cc14
-rw-r--r--sql/sql_base.cc1
-rw-r--r--sql/sql_cache.cc3
-rw-r--r--sql/sql_cache.h9
-rw-r--r--sql/sql_class.cc2
-rw-r--r--sql/sql_class.h3
-rw-r--r--sql/sql_db.cc26
-rw-r--r--sql/sql_derived.cc1
-rw-r--r--sql/sql_lex.cc22
-rw-r--r--sql/sql_load.cc51
-rw-r--r--sql/sql_parse.cc21
-rw-r--r--sql/sql_plugin.cc148
-rw-r--r--sql/sql_prepare.cc19
-rw-r--r--sql/sql_repl.cc24
-rw-r--r--sql/sql_select.cc22
-rw-r--r--sql/sql_statistics.cc172
-rw-r--r--sql/sql_statistics.h14
-rw-r--r--sql/sql_table.cc13
-rw-r--r--sql/sql_time.cc5
-rw-r--r--sql/sql_yacc.yy1
-rw-r--r--sql/sys_vars.cc7
-rw-r--r--sql/table.cc9
-rw-r--r--sql/table.h10
-rw-r--r--sql/table_cache.cc2
-rw-r--r--sql/threadpool_common.cc106
-rw-r--r--sql/wsrep_applier.cc5
-rw-r--r--sql/wsrep_binlog.cc17
-rw-r--r--sql/wsrep_mysqld.cc2
-rw-r--r--sql/wsrep_sst.cc8
59 files changed, 875 insertions, 400 deletions
diff --git a/sql/contributors.h b/sql/contributors.h
index f52d3243453..0359ec54022 100644
--- a/sql/contributors.h
+++ b/sql/contributors.h
@@ -46,6 +46,7 @@ struct show_table_contributors_st show_table_contributors[]= {
{"Auttomattic", "https://automattic.com", "Bronze Sponsor of the MariaDB Foundation"},
{"Verkkokauppa.com", "https://virtuozzo.com", "Bronze Sponsor of the MariaDB Foundation"},
{"Virtuozzo", "https://virtuozzo.com/", "Bronze Sponsor of the MariaDB Foundation"},
+ {"Tencent Game DBA", "http://tencentdba.com/about/", "Bronze Sponsor of the MariaDB Foundation"},
/* Sponsors of important features */
{"Google", "USA", "Sponsoring encryption, parallel replication and GTID"},
diff --git a/sql/encryption.cc b/sql/encryption.cc
index 52aaef896dd..a92296e8b66 100644
--- a/sql/encryption.cc
+++ b/sql/encryption.cc
@@ -29,6 +29,10 @@ uint no_key(uint)
{
return ENCRYPTION_KEY_VERSION_INVALID;
}
+uint zero_size(uint,uint)
+{
+ return 0;
+}
static int ctx_init(void *ctx, const unsigned char* key, unsigned int klen,
const unsigned char* iv, unsigned int ivlen, int flags,
@@ -97,6 +101,7 @@ int finalize_encryption_plugin(st_plugin_int *plugin)
encryption_handler.encryption_key_get_func=
(uint (*)(uint, uint, uchar*, uint*))no_key;
encryption_handler.encryption_key_get_latest_version_func= no_key;
+ encryption_handler.encryption_ctx_size_func= zero_size;
if (plugin && plugin->plugin->deinit && plugin->plugin->deinit(NULL))
{
diff --git a/sql/event_db_repository.cc b/sql/event_db_repository.cc
index 9de55c44dd0..c96060cd5df 100644
--- a/sql/event_db_repository.cc
+++ b/sql/event_db_repository.cc
@@ -166,20 +166,8 @@ const TABLE_FIELD_TYPE event_table_fields[ET_FIELD_COUNT] =
static const TABLE_FIELD_DEF
event_table_def= {ET_FIELD_COUNT, event_table_fields, 0, (uint*) 0};
-class Event_db_intact : public Table_check_intact
-{
-protected:
- void report_error(uint, const char *fmt, ...)
- {
- va_list args;
- va_start(args, fmt);
- error_log_print(ERROR_LEVEL, fmt, args);
- va_end(args);
- }
-};
-
/** In case of an error, a message is printed to the error log. */
-static Event_db_intact table_intact;
+static Table_check_intact_log_error table_intact;
/**
diff --git a/sql/field.cc b/sql/field.cc
index 673bf22a4a5..8d53fca27d7 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -355,7 +355,7 @@ static enum_field_types field_types_merge_rules [FIELDTYPE_NUM][FIELDTYPE_NUM]=
//MYSQL_TYPE_NULL MYSQL_TYPE_TIMESTAMP
MYSQL_TYPE_LONGLONG, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_LONGLONG MYSQL_TYPE_INT24
- MYSQL_TYPE_LONGLONG, MYSQL_TYPE_LONG,
+ MYSQL_TYPE_LONGLONG, MYSQL_TYPE_LONGLONG,
//MYSQL_TYPE_DATE MYSQL_TYPE_TIME
MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_DATETIME MYSQL_TYPE_YEAR
diff --git a/sql/handler.cc b/sql/handler.cc
index 37e60f5c9bd..a91a97598d6 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -5926,6 +5926,10 @@ static int check_wsrep_max_ws_rows()
if (wsrep_max_ws_rows)
{
THD *thd= current_thd;
+
+ if (!WSREP(thd))
+ return 0;
+
thd->wsrep_affected_rows++;
if (thd->wsrep_exec_mode != REPL_RECV &&
thd->wsrep_affected_rows > wsrep_max_ws_rows)
diff --git a/sql/hostname.cc b/sql/hostname.cc
index a84aebdf3c8..e8d6780d095 100644
--- a/sql/hostname.cc
+++ b/sql/hostname.cc
@@ -28,7 +28,6 @@
#include "sql_priv.h"
#include "unireg.h" // SPECIAL_NO_HOST_CACHE
#include "hostname.h"
-#include "unireg.h"
#ifndef __WIN__
#include <netdb.h> // getservbyname, servent
#endif
diff --git a/sql/item.cc b/sql/item.cc
index 6d9274759e4..682f88317f1 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -2879,9 +2879,28 @@ void Item_field::fix_after_pullout(st_select_lex *new_parent, Item **ref)
if (context)
{
Name_resolution_context *ctx= new Name_resolution_context();
- ctx->outer_context= NULL; // We don't build a complete name resolver
- ctx->table_list= NULL; // We rely on first_name_resolution_table instead
+ if (context->select_lex == new_parent)
+ {
+ /*
+ This field was pushed in then pulled out
+ (for example left part of IN)
+ */
+ ctx->outer_context= context->outer_context;
+ }
+ else if (context->outer_context)
+ {
+ /* just pull to the upper context */
+ ctx->outer_context= context->outer_context->outer_context;
+ }
+ else
+ {
+ /* No upper context (merging Derived/VIEW where context chain ends) */
+ ctx->outer_context= NULL;
+ }
+ ctx->table_list= context->first_name_resolution_table;
ctx->select_lex= new_parent;
+ if (context->select_lex == NULL)
+ ctx->select_lex= NULL;
ctx->first_name_resolution_table= context->first_name_resolution_table;
ctx->last_name_resolution_table= context->last_name_resolution_table;
ctx->error_processor= context->error_processor;
@@ -4710,8 +4729,6 @@ static Item** find_field_in_group_list(Item *find_item, ORDER *group_list)
const char *field_name;
ORDER *found_group= NULL;
int found_match_degree= 0;
- Item_ident *cur_field;
- int cur_match_degree= 0;
char name_buff[SAFE_NAME_LEN+1];
if (find_item->type() == Item::FIELD_ITEM ||
@@ -4736,54 +4753,70 @@ static Item** find_field_in_group_list(Item *find_item, ORDER *group_list)
for (ORDER *cur_group= group_list ; cur_group ; cur_group= cur_group->next)
{
- if ((*(cur_group->item))->real_item()->type() == Item::FIELD_ITEM)
+ int cur_match_degree= 0;
+
+ /* SELECT list element with explicit alias */
+ if ((*(cur_group->item))->name &&
+ !(*(cur_group->item))->is_autogenerated_name &&
+ !my_strcasecmp(system_charset_info,
+ (*(cur_group->item))->name, field_name))
{
- cur_field= (Item_ident*) *cur_group->item;
- cur_match_degree= 0;
-
- DBUG_ASSERT(cur_field->field_name != 0);
+ ++cur_match_degree;
+ }
+ /* Reference on the field or view/derived field. */
+ else if ((*(cur_group->item))->type() == Item::FIELD_ITEM ||
+ (*(cur_group->item))->type() == Item::REF_ITEM )
+ {
+ Item_ident *cur_field= (Item_ident*) *cur_group->item;
+ const char *l_db_name= cur_field->db_name;
+ const char *l_table_name= cur_field->table_name;
+ const char *l_field_name= cur_field->field_name;
+
+ DBUG_ASSERT(l_field_name != 0);
if (!my_strcasecmp(system_charset_info,
- cur_field->field_name, field_name))
+ l_field_name, field_name))
++cur_match_degree;
else
continue;
- if (cur_field->table_name && table_name)
+ if (l_table_name && table_name)
{
/* If field_name is qualified by a table name. */
- if (my_strcasecmp(table_alias_charset, cur_field->table_name, table_name))
+ if (my_strcasecmp(table_alias_charset, l_table_name, table_name))
/* Same field names, different tables. */
return NULL;
++cur_match_degree;
- if (cur_field->db_name && db_name)
+ if (l_db_name && db_name)
{
/* If field_name is also qualified by a database name. */
- if (strcmp(cur_field->db_name, db_name))
+ if (strcmp(l_db_name, db_name))
/* Same field names, different databases. */
return NULL;
++cur_match_degree;
}
}
+ }
+ else
+ continue;
- if (cur_match_degree > found_match_degree)
- {
- found_match_degree= cur_match_degree;
- found_group= cur_group;
- }
- else if (found_group && (cur_match_degree == found_match_degree) &&
- ! (*(found_group->item))->eq(cur_field, 0))
- {
- /*
- If the current resolve candidate matches equally well as the current
- best match, they must reference the same column, otherwise the field
- is ambiguous.
- */
- my_error(ER_NON_UNIQ_ERROR, MYF(0),
- find_item->full_name(), current_thd->where);
- return NULL;
- }
+ if (cur_match_degree > found_match_degree)
+ {
+ found_match_degree= cur_match_degree;
+ found_group= cur_group;
+ }
+ else if (found_group && (cur_match_degree == found_match_degree) &&
+ !(*(found_group->item))->eq((*(cur_group->item)), 0))
+ {
+ /*
+ If the current resolve candidate matches equally well as the current
+ best match, they must reference the same column, otherwise the field
+ is ambiguous.
+ */
+ my_error(ER_NON_UNIQ_ERROR, MYF(0),
+ find_item->full_name(), current_thd->where);
+ return NULL;
}
}
@@ -5832,6 +5865,7 @@ String *Item::check_well_formed_result(String *str, bool send_error)
/* Check whether we got a well-formed string */
CHARSET_INFO *cs= str->charset();
uint wlen= str->well_formed_length();
+ null_value= false;
if (wlen < str->length())
{
THD *thd= current_thd;
diff --git a/sql/item.h b/sql/item.h
index 5b3c3a6a0d5..1f3e0f02971 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -4456,7 +4456,7 @@ public:
if (result_type() == ROW_RESULT)
orig_item->bring_value();
}
- virtual bool is_expensive() { return orig_item->is_expensive(); }
+ bool is_expensive() { return orig_item->is_expensive(); }
bool is_expensive_processor(void *arg)
{ return orig_item->is_expensive_processor(arg); }
bool check_vcol_func_processor(void *arg)
@@ -5119,6 +5119,8 @@ public:
return false;
}
table_map used_tables() const { return (table_map)0L; }
+ Field *get_tmp_table_field() { return 0; }
+ Item *get_tmp_table_item(THD *thd) { return this; }
Item_field *field_for_view_update() { return 0; }
bool update_vcol_processor(void *arg) { return 0; }
bool check_func_default_processor(void *arg) { return true; }
@@ -5195,6 +5197,8 @@ public:
*/
table_map used_tables() const { return RAND_TABLE_BIT; }
+ Item_field *field_for_view_update() { return 0; }
+
bool walk(Item_processor processor, bool walk_subquery, void *args)
{
return arg->walk(processor, walk_subquery, args) ||
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 9891d117912..2856cea0697 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -2538,7 +2538,7 @@ Item_func_nullif::fix_length_and_dec()
See also class Item_func_nullif declaration.
*/
if (arg_count == 2)
- args[arg_count++]= args[0];
+ args[arg_count++]= m_arg0 ? m_arg0 : args[0];
THD *thd= current_thd;
/*
@@ -2689,7 +2689,47 @@ Item_func_nullif::fix_length_and_dec()
unsigned_flag= args[2]->unsigned_flag;
fix_char_length(args[2]->max_char_length());
maybe_null=1;
+ m_arg0= args[0];
setup_args_and_comparator(thd, &cmp);
+ /*
+ A special code for EXECUTE..PREPARE.
+
+ If args[0] did not change, then we don't remember it, as it can point
+ to a temporary Item object which will be destroyed between PREPARE
+ and EXECUTE. EXECUTE time fix_length_and_dec() will correctly set args[2]
+ from args[0] again.
+
+ If args[0] changed, then it can be Item_func_conv_charset() for the
+ original args[0], which was permanently installed during PREPARE time
+ into the item tree as a wrapper for args[0], using change_item_tree(), i.e.
+
+ NULLIF(latin1_field, 'a' COLLATE utf8_bin)
+
+ was "rewritten" to:
+
+ CASE WHEN CONVERT(latin1_field USING utf8) = 'a' COLLATE utf8_bin
+ THEN NULL
+ ELSE latin1_field
+
+ - m_args0 points to Item_field corresponding to latin1_field
+ - args[0] points to Item_func_conv_charset
+ - args[0]->args[0] is equal to m_args0
+ - args[1] points to Item_func_set_collation
+ - args[2] points is eqial to m_args0
+
+ In this case we remember and reuse m_arg0 during EXECUTE time as args[2].
+
+ QQ: How to make sure that m_args0 does not point
+ to something temporary which will be destoyed between PREPARE and EXECUTE.
+ The condition below should probably be more strict and somehow check that:
+ - change_item_tree() was called for the new args[0]
+ - m_args0 is referenced from inside args[0], e.g. as a function argument,
+ and therefore it is also something that won't be destroyed between
+ PREPARE and EXECUTE.
+ Any ideas?
+ */
+ if (args[0] == m_arg0)
+ m_arg0= NULL;
}
@@ -4494,7 +4534,8 @@ Item_cond::fix_fields(THD *thd, Item **ref)
was: <field>
become: <field> = 1
*/
- if (item->type() == FIELD_ITEM)
+ Item::Type type= item->type();
+ if (type == Item::FIELD_ITEM || type == Item::REF_ITEM)
{
Query_arena backup, *arena;
Item *new_item;
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index c691797e2c5..7774663bd57 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -1075,6 +1075,7 @@ class Item_func_nullif :public Item_func_hybrid_field_type
if (arg_count == 3 && args[0] != args[2])
args[0]= args[2];
}
+ Item *m_arg0;
public:
/*
Here we pass three arguments to the parent constructor, as NULLIF
@@ -1086,8 +1087,14 @@ public:
*/
Item_func_nullif(THD *thd, Item *a, Item *b):
Item_func_hybrid_field_type(thd, a, b, a),
- m_cache(NULL)
+ m_cache(NULL),
+ m_arg0(NULL)
{ arg_count--; }
+ void cleanup()
+ {
+ Item_func_hybrid_field_type::cleanup();
+ arg_count= 2; // See the comment to the constructor
+ }
bool date_op(MYSQL_TIME *ltime, uint fuzzydate);
double real_op();
longlong int_op();
@@ -1772,10 +1779,26 @@ public:
const char *func_name() const { return "isnull"; }
void print(String *str, enum_query_type query_type);
enum precedence precedence() const { return CMP_PRECEDENCE; }
+
+ bool arg_is_datetime_notnull_field()
+ {
+ Item **args= arguments();
+ if (args[0]->type() == Item::FIELD_ITEM)
+ {
+ Field *field=((Item_field*) args[0])->field;
+
+ if (((field->type() == MYSQL_TYPE_DATE) ||
+ (field->type() == MYSQL_TYPE_DATETIME)) &&
+ (field->flags & NOT_NULL_FLAG))
+ return true;
+ }
+ return false;
+ }
+
/* Optimize case of not_null_column IS NULL */
virtual void update_used_tables()
{
- if (!args[0]->maybe_null)
+ if (!args[0]->maybe_null && !arg_is_datetime_notnull_field())
{
used_tables_cache= 0; /* is always false */
const_item_cache= 1;
@@ -2695,4 +2718,3 @@ extern Ge_creator ge_creator;
extern Le_creator le_creator;
#endif /* ITEM_CMPFUNC_INCLUDED */
-
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 9bafe25e431..c38bdba05c2 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -6596,7 +6596,8 @@ Item_func_sp::init_result_field(THD *thd)
bool Item_func_sp::is_expensive()
{
- return !(m_sp->m_chistics->detistic);
+ return !m_sp->m_chistics->detistic ||
+ current_thd->locked_tables_mode < LTM_LOCK_TABLES;
}
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index b7efa60c520..9740dc9dae1 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -164,31 +164,6 @@ String *Item_func_md5::val_str_ascii(String *str)
}
-/*
- The MD5()/SHA() functions treat their parameter as being a case sensitive.
- Thus we set binary collation on it so different instances of MD5() will be
- compared properly.
-*/
-static CHARSET_INFO *get_checksum_charset(const char *csname)
-{
- CHARSET_INFO *cs= get_charset_by_csname(csname, MY_CS_BINSORT, MYF(0));
- if (!cs)
- {
- // Charset has no binary collation: use my_charset_bin.
- cs= &my_charset_bin;
- }
- return cs;
-}
-
-
-void Item_func_md5::fix_length_and_dec()
-{
- CHARSET_INFO *cs= get_checksum_charset(args[0]->collation.collation->csname);
- args[0]->collation.set(cs, DERIVATION_COERCIBLE);
- fix_length_and_charset(32, default_charset());
-}
-
-
String *Item_func_sha::val_str_ascii(String *str)
{
DBUG_ASSERT(fixed == 1);
@@ -214,8 +189,6 @@ String *Item_func_sha::val_str_ascii(String *str)
void Item_func_sha::fix_length_and_dec()
{
- CHARSET_INFO *cs= get_checksum_charset(args[0]->collation.collation->csname);
- args[0]->collation.set(cs, DERIVATION_COERCIBLE);
// size of hex representation of hash
fix_length_and_charset(SHA1_HASH_SIZE * 2, default_charset());
}
@@ -345,9 +318,6 @@ void Item_func_sha2::fix_length_and_dec()
"sha2");
}
- CHARSET_INFO *cs= get_checksum_charset(args[0]->collation.collation->csname);
- args[0]->collation.set(cs, DERIVATION_COERCIBLE);
-
#else
THD *thd= current_thd;
push_warning_printf(thd,
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index be23f45c286..65c6dacbc73 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -97,23 +97,69 @@ public:
};
-class Item_func_md5 :public Item_str_ascii_func
+/**
+ Functions that return a checksum or a hash of the argument,
+ or somehow else encode or decode the argument,
+ returning an ASCII-repertoire string.
+*/
+class Item_str_ascii_checksum_func: public Item_str_ascii_func
+{
+public:
+ Item_str_ascii_checksum_func(THD *thd, Item *a)
+ :Item_str_ascii_func(thd, a) { }
+ Item_str_ascii_checksum_func(THD *thd, Item *a, Item *b)
+ :Item_str_ascii_func(thd, a, b) { }
+ bool eq(const Item *item, bool binary_cmp) const
+ {
+ // Always use binary argument comparison: MD5('x') != MD5('X')
+ return Item_func::eq(item, true);
+ }
+};
+
+
+/**
+ Functions that return a checksum or a hash of the argument,
+ or somehow else encode or decode the argument,
+ returning a binary string.
+*/
+class Item_str_binary_checksum_func: public Item_str_func
+{
+public:
+ Item_str_binary_checksum_func(THD *thd, Item *a)
+ :Item_str_func(thd, a) { }
+ Item_str_binary_checksum_func(THD *thd, Item *a, Item *b)
+ :Item_str_func(thd, a, b) { }
+ bool eq(const Item *item, bool binary_cmp) const
+ {
+ /*
+ Always use binary argument comparison:
+ FROM_BASE64('test') != FROM_BASE64('TEST')
+ */
+ return Item_func::eq(item, true);
+ }
+};
+
+
+class Item_func_md5 :public Item_str_ascii_checksum_func
{
String tmp_value;
public:
- Item_func_md5(THD *thd, Item *a): Item_str_ascii_func(thd, a) {}
+ Item_func_md5(THD *thd, Item *a): Item_str_ascii_checksum_func(thd, a) {}
String *val_str_ascii(String *);
- void fix_length_and_dec();
+ void fix_length_and_dec()
+ {
+ fix_length_and_charset(32, default_charset());
+ }
const char *func_name() const { return "md5"; }
Item *get_copy(THD *thd, MEM_ROOT *mem_root)
{ return get_item_copy<Item_func_md5>(thd, mem_root, this); }
};
-class Item_func_sha :public Item_str_ascii_func
+class Item_func_sha :public Item_str_ascii_checksum_func
{
public:
- Item_func_sha(THD *thd, Item *a): Item_str_ascii_func(thd, a) {}
+ Item_func_sha(THD *thd, Item *a): Item_str_ascii_checksum_func(thd, a) {}
String *val_str_ascii(String *);
void fix_length_and_dec();
const char *func_name() const { return "sha"; }
@@ -121,10 +167,11 @@ public:
{ return get_item_copy<Item_func_sha>(thd, mem_root, this); }
};
-class Item_func_sha2 :public Item_str_ascii_func
+class Item_func_sha2 :public Item_str_ascii_checksum_func
{
public:
- Item_func_sha2(THD *thd, Item *a, Item *b): Item_str_ascii_func(thd, a, b) {}
+ Item_func_sha2(THD *thd, Item *a, Item *b)
+ :Item_str_ascii_checksum_func(thd, a, b) {}
String *val_str_ascii(String *);
void fix_length_and_dec();
const char *func_name() const { return "sha2"; }
@@ -132,11 +179,12 @@ public:
{ return get_item_copy<Item_func_sha2>(thd, mem_root, this); }
};
-class Item_func_to_base64 :public Item_str_ascii_func
+class Item_func_to_base64 :public Item_str_ascii_checksum_func
{
String tmp_value;
public:
- Item_func_to_base64(THD *thd, Item *a): Item_str_ascii_func(thd, a) {}
+ Item_func_to_base64(THD *thd, Item *a)
+ :Item_str_ascii_checksum_func(thd, a) {}
String *val_str_ascii(String *);
void fix_length_and_dec();
const char *func_name() const { return "to_base64"; }
@@ -144,11 +192,12 @@ public:
{ return get_item_copy<Item_func_to_base64>(thd, mem_root, this); }
};
-class Item_func_from_base64 :public Item_str_func
+class Item_func_from_base64 :public Item_str_binary_checksum_func
{
String tmp_value;
public:
- Item_func_from_base64(THD *thd, Item *a): Item_str_func(thd, a) {}
+ Item_func_from_base64(THD *thd, Item *a)
+ :Item_str_binary_checksum_func(thd, a) { }
String *val_str(String *);
void fix_length_and_dec();
const char *func_name() const { return "from_base64"; }
@@ -158,7 +207,7 @@ public:
#include <my_crypt.h>
-class Item_aes_crypt :public Item_str_func
+class Item_aes_crypt :public Item_str_binary_checksum_func
{
enum { AES_KEY_LENGTH = 128 };
void create_key(String *user_key, uchar* key);
@@ -166,7 +215,8 @@ class Item_aes_crypt :public Item_str_func
protected:
int what;
public:
- Item_aes_crypt(THD *thd, Item *a, Item *b): Item_str_func(thd, a, b) {}
+ Item_aes_crypt(THD *thd, Item *a, Item *b)
+ :Item_str_binary_checksum_func(thd, a, b) {}
String *val_str(String *);
};
@@ -481,7 +531,7 @@ public:
authentication procedure works, see comments in password.c.
*/
-class Item_func_password :public Item_str_ascii_func
+class Item_func_password :public Item_str_ascii_checksum_func
{
public:
enum PW_Alg {OLD, NEW};
@@ -491,9 +541,9 @@ private:
bool deflt;
public:
Item_func_password(THD *thd, Item *a):
- Item_str_ascii_func(thd, a), alg(NEW), deflt(1) {}
+ Item_str_ascii_checksum_func(thd, a), alg(NEW), deflt(1) {}
Item_func_password(THD *thd, Item *a, PW_Alg al):
- Item_str_ascii_func(thd, a), alg(al), deflt(0) {}
+ Item_str_ascii_checksum_func(thd, a), alg(al), deflt(0) {}
String *val_str_ascii(String *str);
bool fix_fields(THD *thd, Item **ref);
void fix_length_and_dec()
@@ -513,12 +563,14 @@ public:
-class Item_func_des_encrypt :public Item_str_func
+class Item_func_des_encrypt :public Item_str_binary_checksum_func
{
String tmp_value,tmp_arg;
public:
- Item_func_des_encrypt(THD *thd, Item *a): Item_str_func(thd, a) {}
- Item_func_des_encrypt(THD *thd, Item *a, Item *b): Item_str_func(thd, a, b) {}
+ Item_func_des_encrypt(THD *thd, Item *a)
+ :Item_str_binary_checksum_func(thd, a) {}
+ Item_func_des_encrypt(THD *thd, Item *a, Item *b)
+ :Item_str_binary_checksum_func(thd, a, b) {}
String *val_str(String *);
void fix_length_and_dec()
{
@@ -531,12 +583,14 @@ public:
{ return get_item_copy<Item_func_des_encrypt>(thd, mem_root, this); }
};
-class Item_func_des_decrypt :public Item_str_func
+class Item_func_des_decrypt :public Item_str_binary_checksum_func
{
String tmp_value;
public:
- Item_func_des_decrypt(THD *thd, Item *a): Item_str_func(thd, a) {}
- Item_func_des_decrypt(THD *thd, Item *a, Item *b): Item_str_func(thd, a, b) {}
+ Item_func_des_decrypt(THD *thd, Item *a)
+ :Item_str_binary_checksum_func(thd, a) {}
+ Item_func_des_decrypt(THD *thd, Item *a, Item *b)
+ :Item_str_binary_checksum_func(thd, a, b) {}
String *val_str(String *);
void fix_length_and_dec()
{
@@ -551,7 +605,13 @@ public:
{ return get_item_copy<Item_func_des_decrypt>(thd, mem_root, this); }
};
-class Item_func_encrypt :public Item_str_func
+
+/**
+ QQ: Item_func_encrypt should derive from Item_str_ascii_checksum_func.
+ However, it should be fixed to handle UCS2, UTF16, UTF32 properly first,
+ as the underlying crypt() call expects a null-terminated input string.
+*/
+class Item_func_encrypt :public Item_str_binary_checksum_func
{
String tmp_value;
@@ -561,11 +621,12 @@ class Item_func_encrypt :public Item_str_func
collation.set(&my_charset_bin);
}
public:
- Item_func_encrypt(THD *thd, Item *a): Item_str_func(thd, a)
+ Item_func_encrypt(THD *thd, Item *a): Item_str_binary_checksum_func(thd, a)
{
constructor_helper();
}
- Item_func_encrypt(THD *thd, Item *a, Item *b): Item_str_func(thd, a, b)
+ Item_func_encrypt(THD *thd, Item *a, Item *b)
+ :Item_str_binary_checksum_func(thd, a, b)
{
constructor_helper();
}
@@ -583,7 +644,7 @@ public:
#include "sql_crypt.h"
-class Item_func_encode :public Item_str_func
+class Item_func_encode :public Item_str_binary_checksum_func
{
private:
/** Whether the PRNG has already been seeded. */
@@ -592,7 +653,7 @@ protected:
SQL_CRYPT sql_crypt;
public:
Item_func_encode(THD *thd, Item *a, Item *seed_arg):
- Item_str_func(thd, a, seed_arg) {}
+ Item_str_binary_checksum_func(thd, a, seed_arg) {}
String *val_str(String *);
void fix_length_and_dec();
const char *func_name() const { return "encode"; }
@@ -911,12 +972,12 @@ public:
};
-class Item_func_hex :public Item_str_ascii_func
+class Item_func_hex :public Item_str_ascii_checksum_func
{
String tmp_value;
public:
Item_func_hex(THD *thd, Item *a):
- Item_str_ascii_func(thd, a) {}
+ Item_str_ascii_checksum_func(thd, a) {}
const char *func_name() const { return "hex"; }
String *val_str_ascii(String *);
void fix_length_and_dec()
@@ -1291,11 +1352,12 @@ public:
#define ZLIB_DEPENDED_FUNCTION { null_value=1; return 0; }
#endif
-class Item_func_compress: public Item_str_func
+class Item_func_compress: public Item_str_binary_checksum_func
{
String buffer;
public:
- Item_func_compress(THD *thd, Item *a): Item_str_func(thd, a) {}
+ Item_func_compress(THD *thd, Item *a)
+ :Item_str_binary_checksum_func(thd, a) {}
void fix_length_and_dec(){max_length= (args[0]->max_length*120)/100+12;}
const char *func_name() const{return "compress";}
String *val_str(String *) ZLIB_DEPENDED_FUNCTION
@@ -1303,11 +1365,12 @@ public:
{ return get_item_copy<Item_func_compress>(thd, mem_root, this); }
};
-class Item_func_uncompress: public Item_str_func
+class Item_func_uncompress: public Item_str_binary_checksum_func
{
String buffer;
public:
- Item_func_uncompress(THD *thd, Item *a): Item_str_func(thd, a) {}
+ Item_func_uncompress(THD *thd, Item *a)
+ :Item_str_binary_checksum_func(thd, a) {}
void fix_length_and_dec(){ maybe_null= 1; max_length= MAX_BLOB_WIDTH; }
const char *func_name() const{return "uncompress";}
String *val_str(String *) ZLIB_DEPENDED_FUNCTION
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index f7105086e55..89c663b5f16 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -228,6 +228,7 @@ bool
Item_subselect::select_transformer(JOIN *join)
{
DBUG_ENTER("Item_subselect::select_transformer");
+ DBUG_ASSERT(thd == join->thd);
DBUG_RETURN(false);
}
@@ -629,6 +630,7 @@ bool Item_subselect::is_expensive()
examined_rows+= cur_join->get_examined_rows();
}
+ // here we are sure that subquery is optimized so thd is set
return !all_are_simple &&
(examined_rows > thd->variables.expensive_subquery_limit);
}
@@ -693,6 +695,7 @@ bool Item_subselect::exec()
subselect_engine *org_engine= engine;
DBUG_ENTER("Item_subselect::exec");
+ DBUG_ASSERT(fixed);
/*
Do not execute subselect in case of a fatal error
@@ -741,6 +744,7 @@ int Item_in_subselect::optimize(double *out_rows, double *cost)
{
int res;
DBUG_ENTER("Item_in_subselect::optimize");
+ DBUG_ASSERT(fixed);
SELECT_LEX *save_select= thd->lex->current_select;
JOIN *join= unit->first_select()->join;
@@ -857,6 +861,7 @@ bool Item_in_subselect::expr_cache_is_needed(THD *thd)
bool Item_in_subselect::exec()
{
DBUG_ENTER("Item_in_subselect::exec");
+ DBUG_ASSERT(fixed);
/*
Initialize the cache of the left predicate operand. This has to be done as
late as now, because Cached_item directly contains a resolved field (not
@@ -911,6 +916,7 @@ table_map Item_subselect::used_tables() const
bool Item_subselect::const_item() const
{
+ DBUG_ASSERT(thd);
return (thd->lex->context_analysis_only ?
FALSE :
forced_const || const_item_cache);
@@ -1112,10 +1118,11 @@ Item_singlerow_subselect::select_transformer(JOIN *join)
DBUG_ENTER("Item_singlerow_subselect::select_transformer");
if (changed)
DBUG_RETURN(false);
+ DBUG_ASSERT(join->thd == thd);
SELECT_LEX *select_lex= join->select_lex;
Query_arena *arena= thd->stmt_arena;
-
+
if (!select_lex->master_unit()->is_union() &&
!select_lex->table_list.elements &&
select_lex->item_list.elements == 1 &&
@@ -1790,6 +1797,7 @@ Item_in_subselect::single_value_transformer(JOIN *join)
{
SELECT_LEX *select_lex= join->select_lex;
DBUG_ENTER("Item_in_subselect::single_value_transformer");
+ DBUG_ASSERT(thd == join->thd);
/*
Check that the right part of the subselect contains no more than one
@@ -1904,6 +1912,7 @@ bool Item_allany_subselect::transform_into_max_min(JOIN *join)
Item **place= optimizer->arguments() + 1;
SELECT_LEX *select_lex= join->select_lex;
Item *subs;
+ DBUG_ASSERT(thd == join->thd);
/*
*/
@@ -2012,6 +2021,7 @@ bool Item_allany_subselect::transform_into_max_min(JOIN *join)
bool Item_in_subselect::fix_having(Item *having, SELECT_LEX *select_lex)
{
bool fix_res= 0;
+ DBUG_ASSERT(thd);
if (!having->fixed)
{
select_lex->having_fix_field= 1;
@@ -2074,6 +2084,7 @@ Item_in_subselect::create_single_in_to_exists_cond(JOIN *join,
Item **having_item)
{
SELECT_LEX *select_lex= join->select_lex;
+ DBUG_ASSERT(thd == join->thd);
/*
The non-transformed HAVING clause of 'join' may be stored in two ways
during JOIN::optimize: this->tmp_having= this->having; this->having= 0;
@@ -2215,6 +2226,7 @@ Item_in_subselect::row_value_transformer(JOIN *join)
uint cols_num= left_expr->cols();
DBUG_ENTER("Item_in_subselect::row_value_transformer");
+ DBUG_ASSERT(thd == join->thd);
// psergey: duplicated_subselect_card_check
if (select_lex->item_list.elements != cols_num)
@@ -2326,6 +2338,7 @@ Item_in_subselect::create_row_in_to_exists_cond(JOIN * join,
!select_lex->table_list.elements);
DBUG_ENTER("Item_in_subselect::create_row_in_to_exists_cond");
+ DBUG_ASSERT(thd == join->thd);
*where_item= NULL;
*having_item= NULL;
@@ -2571,6 +2584,7 @@ bool Item_in_subselect::inject_in_to_exists_cond(JOIN *join_arg)
Item *having_item= join_arg->in_to_exists_having;
DBUG_ENTER("Item_in_subselect::inject_in_to_exists_cond");
+ DBUG_ASSERT(thd == join_arg->thd);
if (where_item)
{
@@ -2700,8 +2714,8 @@ static bool check_equality_for_exist2in(Item_func *func,
args[0]->all_used_tables() == OUTER_REF_TABLE_BIT)
{
/* It is Item_field or Item_direct_view_ref) */
- DBUG_ASSERT(args[0]->type() == Item::FIELD_ITEM ||
- args[0]->type() == Item::REF_ITEM);
+ DBUG_ASSERT(args[1]->type() == Item::FIELD_ITEM ||
+ args[1]->type() == Item::REF_ITEM);
*local_field= (Item_ident *)args[1];
*outer_exp= args[0];
return TRUE;
@@ -3099,6 +3113,7 @@ Item_in_subselect::select_in_like_transformer(JOIN *join)
bool result;
DBUG_ENTER("Item_in_subselect::select_in_like_transformer");
+ DBUG_ASSERT(thd == join->thd);
/*
IN/SOME/ALL/ANY subqueries aren't support LIMIT clause. Without it
@@ -3309,6 +3324,7 @@ bool Item_in_subselect::setup_mat_engine()
subselect_single_select_engine *select_engine;
DBUG_ENTER("Item_in_subselect::setup_mat_engine");
+ DBUG_ASSERT(thd);
/*
The select_engine (that executes transformed IN=>EXISTS subselects) is
@@ -3347,6 +3363,7 @@ bool Item_in_subselect::setup_mat_engine()
bool Item_in_subselect::init_left_expr_cache()
{
JOIN *outer_join;
+ DBUG_ASSERT(thd);
outer_join= unit->outer_select()->join;
/*
@@ -3374,6 +3391,7 @@ bool Item_in_subselect::init_left_expr_cache()
bool Item_in_subselect::init_cond_guards()
{
+ DBUG_ASSERT(thd);
uint cols_num= left_expr->cols();
if (!abort_on_null && left_expr->maybe_null && !pushed_cond_guards)
{
@@ -6662,4 +6680,3 @@ void Item_subselect::init_expr_cache_tracker(THD *thd)
DBUG_ASSERT(expr_cache->type() == Item::EXPR_CACHE_ITEM);
node->cache_tracker= ((Item_cache_wrapper *)expr_cache)->init_tracker(qw->mem_root);
}
-
diff --git a/sql/item_sum.h b/sql/item_sum.h
index b9075db0196..84049814ef9 100644
--- a/sql/item_sum.h
+++ b/sql/item_sum.h
@@ -1195,7 +1195,6 @@ public:
fixed= true;
}
table_map used_tables() const { return (table_map) 1L; }
- void set_result_field(Field *) { DBUG_ASSERT(0); }
void save_in_result_field(bool no_conversions) { DBUG_ASSERT(0); }
bool check_vcol_func_processor(void *arg)
{
diff --git a/sql/log.cc b/sql/log.cc
index d2fc98b80ef..57984bd03f4 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -301,6 +301,9 @@ public:
{
compute_statistics();
truncate(0);
+ if(cache_log.file != -1)
+ my_chsize(cache_log.file, 0, 0, MYF(MY_WME));
+
changes_to_non_trans_temp_table_flag= FALSE;
incident= FALSE;
before_stmt_pos= MY_OFF_T_UNDEF;
@@ -3106,7 +3109,7 @@ bool MYSQL_QUERY_LOG::write(THD *thd, time_t current_time,
if (! write_error)
{
write_error= 1;
- sql_print_error(ER_THD(thd, ER_ERROR_ON_WRITE), name, error);
+ sql_print_error(ER_THD(thd, ER_ERROR_ON_WRITE), name, tmp_errno);
}
}
}
@@ -3399,7 +3402,7 @@ bool MYSQL_BIN_LOG::open(const char *log_name,
if (init_and_set_log_file_name(log_name, new_name, next_log_number,
log_type_arg, io_cache_type_arg))
{
- sql_print_error("MSYQL_BIN_LOG::open failed to generate new file name.");
+ sql_print_error("MYSQL_BIN_LOG::open failed to generate new file name.");
DBUG_RETURN(1);
}
@@ -3428,7 +3431,7 @@ bool MYSQL_BIN_LOG::open(const char *log_name,
}
});
- sql_print_error("MSYQL_BIN_LOG::open failed to sync the index file.");
+ sql_print_error("MYSQL_BIN_LOG::open failed to sync the index file.");
DBUG_RETURN(1);
}
DBUG_EXECUTE_IF("crash_create_non_critical_before_update_index", DBUG_SUICIDE(););
@@ -4534,14 +4537,14 @@ int MYSQL_BIN_LOG::purge_logs(const char *to_log,
if ((error= sync_purge_index_file()))
{
- sql_print_error("MSYQL_BIN_LOG::purge_logs failed to flush register file.");
+ sql_print_error("MYSQL_BIN_LOG::purge_logs failed to flush register file.");
goto err;
}
/* We know how many files to delete. Update index file. */
if ((error=update_log_index(&log_info, need_update_threads)))
{
- sql_print_error("MSYQL_BIN_LOG::purge_logs failed to update the index file");
+ sql_print_error("MYSQL_BIN_LOG::purge_logs failed to update the index file");
goto err;
}
@@ -4551,7 +4554,7 @@ err:
/* Read each entry from purge_index_file and delete the file. */
if (is_inited_purge_index_file() &&
(error= purge_index_entry(thd, reclaimed_space, FALSE)))
- sql_print_error("MSYQL_BIN_LOG::purge_logs failed to process registered files"
+ sql_print_error("MYSQL_BIN_LOG::purge_logs failed to process registered files"
" that would be purged.");
close_purge_index_file();
@@ -4668,7 +4671,7 @@ int MYSQL_BIN_LOG::purge_index_entry(THD *thd, ulonglong *reclaimed_space,
if ((error=reinit_io_cache(&purge_index_file, READ_CACHE, 0, 0, 0)))
{
- sql_print_error("MSYQL_BIN_LOG::purge_index_entry failed to reinit register file "
+ sql_print_error("MYSQL_BIN_LOG::purge_index_entry failed to reinit register file "
"for read");
goto err;
}
@@ -4683,7 +4686,7 @@ int MYSQL_BIN_LOG::purge_index_entry(THD *thd, ulonglong *reclaimed_space,
if (purge_index_file.error)
{
error= purge_index_file.error;
- sql_print_error("MSYQL_BIN_LOG::purge_index_entry error %d reading from "
+ sql_print_error("MYSQL_BIN_LOG::purge_index_entry error %d reading from "
"register file.", error);
goto err;
}
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 3b4d5e8f9a4..85dce217743 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -1897,6 +1897,10 @@ err:
if (error)
{
DBUG_ASSERT(!res);
+#ifdef MYSQL_CLIENT
+ if (force_opt)
+ DBUG_RETURN(new Unknown_log_event());
+#endif
if (event.length() >= OLD_HEADER_LEN)
sql_print_error("Error in Log_event::read_log_event(): '%s',"
" data_len: %lu, event_type: %d", error,
@@ -8680,8 +8684,13 @@ void Unknown_log_event::print(FILE* file_arg, PRINT_EVENT_INFO* print_event_info
if (print_event_info->short_form)
return;
- print_header(&cache, print_event_info, FALSE);
- my_b_printf(&cache, "\n# %s", "Unknown event\n");
+ if (what != ENCRYPTED)
+ {
+ print_header(&cache, print_event_info, FALSE);
+ my_b_printf(&cache, "\n# Unknown event\n");
+ }
+ else
+ my_b_printf(&cache, "# Encrypted event\n");
}
#endif
diff --git a/sql/log_event.h b/sql/log_event.h
index bbefbe26f41..7b8704636af 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -1213,7 +1213,7 @@ public:
return thd ? thd->db : 0;
}
#else
- Log_event() : temp_buf(0), flags(0) {}
+ Log_event() : temp_buf(0), when(0), flags(0) {}
ha_checksum crc;
/* print*() functions are used by mysqlbinlog */
virtual void print(FILE* file, PRINT_EVENT_INFO* print_event_info) = 0;
@@ -3768,6 +3768,7 @@ private:
class Unknown_log_event: public Log_event
{
public:
+ enum { UNKNOWN, ENCRYPTED } what;
/*
Even if this is an unknown event, we still pass description_event to
Log_event's ctor, this way we can extract maximum information from the
@@ -3775,8 +3776,10 @@ public:
*/
Unknown_log_event(const char* buf,
const Format_description_log_event *description_event):
- Log_event(buf, description_event)
+ Log_event(buf, description_event), what(UNKNOWN)
{}
+ /* constructor for hopelessly corrupted events */
+ Unknown_log_event(): Log_event(), what(ENCRYPTED) {}
~Unknown_log_event() {}
void print(FILE* file, PRINT_EVENT_INFO* print_event_info);
Log_event_type get_type_code() { return UNKNOWN_EVENT;}
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index e7fb7b7e0c9..84d6e3b582f 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -4189,6 +4189,7 @@ static int init_common_variables()
max_system_variables.pseudo_thread_id= ~(my_thread_id) 0;
server_start_time= flush_status_time= my_time(0);
+ my_disable_copystat_in_redel= 1;
global_rpl_filter= new Rpl_filter;
binlog_filter= new Rpl_filter;
@@ -4260,6 +4261,8 @@ static int init_common_variables()
return 1;
}
+ opt_log_basename= const_cast<char *>("mysql");
+
if (gethostname(glob_hostname,sizeof(glob_hostname)) < 0)
{
/*
@@ -4269,9 +4272,8 @@ static int init_common_variables()
strmake(glob_hostname, STRING_WITH_LEN("localhost"));
sql_print_warning("gethostname failed, using '%s' as hostname",
glob_hostname);
- opt_log_basename= const_cast<char *>("mysql");
}
- else
+ else if (is_filename_allowed(glob_hostname, strlen(glob_hostname), FALSE))
opt_log_basename= glob_hostname;
strmake(pidfile_name, opt_log_basename, sizeof(pidfile_name)-5);
@@ -5895,6 +5897,12 @@ int mysqld_main(int argc, char **argv)
setbuf(stderr, NULL);
FreeConsole(); // Remove window
}
+
+ if (fileno(stdin) >= 0)
+ {
+ /* Disable CRLF translation (MDEV-9409). */
+ _setmode(fileno(stdin), O_BINARY);
+ }
#endif
#ifdef WITH_WSREP
@@ -9061,9 +9069,10 @@ mysqld_get_one_option(int optid, const struct my_option *opt, char *argument)
case (int) OPT_LOG_BASENAME:
{
if (opt_log_basename[0] == 0 || strchr(opt_log_basename, FN_EXTCHAR) ||
- strchr(opt_log_basename,FN_LIBCHAR))
+ strchr(opt_log_basename,FN_LIBCHAR) ||
+ !is_filename_allowed(opt_log_basename, strlen(opt_log_basename), FALSE))
{
- sql_print_error("Wrong argument for --log-basename. It can't be empty or contain '.' or '" FN_DIRSEP "'");
+ sql_print_error("Wrong argument for --log-basename. It can't be empty or contain '.' or '" FN_DIRSEP "'. It must be valid filename.");
return 1;
}
if (log_error_file_ptr != disabled_my_option)
@@ -9946,9 +9955,9 @@ static int test_if_case_insensitive(const char *dir_name)
MY_STAT stat_info;
DBUG_ENTER("test_if_case_insensitive");
- fn_format(buff, glob_hostname, dir_name, ".lower-test",
+ fn_format(buff, opt_log_basename, dir_name, ".lower-test",
MY_UNPACK_FILENAME | MY_REPLACE_EXT | MY_REPLACE_DIR);
- fn_format(buff2, glob_hostname, dir_name, ".LOWER-TEST",
+ fn_format(buff2, opt_log_basename, dir_name, ".LOWER-TEST",
MY_UNPACK_FILENAME | MY_REPLACE_EXT | MY_REPLACE_DIR);
mysql_file_delete(key_file_casetest, buff2, MYF(0));
if ((file= mysql_file_create(key_file_casetest,
diff --git a/sql/net_serv.cc b/sql/net_serv.cc
index 70111f1b5d6..f9635689e63 100644
--- a/sql/net_serv.cc
+++ b/sql/net_serv.cc
@@ -1,5 +1,5 @@
-/* Copyright (c) 2000, 2013, Oracle and/or its affiliates.
- Copyright (c) 2010, 2014, SkySQL Ab.
+/* Copyright (c) 2000, 2016, Oracle and/or its affiliates.
+ Copyright (c) 2012, 2016, MariaDB
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/opt_range.cc b/sql/opt_range.cc
index 4b535769d6c..01b836fddf7 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -2760,9 +2760,16 @@ bool create_key_parts_for_pseudo_indexes(RANGE_OPT_PARAM *param,
{
Field *field= *field_ptr;
uint16 store_length;
+ uint16 max_key_part_length= (uint16) table->file->max_key_part_length();
key_part->key= keys;
key_part->part= 0;
- key_part->length= (uint16) field->key_length();
+ if (field->flags & BLOB_FLAG)
+ key_part->length= max_key_part_length;
+ else
+ {
+ key_part->length= (uint16) field->key_length();
+ set_if_smaller(key_part->length, max_key_part_length);
+ }
store_length= key_part->length;
if (field->real_maybe_null())
store_length+= HA_KEY_NULL_LENGTH;
@@ -3108,6 +3115,7 @@ bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item **cond)
}
free_alloc:
+ thd->no_errors= 0;
thd->mem_root= param.old_root;
free_root(&alloc, MYF(0));
diff --git a/sql/parse_file.h b/sql/parse_file.h
index e4756e6c8af..87917dbd71b 100644
--- a/sql/parse_file.h
+++ b/sql/parse_file.h
@@ -42,9 +42,9 @@ enum file_opt_type {
struct File_option
{
- LEX_STRING name; /**< Name of the option */
- int offset; /**< offset to base address of value */
- file_opt_type type; /**< Option type */
+ LEX_STRING name; /**< Name of the option */
+ my_ptrdiff_t offset; /**< offset to base address of value */
+ file_opt_type type; /**< Option type */
};
diff --git a/sql/rpl_filter.cc b/sql/rpl_filter.cc
index f1c6d76f7ff..b82e7bada45 100644
--- a/sql/rpl_filter.cc
+++ b/sql/rpl_filter.cc
@@ -282,6 +282,9 @@ Rpl_filter::parse_filter_rule(const char* spec, Add_filter add)
int status= 0;
char *arg, *ptr, *pstr;
+ if (!spec)
+ return false;
+
if (! (ptr= my_strdup(spec, MYF(MY_WME))))
return true;
diff --git a/sql/rpl_gtid.cc b/sql/rpl_gtid.cc
index 4adea76b3cb..1d9cb39075b 100644
--- a/sql/rpl_gtid.cc
+++ b/sql/rpl_gtid.cc
@@ -448,19 +448,7 @@ static const TABLE_FIELD_DEF mysql_gtid_slave_pos_tabledef= {
mysql_rpl_slave_state_pk_parts
};
-class Gtid_db_intact : public Table_check_intact
-{
-protected:
- void report_error(uint, const char *fmt, ...)
- {
- va_list args;
- va_start(args, fmt);
- error_log_print(ERROR_LEVEL, fmt, args);
- va_end(args);
- }
-};
-
-static Gtid_db_intact gtid_table_intact;
+static Table_check_intact_log_error gtid_table_intact;
/*
Check that the mysql.gtid_slave_pos table has the correct definition.
diff --git a/sql/rpl_parallel.cc b/sql/rpl_parallel.cc
index ec5ea725487..f7aab704c43 100644
--- a/sql/rpl_parallel.cc
+++ b/sql/rpl_parallel.cc
@@ -2773,7 +2773,6 @@ rpl_parallel::do_event(rpl_group_info *serial_rgi, Log_event *ev,
/*
Queue the event for processing.
*/
- rli->event_relay_log_pos= rli->future_event_relay_log_pos;
qev->ir= rli->last_inuse_relaylog;
++qev->ir->queued_count;
cur_thread->enqueue(qev);
diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc
index f687f645171..cd189b4ab2d 100644
--- a/sql/rpl_rli.cc
+++ b/sql/rpl_rli.cc
@@ -1245,8 +1245,8 @@ bool Relay_log_info::is_until_satisfied(my_off_t master_beg_pos)
if (until_condition == UNTIL_MASTER_POS)
{
- log_name= (mi->using_parallel() ?
- future_event_master_log_name : group_master_log_name);
+ log_name= (mi->using_parallel() ? future_event_master_log_name
+ : group_master_log_name);
log_pos= master_beg_pos;
}
else
diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt
index aa11b55da0d..03fba3fde49 100644
--- a/sql/share/errmsg-utf8.txt
+++ b/sql/share/errmsg-utf8.txt
@@ -6781,7 +6781,7 @@ ER_FK_COLUMN_NOT_NULL
ger "Spalte '%-.192s' kann nicht NOT NULL sein: wird für eine Fremdschlüsselbeschränkung '%-.192s' SET NULL benötigt"
ER_DUP_INDEX
- eng "Duplicate index '%-.64s' defined on the table '%-.64s.%-.64s'. This is deprecated and will be disallowed in a future release"
+ eng "Duplicate index %`s. This is deprecated and will be disallowed in a future release"
ER_FK_COLUMN_CANNOT_CHANGE
eng "Cannot change column '%-.192s': used in a foreign key constraint '%-.192s'"
diff --git a/sql/signal_handler.cc b/sql/signal_handler.cc
index f9478134ab4..ad7fb873c68 100644
--- a/sql/signal_handler.cc
+++ b/sql/signal_handler.cc
@@ -64,18 +64,18 @@ extern "C" sig_handler handle_fatal_signal(int sig)
struct tm tm;
#ifdef HAVE_STACKTRACE
THD *thd;
-#endif
/*
This flag remembers if the query pointer was found invalid.
We will try and print the query at the end of the signal handler, in case
we're wrong.
*/
bool print_invalid_query_pointer= false;
+#endif
if (segfaulted)
{
my_safe_printf_stderr("Fatal " SIGNAL_FMT " while backtracing\n", sig);
- _exit(1); /* Quit without running destructors */
+ goto end;
}
segfaulted = 1;
@@ -276,6 +276,7 @@ extern "C" sig_handler handle_fatal_signal(int sig)
"\"mlockall\" bugs.\n");
}
+#ifdef HAVE_STACKTRACE
if (print_invalid_query_pointer)
{
my_safe_printf_stderr(
@@ -285,6 +286,7 @@ extern "C" sig_handler handle_fatal_signal(int sig)
my_write_stderr(thd->query(), MY_MIN(65536U, thd->query_length()));
my_safe_printf_stderr("\n\n");
}
+#endif
#ifdef HAVE_WRITE_CORE
if (test_flags & TEST_CORE_ON_SIGNAL)
@@ -299,9 +301,11 @@ end:
#ifndef __WIN__
/*
Quit, without running destructors (etc.)
+ Use a signal, because the parent (systemd) can check that with WIFSIGNALED
On Windows, do not terminate, but pass control to exception filter.
*/
- _exit(1); // Using _exit(), since exit() is not async signal safe
+ signal(sig, SIG_DFL);
+ kill(getpid(), sig);
#else
return;
#endif
diff --git a/sql/slave.cc b/sql/slave.cc
index 77fde743184..05e967c4edb 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -3344,8 +3344,13 @@ static ulong read_event(MYSQL* mysql, Master_info *mi, bool* suppress_warnings,
*suppress_warnings= TRUE;
}
else
- sql_print_error("Error reading packet from server: %s ( server_errno=%d)",
- mysql_error(mysql), mysql_errno(mysql));
+ {
+ if (!mi->rli.abort_slave)
+ {
+ sql_print_error("Error reading packet from server: %s (server_errno=%d)",
+ mysql_error(mysql), mysql_errno(mysql));
+ }
+ }
DBUG_RETURN(packet_error);
}
@@ -3929,6 +3934,13 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli,
if (rli->mi->using_parallel())
{
int res= rli->parallel.do_event(serial_rgi, ev, event_size);
+ /*
+ In parallel replication, we need to update the relay log position
+ immediately so that it will be the correct position from which to
+ read the next event.
+ */
+ if (res == 0)
+ rli->event_relay_log_pos= rli->future_event_relay_log_pos;
if (res >= 0)
DBUG_RETURN(res);
/*
@@ -4928,7 +4940,21 @@ pthread_handler_t handle_slave_sql(void *arg)
serial_rgi->gtid_sub_id= 0;
serial_rgi->gtid_pending= false;
- rli->gtid_skip_flag = GTID_SKIP_NOT;
+ if (mi->using_gtid != Master_info::USE_GTID_NO && mi->using_parallel() &&
+ rli->restart_gtid_pos.count() > 0)
+ {
+ /*
+ With parallel replication in GTID mode, if we have a multi-domain GTID
+ position, we need to start some way back in the relay log and skip any
+ GTID that was already applied before. Since event groups can be split
+ across multiple relay logs, this earlier starting point may be in the
+ middle of an already applied event group, so we also need to skip any
+ remaining part of such group.
+ */
+ rli->gtid_skip_flag = GTID_SKIP_TRANSACTION;
+ }
+ else
+ rli->gtid_skip_flag = GTID_SKIP_NOT;
if (init_relay_log_pos(rli,
rli->group_relay_log_name,
rli->group_relay_log_pos,
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 6334d3fa1dd..ce7de2ed72b 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -1755,7 +1755,7 @@ bool acl_reload(THD *thd)
my_hash_init2(&acl_roles,50, &my_charset_utf8_bin,
0, 0, 0, (my_hash_get_key) acl_role_get_key, 0,
(void (*)(void *))free_acl_role, 0);
- my_hash_init2(&acl_roles_mappings, 50, system_charset_info, 0, 0, 0,
+ my_hash_init2(&acl_roles_mappings, 50, &my_charset_utf8_bin, 0, 0, 0,
(my_hash_get_key) acl_role_map_get_key, 0, 0, 0);
old_mem= acl_memroot;
delete_dynamic(&acl_wild_hosts);
diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc
index ed23d9cccd6..bc5b9bde8e8 100644
--- a/sql/sql_admin.cc
+++ b/sql/sql_admin.cc
@@ -380,7 +380,19 @@ static bool open_only_one_table(THD* thd, TABLE_LIST* table,
}
thd->prepare_derived_at_open= FALSE;
- table->next_global= save_next_global;
+ /*
+ MERGE engine may adjust table->next_global chain, thus we have to
+ append save_next_global after merge children.
+ */
+ if (save_next_global)
+ {
+ TABLE_LIST *table_list_iterator= table;
+ while (table_list_iterator->next_global)
+ table_list_iterator= table_list_iterator->next_global;
+ table_list_iterator->next_global= save_next_global;
+ save_next_global->prev_global= &table_list_iterator->next_global;
+ }
+
table->next_local= save_next_local;
return open_error;
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index e947e9dd90a..b6cfd2f2cc1 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -8446,6 +8446,7 @@ open_system_tables_for_read(THD *thd, TABLE_LIST *table_list,
*/
lex->reset_n_backup_query_tables_list(&query_tables_list_backup);
thd->reset_n_backup_open_tables_state(backup);
+ thd->lex->sql_command= SQLCOM_SELECT;
if (open_and_lock_tables(thd, table_list, FALSE,
MYSQL_OPEN_IGNORE_FLUSH |
diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc
index 2f4856fc4e2..6b13dba876e 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -962,7 +962,7 @@ inline void Query_cache_query::unlock_reading()
void Query_cache_query::init_n_lock()
{
DBUG_ENTER("Query_cache_query::init_n_lock");
- res=0; wri = 0; len = 0;
+ res=0; wri = 0; len = 0; ready= 0;
mysql_rwlock_init(key_rwlock_query_cache_query_lock, &lock);
lock_writing();
DBUG_PRINT("qcache", ("inited & locked query for block 0x%lx",
@@ -1227,6 +1227,7 @@ void Query_cache::end_of_result(THD *thd)
query_cache.split_block(last_result_block,len);
header->found_rows(limit_found_rows);
+ header->set_results_ready(); // signal for plugin
header->result()->type= Query_cache_block::RESULT;
/* Drop the writer. */
diff --git a/sql/sql_cache.h b/sql/sql_cache.h
index 6984c2115f2..945de307ffb 100644
--- a/sql/sql_cache.h
+++ b/sql/sql_cache.h
@@ -156,8 +156,9 @@ struct Query_cache_query
Query_cache_block *res;
Query_cache_tls *wri;
ulong len;
- uint8 tbls_type;
unsigned int last_pkt_nr;
+ uint8 tbls_type;
+ uint8 ready;
Query_cache_query() {} /* Remove gcc warning */
inline void init_n_lock();
@@ -177,6 +178,12 @@ struct Query_cache_query
{
return (((uchar*)this) + ALIGN_SIZE(sizeof(Query_cache_query)));
}
+ /**
+ following used to check if result ready in plugin without
+ locking rw_lock of the query.
+ */
+ inline void set_results_ready() { ready= 1; }
+ inline bool is_results_ready() { return ready; }
void lock_writing();
void lock_reading();
bool try_lock_writing();
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index d7d2944ba89..1837f2878c7 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -5713,9 +5713,11 @@ int THD::decide_logging_format(TABLE_LIST *tables)
{
static const char *prelocked_mode_name[] = {
"NON_PRELOCKED",
+ "LOCK_TABLES",
"PRELOCKED",
"PRELOCKED_UNDER_LOCK_TABLES",
};
+ compile_time_assert(array_elements(prelocked_mode_name) == LTM_always_last);
DBUG_PRINT("debug", ("prelocked_mode: %s",
prelocked_mode_name[locked_tables_mode]));
}
diff --git a/sql/sql_class.h b/sql/sql_class.h
index f0052f8fe57..ef10d7e4053 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -1372,7 +1372,8 @@ enum enum_locked_tables_mode
LTM_NONE= 0,
LTM_LOCK_TABLES,
LTM_PRELOCKED,
- LTM_PRELOCKED_UNDER_LOCK_TABLES
+ LTM_PRELOCKED_UNDER_LOCK_TABLES,
+ LTM_always_last
};
/**
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index 20538fe1fb4..8b7d4ee5ed2 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -815,7 +815,7 @@ static bool
mysql_rm_db_internal(THD *thd,char *db, bool if_exists, bool silent)
{
ulong deleted_tables= 0;
- bool error= true;
+ bool error= true, rm_mysql_schema;
char path[FN_REFLEN + 16];
MY_DIR *dirp;
uint length;
@@ -840,6 +840,18 @@ mysql_rm_db_internal(THD *thd,char *db, bool if_exists, bool silent)
length= build_table_filename(path, sizeof(path) - 1, db, "", "", 0);
strmov(path+length, MY_DB_OPT_FILE); // Append db option file name
del_dbopt(path); // Remove dboption hash entry
+ /*
+ Now remove the db.opt file.
+ The 'find_db_tables_and_rm_known_files' doesn't remove this file
+ if there exists a table with the name 'db', so let's just do it
+ separately. We know this file exists and needs to be deleted anyway.
+ */
+ if (my_delete_with_symlink(path, MYF(0)) && my_errno != ENOENT)
+ {
+ my_error(EE_DELETE, MYF(0), path, my_errno);
+ DBUG_RETURN(true);
+ }
+
path[length]= '\0'; // Remove file name
/* See if the directory exists */
@@ -867,7 +879,8 @@ mysql_rm_db_internal(THD *thd,char *db, bool if_exists, bool silent)
Disable drop of enabled log tables, must be done before name locking.
This check is only needed if we are dropping the "mysql" database.
*/
- if ((my_strcasecmp(system_charset_info, MYSQL_SCHEMA_NAME.str, db) == 0))
+ if ((rm_mysql_schema=
+ (my_strcasecmp(system_charset_info, MYSQL_SCHEMA_NAME.str, db) == 0)))
{
for (table= tables; table; table= table->next_local)
if (check_if_log_table(table, TRUE, "DROP"))
@@ -880,7 +893,7 @@ mysql_rm_db_internal(THD *thd,char *db, bool if_exists, bool silent)
lock_db_routines(thd, dbnorm))
goto exit;
- if (!in_bootstrap)
+ if (!in_bootstrap && !rm_mysql_schema)
{
for (table= tables; table; table= table->next_local)
{
@@ -921,10 +934,13 @@ mysql_rm_db_internal(THD *thd,char *db, bool if_exists, bool silent)
ha_drop_database(path);
tmp_disable_binlog(thd);
query_cache_invalidate1(thd, dbnorm);
- (void) sp_drop_db_routines(thd, dbnorm); /* @todo Do not ignore errors */
+ if (!rm_mysql_schema)
+ {
+ (void) sp_drop_db_routines(thd, dbnorm); /* @todo Do not ignore errors */
#ifdef HAVE_EVENT_SCHEDULER
- Events::drop_schema_events(thd, dbnorm);
+ Events::drop_schema_events(thd, dbnorm);
#endif
+ }
reenable_binlog(thd);
/*
diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc
index 1156b3b8305..daac90d56f6 100644
--- a/sql/sql_derived.cc
+++ b/sql/sql_derived.cc
@@ -713,6 +713,7 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived)
}
unit->derived= derived;
+ derived->fill_me= FALSE;
if (!(derived->derived_result= new (thd->mem_root) select_union(thd)))
DBUG_RETURN(TRUE); // out of memory
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 45a6bf59b99..b2dd04d8fd5 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -1319,7 +1319,7 @@ static int lex_one_token(YYSTYPE *yylval, THD *thd)
state= (enum my_lex_states) state_map[c];
break;
case MY_LEX_ESCAPE:
- if (lip->yyGet() == 'N')
+ if (!lip->eof() && lip->yyGet() == 'N')
{ // Allow \N as shortcut for NULL
yylval->lex_str.str=(char*) "\\N";
yylval->lex_str.length=2;
@@ -3740,12 +3740,28 @@ bool st_select_lex::add_index_hint (THD *thd, char *str, uint length)
bool st_select_lex::optimize_unflattened_subqueries(bool const_only)
{
- for (SELECT_LEX_UNIT *un= first_inner_unit(); un; un= un->next_unit())
+ SELECT_LEX_UNIT *next_unit= NULL;
+ for (SELECT_LEX_UNIT *un= first_inner_unit();
+ un;
+ un= next_unit ? next_unit : un->next_unit())
{
Item_subselect *subquery_predicate= un->item;
-
+ next_unit= NULL;
+
if (subquery_predicate)
{
+ if (!subquery_predicate->fixed)
+ {
+ /*
+ This subquery was excluded as part of some expression so it is
+ invisible from all prepared expression.
+ */
+ next_unit= un->next_unit();
+ un->exclude_level();
+ if (next_unit)
+ continue;
+ break;
+ }
if (subquery_predicate->substype() == Item_subselect::IN_SUBS)
{
Item_in_subselect *in_subs= (Item_in_subselect*) subquery_predicate;
diff --git a/sql/sql_load.cc b/sql/sql_load.cc
index 509df96e89d..c25e73e7346 100644
--- a/sql/sql_load.cc
+++ b/sql/sql_load.cc
@@ -616,7 +616,8 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
*enclosed, skip_lines, ignore);
thd_proc_info(thd, "End bulk insert");
- thd_progress_next_stage(thd);
+ if (!error)
+ thd_progress_next_stage(thd);
if (thd->locked_tables_mode <= LTM_LOCK_TABLES &&
table->file->ha_end_bulk_insert() && !error)
{
@@ -1525,6 +1526,54 @@ inline bool READ_INFO::terminator(const uchar *ptr, uint length)
}
+/**
+ Read a field.
+
+ The data in the loaded file was presumably escaped using
+ - either select_export::send_data() OUTFILE
+ - or mysql_real_escape_string()
+ using the same character set with the one specified in the current
+ "LOAD DATA INFILE ... CHARACTER SET ..." (or the default LOAD character set).
+
+ Note, non-escaped multi-byte characters are scanned as a single entity.
+ This is needed to correctly distinguish between:
+ - 0x5C as an escape character versus
+ - 0x5C as the second byte in a multi-byte sequence (big5, cp932, gbk, sjis)
+
+ Parts of escaped multi-byte characters are scanned on different loop
+ iterations. See the comment about 0x5C handling in select_export::send_data()
+ in sql_class.cc.
+
+ READ_INFO::read_field() does not check wellformedness.
+ Raising wellformedness errors or warnings in READ_INFO::read_field()
+ would be wrong, as the data after unescaping can go into a BLOB field,
+ or into a TEXT/VARCHAR field of a different character set.
+ The loop below only makes sure to revert escaping made by
+ select_export::send_data() or mysql_real_escape_string().
+ Wellformedness is checked later, during Field::store(str,length,cs) time.
+
+ Note, in some cases users can supply data which did not go through
+ escaping properly. For example, utf8 "\<C3><A4>"
+ (backslash followed by LATIN SMALL LETTER A WITH DIAERESIS)
+ is improperly escaped data that could not be generated by
+ select_export::send_data() / mysql_real_escape_string():
+ - either there should be two backslashes: "\\<C3><A4>"
+ - or there should be no backslashes at all: "<C3><A4>"
+ "\<C3>" and "<A4> are scanned on two different loop iterations and
+ store "<C3><A4>" into the field.
+
+ Note, adding useless escapes before multi-byte characters like in the
+ example above is safe in case of utf8, but is not safe in case of
+ character sets that have escape_with_backslash_is_dangerous==TRUE,
+ such as big5, cp932, gbk, sjis. This can lead to mis-interpretation of the
+ data. Suppose we have a big5 character "<EE><5C>" followed by <30> (digit 0).
+ If we add an extra escape before this sequence, then we'll get
+ <5C><EE><5C><30>. The first loop iteration will turn <5C><EE> into <EE>.
+ The second loop iteration will turn <5C><30> into <30>.
+ So the program that generates a dump file for further use with LOAD DATA
+ must make sure to use escapes properly.
+*/
+
int READ_INFO::read_field()
{
int chr,found_enclosed_char;
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 370a4bd7400..06387c2b894 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -3106,13 +3106,16 @@ mysql_execute_command(THD *thd)
}
/*
- Bail out if DB snapshot has not been installed. We however, allow SET,
- SHOW and SELECT queries (only if wsrep_dirty_reads is set).
+ Bail out if DB snapshot has not been installed. SET and SHOW commands,
+ however, are always allowed.
+
+ We additionally allow all other commands that do not change data in
+ case wsrep_dirty_reads is enabled.
*/
if (lex->sql_command != SQLCOM_SET_OPTION &&
!wsrep_is_show_query(lex->sql_command) &&
!(thd->variables.wsrep_dirty_reads &&
- lex->sql_command == SQLCOM_SELECT) &&
+ !is_update_query(lex->sql_command)) &&
!wsrep_node_is_ready(thd))
goto error;
}
@@ -3730,12 +3733,6 @@ mysql_execute_command(THD *thd)
}
/*
- For CREATE TABLE we should not open the table even if it exists.
- If the table exists, we should either not create it or replace it
- */
- lex->query_tables->open_strategy= TABLE_LIST::OPEN_STUB;
-
- /*
If we are a slave, we should add OR REPLACE if we don't have
IF EXISTS. This will help a slave to recover from
CREATE TABLE OR EXISTS failures by dropping the table and
@@ -9445,12 +9442,6 @@ bool create_table_precheck(THD *thd, TABLE_LIST *tables,
if (check_fk_parent_table_access(thd, &lex->create_info, &lex->alter_info, create_table->db))
goto err;
- /*
- For CREATE TABLE we should not open the table even if it exists.
- If the table exists, we should either not create it or replace it
- */
- lex->query_tables->open_strategy= TABLE_LIST::OPEN_STUB;
-
error= FALSE;
err:
diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc
index 58d6ff4cd00..aea83f41527 100644
--- a/sql/sql_plugin.cc
+++ b/sql/sql_plugin.cc
@@ -2864,6 +2864,22 @@ static st_bookmark *find_bookmark(const char *plugin, const char *name,
}
+static size_t var_storage_size(int flags)
+{
+ switch (flags & PLUGIN_VAR_TYPEMASK) {
+ case PLUGIN_VAR_BOOL: return sizeof(my_bool);
+ case PLUGIN_VAR_INT: return sizeof(int);
+ case PLUGIN_VAR_LONG: return sizeof(long);
+ case PLUGIN_VAR_ENUM: return sizeof(long);
+ case PLUGIN_VAR_LONGLONG: return sizeof(ulonglong);
+ case PLUGIN_VAR_SET: return sizeof(ulonglong);
+ case PLUGIN_VAR_STR: return sizeof(char*);
+ case PLUGIN_VAR_DOUBLE: return sizeof(double);
+ default: DBUG_ASSERT(0); return 0;
+ }
+}
+
+
/*
returns a bookmark for thd-local variables, creating if neccessary.
returns null for non thd-local variables.
@@ -2872,39 +2888,13 @@ static st_bookmark *find_bookmark(const char *plugin, const char *name,
static st_bookmark *register_var(const char *plugin, const char *name,
int flags)
{
- uint length= strlen(plugin) + strlen(name) + 3, size= 0, offset, new_size;
+ uint length= strlen(plugin) + strlen(name) + 3, size, offset, new_size;
st_bookmark *result;
char *varname, *p;
- if (!(flags & PLUGIN_VAR_THDLOCAL))
- return NULL;
-
- switch (flags & PLUGIN_VAR_TYPEMASK) {
- case PLUGIN_VAR_BOOL:
- size= sizeof(my_bool);
- break;
- case PLUGIN_VAR_INT:
- size= sizeof(int);
- break;
- case PLUGIN_VAR_LONG:
- case PLUGIN_VAR_ENUM:
- size= sizeof(long);
- break;
- case PLUGIN_VAR_LONGLONG:
- case PLUGIN_VAR_SET:
- size= sizeof(ulonglong);
- break;
- case PLUGIN_VAR_STR:
- size= sizeof(char*);
- break;
- case PLUGIN_VAR_DOUBLE:
- size= sizeof(double);
- break;
- default:
- DBUG_ASSERT(0);
- return NULL;
- };
+ DBUG_ASSERT(flags & PLUGIN_VAR_THDLOCAL);
+ size= var_storage_size(flags);
varname= ((char*) my_alloca(length));
strxmov(varname + 1, plugin, "_", name, NullS);
for (p= varname + 1; *p; p++)
@@ -2998,25 +2988,17 @@ void sync_dynamic_session_variables(THD* thd, bool global_lock)
*/
for (idx= 0; idx < bookmark_hash.records; idx++)
{
- sys_var_pluginvar *pi;
- sys_var *var;
st_bookmark *v= (st_bookmark*) my_hash_element(&bookmark_hash,idx);
if (v->version <= thd->variables.dynamic_variables_version)
continue; /* already in thd->variables */
- if (!(var= intern_find_sys_var(v->key + 1, v->name_len)) ||
- !(pi= var->cast_pluginvar()) ||
- v->key[0] != plugin_var_bookmark_key(pi->plugin_var->flags))
- continue;
-
/* Here we do anything special that may be required of the data types */
- if ((pi->plugin_var->flags & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_STR &&
- pi->plugin_var->flags & PLUGIN_VAR_MEMALLOC)
+ if ((v->key[0] & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_STR &&
+ v->key[0] & BOOKMARK_MEMALLOC)
{
- int offset= ((thdvar_str_t *)(pi->plugin_var))->offset;
- char **pp= (char**) (thd->variables.dynamic_variables_ptr + offset);
+ char **pp= (char**) (thd->variables.dynamic_variables_ptr + v->offset);
if (*pp)
*pp= my_strdup(*pp, MYF(MY_WME|MY_FAE));
}
@@ -3454,69 +3436,58 @@ bool sys_var_pluginvar::session_update(THD *thd, set_var *var)
return false;
}
-bool sys_var_pluginvar::global_update(THD *thd, set_var *var)
+static const void *var_def_ptr(st_mysql_sys_var *pv)
{
- DBUG_ASSERT(!is_readonly());
- mysql_mutex_assert_owner(&LOCK_global_system_variables);
-
- void *tgt= real_value_ptr(thd, OPT_GLOBAL);
- const void *src= &var->save_result;
-
- if (!var->value)
- {
- switch (plugin_var->flags & (PLUGIN_VAR_TYPEMASK | PLUGIN_VAR_THDLOCAL)) {
+ switch (pv->flags & (PLUGIN_VAR_TYPEMASK | PLUGIN_VAR_THDLOCAL)) {
case PLUGIN_VAR_INT:
- src= &((sysvar_uint_t*) plugin_var)->def_val;
- break;
+ return &((sysvar_uint_t*) pv)->def_val;
case PLUGIN_VAR_LONG:
- src= &((sysvar_ulong_t*) plugin_var)->def_val;
- break;
+ return &((sysvar_ulong_t*) pv)->def_val;
case PLUGIN_VAR_LONGLONG:
- src= &((sysvar_ulonglong_t*) plugin_var)->def_val;
- break;
+ return &((sysvar_ulonglong_t*) pv)->def_val;
case PLUGIN_VAR_ENUM:
- src= &((sysvar_enum_t*) plugin_var)->def_val;
- break;
+ return &((sysvar_enum_t*) pv)->def_val;
case PLUGIN_VAR_SET:
- src= &((sysvar_set_t*) plugin_var)->def_val;
- break;
+ return &((sysvar_set_t*) pv)->def_val;
case PLUGIN_VAR_BOOL:
- src= &((sysvar_bool_t*) plugin_var)->def_val;
- break;
+ return &((sysvar_bool_t*) pv)->def_val;
case PLUGIN_VAR_STR:
- src= &((sysvar_str_t*) plugin_var)->def_val;
- break;
+ return &((sysvar_str_t*) pv)->def_val;
case PLUGIN_VAR_DOUBLE:
- src= &((sysvar_double_t*) plugin_var)->def_val;
- break;
+ return &((sysvar_double_t*) pv)->def_val;
case PLUGIN_VAR_INT | PLUGIN_VAR_THDLOCAL:
- src= &((thdvar_uint_t*) plugin_var)->def_val;
- break;
+ return &((thdvar_uint_t*) pv)->def_val;
case PLUGIN_VAR_LONG | PLUGIN_VAR_THDLOCAL:
- src= &((thdvar_ulong_t*) plugin_var)->def_val;
- break;
+ return &((thdvar_ulong_t*) pv)->def_val;
case PLUGIN_VAR_LONGLONG | PLUGIN_VAR_THDLOCAL:
- src= &((thdvar_ulonglong_t*) plugin_var)->def_val;
- break;
+ return &((thdvar_ulonglong_t*) pv)->def_val;
case PLUGIN_VAR_ENUM | PLUGIN_VAR_THDLOCAL:
- src= &((thdvar_enum_t*) plugin_var)->def_val;
- break;
+ return &((thdvar_enum_t*) pv)->def_val;
case PLUGIN_VAR_SET | PLUGIN_VAR_THDLOCAL:
- src= &((thdvar_set_t*) plugin_var)->def_val;
- break;
+ return &((thdvar_set_t*) pv)->def_val;
case PLUGIN_VAR_BOOL | PLUGIN_VAR_THDLOCAL:
- src= &((thdvar_bool_t*) plugin_var)->def_val;
- break;
+ return &((thdvar_bool_t*) pv)->def_val;
case PLUGIN_VAR_STR | PLUGIN_VAR_THDLOCAL:
- src= &((thdvar_str_t*) plugin_var)->def_val;
- break;
+ return &((thdvar_str_t*) pv)->def_val;
case PLUGIN_VAR_DOUBLE | PLUGIN_VAR_THDLOCAL:
- src= &((thdvar_double_t*) plugin_var)->def_val;
- break;
+ return &((thdvar_double_t*) pv)->def_val;
default:
DBUG_ASSERT(0);
+ return NULL;
}
- }
+}
+
+
+bool sys_var_pluginvar::global_update(THD *thd, set_var *var)
+{
+ DBUG_ASSERT(!is_readonly());
+ mysql_mutex_assert_owner(&LOCK_global_system_variables);
+
+ void *tgt= real_value_ptr(thd, OPT_GLOBAL);
+ const void *src= &var->save_result;
+
+ if (!var->value)
+ src= var_def_ptr(plugin_var);
plugin_var->update(thd, plugin_var, tgt, src);
return false;
@@ -3869,7 +3840,18 @@ static int construct_options(MEM_ROOT *mem_root, struct st_plugin_int *tmp,
*(int*)(opt + 1)= offset= v->offset;
if (opt->flags & PLUGIN_VAR_NOCMDOPT)
+ {
+ char *val= global_system_variables.dynamic_variables_ptr + offset;
+ if (((opt->flags & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_STR) &&
+ (opt->flags & PLUGIN_VAR_MEMALLOC))
+ {
+ char *def_val= *(char**)var_def_ptr(opt);
+ *(char**)val= def_val ? my_strdup(def_val, MYF(0)) : NULL;
+ }
+ else
+ memcpy(val, var_def_ptr(opt), var_storage_size(opt->flags));
continue;
+ }
optname= (char*) memdup_root(mem_root, v->key + 1,
(optnamelen= v->name_len) + 1);
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index fcd778d556c..d7a23a41002 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -4034,9 +4034,14 @@ Prepared_statement::execute_loop(String *expanded_query,
bool error;
int reprepare_attempt= 0;
iterations= 0;
-#ifndef DBUG_OFF
- Item *free_list_state= thd->free_list;
-#endif
+
+ /*
+ - In mysql_sql_stmt_execute() we hide all "external" Items
+ e.g. those created in the "SET STATEMENT" part of the "EXECUTE" query.
+ - In case of mysqld_stmt_execute() there should not be "external" Items.
+ */
+ DBUG_ASSERT(thd->free_list == NULL);
+
thd->select_number= select_number_after_prepare;
/* Check if we got an error when sending long data */
if (state == Query_arena::STMT_ERROR)
@@ -4058,12 +4063,8 @@ Prepared_statement::execute_loop(String *expanded_query,
#endif
reexecute:
- /*
- If the free_list is not empty, we'll wrongly free some externally
- allocated items when cleaning up after validation of the prepared
- statement.
- */
- DBUG_ASSERT(thd->free_list == free_list_state);
+ // Make sure that reprepare() did not create any new Items.
+ DBUG_ASSERT(thd->free_list == NULL);
/*
Install the metadata observer. If some metadata version is
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index c115ac5f0ec..2a22810b8c2 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -2205,6 +2205,7 @@ static int send_format_descriptor_event(binlog_send_info *info, IO_CACHE *log,
THD *thd= info->thd;
String *packet= info->packet;
Log_event_type event_type;
+ DBUG_ENTER("send_format_descriptor_event");
/**
* 1) reset fdev before each log-file
@@ -2219,12 +2220,12 @@ static int send_format_descriptor_event(binlog_send_info *info, IO_CACHE *log,
{
info->errmsg= "Out of memory initializing format_description event";
info->error= ER_MASTER_FATAL_ERROR_READING_BINLOG;
- return 1;
+ DBUG_RETURN(1);
}
/* reset transmit packet for the event read from binary log file */
if (reset_transmit_packet(info, info->flags, &ev_offset, &info->errmsg))
- return 1;
+ DBUG_RETURN(1);
/*
Try to find a Format_description_log_event at the beginning of
@@ -2240,7 +2241,7 @@ static int send_format_descriptor_event(binlog_send_info *info, IO_CACHE *log,
if (error)
{
set_read_error(info, error);
- return 1;
+ DBUG_RETURN(1);
}
event_type= (Log_event_type)((uchar)(*packet)[LOG_EVENT_OFFSET+ev_offset]);
@@ -2261,7 +2262,7 @@ static int send_format_descriptor_event(binlog_send_info *info, IO_CACHE *log,
sql_print_warning("Failed to find format descriptor event in "
"start of binlog: %s",
info->log_file_name);
- return 1;
+ DBUG_RETURN(1);
}
info->current_checksum_alg= get_checksum_alg(packet->ptr() + ev_offset,
@@ -2281,7 +2282,7 @@ static int send_format_descriptor_event(binlog_send_info *info, IO_CACHE *log,
sql_print_warning("Master is configured to log replication events "
"with checksum, but will not send such events to "
"slaves that cannot process them");
- return 1;
+ DBUG_RETURN(1);
}
uint ev_len= packet->length() - ev_offset;
@@ -2295,7 +2296,7 @@ static int send_format_descriptor_event(binlog_send_info *info, IO_CACHE *log,
info->error= ER_MASTER_FATAL_ERROR_READING_BINLOG;
info->errmsg= "Corrupt Format_description event found "
"or out-of-memory";
- return 1;
+ DBUG_RETURN(1);
}
delete info->fdev;
info->fdev= tmp;
@@ -2354,7 +2355,7 @@ static int send_format_descriptor_event(binlog_send_info *info, IO_CACHE *log,
{
info->errmsg= "Failed on my_net_write()";
info->error= ER_UNKNOWN_ERROR;
- return 1;
+ DBUG_RETURN(1);
}
/*
@@ -2374,7 +2375,7 @@ static int send_format_descriptor_event(binlog_send_info *info, IO_CACHE *log,
if (error)
{
set_read_error(info, error);
- return 1;
+ DBUG_RETURN(1);
}
event_type= (Log_event_type)((uchar)(*packet)[LOG_EVENT_OFFSET]);
@@ -2386,14 +2387,15 @@ static int send_format_descriptor_event(binlog_send_info *info, IO_CACHE *log,
if (!sele)
{
info->error= ER_MASTER_FATAL_ERROR_READING_BINLOG;
- return 1;
+ DBUG_RETURN(1);
}
if (info->fdev->start_decryption(sele))
{
info->error= ER_MASTER_FATAL_ERROR_READING_BINLOG;
info->errmsg= "Could not decrypt binlog: encryption key error";
- return 1;
+ delete sele;
+ DBUG_RETURN(1);
}
delete sele;
}
@@ -2409,7 +2411,7 @@ static int send_format_descriptor_event(binlog_send_info *info, IO_CACHE *log,
/** all done */
- return 0;
+ DBUG_RETURN(0);
}
static bool should_stop(binlog_send_info *info)
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 89a9eeb1e32..2889e1e1549 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -11857,7 +11857,7 @@ void JOIN::join_free()
/**
Free resources of given join.
- @param fill true if we should free all resources, call with full==1
+ @param full true if we should free all resources, call with full==1
should be last, before it this function can be called with
full==0
@@ -11969,7 +11969,7 @@ void JOIN::cleanup(bool full)
/*
If we have tmp_join and 'this' JOIN is not tmp_join and
tmp_table_param.copy_field's of them are equal then we have to remove
- pointer to tmp_table_param.copy_field from tmp_join, because it qill
+ pointer to tmp_table_param.copy_field from tmp_join, because it will
be removed in tmp_table_param.cleanup().
*/
tmp_table_param.cleanup();
@@ -15111,20 +15111,9 @@ bool cond_is_datetime_is_null(Item *cond)
if (cond->type() == Item::FUNC_ITEM &&
((Item_func*) cond)->functype() == Item_func::ISNULL_FUNC)
{
- Item **args= ((Item_func_isnull*) cond)->arguments();
- if (args[0]->type() == Item::FIELD_ITEM)
- {
- Field *field=((Item_field*) args[0])->field;
-
- if (((field->type() == MYSQL_TYPE_DATE) ||
- (field->type() == MYSQL_TYPE_DATETIME)) &&
- (field->flags & NOT_NULL_FLAG))
- {
- return TRUE;
- }
- }
+ return ((Item_func_isnull*) cond)->arg_is_datetime_notnull_field();
}
- return FALSE;
+ return false;
}
@@ -16082,6 +16071,7 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
case Item::CACHE_ITEM:
case Item::WINDOW_FUNC_ITEM: // psergey-winfunc:
case Item::EXPR_CACHE_ITEM:
+ case Item::PARAM_ITEM:
if (make_copy_field)
{
DBUG_ASSERT(((Item_result_field*)item)->result_field);
@@ -22853,7 +22843,7 @@ setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param,
err:
if (copy)
delete [] param->copy_field; // This is never 0
- param->copy_field=0;
+ param->copy_field= 0;
err2:
DBUG_RETURN(TRUE);
}
diff --git a/sql/sql_statistics.cc b/sql/sql_statistics.cc
index adbc52d1eec..6de8727876c 100644
--- a/sql/sql_statistics.cc
+++ b/sql/sql_statistics.cc
@@ -130,6 +130,128 @@ inline void init_table_list_for_single_stat_table(TABLE_LIST *tbl,
}
+static Table_check_intact_log_error stat_table_intact;
+
+static const
+TABLE_FIELD_TYPE table_stat_fields[TABLE_STAT_N_FIELDS] =
+{
+ {
+ { C_STRING_WITH_LEN("db_name") },
+ { C_STRING_WITH_LEN("varchar(64)") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("table_name") },
+ { C_STRING_WITH_LEN("varchar(64)") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("cardinality") },
+ { C_STRING_WITH_LEN("bigint(21)") },
+ { NULL, 0 }
+ },
+};
+static const uint table_stat_pk_col[]= {0,1};
+static const TABLE_FIELD_DEF
+table_stat_def= {TABLE_STAT_N_FIELDS, table_stat_fields, 2, table_stat_pk_col };
+
+static const
+TABLE_FIELD_TYPE column_stat_fields[COLUMN_STAT_N_FIELDS] =
+{
+ {
+ { C_STRING_WITH_LEN("db_name") },
+ { C_STRING_WITH_LEN("varchar(64)") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("table_name") },
+ { C_STRING_WITH_LEN("varchar(64)") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("column_name") },
+ { C_STRING_WITH_LEN("varchar(64)") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("min_value") },
+ { C_STRING_WITH_LEN("varbinary(255)") },
+ { NULL, 0 }
+ },
+ {
+ { C_STRING_WITH_LEN("max_value") },
+ { C_STRING_WITH_LEN("varbinary(255)") },
+ { NULL, 0 }
+ },
+ {
+ { C_STRING_WITH_LEN("nulls_ratio") },
+ { C_STRING_WITH_LEN("decimal(12,4)") },
+ { NULL, 0 }
+ },
+ {
+ { C_STRING_WITH_LEN("avg_length") },
+ { C_STRING_WITH_LEN("decimal(12,4)") },
+ { NULL, 0 }
+ },
+ {
+ { C_STRING_WITH_LEN("avg_frequency") },
+ { C_STRING_WITH_LEN("decimal(12,4)") },
+ { NULL, 0 }
+ },
+ {
+ { C_STRING_WITH_LEN("hist_size") },
+ { C_STRING_WITH_LEN("tinyint(3)") },
+ { NULL, 0 }
+ },
+ {
+ { C_STRING_WITH_LEN("hist_type") },
+ { C_STRING_WITH_LEN("enum('SINGLE_PREC_HB','DOUBLE_PREC_HB')") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("histogram") },
+ { C_STRING_WITH_LEN("varbinary(255)") },
+ { NULL, 0 }
+ }
+};
+static const uint column_stat_pk_col[]= {0,1,2};
+static const TABLE_FIELD_DEF
+column_stat_def= {COLUMN_STAT_N_FIELDS, column_stat_fields, 3, column_stat_pk_col};
+
+static const
+TABLE_FIELD_TYPE index_stat_fields[INDEX_STAT_N_FIELDS] =
+{
+ {
+ { C_STRING_WITH_LEN("db_name") },
+ { C_STRING_WITH_LEN("varchar(64)") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("table_name") },
+ { C_STRING_WITH_LEN("varchar(64)") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("index") },
+ { C_STRING_WITH_LEN("varchar(64)") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("prefix_arity") },
+ { C_STRING_WITH_LEN("int(11)") },
+ { NULL, 0 }
+ },
+ {
+ { C_STRING_WITH_LEN("avg_frequency") },
+ { C_STRING_WITH_LEN("decimal(12,4)") },
+ { NULL, 0 }
+ }
+};
+static const uint index_stat_pk_col[]= {0,1,2,3};
+static const TABLE_FIELD_DEF
+index_stat_def= {INDEX_STAT_N_FIELDS, index_stat_fields, 4, index_stat_pk_col};
+
+
/**
@brief
Open all statistical tables and lock them
@@ -140,10 +262,30 @@ inline int open_stat_tables(THD *thd, TABLE_LIST *tables,
Open_tables_backup *backup,
bool for_write)
{
+ int rc;
+
+ Dummy_error_handler deh; // suppress errors
+ thd->push_internal_handler(&deh);
init_table_list_for_stat_tables(tables, for_write);
init_mdl_requests(tables);
- return open_system_tables_for_read(thd, tables, backup);
-}
+ rc= open_system_tables_for_read(thd, tables, backup);
+ thd->pop_internal_handler();
+
+
+ /* If the number of tables changes, we should revise the check below. */
+ DBUG_ASSERT(STATISTICS_TABLES == 3);
+
+ if (!rc &&
+ (stat_table_intact.check(tables[TABLE_STAT].table, &table_stat_def) ||
+ stat_table_intact.check(tables[COLUMN_STAT].table, &column_stat_def) ||
+ stat_table_intact.check(tables[INDEX_STAT].table, &index_stat_def)))
+ {
+ close_system_tables(thd, backup);
+ rc= 1;
+ }
+
+ return rc;
+}
/**
@@ -1004,11 +1146,13 @@ public:
switch (i) {
case COLUMN_STAT_MIN_VALUE:
+ table_field->read_stats->min_value->set_notnull();
stat_field->val_str(&val);
table_field->read_stats->min_value->store(val.ptr(), val.length(),
&my_charset_bin);
break;
case COLUMN_STAT_MAX_VALUE:
+ table_field->read_stats->max_value->set_notnull();
stat_field->val_str(&val);
table_field->read_stats->max_value->store(val.ptr(), val.length(),
&my_charset_bin);
@@ -2725,10 +2869,7 @@ int update_statistics_for_table(THD *thd, TABLE *table)
DEBUG_SYNC(thd, "statistics_update_start");
if (open_stat_tables(thd, tables, &open_tables_backup, TRUE))
- {
- thd->clear_error();
DBUG_RETURN(rc);
- }
save_binlog_format= thd->set_current_stmt_binlog_format_stmt();
@@ -3156,10 +3297,7 @@ int delete_statistics_for_table(THD *thd, LEX_STRING *db, LEX_STRING *tab)
DBUG_ENTER("delete_statistics_for_table");
if (open_stat_tables(thd, tables, &open_tables_backup, TRUE))
- {
- thd->clear_error();
DBUG_RETURN(rc);
- }
save_binlog_format= thd->set_current_stmt_binlog_format_stmt();
@@ -3398,10 +3536,7 @@ int rename_table_in_stat_tables(THD *thd, LEX_STRING *db, LEX_STRING *tab,
DBUG_ENTER("rename_table_in_stat_tables");
if (open_stat_tables(thd, tables, &open_tables_backup, TRUE))
- {
- thd->clear_error();
- DBUG_RETURN(rc);
- }
+ DBUG_RETURN(0); // not an error
save_binlog_format= thd->set_current_stmt_binlog_format_stmt();
@@ -3661,17 +3796,8 @@ double get_column_range_cardinality(Field *field,
{
double avg_frequency= col_stats->get_avg_frequency();
res= avg_frequency;
- /*
- psergey-todo: what does check for min_value, max_value mean?
- min/max_value are set to NULL in alloc_statistics_for_table() and
- alloc_statistics_for_table_share(). Both functions will immediately
- call create_min_max_statistical_fields_for_table and
- create_min_max_statistical_fields_for_table_share() respectively,
- which will set min/max_value to be valid pointers, unless OOM
- occurs.
- */
if (avg_frequency > 1.0 + 0.000001 &&
- col_stats->min_value && col_stats->max_value)
+ col_stats->min_max_values_are_provided())
{
Histogram *hist= &col_stats->histogram;
if (hist->is_available())
@@ -3694,7 +3820,7 @@ double get_column_range_cardinality(Field *field,
}
else
{
- if (col_stats->min_value && col_stats->max_value)
+ if (col_stats->min_max_values_are_provided())
{
double sel, min_mp_pos, max_mp_pos;
diff --git a/sql/sql_statistics.h b/sql/sql_statistics.h
index daffd792ba0..f46583839d1 100644
--- a/sql/sql_statistics.h
+++ b/sql/sql_statistics.h
@@ -52,7 +52,8 @@ enum enum_table_stat_col
{
TABLE_STAT_DB_NAME,
TABLE_STAT_TABLE_NAME,
- TABLE_STAT_CARDINALITY
+ TABLE_STAT_CARDINALITY,
+ TABLE_STAT_N_FIELDS
};
enum enum_column_stat_col
@@ -67,7 +68,8 @@ enum enum_column_stat_col
COLUMN_STAT_AVG_FREQUENCY,
COLUMN_STAT_HIST_SIZE,
COLUMN_STAT_HIST_TYPE,
- COLUMN_STAT_HISTOGRAM
+ COLUMN_STAT_HISTOGRAM,
+ COLUMN_STAT_N_FIELDS
};
enum enum_index_stat_col
@@ -76,7 +78,8 @@ enum enum_index_stat_col
INDEX_STAT_TABLE_NAME,
INDEX_STAT_INDEX_NAME,
INDEX_STAT_PREFIX_ARITY,
- INDEX_STAT_AVG_FREQUENCY
+ INDEX_STAT_AVG_FREQUENCY,
+ INDEX_STAT_N_FIELDS
};
inline
@@ -389,6 +392,11 @@ public:
avg_frequency= (ulong) (val * Scale_factor_avg_frequency);
}
+ bool min_max_values_are_provided()
+ {
+ return !is_null(COLUMN_STAT_MIN_VALUE) &&
+ !is_null(COLUMN_STAT_MIN_VALUE);
+ }
};
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index f8a61b641c0..b22f831ddab 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -671,7 +671,7 @@ static bool read_ddl_log_file_entry(uint entry_no)
bool error= FALSE;
File file_id= global_ddl_log.file_id;
uchar *file_entry_buf= (uchar*)global_ddl_log.file_entry_buf;
- uint io_size= global_ddl_log.io_size;
+ size_t io_size= global_ddl_log.io_size;
DBUG_ENTER("read_ddl_log_file_entry");
mysql_mutex_assert_owner(&LOCK_gdl);
@@ -2441,7 +2441,8 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
if (table_type && table_type != view_pseudo_hton)
ha_lock_engine(thd, table_type);
- if (thd->locked_tables_mode)
+ if (thd->locked_tables_mode == LTM_LOCK_TABLES ||
+ thd->locked_tables_mode == LTM_PRELOCKED_UNDER_LOCK_TABLES)
{
if (wait_while_table_is_used(thd, table->table, HA_EXTRA_NOT_USED))
{
@@ -3103,8 +3104,7 @@ void promote_first_timestamp_column(List<Create_field> *column_definitions)
@param key_info Key meta-data info.
@param key_list List of existing keys.
*/
-static void check_duplicate_key(THD *thd,
- Key *key, KEY *key_info,
+static void check_duplicate_key(THD *thd, Key *key, KEY *key_info,
List<Key> *key_list)
{
/*
@@ -3166,14 +3166,11 @@ static void check_duplicate_key(THD *thd,
// Report a warning if we have two identical keys.
- DBUG_ASSERT(thd->lex->query_tables->alias);
if (all_columns_are_identical)
{
push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
ER_DUP_INDEX, ER_THD(thd, ER_DUP_INDEX),
- key_info->name,
- thd->lex->query_tables->db,
- thd->lex->query_tables->alias);
+ key_info->name);
break;
}
}
diff --git a/sql/sql_time.cc b/sql/sql_time.cc
index 5ef036965b8..cad4bae03e8 100644
--- a/sql/sql_time.cc
+++ b/sql/sql_time.cc
@@ -929,7 +929,10 @@ bool date_add_interval(MYSQL_TIME *ltime, interval_type int_type,
my_bool neg= 0;
enum enum_mysql_timestamp_type time_type= ltime->time_type;
- if ((ulong) interval.day > MAX_DAY_NUMBER)
+ if (((ulonglong) interval.day +
+ (ulonglong) interval.hour / 24 +
+ (ulonglong) interval.minute / 24 / 60 +
+ (ulonglong) interval.second / 24 / 60 / 60) > MAX_DAY_NUMBER)
goto invalid_date;
if (time_type != MYSQL_TIMESTAMP_TIME)
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 2cd84a27d45..ff4a5e12e56 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -15720,6 +15720,7 @@ grant_role:
CHARSET_INFO *cs= system_charset_info;
/* trim end spaces (as they'll be lost in mysql.user anyway) */
$1.length= cs->cset->lengthsp(cs, $1.str, $1.length);
+ $1.str[$1.length] = '\0';
if ($1.length == 0)
my_yyabort_error((ER_INVALID_ROLE, MYF(0), ""));
if (!($$=(LEX_USER*) thd->alloc(sizeof(st_lex_user))))
diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc
index 27e6463eb58..bdfedc30d46 100644
--- a/sql/sys_vars.cc
+++ b/sql/sys_vars.cc
@@ -3236,7 +3236,7 @@ static bool fix_table_open_cache(sys_var *, THD *, enum_var_type)
static Sys_var_ulong Sys_table_cache_size(
"table_open_cache", "The number of cached open tables",
GLOBAL_VAR(tc_size), CMD_LINE(REQUIRED_ARG),
- VALID_RANGE(1, 512*1024), DEFAULT(TABLE_OPEN_CACHE_DEFAULT),
+ VALID_RANGE(1, 1024*1024), DEFAULT(TABLE_OPEN_CACHE_DEFAULT),
BLOCK_SIZE(1), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
ON_UPDATE(fix_table_open_cache));
@@ -5042,8 +5042,9 @@ static Sys_var_mybool Sys_wsrep_restart_slave(
GLOBAL_VAR(wsrep_restart_slave), CMD_LINE(OPT_ARG), DEFAULT(FALSE));
static Sys_var_mybool Sys_wsrep_dirty_reads(
- "wsrep_dirty_reads", "Do not reject SELECT queries even when the node "
- "is not ready.", SESSION_ONLY(wsrep_dirty_reads), NO_CMD_LINE,
+ "wsrep_dirty_reads",
+ "Allow reads even when the node is not in the primary component.",
+ SESSION_VAR(wsrep_dirty_reads), CMD_LINE(OPT_ARG),
DEFAULT(FALSE), NO_MUTEX_GUARD, NOT_IN_BINLOG);
static Sys_var_uint Sys_wsrep_gtid_domain_id(
diff --git a/sql/table.cc b/sql/table.cc
index 71c70e2df2e..4688b77ecd7 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -4203,6 +4203,15 @@ Table_check_intact::check(TABLE *table, const TABLE_FIELD_DEF *table_def)
}
+void Table_check_intact_log_error::report_error(uint, const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ error_log_print(ERROR_LEVEL, fmt, args);
+ va_end(args);
+}
+
+
/**
Traverse portion of wait-for graph which is reachable through edge
represented by this flush ticket in search for deadlocks.
diff --git a/sql/table.h b/sql/table.h
index c2c523181a0..6552a8e13da 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -480,6 +480,16 @@ public:
};
+/*
+ If the table isn't valid, report the error to the server log only.
+*/
+class Table_check_intact_log_error : public Table_check_intact
+{
+protected:
+ void report_error(uint, const char *fmt, ...);
+};
+
+
/**
Class representing the fact that some thread waits for table
share to be flushed. Is used to represent information about
diff --git a/sql/table_cache.cc b/sql/table_cache.cc
index 6a6b8ab827e..2feace30672 100644
--- a/sql/table_cache.cc
+++ b/sql/table_cache.cc
@@ -964,6 +964,8 @@ void tdc_release_share(TABLE_SHARE *share)
mysql_mutex_lock(&share->tdc->LOCK_table_share);
if (--share->tdc->ref_count)
{
+ if (!share->is_view)
+ mysql_cond_broadcast(&share->tdc->COND_release);
mysql_mutex_unlock(&share->tdc->LOCK_table_share);
mysql_mutex_unlock(&LOCK_unused_shares);
DBUG_VOID_RETURN;
diff --git a/sql/threadpool_common.cc b/sql/threadpool_common.cc
index 2308f4277d6..643ff80de2a 100644
--- a/sql/threadpool_common.cc
+++ b/sql/threadpool_common.cc
@@ -84,17 +84,16 @@ struct Worker_thread_context
void save()
{
-#ifdef HAVE_PSI_INTERFACE
- psi_thread= PSI_server?PSI_server->get_thread():0;
+#ifdef HAVE_PSI_THREAD_INTERFACE
+ psi_thread = PSI_THREAD_CALL(get_thread)();
#endif
mysys_var= (st_my_thread_var *)pthread_getspecific(THR_KEY_mysys);
}
void restore()
{
-#ifdef HAVE_PSI_INTERFACE
- if (PSI_server)
- PSI_server->set_thread(psi_thread);
+#ifdef HAVE_PSI_THREAD_INTERFACE
+ PSI_THREAD_CALL(set_thread)(psi_thread);
#endif
pthread_setspecific(THR_KEY_mysys,mysys_var);
pthread_setspecific(THR_THD, 0);
@@ -102,6 +101,41 @@ struct Worker_thread_context
};
+#ifdef HAVE_PSI_INTERFACE
+
+/*
+ The following fixes PSI "idle" psi instrumentation.
+ The server assumes that connection becomes idle
+ just before net_read_packet() and switches to active after it.
+ In out setup, server becomes idle when async socket io is made.
+*/
+
+extern void net_before_header_psi(struct st_net *net, void *user_data, size_t);
+
+static void dummy_before_header(struct st_net *, void *, size_t)
+{
+}
+
+static void re_init_net_server_extension(THD *thd)
+{
+ thd->m_net_server_extension.m_before_header = dummy_before_header;
+}
+
+#else
+
+#define re_init_net_server_extension(thd)
+
+#endif /* HAVE_PSI_INTERFACE */
+
+
+static inline void set_thd_idle(THD *thd)
+{
+ thd->net.reading_or_writing= 1;
+#ifdef HAVE_PSI_INTERFACE
+ net_before_header_psi(&thd->net, thd, 0);
+#endif
+}
+
/*
Attach/associate the connection with the OS thread,
*/
@@ -110,10 +144,10 @@ static void thread_attach(THD* thd)
pthread_setspecific(THR_KEY_mysys,thd->mysys_var);
thd->thread_stack=(char*)&thd;
thd->store_globals();
-#ifdef HAVE_PSI_INTERFACE
- if (PSI_server)
- PSI_server->set_thread(thd->event_scheduler.m_psi);
+#ifdef HAVE_PSI_THREAD_INTERFACE
+ PSI_THREAD_CALL(set_thread)(thd->event_scheduler.m_psi);
#endif
+ mysql_socket_set_thread_owner(thd->net.vio->mysql_socket);
}
/*
@@ -188,8 +222,6 @@ error:
static THD* threadpool_add_connection(CONNECT *connect, void *scheduler_data)
{
THD *thd= NULL;
- int error=1;
-
/*
Create a new connection context: mysys_thread_var and PSI thread
@@ -222,45 +254,40 @@ static THD* threadpool_add_connection(CONNECT *connect, void *scheduler_data)
thd->event_scheduler.data= scheduler_data;
/* Create new PSI thread for use with the THD. */
-#ifdef HAVE_PSI_INTERFACE
- if (PSI_server)
- {
- thd->event_scheduler.m_psi =
- PSI_server->new_thread(key_thread_one_connection, thd, thd->thread_id);
- }
+#ifdef HAVE_PSI_THREAD_INTERFACE
+ thd->event_scheduler.m_psi=
+ PSI_THREAD_CALL(new_thread)(key_thread_one_connection, thd, thd->thread_id);
#endif
/* Login. */
thread_attach(thd);
+ re_init_net_server_extension(thd);
ulonglong now= microsecond_interval_timer();
thd->prior_thr_create_utime= now;
thd->start_utime= now;
thd->thr_create_utime= now;
- if (!setup_connection_thread_globals(thd))
- {
- if (!thd_prepare_connection(thd))
- {
-
- /*
- Check if THD is ok, as prepare_new_connection_state()
- can fail, for example if init command failed.
- */
- if (thd_is_connection_alive(thd))
- {
- error= 0;
- thd->net.reading_or_writing= 1;
- thd->skip_wait_timeout= true;
- }
- }
- }
- if (error)
- {
- threadpool_remove_connection(thd);
- thd= NULL;
- }
+ if (setup_connection_thread_globals(thd))
+ goto end;
+
+ if (thd_prepare_connection(thd))
+ goto end;
+
+ /*
+ Check if THD is ok, as prepare_new_connection_state()
+ can fail, for example if init command failed.
+ */
+ if (!thd_is_connection_alive(thd))
+ goto end;
+
+ thd->skip_wait_timeout= true;
+ set_thd_idle(thd);
return thd;
+
+end:
+ threadpool_remove_connection(thd);
+ return NULL;
}
@@ -325,12 +352,13 @@ static int threadpool_process_request(THD *thd)
goto end;
}
+ set_thd_idle(thd);
+
vio= thd->net.vio;
if (!vio->has_data(vio))
{
/* More info on this debug sync is in sql_parse.cc*/
DEBUG_SYNC(thd, "before_do_command_net_read");
- thd->net.reading_or_writing= 1;
goto end;
}
}
diff --git a/sql/wsrep_applier.cc b/sql/wsrep_applier.cc
index 059aabe7b46..cef59513485 100644
--- a/sql/wsrep_applier.cc
+++ b/sql/wsrep_applier.cc
@@ -72,6 +72,9 @@ Format_description_log_event* wsrep_get_apply_format(THD* thd)
{
return (Format_description_log_event*) thd->wsrep_apply_format;
}
+
+ DBUG_ASSERT(thd->wsrep_rgi);
+
return thd->wsrep_rgi->rli->relay_log.description_event_for_exec;
}
@@ -361,8 +364,10 @@ wsrep_cb_status_t wsrep_commit_cb(void* const ctx,
else
rcode = wsrep_rollback(thd);
+ /* Cleanup */
wsrep_set_apply_format(thd, NULL);
thd->mdl_context.release_transactional_locks();
+ thd->reset_query(); /* Mutex protected */
free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
thd->tx_isolation= (enum_tx_isolation) thd->variables.tx_isolation;
diff --git a/sql/wsrep_binlog.cc b/sql/wsrep_binlog.cc
index 7884df586a1..08b7e3f1e3d 100644
--- a/sql/wsrep_binlog.cc
+++ b/sql/wsrep_binlog.cc
@@ -442,11 +442,13 @@ void thd_binlog_flush_pending_rows_event(THD *thd, bool stmt_end)
void wsrep_dump_rbr_buf_with_header(THD *thd, const void *rbr_buf,
size_t buf_len)
{
+ DBUG_ENTER("wsrep_dump_rbr_buf_with_header");
+
char filename[PATH_MAX]= {0};
File file;
IO_CACHE cache;
Log_event_writer writer(&cache);
- Format_description_log_event *ev= wsrep_get_apply_format(thd);
+ Format_description_log_event *ev;
int len= my_snprintf(filename, PATH_MAX, "%s/GRA_%lld_%lld_v2.log",
wsrep_data_home_dir, (longlong) thd->thread_id,
@@ -455,7 +457,7 @@ void wsrep_dump_rbr_buf_with_header(THD *thd, const void *rbr_buf,
if (len >= PATH_MAX)
{
WSREP_ERROR("RBR dump path too long: %d, skipping dump.", len);
- return;
+ DBUG_VOID_RETURN;
}
if ((file= mysql_file_open(key_file_wsrep_gra_log, filename,
@@ -477,6 +479,13 @@ void wsrep_dump_rbr_buf_with_header(THD *thd, const void *rbr_buf,
goto cleanup2;
}
+ /*
+ Instantiate an FDLE object for non-wsrep threads (to be written
+ to the dump file).
+ */
+ ev= (thd->wsrep_applier) ? wsrep_get_apply_format(thd) :
+ (new Format_description_log_event(4));
+
if (writer.write(ev) || my_b_write(&cache, (uchar*)rbr_buf, buf_len) ||
flush_io_cache(&cache))
{
@@ -489,5 +498,9 @@ cleanup2:
cleanup1:
mysql_file_close(file, MYF(MY_WME));
+
+ if (!thd->wsrep_applier) delete ev;
+
+ DBUG_VOID_RETURN;
}
diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc
index 68ce59c0665..b0275fc2fd5 100644
--- a/sql/wsrep_mysqld.cc
+++ b/sql/wsrep_mysqld.cc
@@ -983,6 +983,8 @@ bool wsrep_must_sync_wait (THD* thd, uint mask)
{
return (thd->variables.wsrep_sync_wait & mask) &&
thd->variables.wsrep_on &&
+ !(thd->variables.wsrep_dirty_reads &&
+ !is_update_query(thd->lex->sql_command)) &&
!thd->in_active_multi_stmt_transaction() &&
thd->wsrep_conflict_state != REPLAYING &&
thd->wsrep_sync_wait_gtid.seqno == WSREP_SEQNO_UNDEFINED;
diff --git a/sql/wsrep_sst.cc b/sql/wsrep_sst.cc
index d35514344eb..03cd8674242 100644
--- a/sql/wsrep_sst.cc
+++ b/sql/wsrep_sst.cc
@@ -525,13 +525,11 @@ static void* sst_joiner_thread (void* a)
} else {
// Scan state ID first followed by wsrep_gtid_domain_id.
- char uuid[512];
unsigned long int domain_id;
- size_t len= pos - out + 1;
- if (len > sizeof(uuid)) goto err; // safety check
- memcpy(uuid, out, len); // including '\0'
- err= sst_scan_uuid_seqno (uuid, &ret_uuid, &ret_seqno);
+ // Null-terminate the state-id.
+ out[pos - out]= 0;
+ err= sst_scan_uuid_seqno (out, &ret_uuid, &ret_seqno);
if (err)
{