summaryrefslogtreecommitdiff
path: root/sql/sql_parse.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_parse.cc')
-rw-r--r--sql/sql_parse.cc393
1 files changed, 6 insertions, 387 deletions
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index b5f55b981c8..b78815f0e52 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -50,6 +50,7 @@
// mysql_backup_table,
// mysql_restore_table
#include "sql_truncate.h" // mysql_truncate_table
+#include "sql_reload.h" // reload_acl_and_cache
#include "sql_admin.h" // mysql_assign_to_keycache
#include "sql_connect.h" // check_user,
// decrease_user_connections,
@@ -1696,140 +1697,6 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident,
/**
- Implementation of FLUSH TABLES <table_list> WITH READ LOCK.
-
- In brief: take exclusive locks, expel tables from the table
- cache, reopen the tables, enter the 'LOCKED TABLES' mode,
- downgrade the locks.
- Note: the function is written to be called from
- mysql_execute_command(), it is not reusable in arbitrary
- execution context.
-
- Required privileges
- -------------------
- Since the statement implicitly enters LOCK TABLES mode,
- it requires LOCK TABLES privilege on every table.
- But since the rest of FLUSH commands require
- the global RELOAD_ACL, it also requires RELOAD_ACL.
-
- Compatibility with the global read lock
- ---------------------------------------
- We don't wait for the GRL, since neither the
- 5.1 combination that this new statement is intended to
- replace (LOCK TABLE <list> WRITE; FLUSH TABLES;),
- nor FLUSH TABLES WITH READ LOCK do.
- @todo: this is not implemented, Dmitry disagrees.
- Currently we wait for GRL in another connection,
- but are compatible with a GRL in our own connection.
-
- Behaviour under LOCK TABLES
- ---------------------------
- Bail out: i.e. don't perform an implicit UNLOCK TABLES.
- This is not consistent with LOCK TABLES statement, but is
- in line with behaviour of FLUSH TABLES WITH READ LOCK, and we
- try to not introduce any new statements with implicit
- semantics.
-
- Compatibility with parallel updates
- -----------------------------------
- As a result, we will wait for all open transactions
- against the tables to complete. After the lock downgrade,
- new transactions will be able to read the tables, but not
- write to them.
-
- Differences from FLUSH TABLES <list>
- -------------------------------------
- - you can't flush WITH READ LOCK a non-existent table
- - you can't flush WITH READ LOCK under LOCK TABLES
- - currently incompatible with the GRL (@todo: fix)
-
- Effect on views and temporary tables.
- ------------------------------------
- You can only apply this command to existing base tables.
- If a view with such name exists, ER_WRONG_OBJECT is returned.
- If a temporary table with such name exists, it's ignored:
- if there is a base table, it's used, otherwise ER_NO_SUCH_TABLE
- is returned.
-*/
-
-static bool flush_tables_with_read_lock(THD *thd, TABLE_LIST *all_tables)
-{
- Lock_tables_prelocking_strategy lock_tables_prelocking_strategy;
- TABLE_LIST *table_list;
-
- /*
- This is called from SQLCOM_FLUSH, the transaction has
- been committed implicitly.
- */
-
- /* RELOAD_ACL is checked by the caller. Check table-level privileges. */
- if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, all_tables,
- FALSE, UINT_MAX, FALSE))
- goto error;
-
- if (thd->locked_tables_mode)
- {
- my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0));
- goto error;
- }
-
- /*
- @todo: Since lock_table_names() acquires a global IX
- lock, this actually waits for a GRL in another connection.
- We are thus introducing an incompatibility.
- Do nothing for now, since not taking a global IX violates
- current internal MDL asserts, fix after discussing with
- Dmitry.
- */
- if (lock_table_names(thd, all_tables, 0, thd->variables.lock_wait_timeout,
- MYSQL_OPEN_SKIP_TEMPORARY))
- goto error;
-
- for (table_list= all_tables; table_list;
- table_list= table_list->next_global)
- {
- /* Remove the table from cache. */
- mysql_mutex_lock(&LOCK_open);
- tdc_remove_table(thd, TDC_RT_REMOVE_ALL,
- table_list->db,
- table_list->table_name);
- mysql_mutex_unlock(&LOCK_open);
-
- /* Skip views and temporary tables. */
- table_list->required_type= FRMTYPE_TABLE; /* Don't try to flush views. */
- table_list->open_type= OT_BASE_ONLY; /* Ignore temporary tables. */
- }
-
- if (open_and_lock_tables(thd, all_tables, FALSE,
- MYSQL_OPEN_HAS_MDL_LOCK,
- &lock_tables_prelocking_strategy) ||
- thd->locked_tables_list.init_locked_tables(thd))
- {
- goto error;
- }
- thd->variables.option_bits|= OPTION_TABLE_LOCK;
-
- /*
- Downgrade the exclusive locks.
- Use MDL_SHARED_NO_WRITE as the intended
- post effect of this call is identical
- to LOCK TABLES <...> READ, and we didn't use
- thd->in_lock_talbes and thd->sql_command= SQLCOM_LOCK_TABLES
- hacks to enter the LTM.
- @todo: release the global IX lock here!!!
- */
- for (table_list= all_tables; table_list;
- table_list= table_list->next_global)
- table_list->mdl_request.ticket->downgrade_exclusive_lock(MDL_SHARED_NO_WRITE);
-
- return FALSE;
-
-error:
- return TRUE;
-}
-
-
-/**
Read query from packet and store in thd->query.
Used in COM_QUERY and COM_STMT_PREPARE.
@@ -3226,7 +3093,7 @@ end_with_restore_list:
/* So that DROP TEMPORARY TABLE gets to binlog at commit/rollback */
thd->variables.option_bits|= OPTION_KEEP_LOG;
}
- /* DDL and binlog write order protected by LOCK_open */
+ /* DDL and binlog write order are protected by metadata locks. */
res= mysql_rm_table(thd, first_table, lex->drop_if_exists,
lex->drop_temporary);
}
@@ -3771,6 +3638,10 @@ end_with_restore_list:
if (first_table && lex->type & REFRESH_READ_LOCK)
{
+ /* Check table-level privileges. */
+ if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, all_tables,
+ FALSE, UINT_MAX, FALSE))
+ goto error;
if (flush_tables_with_read_lock(thd, all_tables))
goto error;
my_ok(thd);
@@ -6512,258 +6383,6 @@ void add_join_natural(TABLE_LIST *a, TABLE_LIST *b, List<String> *using_fields,
/**
- Reload/resets privileges and the different caches.
-
- @param thd Thread handler (can be NULL!)
- @param options What should be reset/reloaded (tables, privileges, slave...)
- @param tables Tables to flush (if any)
- @param write_to_binlog True if we can write to the binlog.
-
- @note Depending on 'options', it may be very bad to write the
- query to the binlog (e.g. FLUSH SLAVE); this is a
- pointer where reload_acl_and_cache() will put 0 if
- it thinks we really should not write to the binlog.
- Otherwise it will put 1.
-
- @return Error status code
- @retval 0 Ok
- @retval !=0 Error; thd->killed is set or thd->is_error() is true
-*/
-
-bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
- bool *write_to_binlog)
-{
- bool result=0;
- select_errors=0; /* Write if more errors */
- bool tmp_write_to_binlog= 1;
-
- DBUG_ASSERT(!thd || !thd->in_sub_stmt);
-
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- if (options & REFRESH_GRANT)
- {
- THD *tmp_thd= 0;
- /*
- If reload_acl_and_cache() is called from SIGHUP handler we have to
- allocate temporary THD for execution of acl_reload()/grant_reload().
- */
- if (!thd && (thd= (tmp_thd= new THD)))
- {
- thd->thread_stack= (char*) &tmp_thd;
- thd->store_globals();
- }
-
- if (thd)
- {
- bool reload_acl_failed= acl_reload(thd);
- bool reload_grants_failed= grant_reload(thd);
- bool reload_servers_failed= servers_reload(thd);
-
- if (reload_acl_failed || reload_grants_failed || reload_servers_failed)
- {
- result= 1;
- /*
- When an error is returned, my_message may have not been called and
- the client will hang waiting for a response.
- */
- my_error(ER_UNKNOWN_ERROR, MYF(0), "FLUSH PRIVILEGES failed");
- }
- }
-
- if (tmp_thd)
- {
- delete tmp_thd;
- /* Remember that we don't have a THD */
- my_pthread_setspecific_ptr(THR_THD, 0);
- thd= 0;
- }
- reset_mqh((LEX_USER *)NULL, TRUE);
- }
-#endif
- if (options & REFRESH_LOG)
- {
- /*
- Flush the normal query log, the update log, the binary log,
- the slow query log, the relay log (if it exists) and the log
- tables.
- */
-
- options|= REFRESH_BINARY_LOG;
- options|= REFRESH_RELAY_LOG;
- options|= REFRESH_SLOW_LOG;
- options|= REFRESH_GENERAL_LOG;
- options|= REFRESH_ENGINE_LOG;
- options|= REFRESH_ERROR_LOG;
- }
-
- if (options & REFRESH_ERROR_LOG)
- if (flush_error_log())
- result= 1;
-
- if ((options & REFRESH_SLOW_LOG) && opt_slow_log)
- logger.flush_slow_log();
-
- if ((options & REFRESH_GENERAL_LOG) && opt_log)
- logger.flush_general_log();
-
- if (options & REFRESH_ENGINE_LOG)
- if (ha_flush_logs(NULL))
- result= 1;
-
- if (options & REFRESH_BINARY_LOG)
- {
- /*
- Writing this command to the binlog may result in infinite loops
- when doing mysqlbinlog|mysql, and anyway it does not really make
- sense to log it automatically (would cause more trouble to users
- than it would help them)
- */
- tmp_write_to_binlog= 0;
- if (mysql_bin_log.is_open())
- mysql_bin_log.rotate_and_purge(RP_FORCE_ROTATE);
- }
- if (options & REFRESH_RELAY_LOG)
- {
-#ifdef HAVE_REPLICATION
- mysql_mutex_lock(&LOCK_active_mi);
- rotate_relay_log(active_mi);
- mysql_mutex_unlock(&LOCK_active_mi);
-#endif
- }
-#ifdef HAVE_QUERY_CACHE
- if (options & REFRESH_QUERY_CACHE_FREE)
- {
- query_cache.pack(); // FLUSH QUERY CACHE
- options &= ~REFRESH_QUERY_CACHE; // Don't flush cache, just free memory
- }
- if (options & (REFRESH_TABLES | REFRESH_QUERY_CACHE))
- {
- query_cache.flush(); // RESET QUERY CACHE
- }
-#endif /*HAVE_QUERY_CACHE*/
-
- DBUG_ASSERT(!thd || thd->locked_tables_mode ||
- !thd->mdl_context.has_locks() ||
- thd->handler_tables_hash.records ||
- thd->global_read_lock.is_acquired());
-
- /*
- Note that if REFRESH_READ_LOCK bit is set then REFRESH_TABLES is set too
- (see sql_yacc.yy)
- */
- if (options & (REFRESH_TABLES | REFRESH_READ_LOCK))
- {
- if ((options & REFRESH_READ_LOCK) && thd)
- {
- /*
- On the first hand we need write lock on the tables to be flushed,
- on the other hand we must not try to aspire a global read lock
- if we have a write locked table as this would lead to a deadlock
- when trying to reopen (and re-lock) the table after the flush.
- */
- if (thd->locked_tables_mode)
- {
- my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0));
- return 1;
- }
- /*
- Writing to the binlog could cause deadlocks, as we don't log
- UNLOCK TABLES
- */
- tmp_write_to_binlog= 0;
- if (thd->global_read_lock.lock_global_read_lock(thd))
- return 1; // Killed
- if (close_cached_tables(thd, tables, FALSE, (options & REFRESH_FAST) ?
- FALSE : TRUE))
- result= 1;
-
- if (thd->global_read_lock.make_global_read_lock_block_commit(thd)) // Killed
- {
- /* Don't leave things in a half-locked state */
- thd->global_read_lock.unlock_global_read_lock(thd);
- return 1;
- }
- }
- else
- {
- if (thd && thd->locked_tables_mode)
- {
- /*
- If we are under LOCK TABLES we should have a write
- lock on tables which we are going to flush.
- */
- if (tables)
- {
- for (TABLE_LIST *t= tables; t; t= t->next_local)
- if (!find_table_for_mdl_upgrade(thd->open_tables, t->db,
- t->table_name, FALSE))
- return 1;
- }
- else
- {
- for (TABLE *tab= thd->open_tables; tab; tab= tab->next)
- {
- if (! tab->mdl_ticket->is_upgradable_or_exclusive())
- {
- my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE, MYF(0),
- tab->s->table_name.str);
- return 1;
- }
- }
- }
- }
-
- if (close_cached_tables(thd, tables, FALSE, (options & REFRESH_FAST) ?
- FALSE : TRUE))
- result= 1;
- }
- my_dbopt_cleanup();
- }
- if (options & REFRESH_HOSTS)
- hostname_cache_refresh();
- if (thd && (options & REFRESH_STATUS))
- refresh_status(thd);
- if (options & REFRESH_THREADS)
- flush_thread_cache();
-#ifdef HAVE_REPLICATION
- if (options & REFRESH_MASTER)
- {
- DBUG_ASSERT(thd);
- tmp_write_to_binlog= 0;
- if (reset_master(thd))
- {
- result=1;
- }
- }
-#endif
-#ifdef OPENSSL
- if (options & REFRESH_DES_KEY_FILE)
- {
- if (des_key_file && load_des_key_file(des_key_file))
- result= 1;
- }
-#endif
-#ifdef HAVE_REPLICATION
- if (options & REFRESH_SLAVE)
- {
- tmp_write_to_binlog= 0;
- mysql_mutex_lock(&LOCK_active_mi);
- if (reset_slave(thd, active_mi))
- result=1;
- mysql_mutex_unlock(&LOCK_active_mi);
- }
-#endif
- if (options & REFRESH_USER_RESOURCES)
- reset_mqh((LEX_USER *) NULL, 0); /* purecov: inspected */
- *write_to_binlog= tmp_write_to_binlog;
- /*
- If the query was killed then this function must fail.
- */
- return result || (thd ? thd->killed : 0);
-}
-
-
-/**
kill on thread.
@param thd Thread class