summaryrefslogtreecommitdiff
path: root/sql/sql_base.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_base.cc')
-rw-r--r--sql/sql_base.cc193
1 files changed, 140 insertions, 53 deletions
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 0cd46a7c6fb..3e594d4da4b 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -902,8 +902,7 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh,
bool found=0;
for (TABLE_LIST *table= tables; table; table= table->next_local)
{
- if ((!table->table || !table->table->s->log_table) &&
- remove_table_from_cache(thd, table->db, table->table_name,
+ if (remove_table_from_cache(thd, table->db, table->table_name,
RTFC_OWNED_BY_THD_FLAG))
found=1;
}
@@ -951,8 +950,7 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh,
are employed by CREATE TABLE as in this case table simply does not
exist yet.
*/
- if (!table->s->log_table &&
- (table->needs_reopen_or_name_lock() && table->db_stat))
+ if (table->needs_reopen_or_name_lock() && table->db_stat)
{
found=1;
DBUG_PRINT("signal", ("Waiting for COND_refresh"));
@@ -1679,8 +1677,28 @@ TABLE *find_temporary_table(THD *thd, TABLE_LIST *table_list)
}
-/*
- Close temporary table and unlink from thd->temporary tables
+/**
+ Drop a temporary table.
+
+ Try to locate the table in the list of thd->temporary_tables.
+ If the table is found:
+ - if the table is in thd->locked_tables, unlock it and
+ remove it from the list of locked tables. Currently only transactional
+ temporary tables are present in the locked_tables list.
+ - Close the temporary table, remove its .FRM
+ - remove the table from the list of temporary tables
+
+ This function is used to drop user temporary tables, as well as
+ internal tables created in CREATE TEMPORARY TABLE ... SELECT
+ or ALTER TABLE. Even though part of the work done by this function
+ is redundant when the table is internal, as long as we
+ link both internal and user temporary tables into the same
+ thd->temporary_tables list, it's impossible to tell here whether
+ we're dealing with an internal or a user temporary table.
+
+ @retval TRUE the table was not found in the list of temporary tables
+ of this thread
+ @retval FALSE the table was found and dropped successfully.
*/
bool close_temporary_table(THD *thd, TABLE_LIST *table_list)
@@ -1689,6 +1707,11 @@ bool close_temporary_table(THD *thd, TABLE_LIST *table_list)
if (!(table= find_temporary_table(thd, table_list)))
return 1;
+ /*
+ If LOCK TABLES list is not empty and contains this table,
+ unlock the table and remove the table from this list.
+ */
+ mysql_lock_remove(thd, thd->locked_tables, table, FALSE);
close_temporary_table(thd, table, 1, 1);
return 0;
}
@@ -1835,7 +1858,7 @@ void unlink_open_table(THD *thd, TABLE *find, bool unlock)
!memcmp(list->s->table_cache_key.str, key, key_length))
{
if (unlock && thd->locked_tables)
- mysql_lock_remove(thd, thd->locked_tables,list);
+ mysql_lock_remove(thd, thd->locked_tables, list, TRUE);
VOID(hash_delete(&open_cache,(uchar*) list)); // Close table
}
else
@@ -1861,8 +1884,13 @@ void unlink_open_table(THD *thd, TABLE *find, bool unlock)
@note This routine assumes that table to be closed is open only
by calling thread so we needn't wait until other threads
- will close the table. It also assumes that table to be
- dropped is already unlocked.
+ will close the table. Also unless called under implicit or
+ explicit LOCK TABLES mode it assumes that table to be
+ dropped is already unlocked. In the former case it will
+ also remove lock on the table. But one should not rely on
+ this behaviour as it may change in future.
+ Currently, however, this function is never called for a
+ table that was locked with LOCK TABLES.
*/
void drop_open_table(THD *thd, TABLE *table, const char *db_name,
@@ -2277,7 +2305,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
}
table->query_id= thd->query_id;
table->clear_query_id= 1;
- thd->tmp_table_used= 1;
+ thd->thread_specific_used= TRUE;
DBUG_PRINT("info",("Using temporary table"));
goto reset;
}
@@ -2468,8 +2496,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
&state))
{
/*
- Here we flush tables marked for flush. However we never flush log
- tables here. They are flushed only on FLUSH LOGS.
+ Here we flush tables marked for flush.
Normally, table->s->version contains the value of
refresh_version from the moment when this table was
(re-)opened and added to the cache.
@@ -2486,7 +2513,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
c1: name lock t2; -- blocks
c2: open t1; -- blocks
*/
- if (table->needs_reopen_or_name_lock() && !table->s->log_table)
+ if (table->needs_reopen_or_name_lock())
{
DBUG_PRINT("note",
("Found table '%s.%s' with different refresh version",
@@ -2840,7 +2867,7 @@ void close_data_files_and_morph_locks(THD *thd, const char *db,
!strcmp(table->s->db.str, db))
{
if (thd->locked_tables)
- mysql_lock_remove(thd, thd->locked_tables, table);
+ mysql_lock_remove(thd, thd->locked_tables, table, TRUE);
table->open_placeholder= 1;
close_handle_and_leave_table_as_lock(table);
}
@@ -2962,10 +2989,9 @@ void close_old_data_files(THD *thd, TABLE *table, bool morph_locks,
for (; table ; table=table->next)
{
/*
- Reopen marked for flush. But close log tables. They are flushed only
- explicitly on FLUSH LOGS
+ Reopen marked for flush.
*/
- if (table->needs_reopen_or_name_lock() && !table->s->log_table)
+ if (table->needs_reopen_or_name_lock())
{
found=1;
if (table->db_stat)
@@ -2979,7 +3005,7 @@ void close_old_data_files(THD *thd, TABLE *table, bool morph_locks,
instances of this table.
*/
mysql_lock_abort(thd, table, TRUE);
- mysql_lock_remove(thd, thd->locked_tables, table);
+ mysql_lock_remove(thd, thd->locked_tables, table, TRUE);
/*
We want to protect the table from concurrent DDL operations
(like RENAME TABLE) until we will re-open and re-lock it.
@@ -3012,10 +3038,6 @@ void close_old_data_files(THD *thd, TABLE *table, bool morph_locks,
Wait until all threads has closed the tables in the list
We have also to wait if there is thread that has a lock on this table even
if the table is closed
- NOTE: log tables are handled differently by the logging routines.
- E.g. general_log is always opened and locked by the logger
- and the table handler used by the logger, will be skipped by
- this check.
*/
bool table_is_used(TABLE *table, bool wait_for_name_lock)
@@ -3034,10 +3056,10 @@ bool table_is_used(TABLE *table, bool wait_for_name_lock)
search= (TABLE*) hash_next(&open_cache, (uchar*) key,
key_length, &state))
{
- DBUG_PRINT("info", ("share: 0x%lx locked_by_logger: %d "
+ DBUG_PRINT("info", ("share: 0x%lx "
"open_placeholder: %d locked_by_name: %d "
"db_stat: %u version: %lu",
- (ulong) search->s, search->locked_by_logger,
+ (ulong) search->s,
search->open_placeholder, search->locked_by_name,
search->db_stat,
search->s->version));
@@ -3049,12 +3071,9 @@ bool table_is_used(TABLE *table, bool wait_for_name_lock)
- If we are in flush table and we didn't execute the flush
- If the table engine is open and it's an old version
(We must wait until all engines are shut down to use the table)
- However we fo not wait if we encountered a table, locked by the logger.
- Log tables are managed separately by logging routines.
*/
- if (!search->locked_by_logger &&
- (search->locked_by_name && wait_for_name_lock ||
- (search->is_name_opened() && search->needs_reopen_or_name_lock())))
+ if ( (search->locked_by_name && wait_for_name_lock) ||
+ (search->is_name_opened() && search->needs_reopen_or_name_lock()))
DBUG_RETURN(1);
}
} while ((table=table->next));
@@ -3131,7 +3150,7 @@ TABLE *drop_locked_tables(THD *thd,const char *db, const char *table_name)
if (!strcmp(table->s->table_name.str, table_name) &&
!strcmp(table->s->db.str, db))
{
- mysql_lock_remove(thd, thd->locked_tables,table);
+ mysql_lock_remove(thd, thd->locked_tables, table, TRUE);
if (!found)
{
found= table;
@@ -3766,6 +3785,7 @@ static bool check_lock_and_start_stmt(THD *thd, TABLE *table,
thd Thread handler
table_list Table to open is first table in this list
lock_type Lock to use for open
+ lock_flags Flags passed to mysql_lock_table
NOTE
This function don't do anything like SP/SF/views/triggers analysis done
@@ -3781,7 +3801,8 @@ static bool check_lock_and_start_stmt(THD *thd, TABLE *table,
table_list->table table
*/
-TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type)
+TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type,
+ uint lock_flags)
{
TABLE *table;
bool refresh;
@@ -3797,13 +3818,6 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type)
if (table)
{
-#if defined( __WIN__)
- /* Win32 can't drop a file that is open */
- if (lock_type == TL_WRITE_ALLOW_READ)
- {
- lock_type= TL_WRITE;
- }
-#endif /* __WIN__ */
table_list->lock_type= lock_type;
table_list->table= table;
table->grant= table_list->grant;
@@ -3816,8 +3830,8 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type)
{
DBUG_ASSERT(thd->lock == 0); // You must lock everything at once
if ((table->reginfo.lock_type= lock_type) != TL_UNLOCK)
- if (! (thd->lock= mysql_lock_tables(thd, &table_list->table, 1, 0,
- &refresh)))
+ if (! (thd->lock= mysql_lock_tables(thd, &table_list->table, 1,
+ lock_flags, &refresh)))
table= 0;
}
}
@@ -4156,11 +4170,6 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count, bool *need_reopen)
DBUG_ASSERT(thd->lock == 0); // You must lock everything at once
TABLE **start,**ptr;
uint lock_flag= MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN;
-
- /* Ignore GLOBAL READ LOCK and GLOBAL READ_ONLY if called from a logger */
- if (logger.is_privileged_thread(thd))
- lock_flag|= (MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK |
- MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY);
if (!(ptr=start=(TABLE**) thd->alloc(sizeof(TABLE*)*count)))
DBUG_RETURN(-1);
@@ -4505,8 +4514,7 @@ find_field_in_view(THD *thd, TABLE_LIST *table_list,
table_list->alias, name, item_name, (ulong) ref));
Field_iterator_view field_it;
field_it.set(table_list);
- Query_arena *arena, backup;
- LINT_INIT(arena);
+ Query_arena *arena= 0, backup;
DBUG_ASSERT(table_list->schema_table_reformed ||
(ref != 0 && table_list->view != 0));
@@ -4515,14 +4523,14 @@ find_field_in_view(THD *thd, TABLE_LIST *table_list,
if (!my_strcasecmp(system_charset_info, field_it.name(), name))
{
// in PS use own arena or data will be freed after prepare
- if (register_tree_change)
+ if (register_tree_change && thd->stmt_arena->is_stmt_prepare_or_first_sp_execute())
arena= thd->activate_stmt_arena_if_needed(&backup);
/*
create_item() may, or may not create a new Item, depending on
the column reference. See create_view_field() for details.
*/
Item *item= field_it.create_item(thd);
- if (register_tree_change && arena)
+ if (arena)
thd->restore_active_arena(arena, &backup);
if (!item)
@@ -7189,7 +7197,6 @@ bool remove_table_from_cache(THD *thd, const char *db, const char *table_name,
else if (in_use != thd)
{
DBUG_PRINT("info", ("Table was in use by other thread"));
- in_use->some_tables_deleted=1;
if (table->is_name_opened())
{
DBUG_PRINT("info", ("Found another active instance of the table"));
@@ -7625,7 +7632,7 @@ open_system_tables_for_read(THD *thd, TABLE_LIST *table_list,
if (!table)
goto error;
- DBUG_ASSERT(table->s->system_table);
+ DBUG_ASSERT(table->s->table_category == TABLE_CATEGORY_SYSTEM);
table->use_all_columns();
table->reginfo.lock_type= tables->lock_type;
@@ -7692,12 +7699,92 @@ open_system_table_for_update(THD *thd, TABLE_LIST *one_table)
{
DBUG_ENTER("open_system_table_for_update");
- TABLE *table= open_ltable(thd, one_table, one_table->lock_type);
+ TABLE *table= open_ltable(thd, one_table, one_table->lock_type, 0);
if (table)
{
- DBUG_ASSERT(table->s->system_table);
+ DBUG_ASSERT(table->s->table_category == TABLE_CATEGORY_SYSTEM);
table->use_all_columns();
}
DBUG_RETURN(table);
}
+
+/**
+ Open a performance schema table.
+ Opening such tables is performed internally in the server
+ implementation, and is a 'nested' open, since some tables
+ might be already opened by the current thread.
+ The thread context before this call is saved, and is restored
+ when calling close_performance_schema_table().
+ @param thd The current thread
+ @param one_table Performance schema table to open
+ @param backup [out] Temporary storage used to save the thread context
+*/
+TABLE *
+open_performance_schema_table(THD *thd, TABLE_LIST *one_table,
+ Open_tables_state *backup)
+{
+ uint flags= ( MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK
+ | MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY
+ | MYSQL_LOCK_PERF_SCHEMA );
+
+ DBUG_ENTER("open_performance_schema_table");
+
+ thd->reset_n_backup_open_tables_state(backup);
+
+ TABLE *table= open_ltable(thd, one_table, one_table->lock_type, flags);
+ if (table)
+ {
+ DBUG_ASSERT(table->s->table_category == TABLE_CATEGORY_PERFORMANCE);
+ /* Make sure all columns get assigned to a default value */
+ table->use_all_columns();
+ table->no_replicate= 1;
+ }
+
+ DBUG_RETURN(table);
+}
+
+/**
+ Close a performance schema table.
+ The last table opened by open_performance_schema_table()
+ is closed, then the thread context is restored.
+ @param thd The current thread
+ @param backup [in] the context to restore.
+*/
+void close_performance_schema_table(THD *thd, Open_tables_state *backup)
+{
+ bool found_old_table;
+
+ if (thd->lock)
+ {
+ /*
+ Note:
+ We do not create explicitly a separate transaction for the
+ performance table I/O, but borrow the current transaction.
+ lock + unlock will autocommit the change done in the
+ performance schema table: this is the expected result.
+ The current transaction should not be affected by this code.
+ TODO: Note that if a transactional engine is used for log tables,
+ this code will need to be revised, as a separate transaction
+ might be needed.
+ */
+ mysql_unlock_tables(thd, thd->lock);
+ thd->lock= 0;
+ }
+
+ safe_mutex_assert_not_owner(&LOCK_open);
+
+ pthread_mutex_lock(&LOCK_open);
+
+ found_old_table= false;
+ while (thd->open_tables)
+ found_old_table|= close_thread_table(thd, &thd->open_tables);
+
+ if (found_old_table)
+ broadcast_refresh();
+
+ pthread_mutex_unlock(&LOCK_open);
+
+ thd->restore_backup_open_tables_state(backup);
+}
+