summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorMarko Mäkelä <marko.makela@mariadb.com>2021-10-21 14:57:00 +0300
committerMarko Mäkelä <marko.makela@mariadb.com>2021-10-21 14:57:00 +0300
commit489ef007bec398c3b7b628325b225c3a015922cf (patch)
tree7d1d5b1ea2c55d608f8697377776b9777fa622be /sql
parentd10c42b42541deed899dd1d1e04b69475339196c (diff)
parentd5bcccdabbf1a23c75ab4ee0c14149eb6ed27d98 (diff)
downloadmariadb-git-489ef007bec398c3b7b628325b225c3a015922cf.tar.gz
Merge 10.3 into 10.4
Diffstat (limited to 'sql')
-rw-r--r--sql/CMakeLists.txt1
-rw-r--r--sql/item.cc44
-rw-r--r--sql/item_jsonfunc.cc1
-rw-r--r--sql/log.h14
-rw-r--r--sql/log_event.cc26
-rw-r--r--sql/rpl_mi.cc8
-rw-r--r--sql/rpl_mi.h5
-rw-r--r--sql/sql_acl.cc377
-rw-r--r--sql/sql_handler.cc3
-rw-r--r--sql/sql_repl.cc10
-rw-r--r--sql/sql_select.cc23
-rw-r--r--sql/sql_show.cc7
-rw-r--r--sql/table.cc15
13 files changed, 324 insertions, 210 deletions
diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt
index e620c99cf8a..7154e3dbe44 100644
--- a/sql/CMakeLists.txt
+++ b/sql/CMakeLists.txt
@@ -319,7 +319,6 @@ IF(WITH_MYSQLD_LDFLAGS)
"${MYSQLD_LINK_FLAGS} ${WITH_MYSQLD_LDFLAGS}")
ENDIF()
-
FIND_PACKAGE(BISON 2.0)
diff --git a/sql/item.cc b/sql/item.cc
index 66b3ee46b38..7a00af71b2f 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -3741,8 +3741,48 @@ void Item_string::print(String *str, enum_query_type query_type)
}
else
{
- // Caller wants a result in the charset of str_value.
- str_value.print(str);
+ /*
+ We're restoring a parse-able statement from an Item tree.
+ Make sure to revert character set conversions that previously
+ happened in the parser when Item_string was created.
+ */
+ if (print_introducer)
+ {
+ /*
+ Print the string as is, without conversion:
+ Strings with introducers are not converted in the parser.
+ */
+ str_value.print(str);
+ }
+ else
+ {
+ /*
+ Print the string with conversion.
+ Strings without introducers are converted in the parser,
+ from character_set_client to character_set_connection.
+
+ When restoring a CREATE VIEW statement,
+ - str_value.charsets() contains parse time character_set_connection
+ - str->charset() contains parse time character_set_client
+ So we convert the string back from parse-time character_set_connection
+ to parse time character_set_client.
+
+ In some cases, e.g. SHOW PROCEDURE CODE, it's also possible
+ that str->charset() is "utf8mb3" instead of parse time
+ character_set_client. In these cases we convert
+ here from the parse-time character_set_connection to utf8mb3.
+
+ QQ: perhaps the code behind SHOW PROCEDURE CODE should
+ also request the result in the parse-time character_set_client
+ (like the code restoring CREATE VIEW statements does),
+ rather than in utf8mb3:
+ - utf8mb3 does not work well with non-BMP characters (e.g. emoji).
+ - Simply changing utf8mb3 to utf8mb4 will not fully help:
+ some character sets have unassigned characters,
+ they get lost during during cs->utf8mb4->cs round trip.
+ */
+ str_value.print_with_conversion(str, str->charset());
+ }
}
str->append('\'');
diff --git a/sql/item_jsonfunc.cc b/sql/item_jsonfunc.cc
index 4b4a94c814e..2ad25c00a3c 100644
--- a/sql/item_jsonfunc.cc
+++ b/sql/item_jsonfunc.cc
@@ -3530,6 +3530,7 @@ const char *Item_func_json_format::func_name() const
bool Item_func_json_format::fix_length_and_dec()
{
decimals= 0;
+ collation.set(args[0]->collation);
max_length= args[0]->max_length;
maybe_null= 1;
return FALSE;
diff --git a/sql/log.h b/sql/log.h
index 8994d536298..b7ac4fa5196 100644
--- a/sql/log.h
+++ b/sql/log.h
@@ -938,6 +938,20 @@ public:
void unlock_binlog_end_pos() { mysql_mutex_unlock(&LOCK_binlog_end_pos); }
mysql_mutex_t* get_binlog_end_pos_lock() { return &LOCK_binlog_end_pos; }
+ /*
+ Ensures the log's state is either LOG_OPEN or LOG_CLOSED. If something
+ failed along the desired path and left the log in invalid state, i.e.
+ LOG_TO_BE_OPENED, forces the state to be LOG_CLOSED.
+ */
+ void try_fix_log_state()
+ {
+ mysql_mutex_lock(get_log_lock());
+ /* Only change the log state if it is LOG_TO_BE_OPENED */
+ if (log_state == LOG_TO_BE_OPENED)
+ log_state= LOG_CLOSED;
+ mysql_mutex_unlock(get_log_lock());
+ }
+
int wait_for_update_binlog_end_pos(THD* thd, struct timespec * timeout);
/*
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 0dcb1a8d9a2..62a65d002b7 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -1,6 +1,6 @@
/*
Copyright (c) 2000, 2019, Oracle and/or its affiliates.
- Copyright (c) 2009, 2020, MariaDB
+ Copyright (c) 2009, 2021, 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
@@ -11762,19 +11762,21 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi)
restore_empty_query_table_list(thd->lex);
#if defined(WITH_WSREP) && defined(HAVE_QUERY_CACHE)
- if (WSREP(thd) && wsrep_thd_is_applying(thd))
- {
- query_cache.invalidate_locked_for_write(thd, rgi->tables_to_lock);
- }
+ if (WSREP(thd) && wsrep_thd_is_applying(thd))
+ query_cache.invalidate_locked_for_write(thd, rgi->tables_to_lock);
#endif /* WITH_WSREP && HAVE_QUERY_CACHE */
- if (unlikely(get_flags(STMT_END_F) &&
- (error= rows_event_stmt_cleanup(rgi, thd))))
- slave_rows_error_report(ERROR_LEVEL,
- thd->is_error() ? 0 : error,
- rgi, thd, table,
- get_type_str(),
- RPL_LOG_NAME, log_pos);
+ if (get_flags(STMT_END_F))
+ {
+ if (unlikely(error= rows_event_stmt_cleanup(rgi, thd)))
+ slave_rows_error_report(ERROR_LEVEL,
+ thd->is_error() ? 0 : error,
+ rgi, thd, table,
+ get_type_str(),
+ RPL_LOG_NAME, log_pos);
+ if (thd->slave_thread)
+ free_root(thd->mem_root, MYF(MY_KEEP_PREALLOC));
+ }
DBUG_RETURN(error);
err:
diff --git a/sql/rpl_mi.cc b/sql/rpl_mi.cc
index 43a02147496..fc5b8a4b01c 100644
--- a/sql/rpl_mi.cc
+++ b/sql/rpl_mi.cc
@@ -170,6 +170,8 @@ void Master_info::clear_in_memory_info(bool all)
{
port= MYSQL_PORT;
host[0] = 0; user[0] = 0; password[0] = 0;
+ domain_id_filter.clear_ids();
+ reset_dynamic(&ignore_server_ids);
}
}
@@ -1793,6 +1795,12 @@ void Domain_id_filter::reset_filter()
m_filter= false;
}
+void Domain_id_filter::clear_ids()
+{
+ reset_dynamic(&m_domain_ids[DO_DOMAIN_IDS]);
+ reset_dynamic(&m_domain_ids[IGNORE_DOMAIN_IDS]);
+}
+
/**
Update the do/ignore domain id filter lists.
diff --git a/sql/rpl_mi.h b/sql/rpl_mi.h
index 4d47689ac18..b6ff69d1f64 100644
--- a/sql/rpl_mi.h
+++ b/sql/rpl_mi.h
@@ -79,6 +79,11 @@ public:
void reset_filter();
/*
+ Clear do_ids and ignore_ids to disable domain id filtering
+ */
+ void clear_ids();
+
+ /*
Update the do/ignore domain id filter lists.
@param do_ids [IN] domain ids to be kept
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index e854f9a4a35..c8b829c83a0 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -10062,8 +10062,8 @@ static int handle_grant_struct(enum enum_acl_lists struct_no, bool drop,
LEX_USER *user_from, LEX_USER *user_to)
{
int result= 0;
- int idx;
int elements;
+ bool restart;
const char *UNINIT_VAR(user);
const char *UNINIT_VAR(host);
ACL_USER *acl_user= NULL;
@@ -10171,82 +10171,98 @@ static int handle_grant_struct(enum enum_acl_lists struct_no, bool drop,
DBUG_RETURN(-1);
}
+
#ifdef EXTRA_DEBUG
DBUG_PRINT("loop",("scan struct: %u search user: '%s' host: '%s'",
struct_no, user_from->user.str, user_from->host.str));
#endif
- /* Loop over all elements *backwards* (see the comment below). */
- for (idx= elements - 1; idx >= 0; idx--)
- {
- /*
- Get a pointer to the element.
- */
- switch (struct_no) {
- case USER_ACL:
- acl_user= dynamic_element(&acl_users, idx, ACL_USER*);
- user= acl_user->user.str;
- host= acl_user->host.hostname;
- break;
+ /* Loop over elements backwards as it may reduce the number of mem-moves
+ for dynamic arrays.
- case DB_ACL:
- acl_db= &acl_dbs.at(idx);
- user= acl_db->user;
- host= acl_db->host.hostname;
+ We restart the loop, if we deleted or updated anything in a hash table
+ because calling my_hash_delete or my_hash_update shuffles elements indices
+ and we can miss some if we do only one scan.
+ */
+ do {
+ restart= false;
+ for (int idx= elements - 1; idx >= 0; idx--)
+ {
+ /*
+ Get a pointer to the element.
+ */
+ switch (struct_no) {
+ case USER_ACL:
+ acl_user= dynamic_element(&acl_users, idx, ACL_USER*);
+ user= acl_user->user.str;
+ host= acl_user->host.hostname;
break;
- case COLUMN_PRIVILEGES_HASH:
- case PROC_PRIVILEGES_HASH:
- case FUNC_PRIVILEGES_HASH:
- case PACKAGE_SPEC_PRIVILEGES_HASH:
- case PACKAGE_BODY_PRIVILEGES_HASH:
- grant_name= (GRANT_NAME*) my_hash_element(grant_name_hash, idx);
- user= grant_name->user;
- host= grant_name->host.hostname;
- break;
+ case DB_ACL:
+ acl_db= &acl_dbs.at(idx);
+ user= acl_db->user;
+ host= acl_db->host.hostname;
+ break;
- case PROXY_USERS_ACL:
- acl_proxy_user= dynamic_element(&acl_proxy_users, idx, ACL_PROXY_USER*);
- user= acl_proxy_user->get_user();
- host= acl_proxy_user->get_host();
- break;
+ case COLUMN_PRIVILEGES_HASH:
+ case PROC_PRIVILEGES_HASH:
+ case FUNC_PRIVILEGES_HASH:
+ case PACKAGE_SPEC_PRIVILEGES_HASH:
+ case PACKAGE_BODY_PRIVILEGES_HASH:
+ grant_name= (GRANT_NAME*) my_hash_element(grant_name_hash, idx);
+ user= grant_name->user;
+ host= grant_name->host.hostname;
+ break;
- case ROLES_MAPPINGS_HASH:
- role_grant_pair= (ROLE_GRANT_PAIR *) my_hash_element(roles_mappings_hash, idx);
- user= role_grant_pair->u_uname;
- host= role_grant_pair->u_hname;
- break;
+ case PROXY_USERS_ACL:
+ acl_proxy_user= dynamic_element(&acl_proxy_users, idx, ACL_PROXY_USER*);
+ user= acl_proxy_user->get_user();
+ host= acl_proxy_user->get_host();
+ break;
- default:
- DBUG_ASSERT(0);
- }
- if (! host)
- host= "";
+ case ROLES_MAPPINGS_HASH:
+ role_grant_pair= (ROLE_GRANT_PAIR *) my_hash_element(roles_mappings_hash, idx);
+ user= role_grant_pair->u_uname;
+ host= role_grant_pair->u_hname;
+ break;
+
+ default:
+ DBUG_ASSERT(0);
+ }
+ if (! host)
+ host= "";
#ifdef EXTRA_DEBUG
- DBUG_PRINT("loop",("scan struct: %u index: %u user: '%s' host: '%s'",
- struct_no, idx, user, host));
+ DBUG_PRINT("loop",("scan struct: %u index: %u user: '%s' host: '%s'",
+ struct_no, idx, user, host));
#endif
- if (struct_no == ROLES_MAPPINGS_HASH)
- {
- const char* role= role_grant_pair->r_uname? role_grant_pair->r_uname: "";
- if (user_from->is_role())
+ if (struct_no == ROLES_MAPPINGS_HASH)
{
- /* When searching for roles within the ROLES_MAPPINGS_HASH, we have
- to check both the user field as well as the role field for a match.
+ const char* role= role_grant_pair->r_uname? role_grant_pair->r_uname: "";
+ if (user_from->is_role())
+ {
+ /* When searching for roles within the ROLES_MAPPINGS_HASH, we have
+ to check both the user field as well as the role field for a match.
- It is possible to have a role granted to a role. If we are going
- to modify the mapping entry, it needs to be done on either on the
- "user" end (here represented by a role) or the "role" end. At least
- one part must match.
+ It is possible to have a role granted to a role. If we are going
+ to modify the mapping entry, it needs to be done on either on the
+ "user" end (here represented by a role) or the "role" end. At least
+ one part must match.
- If the "user" end has a not-empty host string, it can never match
- as we are searching for a role here. A role always has an empty host
- string.
- */
- if ((*host || strcmp(user_from->user.str, user)) &&
- strcmp(user_from->user.str, role))
- continue;
+ If the "user" end has a not-empty host string, it can never match
+ as we are searching for a role here. A role always has an empty host
+ string.
+ */
+ if ((*host || strcmp(user_from->user.str, user)) &&
+ strcmp(user_from->user.str, role))
+ continue;
+ }
+ else
+ {
+ if (strcmp(user_from->user.str, user) ||
+ my_strcasecmp(system_charset_info, user_from->host.str, host))
+ continue;
+ }
}
else
{
@@ -10254,157 +10270,134 @@ static int handle_grant_struct(enum enum_acl_lists struct_no, bool drop,
my_strcasecmp(system_charset_info, user_from->host.str, host))
continue;
}
- }
- else
- {
- if (strcmp(user_from->user.str, user) ||
- my_strcasecmp(system_charset_info, user_from->host.str, host))
- continue;
- }
- result= 1; /* At least one element found. */
- if ( drop )
- {
- elements--;
- switch ( struct_no ) {
- case USER_ACL:
- free_acl_user(dynamic_element(&acl_users, idx, ACL_USER*));
- delete_dynamic_element(&acl_users, idx);
- break;
+ result= 1; /* At least one element found. */
+ if ( drop )
+ {
+ elements--;
+ switch ( struct_no ) {
+ case USER_ACL:
+ free_acl_user(dynamic_element(&acl_users, idx, ACL_USER*));
+ delete_dynamic_element(&acl_users, idx);
+ break;
- case DB_ACL:
- acl_dbs.del(idx);
- break;
+ case DB_ACL:
+ acl_dbs.del(idx);
+ break;
- case COLUMN_PRIVILEGES_HASH:
- case PROC_PRIVILEGES_HASH:
- case FUNC_PRIVILEGES_HASH:
- case PACKAGE_SPEC_PRIVILEGES_HASH:
- case PACKAGE_BODY_PRIVILEGES_HASH:
- my_hash_delete(grant_name_hash, (uchar*) grant_name);
- /*
- In our HASH implementation on deletion one elements
- is moved into a place where a deleted element was,
- and the last element is moved into the empty space.
- Thus we need to re-examine the current element, but
- we don't have to restart the search from the beginning.
- */
- if (idx != elements)
- idx++;
- break;
+ case COLUMN_PRIVILEGES_HASH:
+ case PROC_PRIVILEGES_HASH:
+ case FUNC_PRIVILEGES_HASH:
+ case PACKAGE_SPEC_PRIVILEGES_HASH:
+ case PACKAGE_BODY_PRIVILEGES_HASH:
+ my_hash_delete(grant_name_hash, (uchar*) grant_name);
+ restart= true;
+ break;
- case PROXY_USERS_ACL:
- delete_dynamic_element(&acl_proxy_users, idx);
- break;
+ case PROXY_USERS_ACL:
+ delete_dynamic_element(&acl_proxy_users, idx);
+ break;
- case ROLES_MAPPINGS_HASH:
- my_hash_delete(roles_mappings_hash, (uchar*) role_grant_pair);
- if (idx != elements)
- idx++;
- break;
+ case ROLES_MAPPINGS_HASH:
+ my_hash_delete(roles_mappings_hash, (uchar*) role_grant_pair);
+ restart= true;
+ break;
- default:
- DBUG_ASSERT(0);
- break;
+ default:
+ DBUG_ASSERT(0);
+ break;
+ }
}
- }
- else if ( user_to )
- {
- switch ( struct_no ) {
- case USER_ACL:
- acl_user->user= safe_lexcstrdup_root(&acl_memroot, user_to->user);
- update_hostname(&acl_user->host, strdup_root(&acl_memroot, user_to->host.str));
- acl_user->hostname_length= strlen(acl_user->host.hostname);
- break;
+ else if ( user_to )
+ {
+ switch ( struct_no ) {
+ case USER_ACL:
+ acl_user->user= safe_lexcstrdup_root(&acl_memroot, user_to->user);
+ update_hostname(&acl_user->host, strdup_root(&acl_memroot, user_to->host.str));
+ acl_user->hostname_length= strlen(acl_user->host.hostname);
+ break;
- case DB_ACL:
- acl_db->user= strdup_root(&acl_memroot, user_to->user.str);
- update_hostname(&acl_db->host, strdup_root(&acl_memroot, user_to->host.str));
- break;
+ case DB_ACL:
+ acl_db->user= strdup_root(&acl_memroot, user_to->user.str);
+ update_hostname(&acl_db->host, strdup_root(&acl_memroot, user_to->host.str));
+ break;
- case COLUMN_PRIVILEGES_HASH:
- case PROC_PRIVILEGES_HASH:
- case FUNC_PRIVILEGES_HASH:
- case PACKAGE_SPEC_PRIVILEGES_HASH:
- case PACKAGE_BODY_PRIVILEGES_HASH:
- {
- /*
- Save old hash key and its length to be able to properly update
- element position in hash.
- */
- char *old_key= grant_name->hash_key;
- size_t old_key_length= grant_name->key_length;
+ case COLUMN_PRIVILEGES_HASH:
+ case PROC_PRIVILEGES_HASH:
+ case FUNC_PRIVILEGES_HASH:
+ case PACKAGE_SPEC_PRIVILEGES_HASH:
+ case PACKAGE_BODY_PRIVILEGES_HASH:
+ {
+ /*
+ Save old hash key and its length to be able to properly update
+ element position in hash.
+ */
+ char *old_key= grant_name->hash_key;
+ size_t old_key_length= grant_name->key_length;
+
+ /*
+ Update the grant structure with the new user name and host name.
+ */
+ grant_name->set_user_details(user_to->host.str, grant_name->db,
+ user_to->user.str, grant_name->tname,
+ TRUE);
+
+ /*
+ Since username is part of the hash key, when the user name
+ is renamed, the hash key is changed. Update the hash to
+ ensure that the position matches the new hash key value
+ */
+ my_hash_update(grant_name_hash, (uchar*) grant_name, (uchar*) old_key,
+ old_key_length);
+ restart= true;
+ break;
+ }
- /*
- Update the grant structure with the new user name and host name.
- */
- grant_name->set_user_details(user_to->host.str, grant_name->db,
- user_to->user.str, grant_name->tname,
- TRUE);
-
- /*
- Since username is part of the hash key, when the user name
- is renamed, the hash key is changed. Update the hash to
- ensure that the position matches the new hash key value
- */
- my_hash_update(grant_name_hash, (uchar*) grant_name, (uchar*) old_key,
- old_key_length);
- /*
- hash_update() operation could have moved element from the tail or
- the head of the hash to the current position. But it can never
- move an element from the head to the tail or from the tail to the
- head over the current element.
- So we need to examine the current element once again, but
- we don't need to restart the search from the beginning.
- */
- idx++;
+ case PROXY_USERS_ACL:
+ acl_proxy_user->set_user (&acl_memroot, user_to->user.str);
+ acl_proxy_user->set_host (&acl_memroot, user_to->host.str);
break;
- }
- case PROXY_USERS_ACL:
- acl_proxy_user->set_user (&acl_memroot, user_to->user.str);
- acl_proxy_user->set_host (&acl_memroot, user_to->host.str);
- break;
+ case ROLES_MAPPINGS_HASH:
+ {
+ /*
+ Save old hash key and its length to be able to properly update
+ element position in hash.
+ */
+ char *old_key= role_grant_pair->hashkey.str;
+ size_t old_key_length= role_grant_pair->hashkey.length;
+ bool oom;
+
+ if (user_to->is_role())
+ oom= role_grant_pair->init(&acl_memroot, role_grant_pair->u_uname,
+ role_grant_pair->u_hname,
+ user_to->user.str, false);
+ else
+ oom= role_grant_pair->init(&acl_memroot, user_to->user.str,
+ user_to->host.str,
+ role_grant_pair->r_uname, false);
+ if (oom)
+ DBUG_RETURN(-1);
+
+ my_hash_update(roles_mappings_hash, (uchar*) role_grant_pair,
+ (uchar*) old_key, old_key_length);
+ restart= true;
+ break;
+ }
- case ROLES_MAPPINGS_HASH:
- {
- /*
- Save old hash key and its length to be able to properly update
- element position in hash.
- */
- char *old_key= role_grant_pair->hashkey.str;
- size_t old_key_length= role_grant_pair->hashkey.length;
- bool oom;
-
- if (user_to->is_role())
- oom= role_grant_pair->init(&acl_memroot, role_grant_pair->u_uname,
- role_grant_pair->u_hname,
- user_to->user.str, false);
- else
- oom= role_grant_pair->init(&acl_memroot, user_to->user.str,
- user_to->host.str,
- role_grant_pair->r_uname, false);
- if (oom)
- DBUG_RETURN(-1);
-
- my_hash_update(roles_mappings_hash, (uchar*) role_grant_pair,
- (uchar*) old_key, old_key_length);
- idx++; // see the comment above
+ default:
+ DBUG_ASSERT(0);
break;
}
- default:
- DBUG_ASSERT(0);
+ }
+ else
+ {
+ /* If search is requested, we do not need to search further. */
break;
}
-
}
- else
- {
- /* If search is requested, we do not need to search further. */
- break;
- }
- }
+ } while (restart);
#ifdef EXTRA_DEBUG
DBUG_PRINT("loop",("scan struct: %u result %d", struct_no, result));
#endif
diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc
index 8447d5bea7d..073d523b876 100644
--- a/sql/sql_handler.cc
+++ b/sql/sql_handler.cc
@@ -783,6 +783,9 @@ retry:
if (!(handler= mysql_ha_find_handler(thd, &tables->alias)))
goto err0;
+ if (thd->transaction.xid_state.check_has_uncommitted_xa())
+ goto err0;
+
table= handler->table;
tables->table= table; // This is used by fix_fields
table->pos_in_table_list= tables;
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index e96129465fe..94cbc6be614 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -3948,6 +3948,16 @@ err:
mi->unlock_slave_threads();
if (ret == FALSE)
my_ok(thd);
+ else
+ {
+ /*
+ Depending on where CHANGE MASTER failed, the logs may be waiting to be
+ reopened. This would break future log updates and CHANGE MASTER calls.
+ `try_fix_log_state()` allows the relay log to fix its state to no longer
+ expect to be reopened.
+ */
+ mi->rli.relay_log.try_fix_log_state();
+ }
DBUG_RETURN(ret);
}
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 2010260eaf6..e12eeb6c815 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -27702,6 +27702,11 @@ void st_select_lex::print(THD *thd, String *str, enum_query_type query_type)
//Item List
bool first= 1;
+ /*
+ outer_select() can not be used here because it is for name resolution
+ and will return NULL at any end of name resolution chain (view/derived)
+ */
+ bool top_level= (get_master()->get_master() == 0);
List_iterator_fast<Item> it(item_list);
Item *item;
while ((item= it++))
@@ -27711,7 +27716,8 @@ void st_select_lex::print(THD *thd, String *str, enum_query_type query_type)
else
str->append(',');
- if (is_subquery_function() && item->is_autogenerated_name)
+ if ((is_subquery_function() && item->is_autogenerated_name) ||
+ !item->name.str)
{
/*
Do not print auto-generated aliases in subqueries. It has no purpose
@@ -27720,7 +27726,20 @@ void st_select_lex::print(THD *thd, String *str, enum_query_type query_type)
item->print(str, query_type);
}
else
- item->print_item_w_name(str, query_type);
+ {
+ /*
+ Do not print illegal names (if it is not top level SELECT).
+ Top level view checked (and correct name are assigned),
+ other cases of top level SELECT are not important, because
+ it is not "table field".
+ */
+ if (top_level ||
+ !item->is_autogenerated_name ||
+ !check_column_name(item->name.str))
+ item->print_item_w_name(str, query_type);
+ else
+ item->print(str, query_type);
+ }
}
/*
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 40efe1ec550..cf3719b0cd0 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -4511,7 +4511,9 @@ make_table_name_list(THD *thd, Dynamic_array<LEX_CSTRING*> *table_names,
if (!lookup_field_vals->wild_table_value &&
lookup_field_vals->table_value.str)
{
- if (lookup_field_vals->table_value.length > NAME_LEN)
+ if (check_table_name(lookup_field_vals->table_value.str,
+ lookup_field_vals->table_value.length,
+ false))
{
/*
Impossible value for a table name,
@@ -4548,6 +4550,9 @@ make_table_name_list(THD *thd, Dynamic_array<LEX_CSTRING*> *table_names,
return (schema_tables_add(thd, table_names,
lookup_field_vals->table_value.str));
+ if (check_db_name((LEX_STRING*)db_name))
+ return 0; // Impossible TABLE_SCHEMA name
+
find_files_result res= find_files(thd, table_names, db_name, path,
&lookup_field_vals->table_value);
if (res != FIND_FILES_OK)
diff --git a/sql/table.cc b/sql/table.cc
index e24309fdd70..9a2b2819455 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -4709,6 +4709,21 @@ bool check_table_name(const char *name, size_t length, bool check_for_path_chars
if (check_for_path_chars &&
(*name == '/' || *name == '\\' || *name == '~' || *name == FN_EXTCHAR))
return 1;
+ /*
+ We don't allow zero byte in table/schema names:
+ - Some code still uses NULL-terminated strings.
+ Zero bytes will confuse this code.
+ - There is a little practical use of zero bytes in names anyway.
+ Note, if the string passed as "name" comes here
+ from the parser as an identifier, it does not contain zero bytes,
+ as the parser rejects zero bytes in identifiers.
+ But "name" can also come here from queries like this:
+ SELECT * FROM I_S.TABLES WHERE TABLE_NAME='str';
+ In this case "name" is a general string expression
+ and it can have any arbitrary bytes, including zero bytes.
+ */
+ if (*name == 0x00)
+ return 1;
name++;
name_length++;
}