From d9aa82154b02ec2e6bccb0048f9e0c94b6b0af6b Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich Date: Mon, 27 Sep 2010 17:03:27 +0400 Subject: WL#5496 - Plugin LOAD_OPTION in INFORMATION_SCHEMA.PLUGINS This patch implements I_S.PLUGINS.LOAD_OPTION column as specified by WL#5496. mysql-test/r/plugin_load_option.result: A test case for WL#5496. mysql-test/suite/funcs_1/r/is_columns_is.result: Adjusted a test case according to WL#5496. mysql-test/t/plugin_load_option.test: A test case for WL#5496. sql/sql_show.cc: Added LOAD_OPTION column to I_S.PLUGINS. --- sql/sql_show.cc | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'sql/sql_show.cc') diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 6b24e3db7bc..10b918b2505 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -211,6 +211,11 @@ static my_bool show_plugins(THD *thd, plugin_ref plugin, } table->field[9]->set_notnull(); + table->field[10]->store( + global_plugin_typelib_names[plugin_load_option(plugin)], + strlen(global_plugin_typelib_names[plugin_load_option(plugin)]), + cs); + return schema_table_store_record(thd, table); } @@ -7214,6 +7219,7 @@ ST_FIELD_INFO plugin_fields_info[]= {"PLUGIN_AUTHOR", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE}, {"PLUGIN_DESCRIPTION", 65535, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE}, {"PLUGIN_LICENSE", 80, MYSQL_TYPE_STRING, 0, 1, "License", SKIP_OPEN_TABLE}, + {"LOAD_OPTION", 64, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}, {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE} }; -- cgit v1.2.1 From a5efb91deaf8a9c3bf53cd82ebd574be0cdabc5d Mon Sep 17 00:00:00 2001 From: Davi Arnaut Date: Wed, 6 Oct 2010 11:34:28 -0300 Subject: Bug#49938: Failing assertion: inode or deadlock in fsp/fsp0fsp.c Bug#54678: InnoDB, TRUNCATE, ALTER, I_S SELECT, crash or deadlock - Incompatible change: truncate no longer resorts to a row by row delete if the storage engine does not support the truncate method. Consequently, the count of affected rows does not, in any case, reflect the actual number of rows. - Incompatible change: it is no longer possible to truncate a table that participates as a parent in a foreign key constraint, unless it is a self-referencing constraint (both parent and child are in the same table). To work around this incompatible change and still be able to truncate such tables, disable foreign checks with SET foreign_key_checks=0 before truncate. Alternatively, if foreign key checks are necessary, please use a DELETE statement without a WHERE condition. Problem description: The problem was that for storage engines that do not support truncate table via a external drop and recreate, such as InnoDB which implements truncate via a internal drop and recreate, the delete_all_rows method could be invoked with a shared metadata lock, causing problems if the engine needed exclusive access to some internal metadata. This problem originated with the fact that there is no truncate specific handler method, which ended up leading to a abuse of the delete_all_rows method that is primarily used for delete operations without a condition. Solution: The solution is to introduce a truncate handler method that is invoked when the engine does not support truncation via a table drop and recreate. This method is invoked under a exclusive metadata lock, so that there is only a single instance of the table when the method is invoked. Also, the method is not invoked and a error is thrown if the table is a parent in a non-self-referencing foreign key relationship. This was necessary to avoid inconsistency as some integrity checks are bypassed. This is inline with the fact that truncate is primarily a DDL operation that was designed to quickly remove all data from a table. mysql-test/suite/innodb/t/innodb-truncate.test: Add test cases for truncate and foreign key checks. Also test that InnoDB resets auto-increment on truncate. mysql-test/suite/innodb/t/innodb.test: FK is not necessary, test is related to auto-increment. Update error number, truncate is no longer invoked if table is parent in a FK relationship. mysql-test/suite/innodb/t/innodb_mysql.test: Update error number, truncate is no longer invoked if table is parent in a FK relationship. Use delete instead of truncate, test is used to check the interaction of FKs, triggers and delete. mysql-test/suite/parts/inc/partition_check.inc: Fix typo. mysql-test/suite/sys_vars/t/foreign_key_checks_func.test: Update error number, truncate is no longer invoked if table is parent in a FK relationship. mysql-test/t/mdl_sync.test: Modify test case to reflect and ensure that truncate takes a exclusive metadata lock. mysql-test/t/trigger-trans.test: Update error number, truncate is no longer invoked if table is parent in a FK relationship. sql/ha_partition.cc: Reorganize the various truncate methods. delete_all_rows is now passed directly to the underlying engines, so as truncate. The code responsible for truncating individual partitions is moved to ha_partition::truncate_partition, which is invoked when a ALTER TABLE t1 TRUNCATE PARTITION p statement is executed. Since the partition truncate no longer can be invoked via delete, the bitmap operations are not necessary anymore. The explicit reset of the auto-increment value is also removed as the underlying engines are now responsible for reseting the value. sql/handler.cc: Wire up the handler truncate method. sql/handler.h: Introduce and document the truncate handler method. It assumes certain use cases of delete_all_rows. Add method to retrieve the list of foreign keys referencing a table. Method is used to avoid truncating tables that are parent in a foreign key relationship. sql/share/errmsg-utf8.txt: Add error message for truncate and FK. sql/sql_lex.h: Introduce a flag so that the partition engine can detect when a partition is being truncated. Used to give a special error. sql/sql_parse.cc: Function mysql_truncate_table no longer exists. sql/sql_partition_admin.cc: Implement the TRUNCATE PARTITION statement. sql/sql_truncate.cc: Change the truncate table implementation to use the new truncate handler method and to not rely on row-by-row delete anymore. The truncate handler method is always invoked with a exclusive metadata lock. Also, it is no longer possible to truncate a table that is parent in some non-self-referencing foreign key. storage/archive/ha_archive.cc: Rename method as the description indicates that in the future this could be a truncate operation. storage/blackhole/ha_blackhole.cc: Implement truncate as no operation for the blackhole engine in order to remain compatible with older releases. storage/federated/ha_federated.cc: Introduce truncate method that invokes delete_all_rows. This is required to support partition truncate as this form of truncate does not implement the drop and recreate protocol. storage/heap/ha_heap.cc: Introduce truncate method that invokes delete_all_rows. This is required to support partition truncate as this form of truncate does not implement the drop and recreate protocol. storage/ibmdb2i/ha_ibmdb2i.cc: Introduce truncate method that invokes delete_all_rows. This is required to support partition truncate as this form of truncate does not implement the drop and recreate protocol. storage/innobase/handler/ha_innodb.cc: Rename delete_all_rows to truncate. InnoDB now does truncate under a exclusive metadata lock. Introduce and reorganize methods used to retrieve the list of foreign keys referenced by a or referencing a table. storage/myisammrg/ha_myisammrg.cc: Introduce truncate method that invokes delete_all_rows. This is required in order to remain compatible with earlier releases where truncate would resort to a row-by-row delete. --- sql/sql_show.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'sql/sql_show.cc') diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 6b24e3db7bc..ba4b0ae7a0a 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -5063,8 +5063,8 @@ static int get_schema_constraints_record(THD *thd, TABLE_LIST *tables, while ((f_key_info=it++)) { if (store_constraints(thd, table, db_name, table_name, - f_key_info->forein_id->str, - strlen(f_key_info->forein_id->str), + f_key_info->foreign_id->str, + strlen(f_key_info->foreign_id->str), "FOREIGN KEY", 11)) DBUG_RETURN(1); } @@ -5263,8 +5263,8 @@ static int get_schema_key_column_usage_record(THD *thd, f_idx++; restore_record(table, s->default_values); store_key_column_usage(table, db_name, table_name, - f_key_info->forein_id->str, - f_key_info->forein_id->length, + f_key_info->foreign_id->str, + f_key_info->foreign_id->length, f_info->str, f_info->length, (longlong) f_idx); table->field[8]->store((longlong) f_idx, TRUE); @@ -6053,8 +6053,8 @@ get_referential_constraints_record(THD *thd, TABLE_LIST *tables, table->field[0]->store(STRING_WITH_LEN("def"), cs); table->field[1]->store(db_name->str, db_name->length, cs); table->field[9]->store(table_name->str, table_name->length, cs); - table->field[2]->store(f_key_info->forein_id->str, - f_key_info->forein_id->length, cs); + table->field[2]->store(f_key_info->foreign_id->str, + f_key_info->foreign_id->length, cs); table->field[3]->store(STRING_WITH_LEN("def"), cs); table->field[4]->store(f_key_info->referenced_db->str, f_key_info->referenced_db->length, cs); -- cgit v1.2.1 From 248625d910dda9848c99f28c5c73c4e4a9bfc4ae Mon Sep 17 00:00:00 2001 From: Konstantin Osipov Date: Thu, 14 Oct 2010 20:56:56 +0400 Subject: A fix and a test case for Bug#56540 "Exception (crash) in sql_show.cc during rqg_info_schema test on Windows". Ensure we do not access freed memory when filling information_schema.views when one of the views could not be properly opened. mysql-test/r/information_schema.result: Update results - a fix for Bug#56540. mysql-test/t/information_schema.test: Add a test case for Bug#56540 sql/sql_base.cc: Push an error into the Diagnostics area when we return an error. This directs get_all_tables() to the execution branch which doesn't involve 'process_table()' when no table/view was opened. sql/sql_show.cc: Do not try to access underlying table fields when opening of a view failed. The underlying table is closed in that case, and accessing its fields may lead to dereferencing a damaged pointer. --- sql/sql_show.cc | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) (limited to 'sql/sql_show.cc') diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 16deb50b17c..a25cfcdedc8 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -4934,18 +4934,29 @@ static int get_schema_views_record(THD *thd, TABLE_LIST *tables, else table->field[4]->store(STRING_WITH_LEN("NONE"), cs); - if (table->pos_in_table_list->table_open_method & - OPEN_FULL_TABLE) + /* + Only try to fill in the information about view updatability + if it is requested as part of the top-level query (i.e. + it's select * from i_s.views, as opposed to, say, select + security_type from i_s.views). Do not try to access the + underlying tables if there was an error when opening the + view: all underlying tables are released back to the table + definition cache on error inside open_normal_and_derived_tables(). + If a field is not assigned explicitly, it defaults to NULL. + */ + if (res == FALSE && + table->pos_in_table_list->table_open_method & OPEN_FULL_TABLE) { updatable_view= 0; if (tables->algorithm != VIEW_ALGORITHM_TMPTABLE) { /* - We should use tables->view->select_lex.item_list here and - can not use Field_iterator_view because the view always uses - temporary algorithm during opening for I_S and - TABLE_LIST fields 'field_translation' & 'field_translation_end' - are uninitialized is this case. + We should use tables->view->select_lex.item_list here + and can not use Field_iterator_view because the view + always uses temporary algorithm during opening for I_S + and TABLE_LIST fields 'field_translation' + & 'field_translation_end' are uninitialized is this + case. */ List *fields= &tables->view->select_lex.item_list; List_iterator it(*fields); -- cgit v1.2.1 From 1a5a109524cbd3445544888170686b023c6331b8 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Tue, 2 Nov 2010 15:20:02 +0200 Subject: Bug #51208: Extra string allocation from thd->mem_root in sql_show.cc, find_files() Removed the extra allocation. --- sql/sql_show.cc | 6 ------ 1 file changed, 6 deletions(-) (limited to 'sql/sql_show.cc') diff --git a/sql/sql_show.cc b/sql/sql_show.cc index e074461b452..9b344204d64 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -534,12 +534,6 @@ find_files(THD *thd, List *files, const char *db, else if (wild_compare(uname, wild, 0)) continue; } - if (!(file_name= - thd->make_lex_string(file_name, uname, file_name_len, TRUE))) - { - my_dirend(dirp); - DBUG_RETURN(FIND_FILES_OOM); - } } else { -- cgit v1.2.1 From c1b2d729002fa28bf29957436c0ed1926e9c45a6 Mon Sep 17 00:00:00 2001 From: Jon Olav Hauglid Date: Wed, 3 Nov 2010 16:47:32 +0100 Subject: Bug #57130 crash in Item_field::print during SHOW CREATE TABLE or VIEW This crash could happen if SHOW CREATE VIEW indirectly failed to open a view due to failures to open underlying tables (or functions). Several such errors were hidden and converted to ER_VIEW_INVALID warnings to prevent exposing details of underlying tables for which the user have no privileges. However, with the changes introduced by the patch for Bug#52044, failing to open a view will cause opened tables, views and functions to be closed. Since the errors causing these failures were converted to warnings, SHOW CREATE VIEW would try to continue. This made it possible to try to access memory that had been freed, causing a crash. This patch fixes the problem by not closing opened tables, views and functions in these cases. This allows SHOW CREATE VIEW to continue and also prevents it from accessing freed memory. Test case added to lock_sync.test. --- sql/sql_show.cc | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'sql/sql_show.cc') diff --git a/sql/sql_show.cc b/sql/sql_show.cc index be3dd8a0ca2..fa9c0e85c27 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -29,6 +29,8 @@ #include "repl_failsafe.h" #include "sql_parse.h" // check_access, check_table_access #include "sql_partition.h" // partition_element +#include "sql_derived.h" // mysql_derived_prepare, + // mysql_handle_derived, #include "sql_db.h" // check_db_dir_existence, load_db_opt_by_name #include "sql_time.h" // interval_type_to_name #include "tztime.h" // struct Time_zone @@ -683,11 +685,18 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) thd->lex->view_prepare_mode= TRUE; { + /* + Use open_tables() directly rather than open_normal_and_derived_tables(). + This ensures that close_thread_tables() is not called if open tables fails + and the error is ignored. This allows us to handle broken views nicely. + */ + uint counter; Show_create_error_handler view_error_suppressor(thd, table_list); thd->push_internal_handler(&view_error_suppressor); bool open_error= - open_normal_and_derived_tables(thd, table_list, - MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL); + open_tables(thd, &table_list, &counter, + MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL) || + mysql_handle_derived(thd->lex, &mysql_derived_prepare); thd->pop_internal_handler(); if (open_error && (thd->killed || thd->is_error())) goto exit; -- cgit v1.2.1 From 6bf6272fdabf78e62f04fbcafb1d1e7dee2b27c2 Mon Sep 17 00:00:00 2001 From: Dmitry Lenev Date: Thu, 11 Nov 2010 20:11:05 +0300 Subject: Patch that refactors global read lock implementation and fixes bug #57006 "Deadlock between HANDLER and FLUSH TABLES WITH READ LOCK" and bug #54673 "It takes too long to get readlock for 'FLUSH TABLES WITH READ LOCK'". The first bug manifested itself as a deadlock which occurred when a connection, which had some table open through HANDLER statement, tried to update some data through DML statement while another connection tried to execute FLUSH TABLES WITH READ LOCK concurrently. What happened was that FTWRL in the second connection managed to perform first step of GRL acquisition and thus blocked all upcoming DML. After that it started to wait for table open through HANDLER statement to be flushed. When the first connection tried to execute DML it has started to wait for GRL/the second connection creating deadlock. The second bug manifested itself as starvation of FLUSH TABLES WITH READ LOCK statements in cases when there was a constant stream of concurrent DML statements (in two or more connections). This has happened because requests for protection against GRL which were acquired by DML statements were ignoring presence of pending GRL and thus the latter was starved. This patch solves both these problems by re-implementing GRL using metadata locks. Similar to the old implementation acquisition of GRL in new implementation is two-step. During the first step we block all concurrent DML and DDL statements by acquiring global S metadata lock (each DML and DDL statement acquires global IX lock for its duration). During the second step we block commits by acquiring global S lock in COMMIT namespace (commit code acquires global IX lock in this namespace). Note that unlike in old implementation acquisition of protection against GRL in DML and DDL is semi-automatic. We assume that any statement which should be blocked by GRL will either open and acquires write-lock on tables or acquires metadata locks on objects it is going to modify. For any such statement global IX metadata lock is automatically acquired for its duration. The first problem is solved because waits for GRL become visible to deadlock detector in metadata locking subsystem and thus deadlocks like one in the first bug become impossible. The second problem is solved because global S locks which are used for GRL implementation are given preference over IX locks which are acquired by concurrent DML (and we can switch to fair scheduling in future if needed). Important change: FTWRL/GRL no longer blocks DML and DDL on temporary tables. Before this patch behavior was not consistent in this respect: in some cases DML/DDL statements on temporary tables were blocked while in others they were not. Since the main use cases for FTWRL are various forms of backups and temporary tables are not preserved during backups we have opted for consistently allowing DML/DDL on temporary tables during FTWRL/GRL. Important change: This patch changes thread state names which are used when DML/DDL of FTWRL is waiting for global read lock. It is now either "Waiting for global read lock" or "Waiting for commit lock" depending on the stage on which FTWRL is. Incompatible change: To solve deadlock in events code which was exposed by this patch we have to replace LOCK_event_metadata mutex with metadata locks on events. As result we have to prohibit DDL on events under LOCK TABLES. This patch also adds extensive test coverage for interaction of DML/DDL and FTWRL. Performance of new and old global read lock implementations in sysbench tests were compared. There were no significant difference between new and old implementations. mysql-test/include/check_ftwrl_compatible.inc: Added helper script which allows to check that a statement is compatible with FLUSH TABLES WITH READ LOCK. mysql-test/include/check_ftwrl_incompatible.inc: Added helper script which allows to check that a statement is incompatible with FLUSH TABLES WITH READ LOCK. mysql-test/include/handler.inc: Adjusted test case to the fact that now DROP TABLE closes open HANDLERs for the table to be dropped before checking if there active FTWRL in this connection. mysql-test/include/wait_show_condition.inc: Fixed small error in the timeout message. The correct name of variable used as parameter for this script is "$condition" and not "$wait_condition". mysql-test/r/delayed.result: Added test coverage for scenario which triggered assert in metadata locking subsystem. mysql-test/r/events_2.result: Updated test results after prohibiting event DDL operations under LOCK TABLES. mysql-test/r/flush.result: Added test coverage for bug #57006 "Deadlock between HANDLER and FLUSH TABLES WITH READ LOCK". mysql-test/r/flush_read_lock.result: Added test coverage for various aspects of FLUSH TABLES WITH READ LOCK functionality. mysql-test/r/flush_read_lock_kill.result: Adjusted test case after replacing custom global read lock implementation with one based on metadata locks. Use new debug_sync point. Do not disable concurrent inserts as now InnoDB we always use InnoDB table. mysql-test/r/handler_innodb.result: Adjusted test case to the fact that now DROP TABLE closes open HANDLERs for the table to be dropped before checking if there active FTWRL in this connection. mysql-test/r/handler_myisam.result: Adjusted test case to the fact that now DROP TABLE closes open HANDLERs for the table to be dropped before checking if there active FTWRL in this connection. mysql-test/r/mdl_sync.result: Adjusted test case after replacing custom global read lock implementation with one based on metadata locks. Replaced usage of GRL-specific debug_sync's with appropriate sync points in MDL subsystem. mysql-test/suite/perfschema/r/dml_setup_instruments.result: Updated test results after removing global COND_global_read_lock condition variable. mysql-test/suite/perfschema/r/func_file_io.result: Ensure that this test doesn't affect subsequent tests. At the end of its execution enable back P_S instrumentation which this test disables at some point. mysql-test/suite/perfschema/r/func_mutex.result: Ensure that this test doesn't affect subsequent tests. At the end of its execution enable back P_S instrumentation which this test disables at some point. mysql-test/suite/perfschema/r/global_read_lock.result: Adjusted test case to take into account that new GRL implementation is based on MDL. mysql-test/suite/perfschema/r/server_init.result: Adjusted test case after replacing custom global read lock implementation with one based on MDL and replacing LOCK_event_metadata mutex with metadata lock. mysql-test/suite/perfschema/t/func_file_io.test: Ensure that this test doesn't affect subsequent tests. At the end of its execution enable back P_S instrumentation which this test disables at some point. mysql-test/suite/perfschema/t/func_mutex.test: Ensure that this test doesn't affect subsequent tests. At the end of its execution enable back P_S instrumentation which this test disables at some point. mysql-test/suite/perfschema/t/global_read_lock.test: Adjusted test case to take into account that new GRL implementation is based on MDL. mysql-test/suite/perfschema/t/server_init.test: Adjusted test case after replacing custom global read lock implementation with one based on MDL and replacing LOCK_event_metadata mutex with metadata lock. mysql-test/suite/rpl/r/rpl_tmp_table_and_DDL.result: Updated test results after prohibiting event DDL under LOCK TABLES. mysql-test/t/delayed.test: Added test coverage for scenario which triggered assert in metadata locking subsystem. mysql-test/t/events_2.test: Updated test case after prohibiting event DDL operations under LOCK TABLES. mysql-test/t/flush.test: Added test coverage for bug #57006 "Deadlock between HANDLER and FLUSH TABLES WITH READ LOCK". mysql-test/t/flush_block_commit.test: Adjusted test case after changing thread state name which is used when COMMIT waits for FLUSH TABLES WITH READ LOCK from "Waiting for release of readlock" to "Waiting for commit lock". mysql-test/t/flush_block_commit_notembedded.test: Adjusted test case after changing thread state name which is used when DML waits for FLUSH TABLES WITH READ LOCK. Now we use "Waiting for global read lock" in this case. mysql-test/t/flush_read_lock.test: Added test coverage for various aspects of FLUSH TABLES WITH READ LOCK functionality. mysql-test/t/flush_read_lock_kill-master.opt: We no longer need to use make_global_read_lock_block_commit_loop debug tag in this test. Instead we rely on an appropriate debug_sync point in MDL code. mysql-test/t/flush_read_lock_kill.test: Adjusted test case after replacing custom global read lock implementation with one based on metadata locks. Use new debug_sync point. Do not disable concurrent inserts as now InnoDB we always use InnoDB table. mysql-test/t/lock_multi.test: Adjusted test case after changing thread state names which are used when DML or DDL waits for FLUSH TABLES WITH READ LOCK to "Waiting for global read lock". mysql-test/t/mdl_sync.test: Adjusted test case after replacing custom global read lock implementation with one based on metadata locks. Replaced usage of GRL-specific debug_sync's with appropriate sync points in MDL subsystem. Updated thread state names which are used when DDL waits for FTWRL. mysql-test/t/trigger_notembedded.test: Adjusted test case after changing thread state names which are used when DML or DDL waits for FLUSH TABLES WITH READ LOCK to "Waiting for global read lock". sql/event_data_objects.cc: Removed Event_queue_element::status/last_executed_changed members and Event_queue_element::update_timing_fields() method. We no longer use this class for updating mysql.events once event is chosen for execution. Accesses to instances of this class in scheduler thread require protection by Event_queue::LOCK_event_queue mutex and we try to avoid updating table while holding this lock. sql/event_data_objects.h: Removed Event_queue_element::status/last_executed_changed members and Event_queue_element::update_timing_fields() method. We no longer use this class for updating mysql.events once event is chosen for execution. Accesses to instances of this class in scheduler thread require protection by Event_queue::LOCK_event_queue mutex and we try to avoid updating table while holding this lock. sql/event_db_repository.cc: - Changed Event_db_repository methods to not release all metadata locks once they are done updating mysql.events table. This allows to keep metadata lock protecting against GRL and lock protecting particular event around until corresponding DDL statement is written to the binary log. - Removed logic for conditional update of "status" and "last_executed" fields from update_timing_fields_for_event() method. In the only case when this method is called now "last_executed" is always modified and tracking change of "status" is too much hassle. sql/event_db_repository.h: Removed logic for conditional update of "status" and "last_executed" fields from Event_db_repository:: update_timing_fields_for_event() method. In the only case when this method is called now "last_executed" is always modified and tracking change of "status" field is too much hassle. sql/event_queue.cc: Changed event scheduler code not to update mysql.events table while holding Event_queue::LOCK_event_queue mutex. Doing so led to a deadlock with a new GRL implementation. This deadlock didn't occur with old implementation due to fact that code acquiring protection against GRL ignored pending GRL requests (which lead to GRL starvation). One of goals of new implementation is to disallow GRL starvation and so we have to solve problem with this deadlock in a different way. sql/events.cc: Changed methods of Events class to acquire protection against GRL while perfoming DDL statement and keep it until statement is written to the binary log. Unfortunately this step together with new GRL implementation exposed deadlock involving Events::LOCK_event_metadata and GRL. To solve it Events::LOCK_event_metadata mutex was replaced with a metadata lock on event. As a side-effect events DDL has to be prohibited under LOCK TABLES even in cases when mysql.events table was explicitly locked for write. sql/events.h: Replaced Events::LOCK_event_metadata mutex with a metadata lock on event. sql/ha_ndbcluster.cc: Updated code after replacing custom global read lock implementation with one based on MDL. Since MDL subsystem should now be able to detect deadlocks involving metadata locks and GRL there is no need for special handling of active GRL. sql/handler.cc: Replaced custom implementation of global read lock with one based on metadata locks. Consequently when doing commit instead of calling method of Global_read_lock class to acquire protection against GRL we simply acquire IX in COMMIT namespace. sql/lock.cc: Replaced custom implementation of global read lock with one based on metadata locks. This step allows to expose wait for GRL to deadlock detector of MDL subsystem and thus succesfully resolve deadlocks similar to one behind bug #57006 "Deadlock between HANDLER and FLUSH TABLES WITH READ LOCK". It also solves problem with GRL starvation described in bug #54673 "It takes too long to get readlock for 'FLUSH TABLES WITH READ LOCK'" since metadata locks used by GRL give preference to FTWRL statement instead of DML statements (if needed in future this can be changed to fair scheduling). Similar to old implementation of acquisition of GRL is two-step. During the first step we block all concurrent DML and DDL statements by acquiring global S metadata lock (each DML and DDL statement acquires global IX lock for its duration). During the second step we block commits by acquiring global S lock in COMMIT namespace (commit code acquires global IX lock in this namespace). Note that unlike in old implementation acquisition of protection against GRL in DML and DDL is semi-automatic. We assume that any statement which should be blocked by GRL will either open and acquires write-lock on tables or acquires metadata locks on objects it is going to modify. For any such statement global IX metadata lock is automatically acquired for its duration. To support this change: - Global_read_lock::lock/unlock_global_read_lock and make_global_read_lock_block_commit methods were changed accordingly. - Global_read_lock::wait_if_global_read_lock() and start_waiting_global_read_lock() methods were dropped. It is now responsibility of code acquiring metadata locks opening tables to acquire protection against GRL by explicitly taking global IX lock with statement duration. - Global variables, mutex and condition variable used by old implementation was removed. - lock_routine_name() was changed to use statement duration for its global IX lock. It was also renamed to lock_object_name() as it now also used to take metadata locks on events. - Global_read_lock::set_explicit_lock_duration() was added which allows not to release locks used for GRL when leaving prelocked mode. sql/lock.h: - Renamed lock_routine_name() to lock_object_name() and changed its signature to allow its usage for events. - Removed broadcast_refresh() function. It is no longer needed with new GRL implementation. sql/log_event.cc: Release metadata locks with statement duration at the end of processing legacy event for LOAD DATA. This ensures that replication thread processing such event properly releases its protection against global read lock. sql/mdl.cc: Changed MDL subsystem to support new MDL-based implementation of global read lock. Added COMMIT and EVENTS namespaces for metadata locks. Changed thread state name for GLOBAL namespace to "Waiting for global read lock". Optimized MDL_map::find_or_insert() method to avoid taking m_mutex mutex when looking up MDL_lock objects for GLOBAL or COMMIT namespaces. We keep pre-created MDL_lock objects for these namespaces around and simply return pointers to these global objects when needed. Changed MDL_lock/MDL_scoped_lock to properly handle notification of insert delayed handler threads when FTWRL takes global S lock. Introduced concept of lock duration. In addition to locks with transaction duration which work in the way which is similar to how locks worked before (i.e. they are released at the end of transaction), locks with statement and explicit duration were introduced. Locks with statement duration are automatically released at the end of statement. Locks with explicit duration require explicit release and obsolete concept of transactional sentinel. * Changed MDL_request and MDL_ticket classes to support notion of duration. * Changed MDL_context to keep locks with different duration in different lists. Changed code handling ticket list to take this into account. * Changed methods responsible for releasing locks to take into account duration of tickets. Particularly public MDL_context::release_lock() method now only can release tickets with explicit duration (there is still internal method which allows to specify duration). To release locks with statement or transaction duration one have to use release_statement/transactional_locks() methods. * Concept of savepoint for MDL subsystem now has to take into account locks with statement duration. Consequently MDL_savepoint class was introduced and methods working with savepoints were updated accordingly. * Added methods which allow to set duration for one or all locks in the context. sql/mdl.h: Changed MDL subsystem to support new MDL-based implementation of global read lock. Added COMMIT and EVENTS namespaces for metadata locks. Introduced concept of lock duration. In addition to locks with transaction duration which work in the way which is similar to how locks worked before (i.e. they are released at the end of transaction), locks with statement and explicit duration were introduced. Locks with statement duration are automatically released at the end of statement. Locks with explicit duration require explicit release and obsolete concept of transactional sentinel. * Changed MDL_request and MDL_ticket classes to support notion of duration. * Changed MDL_context to keep locks with different duration in different lists. Changed code handling ticket list to take this into account. * Changed methods responsible for releasing locks to take into account duration of tickets. Particularly public MDL_context::release_lock() method now only can release tickets with explicit duration (there is still internal method which allows to specify duration). To release locks with statement or transaction duration one have to use release_statement/transactional_locks() methods. * Concept of savepoint for MDL subsystem now has to take into account locks with statement duration. Consequently MDL_savepoint class was introduced and methods working with savepoints were updated accordingly. * Added methods which allow to set duration for one or all locks in the context. sql/mysqld.cc: Removed global mutex and condition variables which were used by old implementation of GRL. Also we no longer need to initialize Events::LOCK_event_metadata mutex as it was replaced with metadata locks on events. sql/mysqld.h: Removed global variable, mutex and condition variables which were used by old implementation of GRL. sql/rpl_rli.cc: When slave thread closes tables which were open for handling of RBR events ensure that it releases global IX lock which was acquired as protection against GRL. sql/sp.cc: Adjusted code to the new signature of lock_object/routine_name(), to the fact that one now needs specify duration of lock when initializing MDL_request and to the fact that savepoints for MDL subsystem are now represented by MDL_savepoint class. sql/sp_head.cc: Ensure that statements in stored procedures release statement metadata locks and thus release their protectiong against GRL in proper moment in time. Adjusted code to the fact that one now needs specify duration of lock when initializing MDL_request. sql/sql_admin.cc: Adjusted code to the fact that one now needs specify duration of lock when initializing MDL_request. sql/sql_base.cc: - Implemented support for new approach to acquiring protection against global read lock. We no longer acquire such protection explicitly on the basis of statement flags. Instead we always rely on code which is responsible for acquiring metadata locks on object to be changed acquiring this protection. This is achieved by acquiring global IX metadata lock with statement duration. Code doing this also responsible for checking that current connection has no active GRL by calling an Global_read_lock::can_acquire_protection() method. Changed code in open_table() and lock_table_names() accordingly. Note that as result of this change DDL and DML on temporary tables is always compatible with GRL (before it was incompatible in some cases and compatible in other cases). - To speed-up code acquiring protection against GRL introduced m_has_protection_against_grl member in Open_table_context class. It indicates that protection was already acquired sometime during open_tables() execution and new attempts can be skipped. - Thanks to new GRL implementation calls to broadcast_refresh() became unnecessary and were removed. - Adjusted code to the fact that one now needs specify duration of lock when initializing MDL_request and to the fact that savepoints for MDL subsystem are now represented by MDL_savepoint class. sql/sql_base.h: Adjusted code to the fact that savepoints for MDL subsystem are now represented by MDL_savepoint class. Also introduced Open_table_context::m_has_protection_against_grl member which allows to avoid acquiring protection against GRL while opening tables if such protection was already acquired. sql/sql_class.cc: Changed THD::leave_locked_tables_mode() after transactional sentinel for metadata locks was obsoleted by introduction of locks with explicit duration. sql/sql_class.h: - Adjusted code to the fact that savepoints for MDL subsystem are now represented by MDL_savepoint class. - Changed Global_read_lock class according to changes in global read lock implementation: * wait_if_global_read_lock and start_waiting_global_read_lock are now gone. Instead code needing protection against GRL has to acquire global IX metadata lock with statement duration itself. To help it new can_acquire_protection() was introduced. Also as result of the above change m_protection_count member is gone too. * Added m_mdl_blocks_commits_lock member to store metadata lock blocking commits. * Adjusted code to the fact that concept of transactional sentinel was obsoleted by concept of lock duration. - Removed CF_PROTECT_AGAINST_GRL flag as it is no longer necessary. New GRL implementation acquires protection against global read lock automagically when statement acquires metadata locks on tables or other objects it is going to change. sql/sql_db.cc: Adjusted code to the fact that one now needs specify duration of lock when initializing MDL_request. sql/sql_handler.cc: Removed call to broadcast_refresh() function. It is no longer needed with new GRL implementation. Adjusted code after introducing duration concept for metadata locks. Particularly to the fact transactional sentinel was replaced with explicit duration. sql/sql_handler.h: Renamed mysql_ha_move_tickets_after_trans_sentinel() to mysql_ha_set_explicit_lock_duration() after transactional sentinel was obsoleted by locks with explicit duration. sql/sql_insert.cc: Adjusted code handling delaying inserts after switching to new GRL implementation. Now connection thread initiating delayed insert has to acquire global IX lock in addition to metadata lock on table being inserted into. This IX lock protects against GRL and similarly to SW lock on table being inserted into has to be passed to handler thread in order to avoid deadlocks. sql/sql_lex.cc: LEX::protect_against_global_read_lock member is no longer necessary since protection against GRL is automatically taken by code acquiring metadata locks/opening tables. sql/sql_lex.h: LEX::protect_against_global_read_lock member is no longer necessary since protection against GRL is automatically taken by code acquiring metadata locks/opening tables. sql/sql_parse.cc: - Implemented support for new approach to acquiring protection against global read lock. We no longer acquire such protection explicitly on the basis of statement flags. Instead we always rely on code which is responsible for acquiring metadata locks on object to be changed acquiring this protection. This is achieved by acquiring global IX metadata lock with statement duration. This lock is automatically released at the end of statement execution. - Changed implementation of CREATE/DROP PROCEDURE/FUNCTION not to release metadata locks and thus protection against of GRL in the middle of statement execution. - Adjusted code to the fact that one now needs specify duration of lock when initializing MDL_request and to the fact that savepoints for MDL subsystem are now represented by MDL_savepoint class. sql/sql_prepare.cc: Adjusted code to the to the fact that savepoints for MDL subsystem are now represented by MDL_savepoint class. sql/sql_rename.cc: With new GRL implementation there is no need to explicitly acquire protection against GRL before renaming tables. This happens automatically in code which acquires metadata locks on tables being renamed. sql/sql_show.cc: Adjusted code to the fact that one now needs specify duration of lock when initializing MDL_request and to the fact that savepoints for MDL subsystem are now represented by MDL_savepoint class. sql/sql_table.cc: - With new GRL implementation there is no need to explicitly acquire protection against GRL before dropping tables. This happens automatically in code which acquires metadata locks on tables being dropped. - Changed mysql_alter_table() not to release lock on new table name explicitly and to rely on automatic release of locks at the end of statement instead. This was necessary since now MDL_context::release_lock() is supported only for locks for explicit duration. sql/sql_trigger.cc: With new GRL implementation there is no need to explicitly acquire protection against GRL before changing table triggers. This happens automatically in code which acquires metadata locks on tables which triggers are to be changed. sql/sql_update.cc: Fix bug exposed by GRL testing. During prepare phase acquire only S metadata locks instead of SW locks to keep prepare of multi-UPDATE compatible with concurrent LOCK TABLES WRITE and global read lock. sql/sql_view.cc: With new GRL implementation there is no need to explicitly acquire protection against GRL before creating view. This happens automatically in code which acquires metadata lock on view to be created. sql/sql_yacc.yy: LEX::protect_against_global_read_lock member is no longer necessary since protection against GRL is automatically taken by code acquiring metadata locks/opening tables. sql/table.cc: Adjusted code to the fact that one now needs specify duration of lock when initializing MDL_request. sql/table.h: Adjusted code to the fact that one now needs specify duration of lock when initializing MDL_request. sql/transaction.cc: Replaced custom implementation of global read lock with one based on metadata locks. Consequently when doing commit instead of calling method of Global_read_lock class to acquire protection against GRL we simply acquire IX in COMMIT namespace. Also adjusted code to the fact that MDL savepoint is now represented by MDL_savepoint class. --- sql/sql_show.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sql/sql_show.cc') diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 19a73c85a9b..b8c66562b1a 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -671,7 +671,7 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) Metadata locks taken during SHOW CREATE should be released when the statmement completes as it is an information statement. */ - MDL_ticket *mdl_savepoint= thd->mdl_context.mdl_savepoint(); + MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint(); /* We want to preserve the tree for views. */ thd->lex->view_prepare_mode= TRUE; @@ -3186,7 +3186,7 @@ try_acquire_high_prio_shared_mdl_lock(THD *thd, TABLE_LIST *table, { bool error; table->mdl_request.init(MDL_key::TABLE, table->db, table->table_name, - MDL_SHARED_HIGH_PRIO); + MDL_SHARED_HIGH_PRIO, MDL_TRANSACTION); if (can_deadlock) { @@ -7745,7 +7745,7 @@ bool show_create_trigger(THD *thd, const sp_name *trg_name) Metadata locks taken during SHOW CREATE TRIGGER should be released when the statement completes as it is an information statement. */ - MDL_ticket *mdl_savepoint= thd->mdl_context.mdl_savepoint(); + MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint(); /* Open the table by name in order to load Table_triggers_list object. -- cgit v1.2.1 From 185e189da36bb0f5c71c2766fd1aff771a8d96a3 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Thu, 18 Nov 2010 17:08:32 +0300 Subject: Bug#57306 SHOW PROCESSLIST does not display string literals well. Problem: Extended characters outside of ASCII range where not displayed properly in SHOW PROCESSLIST, because thd_info->query was always sent as system_character_set (utf8). This was wrong, because query buffer is never converted to utf8 - it is always have client character set. Fix: sending query buffer using query character set @ sql/sql_class.cc @ sql/sql_class.h Introducing a new class CSET_STRING, a LEX_STRING with character set. Adding set_query(&CSET_STRING) Adding reset_query(), to use instead of set_query(0, NULL). @ sql/event_data_objects.cc Using reset_query() @ sql/log_event.cc Using reset_query() Adding charset argument to set_query_and_id(). @ sql/slave.cc Using reset_query(). @ sql/sp_head.cc Changing backing up and restore code to use CSET_STRING. @ sql/sql_audit.h Using CSET_STRING. In the "else" branch it's OK not to use global_system_variables.character_set_client. &my_charset_latin1, which is set in constructor, is fine (verified with Sergey Vojtovich). @ sql/sql_insert.cc Using set_query() with proper character set: table_name is utf8. @ sql/sql_parse.cc Adding character set argument to set_query_and_id(). (This is the main point where thd->charset() is stored into thd->query_string.cs, for use in "SHOW PROCESSLIST".) Using reset_query(). @ sql/sql_prepare.cc Storing client character set into thd->query_string.cs. @ sql/sql_show.cc Using CSET_STRING to fetch and send charset-aware query information from threads. @ storage/myisam/ha_myisam.cc Using set_query() with proper character set: table_name is utf8. @ mysql-test/r/show_check.result @ mysql-test/t/show_check.test Adding tests --- sql/sql_show.cc | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'sql/sql_show.cc') diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 19a73c85a9b..6283deed331 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1727,7 +1727,7 @@ public: time_t start_time; uint command; const char *user,*host,*db,*proc_info,*state_info; - char *query; + CSET_STRING query_string; }; #ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION @@ -1824,12 +1824,14 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose) if (mysys_var) mysql_mutex_unlock(&mysys_var->mutex); - thd_info->query=0; /* Lock THD mutex that protects its data when looking at it. */ if (tmp->query()) { uint length= min(max_query_length, tmp->query_length()); - thd_info->query= (char*) thd->strmake(tmp->query(),length); + char *q= thd->strmake(tmp->query(),length); + /* Safety: in case strmake failed, we set length to 0. */ + thd_info->query_string= + CSET_STRING(q, q ? length : 0, tmp->query_charset()); } mysql_mutex_unlock(&tmp->LOCK_thd_data); thd_info->start_time= tmp->start_time; @@ -1857,7 +1859,8 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose) else protocol->store_null(); protocol->store(thd_info->state_info, system_charset_info); - protocol->store(thd_info->query, system_charset_info); + protocol->store(thd_info->query_string.str(), + thd_info->query_string.charset()); if (protocol->write()) break; /* purecov: inspected */ } -- cgit v1.2.1 From 2d1d7b1323df809313016f03c36ec52807b64e6c Mon Sep 17 00:00:00 2001 From: Davi Arnaut Date: Mon, 22 Nov 2010 14:10:44 -0200 Subject: Assorted fixes for test failures. mysql-test/suite/sys_vars/t/shared_memory_base_name_basic.test: The server shared memory name is located in the server's temporary directory, not in the mysqltest one. sql/sql_show.cc: */ ends a comment, add space to avoid problems. --- sql/sql_show.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'sql/sql_show.cc') diff --git a/sql/sql_show.cc b/sql/sql_show.cc index ec147a99553..f8853611b39 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -596,11 +596,11 @@ public: return m_view_access_denied_message_ptr; } - bool handle_condition(THD *thd, uint sql_errno, const char */* sqlstate */, + bool handle_condition(THD *thd, uint sql_errno, const char * /* sqlstate */, MYSQL_ERROR::enum_warning_level level, - const char *message, MYSQL_ERROR **/* cond_hdl */) + const char *message, MYSQL_ERROR ** /* cond_hdl */) { - /* + /* The handler does not handle the errors raised by itself. At this point we know if top_view is really a view. */ @@ -610,7 +610,7 @@ public: m_handling= TRUE; bool is_handled; - + switch (sql_errno) { case ER_TABLEACCESS_DENIED_ERROR: -- cgit v1.2.1 From 4edea18f8daa9b1c1e5614560753a03cfdcb1adb Mon Sep 17 00:00:00 2001 From: Christopher Powers Date: Mon, 29 Nov 2010 22:46:43 -0600 Subject: Bug#35333, "If Federated table can't connect to remote host, can't retrieve metadata" Improved error handling such that queries against Information_Schema.Tables won't fail if a federated table can't make a remote connection. mysql-test/r/merge.result: Updated with warnings that were previously masked. mysql-test/r/show_check.result: Updated with warnings that were previously masked. mysql-test/r/view.result: Updated with warnings that were previously masked. sql/sql_show.cc: If get_schema_tables_record() encounters an error, push a warning, set the TABLE COMMENT column with the error text, and clear the error so that the operation can continue. --- sql/sql_show.cc | 43 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 9 deletions(-) (limited to 'sql/sql_show.cc') diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 9b344204d64..ee0e2bf5ce7 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -3636,28 +3636,28 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables, { const char *tmp_buff; MYSQL_TIME time; + int info_error= 0; CHARSET_INFO *cs= system_charset_info; DBUG_ENTER("get_schema_tables_record"); restore_record(table, s->default_values); table->field[1]->store(db_name->str, db_name->length, cs); table->field[2]->store(table_name->str, table_name->length, cs); + if (res) { - /* - there was errors during opening tables - */ - const char *error= thd->is_error() ? thd->main_da.message() : ""; + /* There was a table open error, so set the table type and return */ if (tables->view) table->field[3]->store(STRING_WITH_LEN("VIEW"), cs); else if (tables->schema_table) table->field[3]->store(STRING_WITH_LEN("SYSTEM VIEW"), cs); else table->field[3]->store(STRING_WITH_LEN("BASE TABLE"), cs); - table->field[20]->store(error, strlen(error), cs); - thd->clear_error(); + + goto err; } - else if (tables->view) + + if (tables->view) { table->field[3]->store(STRING_WITH_LEN("VIEW"), cs); table->field[20]->store(STRING_WITH_LEN("VIEW"), cs); @@ -3746,9 +3746,14 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables, if (share->comment.str) table->field[20]->store(share->comment.str, share->comment.length, cs); - if(file) + if (file) { - file->info(HA_STATUS_VARIABLE | HA_STATUS_TIME | HA_STATUS_AUTO); + /* If info() fails, then there's nothing else to do */ + if ((info_error= file->info(HA_STATUS_VARIABLE | + HA_STATUS_TIME | + HA_STATUS_AUTO)) != 0) + goto err; + enum row_type row_type = file->get_row_type(); switch (row_type) { case ROW_TYPE_NOT_USED: @@ -3826,6 +3831,26 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables, } } } + +err: + if (res || info_error) + { + /* + If an error was encountered, push a warning, set the TABLE COMMENT + column with the error text, and clear the error so that the operation + can continue. + */ + const char *error= thd->is_error() ? thd->main_da.message() : ""; + table->field[20]->store(error, strlen(error), cs); + + if (thd->is_error()) + { + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + thd->main_da.sql_errno(), thd->main_da.message()); + thd->clear_error(); + } + } + DBUG_RETURN(schema_table_store_record(thd, table)); } -- cgit v1.2.1 From e199c7cd17e9d37befd67f907f66e7f235c71d6d Mon Sep 17 00:00:00 2001 From: Christopher Powers Date: Mon, 29 Nov 2010 18:51:46 -0600 Subject: Bug#35333, "If Federated table can't connect to remote host, can't retrieve metadata" Improved error handling such that queries against Information_Schema.Tables won't fail if a Federated table is unable to connect to remote host. sql/sql_show.cc: If Handler::Info() fails, save error text in TABLE COMMENTS column, clear error. --- sql/sql_show.cc | 200 ++++++++++++++++++++++++++++++++------------------------ 1 file changed, 113 insertions(+), 87 deletions(-) (limited to 'sql/sql_show.cc') diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 13045280c5f..1075e7f76d1 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -48,7 +48,7 @@ bool schema_table_store_record(THD *thd, TABLE *table); /*************************************************************************** -** List all table types supported +** List all table types supported ***************************************************************************/ bool mysqld_show_storage_engines(THD *thd) @@ -65,7 +65,7 @@ bool mysqld_show_storage_engines(THD *thd) Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) DBUG_RETURN(TRUE); - const char *default_type_name= + const char *default_type_name= ha_get_storage_engine((enum db_type)thd->variables.table_type); handlerton **types; @@ -406,7 +406,7 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) /* Clear all messages with 'error' level status and - issue a warning with 'warning' level status in + issue a warning with 'warning' level status in case of invalid view and last error is ER_VIEW_INVALID */ mysql_reset_errors(thd, true); @@ -603,7 +603,7 @@ mysqld_list_fields(THD *thd, TABLE_LIST *table_list, const char *wild) Field **ptr,*field; for (ptr=table->field ; (field= *ptr); ptr++) { - if (!wild || !wild[0] || + if (!wild || !wild[0] || !wild_case_compare(system_charset_info, field->field_name,wild)) { if (table_list->view) @@ -809,13 +809,13 @@ static bool get_field_default_value(THD *thd, TABLE *table, bool has_default; bool has_now_default; enum enum_field_types field_type= field->type(); - /* + /* We are using CURRENT_TIMESTAMP instead of NOW because it is more standard */ - has_now_default= table->timestamp_field == field && + has_now_default= table->timestamp_field == field && field->unireg_check != Field::TIMESTAMP_UN_FIELD; - + has_default= (field_type != FIELD_TYPE_BLOB && !(field->flags & NO_DEFAULT_VALUE_FLAG) && field->unireg_check != Field::NEXT_NUMBER && @@ -837,7 +837,7 @@ static bool get_field_default_value(THD *thd, TABLE *table, char *ptr= longlong2str(dec, tmp + 2, 2); uint32 length= (uint32) (ptr - tmp); tmp[0]= 'b'; - tmp[1]= '\''; + tmp[1]= '\''; tmp[length]= '\''; type.length(length + 1); quoted= 0; @@ -929,7 +929,7 @@ store_create_info(THD *thd, TABLE_LIST *table_list, String *packet) field->sql_type(type); packet->append(type.ptr(), type.length(), system_charset_info); - if (field->has_charset() && + if (field->has_charset() && !(thd->variables.sql_mode & (MODE_MYSQL323 | MODE_MYSQL40))) { if (field->charset() != share->table_charset) @@ -937,8 +937,8 @@ store_create_info(THD *thd, TABLE_LIST *table_list, String *packet) packet->append(STRING_WITH_LEN(" character set ")); packet->append(field->charset()->csname); } - /* - For string types dump collation name only if + /* + For string types dump collation name only if collation is not primary for the given charset */ if (!(field->charset()->state & MY_CS_PRIMARY)) @@ -965,11 +965,11 @@ store_create_info(THD *thd, TABLE_LIST *table_list, String *packet) packet->append(def_value.ptr(), def_value.length(), system_charset_info); } - if (!limited_mysql_mode && table->timestamp_field == field && + if (!limited_mysql_mode && table->timestamp_field == field && field->unireg_check != Field::TIMESTAMP_DN_FIELD) packet->append(STRING_WITH_LEN(" on update CURRENT_TIMESTAMP")); - if (field->unireg_check == Field::NEXT_NUMBER && + if (field->unireg_check == Field::NEXT_NUMBER && !(thd->variables.sql_mode & MODE_NO_FIELD_OPTIONS)) packet->append(STRING_WITH_LEN(" auto_increment")); @@ -1088,7 +1088,7 @@ store_create_info(THD *thd, TABLE_LIST *table_list, String *packet) packet->append(buff, (uint) (end - buff)); } - + if (share->table_charset && !(thd->variables.sql_mode & MODE_MYSQL323) && !(thd->variables.sql_mode & MODE_MYSQL40)) @@ -1179,7 +1179,7 @@ view_store_options(THD *thd, TABLE_LIST *table, String *buff) /* Append DEFINER clause to the given buffer. - + SYNOPSIS append_definer() thd [in] thread handle @@ -1209,7 +1209,7 @@ static void append_algorithm(TABLE_LIST *table, String *buff) /* Append DEFINER clause to the given buffer. - + SYNOPSIS append_definer() thd [in] thread handle @@ -1374,8 +1374,8 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose) "%s:%u", tmp_sctx->host_or_ip, tmp->peer_port); } else - thd_info->host= thd->strdup(tmp_sctx->host_or_ip[0] ? - tmp_sctx->host_or_ip : + thd_info->host= thd->strdup(tmp_sctx->host_or_ip[0] ? + tmp_sctx->host_or_ip : tmp_sctx->host ? tmp_sctx->host : ""); if ((thd_info->db=tmp->db)) // Safe test thd_info->db=thd->strdup(thd_info->db); @@ -1852,14 +1852,14 @@ void calc_sum_of_all_status(STATUS_VAR *to) I_List_iterator it(threads); THD *tmp; - + /* Get global values as base */ *to= global_status_var; - + /* Add to this status from existing threads */ while ((tmp= it++)) add_to_status(to, &tmp->status_var); - + VOID(pthread_mutex_unlock(&LOCK_thread_count)); DBUG_VOID_RETURN; } @@ -1911,7 +1911,7 @@ bool schema_table_store_record(THD *thd, TABLE *table) int error; if ((error= table->file->write_row(table->record[0]))) { - if (create_myisam_from_heap(thd, table, + if (create_myisam_from_heap(thd, table, table->pos_in_table_list->schema_table_param, error, 0)) return 1; @@ -1946,7 +1946,7 @@ int make_table_list(THD *thd, SELECT_LEX *sel, { Table_ident *table_ident; LEX_STRING ident_db, ident_table; - ident_db.str= db; + ident_db.str= db; ident_db.length= (uint) strlen(db); ident_table.str= table; ident_table.length= (uint) strlen(table); @@ -1980,10 +1980,10 @@ bool uses_only_table_name_fields(Item *item, TABLE_LIST *table) const char *field_name2= schema_table->idx_field2 >= 0 ? field_info[schema_table->idx_field2].field_name : ""; if (table->table != item_field->field->table || (cs->coll->strnncollsp(cs, (uchar *) field_name1, (uint) strlen(field_name1), - (uchar *) item_field->field_name, + (uchar *) item_field->field_name, (uint) strlen(item_field->field_name), 0) && cs->coll->strnncollsp(cs, (uchar *) field_name2, (uint) strlen(field_name2), - (uchar *) item_field->field_name, + (uchar *) item_field->field_name, (uint) strlen(item_field->field_name), 0))) return 0; } @@ -2072,7 +2072,7 @@ enum enum_schema_tables get_schema_table_idx(ST_SCHEMA_TABLE *schema_table) with_i_schema returns 1 if we added 'IS' name to list otherwise returns 0 is_wild_value if value is 1 then idx_field_vals->db_name is - wild string otherwise it's db name; + wild string otherwise it's db name; RETURN zero success @@ -2094,7 +2094,7 @@ int make_db_list(THD *thd, List *files, LIKE clause (see also get_index_field_values() function) */ if (!idx_field_vals->db_value || - !wild_case_compare(system_charset_info, + !wild_case_compare(system_charset_info, INFORMATION_SCHEMA_NAME.str, idx_field_vals->db_value)) { @@ -2179,7 +2179,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) List bases; List_iterator_fast it(bases); COND *partial_cond; - uint derived_tables= lex->derived_tables; + uint derived_tables= lex->derived_tables; int error= 1; db_type not_used; Open_tables_state open_tables_state_backup; @@ -2217,7 +2217,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) Let us set fake sql_command so views won't try to merge themselves into main statement. If we don't do this, SELECT * from information_schema.xxxx will cause problems. - SQLCOM_SHOW_FIELDS is used because it satisfies 'only_view_structure()' + SQLCOM_SHOW_FIELDS is used because it satisfies 'only_view_structure()' */ lex->sql_command= SQLCOM_SHOW_FIELDS; res= open_normal_and_derived_tables(thd, show_table_list, @@ -2227,15 +2227,15 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) get_all_tables() returns 1 on failure and 0 on success thus return only these and not the result code of ::process_table() - We should use show_table_list->alias instead of + We should use show_table_list->alias instead of show_table_list->table_name because table_name could be changed during opening of I_S tables. It's safe - to use alias because alias contains original table name - in this case(this part of code is used only for + to use alias because alias contains original table name + in this case(this part of code is used only for 'show columns' & 'show statistics' commands). */ error= test(schema_table->process_table(thd, show_table_list, - table, res, + table, res, (show_table_list->view ? show_table_list->view_db.str : show_table_list->db), @@ -2263,7 +2263,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) (base_name= select_lex->db) && !bases.elements)) { #ifndef NO_EMBEDDED_ACCESS_CHECKS - if (!check_access(thd,SELECT_ACL, base_name, + if (!check_access(thd,SELECT_ACL, base_name, &thd->col_access, 0, 1, with_i_schema) || sctx->master_access & (DB_ACLS | SHOW_DB_ACL) || acl_get(sctx->host, sctx->ip, sctx->priv_user, base_name,0) || @@ -2281,7 +2281,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) strxmov(path, mysql_data_home, "/", base_name, NullS); end= path + (len= unpack_dirname(path,path)); len= FN_LEN - len; - find_files_result res= find_files(thd, &files, base_name, + find_files_result res= find_files(thd, &files, base_name, path, idx_field_vals.table_value, 0); if (res != FIND_FILES_OK) { @@ -2367,9 +2367,9 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) res= open_normal_and_derived_tables(thd, show_table_list, MYSQL_LOCK_IGNORE_FLUSH); lex->sql_command= save_sql_command; - /* + /* They can drop table after table names list creation and - before table opening. We open non existing table and + before table opening. We open non existing table and get ER_NO_SUCH_TABLE error. In this case we do not store the record into I_S table and clear error. */ @@ -2381,10 +2381,10 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) else { /* - We should use show_table_list->alias instead of + We should use show_table_list->alias instead of show_table_list->table_name because table_name could be changed during opening of I_S tables. It's safe - to use alias because alias contains original table name + to use alias because alias contains original table name in this case. */ res= schema_table->process_table(thd, show_table_list, table, @@ -2486,28 +2486,28 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables, { const char *tmp_buff; MYSQL_TIME time; + int info_error= 0; CHARSET_INFO *cs= system_charset_info; DBUG_ENTER("get_schema_tables_record"); restore_record(table, s->default_values); table->field[1]->store(base_name, (uint) strlen(base_name), cs); table->field[2]->store(file_name, (uint) strlen(file_name), cs); + if (res) { - /* - there was errors during opening tables - */ - const char *error= thd->net.last_error; + /* There was a table open error, so set the table type and return */ if (tables->view) table->field[3]->store(STRING_WITH_LEN("VIEW"), cs); else if (tables->schema_table) table->field[3]->store(STRING_WITH_LEN("SYSTEM VIEW"), cs); else table->field[3]->store(STRING_WITH_LEN("BASE TABLE"), cs); - table->field[20]->store(error, (uint) strlen(error), cs); - thd->clear_error(); + + goto err; } - else if (tables->view) + + if (tables->view) { table->field[3]->store(STRING_WITH_LEN("VIEW"), cs); table->field[20]->store(STRING_WITH_LEN("VIEW"), cs); @@ -2518,8 +2518,15 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables, TABLE_SHARE *share= show_table->s; handler *file= show_table->file; - file->info(HA_STATUS_VARIABLE | HA_STATUS_TIME | HA_STATUS_AUTO | - HA_STATUS_NO_LOCK); + if (!file) + goto err; + + if ((info_error= file->info(HA_STATUS_VARIABLE | + HA_STATUS_TIME | + HA_STATUS_AUTO | + HA_STATUS_NO_LOCK)) != 0) + goto err; + if (share->tmp_table == SYSTEM_TMP_TABLE) table->field[3]->store(STRING_WITH_LEN("SYSTEM VIEW"), cs); else if (share->tmp_table) @@ -2636,7 +2643,7 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables, if (share->db_create_options & HA_OPTION_DELAY_KEY_WRITE) ptr=strmov(ptr," delay_key_write=1"); if (share->row_type != ROW_TYPE_DEFAULT) - ptr=strxmov(ptr, " row_format=", + ptr=strxmov(ptr, " row_format=", ha_row_type[(uint) share->row_type], NullS); if (file->raid_type) @@ -2649,7 +2656,7 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables, ptr=strmov(ptr,buff); } table->field[19]->store(option_buff+1, - (ptr == option_buff ? 0 : + (ptr == option_buff ? 0 : (uint) (ptr-option_buff)-1), cs); { char *comment; @@ -2658,13 +2665,32 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables, { table->field[20]->store(comment, (comment == share->comment.str ? - share->comment.length : + share->comment.length : (uint) strlen(comment)), cs); if (comment != share->comment.str) my_free(comment, MYF(0)); } } } + +err: + if (res || info_error) + { + /* + If an error was encountered, push a warning, set the TABLE COMMENT + column with the error text, and clear the error so that the operation + can continue. + */ + const char *error= thd->net.last_error; + if (error) + { + table->field[20]->store(error, strlen(error), cs); + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + thd->net.last_errno, thd->net.last_error); + thd->clear_error(); + } + } + DBUG_RETURN(schema_table_store_record(thd, table)); } @@ -2691,7 +2717,7 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables, /* I.e. we are in SELECT FROM INFORMATION_SCHEMA.COLUMS rather than in SHOW COLUMNS - */ + */ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, thd->net.last_errno, thd->net.last_error); thd->clear_error(); @@ -2732,7 +2758,7 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables, uint col_access; check_access(thd,SELECT_ACL | EXTRA_ACL, base_name, &tables->grant.privilege, 0, 0, test(tables->schema_table)); - col_access= get_column_grant(thd, &tables->grant, + col_access= get_column_grant(thd, &tables->grant, base_name, file_name, field->field_name) & COL_ACLS; if (!tables->schema_table && !col_access) @@ -2755,9 +2781,9 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables, cs); table->field[4]->store((longlong) count, TRUE); field->sql_type(type); - table->field[14]->store(type.ptr(), type.length(), cs); + table->field[14]->store(type.ptr(), type.length(), cs); tmp_buff= strchr(type.ptr(), '('); - table->field[7]->store(type.ptr(), (uint) + table->field[7]->store(type.ptr(), (uint) (tmp_buff ? tmp_buff - type.ptr() : type.length()), cs); @@ -2778,7 +2804,7 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables, uint32 octet_max_length= field->max_display_length(); if (is_blob && octet_max_length != (uint32) 4294967295U) octet_max_length /= field->charset()->mbmaxlen; - longlong char_max_len= is_blob ? + longlong char_max_len= is_blob ? (longlong) octet_max_length / field->charset()->mbminlen : (longlong) octet_max_length / field->charset()->mbmaxlen; table->field[8]->store(char_max_len, TRUE); @@ -2811,7 +2837,7 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables, field_length= field->max_display_length(); decimals= -1; // return NULL break; - case FIELD_TYPE_FLOAT: + case FIELD_TYPE_FLOAT: case FIELD_TYPE_DOUBLE: field_length= field->field_length; if (decimals == NOT_FIXED_DEC) @@ -2874,7 +2900,7 @@ int fill_schema_charsets(THD *thd, TABLE_LIST *tables, COND *cond) for (cs= all_charsets ; cs < all_charsets+255 ; cs++) { CHARSET_INFO *tmp_cs= cs[0]; - if (tmp_cs && (tmp_cs->state & MY_CS_PRIMARY) && + if (tmp_cs && (tmp_cs->state & MY_CS_PRIMARY) && (tmp_cs->state & MY_CS_AVAILABLE) && !(wild && wild[0] && wild_case_compare(scs, tmp_cs->csname,wild))) @@ -2904,13 +2930,13 @@ int fill_schema_collation(THD *thd, TABLE_LIST *tables, COND *cond) { CHARSET_INFO **cl; CHARSET_INFO *tmp_cs= cs[0]; - if (!tmp_cs || !(tmp_cs->state & MY_CS_AVAILABLE) || + if (!tmp_cs || !(tmp_cs->state & MY_CS_AVAILABLE) || !(tmp_cs->state & MY_CS_PRIMARY)) continue; for (cl= all_charsets; cl < all_charsets+255 ;cl ++) { CHARSET_INFO *tmp_cl= cl[0]; - if (!tmp_cl || !(tmp_cl->state & MY_CS_AVAILABLE) || + if (!tmp_cl || !(tmp_cl->state & MY_CS_AVAILABLE) || !my_charset_same(tmp_cs, tmp_cl)) continue; if (!(wild && wild[0] && @@ -2944,13 +2970,13 @@ int fill_schema_coll_charset_app(THD *thd, TABLE_LIST *tables, COND *cond) { CHARSET_INFO **cl; CHARSET_INFO *tmp_cs= cs[0]; - if (!tmp_cs || !(tmp_cs->state & MY_CS_AVAILABLE) || + if (!tmp_cs || !(tmp_cs->state & MY_CS_AVAILABLE) || !(tmp_cs->state & MY_CS_PRIMARY)) continue; for (cl= all_charsets; cl < all_charsets+255 ;cl ++) { CHARSET_INFO *tmp_cl= cl[0]; - if (!tmp_cl || !(tmp_cl->state & MY_CS_AVAILABLE) || + if (!tmp_cl || !(tmp_cl->state & MY_CS_AVAILABLE) || !my_charset_same(tmp_cs,tmp_cl)) continue; restore_record(table, s->default_values); @@ -3014,7 +3040,7 @@ bool store_schema_proc(THD *thd, TABLE *table, TABLE *proc_table, table->field[10]->store(STRING_WITH_LEN("SQL"), cs); get_field(thd->mem_root, proc_table->field[6], &tmp_string); table->field[11]->store(tmp_string.ptr(), tmp_string.length(), cs); - table->field[12]->store(sp_data_access_name[enum_idx].str, + table->field[12]->store(sp_data_access_name[enum_idx].str, sp_data_access_name[enum_idx].length , cs); get_field(thd->mem_root, proc_table->field[7], &tmp_string); table->field[14]->store(tmp_string.ptr(), tmp_string.length(), cs); @@ -3290,10 +3316,10 @@ static int get_schema_views_record(THD *thd, TABLE_LIST *tables, if (schema_table_store_record(thd, table)) DBUG_RETURN(1); if (res) - push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, thd->net.last_errno, thd->net.last_error); } - if (res) + if (res) thd->clear_error(); DBUG_RETURN(0); } @@ -3334,7 +3360,7 @@ static int get_schema_constraints_record(THD *thd, TABLE_LIST *tables, TABLE *show_table= tables->table; KEY *key_info=show_table->key_info; uint primary_key= show_table->s->primary_key; - show_table->file->info(HA_STATUS_VARIABLE | + show_table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK | HA_STATUS_TIME); for (uint i=0 ; i < show_table->s->keys ; i++, key_info++) @@ -3363,7 +3389,7 @@ static int get_schema_constraints_record(THD *thd, TABLE_LIST *tables, List_iterator_fast it(f_key_list); while ((f_key_info=it++)) { - if (store_constraints(thd, table, base_name, file_name, + if (store_constraints(thd, table, base_name, file_name, f_key_info->forein_id->str, (uint) strlen(f_key_info->forein_id->str), "FOREIGN KEY", 11)) @@ -3472,7 +3498,7 @@ ret: void store_key_column_usage(TABLE *table, const char*db, const char *tname, - const char *key_name, uint key_len, + const char *key_name, uint key_len, const char *con_type, uint con_len, longlong idx) { CHARSET_INFO *cs= system_charset_info; @@ -3506,7 +3532,7 @@ static int get_schema_key_column_usage_record(THD *thd, TABLE *show_table= tables->table; KEY *key_info=show_table->key_info; uint primary_key= show_table->s->primary_key; - show_table->file->info(HA_STATUS_VARIABLE | + show_table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK | HA_STATUS_TIME); for (uint i=0 ; i < show_table->s->keys ; i++, key_info++) @@ -3523,8 +3549,8 @@ static int get_schema_key_column_usage_record(THD *thd, restore_record(table, s->default_values); store_key_column_usage(table, base_name, file_name, key_info->name, - (uint) strlen(key_info->name), - key_part->field->field_name, + (uint) strlen(key_info->name), + key_part->field->field_name, (uint) strlen(key_part->field->field_name), (longlong) f_idx); if (schema_table_store_record(thd, table)) @@ -3560,7 +3586,7 @@ static int get_schema_key_column_usage_record(THD *thd, system_charset_info); table->field[9]->set_notnull(); table->field[10]->store(f_key_info->referenced_table->str, - f_key_info->referenced_table->length, + f_key_info->referenced_table->length, system_charset_info); table->field[10]->set_notnull(); table->field[11]->store(r_info->str, r_info->length, @@ -3607,7 +3633,7 @@ int fill_variables(THD *thd, TABLE_LIST *tables, COND *cond) LEX *lex= thd->lex; const char *wild= lex->wild ? lex->wild->ptr() : NullS; pthread_mutex_lock(&LOCK_global_system_variables); - res= show_status_array(thd, wild, init_vars, + res= show_status_array(thd, wild, init_vars, lex->option_type, 0, "", tables->table); pthread_mutex_unlock(&LOCK_global_system_variables); DBUG_RETURN(res); @@ -3626,7 +3652,7 @@ int fill_status(THD *thd, TABLE_LIST *tables, COND *cond) if (lex->option_type == OPT_GLOBAL) calc_sum_of_all_status(&tmp); res= show_status_array(thd, wild, status_vars, OPT_GLOBAL, - (lex->option_type == OPT_GLOBAL ? + (lex->option_type == OPT_GLOBAL ? &tmp: &thd->status_var), "",tables->table); pthread_mutex_unlock(&LOCK_status); DBUG_RETURN(res); @@ -3717,7 +3743,7 @@ TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list) break; case MYSQL_TYPE_FLOAT: case MYSQL_TYPE_DOUBLE: - if ((item= new Item_float(fields_info->field_name, 0.0, NOT_FIXED_DEC, + if ((item= new Item_float(fields_info->field_name, 0.0, NOT_FIXED_DEC, fields_info->field_length)) == NULL) DBUG_RETURN(NULL); break; @@ -3761,7 +3787,7 @@ TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list) tmp_table_param->schema_table= 1; SELECT_LEX *select_lex= thd->lex->current_select; if (!(table= create_tmp_table(thd, tmp_table_param, - field_list, (ORDER*) 0, 0, 0, + field_list, (ORDER*) 0, 0, 0, (select_lex->options | thd->options | TMP_TABLE_ALL_COLUMNS), HA_POS_ERROR, table_list->alias))) @@ -4102,7 +4128,7 @@ bool get_schema_tables_result(JOIN *join, thd->no_warnings_for_error= 1; for (JOIN_TAB *tab= join->join_tab; tab < tmp_join_tab; tab++) - { + { if (!tab->table || !tab->table->pos_in_table_list) break; @@ -4454,13 +4480,13 @@ ST_FIELD_INFO variables_fields_info[]= ST_SCHEMA_TABLE schema_tables[]= { - {"CHARACTER_SETS", charsets_fields_info, create_schema_table, + {"CHARACTER_SETS", charsets_fields_info, create_schema_table, fill_schema_charsets, make_character_sets_old_format, 0, -1, -1, 0}, - {"COLLATIONS", collation_fields_info, create_schema_table, + {"COLLATIONS", collation_fields_info, create_schema_table, fill_schema_collation, make_old_format, 0, -1, -1, 0}, {"COLLATION_CHARACTER_SET_APPLICABILITY", coll_charset_app_fields_info, create_schema_table, fill_schema_coll_charset_app, 0, 0, -1, -1, 0}, - {"COLUMNS", columns_fields_info, create_schema_table, + {"COLUMNS", columns_fields_info, create_schema_table, get_all_tables, make_columns_old_format, get_schema_column_record, 1, 2, 0}, {"COLUMN_PRIVILEGES", column_privileges_fields_info, create_schema_table, fill_schema_column_privileges, 0, 0, -1, -1, 0}, @@ -4469,19 +4495,19 @@ ST_SCHEMA_TABLE schema_tables[]= {"OPEN_TABLES", open_tables_fields_info, create_schema_table, fill_open_tables, make_old_format, 0, -1, -1, 1}, {"PROFILING", query_profile_statistics_info, create_schema_table, - fill_query_profile_statistics_info, make_profile_table_for_show, + fill_query_profile_statistics_info, make_profile_table_for_show, NULL, -1, -1, false}, - {"ROUTINES", proc_fields_info, create_schema_table, + {"ROUTINES", proc_fields_info, create_schema_table, fill_schema_proc, make_proc_old_format, 0, -1, -1, 0}, {"SCHEMATA", schema_fields_info, create_schema_table, fill_schema_shemata, make_schemata_old_format, 0, 1, -1, 0}, {"SCHEMA_PRIVILEGES", schema_privileges_fields_info, create_schema_table, fill_schema_schema_privileges, 0, 0, -1, -1, 0}, - {"STATISTICS", stat_fields_info, create_schema_table, + {"STATISTICS", stat_fields_info, create_schema_table, get_all_tables, make_old_format, get_schema_stat_record, 1, 2, 0}, - {"STATUS", variables_fields_info, create_schema_table, fill_status, + {"STATUS", variables_fields_info, create_schema_table, fill_status, make_old_format, 0, -1, -1, 1}, - {"TABLES", tables_fields_info, create_schema_table, + {"TABLES", tables_fields_info, create_schema_table, get_all_tables, make_old_format, get_schema_tables_record, 1, 2, 0}, {"TABLE_CONSTRAINTS", table_constraints_fields_info, create_schema_table, get_all_tables, 0, get_schema_constraints_record, 3, 4, 0}, @@ -4491,11 +4517,11 @@ ST_SCHEMA_TABLE schema_tables[]= fill_schema_table_privileges, 0, 0, -1, -1, 0}, {"TRIGGERS", triggers_fields_info, create_schema_table, get_all_tables, make_old_format, get_schema_triggers_record, 5, 6, 0}, - {"USER_PRIVILEGES", user_privileges_fields_info, create_schema_table, + {"USER_PRIVILEGES", user_privileges_fields_info, create_schema_table, fill_schema_user_privileges, 0, 0, -1, -1, 0}, {"VARIABLES", variables_fields_info, create_schema_table, fill_variables, make_old_format, 0, -1, -1, 1}, - {"VIEWS", view_fields_info, create_schema_table, + {"VIEWS", view_fields_info, create_schema_table, get_all_tables, 0, get_schema_views_record, 1, 2, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0} }; -- cgit v1.2.1 From 8f3d884dd2116fa37221bbbc9704ff27d07518e0 Mon Sep 17 00:00:00 2001 From: Christopher Powers Date: Tue, 30 Nov 2010 11:20:56 -0600 Subject: Bug#35333, "If Federated table can't connect to remote host, can't retrieve metadata" Improved error handling such that queries against Information_Schema.Tables won't fail if a federated table can't make a remote connection. mysql-test/r/lock_multi.result: Updated with warnings that were previously masked. mysql-test/r/mdl_sync.result: Updated with warnings that were previously masked. mysql-test/r/merge.result: Updated with warnings that were previously masked. mysql-test/r/show_check.result: Updated with warnings that were previously masked. mysql-test/r/view.result: Updated with warnings that were previously masked. mysql-test/suite/federated/federated_bug_35333.result: New test results for bug#35333 mysql-test/suite/federated/federated_bug_35333.test: New test or bug#35333 sql/sql_show.cc: If get_schema_tables_record() encounters an error, push a warning, set the TABLE COMMENT column with the error text, and clear the error so that the operation can continue. --- sql/sql_show.cc | 62 +++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 54 insertions(+), 8 deletions(-) (limited to 'sql/sql_show.cc') diff --git a/sql/sql_show.cc b/sql/sql_show.cc index f8853611b39..2c71fe5dd48 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -3781,6 +3781,7 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables, { const char *tmp_buff; MYSQL_TIME time; + int info_error= 0; CHARSET_INFO *cs= system_charset_info; DBUG_ENTER("get_schema_tables_record"); @@ -3788,22 +3789,21 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables, table->field[0]->store(STRING_WITH_LEN("def"), cs); table->field[1]->store(db_name->str, db_name->length, cs); table->field[2]->store(table_name->str, table_name->length, cs); + if (res) { - /* - there was errors during opening tables - */ - const char *error= thd->is_error() ? thd->stmt_da->message() : ""; + /* There was a table open error, so set the table type and return */ if (tables->view) table->field[3]->store(STRING_WITH_LEN("VIEW"), cs); else if (tables->schema_table) table->field[3]->store(STRING_WITH_LEN("SYSTEM VIEW"), cs); else table->field[3]->store(STRING_WITH_LEN("BASE TABLE"), cs); - table->field[20]->store(error, strlen(error), cs); - thd->clear_error(); + + goto err; } - else if (tables->view) + + if (tables->view) { table->field[3]->store(STRING_WITH_LEN("VIEW"), cs); table->field[20]->store(STRING_WITH_LEN("VIEW"), cs); @@ -3818,6 +3818,7 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables, #ifdef WITH_PARTITION_STORAGE_ENGINE bool is_partitioned= FALSE; #endif + if (share->tmp_table == SYSTEM_TMP_TABLE) table->field[3]->store(STRING_WITH_LEN("SYSTEM VIEW"), cs); else if (share->tmp_table) @@ -3831,6 +3832,9 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables, continue; table->field[i]->set_notnull(); } + + /* Collect table info from the table share */ + #ifdef WITH_PARTITION_STORAGE_ENGINE if (share->db_type() == partition_hton && share->partition_info_str_len) @@ -3839,62 +3843,82 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables, is_partitioned= TRUE; } #endif + tmp_buff= (char *) ha_resolve_storage_engine_name(tmp_db_type); table->field[4]->store(tmp_buff, strlen(tmp_buff), cs); table->field[5]->store((longlong) share->frm_version, TRUE); ptr=option_buff; + if (share->min_rows) { ptr=strmov(ptr," min_rows="); ptr=longlong10_to_str(share->min_rows,ptr,10); } + if (share->max_rows) { ptr=strmov(ptr," max_rows="); ptr=longlong10_to_str(share->max_rows,ptr,10); } + if (share->avg_row_length) { ptr=strmov(ptr," avg_row_length="); ptr=longlong10_to_str(share->avg_row_length,ptr,10); } + if (share->db_create_options & HA_OPTION_PACK_KEYS) ptr=strmov(ptr," pack_keys=1"); + if (share->db_create_options & HA_OPTION_NO_PACK_KEYS) ptr=strmov(ptr," pack_keys=0"); + /* We use CHECKSUM, instead of TABLE_CHECKSUM, for backward compability */ if (share->db_create_options & HA_OPTION_CHECKSUM) ptr=strmov(ptr," checksum=1"); + if (share->db_create_options & HA_OPTION_DELAY_KEY_WRITE) ptr=strmov(ptr," delay_key_write=1"); + if (share->row_type != ROW_TYPE_DEFAULT) ptr=strxmov(ptr, " row_format=", ha_row_type[(uint) share->row_type], NullS); + if (share->key_block_size) { ptr= strmov(ptr, " KEY_BLOCK_SIZE="); ptr= longlong10_to_str(share->key_block_size, ptr, 10); } + #ifdef WITH_PARTITION_STORAGE_ENGINE if (is_partitioned) ptr= strmov(ptr, " partitioned"); #endif + table->field[19]->store(option_buff+1, (ptr == option_buff ? 0 : (uint) (ptr-option_buff)-1), cs); tmp_buff= (share->table_charset ? share->table_charset->name : "default"); + table->field[17]->store(tmp_buff, strlen(tmp_buff), cs); if (share->comment.str) table->field[20]->store(share->comment.str, share->comment.length, cs); + /* Collect table info from the storage engine */ + if(file) { - file->info(HA_STATUS_VARIABLE | HA_STATUS_TIME | HA_STATUS_AUTO); + /* If info() fails, then there's nothing else to do */ + if ((info_error= file->info(HA_STATUS_VARIABLE | + HA_STATUS_TIME | + HA_STATUS_AUTO)) != 0) + goto err; + enum row_type row_type = file->get_row_type(); switch (row_type) { case ROW_TYPE_NOT_USED: @@ -3923,7 +3947,9 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables, tmp_buff= "Paged"; break; } + table->field[6]->store(tmp_buff, strlen(tmp_buff), cs); + if (!tables->schema_table) { table->field[7]->store((longlong) file->stats.records, TRUE); @@ -3972,6 +3998,26 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables, } } } + +err: + if (res || info_error) + { + /* + If an error was encountered, push a warning, set the TABLE COMMENT + column with the error text, and clear the error so that the operation + can continue. + */ + const char *error= thd->is_error() ? thd->stmt_da->message() : ""; + table->field[20]->store(error, strlen(error), cs); + + if (thd->is_error()) + { + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + thd->stmt_da->sql_errno(), thd->stmt_da->message()); + thd->clear_error(); + } + } + DBUG_RETURN(schema_table_store_record(thd, table)); } -- cgit v1.2.1 From fcb83cbf15653bbed15936d8eafb4fc7de3e743b Mon Sep 17 00:00:00 2001 From: Sergey Glukhov Date: Tue, 14 Dec 2010 12:33:03 +0300 Subject: Fixed following problems: --Bug#52157 various crashes and assertions with multi-table update, stored function --Bug#54475 improper error handling causes cascading crashing failures in innodb/ndb --Bug#57703 create view cause Assertion failed: 0, file .\item_subselect.cc, line 846 --Bug#57352 valgrind warnings when creating view --Recently discovered problem when a nested materialized derived table is used before being populated and it leads to incorrect result We have several modes when we should disable subquery evaluation. The reasons for disabling are different. It could be uselessness of the evaluation as in case of 'CREATE VIEW' or 'PREPARE stmt', or we should disable subquery evaluation if tables are not locked yet as it happens in bug#54475, or too early evaluation of subqueries can lead to wrong result as it happened in Bug#19077. Main problem is that if subquery items are treated as const they are evaluated in ::fix_fields(), ::fix_length_and_dec() of the parental items as a lot of these methods have Item::val_...() calls inside. We have to make subqueries non-const to prevent unnecessary subquery evaluation. At the moment we have different methods for this. Here is a list of these modes: 1. PREPARE stmt; We use UNCACHEABLE_PREPARE flag. It is set during parsing in sql_parse.cc, mysql_new_select() for each SELECT_LEX object and cleared at the end of PREPARE in sql_prepare.cc, init_stmt_after_parse(). If this flag is set subquery becomes non-const and evaluation does not happen. 2. CREATE|ALTER VIEW, SHOW CREATE VIEW, I_S tables which process FRM files We use LEX::view_prepare_mode field. We set it before view preparation and check this flag in ::fix_fields(), ::fix_length_and_dec(). Some bugs are fixed using this approach, some are not(Bug#57352, Bug#57703). The problem here is that we have a lot of ::fix_fields(), ::fix_length_and_dec() where we use Item::val_...() calls for const items. 3. Derived tables with subquery = wrong result(Bug19077) The reason of this bug is too early subquery evaluation. It was fixed by adding Item::with_subselect field The check of this field in appropriate places prevents const item evaluation if the item have subquery. The fix for Bug19077 fixes only the problem with convert_constant_item() function and does not cover other places(::fix_fields(), ::fix_length_and_dec() again) where subqueries could be evaluated. Example: CREATE TABLE t1 (i INT, j BIGINT); INSERT INTO t1 VALUES (1, 2), (2, 2), (3, 2); SELECT * FROM (SELECT MIN(i) FROM t1 WHERE j = SUBSTRING('12', (SELECT * FROM (SELECT MIN(j) FROM t1) t2))) t3; DROP TABLE t1; 4. Derived tables with subquery where subquery is evaluated before table locking(Bug#54475, Bug#52157) Suggested solution is following: -Introduce new field LEX::context_analysis_only with the following possible flags: #define CONTEXT_ANALYSIS_ONLY_PREPARE 1 #define CONTEXT_ANALYSIS_ONLY_VIEW 2 #define CONTEXT_ANALYSIS_ONLY_DERIVED 4 -Set/clean these flags when we perform context analysis operation -Item_subselect::const_item() returns result depending on LEX::context_analysis_only. If context_analysis_only is set then we return FALSE that means that subquery is non-const. As all subquery types are wrapped by Item_subselect it allow as to make subquery non-const when it's necessary. mysql-test/r/derived.result: test case mysql-test/r/multi_update.result: test case mysql-test/r/view.result: test case mysql-test/suite/innodb/r/innodb_multi_update.result: test case mysql-test/suite/innodb/t/innodb_multi_update.test: test case mysql-test/suite/innodb_plugin/r/innodb_multi_update.result: test case mysql-test/suite/innodb_plugin/t/innodb_multi_update.test: test case mysql-test/t/derived.test: test case mysql-test/t/multi_update.test: test case mysql-test/t/view.test: test case sql/item.cc: --removed unnecessary code sql/item_cmpfunc.cc: --removed unnecessary checks --THD::is_context_analysis_only() is replaced with LEX::is_ps_or_view_context_analysis() sql/item_func.cc: --refactored context analysis checks sql/item_row.cc: --removed unnecessary checks sql/item_subselect.cc: --removed unnecessary code --added DBUG_ASSERT into Item_subselect::exec() which asserts that subquery execution can not happen if LEX::context_analysis_only is set, i.e. at context analysis stage. --Item_subselect::const_item() Return FALSE if LEX::context_analysis_only is set. It prevents subquery evaluation in ::fix_fields & ::fix_length_and_dec at context analysis stage. sql/item_subselect.h: --removed unnecessary code sql/mysql_priv.h: --Added new set of flags. sql/sql_class.h: --removed unnecessary code sql/sql_derived.cc: --added LEX::context_analysis_only analysis intialization/cleanup sql/sql_lex.cc: --init LEX::context_analysis_only field sql/sql_lex.h: --New LEX::context_analysis_only field sql/sql_parse.cc: --removed unnecessary code sql/sql_prepare.cc: --removed unnecessary code --added LEX::context_analysis_only analysis intialization/cleanup sql/sql_select.cc: --refactored context analysis checks sql/sql_show.cc: --added LEX::context_analysis_only analysis intialization/cleanup sql/sql_view.cc: --added LEX::context_analysis_only analysis intialization/cleanup --- sql/sql_show.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'sql/sql_show.cc') diff --git a/sql/sql_show.cc b/sql/sql_show.cc index ee0e2bf5ce7..ed7a8d32eb8 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -718,7 +718,7 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) table_list->table_name)); /* We want to preserve the tree for views. */ - thd->lex->view_prepare_mode= TRUE; + thd->lex->context_analysis_only|= CONTEXT_ANALYSIS_ONLY_VIEW; { Show_create_error_handler view_error_suppressor(thd, table_list); @@ -3315,7 +3315,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) uint derived_tables= lex->derived_tables; int error= 1; Open_tables_state open_tables_state_backup; - bool save_view_prepare_mode= lex->view_prepare_mode; + uint8 save_context_analysis_only= lex->context_analysis_only; Query_tables_list query_tables_list_backup; #ifndef NO_EMBEDDED_ACCESS_CHECKS Security_context *sctx= thd->security_ctx; @@ -3323,7 +3323,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) uint table_open_method; DBUG_ENTER("get_all_tables"); - lex->view_prepare_mode= TRUE; + lex->context_analysis_only|= CONTEXT_ANALYSIS_ONLY_VIEW; lex->reset_n_backup_query_tables_list(&query_tables_list_backup); /* @@ -3540,7 +3540,7 @@ err: lex->restore_backup_query_tables_list(&query_tables_list_backup); lex->derived_tables= derived_tables; lex->all_selects_list= old_all_select_lex; - lex->view_prepare_mode= save_view_prepare_mode; + lex->context_analysis_only= save_context_analysis_only; lex->sql_command= save_sql_command; DBUG_RETURN(error); } -- cgit v1.2.1 From 247ecb7597015d02a93732373c742e0c8bd8fc73 Mon Sep 17 00:00:00 2001 From: Mikael Ronstrom Date: Fri, 17 Dec 2010 21:58:40 +0100 Subject: BUG#59013, make partition handler not miss HA_STATUS_NO_LOCK, add HA_STATUS_VARIABLE_EXTRA to remove InnoDB bottleneck --- sql/sql_show.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'sql/sql_show.cc') diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 0421cc35c5d..684456e5139 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -3925,6 +3925,7 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables, /* If info() fails, then there's nothing else to do */ if ((info_error= file->info(HA_STATUS_VARIABLE | HA_STATUS_TIME | + HA_STATUS_VARIABLE_EXTRA | HA_STATUS_AUTO)) != 0) goto err; -- cgit v1.2.1 From 029a5df87044dd392d3c393a2ba1c882722c94e0 Mon Sep 17 00:00:00 2001 From: Tor Didriksen Date: Tue, 21 Dec 2010 13:00:26 +0100 Subject: Bug #58699 cannot build with gcc dbg on solaris cmake/os/SunOS.cmake: Remove TARGET_OS_SOLARIS config.h.cmake: Remove TARGET_OS_SOLARIS Add PTHREAD_ONCE_INITIALIZER configure.cmake: Add function for testing whether we need { PTHREAD_ONCE_INIT } rather than PTHREAD_ONCE_INIT include/my_pthread.h: Use PTHREAD_ONCE_INITIALIZER if set by cmake. include/mysql/psi/mysql_file.h: Include my_global.h first, to get correct platform definitions. mysys/ptr_cmp.c: Hide the unused static functions in #ifdef's on solaris. Use __sun (defined by both gcc and SunPro cc) rather than TARGET_OS_SOLARIS sql/my_decimal.cc: Include my_global.h first, to get correct platform definitions. sql/mysqld.cc: Fix signed/unsigned comparison warning. sql/sql_audit.h: Include my_global.h first, to get correct platform definitions. sql/sql_plugin.h: Include my_global.h first, to get correct platform definitions. sql/sql_show.cc: Fix: warning: cast from pointer to integer of different size sql/sys_vars.h: Use reinterpret_cast rather than c-style cast. storage/perfschema/pfs_instr.cc: Include my_global.h first, to get correct platform definitions. --- sql/sql_show.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql/sql_show.cc') diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 0421cc35c5d..80dfde5343e 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2255,7 +2255,7 @@ static bool show_status_array(THD *thd, const char *wild, end= int10_to_str(*(long*) value, buff, 10); break; case SHOW_LONGLONG_STATUS: - value= ((char *) status_var + (ulonglong) value); + value= ((char *) status_var + (ulong) value); /* fall through */ case SHOW_LONGLONG: end= longlong10_to_str(*(longlong*) value, buff, 10); -- cgit v1.2.1 From 85323eda8a5823e4db1fa34dc998684b67e710b5 Mon Sep 17 00:00:00 2001 From: Kent Boortz Date: Tue, 28 Dec 2010 19:57:23 +0100 Subject: - Added/updated copyright headers - Removed files specific to compiling on OS/2 - Removed files specific to SCO Unix packaging - Removed "libmysqld/copyright", text is included in documentation - Removed LaTeX headers for NDB Doxygen documentation - Removed obsolete NDB files - Removed "mkisofs" binaries - Removed the "cvs2cl.pl" script - Changed a few GPL texts to use "program" instead of "library" --- sql/sql_show.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql/sql_show.cc') diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 1075e7f76d1..56f0ce78c8c 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2000-2004 MySQL AB +/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. 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 -- cgit v1.2.1 From cafdf6e6d20b848df396cb83dd7bfe27f1c1a22a Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 4 Jan 2011 12:34:39 -0600 Subject: 43818 - Patch for mysql-5.1-innodb Avoid handler::info() call for three Information Schema tables; TABLE_CONSTRAINTS, KEY_COLUMN_USAGE, & REFERENTIAL_CONTRAINTS --- sql/sql_show.cc | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) (limited to 'sql/sql_show.cc') diff --git a/sql/sql_show.cc b/sql/sql_show.cc index ed7a8d32eb8..7eff7740fc0 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -4647,9 +4647,10 @@ static int get_schema_constraints_record(THD *thd, TABLE_LIST *tables, TABLE *show_table= tables->table; KEY *key_info=show_table->key_info; uint primary_key= show_table->s->primary_key; - show_table->file->info(HA_STATUS_VARIABLE | - HA_STATUS_NO_LOCK | - HA_STATUS_TIME); + + // This is not needed since no statistics are displayed. + // show_table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK | HA_STATUS_TIME); + for (uint i=0 ; i < show_table->s->keys ; i++, key_info++) { if (i != primary_key && !(key_info->flags & HA_NOSAME)) @@ -4831,9 +4832,10 @@ static int get_schema_key_column_usage_record(THD *thd, TABLE *show_table= tables->table; KEY *key_info=show_table->key_info; uint primary_key= show_table->s->primary_key; - show_table->file->info(HA_STATUS_VARIABLE | - HA_STATUS_NO_LOCK | - HA_STATUS_TIME); + + // This is not needed since no statistics are displayed. + // show_table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK | HA_STATUS_TIME); + for (uint i=0 ; i < show_table->s->keys ; i++, key_info++) { if (i != primary_key && !(key_info->flags & HA_NOSAME)) @@ -5562,9 +5564,9 @@ get_referential_constraints_record(THD *thd, TABLE_LIST *tables, { List f_key_list; TABLE *show_table= tables->table; - show_table->file->info(HA_STATUS_VARIABLE | - HA_STATUS_NO_LOCK | - HA_STATUS_TIME); + + // This is not needed since no statistics are displayed. + // show_table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK | HA_STATUS_TIME); show_table->file->get_foreign_key_list(thd, &f_key_list); FOREIGN_KEY_INFO *f_key_info; -- cgit v1.2.1 From 60353d7eb6058198bed7dad50ee7cd5ff22fe84a Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Fri, 14 Jan 2011 16:57:13 +0200 Subject: Bug #59275: SHOW PRIVILEGES doesn't have an entry for the PROXY privilege Added the privilege to the SHOW command. --- sql/sql_show.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'sql/sql_show.cc') diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 9bf24bb88f9..f965c9371f0 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -336,6 +336,7 @@ static struct show_privileges_st sys_privileges[]= {"Insert", "Tables", "To insert data into tables"}, {"Lock tables","Databases","To use LOCK TABLES (together with SELECT privilege)"}, {"Process", "Server Admin", "To view the plain text of currently executing queries"}, + {"Proxy", "Server Admin", "To make proxy user possible"}, {"References", "Databases,Tables", "To have references on tables"}, {"Reload", "Server Admin", "To reload or refresh tables, logs and privileges"}, {"Replication client","Server Admin","To ask where the slave or master servers are"}, -- cgit v1.2.1 From de3c4428b8c759e85631d8d70b5845c872de5400 Mon Sep 17 00:00:00 2001 From: Karen Langford Date: Tue, 25 Jan 2011 15:42:40 +0100 Subject: Updating header copyright/README in source for 2011 --- sql/sql_show.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql/sql_show.cc') diff --git a/sql/sql_show.cc b/sql/sql_show.cc index cf6a34d4ef5..1524a8fb87f 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. 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 -- cgit v1.2.1 From 0be575b7c8a7d551e7b0ea011b715f5e808e2eab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20Bl=C3=A5udd?= Date: Fri, 4 Mar 2011 09:41:29 +0100 Subject: Bug#60111 storage type for table not saved in .frm - Add new "format section" in extra data segment with additional table and column properties. This was originally introduced in 5.1.20 based MySQL Cluster - Remove hardcoded STORAGE DISK for table and instead output the real storage format used. Keep both TABLESPACE and STORAGE inside same version guard. - Implement default version of handler::get_tablespace_name() since tablespace is now available in share and it's unnecessary for each handler to implement. (the function could actually be removed totally now). - Add test for combinations of TABLESPACE and STORAGE with CREATE TABLE and ALTER TABLE - Add test to show that 5.5 now can read a .frm file created by MySQL Cluster 7.0.22. Although it does not yet show the column level attributes, they are read. --- sql/sql_show.cc | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) (limited to 'sql/sql_show.cc') diff --git a/sql/sql_show.cc b/sql/sql_show.cc index abef175ab55..c3dda3072f2 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1379,17 +1379,24 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet, if (!(thd->variables.sql_mode & MODE_NO_TABLE_OPTIONS) && !foreign_db_mode) { show_table_options= TRUE; - /* - Get possible table space definitions and append them - to the CREATE TABLE statement - */ - if ((for_str= file->get_tablespace_name(thd,0,0))) + /* TABLESPACE and STORAGE */ + if (share->tablespace || + share->default_storage_media != HA_SM_DEFAULT) { - packet->append(STRING_WITH_LEN(" /*!50100 TABLESPACE ")); - packet->append(for_str, strlen(for_str)); - packet->append(STRING_WITH_LEN(" STORAGE DISK */")); - my_free(for_str); + packet->append(STRING_WITH_LEN(" /*!50100")); + if (share->tablespace) + { + packet->append(STRING_WITH_LEN(" TABLESPACE ")); + packet->append(share->tablespace, strlen(share->tablespace)); + } + + if (share->default_storage_media == HA_SM_DISK) + packet->append(STRING_WITH_LEN(" STORAGE DISK")); + if (share->default_storage_media == HA_SM_MEMORY) + packet->append(STRING_WITH_LEN(" STORAGE MEMORY")); + + packet->append(STRING_WITH_LEN(" */")); } /* -- cgit v1.2.1 From 1c5d585ba596df84233f8710fbc115a6df22b36b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20Bl=C3=A5udd?= Date: Fri, 25 Mar 2011 10:06:07 +0100 Subject: Bug#60111 storage type for table not saved in .frm (aka BUG#11766883) - fix review comments - Rewrite last usage of handler::get_tablespace_name to use table->s->tablespace directly - Remove(revert) the addition of default implementation for handler::get_tablespace_name - Add comments describing the new TABLE_SHARE members default_storage_media and tablespace - Fix usage of incorrect mask for column_format bits, i.e COLUMN_FORMAT_MASK --- sql/sql_show.cc | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'sql/sql_show.cc') diff --git a/sql/sql_show.cc b/sql/sql_show.cc index c3dda3072f2..a93f06d9409 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -5503,12 +5503,9 @@ static void store_schema_partitions_record(THD *thd, TABLE *schema_table, strlen(part_elem->tablespace_name), cs); else { - char *ts= showing_table->file->get_tablespace_name(thd,0,0); + char *ts= showing_table->s->tablespace; if(ts) - { table->field[24]->store(ts, strlen(ts), cs); - my_free(ts); - } else table->field[24]->set_null(); } -- cgit v1.2.1 From 5321b3a57a5191471cba0db85a11e21fb702200a Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Mon, 4 Apr 2011 16:04:15 +0300 Subject: Bug #11758687: 50924: object names not resolved correctly on lctn2 systems There was a local variable in get_all_tables() to store the "original" value of the database name as it can get lowercased depending on the lower_case_table_name value. get_all_tables() iterates over database names and for each database iterates over the tables in it. The "original" db name was assigned in the table names loop. Thus the first table is ok, but the second and subsequent tables get the lowercased name from processing the first table. Fixed by moving the assignment of the original database name from the inner (table name) to the outer (database name) loop. Test suite added. --- sql/sql_show.cc | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'sql/sql_show.cc') diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 1524a8fb87f..5b835096042 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -3399,6 +3399,12 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) it.rewind(); /* To get access to new elements in basis list */ while ((db_name= it++)) { + LEX_STRING orig_db_name; + + /* db_name can be changed in make_table_list() func */ + if (!thd->make_lex_string(&orig_db_name, db_name->str, + db_name->length, FALSE)) + goto err; #ifndef NO_EMBEDDED_ACCESS_CHECKS if (!(check_access(thd,SELECT_ACL, db_name->str, &thd->col_access, 0, 1, with_i_schema) || @@ -3461,17 +3467,13 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) } int res; - LEX_STRING tmp_lex_string, orig_db_name; + LEX_STRING tmp_lex_string; /* Set the parent lex of 'sel' because it is needed by sel.init_query() which is called inside make_table_list. */ thd->no_warnings_for_error= 1; sel.parent_lex= lex; - /* db_name can be changed in make_table_list() func */ - if (!thd->make_lex_string(&orig_db_name, db_name->str, - db_name->length, FALSE)) - goto err; if (make_table_list(thd, &sel, db_name, table_name)) goto err; TABLE_LIST *show_table_list= sel.table_list.first; -- cgit v1.2.1 From 060541c02e6c332db0f08fa3b861cb2de305c71f Mon Sep 17 00:00:00 2001 From: Alexander Nozdrin Date: Fri, 15 Apr 2011 16:02:22 +0400 Subject: A patch for Bug#11763166 (55847: SHOW WARNINGS returns empty result set when SQLEXCEPTION is active. The problem was in a hackish THD::no_warnings_for_error attribute. When it was set, an error was not written to Warning_info -- only Diagnostics_area state was changed. That means, Diagnostics_area might contain error state, which is not present in Warning_info. The user-visible problem was that in some cases SHOW WARNINGS returned empty result set (i.e. there were no warnings) while the previous SQL statement failed. According to the MySQL protocol errors must be presented in warning list. The main idea of this patch is to remove THD::no_warnings_for_error. There were few places where it was used: - sql_admin.cc, handling of REPAIR TABLE USE_FRM. - sql_show.cc, when calling fill_schema_table_from_frm(). - sql_show.cc, when calling fill_table(). The fix is to either use internal-error-handlers, or to use temporary Warning_info storing warnings, which might be ignored. This patch is needed to fix Bug 11763162 (55843). --- sql/sql_show.cc | 153 ++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 144 insertions(+), 9 deletions(-) (limited to 'sql/sql_show.cc') diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 464b966e4be..9e9de5e3524 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -3415,6 +3415,45 @@ end: } +/** + Trigger_error_handler is intended to intercept and silence SQL conditions + that might happen during trigger loading for SHOW statements. + The potential SQL conditions are: + + - ER_PARSE_ERROR -- this error is thrown if a trigger definition file + is damaged or contains invalid CREATE TRIGGER statement. That should + not happen in normal life. + + - ER_TRG_NO_DEFINER -- this warning is thrown when we're loading a + trigger created/imported in/from the version of MySQL, which does not + support trigger definers. + + - ER_TRG_NO_CREATION_CTX -- this warning is thrown when we're loading a + trigger created/imported in/from the version of MySQL, which does not + support trigger creation contexts. +*/ + +class Trigger_error_handler : public Internal_error_handler +{ +public: + bool handle_condition(THD *thd, + uint sql_errno, + const char* sqlstate, + MYSQL_ERROR::enum_warning_level level, + const char* msg, + MYSQL_ERROR ** cond_hdl) + { + if (sql_errno == ER_PARSE_ERROR || + sql_errno == ER_TRG_NO_DEFINER || + sql_errno == ER_TRG_NO_CREATION_CTX) + return true; + + return false; + } +}; + + + /** @brief Fill I_S tables whose data are retrieved from frm files and storage engine @@ -3570,7 +3609,6 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) acl_get(sctx->host, sctx->ip, sctx->priv_user, db_name->str, 0)) #endif { - thd->no_warnings_for_error= 1; List table_names; int res= make_table_name_list(thd, &table_names, lex, &lookup_field_vals, @@ -3619,9 +3657,24 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) if (!(table_open_method & ~OPEN_FRM_ONLY) && !with_i_schema) { - if (!fill_schema_table_from_frm(thd, tables, schema_table, db_name, - table_name, schema_table_idx, - can_deadlock)) + /* + Here we need to filter out warnings, which can happen + during loading of triggers in fill_schema_table_from_frm(), + because we don't need those warnings to pollute output of + SELECT from I_S / SHOW-statements. + */ + + Trigger_error_handler err_handler; + thd->push_internal_handler(&err_handler); + + int res= fill_schema_table_from_frm(thd, tables, schema_table, + db_name, table_name, + schema_table_idx, + can_deadlock); + + thd->pop_internal_handler(); + + if (!res) continue; } @@ -3631,7 +3684,6 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) Set the parent lex of 'sel' because it is needed by sel.init_query() which is called inside make_table_list. */ - thd->no_warnings_for_error= 1; sel.parent_lex= lex; if (make_table_list(thd, &sel, db_name, table_name)) goto err; @@ -6675,6 +6727,92 @@ int make_schema_select(THD *thd, SELECT_LEX *sel, } +/** + Fill INFORMATION_SCHEMA-table, leave correct Diagnostics_area / + Warning_info state after itself. + + This function is a wrapper around ST_SCHEMA_TABLE::fill_table(), which + may "partially silence" some errors. The thing is that during + fill_table() many errors might be emitted. These errors stem from the + nature of fill_table(). + + For example, SELECT ... FROM INFORMATION_SCHEMA.xxx WHERE TABLE_NAME = 'xxx' + results in a number of 'Table .xxx does not exist' errors, + because fill_table() tries to open the 'xxx' table in every possible + database. + + Those errors are cleared (the error status is cleared from + Diagnostics_area) inside fill_table(), but they remain in Warning_info + (Warning_info is not cleared because it may contain useful warnings). + + This function is responsible for making sure that Warning_info does not + contain warnings corresponding to the cleared errors. + + @note: THD::no_warnings_for_error used to be set before calling + fill_table(), thus those errors didn't go to Warning_info. This is not + the case now (THD::no_warnings_for_error was eliminated as a hack), so we + need to take care of those warnings here. + + @param thd Thread context. + @param table_list I_S table. + @param join_table JOIN/SELECT table. + + @return Error status. + @retval TRUE Error. + @retval FALSE Success. +*/ +static bool do_fill_table(THD *thd, + TABLE_LIST *table_list, + JOIN_TAB *join_table) +{ + // NOTE: fill_table() may generate many "useless" warnings, which will be + // ignored afterwards. On the other hand, there might be "useful" + // warnings, which should be presented to the user. Warning_info usually + // stores no more than THD::variables.max_error_count warnings. + // The problem is that "useless warnings" may occupy all the slots in the + // Warning_info, so "useful warnings" get rejected. In order to avoid + // that problem we create a Warning_info instance, which is capable of + // storing "unlimited" number of warnings. + Warning_info wi(thd->query_id, true); + Warning_info *wi_saved= thd->warning_info; + + thd->warning_info= &wi; + + bool res= table_list->schema_table->fill_table( + thd, table_list, join_table->select_cond); + + thd->warning_info= wi_saved; + + // Pass an error if any. + + if (thd->stmt_da->is_error()) + { + thd->warning_info->push_warning(thd, + thd->stmt_da->sql_errno(), + thd->stmt_da->get_sqlstate(), + MYSQL_ERROR::WARN_LEVEL_ERROR, + thd->stmt_da->message()); + } + + // Pass warnings (if any). + // + // Filter out warnings with WARN_LEVEL_ERROR level, because they + // correspond to the errors which were filtered out in fill_table(). + + + List_iterator_fast it(wi.warn_list()); + MYSQL_ERROR *err; + + while ((err= it++)) + { + if (err->get_level() != MYSQL_ERROR::WARN_LEVEL_ERROR) + thd->warning_info->push_warning(thd, err); + } + + return res; +} + + /* Fill temporary schema tables before SELECT @@ -6697,7 +6835,6 @@ bool get_schema_tables_result(JOIN *join, bool result= 0; DBUG_ENTER("get_schema_tables_result"); - thd->no_warnings_for_error= 1; for (JOIN_TAB *tab= join->join_tab; tab < tmp_join_tab; tab++) { if (!tab->table || !tab->table->pos_in_table_list) @@ -6748,8 +6885,7 @@ bool get_schema_tables_result(JOIN *join, else table_list->table->file->stats.records= 0; - if (table_list->schema_table->fill_table(thd, table_list, - tab->select_cond)) + if (do_fill_table(thd, table_list, tab)) { result= 1; join->error= 1; @@ -6761,7 +6897,6 @@ bool get_schema_tables_result(JOIN *join, table_list->schema_table_state= executed_place; } } - thd->no_warnings_for_error= 0; DBUG_RETURN(result); } -- cgit v1.2.1 From 733893ba502cfd1378ece9c1e0dbae98bf7ba9df Mon Sep 17 00:00:00 2001 From: Dmitry Shulga Date: Fri, 20 May 2011 23:52:52 +0700 Subject: Fixed bug#11749345 (formerly bug#38813) - increasing memory consumption when selecting from I_S and views exist, in SP. Symptoms: re-execution of prepared statement (or statement in a stored routine) which read from one of I_S tables and which in order to fill this I_S table had to open a view led to increasing memory consumption. What happened in this situation was that during the process of view opening for purpose of I_S filling view-related structures (like its LEX) were allocated on persistent MEM_ROOT of prepared statement (or stored routine). Since this MEM_ROOT is not freed until prepared statement deallocation (or expulsion of stored routine from the cache) and code responsible for filling I_S is not able to re-use results of view opening from previous executions this allocation ended up in memory hogging. This patch solves the problem by ensuring that when a view opened for the purpose of I_S filling all its structures are allocated on non-persistent runtime MEM_ROOT. This is achieved by activating a temporary Query_arena bound to this MEM_ROOT. Since this step makes impossible linking of view structures into LEX of our prepared statement (or stored routine statement) this patch also changes code filling I_S table to install a proxy LEX before trying to open a view or a table. Consequently some code which was responsible for backing-up/restoring parts of LEX when view/table was opened during filling of I_S table became redundant and was removed. This patch doesn't contain test case for this bug as it is hard to test memory hogging in our test suite. --- sql/sql_show.cc | 320 +++++++++++++++++++++++++++++++------------------------- 1 file changed, 180 insertions(+), 140 deletions(-) (limited to 'sql/sql_show.cc') diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 5b835096042..310ec3b8e4f 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2428,12 +2428,11 @@ bool schema_table_store_record(THD *thd, TABLE *table) } -int make_table_list(THD *thd, SELECT_LEX *sel, - LEX_STRING *db_name, LEX_STRING *table_name) +static int make_table_list(THD *thd, SELECT_LEX *sel, + LEX_STRING *db_name, LEX_STRING *table_name) { Table_ident *table_ident; table_ident= new Table_ident(thd, *db_name, *table_name, 1); - sel->init_query(); if (!sel->add_table_to_list(thd, table_ident, 0, 0, TL_READ)) return 1; return 0; @@ -3003,79 +3002,179 @@ make_table_name_list(THD *thd, List *table_names, LEX *lex, /** - @brief Fill I_S table for SHOW COLUMNS|INDEX commands + Fill I_S table with data obtained by performing full-blown table open. + + @param thd Thread handler. + @param is_show_fields_or_keys Indicates whether it is a legacy SHOW + COLUMNS or SHOW KEYS statement. + @param table TABLE object for I_S table to be filled. + @param schema_table I_S table description structure. + @param orig_db_name Database name. + @param orig_table_name Table name. + @param open_tables_state_backup Open_tables_state object which is used + to save/restore original status of + variables related to open tables state. + + @retval FALSE - Success. + @retval TRUE - Failure. +*/ - @param[in] thd thread handler - @param[in] tables TABLE_LIST for I_S table - @param[in] schema_table pointer to I_S structure - @param[in] open_tables_state_backup pointer to Open_tables_state object - which is used to save|restore original - status of variables related to - open tables state +static bool +fill_schema_table_by_open(THD *thd, bool is_show_fields_or_keys, + TABLE *table, ST_SCHEMA_TABLE *schema_table, + LEX_STRING *orig_db_name, + LEX_STRING *orig_table_name, + Open_tables_state *open_tables_state_backup) +{ + Query_arena i_s_arena(thd->mem_root, + Query_arena::CONVENTIONAL_EXECUTION), + backup_arena, *old_arena; + LEX *old_lex= thd->lex, temp_lex, *lex; + LEX_STRING db_name, table_name; + TABLE_LIST *table_list; + bool result= true; - @return Operation status - @retval 0 success - @retval 1 error -*/ + /* + When a view is opened its structures are allocated on a permanent + statement arena and linked into the LEX tree for the current statement + (this happens even in cases when view is handled through TEMPTABLE + algorithm). -static int -fill_schema_show_cols_or_idxs(THD *thd, TABLE_LIST *tables, - ST_SCHEMA_TABLE *schema_table, - Open_tables_state *open_tables_state_backup) -{ - LEX *lex= thd->lex; - bool res; - LEX_STRING tmp_lex_string, tmp_lex_string1, *db_name, *table_name; - enum_sql_command save_sql_command= lex->sql_command; - TABLE_LIST *show_table_list= tables->schema_select_lex->table_list.first; - TABLE *table= tables->table; - int error= 1; - DBUG_ENTER("fill_schema_show"); + To prevent this process from unnecessary hogging of memory in the permanent + arena of our I_S query and to avoid damaging its LEX we use temporary + arena and LEX for table/view opening. + + Use temporary arena instead of statement permanent arena. Also make + it active arena and save original one for successive restoring. + */ + old_arena= thd->stmt_arena; + thd->stmt_arena= &i_s_arena; + thd->set_n_backup_active_arena(&i_s_arena, &backup_arena); + + /* Prepare temporary LEX. */ + thd->lex= lex= &temp_lex; + lex_start(thd); + + /* Disable constant subquery evaluation as we won't be locking tables. */ + lex->context_analysis_only= CONTEXT_ANALYSIS_ONLY_VIEW; - lex->all_selects_list= tables->schema_select_lex; /* - Restore thd->temporary_tables to be able to process - temporary tables(only for 'show index' & 'show columns'). - This should be changed when processing of temporary tables for - I_S tables will be done. + Some of process_table() functions rely on wildcard being passed from + old LEX (or at least being initialized). */ - thd->temporary_tables= open_tables_state_backup->temporary_tables; + lex->wild= old_lex->wild; + + /* + Since make_table_list() might change database and table name passed + to it we create copies of orig_db_name and orig_table_name here. + These copies are used for make_table_list() while unaltered values + are passed to process_table() functions. + */ + if (!thd->make_lex_string(&db_name, orig_db_name->str, + orig_db_name->length, FALSE) || + !thd->make_lex_string(&table_name, orig_table_name->str, + orig_table_name->length, FALSE)) + goto end; + + /* + Create table list element for table to be open. Link it with the + temporary LEX. The latter is required to correctly open views and + produce table describing their structure. + */ + if (make_table_list(thd, &lex->select_lex, &db_name, &table_name)) + goto end; + + table_list= lex->select_lex.table_list.first; + + if (is_show_fields_or_keys) + { + /* + Restore thd->temporary_tables to be able to process + temporary tables (only for 'show index' & 'show columns'). + This should be changed when processing of temporary tables for + I_S tables will be done. + */ + thd->temporary_tables= open_tables_state_backup->temporary_tables; + } + else + { + /* + Apply optimization flags for table opening which are relevant for + this I_S table. We can't do this for SHOW COLUMNS/KEYS because of + backward compatibility. + */ + table_list->i_s_requested_object= schema_table->i_s_requested_object; + } + /* Let us set fake sql_command so views won't try to merge themselves into main statement. If we don't do this, SELECT * from information_schema.xxxx will cause problems. - SQLCOM_SHOW_FIELDS is used because it satisfies 'only_view_structure()' + SQLCOM_SHOW_FIELDS is used because it satisfies + 'only_view_structure()'. */ lex->sql_command= SQLCOM_SHOW_FIELDS; - res= open_normal_and_derived_tables(thd, show_table_list, - MYSQL_LOCK_IGNORE_FLUSH); - lex->sql_command= save_sql_command; + + result= open_normal_and_derived_tables(thd, table_list, + MYSQL_LOCK_IGNORE_FLUSH); + /* - get_all_tables() returns 1 on failure and 0 on success thus - return only these and not the result code of ::process_table() - - We should use show_table_list->alias instead of - show_table_list->table_name because table_name - could be changed during opening of I_S tables. It's safe - to use alias because alias contains original table name - in this case(this part of code is used only for - 'show columns' & 'show statistics' commands). + Restore old value of sql_command back as it is being looked at in + process_table() function. */ - table_name= thd->make_lex_string(&tmp_lex_string1, show_table_list->alias, - strlen(show_table_list->alias), FALSE); - if (!show_table_list->view) - db_name= thd->make_lex_string(&tmp_lex_string, show_table_list->db, - show_table_list->db_length, FALSE); - else - db_name= &show_table_list->view_db; - - - error= test(schema_table->process_table(thd, show_table_list, - table, res, db_name, - table_name)); - thd->temporary_tables= 0; - close_tables_for_reopen(thd, &show_table_list); - DBUG_RETURN(error); + lex->sql_command= old_lex->sql_command; + + /* + XXX: show_table_list has a flag i_is_requested, + and when it's set, open_normal_and_derived_tables() + can return an error without setting an error message + in THD, which is a hack. This is why we have to + check for res, then for thd->is_error() and only then + for thd->main_da.sql_errno(). + + Again we don't do this for SHOW COLUMNS/KEYS because + of backward compatibility. + */ + if (!is_show_fields_or_keys && result && thd->is_error() && + thd->main_da.sql_errno() == ER_NO_SUCH_TABLE) + { + /* + Hide error for a non-existing table. + For example, this error can occur when we use a where condition + with a db name and table, but the table does not exist. + */ + result= 0; + thd->clear_error(); + } + else + { + result= schema_table->process_table(thd, table_list, + table, result, + orig_db_name, + orig_table_name); + } + +end: + lex->unit.cleanup(); + + /* Restore original LEX value, statement's arena and THD arena values. */ + lex_end(thd->lex); + + if (i_s_arena.free_list) + i_s_arena.free_items(); + + /* + For safety reset list of open temporary tables before closing + all tables open within this Open_tables_state. + */ + thd->temporary_tables= NULL; + close_thread_tables(thd); + thd->lex= old_lex; + + thd->stmt_arena= old_arena; + thd->restore_active_arena(&i_s_arena, &backup_arena); + + return result; } @@ -3300,11 +3399,8 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) { LEX *lex= thd->lex; TABLE *table= tables->table; - SELECT_LEX *old_all_select_lex= lex->all_selects_list; - enum_sql_command save_sql_command= lex->sql_command; SELECT_LEX *lsel= tables->schema_select_lex; ST_SCHEMA_TABLE *schema_table= tables->schema_table; - SELECT_LEX sel; LOOKUP_FIELD_VALUES lookup_field_vals; LEX_STRING *db_name, *table_name; bool with_i_schema; @@ -3312,20 +3408,14 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) List db_names; List_iterator_fast it(db_names); COND *partial_cond= 0; - uint derived_tables= lex->derived_tables; int error= 1; Open_tables_state open_tables_state_backup; - uint8 save_context_analysis_only= lex->context_analysis_only; - Query_tables_list query_tables_list_backup; #ifndef NO_EMBEDDED_ACCESS_CHECKS Security_context *sctx= thd->security_ctx; #endif uint table_open_method; DBUG_ENTER("get_all_tables"); - lex->context_analysis_only|= CONTEXT_ANALYSIS_ONLY_VIEW; - lex->reset_n_backup_query_tables_list(&query_tables_list_backup); - /* We should not introduce deadlocks even if we already have some tables open and locked, since we won't lock tables which we will @@ -3340,8 +3430,18 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) */ if (lsel && lsel->table_list.first) { - error= fill_schema_show_cols_or_idxs(thd, tables, schema_table, - &open_tables_state_backup); + LEX_STRING db_name, table_name; + + db_name.str= lsel->table_list.first->db; + db_name.length= lsel->table_list.first->db_length; + + table_name.str= lsel->table_list.first->table_name; + table_name.length= lsel->table_list.first->table_name_length; + + error= fill_schema_table_by_open(thd, TRUE, + table, schema_table, + &db_name, &table_name, + &open_tables_state_backup); goto err; } @@ -3399,12 +3499,6 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) it.rewind(); /* To get access to new elements in basis list */ while ((db_name= it++)) { - LEX_STRING orig_db_name; - - /* db_name can be changed in make_table_list() func */ - if (!thd->make_lex_string(&orig_db_name, db_name->str, - db_name->length, FALSE)) - goto err; #ifndef NO_EMBEDDED_ACCESS_CHECKS if (!(check_access(thd,SELECT_ACL, db_name->str, &thd->col_access, 0, 1, with_i_schema) || @@ -3466,64 +3560,14 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) continue; } - int res; - LEX_STRING tmp_lex_string; - /* - Set the parent lex of 'sel' because it is needed by - sel.init_query() which is called inside make_table_list. - */ thd->no_warnings_for_error= 1; - sel.parent_lex= lex; - if (make_table_list(thd, &sel, db_name, table_name)) - goto err; - TABLE_LIST *show_table_list= sel.table_list.first; - lex->all_selects_list= &sel; - lex->derived_tables= 0; - lex->sql_command= SQLCOM_SHOW_FIELDS; - show_table_list->i_s_requested_object= - schema_table->i_s_requested_object; + DEBUG_SYNC(thd, "before_open_in_get_all_tables"); - res= open_normal_and_derived_tables(thd, show_table_list, - MYSQL_LOCK_IGNORE_FLUSH); - lex->sql_command= save_sql_command; - /* - XXX: show_table_list has a flag i_is_requested, - and when it's set, open_normal_and_derived_tables() - can return an error without setting an error message - in THD, which is a hack. This is why we have to - check for res, then for thd->is_error() only then - for thd->main_da.sql_errno(). - */ - if (res && thd->is_error() && - thd->main_da.sql_errno() == ER_NO_SUCH_TABLE) - { - /* - Hide error for not existing table. - This error can occur for example when we use - where condition with db name and table name and this - table does not exist. - */ - res= 0; - thd->clear_error(); - } - else - { - /* - We should use show_table_list->alias instead of - show_table_list->table_name because table_name - could be changed during opening of I_S tables. It's safe - to use alias because alias contains original table name - in this case. - */ - thd->make_lex_string(&tmp_lex_string, show_table_list->alias, - strlen(show_table_list->alias), FALSE); - res= schema_table->process_table(thd, show_table_list, table, - res, &orig_db_name, - &tmp_lex_string); - close_tables_for_reopen(thd, &show_table_list); - } - DBUG_ASSERT(!lex->query_tables_own_last); - if (res) + + if (fill_schema_table_by_open(thd, FALSE, + table, schema_table, + db_name, table_name, + &open_tables_state_backup)) goto err; } } @@ -3539,11 +3583,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) error= 0; err: thd->restore_backup_open_tables_state(&open_tables_state_backup); - lex->restore_backup_query_tables_list(&query_tables_list_backup); - lex->derived_tables= derived_tables; - lex->all_selects_list= old_all_select_lex; - lex->context_analysis_only= save_context_analysis_only; - lex->sql_command= save_sql_command; + DBUG_RETURN(error); } -- cgit v1.2.1 From 876fd28402286a4273ffd441aef18166b998f06f Mon Sep 17 00:00:00 2001 From: Dmitry Shulga Date: Wed, 25 May 2011 23:44:08 +0700 Subject: Follow-up for patch for bug#11749345. sql/sql_show.cc: Restored DEBUG_SYNC point missed during merge 5.1->5.5 --- sql/sql_show.cc | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sql/sql_show.cc') diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 61a2287419c..fb5ed62ecdf 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -3766,6 +3766,8 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) continue; } + DEBUG_SYNC(thd, "before_open_in_get_all_tables"); + if (fill_schema_table_by_open(thd, FALSE, table, schema_table, db_name, table_name, -- cgit v1.2.1