summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/contributors.h2
-rw-r--r--sql/handler.cc7
-rw-r--r--sql/handler.h14
-rw-r--r--sql/item.h35
-rw-r--r--sql/item_geofunc.cc2
-rw-r--r--sql/item_geofunc.h2
-rw-r--r--sql/item_strfunc.cc230
-rw-r--r--sql/item_strfunc.h16
-rw-r--r--sql/log_event.cc6
-rw-r--r--sql/mysqld.cc5
-rw-r--r--sql/opt_subselect.cc4
-rw-r--r--sql/rpl_rli.cc9
-rw-r--r--sql/sql_class.cc4
-rw-r--r--sql/sql_class.h11
-rw-r--r--sql/sql_connect.cc2
-rw-r--r--sql/sql_insert.cc9
-rw-r--r--sql/sql_parse.cc4
-rw-r--r--sql/sql_plugin.cc24
-rw-r--r--sql/sql_priv.h2
-rw-r--r--sql/sql_select.cc77
-rw-r--r--sql/sql_select.h8
-rw-r--r--sql/sql_show.cc15
-rw-r--r--sql/sql_table.cc27
-rw-r--r--sql/sql_union.cc4
-rw-r--r--sql/sys_vars.cc4
-rw-r--r--sql/table.cc11
-rw-r--r--sql/temporary_tables.cc1
-rw-r--r--sql/transaction.cc29
28 files changed, 365 insertions, 199 deletions
diff --git a/sql/contributors.h b/sql/contributors.h
index 3a771e2b493..88a4a088acf 100644
--- a/sql/contributors.h
+++ b/sql/contributors.h
@@ -39,9 +39,11 @@ struct show_table_contributors_st show_table_contributors[]= {
/* MariaDB foundation sponsors, in contribution, size , time order */
{"Booking.com", "https://www.booking.com", "Founding member, Platinum Sponsor of the MariaDB Foundation"},
{"Alibaba Cloud", "https://intl.aliyun.com", "Platinum Sponsor of the MariaDB Foundation"},
+ {"Tencent Cloud", "https://cloud.tencent.com", "Platinum Sponsor of the MariaDB Foundation"},
{"MariaDB Corporation", "https://mariadb.com", "Founding member, Gold Sponsor of the MariaDB Foundation"},
{"Visma", "https://visma.com", "Gold Sponsor of the MariaDB Foundation"},
{"DBS", "https://dbs.com", "Gold Sponsor of the MariaDB Foundation"},
+ {"IBM", "https://www.ibm.com", "Gold Sponsor of the MariaDB Foundation"},
{"Nexedi", "https://www.nexedi.com", "Silver Sponsor of the MariaDB Foundation"},
{"Acronis", "http://www.acronis.com", "Silver Sponsor of the MariaDB Foundation"},
{"Auttomattic", "https://automattic.com", "Bronze Sponsor of the MariaDB Foundation"},
diff --git a/sql/handler.cc b/sql/handler.cc
index 95b16a51980..a4a2297bd2f 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -4856,7 +4856,12 @@ static my_bool discover_handlerton(THD *thd, plugin_ref plugin,
{
if (error)
{
- DBUG_ASSERT(share->error); // tdc_lock_share needs that
+ if (!share->error)
+ {
+ share->error= OPEN_FRM_ERROR_ALREADY_ISSUED;
+ plugin_unlock(0, share->db_plugin);
+ }
+
/*
report an error, unless it is "generic" and a more
specific one was already reported
diff --git a/sql/handler.h b/sql/handler.h
index ee4836dcc34..d021edf28d2 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -1465,16 +1465,30 @@ struct THD_TRANS
static unsigned int const CREATED_TEMP_TABLE= 0x02;
static unsigned int const DROPPED_TEMP_TABLE= 0x04;
static unsigned int const DID_WAIT= 0x08;
+ static unsigned int const DID_DDL= 0x10;
void mark_created_temp_table()
{
DBUG_PRINT("debug", ("mark_created_temp_table"));
m_unsafe_rollback_flags|= CREATED_TEMP_TABLE;
}
+ void mark_dropped_temp_table()
+ {
+ DBUG_PRINT("debug", ("mark_dropped_temp_table"));
+ m_unsafe_rollback_flags|= DROPPED_TEMP_TABLE;
+ }
+ bool has_created_dropped_temp_table() const {
+ return
+ (m_unsafe_rollback_flags & (CREATED_TEMP_TABLE|DROPPED_TEMP_TABLE)) != 0;
+ }
void mark_trans_did_wait() { m_unsafe_rollback_flags|= DID_WAIT; }
bool trans_did_wait() const {
return (m_unsafe_rollback_flags & DID_WAIT) != 0;
}
+ void mark_trans_did_ddl() { m_unsafe_rollback_flags|= DID_DDL; }
+ bool trans_did_ddl() const {
+ return (m_unsafe_rollback_flags & DID_DDL) != 0;
+ }
};
diff --git a/sql/item.h b/sql/item.h
index 3cb904d3c59..cee88756bbf 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -994,25 +994,20 @@ public:
store return value of this method.
NOTE
- Buffer passed via argument should only be used if the item itself
- doesn't have an own String buffer. In case when the item maintains
- it's own string buffer, it's preferable to return it instead to
- minimize number of mallocs/memcpys.
- The caller of this method can modify returned string, but only in case
- when it was allocated on heap, (is_alloced() is true). This allows
- the caller to efficiently use a buffer allocated by a child without
- having to allocate a buffer of it's own. The buffer, given to
- val_str() as argument, belongs to the caller and is later used by the
- caller at it's own choosing.
- A few implications from the above:
- - unless you return a string object which only points to your buffer
- but doesn't manages it you should be ready that it will be
- modified.
- - even for not allocated strings (is_alloced() == false) the caller
- can change charset (see Item_func_{typecast/binary}. XXX: is this
- a bug?
- - still you should try to minimize data copying and return internal
- object whenever possible.
+ The caller can modify the returned String, if it's not marked
+ "const" (with the String::mark_as_const() method). That means that
+ if the item returns its own internal buffer (e.g. tmp_value), it
+ *must* be marked "const" [1]. So normally it's preferrable to
+ return the result value in the String, that was passed as an
+ argument. But, for example, SUBSTR() returns a String that simply
+ points into the buffer of SUBSTR()'s args[0]->val_str(). Such a
+ String is always "const", so it's ok to use tmp_value for that and
+ avoid reallocating/copying of the argument String.
+
+ [1] consider SELECT CONCAT(f, ":", f) FROM (SELECT func() AS f);
+ here the return value of f() is used twice in the top-level
+ select, and if they share the same tmp_value buffer, modifying the
+ first one will implicitly modify the second too.
RETURN
In case of NULL value return 0 (NULL pointer) and set null_value flag
@@ -1771,7 +1766,7 @@ public:
{ return this; }
virtual bool expr_cache_is_needed(THD *) { return FALSE; }
virtual Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs);
- bool needs_charset_converter(uint32 length, CHARSET_INFO *tocs)
+ bool needs_charset_converter(uint32 length, CHARSET_INFO *tocs) const
{
/*
This will return "true" if conversion happens:
diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc
index 16bad154862..560d822bea7 100644
--- a/sql/item_geofunc.cc
+++ b/sql/item_geofunc.cc
@@ -1949,7 +1949,7 @@ String *Item_func_buffer::val_str(String *str_value)
{
DBUG_ENTER("Item_func_buffer::val_str");
DBUG_ASSERT(fixed == 1);
- String *obj= args[0]->val_str(&tmp_value);
+ String *obj= args[0]->val_str(str_value);
double dist= args[1]->val_real();
Geometry_buffer buffer;
Geometry *g;
diff --git a/sql/item_geofunc.h b/sql/item_geofunc.h
index a164f9dec89..abe189395ec 100644
--- a/sql/item_geofunc.h
+++ b/sql/item_geofunc.h
@@ -297,7 +297,6 @@ public:
class Item_func_spatial_collection: public Item_geometry_func
{
- String tmp_value;
enum Geometry::wkbType coll_type;
enum Geometry::wkbType item_type;
public:
@@ -483,7 +482,6 @@ protected:
Gcalc_result_receiver res_receiver;
Gcalc_operation_reducer operation;
- String tmp_value;
public:
Item_func_buffer(THD *thd, Item *obj, Item *distance):
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index e91cf64fd04..3c2b2374f1e 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -66,8 +66,14 @@ size_t username_char_length= 80;
Conversion happens only in case of "tricky" Item character set (e.g. UCS2).
Normally conversion does not happen, and val_str_ascii() is immediately
returned instead.
+
+ No matter if conversion is needed or not needed,
+ the result is always returned in "str" (see MDEV-10306 why).
+
+ @param [OUT] str - Store the result here
+ @param [IN] ascii_buffer - Use this temporary buffer to call val_str_ascii()
*/
-String *Item_func::val_str_from_val_str_ascii(String *str, String *str2)
+String *Item_func::val_str_from_val_str_ascii(String *str, String *ascii_buffer)
{
DBUG_ASSERT(fixed == 1);
@@ -79,19 +85,19 @@ String *Item_func::val_str_from_val_str_ascii(String *str, String *str2)
return res;
}
- DBUG_ASSERT(str != str2);
+ DBUG_ASSERT(str != ascii_buffer);
uint errors;
- String *res= val_str_ascii(str);
+ String *res= val_str_ascii(ascii_buffer);
if (!res)
return 0;
- if ((null_value= str2->copy(res->ptr(), res->length(),
- &my_charset_latin1, collation.collation,
- &errors)))
+ if ((null_value= str->copy(res->ptr(), res->length(),
+ &my_charset_latin1, collation.collation,
+ &errors)))
return 0;
- return str2;
+ return str;
}
@@ -307,11 +313,11 @@ void Item_aes_crypt::create_key(String *user_key, uchar *real_key)
}
-String *Item_aes_crypt::val_str(String *str)
+String *Item_aes_crypt::val_str(String *str2)
{
DBUG_ASSERT(fixed == 1);
StringBuffer<80> user_key_buf;
- String *sptr= args[0]->val_str(str);
+ String *sptr= args[0]->val_str(&str_value);
String *user_key= args[1]->val_str(&user_key_buf);
uint32 aes_length;
@@ -320,17 +326,17 @@ String *Item_aes_crypt::val_str(String *str)
null_value=0;
aes_length=my_aes_get_size(MY_AES_ECB, sptr->length());
- if (!str_value.alloc(aes_length)) // Ensure that memory is free
+ if (!str2->alloc(aes_length)) // Ensure that memory is free
{
uchar rkey[AES_KEY_LENGTH / 8];
create_key(user_key, rkey);
if (!my_aes_crypt(MY_AES_ECB, what, (uchar*)sptr->ptr(), sptr->length(),
- (uchar*)str_value.ptr(), &aes_length,
+ (uchar*)str2->ptr(), &aes_length,
rkey, AES_KEY_LENGTH / 8, 0, 0))
{
- str_value.length((uint) aes_length);
- return &str_value;
+ str2->length((uint) aes_length);
+ return str2;
}
}
}
@@ -345,6 +351,7 @@ void Item_func_aes_encrypt::fix_length_and_dec()
}
+
void Item_func_aes_decrypt::fix_length_and_dec()
{
max_length=args[0]->max_length;
@@ -373,7 +380,7 @@ void Item_func_to_base64::fix_length_and_dec()
String *Item_func_to_base64::val_str_ascii(String *str)
{
- String *res= args[0]->val_str(str);
+ String *res= args[0]->val_str(&tmp_value);
bool too_long= false;
int length;
if (!res ||
@@ -381,7 +388,7 @@ String *Item_func_to_base64::val_str_ascii(String *str)
(too_long=
((uint) (length= my_base64_needed_encoded_length((int) res->length())) >
current_thd->variables.max_allowed_packet)) ||
- tmp_value.alloc((uint) length))
+ str->alloc((uint) length))
{
null_value= 1; // NULL input, too long input, or OOM.
if (too_long)
@@ -395,11 +402,11 @@ String *Item_func_to_base64::val_str_ascii(String *str)
}
return 0;
}
- my_base64_encode(res->ptr(), (int) res->length(), (char*) tmp_value.ptr());
+ my_base64_encode(res->ptr(), (int) res->length(), (char*) str->ptr());
DBUG_ASSERT(length > 0);
- tmp_value.length((uint) length - 1); // Without trailing '\0'
+ str->length((uint) length - 1); // Without trailing '\0'
null_value= 0;
- return &tmp_value;
+ return str;
}
@@ -420,7 +427,7 @@ void Item_func_from_base64::fix_length_and_dec()
String *Item_func_from_base64::val_str(String *str)
{
- String *res= args[0]->val_str_ascii(str);
+ String *res= args[0]->val_str_ascii(&tmp_value);
int length;
const char *end_ptr;
@@ -440,11 +447,11 @@ String *Item_func_from_base64::val_str(String *str)
goto err;
}
- if (tmp_value.alloc((uint) length))
+ if (str->alloc((uint) length))
goto err;
if ((length= my_base64_decode(res->ptr(), (int) res->length(),
- (char *) tmp_value.ptr(), &end_ptr, 0)) < 0 ||
+ (char *) str->ptr(), &end_ptr, 0)) < 0 ||
end_ptr < res->ptr() + res->length())
{
THD *thd= current_thd;
@@ -454,9 +461,9 @@ String *Item_func_from_base64::val_str(String *str)
goto err;
}
- tmp_value.length((uint) length);
+ str->length((uint) length);
null_value= 0;
- return &tmp_value;
+ return str;
err:
null_value= 1; // NULL input, too long input, OOM, or badly formed input
return 0;
@@ -712,7 +719,7 @@ String *Item_func_des_encrypt::val_str(String *str)
struct st_des_keyschedule keyschedule;
const char *append_str="********";
uint key_number, res_length, tail;
- String *res= args[0]->val_str(str);
+ String *res= args[0]->val_str(&tmp_value);
if ((null_value= args[0]->null_value))
return 0; // ENCRYPT(NULL) == NULL
@@ -736,7 +743,7 @@ String *Item_func_des_encrypt::val_str(String *str)
}
else
{
- String *keystr=args[1]->val_str(&tmp_value);
+ String *keystr= args[1]->val_str(str);
if (!keystr)
goto error;
key_number=127; // User key string
@@ -768,23 +775,23 @@ String *Item_func_des_encrypt::val_str(String *str)
tmp_arg.length(0);
tmp_arg.append(res->ptr(), res->length());
code= ER_OUT_OF_RESOURCES;
- if (tmp_arg.append(append_str, tail) || tmp_value.alloc(res_length+1))
+ if (tmp_arg.append(append_str, tail) || str->alloc(res_length+1))
goto error;
tmp_arg[res_length-1]=tail; // save extra length
- tmp_value.realloc(res_length+1);
- tmp_value.length(res_length+1);
- tmp_value.set_charset(&my_charset_bin);
- tmp_value[0]=(char) (128 | key_number);
+ str->realloc(res_length+1);
+ str->length(res_length+1);
+ str->set_charset(&my_charset_bin);
+ (*str)[0]=(char) (128 | key_number);
// Real encryption
bzero((char*) &ivec,sizeof(ivec));
DES_ede3_cbc_encrypt((const uchar*) (tmp_arg.ptr()),
- (uchar*) (tmp_value.ptr()+1),
+ (uchar*) (str->ptr()+1),
res_length,
&keyschedule.ks1,
&keyschedule.ks2,
&keyschedule.ks3,
&ivec, TRUE);
- return &tmp_value;
+ return str;
error:
THD *thd= current_thd;
@@ -810,7 +817,7 @@ String *Item_func_des_decrypt::val_str(String *str)
DES_cblock ivec;
struct st_des_keyblock keyblock;
struct st_des_keyschedule keyschedule;
- String *res= args[0]->val_str(str);
+ String *res= args[0]->val_str(&tmp_value);
uint length,tail;
if ((null_value= args[0]->null_value))
@@ -834,7 +841,7 @@ String *Item_func_des_decrypt::val_str(String *str)
else
{
// We make good 24-byte (168 bit) key from given plaintext key with MD5
- String *keystr=args[1]->val_str(&tmp_value);
+ String *keystr= args[1]->val_str(str);
if (!keystr)
goto error;
@@ -849,23 +856,23 @@ String *Item_func_des_decrypt::val_str(String *str)
DES_set_key_unchecked(&keyblock.key3,&keyschedule.ks3);
}
code= ER_OUT_OF_RESOURCES;
- if (tmp_value.alloc(length-1))
+ if (str->alloc(length-1))
goto error;
bzero((char*) &ivec,sizeof(ivec));
DES_ede3_cbc_encrypt((const uchar*) res->ptr()+1,
- (uchar*) (tmp_value.ptr()),
+ (uchar*) (str->ptr()),
length-1,
&keyschedule.ks1,
&keyschedule.ks2,
&keyschedule.ks3,
&ivec, FALSE);
/* Restore old length of key */
- if ((tail=(uint) (uchar) tmp_value[length-2]) > 8)
+ if ((tail=(uint) (uchar) (*str)[length-2]) > 8)
goto wrong_key; // Wrong key
- tmp_value.length(length-1-tail);
- tmp_value.set_charset(&my_charset_bin);
- return &tmp_value;
+ str->length(length-1-tail);
+ str->set_charset(&my_charset_bin);
+ return str;
error:
{
@@ -1063,25 +1070,26 @@ void Item_func_concat_ws::fix_length_and_dec()
String *Item_func_reverse::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
- String *res = args[0]->val_str(str);
- char *ptr, *end, *tmp;
+ String *res= args[0]->val_str(&tmp_value);
+ const char *ptr, *end;
+ char *tmp;
if ((null_value=args[0]->null_value))
return 0;
/* An empty string is a special case as the string pointer may be null */
if (!res->length())
return make_empty_result();
- if (tmp_value.alloced_length() < res->length() &&
- tmp_value.realloc(res->length()))
+ if (str->alloced_length() < res->length() &&
+ str->realloc(res->length()))
{
null_value= 1;
return 0;
}
- tmp_value.length(res->length());
- tmp_value.set_charset(res->charset());
- ptr= (char *) res->ptr();
- end= ptr + res->length();
- tmp= (char *) tmp_value.ptr() + tmp_value.length();
+ str->length(res->length());
+ str->set_charset(res->charset());
+ ptr= res->ptr();
+ end= res->end();
+ tmp= (char *) str->end();
#ifdef USE_MB
if (use_mb(res->charset()))
{
@@ -1091,7 +1099,7 @@ String *Item_func_reverse::val_str(String *str)
if ((l= my_ismbchar(res->charset(),ptr,end)))
{
tmp-= l;
- DBUG_ASSERT(tmp >= tmp_value.ptr());
+ DBUG_ASSERT(tmp >= str->ptr());
memcpy(tmp,ptr,l);
ptr+= l;
}
@@ -1105,7 +1113,7 @@ String *Item_func_reverse::val_str(String *str)
while (ptr < end)
*--tmp= *ptr++;
}
- return &tmp_value;
+ return str;
}
@@ -2285,6 +2293,7 @@ String *Item_func_database::val_str(String *str)
}
else
str->copy(thd->db, thd->db_length, system_charset_info);
+ null_value= 0;
return str;
}
@@ -2319,6 +2328,28 @@ bool Item_func_user::init(const char *user, const char *host)
}
+Item *Item_func_sysconst::safe_charset_converter(THD *thd, CHARSET_INFO *tocs)
+{
+ /*
+ During view or prepared statement creation, the item should not
+ make use of const_charset_converter as it would imply substitution
+ with constant items which is not correct. Functions can have different
+ values during view creation and view execution based on context.
+
+ Return the identical item during view creation and prepare.
+ */
+ if (thd->lex->is_ps_or_view_context_analysis())
+ return this;
+ return const_charset_converter(thd, tocs, true, fully_qualified_func_name());
+}
+
+bool Item_func_sysconst::const_item() const
+{
+ if (current_thd->lex->is_ps_or_view_context_analysis())
+ return false;
+ return true;
+}
+
bool Item_func_user::fix_fields(THD *thd, Item **ref)
{
return (Item_func_sysconst::fix_fields(thd, ref) ||
@@ -2344,15 +2375,13 @@ bool Item_func_current_role::fix_fields(THD *thd, Item **ref)
Security_context *ctx= context && context->security_ctx
? context->security_ctx : thd->security_ctx;
-
if (ctx->priv_role[0])
{
if (str_value.copy(ctx->priv_role, strlen(ctx->priv_role),
system_charset_info))
return 1;
-
- null_value= maybe_null= 0;
str_value.mark_as_const();
+ null_value= maybe_null= 0;
return 0;
}
null_value= maybe_null= 1;
@@ -2366,7 +2395,6 @@ void Item_func_soundex::fix_length_and_dec()
DBUG_ASSERT(collation.collation != NULL);
set_if_bigger(char_length, 4);
fix_char_length(char_length);
- tmp_value.set_charset(collation.collation);
}
@@ -2411,7 +2439,7 @@ static bool my_uni_isalpha(int wc)
String *Item_func_soundex::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
- String *res =args[0]->val_str(str);
+ String *res= args[0]->val_str(&tmp_value);
char last_ch,ch;
CHARSET_INFO *cs= collation.collation;
my_wc_t wc;
@@ -2421,10 +2449,11 @@ String *Item_func_soundex::val_str(String *str)
if ((null_value= args[0]->null_value))
return 0; /* purecov: inspected */
- if (tmp_value.alloc(MY_MAX(res->length(), 4 * cs->mbminlen)))
- return str; /* purecov: inspected */
- char *to= (char *) tmp_value.ptr();
- char *to_end= to + tmp_value.alloced_length();
+ if (str->alloc(MY_MAX(res->length(), 4 * cs->mbminlen)))
+ return &tmp_value; /* purecov: inspected */
+ str->set_charset(collation.collation);
+ char *to= (char *) str->ptr();
+ char *to_end= to + str->alloced_length();
char *from= (char *) res->ptr(), *end= from + res->length();
for ( ; ; ) /* Skip pre-space */
@@ -2509,8 +2538,8 @@ String *Item_func_soundex::val_str(String *str)
to+= nbytes;
}
- tmp_value.length((uint) (to-tmp_value.ptr()));
- return &tmp_value;
+ str->length((uint) (to - str->ptr()));
+ return str;
}
@@ -3332,13 +3361,13 @@ String *Item_func_conv_charset::val_str(String *str)
DBUG_ASSERT(fixed == 1);
if (use_cached_value)
return null_value ? 0 : &str_value;
- String *arg= args[0]->val_str(str);
+ String *arg= args[0]->val_str(&tmp_value);
String_copier_for_item copier(current_thd);
return ((null_value= args[0]->null_value ||
- copier.copy_with_warn(collation.collation, &tmp_value,
+ copier.copy_with_warn(collation.collation, str,
arg->charset(), arg->ptr(),
arg->length(), arg->length()))) ?
- 0 : &tmp_value;
+ 0 : str;
}
void Item_func_conv_charset::fix_length_and_dec()
@@ -3479,7 +3508,7 @@ String *Item_func_weight_string::val_str(String *str)
DBUG_ASSERT(fixed == 1);
if (args[0]->result_type() != STRING_RESULT ||
- !(res= args[0]->val_str(str)))
+ !(res= args[0]->val_str(&tmp_value)))
goto nl;
/*
@@ -3529,19 +3558,20 @@ String *Item_func_weight_string::val_str(String *str)
goto nl;
}
}
- if (tmp_value.alloc(tmp_length))
+
+ if (str->alloc(tmp_length))
goto nl;
frm_length= cs->coll->strnxfrm(cs,
- (uchar *) tmp_value.ptr(), tmp_length,
+ (uchar *) str->ptr(), tmp_length,
nweights ? nweights : tmp_length,
(const uchar *) res->ptr(), res->length(),
flags);
DBUG_ASSERT(frm_length <= tmp_length);
- tmp_value.length(frm_length);
+ str->length(frm_length);
null_value= 0;
- return &tmp_value;
+ return str;
nl:
null_value= 1;
@@ -3597,18 +3627,18 @@ String *Item_func_hex::val_str_ascii(String *str)
}
/* Convert given string to a hex string, character by character */
- res= args[0]->val_str(str);
- if (!res || tmp_value.alloc(res->length()*2+1))
+ res= args[0]->val_str(&tmp_value);
+ if (!res || str->alloc(res->length()*2+1))
{
null_value=1;
return 0;
}
null_value=0;
- tmp_value.length(res->length()*2);
- tmp_value.set_charset(&my_charset_latin1);
+ str->length(res->length()*2);
+ str->set_charset(&my_charset_latin1);
- octet2hex((char*) tmp_value.ptr(), res->ptr(), res->length());
- return &tmp_value;
+ octet2hex((char*) str->ptr(), res->ptr(), res->length());
+ return str;
}
/** Convert given hex string to a binary string. */
@@ -3621,8 +3651,8 @@ String *Item_func_unhex::val_str(String *str)
uint length;
DBUG_ASSERT(fixed == 1);
- res= args[0]->val_str(str);
- if (!res || tmp_value.alloc(length= (1+res->length())/2))
+ res= args[0]->val_str(&tmp_value);
+ if (!res || str->alloc(length= (1+res->length())/2))
{
null_value=1;
return 0;
@@ -3630,8 +3660,8 @@ String *Item_func_unhex::val_str(String *str)
from= res->ptr();
null_value= 0;
- tmp_value.length(length);
- to= (char*) tmp_value.ptr();
+ str->length(length);
+ to= (char*) str->ptr();
if (res->length() % 2)
{
int hex_char;
@@ -3649,7 +3679,7 @@ String *Item_func_unhex::val_str(String *str)
if ((null_value= (hex_char == -1)))
return 0;
}
- return &tmp_value;
+ return str;
}
@@ -3900,7 +3930,7 @@ String *Item_func_quote::val_str(String *str)
ulong max_allowed_packet= current_thd->variables.max_allowed_packet;
char *from, *to, *end, *start;
- String *arg= args[0]->val_str(str);
+ String *arg= args[0]->val_str(&tmp_value);
uint arg_length, new_length;
if (!arg) // Null argument
{
@@ -3927,7 +3957,7 @@ String *Item_func_quote::val_str(String *str)
set_if_smaller(new_length, max_allowed_packet);
}
- if (tmp_value.alloc(new_length))
+ if (str->alloc(new_length))
goto null;
if (collation.collation->mbmaxlen > 1)
@@ -3935,7 +3965,7 @@ String *Item_func_quote::val_str(String *str)
CHARSET_INFO *cs= collation.collation;
int mblen;
uchar *to_end;
- to= (char*) tmp_value.ptr();
+ to= (char*) str->ptr();
to_end= (uchar*) to + new_length;
/* Put leading quote */
@@ -3972,14 +4002,14 @@ String *Item_func_quote::val_str(String *str)
if ((mblen= cs->cset->wc_mb(cs, '\'', (uchar *) to, to_end)) <= 0)
goto toolong;
to+= mblen;
- new_length= to - tmp_value.ptr();
+ new_length= to - str->ptr();
goto ret;
}
/*
We replace characters from the end to the beginning
*/
- to= (char*) tmp_value.ptr() + new_length - 1;
+ to= (char*) str->ptr() + new_length - 1;
*to--= '\'';
for (start= (char*) arg->ptr(),end= start + arg_length; end-- != start; to--)
{
@@ -4009,10 +4039,10 @@ String *Item_func_quote::val_str(String *str)
*to= '\'';
ret:
- tmp_value.length(new_length);
- tmp_value.set_charset(collation.collation);
+ str->length(new_length);
+ str->set_charset(collation.collation);
null_value= 0;
- return &tmp_value;
+ return str;
toolong:
push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN,
@@ -4086,7 +4116,7 @@ String *Item_func_compress::val_str(String *str)
char *tmp, *last_char;
DBUG_ASSERT(fixed == 1);
- if (!(res= args[0]->val_str(str)))
+ if (!(res= args[0]->val_str(&tmp_value)))
{
null_value= 1;
return 0;
@@ -4107,13 +4137,13 @@ String *Item_func_compress::val_str(String *str)
// Check new_size overflow: new_size <= res->length()
if (((uint32) (new_size+5) <= res->length()) ||
- buffer.realloc((uint32) new_size + 4 + 1))
+ str->realloc((uint32) new_size + 4 + 1))
{
null_value= 1;
return 0;
}
- body= ((Byte*)buffer.ptr()) + 4;
+ body= ((Byte*)str->ptr()) + 4;
// As far as we have checked res->is_empty() we can use ptr()
if ((err= my_compress_buffer(body, &new_size, (const uchar *)res->ptr(),
@@ -4127,7 +4157,7 @@ String *Item_func_compress::val_str(String *str)
return 0;
}
- tmp= (char*)buffer.ptr(); // int4store is a macro; avoid side effects
+ tmp= (char*) str->ptr(); // int4store is a macro; avoid side effects
int4store(tmp, res->length() & 0x3FFFFFFF);
/* This is to ensure that things works for CHAR fields, which trim ' ': */
@@ -4138,15 +4168,15 @@ String *Item_func_compress::val_str(String *str)
new_size++;
}
- buffer.length((uint32)new_size + 4);
- return &buffer;
+ str->length((uint32)new_size + 4);
+ return str;
}
String *Item_func_uncompress::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
- String *res= args[0]->val_str(str);
+ String *res= args[0]->val_str(&tmp_value);
ulong new_size;
int err;
uint code;
@@ -4179,14 +4209,14 @@ String *Item_func_uncompress::val_str(String *str)
max_allowed_packet));
goto err;
}
- if (buffer.realloc((uint32)new_size))
+ if (str->realloc((uint32)new_size))
goto err;
- if ((err= uncompress((Byte*)buffer.ptr(), &new_size,
+ if ((err= uncompress((Byte*)str->ptr(), &new_size,
((const Bytef*)res->ptr())+4,res->length()-4)) == Z_OK)
{
- buffer.length((uint32) new_size);
- return &buffer;
+ str->length((uint32) new_size);
+ return str;
}
code= ((err == Z_BUF_ERROR) ? ER_ZLIB_Z_BUF_ERROR :
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index 65c6dacbc73..0729f8f9c15 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -142,7 +142,6 @@ public:
class Item_func_md5 :public Item_str_ascii_checksum_func
{
- String tmp_value;
public:
Item_func_md5(THD *thd, Item *a): Item_str_ascii_checksum_func(thd, a) {}
String *val_str_ascii(String *);
@@ -258,7 +257,6 @@ public:
class Item_func_decode_histogram :public Item_str_func
{
- String tmp_value;
public:
Item_func_decode_histogram(THD *thd, Item *a, Item *b):
Item_str_func(thd, a, b) {}
@@ -684,10 +682,7 @@ class Item_func_sysconst :public Item_str_func
public:
Item_func_sysconst(THD *thd): Item_str_func(thd)
{ collation.set(system_charset_info,DERIVATION_SYSCONST); }
- Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs)
- {
- return const_charset_converter(thd, tocs, true, fully_qualified_func_name());
- }
+ Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs);
/*
Used to create correct Item name in new converted item in
safe_charset_converter, return string representation of this function
@@ -699,6 +694,7 @@ public:
return mark_unsupported_function(fully_qualified_func_name(), arg,
VCOL_SESSION_FUNC);
}
+ bool const_item() const;
};
@@ -787,7 +783,7 @@ public:
String *val_str(String *)
{
DBUG_ASSERT(fixed == 1);
- return (null_value ? 0 : &str_value);
+ return null_value ? NULL : &str_value;
}
bool check_vcol_func_processor(void *arg)
{
@@ -844,7 +840,6 @@ public:
class Item_func_format :public Item_str_ascii_func
{
- String tmp_str;
MY_LOCALE *locale;
public:
Item_func_format(THD *thd, Item *org, Item *dec):
@@ -909,7 +904,6 @@ public:
class Item_func_binlog_gtid_pos :public Item_str_func
{
- String tmp_value;
public:
Item_func_binlog_gtid_pos(THD *thd, Item *arg1, Item *arg2):
Item_str_func(thd, arg1, arg2) {}
@@ -1354,7 +1348,7 @@ public:
class Item_func_compress: public Item_str_binary_checksum_func
{
- String buffer;
+ String tmp_value;
public:
Item_func_compress(THD *thd, Item *a)
:Item_str_binary_checksum_func(thd, a) {}
@@ -1367,7 +1361,7 @@ public:
class Item_func_uncompress: public Item_str_binary_checksum_func
{
- String buffer;
+ String tmp_value;
public:
Item_func_uncompress(THD *thd, Item *a)
:Item_str_binary_checksum_func(thd, a) {}
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 79e8f7e0a94..26c288ef767 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -7451,8 +7451,10 @@ Gtid_log_event::Gtid_log_event(THD *thd_arg, uint64 seq_no_arg,
if (thd_arg->transaction.stmt.trans_did_wait() ||
thd_arg->transaction.all.trans_did_wait())
flags2|= FL_WAITED;
- if (sql_command_flags[thd->lex->sql_command] &
- (CF_DISALLOW_IN_RO_TRANS | CF_AUTO_COMMIT_TRANS))
+ if (thd_arg->transaction.stmt.trans_did_ddl() ||
+ thd_arg->transaction.stmt.has_created_dropped_temp_table() ||
+ thd_arg->transaction.all.trans_did_ddl() ||
+ thd_arg->transaction.all.has_created_dropped_temp_table())
flags2|= FL_DDL;
else if (is_transactional)
flags2|= FL_TRANSACTIONAL;
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 871a3140891..373f9bae26e 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -4036,8 +4036,9 @@ static void my_malloc_size_cb_func(long long size, my_bool is_thread_specific)
(longlong) thd->status_var.local_memory_used,
size));
thd->status_var.local_memory_used+= size;
- if (thd->status_var.local_memory_used > (int64)thd->variables.max_mem_used &&
- !thd->killed)
+ if (size > 0 &&
+ thd->status_var.local_memory_used > (int64)thd->variables.max_mem_used &&
+ !thd->killed && !thd->get_stmt_da()->is_set())
{
char buf[1024];
thd->killed= KILL_QUERY;
diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc
index 0b01925ba93..f37db88957a 100644
--- a/sql/opt_subselect.cc
+++ b/sql/opt_subselect.cc
@@ -3443,6 +3443,7 @@ void fix_semijoin_strategies_for_picked_join_order(JOIN *join)
table_map remaining_tables= 0;
table_map handled_tabs= 0;
join->sjm_lookup_tables= 0;
+ join->sjm_scan_tables= 0;
for (tablenr= table_count - 1 ; tablenr != join->const_tables - 1; tablenr--)
{
POSITION *pos= join->best_positions + tablenr;
@@ -3500,6 +3501,9 @@ void fix_semijoin_strategies_for_picked_join_order(JOIN *join)
for (i= tablenr; i != (first + sjm->tables - 1); i--)
rem_tables |= join->best_positions[i].table->table->map;
+ for (i= first; i < first+ sjm->tables; i++)
+ join->sjm_scan_tables |= join->best_positions[i].table->table->map;
+
POSITION dummy;
join->cur_sj_inner_tables= 0;
for (i= first + sjm->tables; i <= tablenr; i++)
diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc
index fda922c3e12..9bdb096a116 100644
--- a/sql/rpl_rli.cc
+++ b/sql/rpl_rli.cc
@@ -124,10 +124,13 @@ int Relay_log_info::init(const char* info_fname)
char fname[FN_REFLEN+128];
const char* msg = 0;
int error = 0;
+ mysql_mutex_t *log_lock;
DBUG_ENTER("Relay_log_info::init");
if (inited) // Set if this function called
DBUG_RETURN(0);
+
+ log_lock= relay_log.get_log_lock();
fn_format(fname, info_fname, mysql_data_home, "", 4+32);
mysql_mutex_lock(&data_lock);
cur_log_fd = -1;
@@ -207,7 +210,6 @@ a file name for --relay-log-index option", opt_relaylog_index_name);
/* For multimaster, add connection name to relay log filenames */
char buf_relay_logname[FN_REFLEN], buf_relaylog_index_name_buff[FN_REFLEN];
char *buf_relaylog_index_name= opt_relaylog_index_name;
- mysql_mutex_t *log_lock;
create_logfile_name_with_suffix(buf_relay_logname,
sizeof(buf_relay_logname),
@@ -227,7 +229,6 @@ a file name for --relay-log-index option", opt_relaylog_index_name);
note, that if open() fails, we'll still have index file open
but a destructor will take care of that
*/
- log_lock= relay_log.get_log_lock();
mysql_mutex_lock(log_lock);
if (relay_log.open_index_file(buf_relaylog_index_name, ln, TRUE) ||
relay_log.open(ln, LOG_BIN, 0, 0, SEQ_READ_APPEND,
@@ -304,7 +305,9 @@ Failed to open the existing relay log info file '%s' (errno %d)",
if (info_fd >= 0)
mysql_file_close(info_fd, MYF(0));
info_fd= -1;
+ mysql_mutex_lock(log_lock);
relay_log.close(LOG_CLOSE_INDEX | LOG_CLOSE_STOP_EVENT);
+ mysql_mutex_unlock(log_lock);
mysql_mutex_unlock(&data_lock);
DBUG_RETURN(1);
}
@@ -426,7 +429,9 @@ err:
if (info_fd >= 0)
mysql_file_close(info_fd, MYF(0));
info_fd= -1;
+ mysql_mutex_lock(log_lock);
relay_log.close(LOG_CLOSE_INDEX | LOG_CLOSE_STOP_EVENT);
+ mysql_mutex_unlock(log_lock);
mysql_mutex_unlock(&data_lock);
DBUG_RETURN(1);
}
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 3d34f657ae3..a4e522b90d3 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -724,6 +724,7 @@ THD::THD(my_thread_id id, bool is_wsrep_applier)
debug_sync_control(0),
#endif /* defined(ENABLED_DEBUG_SYNC) */
wait_for_commit_ptr(0),
+ m_internal_handler(0),
main_da(0, false, false),
m_stmt_da(&main_da),
tdc_hash_pins(0),
@@ -916,7 +917,6 @@ THD::THD(my_thread_id id, bool is_wsrep_applier)
MYF(MY_WME|MY_THREAD_SPECIFIC));
}
- m_internal_handler= NULL;
m_binlog_invoker= INVOKER_NONE;
memset(&invoker_user, 0, sizeof(invoker_user));
memset(&invoker_host, 0, sizeof(invoker_host));
@@ -1252,6 +1252,8 @@ void THD::init(void)
server_status= SERVER_STATUS_AUTOCOMMIT;
if (variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES)
server_status|= SERVER_STATUS_NO_BACKSLASH_ESCAPES;
+ if (variables.sql_mode & MODE_ANSI_QUOTES)
+ server_status|= SERVER_STATUS_ANSI_QUOTES;
transaction.all.modified_non_trans_table=
transaction.stmt.modified_non_trans_table= FALSE;
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 8052e28fbb4..acd3ff0300e 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -4279,7 +4279,16 @@ public:
{
main_lex.restore_set_statement_var();
}
-
+ /* Copy relevant `stmt` transaction flags to `all` transaction. */
+ void merge_unsafe_rollback_flags()
+ {
+ if (transaction.stmt.modified_non_trans_table)
+ transaction.all.modified_non_trans_table= TRUE;
+ transaction.all.m_unsafe_rollback_flags|=
+ (transaction.stmt.m_unsafe_rollback_flags &
+ (THD_TRANS::DID_WAIT | THD_TRANS::CREATED_TEMP_TABLE |
+ THD_TRANS::DROPPED_TEMP_TABLE | THD_TRANS::DID_DDL));
+ }
/*
Reset current_linfo
Setting current_linfo to 0 needs to be done with LOCK_thread_count to
diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc
index 5cb4cd87296..35ec7fa74e1 100644
--- a/sql/sql_connect.cc
+++ b/sql/sql_connect.cc
@@ -1462,7 +1462,7 @@ THD *CONNECT::create_thd(THD *thd)
res= my_net_init(&thd->net, vio, thd, MYF(MY_THREAD_SPECIFIC));
vio= 0; // Vio now handled by thd
- if (res)
+ if (res || thd->is_error())
{
if (!thd_reused)
delete thd;
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 5d6cf96a9a3..d037bad76ec 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -4419,6 +4419,15 @@ void select_create::store_values(List<Item> &values)
bool select_create::send_eof()
{
DBUG_ENTER("select_create::send_eof");
+
+ /*
+ The routine that writes the statement in the binary log
+ is in select_insert::prepare_eof(). For that reason, we
+ mark the flag at this point.
+ */
+ if (table->s->tmp_table)
+ thd->transaction.stmt.mark_created_temp_table();
+
if (prepare_eof())
{
abort_result_set();
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 7c910e87c75..ac742d79681 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -3325,6 +3325,7 @@ mysql_execute_command(THD *thd)
goto error;
}
}
+ thd->transaction.stmt.mark_trans_did_ddl();
}
#ifndef DBUG_OFF
@@ -7456,8 +7457,7 @@ void THD::reset_for_next_command()
if (!thd->in_multi_stmt_transaction_mode())
{
thd->variables.option_bits&= ~OPTION_KEEP_LOG;
- thd->transaction.all.modified_non_trans_table= FALSE;
- thd->transaction.all.m_unsafe_rollback_flags&= ~THD_TRANS::DID_WAIT;
+ thd->transaction.all.reset();
}
DBUG_ASSERT(thd->security_ctx== &thd->main_security_ctx);
thd->thread_specific_used= FALSE;
diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc
index 5249f3b6ab3..97ef24f44ed 100644
--- a/sql/sql_plugin.cc
+++ b/sql/sql_plugin.cc
@@ -327,6 +327,12 @@ static plugin_ref intern_plugin_lock(LEX *lex, plugin_ref plugin);
static void intern_plugin_unlock(LEX *lex, plugin_ref plugin);
static void reap_plugins(void);
+bool plugin_is_forced(struct st_plugin_int *p)
+{
+ return p->load_option == PLUGIN_FORCE ||
+ p->load_option == PLUGIN_FORCE_PLUS_PERMANENT;
+}
+
static void report_error(int where_to, uint error, ...)
{
va_list args;
@@ -1397,7 +1403,7 @@ static int plugin_initialize(MEM_ROOT *tmp_root, struct st_plugin_int *plugin,
if (options_only || state == PLUGIN_IS_DISABLED)
{
- ret= 0;
+ ret= !options_only && plugin_is_forced(plugin);
state= PLUGIN_IS_DISABLED;
goto err;
}
@@ -1711,8 +1717,7 @@ int plugin_init(int *argc, char **argv, int flags)
while ((plugin_ptr= *(--reap)))
{
mysql_mutex_unlock(&LOCK_plugin);
- if (plugin_ptr->load_option == PLUGIN_FORCE ||
- plugin_ptr->load_option == PLUGIN_FORCE_PLUS_PERMANENT)
+ if (plugin_is_forced(plugin_ptr))
reaped_mandatory_plugin= TRUE;
plugin_deinitialize(plugin_ptr, true);
mysql_mutex_lock(&LOCK_plugin);
@@ -3666,8 +3671,7 @@ static int construct_options(MEM_ROOT *mem_root, struct st_plugin_int *tmp,
plugin_dash.length + 1);
strxmov(plugin_name_with_prefix_ptr, plugin_dash.str, plugin_name_ptr, NullS);
- if (tmp->load_option != PLUGIN_FORCE &&
- tmp->load_option != PLUGIN_FORCE_PLUS_PERMANENT)
+ if (!plugin_is_forced(tmp))
{
/* support --skip-plugin-foo syntax */
options[0].name= plugin_name_ptr;
@@ -4054,8 +4058,11 @@ static int test_plugin_options(MEM_ROOT *tmp_root, struct st_plugin_int *tmp,
my_afree(tmp_backup);
}
- if (tmp->load_option != PLUGIN_FORCE &&
- tmp->load_option != PLUGIN_FORCE_PLUS_PERMANENT)
+ /*
+ We adjust the default value to account for the hardcoded exceptions
+ we have set for the federated and ndbcluster storage engines.
+ */
+ if (!plugin_is_forced(tmp))
opts[0].def_value= opts[1].def_value= plugin_load_option;
error= handle_options(argc, &argv, opts, mark_changed);
@@ -4071,8 +4078,7 @@ static int test_plugin_options(MEM_ROOT *tmp_root, struct st_plugin_int *tmp,
Set plugin loading policy from option value. First element in the option
list is always the <plugin name> option value.
*/
- if (tmp->load_option != PLUGIN_FORCE &&
- tmp->load_option != PLUGIN_FORCE_PLUS_PERMANENT)
+ if (!plugin_is_forced(tmp))
plugin_load_option= (enum_plugin_load_option) *(ulong*) opts[0].value;
}
diff --git a/sql/sql_priv.h b/sql/sql_priv.h
index 67547f7a030..6c9df6a9606 100644
--- a/sql/sql_priv.h
+++ b/sql/sql_priv.h
@@ -122,7 +122,7 @@
#define OPTION_AUTOCOMMIT (1ULL << 8) // THD, user
#define OPTION_BIG_SELECTS (1ULL << 9) // THD, user
#define OPTION_LOG_OFF (1ULL << 10) // THD, user
-#define OPTION_QUOTE_SHOW_CREATE (1ULL << 11) // THD, user, unused
+#define OPTION_QUOTE_SHOW_CREATE (1ULL << 11) // THD, user
#define TMP_TABLE_ALL_COLUMNS (1ULL << 12) // SELECT, intern
#define OPTION_WARNINGS (1ULL << 13) // THD, user
#define OPTION_AUTO_IS_NULL (1ULL << 14) // THD, user, binlog
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 2c7ccbf3e2b..e8e399868db 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -1451,6 +1451,7 @@ JOIN::optimize_inner()
if (!select_lex->have_window_funcs())
zero_result_cause= "Select tables optimized away";
tables_list= 0; // All tables resolved
+ select_lex->min_max_opt_list.empty();
const_tables= top_join_tab_count= table_count;
/*
Extract all table-independent conditions and replace the WHERE
@@ -2662,8 +2663,11 @@ bool JOIN::make_aggr_tables_info()
if (sort_table_cond)
{
if (!curr_tab->select)
+ {
if (!(curr_tab->select= new SQL_SELECT))
DBUG_RETURN(true);
+ curr_tab->select->head= curr_tab->table;
+ }
if (!curr_tab->select->cond)
curr_tab->select->cond= sort_table_cond;
else
@@ -5971,7 +5975,7 @@ add_group_and_distinct_keys(JOIN *join, JOIN_TAB *join_tab)
Item_field *cur_item;
key_map possible_keys(0);
- if (join->group_list)
+ if (join->group_list || join->simple_group)
{ /* Collect all query fields referenced in the GROUP clause. */
for (cur_group= join->group_list; cur_group; cur_group= cur_group->next)
(*cur_group->item)->walk(&Item::collect_item_field_processor, 0,
@@ -8367,6 +8371,63 @@ bool JOIN_TAB::hash_join_is_possible()
}
+/**
+ @brief
+ Check whether a KEYUSE can be really used for access this join table
+
+ @param join Join structure with the best join order
+ for which the check is performed
+ @param keyuse Evaluated KEYUSE structure
+
+ @details
+ This function is supposed to be used after the best execution plan have been
+ already chosen and the JOIN_TAB array for the best join order been already set.
+ For a given KEYUSE to access this JOIN_TAB in the best execution plan the
+ function checks whether it really can be used. The function first performs
+ the check with access_from_tables_is_allowed(). If it succeeds it checks
+ whether the keyuse->val does not use some fields of a materialized semijoin
+ nest that cannot be used to build keys to access outer tables.
+ Such KEYUSEs exists for the query like this:
+ select * from ot
+ where ot.c in (select it1.c from it1, it2 where it1.c=f(it2.c))
+ Here we have two KEYUSEs to access table ot: with val=it1.c and val=f(it2.c).
+ However if the subquery was materialized the second KEYUSE cannot be employed
+ to access ot.
+
+ @retval true the given keyuse can be used for ref access of this JOIN_TAB
+ @retval false otherwise
+*/
+
+bool JOIN_TAB::keyuse_is_valid_for_access_in_chosen_plan(JOIN *join,
+ KEYUSE *keyuse)
+{
+ if (!access_from_tables_is_allowed(keyuse->used_tables,
+ join->sjm_lookup_tables))
+ return false;
+ if (join->sjm_scan_tables & table->map)
+ return true;
+ table_map keyuse_sjm_scan_tables= keyuse->used_tables &
+ join->sjm_scan_tables;
+ if (!keyuse_sjm_scan_tables)
+ return true;
+ uint sjm_tab_nr= 0;
+ while (!(keyuse_sjm_scan_tables & table_map(1) << sjm_tab_nr))
+ sjm_tab_nr++;
+ JOIN_TAB *sjm_tab= join->map2table[sjm_tab_nr];
+ TABLE_LIST *emb_sj_nest= sjm_tab->emb_sj_nest;
+ if (!(emb_sj_nest->sj_mat_info && emb_sj_nest->sj_mat_info->is_used &&
+ emb_sj_nest->sj_mat_info->is_sj_scan))
+ return true;
+ st_select_lex *sjm_sel= emb_sj_nest->sj_subq_pred->unit->first_select();
+ for (uint i= 0; i < sjm_sel->item_list.elements; i++)
+ {
+ if (sjm_sel->ref_pointer_array[i] == keyuse->val)
+ return true;
+ }
+ return false;
+}
+
+
static uint
cache_record_length(JOIN *join,uint idx)
{
@@ -8956,6 +9017,7 @@ static bool create_hj_key_for_table(JOIN *join, JOIN_TAB *join_tab,
do
{
if (!(~used_tables & keyuse->used_tables) &&
+ join_tab->keyuse_is_valid_for_access_in_chosen_plan(join, keyuse) &&
are_tables_local(join_tab, keyuse->used_tables))
{
if (first_keyuse)
@@ -8970,6 +9032,8 @@ static bool create_hj_key_for_table(JOIN *join, JOIN_TAB *join_tab,
{
if (curr->keypart == keyuse->keypart &&
!(~used_tables & curr->used_tables) &&
+ join_tab->keyuse_is_valid_for_access_in_chosen_plan(join,
+ keyuse) &&
are_tables_local(join_tab, curr->used_tables))
break;
}
@@ -9004,6 +9068,7 @@ static bool create_hj_key_for_table(JOIN *join, JOIN_TAB *join_tab,
do
{
if (!(~used_tables & keyuse->used_tables) &&
+ join_tab->keyuse_is_valid_for_access_in_chosen_plan(join, keyuse) &&
are_tables_local(join_tab, keyuse->used_tables))
{
bool add_key_part= TRUE;
@@ -9013,7 +9078,9 @@ static bool create_hj_key_for_table(JOIN *join, JOIN_TAB *join_tab,
{
if (curr->keypart == keyuse->keypart &&
!(~used_tables & curr->used_tables) &&
- are_tables_local(join_tab, curr->used_tables))
+ join_tab->keyuse_is_valid_for_access_in_chosen_plan(join,
+ curr) &&
+ are_tables_local(join_tab, curr->used_tables))
{
keyuse->keypart= NO_KEYPART;
add_key_part= FALSE;
@@ -9115,8 +9182,7 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j,
do
{
if (!(~used_tables & keyuse->used_tables) &&
- j->access_from_tables_is_allowed(keyuse->used_tables,
- join->sjm_lookup_tables))
+ j->keyuse_is_valid_for_access_in_chosen_plan(join, keyuse))
{
if (are_tables_local(j, keyuse->val->used_tables()))
{
@@ -9186,8 +9252,7 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j,
for (i=0 ; i < keyparts ; keyuse++,i++)
{
while (((~used_tables) & keyuse->used_tables) ||
- !j->access_from_tables_is_allowed(keyuse->used_tables,
- join->sjm_lookup_tables) ||
+ !j->keyuse_is_valid_for_access_in_chosen_plan(join, keyuse) ||
keyuse->keypart == NO_KEYPART ||
(keyuse->keypart !=
(is_hash_join_key_no(key) ?
diff --git a/sql/sql_select.h b/sql/sql_select.h
index ab5dc08e044..886a66c3ef4 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -604,6 +604,8 @@ typedef struct st_join_table {
!(used_sjm_lookup_tables & ~emb_sj_nest->sj_inner_tables));
}
+ bool keyuse_is_valid_for_access_in_chosen_plan(JOIN *join, KEYUSE *keyuse);
+
void remove_redundant_bnl_scan_conds();
void save_explain_data(Explain_table_access *eta, table_map prefix_tables,
@@ -1120,6 +1122,11 @@ public:
to materialize and access by lookups
*/
table_map sjm_lookup_tables;
+ /**
+ Bitmap of semijoin tables that the chosen plan decided
+ to materialize to scan the results of materialization
+ */
+ table_map sjm_scan_tables;
/*
Constant tables for which we have found a row (as opposed to those for
which we didn't).
@@ -1488,6 +1495,7 @@ public:
in_to_exists_having= NULL;
emb_sjm_nest= NULL;
sjm_lookup_tables= 0;
+ sjm_scan_tables= 0;
}
/* True if the plan guarantees that it will be returned zero or one row */
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index cf4c2526807..229d284bc3d 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -1336,8 +1336,13 @@ bool mysqld_show_create_db(THD *thd, LEX_STRING *dbname,
if (test_all_bits(sctx->master_access, DB_ACLS))
db_access=DB_ACLS;
else
- db_access= (acl_get(sctx->host, sctx->ip, sctx->priv_user, dbname->str, 0) |
- sctx->master_access);
+ {
+ db_access= acl_get(sctx->host, sctx->ip, sctx->priv_user, dbname->str, 0) |
+ sctx->master_access;
+ if (sctx->priv_role[0])
+ db_access|= acl_get("", "", sctx->priv_role, dbname->str, 0);
+ }
+
if (!(db_access & DB_ACLS) && check_grant_db(thd,dbname->str))
{
status_var_increment(thd->status_var.access_denied_errors);
@@ -4995,8 +5000,10 @@ int fill_schema_schemata(THD *thd, TABLE_LIST *tables, COND *cond)
}
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (sctx->master_access & (DB_ACLS | SHOW_DB_ACL) ||
- acl_get(sctx->host, sctx->ip, sctx->priv_user, db_name->str, 0) ||
- !check_grant_db(thd, db_name->str))
+ acl_get(sctx->host, sctx->ip, sctx->priv_user, db_name->str, false) ||
+ (sctx->priv_role[0] ?
+ acl_get("", "", sctx->priv_role, db_name->str, false) : 0) ||
+ !check_grant_db(thd, db_name->str))
#endif
{
load_db_opt_by_name(thd, db_name->str, &create);
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 5e247915905..5c5f2d373c7 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -2549,6 +2549,9 @@ err:
if (non_trans_tmp_table_deleted ||
trans_tmp_table_deleted || non_tmp_table_deleted)
{
+ if (non_trans_tmp_table_deleted || trans_tmp_table_deleted)
+ thd->transaction.stmt.mark_dropped_temp_table();
+
query_cache_invalidate3(thd, tables, 0);
if (!dont_log_query && mysql_bin_log.is_open())
{
@@ -5091,6 +5094,9 @@ err:
if (thd->is_current_stmt_binlog_format_row() && create_info->tmp_table())
DBUG_RETURN(result);
+ if (create_info->tmp_table())
+ thd->transaction.stmt.mark_created_temp_table();
+
/* Write log if no error or if we already deleted a table */
if (!result || thd->log_current_statement)
{
@@ -5617,13 +5623,17 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table,
DBUG_PRINT("info",
("res: %d tmp_table: %d create_info->table: %p",
res, create_info->tmp_table(), local_create_info.table));
- if (!res && create_info->tmp_table() && local_create_info.table)
+ if (create_info->tmp_table())
{
- /*
- Remember that tmp table creation was logged so that we know if
- we should log a delete of it.
- */
- local_create_info.table->s->table_creation_was_logged= 1;
+ thd->transaction.stmt.mark_created_temp_table();
+ if (!res && local_create_info.table)
+ {
+ /*
+ Remember that tmp table creation was logged so that we know if
+ we should log a delete of it.
+ */
+ local_create_info.table->s->table_creation_was_logged= 1;
+ }
}
do_logging= TRUE;
}
@@ -9655,8 +9665,12 @@ bool mysql_trans_prepare_alter_copy_data(THD *thd)
bool mysql_trans_commit_alter_copy_data(THD *thd)
{
bool error= FALSE;
+ uint save_unsafe_rollback_flags;
DBUG_ENTER("mysql_trans_commit_alter_copy_data");
+ /* Save flags as transcommit_implicit_are_deleting_them */
+ save_unsafe_rollback_flags= thd->transaction.stmt.m_unsafe_rollback_flags;
+
if (ha_enable_transaction(thd, TRUE))
DBUG_RETURN(TRUE);
@@ -9671,6 +9685,7 @@ bool mysql_trans_commit_alter_copy_data(THD *thd)
if (trans_commit_implicit(thd))
error= TRUE;
+ thd->transaction.stmt.m_unsafe_rollback_flags= save_unsafe_rollback_flags;
DBUG_RETURN(error);
}
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index 431d6822f0e..92923779be7 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -772,7 +772,9 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
if (saved_error)
goto err;
- if (fake_select_lex != NULL && thd->stmt_arena->is_stmt_prepare())
+ if (fake_select_lex != NULL &&
+ (thd->stmt_arena->is_stmt_prepare() ||
+ (thd->lex->context_analysis_only & CONTEXT_ANALYSIS_ONLY_VIEW)))
{
/* Validate the global parameters of this union */
diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc
index 2c74ad5cb29..e2071184365 100644
--- a/sql/sys_vars.cc
+++ b/sql/sys_vars.cc
@@ -3052,6 +3052,10 @@ static bool fix_sql_mode(sys_var *self, THD *thd, enum_var_type type)
thd->server_status|= SERVER_STATUS_NO_BACKSLASH_ESCAPES;
else
thd->server_status&= ~SERVER_STATUS_NO_BACKSLASH_ESCAPES;
+ if (thd->variables.sql_mode & MODE_ANSI_QUOTES)
+ thd->server_status|= SERVER_STATUS_ANSI_QUOTES;
+ else
+ thd->server_status&= ~SERVER_STATUS_ANSI_QUOTES;
}
return false;
}
diff --git a/sql/table.cc b/sql/table.cc
index 511a1567a53..b03f64bc7e0 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -4499,16 +4499,7 @@ void TABLE::init(THD *thd, TABLE_LIST *tl)
DBUG_ASSERT(!file->keyread_enabled());
- /* mark the record[0] uninitialized */
- TRASH_ALLOC(record[0], s->reclength);
-
- /*
- Initialize the null marker bits, to ensure that if we are doing a read
- of only selected columns (like in keyread), all null markers are
- initialized.
- */
- memset(record[0], 255, s->null_bytes);
- memset(record[1], 255, s->null_bytes);
+ restore_record(this, s->default_values);
/* Tables may be reused in a sub statement. */
DBUG_ASSERT(!file->extra(HA_EXTRA_IS_ATTACHED_CHILDREN));
diff --git a/sql/temporary_tables.cc b/sql/temporary_tables.cc
index 174d1b6e184..42ebb87cbe4 100644
--- a/sql/temporary_tables.cc
+++ b/sql/temporary_tables.cc
@@ -1384,6 +1384,7 @@ bool THD::log_events_and_free_tmp_shares()
variables.character_set_client= cs_save;
get_stmt_da()->set_overwrite_status(true);
+ transaction.stmt.mark_dropped_temp_table();
if ((error= (mysql_bin_log.write(&qinfo) || error)))
{
/*
diff --git a/sql/transaction.cc b/sql/transaction.cc
index 9bacfb81bba..d01519b8bd4 100644
--- a/sql/transaction.cc
+++ b/sql/transaction.cc
@@ -198,11 +198,10 @@ bool trans_begin(THD *thd, uint flags)
thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
/*
- The following set should not be needed as the flag should always be 0
- when we come here. We should at some point change this to an assert.
+ The following set should not be needed as transaction state should
+ already be reset. We should at some point change this to an assert.
*/
- thd->transaction.all.modified_non_trans_table= FALSE;
- thd->transaction.all.m_unsafe_rollback_flags&= ~THD_TRANS::DID_WAIT;
+ thd->transaction.all.reset();
thd->has_waiter= false;
thd->waiting_on_group_commit= false;
@@ -323,8 +322,7 @@ bool trans_commit(THD *thd)
else
(void) RUN_HOOK(transaction, after_commit, (thd, FALSE));
thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
- thd->transaction.all.modified_non_trans_table= FALSE;
- thd->transaction.all.m_unsafe_rollback_flags&= ~THD_TRANS::DID_WAIT;
+ thd->transaction.all.reset();
thd->lex->start_transaction_opt= 0;
trans_track_end_trx(thd);
@@ -373,8 +371,7 @@ bool trans_commit_implicit(THD *thd)
}
thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
- thd->transaction.all.modified_non_trans_table= FALSE;
- thd->transaction.all.m_unsafe_rollback_flags&= ~THD_TRANS::DID_WAIT;
+ thd->transaction.all.reset();
/*
Upon implicit commit, reset the current transaction
@@ -420,8 +417,7 @@ bool trans_rollback(THD *thd)
thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
/* Reset the binlog transaction marker */
thd->variables.option_bits&= ~OPTION_GTID_BEGIN;
- thd->transaction.all.modified_non_trans_table= FALSE;
- thd->transaction.all.m_unsafe_rollback_flags&= ~THD_TRANS::DID_WAIT;
+ thd->transaction.all.reset();
thd->lex->start_transaction_opt= 0;
trans_track_end_trx(thd);
@@ -467,8 +463,7 @@ bool trans_rollback_implicit(THD *thd)
preserve backward compatibility.
*/
thd->variables.option_bits&= ~(OPTION_KEEP_LOG);
- thd->transaction.all.modified_non_trans_table= false;
- thd->transaction.all.m_unsafe_rollback_flags&= ~THD_TRANS::DID_WAIT;
+ thd->transaction.all.reset();
/* Rollback should clear transaction_rollback_request flag. */
DBUG_ASSERT(! thd->transaction_rollback_request);
@@ -506,6 +501,8 @@ bool trans_commit_stmt(THD *thd)
*/
DBUG_ASSERT(! thd->in_sub_stmt);
+ thd->merge_unsafe_rollback_flags();
+
if (thd->transaction.stmt.ha_list)
{
if (WSREP_ON)
@@ -559,6 +556,8 @@ bool trans_rollback_stmt(THD *thd)
*/
DBUG_ASSERT(! thd->in_sub_stmt);
+ thd->merge_unsafe_rollback_flags();
+
if (thd->transaction.stmt.ha_list)
{
if (WSREP_ON)
@@ -979,8 +978,7 @@ bool trans_xa_commit(THD *thd)
}
thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
- thd->transaction.all.modified_non_trans_table= FALSE;
- thd->transaction.all.m_unsafe_rollback_flags&= ~THD_TRANS::DID_WAIT;
+ thd->transaction.all.reset();
thd->server_status&=
~(SERVER_STATUS_IN_TRANS | SERVER_STATUS_IN_TRANS_READONLY);
DBUG_PRINT("info", ("clearing SERVER_STATUS_IN_TRANS"));
@@ -1037,8 +1035,7 @@ bool trans_xa_rollback(THD *thd)
res= xa_trans_force_rollback(thd);
thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
- thd->transaction.all.modified_non_trans_table= FALSE;
- thd->transaction.all.m_unsafe_rollback_flags&= ~THD_TRANS::DID_WAIT;
+ thd->transaction.all.reset();
thd->server_status&=
~(SERVER_STATUS_IN_TRANS | SERVER_STATUS_IN_TRANS_READONLY);
DBUG_PRINT("info", ("clearing SERVER_STATUS_IN_TRANS"));