summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/contributors.h1
-rw-r--r--sql/field.cc2
-rw-r--r--sql/handler.cc99
-rw-r--r--sql/item.cc54
-rw-r--r--sql/item_cmpfunc.cc3
-rw-r--r--sql/item_strfunc.cc30
-rw-r--r--sql/item_strfunc.h129
-rw-r--r--sql/item_sum.h1
-rw-r--r--sql/log.cc2
-rw-r--r--sql/log_event.cc1
-rw-r--r--sql/mysqld.cc32
-rw-r--r--sql/net_serv.cc4
-rw-r--r--sql/parse_file.h6
-rw-r--r--sql/signal_handler.cc4
-rw-r--r--sql/sql_acl.cc8
-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.h8
-rw-r--r--sql/sql_parse.cc7
-rw-r--r--sql/sql_plugin.cc241
-rw-r--r--sql/sql_plugin.h7
-rw-r--r--sql/sql_prepare.cc48
-rw-r--r--sql/sql_select.cc30
-rw-r--r--sql/table_cache.cc2
-rw-r--r--sql/wsrep_mysqld.cc13
-rw-r--r--sql/wsrep_sst.cc8
29 files changed, 485 insertions, 284 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/field.cc b/sql/field.cc
index ae815187019..b909d14ec8f 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 de456f703f1..802364cb6e5 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -5875,6 +5875,30 @@ int handler::ha_reset()
}
+static int check_wsrep_max_ws_rows()
+{
+#ifdef WITH_WSREP
+ 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)
+ {
+ trans_rollback_stmt(thd) || trans_rollback(thd);
+ my_message(ER_ERROR_DURING_COMMIT, "wsrep_max_ws_rows exceeded", MYF(0));
+ return ER_ERROR_DURING_COMMIT;
+ }
+ }
+#endif /* WITH_WSREP */
+ return 0;
+}
+
+
int handler::ha_write_row(uchar *buf)
{
int error;
@@ -5897,20 +5921,9 @@ int handler::ha_write_row(uchar *buf)
rows_changed++;
if (unlikely(error= binlog_log_row(table, 0, buf, log_func)))
DBUG_RETURN(error); /* purecov: inspected */
-#ifdef WITH_WSREP
- current_thd->wsrep_affected_rows++;
- if (wsrep_max_ws_rows &&
- current_thd->wsrep_exec_mode != REPL_RECV &&
- current_thd->wsrep_affected_rows > wsrep_max_ws_rows)
- {
- trans_rollback_stmt(current_thd) || trans_rollback(current_thd);
- my_message(ER_ERROR_DURING_COMMIT, "wsrep_max_ws_rows exceeded", MYF(0));
- DBUG_RETURN(ER_ERROR_DURING_COMMIT);
- }
-#endif /* WITH_WSREP */
DEBUG_SYNC_C("ha_write_row_end");
- DBUG_RETURN(0);
+ DBUG_RETURN(check_wsrep_max_ws_rows());
}
@@ -5941,18 +5954,7 @@ int handler::ha_update_row(const uchar *old_data, uchar *new_data)
rows_changed++;
if (unlikely(error= binlog_log_row(table, old_data, new_data, log_func)))
return error;
-#ifdef WITH_WSREP
- current_thd->wsrep_affected_rows++;
- if (wsrep_max_ws_rows &&
- current_thd->wsrep_exec_mode != REPL_RECV &&
- current_thd->wsrep_affected_rows > wsrep_max_ws_rows)
- {
- trans_rollback_stmt(current_thd) || trans_rollback(current_thd);
- my_message(ER_ERROR_DURING_COMMIT, "wsrep_max_ws_rows exceeded", MYF(0));
- return ER_ERROR_DURING_COMMIT;
- }
-#endif /* WITH_WSREP */
- return 0;
+ return check_wsrep_max_ws_rows();
}
int handler::ha_delete_row(const uchar *buf)
@@ -5979,18 +5981,7 @@ int handler::ha_delete_row(const uchar *buf)
rows_changed++;
if (unlikely(error= binlog_log_row(table, buf, 0, log_func)))
return error;
-#ifdef WITH_WSREP
- current_thd->wsrep_affected_rows++;
- if (wsrep_max_ws_rows &&
- current_thd->wsrep_exec_mode != REPL_RECV &&
- current_thd->wsrep_affected_rows > wsrep_max_ws_rows)
- {
- trans_rollback_stmt(current_thd) || trans_rollback(current_thd);
- my_message(ER_ERROR_DURING_COMMIT, "wsrep_max_ws_rows exceeded", MYF(0));
- return ER_ERROR_DURING_COMMIT;
- }
-#endif /* WITH_WSREP */
- return 0;
+ return check_wsrep_max_ws_rows();
}
@@ -6105,6 +6096,13 @@ void handler::set_lock_type(enum thr_lock_type lock)
@note Aborting the transaction does NOT end it, it still has to
be rolled back with hton->rollback().
+ @note It is safe to abort from one thread (bf_thd) the transaction,
+ running in another thread (victim_thd), because InnoDB's lock_sys and
+ trx_mutex guarantee the necessary protection. However, its not safe
+ to access victim_thd->transaction, because it's not protected from
+ concurrent accesses. And it's an overkill to take LOCK_plugin and
+ iterate the whole installed_htons[] array every time.
+
@param bf_thd brute force THD asking for the abort
@param victim_thd victim THD to be aborted
@@ -6121,29 +6119,16 @@ int ha_abort_transaction(THD *bf_thd, THD *victim_thd, my_bool signal)
DBUG_RETURN(0);
}
- /* Try statement transaction if standard one is not set. */
- THD_TRANS *trans= (victim_thd->transaction.all.ha_list) ?
- &victim_thd->transaction.all : &victim_thd->transaction.stmt;
-
- Ha_trx_info *ha_info= trans->ha_list, *ha_info_next;
-
- for (; ha_info; ha_info= ha_info_next)
+ handlerton *hton= installed_htons[DB_TYPE_INNODB];
+ if (hton && hton->abort_transaction)
{
- handlerton *hton= ha_info->ht();
- if (!hton->abort_transaction)
- {
- /* Skip warning for binlog & wsrep. */
- if (hton->db_type != DB_TYPE_BINLOG && hton != wsrep_hton)
- {
- WSREP_WARN("Cannot abort transaction.");
- }
- }
- else
- {
- hton->abort_transaction(hton, bf_thd, victim_thd, signal);
- }
- ha_info_next= ha_info->next();
+ hton->abort_transaction(hton, bf_thd, victim_thd, signal);
+ }
+ else
+ {
+ WSREP_WARN("Cannot abort InnoDB transaction");
}
+
DBUG_RETURN(0);
}
diff --git a/sql/item.cc b/sql/item.cc
index 71df93f3ffc..47635b14f46 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -57,6 +57,17 @@ bool cmp_items(Item *a, Item *b)
}
+/**
+ Set max_sum_func_level if it is needed
+*/
+inline void set_max_sum_func_level(THD *thd, SELECT_LEX *select)
+{
+ if (thd->lex->in_sum_func &&
+ thd->lex->in_sum_func->nest_level >= select->nest_level)
+ set_if_bigger(thd->lex->in_sum_func->max_sum_func_level,
+ select->nest_level - 1);
+}
+
/*****************************************************************************
** Item functions
*****************************************************************************/
@@ -2662,9 +2673,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;
@@ -4885,6 +4915,11 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference)
if (rf->fix_fields(thd, reference) || rf->check_cols(1))
return -1;
+ /*
+ We can not "move" aggregate function in the place where
+ its arguments are not defined.
+ */
+ set_max_sum_func_level(thd, select);
mark_as_dependent(thd, last_checked_context->select_lex,
context->select_lex, rf,
rf);
@@ -4893,6 +4928,11 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference)
}
else
{
+ /*
+ We can not "move" aggregate function in the place where
+ its arguments are not defined.
+ */
+ set_max_sum_func_level(thd, select);
mark_as_dependent(thd, last_checked_context->select_lex,
context->select_lex,
this, (Item_ident*)*reference);
@@ -5024,6 +5064,11 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
return(1);
}
+ /*
+ We can not "move" aggregate function in the place where
+ its arguments are not defined.
+ */
+ set_max_sum_func_level(thd, thd->lex->current_select);
set_field(new_field);
return 0;
}
@@ -5048,6 +5093,11 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
select->parsing_place == IN_GROUP_BY &&
alias_name_used ? *rf->ref : rf);
+ /*
+ We can not "move" aggregate function in the place where
+ its arguments are not defined.
+ */
+ set_max_sum_func_level(thd, thd->lex->current_select);
return FALSE;
}
}
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index bd1e8b72157..a222335cf97 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -4507,7 +4507,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_strfunc.cc b/sql/item_strfunc.cc
index 75b034cbd4f..43770a88cdc 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -165,31 +165,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);
@@ -215,8 +190,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());
}
@@ -346,9 +319,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 65c286819d3..a56e100a956 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -96,50 +96,99 @@ 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"; }
};
-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"; }
};
-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"; }
};
-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"; }
};
-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"; }
@@ -147,7 +196,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);
@@ -155,7 +204,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 *);
};
@@ -431,7 +481,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};
@@ -441,9 +491,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()
@@ -461,12 +511,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()
{
@@ -477,12 +529,14 @@ public:
const char *func_name() const { return "des_encrypt"; }
};
-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()
{
@@ -495,7 +549,13 @@ public:
const char *func_name() const { return "des_decrypt"; }
};
-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;
@@ -505,11 +565,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();
}
@@ -525,7 +586,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. */
@@ -534,7 +595,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"; }
@@ -803,12 +864,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()
@@ -1149,21 +1210,23 @@ 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
};
-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_sum.h b/sql/item_sum.h
index 8568eaae907..7ad037c046b 100644
--- a/sql/item_sum.h
+++ b/sql/item_sum.h
@@ -1084,7 +1084,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); }
};
diff --git a/sql/log.cc b/sql/log.cc
index be24bcd718a..45ab5c8827b 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -3102,7 +3102,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);
}
}
}
diff --git a/sql/log_event.cc b/sql/log_event.cc
index afa58afc21d..de6528638f0 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -6022,7 +6022,6 @@ int Load_log_event::do_apply_event(NET* net, rpl_group_info *rgi,
new_db.str= (char *) rpl_filter->get_rewrite_db(db, &new_db.length);
thd->set_db(new_db.str, new_db.length);
DBUG_ASSERT(thd->query() == 0);
- thd->reset_query_inner(); // Should not be needed
thd->is_slave_error= 0;
clear_all_errors(thd, const_cast<Relay_log_info*>(rli));
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index a71d6d10042..2f0fd46845c 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -4096,6 +4096,7 @@ static int init_common_variables()
max_system_variables.pseudo_thread_id= (ulong)~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;
@@ -4167,6 +4168,8 @@ static int init_common_variables()
return 1;
}
+ opt_log_basename= const_cast<char *>("mysql");
+
if (gethostname(glob_hostname,sizeof(glob_hostname)) < 0)
{
/*
@@ -4176,9 +4179,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);
@@ -5075,6 +5077,12 @@ static int init_server_components()
}
/*
+ Since some wsrep threads (THDs) are create before plugins are
+ initialized, LOCK_plugin mutex needs to be initialized here.
+ */
+ plugin_mutex_init();
+
+ /*
Wsrep initialization must happen at this point, because:
- opt_bin_logname must be known when starting replication
since SST may need it
@@ -5302,6 +5310,17 @@ static int init_server_components()
#endif
#ifdef WITH_WSREP
+ /*
+ Now is the right time to initialize members of wsrep startup threads
+ that rely on plugins and other related global system variables to be
+ initialized. This initialization was not possible before, as plugins
+ (and thus some global system variables) are initialized after wsrep
+ startup threads are created.
+ Note: This only needs to be done for rsync, xtrabackup based SST methods.
+ */
+ if (wsrep_before_SE())
+ wsrep_plugins_post_init();
+
if (WSREP_ON && !opt_bin_log)
{
wsrep_emulate_bin_log= 1;
@@ -8970,9 +8989,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)
@@ -9867,9 +9887,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 ef7a46a7109..da3c5646e84 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/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/signal_handler.cc b/sql/signal_handler.cc
index 9dd3e532d1e..f72eb676743 100644
--- a/sql/signal_handler.cc
+++ b/sql/signal_handler.cc
@@ -64,13 +64,13 @@ 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)
{
@@ -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)
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 23302e1847e..48c57303805 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -2797,7 +2797,7 @@ bool change_password(THD *thd, LEX_USER *user)
if (WSREP(thd) && !IF_WSREP(thd->wsrep_applier, 0))
{
- thd->set_query_inner(buff, query_length, system_charset_info);
+ thd->set_query(buff, query_length, system_charset_info);
WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, (char*)"user", NULL);
}
@@ -2858,7 +2858,7 @@ error: // this label is used in WSREP_TO_ISOLATION_BEGIN
{
WSREP_TO_ISOLATION_END;
- thd->set_query_inner(query_save);
+ thd->set_query(query_save);
thd->wsrep_exec_mode = LOCAL_STATE;
}
#endif /* WITH_WSREP */
@@ -2913,7 +2913,7 @@ int acl_set_default_role(THD *thd, const char *host, const char *user,
if (WSREP(thd) && !IF_WSREP(thd->wsrep_applier, 0))
{
- thd->set_query_inner(buff, query_length, system_charset_info);
+ thd->set_query(buff, query_length, system_charset_info);
WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, (char*)"user", NULL);
}
@@ -3009,7 +3009,7 @@ error: // this label is used in WSREP_TO_ISOLATION_END
{
WSREP_TO_ISOLATION_END;
- thd->set_query_inner(query_save);
+ thd->set_query(query_save);
thd->wsrep_exec_mode = LOCAL_STATE;
}
#endif /* WITH_WSREP */
diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc
index b974075b442..1f4426f2043 100644
--- a/sql/sql_admin.cc
+++ b/sql/sql_admin.cc
@@ -466,7 +466,19 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
}
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;
thd->open_options&= ~extra_open_options;
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 9ea5b20dce6..b4a3cc27d2c 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -9267,6 +9267,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 91dd8ad7325..c69303c5273 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -961,7 +961,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",
@@ -1226,6 +1226,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 00ba9bf59d8..657caf4a5bc 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 430191cee5d..4143d2cc419 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -5828,9 +5828,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 b22dc8142d8..da885c3dbac 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -1262,7 +1262,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
};
@@ -4610,6 +4611,11 @@ public:
save_copy_field_end= copy_field_end= NULL;
}
}
+ void free_copy_field_data()
+ {
+ for (Copy_field *ptr= copy_field ; ptr != copy_field_end ; ptr++)
+ ptr->tmp.free();
+ }
};
class select_union :public select_result_interceptor
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index c6d80e1ba97..a15f3da8e12 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -7298,10 +7298,9 @@ void mysql_parse(THD *thd, char *rawbuf, uint length,
Note that we don't need LOCK_thread_count to modify query_length.
*/
if (found_semicolon && (ulong) (found_semicolon - thd->query()))
- thd->set_query_inner(thd->query(),
- (uint32) (found_semicolon -
- thd->query() - 1),
- thd->charset());
+ thd->set_query(thd->query(),
+ (uint32) (found_semicolon - thd->query() - 1),
+ thd->charset());
/* Actually execute the query */
if (found_semicolon)
{
diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc
index 60248f3fef4..5b16482ae66 100644
--- a/sql/sql_plugin.cc
+++ b/sql/sql_plugin.cc
@@ -1536,10 +1536,6 @@ int plugin_init(int *argc, char **argv, int flags)
dlopen_count =0;
-#ifdef HAVE_PSI_INTERFACE
- init_plugin_psi_keys();
-#endif
-
init_alloc_root(&plugin_mem_root, 4096, 4096, MYF(0));
init_alloc_root(&plugin_vars_mem_root, 4096, 4096, MYF(0));
init_alloc_root(&tmp_root, 4096, 4096, MYF(0));
@@ -1548,9 +1544,6 @@ int plugin_init(int *argc, char **argv, int flags)
get_bookmark_hash_key, NULL, HASH_UNIQUE))
goto err;
-
- mysql_mutex_init(key_LOCK_plugin, &LOCK_plugin, MY_MUTEX_INIT_FAST);
-
if (my_init_dynamic_array(&plugin_dl_array,
sizeof(struct st_plugin_dl *), 16, 16, MYF(0)) ||
my_init_dynamic_array(&plugin_array,
@@ -2849,6 +2842,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.
@@ -2857,39 +2866,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++)
@@ -2983,25 +2966,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));
}
@@ -3116,28 +3091,19 @@ void plugin_thdvar_init(THD *thd)
thd->variables.dynamic_variables_size= 0;
thd->variables.dynamic_variables_ptr= 0;
- if (IF_WSREP((!WSREP(thd) || !thd->wsrep_applier),1))
- {
- mysql_mutex_lock(&LOCK_plugin);
- thd->variables.table_plugin=
- intern_plugin_lock(NULL, global_system_variables.table_plugin);
- if (global_system_variables.tmp_table_plugin)
- thd->variables.tmp_table_plugin=
- intern_plugin_lock(NULL, global_system_variables.tmp_table_plugin);
- if (global_system_variables.enforced_table_plugin)
- thd->variables.enforced_table_plugin=
- intern_plugin_lock(NULL, global_system_variables.enforced_table_plugin);
- intern_plugin_unlock(NULL, old_table_plugin);
- intern_plugin_unlock(NULL, old_tmp_table_plugin);
- intern_plugin_unlock(NULL, old_enforced_table_plugin);
- mysql_mutex_unlock(&LOCK_plugin);
- }
- else
- {
- thd->variables.table_plugin= NULL;
- thd->variables.tmp_table_plugin= NULL;
- thd->variables.enforced_table_plugin= NULL;
- }
+ mysql_mutex_lock(&LOCK_plugin);
+ thd->variables.table_plugin=
+ intern_plugin_lock(NULL, global_system_variables.table_plugin);
+ if (global_system_variables.tmp_table_plugin)
+ thd->variables.tmp_table_plugin=
+ intern_plugin_lock(NULL, global_system_variables.tmp_table_plugin);
+ if (global_system_variables.enforced_table_plugin)
+ thd->variables.enforced_table_plugin=
+ intern_plugin_lock(NULL, global_system_variables.enforced_table_plugin);
+ intern_plugin_unlock(NULL, old_table_plugin);
+ intern_plugin_unlock(NULL, old_tmp_table_plugin);
+ intern_plugin_unlock(NULL, old_enforced_table_plugin);
+ mysql_mutex_unlock(&LOCK_plugin);
DBUG_VOID_RETURN;
}
@@ -3448,69 +3414,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;
@@ -3863,7 +3818,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);
@@ -4261,3 +4227,54 @@ int thd_setspecific(MYSQL_THD thd, MYSQL_THD_KEY_T key, void *value)
return 0;
}
+void plugin_mutex_init()
+{
+#ifdef HAVE_PSI_INTERFACE
+ init_plugin_psi_keys();
+#endif
+ mysql_mutex_init(key_LOCK_plugin, &LOCK_plugin, MY_MUTEX_INIT_FAST);
+}
+
+#ifdef WITH_WSREP
+
+/*
+ Placeholder for global_system_variables.table_plugin required during
+ initialization of startup wsrep threads.
+*/
+static st_plugin_int wsrep_dummy_plugin;
+static st_plugin_int *wsrep_dummy_plugin_ptr;
+
+/*
+ Initialize wsrep_dummy_plugin and assign it to
+ global_system_variables.table_plugin.
+*/
+void wsrep_plugins_pre_init()
+{
+ wsrep_dummy_plugin_ptr= &wsrep_dummy_plugin;
+ wsrep_dummy_plugin.state= PLUGIN_IS_DISABLED;
+ global_system_variables.table_plugin=
+ plugin_int_to_ref(wsrep_dummy_plugin_ptr);
+}
+
+/*
+ This function is intended to be called after the plugins and related
+ global system variables are initialized. It re-initializes some data
+ members of wsrep startup threads with correct values, as these value
+ were not available at the time these threads were created.
+*/
+void wsrep_plugins_post_init()
+{
+ THD *thd;
+ I_List_iterator<THD> it(threads);
+
+ while ((thd= it++))
+ {
+ if (IF_WSREP(thd->wsrep_applier,1))
+ {
+ plugin_thdvar_init(thd);
+ }
+ }
+
+ return;
+}
+#endif /* WITH_WSREP */
diff --git a/sql/sql_plugin.h b/sql/sql_plugin.h
index 77ec24bbe9c..d11c449962a 100644
--- a/sql/sql_plugin.h
+++ b/sql/sql_plugin.h
@@ -180,6 +180,7 @@ sys_var *find_plugin_sysvar(st_plugin_int *plugin, st_mysql_sys_var *var);
void plugin_opt_set_limits(struct my_option *, const struct st_mysql_sys_var *);
extern SHOW_COMP_OPTION plugin_status(const char *name, size_t len, int type);
extern bool check_valid_path(const char *path, size_t length);
+extern void plugin_mutex_init();
typedef my_bool (plugin_foreach_func)(THD *thd,
plugin_ref plugin,
@@ -194,3 +195,9 @@ extern bool plugin_dl_foreach(THD *thd, const LEX_STRING *dl,
extern void sync_dynamic_session_variables(THD* thd, bool global_lock);
#endif
+
+#ifdef WITH_WSREP
+extern void wsrep_plugins_pre_init();
+extern void wsrep_plugins_post_init();
+#endif /* WITH_WSREP */
+
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 0db1daa378e..d381825851d 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -3030,7 +3030,36 @@ void mysql_sql_stmt_execute(THD *thd)
DBUG_PRINT("info",("stmt: 0x%lx", (long) stmt));
+ /*
+ thd->free_list can already have some Items,
+ e.g. for a query like this:
+ PREPARE stmt FROM 'INSERT INTO t1 VALUES (@@max_sort_length)';
+ SET STATEMENT max_sort_length=2048 FOR EXECUTE stmt;
+ thd->free_list contains a pointer to Item_int corresponding to 2048.
+
+ If Prepared_statement::execute() notices that the table metadata for "t1"
+ has changed since PREPARE, it returns an error asking the calling
+ Prepared_statement::execute_loop() to re-prepare the statement.
+ Before returning the error, Prepared_statement::execute()
+ calls Prepared_statement::cleanup_stmt(),
+ which calls thd->cleanup_after_query(),
+ which calls Query_arena::free_items().
+
+ We hide "external" Items, e.g. those created while parsing the
+ "SET STATEMENT" part of the query,
+ so they don't get freed in case of re-prepare.
+ See MDEV-10702 Crash in SET STATEMENT FOR EXECUTE
+ */
+ Item *free_list_backup= thd->free_list;
+ thd->free_list= NULL; // Hide the external (e.g. "SET STATEMENT") Items
(void) stmt->execute_loop(&expanded_query, FALSE, NULL, NULL);
+ thd->free_items(); // Free items created by execute_loop()
+ /*
+ Now restore the "external" (e.g. "SET STATEMENT") Item list.
+ It will be freed normaly in THD::cleanup_after_query().
+ */
+ thd->free_list= free_list_backup;
+
stmt->lex->restore_set_statement_var();
DBUG_VOID_RETURN;
}
@@ -3853,9 +3882,14 @@ Prepared_statement::execute_loop(String *expanded_query,
Reprepare_observer reprepare_observer;
bool error;
int reprepare_attempt= 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)
@@ -3877,12 +3911,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_select.cc b/sql/sql_select.cc
index 5dc50c92104..239e5b6b5d2 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -9172,9 +9172,26 @@ JOIN::make_simple_join(JOIN *parent, TABLE *temp_table)
We need to destruct the copy_field (allocated in create_tmp_table())
before setting it to 0 if the join is not "reusable".
*/
- if (!tmp_join || tmp_join != this)
- tmp_table_param.cleanup();
- tmp_table_param.copy_field= tmp_table_param.copy_field_end=0;
+ if (!tmp_join || tmp_join != this)
+ tmp_table_param.cleanup();
+ else
+ {
+ /*
+ Free data buffered in copy_fields, but keep data pointed by copy_field
+ around for next iteration (possibly stored in save_copy_fields).
+
+ It would be logically simpler to not clear copy_field
+ below, but as we have loops that runs over copy_field to
+ copy_field_end that should not be done anymore, it's simpler to
+ just clear the pointers.
+
+ Another option would be to just clear copy_field_end and not run
+ the loops if this is not set or to have tmp_table_param.cleanup()
+ to run cleanup on save_copy_field if copy_field is not set.
+ */
+ tmp_table_param.free_copy_field_data();
+ tmp_table_param.copy_field= tmp_table_param.copy_field_end=0;
+ }
first_record= sort_and_group=0;
send_records= (ha_rows) 0;
@@ -11890,7 +11907,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
@@ -12010,7 +12027,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().
*/
if (tmp_join &&
@@ -16114,6 +16131,7 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
case Item::VARBIN_ITEM:
case Item::CACHE_ITEM:
case Item::EXPR_CACHE_ITEM:
+ case Item::PARAM_ITEM:
if (make_copy_field)
{
DBUG_ASSERT(((Item_result_field*)item)->result_field);
@@ -22917,7 +22935,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/table_cache.cc b/sql/table_cache.cc
index 2dd368a1945..16a47b37417 100644
--- a/sql/table_cache.cc
+++ b/sql/table_cache.cc
@@ -778,6 +778,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/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc
index 776bf4a3ab2..0deb19dfc77 100644
--- a/sql/wsrep_mysqld.cc
+++ b/sql/wsrep_mysqld.cc
@@ -36,6 +36,7 @@
#include <cstdlib>
#include "log_event.h"
#include <slave.h>
+#include "sql_plugin.h" /* wsrep_plugins_pre_init() */
wsrep_t *wsrep = NULL;
/*
@@ -771,7 +772,6 @@ void wsrep_thr_init()
mysql_mutex_init(key_LOCK_wsrep_config_state, &LOCK_wsrep_config_state, MY_MUTEX_INIT_FAST);
}
-
void wsrep_init_startup (bool first)
{
if (wsrep_init()) unireg_abort(1);
@@ -782,6 +782,17 @@ void wsrep_init_startup (bool first)
wsrep_debug, wsrep_convert_LOCK_to_trx,
(wsrep_on_fun)wsrep_on);
+ /*
+ Pre-initialize global_system_variables.table_plugin with a dummy engine
+ (placeholder) required during the initialization of wsrep threads (THDs).
+ (see: plugin_thdvar_init())
+ Note: This only needs to be done for rsync & xtrabackup based SST methods.
+ In case of mysqldump SST method, the wsrep threads are created after the
+ server plugins & global system variables are initialized.
+ */
+ if (wsrep_before_SE())
+ wsrep_plugins_pre_init();
+
/* Skip replication start if dummy wsrep provider is loaded */
if (!strcmp(wsrep_provider, WSREP_NONE)) return;
diff --git a/sql/wsrep_sst.cc b/sql/wsrep_sst.cc
index d88263d75cb..7c366435472 100644
--- a/sql/wsrep_sst.cc
+++ b/sql/wsrep_sst.cc
@@ -476,13 +476,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)
{