You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1583 lines
43 KiB

Fix all warnings given by UBSAN The easiest way to compile and test the server with UBSAN is to run: ./BUILD/compile-pentium64-ubsan and then run mysql-test-run. After this commit, one should be able to run this without any UBSAN warnings. There is still a few compiler warnings that should be fixed at some point, but these do not expose any real bugs. The 'special' cases where we disable, suppress or circumvent UBSAN are: - ref10 source (as here we intentionally do some shifts that UBSAN complains about. - x86 version of optimized int#korr() methods. UBSAN do not like unaligned memory access of integers. Fixed by using byte_order_generic.h when compiling with UBSAN - We use smaller thread stack with ASAN and UBSAN, which forced me to disable a few tests that prints the thread stack size. - Verifying class types does not work for shared libraries. I added suppression in mysql-test-run.pl for this case. - Added '#ifdef WITH_UBSAN' when using integer arithmetic where it is safe to have overflows (two cases, in item_func.cc). Things fixed: - Don't left shift signed values (byte_order_generic.h, mysqltest.c, item_sum.cc and many more) - Don't assign not non existing values to enum variables. - Ensure that bool and enum values are properly initialized in constructors. This was needed as UBSAN checks that these types has correct values when one copies an object. (gcalc_tools.h, ha_partition.cc, item_sum.cc, partition_element.h ...) - Ensure we do not called handler functions on unallocated objects or deleted objects. (events.cc, sql_acl.cc). - Fixed bugs in Item_sp::Item_sp() where we did not call constructor on Query_arena object. - Fixed several cast of objects to an incompatible class! (Item.cc, Item_buff.cc, item_timefunc.cc, opt_subselect.cc, sql_acl.cc, sql_select.cc ...) - Ensure we do not do integer arithmetic that causes over or underflows. This includes also ++ and -- of integers. (Item_func.cc, Item_strfunc.cc, item_timefunc.cc, sql_base.cc ...) - Added JSON_VALUE_UNITIALIZED to json_value_types and ensure that value_type is initialized to this instead of to -1, which is not a valid enum value for json_value_types. - Ensure we do not call memcpy() when second argument could be null. - Fixed that Item_func_str::make_empty_result() creates an empty string instead of a null string (safer as it ensures we do not do arithmetic on null strings). Other things: - Changed struct st_position to an OBJECT and added an initialization function to it to ensure that we do not copy or use uninitialized members. The change to a class was also motived that we used "struct st_position" and POSITION randomly trough the code which was confusing. - Notably big rewrite in sql_acl.cc to avoid using deleted objects. - Changed in sql_partition to use '^' instead of '-'. This is safe as the operator is either 0 or 0x8000000000000000ULL. - Added check for select_nr < INT_MAX in JOIN::build_explain() to avoid bug when get_select() could return NULL. - Reordered elements in POSITION for better alignment. - Changed sql_test.cc::print_plan() to use pointers instead of objects. - Fixed bug in find_set() where could could execute '1 << -1'. - Added variable have_sanitizer, used by mtr. (This variable was before only in 10.5 and up). It can now have one of two values: ASAN or UBSAN. - Moved ~Archive_share() from ha_archive.cc to ha_archive.h and marked it virtual. This was an effort to get UBSAN to work with loaded storage engines. I kept the change as the new place is better. - Added in CONNECT engine COLBLK::SetName(), to get around a wrong cast in tabutil.cpp. - Added HAVE_REPLICATION around usage of rgi_slave, to get embedded server to compile with UBSAN. (Patch from Marko). - Added #ifdef for powerpc64 to avoid a bug in old gcc versions related to integer arithmetic. Changes that should not be needed but had to be done to suppress warnings from UBSAN: - Added static_cast<<uint16_t>> around shift to get rid of a LOT of compiler warnings when using UBSAN. - Had to change some '/' of 2 base integers to shift to get rid of some compile time warnings. Reviewed by: - Json changes: Alexey Botchkov - Charset changes in ctype-uca.c: Alexander Barkov - InnoDB changes & Embedded server: Marko Mäkelä - sql_acl.cc changes: Vicențiu Ciorbaru - build_explain() changes: Sergey Petrunia
5 years ago
MDEV-10139 Support for SEQUENCE objects Working features: CREATE OR REPLACE [TEMPORARY] SEQUENCE [IF NOT EXISTS] name [ INCREMENT [ BY | = ] increment ] [ MINVALUE [=] minvalue | NO MINVALUE ] [ MAXVALUE [=] maxvalue | NO MAXVALUE ] [ START [ WITH | = ] start ] [ CACHE [=] cache ] [ [ NO ] CYCLE ] ENGINE=xxx COMMENT=".." SELECT NEXT VALUE FOR sequence_name; SELECT NEXTVAL(sequence_name); SELECT PREVIOUS VALUE FOR sequence_name; SELECT LASTVAL(sequence_name); SHOW CREATE SEQUENCE sequence_name; SHOW CREATE TABLE sequence_name; CREATE TABLE sequence-structure ... SEQUENCE=1 ALTER TABLE sequence RENAME TO sequence2; RENAME TABLE sequence TO sequence2; DROP [TEMPORARY] SEQUENCE [IF EXISTS] sequence_names Missing features - SETVAL(value,sequence_name), to be used with replication. - Check replication, including checking that sequence tables are marked not transactional. - Check that a commit happens for NEXT VALUE that changes table data (may already work) - ALTER SEQUENCE. ANSI SQL version of setval. - Share identical sequence entries to not add things twice to table list. - testing insert/delete/update/truncate/load data - Run and fix Alibaba sequence tests (part of mysql-test/suite/sql_sequence) - Write documentation for NEXT VALUE / PREVIOUS_VALUE - NEXTVAL in DEFAULT - Ensure that NEXTVAL in DEFAULT uses database from base table - Two NEXTVAL for same row should give same answer. - Oracle syntax sequence_table.nextval, without any FOR or FROM. - Sequence tables are treated as 'not read constant tables' by SELECT; Would be better if we would have a separate list for sequence tables so that select doesn't know about them, except if refereed to with FROM. Other things done: - Improved output for safemalloc backtrack - frm_type_enum changed to Table_type - Removed lex->is_view and replaced with lex->table_type. This allows use to more easy check if item is view, sequence or table. - Added table flag HA_CAN_TABLES_WITHOUT_ROLLBACK, needed for handlers that want's to support sequences - Added handler calls: - engine_name(), to simplify getting engine name for partition and sequences - update_first_row(), to be able to do efficient sequence implementations. - Made binlog_log_row() global to be able to call it from ha_sequence.cc - Added handler variable: row_already_logged, to be able to flag that the changed row is already logging to replication log. - Added CF_DB_CHANGE and CF_SCHEMA_CHANGE flags to simplify deny_updates_if_read_only_option() - Added sp_add_cfetch() to avoid new conflicts in sql_yacc.yy - Moved code for add_table_options() out from sql_show.cc::show_create_table() - Added String::append_longlong() and used it in sql_show.cc to simplify code. - Added extra option to dd_frm_type() and ha_table_exists to indicate if the table is a sequence. Needed by DROP SQUENCE to not drop a table.
9 years ago
MDEV-10139 Support for SEQUENCE objects Working features: CREATE OR REPLACE [TEMPORARY] SEQUENCE [IF NOT EXISTS] name [ INCREMENT [ BY | = ] increment ] [ MINVALUE [=] minvalue | NO MINVALUE ] [ MAXVALUE [=] maxvalue | NO MAXVALUE ] [ START [ WITH | = ] start ] [ CACHE [=] cache ] [ [ NO ] CYCLE ] ENGINE=xxx COMMENT=".." SELECT NEXT VALUE FOR sequence_name; SELECT NEXTVAL(sequence_name); SELECT PREVIOUS VALUE FOR sequence_name; SELECT LASTVAL(sequence_name); SHOW CREATE SEQUENCE sequence_name; SHOW CREATE TABLE sequence_name; CREATE TABLE sequence-structure ... SEQUENCE=1 ALTER TABLE sequence RENAME TO sequence2; RENAME TABLE sequence TO sequence2; DROP [TEMPORARY] SEQUENCE [IF EXISTS] sequence_names Missing features - SETVAL(value,sequence_name), to be used with replication. - Check replication, including checking that sequence tables are marked not transactional. - Check that a commit happens for NEXT VALUE that changes table data (may already work) - ALTER SEQUENCE. ANSI SQL version of setval. - Share identical sequence entries to not add things twice to table list. - testing insert/delete/update/truncate/load data - Run and fix Alibaba sequence tests (part of mysql-test/suite/sql_sequence) - Write documentation for NEXT VALUE / PREVIOUS_VALUE - NEXTVAL in DEFAULT - Ensure that NEXTVAL in DEFAULT uses database from base table - Two NEXTVAL for same row should give same answer. - Oracle syntax sequence_table.nextval, without any FOR or FROM. - Sequence tables are treated as 'not read constant tables' by SELECT; Would be better if we would have a separate list for sequence tables so that select doesn't know about them, except if refereed to with FROM. Other things done: - Improved output for safemalloc backtrack - frm_type_enum changed to Table_type - Removed lex->is_view and replaced with lex->table_type. This allows use to more easy check if item is view, sequence or table. - Added table flag HA_CAN_TABLES_WITHOUT_ROLLBACK, needed for handlers that want's to support sequences - Added handler calls: - engine_name(), to simplify getting engine name for partition and sequences - update_first_row(), to be able to do efficient sequence implementations. - Made binlog_log_row() global to be able to call it from ha_sequence.cc - Added handler variable: row_already_logged, to be able to flag that the changed row is already logging to replication log. - Added CF_DB_CHANGE and CF_SCHEMA_CHANGE flags to simplify deny_updates_if_read_only_option() - Added sp_add_cfetch() to avoid new conflicts in sql_yacc.yy - Moved code for add_table_options() out from sql_show.cc::show_create_table() - Added String::append_longlong() and used it in sql_show.cc to simplify code. - Added extra option to dd_frm_type() and ha_table_exists to indicate if the table is a sequence. Needed by DROP SQUENCE to not drop a table.
9 years ago
MDEV-19076: rpl_parallel_temptable result mismatch '-33 optimistic' Problem: ======== The test now fails with the following trace: CURRENT_TEST: rpl.rpl_parallel_temptable --- /mariadb/10.4/mysql-test/suite/rpl/r/rpl_parallel_temptable.result +++ /mariadb/10.4/mysql-test/suite/rpl/r/rpl_parallel_temptable.reject @@ -194,7 +194,6 @@ 30 conservative 31 conservative 32 optimistic -33 optimistic Analysis: ========= The part of test which fails with result content mismatch is given below. CREATE TEMPORARY TABLE t4 (a INT PRIMARY KEY) ENGINE=InnoDB; INSERT INTO t4 VALUES (32); INSERT INTO t4 VALUES (33); INSERT INTO t1 SELECT a, "optimistic" FROM t4; slave_parallel_mode=optimistic The expectation of the above test script is, INSERT FROM SELECT should read both 32, 33 and populate table 't1'. But this expectation fails occasionally. All three INSERT statements are handed over to three different slave parallel workers. Temporary tables are not safe for parallel replication. They were designed to be visible to one thread only, so have no table locking. Thus there is no protection against two conflicting transactions committing in parallel and things like that. So anything that uses temporary tables will be serialized with anything before it, when using parallel replication by using a "wait_for_prior_commit" function call. This will ensure that the each transaction is executed sequentially. But there exists a code path in which the above wait doesn't happen. Because of this at times INSERT from SELECT doesn't wait for the INSERT (33) to complete and it completes its executes and enters commit stage. Hence only row 32 is found in those cases resulting in test failure. The wait needs to be added within "open_temporary_table" call. The code looks like this within "open_temporary_table". Each thread tries to open temporary table in 3 different ways: case 1: Find a temporary table which is already in use by using find_temporary_table(tl) && wait_for_prior_commit() case 2: If above failed then try to look for temporary table which is marked for free for reuse. This internally calls "wait_for_prior_commit()" if table is found. find_and_use_tmp_table(tl, &table) case 3: If none of the above open a new table handle from table share. if (!table && (share= find_tmp_table_share(tl))) { table= open_temporary_table(share, tl->get_table_name(), true); } At present the "wait_for_prior_commit" happens only in case 1 & 2. Fix: ==== On slave add a call for "wait_for_prior_commit" for case 3. The above wait on slave will solve the issue. A more detailed fix would be to mark temporary tables as not safe for parallel execution on the master side. In order to do that, on the master side, mark the Gtid_log_event specific flag FL_TRANSACTIONAL to be false all the time. So that they are not scheduled parallely.
7 years ago
Fix all warnings given by UBSAN The easiest way to compile and test the server with UBSAN is to run: ./BUILD/compile-pentium64-ubsan and then run mysql-test-run. After this commit, one should be able to run this without any UBSAN warnings. There is still a few compiler warnings that should be fixed at some point, but these do not expose any real bugs. The 'special' cases where we disable, suppress or circumvent UBSAN are: - ref10 source (as here we intentionally do some shifts that UBSAN complains about. - x86 version of optimized int#korr() methods. UBSAN do not like unaligned memory access of integers. Fixed by using byte_order_generic.h when compiling with UBSAN - We use smaller thread stack with ASAN and UBSAN, which forced me to disable a few tests that prints the thread stack size. - Verifying class types does not work for shared libraries. I added suppression in mysql-test-run.pl for this case. - Added '#ifdef WITH_UBSAN' when using integer arithmetic where it is safe to have overflows (two cases, in item_func.cc). Things fixed: - Don't left shift signed values (byte_order_generic.h, mysqltest.c, item_sum.cc and many more) - Don't assign not non existing values to enum variables. - Ensure that bool and enum values are properly initialized in constructors. This was needed as UBSAN checks that these types has correct values when one copies an object. (gcalc_tools.h, ha_partition.cc, item_sum.cc, partition_element.h ...) - Ensure we do not called handler functions on unallocated objects or deleted objects. (events.cc, sql_acl.cc). - Fixed bugs in Item_sp::Item_sp() where we did not call constructor on Query_arena object. - Fixed several cast of objects to an incompatible class! (Item.cc, Item_buff.cc, item_timefunc.cc, opt_subselect.cc, sql_acl.cc, sql_select.cc ...) - Ensure we do not do integer arithmetic that causes over or underflows. This includes also ++ and -- of integers. (Item_func.cc, Item_strfunc.cc, item_timefunc.cc, sql_base.cc ...) - Added JSON_VALUE_UNITIALIZED to json_value_types and ensure that value_type is initialized to this instead of to -1, which is not a valid enum value for json_value_types. - Ensure we do not call memcpy() when second argument could be null. - Fixed that Item_func_str::make_empty_result() creates an empty string instead of a null string (safer as it ensures we do not do arithmetic on null strings). Other things: - Changed struct st_position to an OBJECT and added an initialization function to it to ensure that we do not copy or use uninitialized members. The change to a class was also motived that we used "struct st_position" and POSITION randomly trough the code which was confusing. - Notably big rewrite in sql_acl.cc to avoid using deleted objects. - Changed in sql_partition to use '^' instead of '-'. This is safe as the operator is either 0 or 0x8000000000000000ULL. - Added check for select_nr < INT_MAX in JOIN::build_explain() to avoid bug when get_select() could return NULL. - Reordered elements in POSITION for better alignment. - Changed sql_test.cc::print_plan() to use pointers instead of objects. - Fixed bug in find_set() where could could execute '1 << -1'. - Added variable have_sanitizer, used by mtr. (This variable was before only in 10.5 and up). It can now have one of two values: ASAN or UBSAN. - Moved ~Archive_share() from ha_archive.cc to ha_archive.h and marked it virtual. This was an effort to get UBSAN to work with loaded storage engines. I kept the change as the new place is better. - Added in CONNECT engine COLBLK::SetName(), to get around a wrong cast in tabutil.cpp. - Added HAVE_REPLICATION around usage of rgi_slave, to get embedded server to compile with UBSAN. (Patch from Marko). - Added #ifdef for powerpc64 to avoid a bug in old gcc versions related to integer arithmetic. Changes that should not be needed but had to be done to suppress warnings from UBSAN: - Added static_cast<<uint16_t>> around shift to get rid of a LOT of compiler warnings when using UBSAN. - Had to change some '/' of 2 base integers to shift to get rid of some compile time warnings. Reviewed by: - Json changes: Alexey Botchkov - Charset changes in ctype-uca.c: Alexander Barkov - InnoDB changes & Embedded server: Marko Mäkelä - sql_acl.cc changes: Vicențiu Ciorbaru - build_explain() changes: Sergey Petrunia
5 years ago
MDEV-10139 Support for SEQUENCE objects Working features: CREATE OR REPLACE [TEMPORARY] SEQUENCE [IF NOT EXISTS] name [ INCREMENT [ BY | = ] increment ] [ MINVALUE [=] minvalue | NO MINVALUE ] [ MAXVALUE [=] maxvalue | NO MAXVALUE ] [ START [ WITH | = ] start ] [ CACHE [=] cache ] [ [ NO ] CYCLE ] ENGINE=xxx COMMENT=".." SELECT NEXT VALUE FOR sequence_name; SELECT NEXTVAL(sequence_name); SELECT PREVIOUS VALUE FOR sequence_name; SELECT LASTVAL(sequence_name); SHOW CREATE SEQUENCE sequence_name; SHOW CREATE TABLE sequence_name; CREATE TABLE sequence-structure ... SEQUENCE=1 ALTER TABLE sequence RENAME TO sequence2; RENAME TABLE sequence TO sequence2; DROP [TEMPORARY] SEQUENCE [IF EXISTS] sequence_names Missing features - SETVAL(value,sequence_name), to be used with replication. - Check replication, including checking that sequence tables are marked not transactional. - Check that a commit happens for NEXT VALUE that changes table data (may already work) - ALTER SEQUENCE. ANSI SQL version of setval. - Share identical sequence entries to not add things twice to table list. - testing insert/delete/update/truncate/load data - Run and fix Alibaba sequence tests (part of mysql-test/suite/sql_sequence) - Write documentation for NEXT VALUE / PREVIOUS_VALUE - NEXTVAL in DEFAULT - Ensure that NEXTVAL in DEFAULT uses database from base table - Two NEXTVAL for same row should give same answer. - Oracle syntax sequence_table.nextval, without any FOR or FROM. - Sequence tables are treated as 'not read constant tables' by SELECT; Would be better if we would have a separate list for sequence tables so that select doesn't know about them, except if refereed to with FROM. Other things done: - Improved output for safemalloc backtrack - frm_type_enum changed to Table_type - Removed lex->is_view and replaced with lex->table_type. This allows use to more easy check if item is view, sequence or table. - Added table flag HA_CAN_TABLES_WITHOUT_ROLLBACK, needed for handlers that want's to support sequences - Added handler calls: - engine_name(), to simplify getting engine name for partition and sequences - update_first_row(), to be able to do efficient sequence implementations. - Made binlog_log_row() global to be able to call it from ha_sequence.cc - Added handler variable: row_already_logged, to be able to flag that the changed row is already logging to replication log. - Added CF_DB_CHANGE and CF_SCHEMA_CHANGE flags to simplify deny_updates_if_read_only_option() - Added sp_add_cfetch() to avoid new conflicts in sql_yacc.yy - Moved code for add_table_options() out from sql_show.cc::show_create_table() - Added String::append_longlong() and used it in sql_show.cc to simplify code. - Added extra option to dd_frm_type() and ha_table_exists to indicate if the table is a sequence. Needed by DROP SQUENCE to not drop a table.
9 years ago
Clean up and speed up interfaces for binary row logging MDEV-21605 Clean up and speed up interfaces for binary row logging MDEV-21617 Bug fix for previous version of this code The intention is to have as few 'if' as possible in ha_write() and related functions. This is done by pre-calculating once per statement the row_logging state for all tables. Benefits are simpler and faster code both when binary logging is disabled and when it's enabled. Changes: - Added handler->row_logging to make it easy to check it table should be row logged. This also made it easier to disabling row logging for system, internal and temporary tables. - The tables row_logging capabilities are checked once per "statements that updates tables" in THD::binlog_prepare_for_row_logging() which is called when needed from THD::decide_logging_format(). - Removed most usage of tmp_disable_binlog(), reenable_binlog() and temporary saving and setting of thd->variables.option_bits. - Moved checks that can't change during a statement from check_table_binlog_row_based() to check_table_binlog_row_based_internal() - Removed flag row_already_logged (used by sequence engine) - Moved binlog_log_row() to a handler:: - Moved write_locked_table_maps() to THD::binlog_write_table_maps() as most other related binlog functions are in THD. - Removed binlog_write_table_map() and binlog_log_row_internal() as they are now obsolete as 'has_transactions()' is pre-calculated in prepare_for_row_logging(). - Remove 'is_transactional' argument from binlog_write_table_map() as this can now be read from handler. - Changed order of 'if's in handler::external_lock() and wsrep_mysqld.h to first evaluate fast and likely cases before more complex ones. - Added error checking in ha_write_row() and related functions if binlog_log_row() failed. - Don't clear check_table_binlog_row_based_result in clear_cached_table_binlog_row_based_flag() as it's not needed. - THD::clear_binlog_table_maps() has been replaced with THD::reset_binlog_for_next_statement() - Added 'MYSQL_OPEN_IGNORE_LOGGING_FORMAT' flag to open_and_lock_tables() to avoid calculating of binary log format for internal opens. This flag is also used to avoid reading statistics tables for internal tables. - Added OPTION_BINLOG_LOG_OFF as a simple way to turn of binlog temporary for create (instead of using THD::sql_log_bin_off. - Removed flag THD::sql_log_bin_off (not needed anymore) - Speed up THD::decide_logging_format() by remembering if blackhole engine is used and avoid a loop over all tables if it's not used (the common case). - THD::decide_logging_format() is not called anymore if no tables are used for the statement. This will speed up pure stored procedure code with about 5%+ according to some simple tests. - We now get annotated events on slave if a CREATE ... SELECT statement is transformed on the slave from statement to row logging. - In the original code, the master could come into a state where row logging is enforced for all future events if statement could be used. This is now partly fixed. Other changes: - Ensure that all tables used by a statement has query_id set. - Had to restore the row_logging flag for not used tables in THD::binlog_write_table_maps (not normal scenario) - Removed injector::transaction::use_table(server_id_type sid, table tbl) as it's not used. - Cleaned up set_slave_thread_options() - Some more DBUG_ENTER/DBUG_RETURN, code comments and minor indentation changes. - Ensure we only call THD::decide_logging_format_low() once in mysql_insert() (inefficiency). - Don't annotate INSERT DELAYED - Removed zeroing pos_in_table_list in THD::open_temporary_table() as it's already 0
6 years ago
MDEV-10139 Support for SEQUENCE objects Working features: CREATE OR REPLACE [TEMPORARY] SEQUENCE [IF NOT EXISTS] name [ INCREMENT [ BY | = ] increment ] [ MINVALUE [=] minvalue | NO MINVALUE ] [ MAXVALUE [=] maxvalue | NO MAXVALUE ] [ START [ WITH | = ] start ] [ CACHE [=] cache ] [ [ NO ] CYCLE ] ENGINE=xxx COMMENT=".." SELECT NEXT VALUE FOR sequence_name; SELECT NEXTVAL(sequence_name); SELECT PREVIOUS VALUE FOR sequence_name; SELECT LASTVAL(sequence_name); SHOW CREATE SEQUENCE sequence_name; SHOW CREATE TABLE sequence_name; CREATE TABLE sequence-structure ... SEQUENCE=1 ALTER TABLE sequence RENAME TO sequence2; RENAME TABLE sequence TO sequence2; DROP [TEMPORARY] SEQUENCE [IF EXISTS] sequence_names Missing features - SETVAL(value,sequence_name), to be used with replication. - Check replication, including checking that sequence tables are marked not transactional. - Check that a commit happens for NEXT VALUE that changes table data (may already work) - ALTER SEQUENCE. ANSI SQL version of setval. - Share identical sequence entries to not add things twice to table list. - testing insert/delete/update/truncate/load data - Run and fix Alibaba sequence tests (part of mysql-test/suite/sql_sequence) - Write documentation for NEXT VALUE / PREVIOUS_VALUE - NEXTVAL in DEFAULT - Ensure that NEXTVAL in DEFAULT uses database from base table - Two NEXTVAL for same row should give same answer. - Oracle syntax sequence_table.nextval, without any FOR or FROM. - Sequence tables are treated as 'not read constant tables' by SELECT; Would be better if we would have a separate list for sequence tables so that select doesn't know about them, except if refereed to with FROM. Other things done: - Improved output for safemalloc backtrack - frm_type_enum changed to Table_type - Removed lex->is_view and replaced with lex->table_type. This allows use to more easy check if item is view, sequence or table. - Added table flag HA_CAN_TABLES_WITHOUT_ROLLBACK, needed for handlers that want's to support sequences - Added handler calls: - engine_name(), to simplify getting engine name for partition and sequences - update_first_row(), to be able to do efficient sequence implementations. - Made binlog_log_row() global to be able to call it from ha_sequence.cc - Added handler variable: row_already_logged, to be able to flag that the changed row is already logging to replication log. - Added CF_DB_CHANGE and CF_SCHEMA_CHANGE flags to simplify deny_updates_if_read_only_option() - Added sp_add_cfetch() to avoid new conflicts in sql_yacc.yy - Moved code for add_table_options() out from sql_show.cc::show_create_table() - Added String::append_longlong() and used it in sql_show.cc to simplify code. - Added extra option to dd_frm_type() and ha_table_exists to indicate if the table is a sequence. Needed by DROP SQUENCE to not drop a table.
9 years ago
Fix all warnings given by UBSAN The easiest way to compile and test the server with UBSAN is to run: ./BUILD/compile-pentium64-ubsan and then run mysql-test-run. After this commit, one should be able to run this without any UBSAN warnings. There is still a few compiler warnings that should be fixed at some point, but these do not expose any real bugs. The 'special' cases where we disable, suppress or circumvent UBSAN are: - ref10 source (as here we intentionally do some shifts that UBSAN complains about. - x86 version of optimized int#korr() methods. UBSAN do not like unaligned memory access of integers. Fixed by using byte_order_generic.h when compiling with UBSAN - We use smaller thread stack with ASAN and UBSAN, which forced me to disable a few tests that prints the thread stack size. - Verifying class types does not work for shared libraries. I added suppression in mysql-test-run.pl for this case. - Added '#ifdef WITH_UBSAN' when using integer arithmetic where it is safe to have overflows (two cases, in item_func.cc). Things fixed: - Don't left shift signed values (byte_order_generic.h, mysqltest.c, item_sum.cc and many more) - Don't assign not non existing values to enum variables. - Ensure that bool and enum values are properly initialized in constructors. This was needed as UBSAN checks that these types has correct values when one copies an object. (gcalc_tools.h, ha_partition.cc, item_sum.cc, partition_element.h ...) - Ensure we do not called handler functions on unallocated objects or deleted objects. (events.cc, sql_acl.cc). - Fixed bugs in Item_sp::Item_sp() where we did not call constructor on Query_arena object. - Fixed several cast of objects to an incompatible class! (Item.cc, Item_buff.cc, item_timefunc.cc, opt_subselect.cc, sql_acl.cc, sql_select.cc ...) - Ensure we do not do integer arithmetic that causes over or underflows. This includes also ++ and -- of integers. (Item_func.cc, Item_strfunc.cc, item_timefunc.cc, sql_base.cc ...) - Added JSON_VALUE_UNITIALIZED to json_value_types and ensure that value_type is initialized to this instead of to -1, which is not a valid enum value for json_value_types. - Ensure we do not call memcpy() when second argument could be null. - Fixed that Item_func_str::make_empty_result() creates an empty string instead of a null string (safer as it ensures we do not do arithmetic on null strings). Other things: - Changed struct st_position to an OBJECT and added an initialization function to it to ensure that we do not copy or use uninitialized members. The change to a class was also motived that we used "struct st_position" and POSITION randomly trough the code which was confusing. - Notably big rewrite in sql_acl.cc to avoid using deleted objects. - Changed in sql_partition to use '^' instead of '-'. This is safe as the operator is either 0 or 0x8000000000000000ULL. - Added check for select_nr < INT_MAX in JOIN::build_explain() to avoid bug when get_select() could return NULL. - Reordered elements in POSITION for better alignment. - Changed sql_test.cc::print_plan() to use pointers instead of objects. - Fixed bug in find_set() where could could execute '1 << -1'. - Added variable have_sanitizer, used by mtr. (This variable was before only in 10.5 and up). It can now have one of two values: ASAN or UBSAN. - Moved ~Archive_share() from ha_archive.cc to ha_archive.h and marked it virtual. This was an effort to get UBSAN to work with loaded storage engines. I kept the change as the new place is better. - Added in CONNECT engine COLBLK::SetName(), to get around a wrong cast in tabutil.cpp. - Added HAVE_REPLICATION around usage of rgi_slave, to get embedded server to compile with UBSAN. (Patch from Marko). - Added #ifdef for powerpc64 to avoid a bug in old gcc versions related to integer arithmetic. Changes that should not be needed but had to be done to suppress warnings from UBSAN: - Added static_cast<<uint16_t>> around shift to get rid of a LOT of compiler warnings when using UBSAN. - Had to change some '/' of 2 base integers to shift to get rid of some compile time warnings. Reviewed by: - Json changes: Alexey Botchkov - Charset changes in ctype-uca.c: Alexander Barkov - InnoDB changes & Embedded server: Marko Mäkelä - sql_acl.cc changes: Vicențiu Ciorbaru - build_explain() changes: Sergey Petrunia
5 years ago
Fix all warnings given by UBSAN The easiest way to compile and test the server with UBSAN is to run: ./BUILD/compile-pentium64-ubsan and then run mysql-test-run. After this commit, one should be able to run this without any UBSAN warnings. There is still a few compiler warnings that should be fixed at some point, but these do not expose any real bugs. The 'special' cases where we disable, suppress or circumvent UBSAN are: - ref10 source (as here we intentionally do some shifts that UBSAN complains about. - x86 version of optimized int#korr() methods. UBSAN do not like unaligned memory access of integers. Fixed by using byte_order_generic.h when compiling with UBSAN - We use smaller thread stack with ASAN and UBSAN, which forced me to disable a few tests that prints the thread stack size. - Verifying class types does not work for shared libraries. I added suppression in mysql-test-run.pl for this case. - Added '#ifdef WITH_UBSAN' when using integer arithmetic where it is safe to have overflows (two cases, in item_func.cc). Things fixed: - Don't left shift signed values (byte_order_generic.h, mysqltest.c, item_sum.cc and many more) - Don't assign not non existing values to enum variables. - Ensure that bool and enum values are properly initialized in constructors. This was needed as UBSAN checks that these types has correct values when one copies an object. (gcalc_tools.h, ha_partition.cc, item_sum.cc, partition_element.h ...) - Ensure we do not called handler functions on unallocated objects or deleted objects. (events.cc, sql_acl.cc). - Fixed bugs in Item_sp::Item_sp() where we did not call constructor on Query_arena object. - Fixed several cast of objects to an incompatible class! (Item.cc, Item_buff.cc, item_timefunc.cc, opt_subselect.cc, sql_acl.cc, sql_select.cc ...) - Ensure we do not do integer arithmetic that causes over or underflows. This includes also ++ and -- of integers. (Item_func.cc, Item_strfunc.cc, item_timefunc.cc, sql_base.cc ...) - Added JSON_VALUE_UNITIALIZED to json_value_types and ensure that value_type is initialized to this instead of to -1, which is not a valid enum value for json_value_types. - Ensure we do not call memcpy() when second argument could be null. - Fixed that Item_func_str::make_empty_result() creates an empty string instead of a null string (safer as it ensures we do not do arithmetic on null strings). Other things: - Changed struct st_position to an OBJECT and added an initialization function to it to ensure that we do not copy or use uninitialized members. The change to a class was also motived that we used "struct st_position" and POSITION randomly trough the code which was confusing. - Notably big rewrite in sql_acl.cc to avoid using deleted objects. - Changed in sql_partition to use '^' instead of '-'. This is safe as the operator is either 0 or 0x8000000000000000ULL. - Added check for select_nr < INT_MAX in JOIN::build_explain() to avoid bug when get_select() could return NULL. - Reordered elements in POSITION for better alignment. - Changed sql_test.cc::print_plan() to use pointers instead of objects. - Fixed bug in find_set() where could could execute '1 << -1'. - Added variable have_sanitizer, used by mtr. (This variable was before only in 10.5 and up). It can now have one of two values: ASAN or UBSAN. - Moved ~Archive_share() from ha_archive.cc to ha_archive.h and marked it virtual. This was an effort to get UBSAN to work with loaded storage engines. I kept the change as the new place is better. - Added in CONNECT engine COLBLK::SetName(), to get around a wrong cast in tabutil.cpp. - Added HAVE_REPLICATION around usage of rgi_slave, to get embedded server to compile with UBSAN. (Patch from Marko). - Added #ifdef for powerpc64 to avoid a bug in old gcc versions related to integer arithmetic. Changes that should not be needed but had to be done to suppress warnings from UBSAN: - Added static_cast<<uint16_t>> around shift to get rid of a LOT of compiler warnings when using UBSAN. - Had to change some '/' of 2 base integers to shift to get rid of some compile time warnings. Reviewed by: - Json changes: Alexey Botchkov - Charset changes in ctype-uca.c: Alexander Barkov - InnoDB changes & Embedded server: Marko Mäkelä - sql_acl.cc changes: Vicențiu Ciorbaru - build_explain() changes: Sergey Petrunia
5 years ago
Fix all warnings given by UBSAN The easiest way to compile and test the server with UBSAN is to run: ./BUILD/compile-pentium64-ubsan and then run mysql-test-run. After this commit, one should be able to run this without any UBSAN warnings. There is still a few compiler warnings that should be fixed at some point, but these do not expose any real bugs. The 'special' cases where we disable, suppress or circumvent UBSAN are: - ref10 source (as here we intentionally do some shifts that UBSAN complains about. - x86 version of optimized int#korr() methods. UBSAN do not like unaligned memory access of integers. Fixed by using byte_order_generic.h when compiling with UBSAN - We use smaller thread stack with ASAN and UBSAN, which forced me to disable a few tests that prints the thread stack size. - Verifying class types does not work for shared libraries. I added suppression in mysql-test-run.pl for this case. - Added '#ifdef WITH_UBSAN' when using integer arithmetic where it is safe to have overflows (two cases, in item_func.cc). Things fixed: - Don't left shift signed values (byte_order_generic.h, mysqltest.c, item_sum.cc and many more) - Don't assign not non existing values to enum variables. - Ensure that bool and enum values are properly initialized in constructors. This was needed as UBSAN checks that these types has correct values when one copies an object. (gcalc_tools.h, ha_partition.cc, item_sum.cc, partition_element.h ...) - Ensure we do not called handler functions on unallocated objects or deleted objects. (events.cc, sql_acl.cc). - Fixed bugs in Item_sp::Item_sp() where we did not call constructor on Query_arena object. - Fixed several cast of objects to an incompatible class! (Item.cc, Item_buff.cc, item_timefunc.cc, opt_subselect.cc, sql_acl.cc, sql_select.cc ...) - Ensure we do not do integer arithmetic that causes over or underflows. This includes also ++ and -- of integers. (Item_func.cc, Item_strfunc.cc, item_timefunc.cc, sql_base.cc ...) - Added JSON_VALUE_UNITIALIZED to json_value_types and ensure that value_type is initialized to this instead of to -1, which is not a valid enum value for json_value_types. - Ensure we do not call memcpy() when second argument could be null. - Fixed that Item_func_str::make_empty_result() creates an empty string instead of a null string (safer as it ensures we do not do arithmetic on null strings). Other things: - Changed struct st_position to an OBJECT and added an initialization function to it to ensure that we do not copy or use uninitialized members. The change to a class was also motived that we used "struct st_position" and POSITION randomly trough the code which was confusing. - Notably big rewrite in sql_acl.cc to avoid using deleted objects. - Changed in sql_partition to use '^' instead of '-'. This is safe as the operator is either 0 or 0x8000000000000000ULL. - Added check for select_nr < INT_MAX in JOIN::build_explain() to avoid bug when get_select() could return NULL. - Reordered elements in POSITION for better alignment. - Changed sql_test.cc::print_plan() to use pointers instead of objects. - Fixed bug in find_set() where could could execute '1 << -1'. - Added variable have_sanitizer, used by mtr. (This variable was before only in 10.5 and up). It can now have one of two values: ASAN or UBSAN. - Moved ~Archive_share() from ha_archive.cc to ha_archive.h and marked it virtual. This was an effort to get UBSAN to work with loaded storage engines. I kept the change as the new place is better. - Added in CONNECT engine COLBLK::SetName(), to get around a wrong cast in tabutil.cpp. - Added HAVE_REPLICATION around usage of rgi_slave, to get embedded server to compile with UBSAN. (Patch from Marko). - Added #ifdef for powerpc64 to avoid a bug in old gcc versions related to integer arithmetic. Changes that should not be needed but had to be done to suppress warnings from UBSAN: - Added static_cast<<uint16_t>> around shift to get rid of a LOT of compiler warnings when using UBSAN. - Had to change some '/' of 2 base integers to shift to get rid of some compile time warnings. Reviewed by: - Json changes: Alexey Botchkov - Charset changes in ctype-uca.c: Alexander Barkov - InnoDB changes & Embedded server: Marko Mäkelä - sql_acl.cc changes: Vicențiu Ciorbaru - build_explain() changes: Sergey Petrunia
5 years ago
Fix all warnings given by UBSAN The easiest way to compile and test the server with UBSAN is to run: ./BUILD/compile-pentium64-ubsan and then run mysql-test-run. After this commit, one should be able to run this without any UBSAN warnings. There is still a few compiler warnings that should be fixed at some point, but these do not expose any real bugs. The 'special' cases where we disable, suppress or circumvent UBSAN are: - ref10 source (as here we intentionally do some shifts that UBSAN complains about. - x86 version of optimized int#korr() methods. UBSAN do not like unaligned memory access of integers. Fixed by using byte_order_generic.h when compiling with UBSAN - We use smaller thread stack with ASAN and UBSAN, which forced me to disable a few tests that prints the thread stack size. - Verifying class types does not work for shared libraries. I added suppression in mysql-test-run.pl for this case. - Added '#ifdef WITH_UBSAN' when using integer arithmetic where it is safe to have overflows (two cases, in item_func.cc). Things fixed: - Don't left shift signed values (byte_order_generic.h, mysqltest.c, item_sum.cc and many more) - Don't assign not non existing values to enum variables. - Ensure that bool and enum values are properly initialized in constructors. This was needed as UBSAN checks that these types has correct values when one copies an object. (gcalc_tools.h, ha_partition.cc, item_sum.cc, partition_element.h ...) - Ensure we do not called handler functions on unallocated objects or deleted objects. (events.cc, sql_acl.cc). - Fixed bugs in Item_sp::Item_sp() where we did not call constructor on Query_arena object. - Fixed several cast of objects to an incompatible class! (Item.cc, Item_buff.cc, item_timefunc.cc, opt_subselect.cc, sql_acl.cc, sql_select.cc ...) - Ensure we do not do integer arithmetic that causes over or underflows. This includes also ++ and -- of integers. (Item_func.cc, Item_strfunc.cc, item_timefunc.cc, sql_base.cc ...) - Added JSON_VALUE_UNITIALIZED to json_value_types and ensure that value_type is initialized to this instead of to -1, which is not a valid enum value for json_value_types. - Ensure we do not call memcpy() when second argument could be null. - Fixed that Item_func_str::make_empty_result() creates an empty string instead of a null string (safer as it ensures we do not do arithmetic on null strings). Other things: - Changed struct st_position to an OBJECT and added an initialization function to it to ensure that we do not copy or use uninitialized members. The change to a class was also motived that we used "struct st_position" and POSITION randomly trough the code which was confusing. - Notably big rewrite in sql_acl.cc to avoid using deleted objects. - Changed in sql_partition to use '^' instead of '-'. This is safe as the operator is either 0 or 0x8000000000000000ULL. - Added check for select_nr < INT_MAX in JOIN::build_explain() to avoid bug when get_select() could return NULL. - Reordered elements in POSITION for better alignment. - Changed sql_test.cc::print_plan() to use pointers instead of objects. - Fixed bug in find_set() where could could execute '1 << -1'. - Added variable have_sanitizer, used by mtr. (This variable was before only in 10.5 and up). It can now have one of two values: ASAN or UBSAN. - Moved ~Archive_share() from ha_archive.cc to ha_archive.h and marked it virtual. This was an effort to get UBSAN to work with loaded storage engines. I kept the change as the new place is better. - Added in CONNECT engine COLBLK::SetName(), to get around a wrong cast in tabutil.cpp. - Added HAVE_REPLICATION around usage of rgi_slave, to get embedded server to compile with UBSAN. (Patch from Marko). - Added #ifdef for powerpc64 to avoid a bug in old gcc versions related to integer arithmetic. Changes that should not be needed but had to be done to suppress warnings from UBSAN: - Added static_cast<<uint16_t>> around shift to get rid of a LOT of compiler warnings when using UBSAN. - Had to change some '/' of 2 base integers to shift to get rid of some compile time warnings. Reviewed by: - Json changes: Alexey Botchkov - Charset changes in ctype-uca.c: Alexander Barkov - InnoDB changes & Embedded server: Marko Mäkelä - sql_acl.cc changes: Vicențiu Ciorbaru - build_explain() changes: Sergey Petrunia
5 years ago
  1. /*
  2. Copyright (c) 2016, 2021, MariaDB Corporation.
  3. This program is free software; you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation; version 2 of the License.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  9. GNU General Public License for more details.
  10. You should have received a copy of the GNU General Public License
  11. along with this program; if not, write to the Free Software
  12. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  13. */
  14. /**
  15. All methods pertaining to temporary tables.
  16. */
  17. #include "mariadb.h"
  18. #include "sql_acl.h" /* TMP_TABLE_ACLS */
  19. #include "sql_base.h" /* tdc_create_key */
  20. #include "lock.h" /* mysql_lock_remove */
  21. #include "log_event.h" /* Query_log_event */
  22. #include "sql_show.h" /* append_identifier */
  23. #include "sql_handler.h" /* mysql_ha_rm_temporary_tables */
  24. #include "rpl_rli.h" /* rpl_group_info */
  25. #define IS_USER_TABLE(A) ((A->tmp_table == TRANSACTIONAL_TMP_TABLE) || \
  26. (A->tmp_table == NON_TRANSACTIONAL_TMP_TABLE))
  27. /**
  28. Check whether temporary tables exist. The decision is made based on the
  29. existence of TMP_TABLE_SHAREs in Open_tables_state::temporary_tables list.
  30. @return false Temporary tables exist
  31. true No temporary table exist
  32. */
  33. bool THD::has_thd_temporary_tables()
  34. {
  35. DBUG_ENTER("THD::has_thd_temporary_tables");
  36. bool result= (temporary_tables && !temporary_tables->is_empty());
  37. DBUG_RETURN(result);
  38. }
  39. /**
  40. Create a temporary table, open it and return the TABLE handle.
  41. @param frm [IN] Binary frm image
  42. @param path [IN] File path (without extension)
  43. @param db [IN] Schema name
  44. @param table_name [IN] Table name
  45. @return Success A pointer to table object
  46. Failure NULL
  47. */
  48. TABLE *THD::create_and_open_tmp_table(LEX_CUSTRING *frm,
  49. const char *path,
  50. const char *db,
  51. const char *table_name,
  52. bool open_internal_tables)
  53. {
  54. DBUG_ENTER("THD::create_and_open_tmp_table");
  55. TMP_TABLE_SHARE *share;
  56. TABLE *table= NULL;
  57. if ((share= create_temporary_table(frm, path, db, table_name)))
  58. {
  59. open_options|= HA_OPEN_FOR_CREATE;
  60. table= open_temporary_table(share, table_name);
  61. open_options&= ~HA_OPEN_FOR_CREATE;
  62. /*
  63. Failed to open a temporary table instance. As we are not passing
  64. the created TMP_TABLE_SHARE to the caller, we must remove it from
  65. the list and free it here.
  66. */
  67. if (!table)
  68. {
  69. /* Remove the TABLE_SHARE from the list of temporary tables. */
  70. temporary_tables->remove(share);
  71. /* Free the TMP_TABLE_SHARE. */
  72. free_tmp_table_share(share, false);
  73. DBUG_RETURN(0);
  74. }
  75. /* Open any related tables */
  76. if (open_internal_tables && table->internal_tables &&
  77. open_and_lock_internal_tables(table, true))
  78. {
  79. drop_temporary_table(table, NULL, false);
  80. DBUG_RETURN(0);
  81. }
  82. }
  83. DBUG_RETURN(table);
  84. }
  85. /**
  86. Check whether an open table with db/table name is in use.
  87. @param db [IN] Database name
  88. @param table_name [IN] Table name
  89. @param state [IN] State of temp table to open
  90. @return Success Pointer to first used table instance.
  91. Failure NULL
  92. */
  93. TABLE *THD::find_temporary_table(const char *db,
  94. const char *table_name,
  95. Temporary_table_state state)
  96. {
  97. DBUG_ENTER("THD::find_temporary_table");
  98. TABLE *table;
  99. char key[MAX_DBKEY_LENGTH];
  100. uint key_length;
  101. bool locked;
  102. if (!has_temporary_tables())
  103. {
  104. DBUG_RETURN(NULL);
  105. }
  106. key_length= create_tmp_table_def_key(key, db, table_name);
  107. locked= lock_temporary_tables();
  108. table= find_temporary_table(key, key_length, state);
  109. if (locked)
  110. {
  111. DBUG_ASSERT(m_tmp_tables_locked);
  112. unlock_temporary_tables();
  113. }
  114. DBUG_RETURN(table);
  115. }
  116. /**
  117. Check whether an open table specified in TABLE_LIST is in use.
  118. @return tl [IN] TABLE_LIST
  119. @return Success Pointer to first used table instance.
  120. Failure NULL
  121. */
  122. TABLE *THD::find_temporary_table(const TABLE_LIST *tl,
  123. Temporary_table_state state)
  124. {
  125. DBUG_ENTER("THD::find_temporary_table");
  126. TABLE *table= find_temporary_table(tl->get_db_name(), tl->get_table_name(),
  127. state);
  128. DBUG_RETURN(table);
  129. }
  130. /**
  131. Check whether a temporary table exists with the specified key.
  132. The key, in this case, is not the usual key used for temporary tables.
  133. It does not contain server_id & pseudo_thread_id. This function is
  134. essentially used use to check whether there is any temporary table
  135. which _shadows_ a base table.
  136. (see: Query_cache::send_result_to_client())
  137. @return Success A pointer to table share object
  138. Failure NULL
  139. */
  140. TMP_TABLE_SHARE *THD::find_tmp_table_share_w_base_key(const char *key,
  141. uint key_length)
  142. {
  143. DBUG_ENTER("THD::find_tmp_table_share_w_base_key");
  144. TMP_TABLE_SHARE *share;
  145. TMP_TABLE_SHARE *result= NULL;
  146. bool locked;
  147. if (!has_temporary_tables())
  148. {
  149. DBUG_RETURN(NULL);
  150. }
  151. locked= lock_temporary_tables();
  152. All_tmp_tables_list::Iterator it(*temporary_tables);
  153. while ((share= it++))
  154. {
  155. if ((share->table_cache_key.length - TMP_TABLE_KEY_EXTRA) == key_length
  156. && !memcmp(share->table_cache_key.str, key, key_length))
  157. {
  158. result= share;
  159. }
  160. }
  161. if (locked)
  162. {
  163. DBUG_ASSERT(m_tmp_tables_locked);
  164. unlock_temporary_tables();
  165. }
  166. DBUG_RETURN(result);
  167. }
  168. /**
  169. Lookup the TMP_TABLE_SHARE using the given db/table_name.The server_id and
  170. pseudo_thread_id used to generate table definition key is taken from THD
  171. (see create_tmp_table_def_key()). Return NULL is none found.
  172. @return Success A pointer to table share object
  173. Failure NULL
  174. */
  175. TMP_TABLE_SHARE *THD::find_tmp_table_share(const char *db,
  176. const char *table_name)
  177. {
  178. DBUG_ENTER("THD::find_tmp_table_share");
  179. TMP_TABLE_SHARE *share;
  180. char key[MAX_DBKEY_LENGTH];
  181. uint key_length;
  182. key_length= create_tmp_table_def_key(key, db, table_name);
  183. share= find_tmp_table_share(key, key_length);
  184. DBUG_RETURN(share);
  185. }
  186. /**
  187. Lookup TMP_TABLE_SHARE using the specified TABLE_LIST element.
  188. Return NULL is none found.
  189. @param tl [IN] Table
  190. @return Success A pointer to table share object
  191. Failure NULL
  192. */
  193. TMP_TABLE_SHARE *THD::find_tmp_table_share(const TABLE_LIST *tl)
  194. {
  195. DBUG_ENTER("THD::find_tmp_table_share");
  196. TMP_TABLE_SHARE *share= find_tmp_table_share(tl->get_db_name(),
  197. tl->get_table_name());
  198. DBUG_RETURN(share);
  199. }
  200. /**
  201. Lookup TMP_TABLE_SHARE using the specified table definition key.
  202. Return NULL is none found.
  203. @return Success A pointer to table share object
  204. Failure NULL
  205. */
  206. TMP_TABLE_SHARE *THD::find_tmp_table_share(const char *key, size_t key_length)
  207. {
  208. DBUG_ENTER("THD::find_tmp_table_share");
  209. TMP_TABLE_SHARE *share;
  210. TMP_TABLE_SHARE *result= NULL;
  211. bool locked;
  212. if (!has_temporary_tables())
  213. {
  214. DBUG_RETURN(NULL);
  215. }
  216. locked= lock_temporary_tables();
  217. All_tmp_tables_list::Iterator it(*temporary_tables);
  218. while ((share= it++))
  219. {
  220. if (share->table_cache_key.length == key_length &&
  221. !(memcmp(share->table_cache_key.str, key, key_length)))
  222. {
  223. result= share;
  224. break;
  225. }
  226. }
  227. if (locked)
  228. {
  229. DBUG_ASSERT(m_tmp_tables_locked);
  230. unlock_temporary_tables();
  231. }
  232. DBUG_RETURN(result);
  233. }
  234. /**
  235. Find a temporary table specified by TABLE_LIST instance in the open table
  236. list and prepare its TABLE instance for use. If
  237. This function tries to resolve this table in the list of temporary tables
  238. of this thread. Temporary tables are thread-local and "shadow" base
  239. tables with the same name.
  240. @note In most cases one should use THD::open_tables() instead
  241. of this call.
  242. @note One should finalize process of opening temporary table for table
  243. list element by calling open_and_process_table(). This function
  244. is responsible for table version checking and handling of merge
  245. tables.
  246. @note We used to check global_read_lock before opening temporary tables.
  247. However, that limitation was artificial and is removed now.
  248. @param tl [IN] TABLE_LIST
  249. @return Error status.
  250. @retval false On success. If a temporary table exists
  251. for the given key, tl->table is set.
  252. @retval true On error. my_error() has been called.
  253. */
  254. bool THD::open_temporary_table(TABLE_LIST *tl)
  255. {
  256. DBUG_ENTER("THD::open_temporary_table");
  257. DBUG_PRINT("enter", ("table: '%s'.'%s'", tl->db.str, tl->table_name.str));
  258. TMP_TABLE_SHARE *share;
  259. TABLE *table= NULL;
  260. /*
  261. Code in open_table() assumes that TABLE_LIST::table can be non-zero only
  262. for pre-opened temporary tables.
  263. */
  264. DBUG_ASSERT(tl->table == NULL);
  265. /*
  266. This function should not be called for cases when derived or I_S
  267. tables can be met since table list elements for such tables can
  268. have invalid db or table name.
  269. Instead THD::open_tables() should be used.
  270. */
  271. DBUG_ASSERT(!tl->derived);
  272. DBUG_ASSERT(!tl->schema_table);
  273. DBUG_ASSERT(has_temporary_tables());
  274. if (tl->open_type == OT_BASE_ONLY)
  275. {
  276. DBUG_PRINT("info", ("skip_temporary is set or no temporary tables"));
  277. DBUG_RETURN(false);
  278. }
  279. if (!tl->db.str)
  280. {
  281. DBUG_PRINT("info",
  282. ("Table reference to a temporary table must have database set"));
  283. DBUG_RETURN(false);
  284. }
  285. /*
  286. Temporary tables are not safe for parallel replication. They were
  287. designed to be visible to one thread only, so have no table locking.
  288. Thus there is no protection against two conflicting transactions
  289. committing in parallel and things like that.
  290. So for now, anything that uses temporary tables will be serialised
  291. with anything before it, when using parallel replication.
  292. */
  293. if (rgi_slave &&
  294. rgi_slave->is_parallel_exec &&
  295. find_temporary_table(tl) &&
  296. wait_for_prior_commit())
  297. DBUG_RETURN(true);
  298. /*
  299. First check if there is a reusable open table available in the
  300. open table list.
  301. */
  302. if (find_and_use_tmp_table(tl, &table))
  303. {
  304. DBUG_RETURN(true); /* Error */
  305. }
  306. /*
  307. No reusable table was found. We will have to open a new instance.
  308. */
  309. if (!table && (share= find_tmp_table_share(tl)))
  310. {
  311. table= open_temporary_table(share, tl->get_table_name());
  312. /*
  313. Temporary tables are not safe for parallel replication. They were
  314. designed to be visible to one thread only, so have no table locking.
  315. Thus there is no protection against two conflicting transactions
  316. committing in parallel and things like that.
  317. So for now, anything that uses temporary tables will be serialised
  318. with anything before it, when using parallel replication.
  319. */
  320. if (table && rgi_slave &&
  321. rgi_slave->is_parallel_exec &&
  322. wait_for_prior_commit())
  323. DBUG_RETURN(true);
  324. if (!table && is_error())
  325. DBUG_RETURN(true); // Error when opening table
  326. }
  327. if (!table)
  328. {
  329. if (tl->open_type == OT_TEMPORARY_ONLY &&
  330. tl->open_strategy == TABLE_LIST::OPEN_NORMAL)
  331. {
  332. my_error(ER_NO_SUCH_TABLE, MYF(0), tl->db.str, tl->table_name.str);
  333. DBUG_RETURN(true);
  334. }
  335. DBUG_RETURN(false);
  336. }
  337. #ifdef WITH_PARTITION_STORAGE_ENGINE
  338. if (tl->partition_names)
  339. {
  340. /* Partitioned temporary tables is not supported. */
  341. DBUG_ASSERT(!table->part_info);
  342. my_error(ER_PARTITION_CLAUSE_ON_NONPARTITIONED, MYF(0));
  343. DBUG_RETURN(true);
  344. }
  345. #endif
  346. table->query_id= query_id;
  347. thread_specific_used= true;
  348. /* It is neither a derived table nor non-updatable view. */
  349. tl->updatable= true;
  350. tl->table= table;
  351. table->init(this, tl);
  352. DBUG_PRINT("info", ("Using temporary table"));
  353. DBUG_RETURN(false);
  354. }
  355. /**
  356. Pre-open temporary tables corresponding to table list elements.
  357. @note One should finalize process of opening temporary tables
  358. by calling open_tables(). This function is responsible
  359. for table version checking and handling of merge tables.
  360. @param tl [IN] TABLE_LIST
  361. @return false On success. If a temporary table exists
  362. for the given element, tl->table is set.
  363. true On error. my_error() has been called.
  364. */
  365. bool THD::open_temporary_tables(TABLE_LIST *tl)
  366. {
  367. TABLE_LIST *first_not_own;
  368. DBUG_ENTER("THD::open_temporary_tables");
  369. if (!has_temporary_tables())
  370. DBUG_RETURN(0);
  371. first_not_own= lex->first_not_own_table();
  372. for (TABLE_LIST *table= tl; table && table != first_not_own;
  373. table= table->next_global)
  374. {
  375. if (table->derived || table->schema_table)
  376. {
  377. /*
  378. Derived and I_S tables will be handled by a later call to open_tables().
  379. */
  380. continue;
  381. }
  382. if (open_temporary_table(table))
  383. {
  384. DBUG_RETURN(true);
  385. }
  386. }
  387. DBUG_RETURN(false);
  388. }
  389. /**
  390. Close all temporary tables created by 'CREATE TEMPORARY TABLE' for thread
  391. creates one DROP TEMPORARY TABLE binlog event for each pseudo-thread.
  392. Temporary tables created in a sql slave is closed by
  393. Relay_log_info::close_temporary_tables().
  394. @return false Success
  395. true Failure
  396. */
  397. bool THD::close_temporary_tables()
  398. {
  399. DBUG_ENTER("THD::close_temporary_tables");
  400. TMP_TABLE_SHARE *share;
  401. TABLE *table;
  402. bool error= false;
  403. if (!has_thd_temporary_tables())
  404. {
  405. if (temporary_tables)
  406. {
  407. my_free(temporary_tables);
  408. temporary_tables= NULL;
  409. }
  410. DBUG_RETURN(false);
  411. }
  412. DBUG_ASSERT(!rgi_slave);
  413. /*
  414. Ensure we don't have open HANDLERs for tables we are about to close.
  415. This is necessary when THD::close_temporary_tables() is called as
  416. part of execution of BINLOG statement (e.g. for format description event).
  417. */
  418. mysql_ha_rm_temporary_tables(this);
  419. /* Close all open temporary tables. */
  420. All_tmp_tables_list::Iterator it(*temporary_tables);
  421. while ((share= it++))
  422. {
  423. /* Traverse the table list. */
  424. while ((table= share->all_tmp_tables.pop_front()))
  425. {
  426. table->file->extra(HA_EXTRA_PREPARE_FOR_DROP);
  427. free_temporary_table(table);
  428. }
  429. }
  430. // Write DROP TEMPORARY TABLE query log events to binary log.
  431. if (mysql_bin_log.is_open())
  432. {
  433. error= log_events_and_free_tmp_shares();
  434. }
  435. else
  436. {
  437. while ((share= temporary_tables->pop_front()))
  438. {
  439. free_tmp_table_share(share, true);
  440. }
  441. }
  442. /* By now, there mustn't be any elements left in the list. */
  443. DBUG_ASSERT(temporary_tables->is_empty());
  444. my_free(temporary_tables);
  445. temporary_tables= NULL;
  446. DBUG_RETURN(error);
  447. }
  448. /**
  449. Rename a temporary table.
  450. @param table [IN] Table handle
  451. @param db [IN] New schema name
  452. @param table_name [IN] New table name
  453. @return false Success
  454. true Error
  455. */
  456. bool THD::rename_temporary_table(TABLE *table,
  457. const LEX_CSTRING *db,
  458. const LEX_CSTRING *table_name)
  459. {
  460. char *key;
  461. uint key_length;
  462. TABLE_SHARE *share= table->s;
  463. DBUG_ENTER("THD::rename_temporary_table");
  464. if (!(key= (char *) alloc_root(&share->mem_root, MAX_DBKEY_LENGTH)))
  465. DBUG_RETURN(true);
  466. /*
  467. Temporary tables are renamed by simply changing their table definition key.
  468. */
  469. key_length= create_tmp_table_def_key(key, db->str, table_name->str);
  470. share->set_table_cache_key(key, key_length);
  471. DBUG_RETURN(false);
  472. }
  473. /**
  474. Drop a temporary table.
  475. Try to locate the table in the list of open temporary tables.
  476. If the table is found:
  477. - If the table is locked with LOCK TABLES or by prelocking,
  478. unlock it and remove it from the list of locked tables
  479. (THD::lock). Currently only transactional temporary tables
  480. are locked.
  481. - Close the temporary table, remove its .FRM.
  482. - Remove the table share from the list of temporary table shares.
  483. This function is used to drop user temporary tables, as well as
  484. internal tables created in CREATE TEMPORARY TABLE ... SELECT
  485. or ALTER TABLE.
  486. @param table [IN] Temporary table to be deleted
  487. @param is_trans [OUT] Is set to the type of the table:
  488. transactional (e.g. innodb) as true or
  489. non-transactional (e.g. myisam) as false.
  490. @paral delete_table [IN] Whether to delete the table files?
  491. @return false Table was dropped
  492. true Error
  493. */
  494. bool THD::drop_temporary_table(TABLE *table, bool *is_trans, bool delete_table)
  495. {
  496. DBUG_ENTER("THD::drop_temporary_table");
  497. TMP_TABLE_SHARE *share;
  498. TABLE *tab;
  499. bool result= false;
  500. bool locked;
  501. DBUG_ASSERT(table);
  502. DBUG_PRINT("tmptable", ("Dropping table: '%s'.'%s'",
  503. table->s->db.str, table->s->table_name.str));
  504. locked= lock_temporary_tables();
  505. share= tmp_table_share(table);
  506. /* Table might be in use by some outer statement. */
  507. All_share_tables_list::Iterator it(share->all_tmp_tables);
  508. while ((tab= it++))
  509. {
  510. if (tab != table && tab->query_id != 0)
  511. {
  512. /* Found a table instance in use. This table cannot be be dropped. */
  513. my_error(ER_CANT_REOPEN_TABLE, MYF(0), table->alias.c_ptr());
  514. result= true;
  515. goto end;
  516. }
  517. }
  518. if (is_trans)
  519. *is_trans= table->file->has_transactions();
  520. /*
  521. Iterate over the list of open tables and close them.
  522. */
  523. while ((tab= share->all_tmp_tables.pop_front()))
  524. {
  525. /*
  526. We need to set the THD as it may be different in case of
  527. parallel replication
  528. */
  529. tab->in_use= this;
  530. if (delete_table)
  531. tab->file->extra(HA_EXTRA_PREPARE_FOR_DROP);
  532. free_temporary_table(tab);
  533. }
  534. DBUG_ASSERT(temporary_tables);
  535. /* Remove the TABLE_SHARE from the list of temporary tables. */
  536. temporary_tables->remove(share);
  537. /* Free the TABLE_SHARE and/or delete the files. */
  538. free_tmp_table_share(share, delete_table);
  539. end:
  540. if (locked)
  541. {
  542. DBUG_ASSERT(m_tmp_tables_locked);
  543. unlock_temporary_tables();
  544. }
  545. DBUG_RETURN(result);
  546. }
  547. /**
  548. Delete the temporary table files.
  549. @param base [IN] Handlerton for table to be deleted.
  550. @param path [IN] Path to the table to be deleted (i.e. path
  551. to its .frm without an extension).
  552. @return false Success
  553. true Error
  554. */
  555. bool THD::rm_temporary_table(handlerton *base, const char *path)
  556. {
  557. DBUG_ENTER("THD::rm_temporary_table");
  558. bool error= false;
  559. char frm_path[FN_REFLEN + 1];
  560. strxnmov(frm_path, sizeof(frm_path) - 1, path, reg_ext, NullS);
  561. if (base->drop_table(base, path) > 0)
  562. {
  563. error= true;
  564. sql_print_warning("Could not remove temporary table: '%s', error: %d",
  565. path, my_errno);
  566. }
  567. if (mysql_file_delete(key_file_frm, frm_path,
  568. MYF(MY_WME | MY_IGNORE_ENOENT)))
  569. error= true;
  570. DBUG_RETURN(error);
  571. }
  572. /**
  573. Mark all temporary tables which were used by the current statement or
  574. sub-statement as free for reuse, but only if the query_id can be cleared.
  575. @remark For temp tables associated with a open SQL HANDLER the query_id
  576. is not reset until the HANDLER is closed.
  577. */
  578. void THD::mark_tmp_tables_as_free_for_reuse()
  579. {
  580. DBUG_ENTER("THD::mark_tmp_tables_as_free_for_reuse");
  581. TMP_TABLE_SHARE *share;
  582. TABLE *table;
  583. bool locked;
  584. if (query_id == 0)
  585. {
  586. /*
  587. Thread has not executed any statement and has not used any
  588. temporary tables.
  589. */
  590. DBUG_VOID_RETURN;
  591. }
  592. if (!has_temporary_tables())
  593. {
  594. DBUG_VOID_RETURN;
  595. }
  596. locked= lock_temporary_tables();
  597. All_tmp_tables_list::Iterator it(*temporary_tables);
  598. while ((share= it++))
  599. {
  600. All_share_tables_list::Iterator tables_it(share->all_tmp_tables);
  601. while ((table= tables_it++))
  602. {
  603. if ((table->query_id == query_id) && !table->open_by_handler)
  604. mark_tmp_table_as_free_for_reuse(table);
  605. }
  606. }
  607. if (locked)
  608. {
  609. DBUG_ASSERT(m_tmp_tables_locked);
  610. unlock_temporary_tables();
  611. }
  612. if (rgi_slave)
  613. {
  614. /*
  615. Temporary tables are shared with other by sql execution threads.
  616. As a safety measure, clear the pointer to the common area.
  617. */
  618. temporary_tables= NULL;
  619. }
  620. DBUG_VOID_RETURN;
  621. }
  622. /**
  623. Reset a single temporary table. Effectively this "closes" one temporary
  624. table in a session.
  625. @param table Temporary table
  626. @return void
  627. */
  628. void THD::mark_tmp_table_as_free_for_reuse(TABLE *table)
  629. {
  630. DBUG_ENTER("THD::mark_tmp_table_as_free_for_reuse");
  631. DBUG_ASSERT(table->s->tmp_table);
  632. table->query_id= 0;
  633. table->file->ha_reset();
  634. /* Detach temporary MERGE children from temporary parent. */
  635. DBUG_ASSERT(table->file);
  636. table->file->extra(HA_EXTRA_DETACH_CHILDREN);
  637. /*
  638. Reset temporary table lock type to it's default value (TL_WRITE).
  639. Statements such as INSERT INTO .. SELECT FROM tmp, CREATE TABLE
  640. .. SELECT FROM tmp and UPDATE may under some circumstances modify
  641. the lock type of the tables participating in the statement. This
  642. isn't a problem for non-temporary tables since their lock type is
  643. reset at every open, but the same does not occur for temporary
  644. tables for historical reasons.
  645. Furthermore, the lock type of temporary tables is not really that
  646. important because they can only be used by one query at a time.
  647. Nonetheless, it's safer from a maintenance point of view to reset
  648. the lock type of this singleton TABLE object as to not cause problems
  649. when the table is reused.
  650. Even under LOCK TABLES mode its okay to reset the lock type as
  651. LOCK TABLES is allowed (but ignored) for a temporary table.
  652. */
  653. table->reginfo.lock_type= TL_WRITE;
  654. DBUG_VOID_RETURN;
  655. }
  656. /**
  657. Remove and return the specified table's TABLE_SHARE from the temporary
  658. tables list.
  659. @param table [IN] Table
  660. @return TMP_TABLE_SHARE of the specified table.
  661. */
  662. TMP_TABLE_SHARE *THD::save_tmp_table_share(TABLE *table)
  663. {
  664. DBUG_ENTER("THD::save_tmp_table_share");
  665. TMP_TABLE_SHARE *share;
  666. lock_temporary_tables();
  667. DBUG_ASSERT(temporary_tables);
  668. share= tmp_table_share(table);
  669. temporary_tables->remove(share);
  670. unlock_temporary_tables();
  671. DBUG_RETURN(share);
  672. }
  673. /**
  674. Add the specified TMP_TABLE_SHARE to the temporary tables list.
  675. @param share [IN] Table share
  676. @return void
  677. */
  678. void THD::restore_tmp_table_share(TMP_TABLE_SHARE *share)
  679. {
  680. DBUG_ENTER("THD::restore_tmp_table_share");
  681. lock_temporary_tables();
  682. DBUG_ASSERT(temporary_tables);
  683. temporary_tables->push_front(share);
  684. unlock_temporary_tables();
  685. DBUG_VOID_RETURN;
  686. }
  687. /**
  688. If its a replication slave, report whether slave temporary tables
  689. exist (Relay_log_info::save_temporary_tables) or report about THD
  690. temporary table (Open_tables_state::temporary_tables) otherwise.
  691. @return false Temporary tables exist
  692. true No temporary table exist
  693. */
  694. bool THD::has_temporary_tables()
  695. {
  696. DBUG_ENTER("THD::has_temporary_tables");
  697. bool result=
  698. #ifdef HAVE_REPLICATION
  699. rgi_slave ? (rgi_slave->rli->save_temporary_tables &&
  700. !rgi_slave->rli->save_temporary_tables->is_empty()) :
  701. #endif
  702. has_thd_temporary_tables();
  703. DBUG_RETURN(result);
  704. }
  705. /**
  706. Create a table definition key.
  707. @param key [OUT] Buffer for the key to be created (must
  708. be of size MAX_DBKRY_LENGTH)
  709. @param db [IN] Database name
  710. @param table_name [IN] Table name
  711. @return Key length.
  712. @note
  713. The table key is create from:
  714. db + \0
  715. table_name + \0
  716. Additionally, we add the following to make each temporary table unique on
  717. the slave.
  718. 4 bytes of master thread id
  719. 4 bytes of pseudo thread id
  720. */
  721. uint THD::create_tmp_table_def_key(char *key, const char *db,
  722. const char *table_name)
  723. {
  724. DBUG_ENTER("THD::create_tmp_table_def_key");
  725. uint key_length;
  726. key_length= tdc_create_key(key, db, table_name);
  727. int4store(key + key_length, variables.server_id);
  728. int4store(key + key_length + 4, variables.pseudo_thread_id);
  729. key_length += TMP_TABLE_KEY_EXTRA;
  730. DBUG_RETURN(key_length);
  731. }
  732. /**
  733. Create a temporary table.
  734. @param frm [IN] Binary frm image
  735. @param path [IN] File path (without extension)
  736. @param db [IN] Schema name
  737. @param table_name [IN] Table name
  738. @return Success A pointer to table share object
  739. Failure NULL
  740. */
  741. TMP_TABLE_SHARE *THD::create_temporary_table(LEX_CUSTRING *frm,
  742. const char *path,
  743. const char *db,
  744. const char *table_name)
  745. {
  746. DBUG_ENTER("THD::create_temporary_table");
  747. TMP_TABLE_SHARE *share;
  748. char key_cache[MAX_DBKEY_LENGTH];
  749. char *saved_key_cache;
  750. char *tmp_path;
  751. uint key_length;
  752. bool locked;
  753. int res;
  754. /* Temporary tables are not safe for parallel replication. */
  755. if (rgi_slave &&
  756. rgi_slave->is_parallel_exec &&
  757. wait_for_prior_commit())
  758. DBUG_RETURN(NULL);
  759. /* Create the table definition key for the temporary table. */
  760. key_length= create_tmp_table_def_key(key_cache, db, table_name);
  761. if (!(share= (TMP_TABLE_SHARE *) my_malloc(key_memory_table_share,
  762. sizeof(TMP_TABLE_SHARE) +
  763. strlen(path) + 1 + key_length,
  764. MYF(MY_WME))))
  765. {
  766. DBUG_RETURN(NULL); /* Out of memory */
  767. }
  768. tmp_path= (char *)(share + 1);
  769. saved_key_cache= strmov(tmp_path, path) + 1;
  770. memcpy(saved_key_cache, key_cache, key_length);
  771. init_tmp_table_share(this, share, saved_key_cache, key_length,
  772. strend(saved_key_cache) + 1, tmp_path);
  773. /*
  774. Prefer using frm image over file. The image might not be available in
  775. ALTER TABLE, when the discovering engine took over the ownership (see
  776. TABLE::read_frm_image).
  777. */
  778. res= (frm->str)
  779. ? share->init_from_binary_frm_image(this, false, frm->str, frm->length)
  780. : open_table_def(this, share, GTS_TABLE | GTS_USE_DISCOVERY);
  781. if (res)
  782. {
  783. /*
  784. No need to lock share->mutex as this is not needed for temporary tables.
  785. */
  786. free_table_share(share);
  787. my_free(share);
  788. DBUG_RETURN(NULL);
  789. }
  790. share->m_psi= PSI_CALL_get_table_share(true, share);
  791. locked= lock_temporary_tables();
  792. /* Initialize the all_tmp_tables list. */
  793. share->all_tmp_tables.empty();
  794. /*
  795. We need to alloc & initialize temporary_tables if this happens
  796. to be the very first temporary table.
  797. */
  798. if (!temporary_tables)
  799. {
  800. if ((temporary_tables=
  801. (All_tmp_tables_list *) my_malloc(key_memory_table_share,
  802. sizeof(All_tmp_tables_list),
  803. MYF(MY_WME))))
  804. {
  805. temporary_tables->empty();
  806. }
  807. else
  808. {
  809. DBUG_RETURN(NULL); /* Out of memory */
  810. }
  811. }
  812. /* Add share to the head of the temporary table share list. */
  813. temporary_tables->push_front(share);
  814. if (locked)
  815. {
  816. DBUG_ASSERT(m_tmp_tables_locked);
  817. unlock_temporary_tables();
  818. }
  819. DBUG_RETURN(share);
  820. }
  821. /**
  822. Find a table with the specified key.
  823. @param key [IN] Key
  824. @param key_length [IN] Key length
  825. @param state [IN] Open table state to look for
  826. @return Success Pointer to the table instance.
  827. Failure NULL
  828. */
  829. TABLE *THD::find_temporary_table(const char *key, uint key_length,
  830. Temporary_table_state state)
  831. {
  832. DBUG_ENTER("THD::find_temporary_table");
  833. TMP_TABLE_SHARE *share;
  834. TABLE *table;
  835. TABLE *result= NULL;
  836. bool locked;
  837. locked= lock_temporary_tables();
  838. All_tmp_tables_list::Iterator it(*temporary_tables);
  839. while ((share= it++))
  840. {
  841. if (share->table_cache_key.length == key_length &&
  842. !(memcmp(share->table_cache_key.str, key, key_length)))
  843. {
  844. /* A matching TMP_TABLE_SHARE is found. */
  845. All_share_tables_list::Iterator tables_it(share->all_tmp_tables);
  846. bool found= false;
  847. while (!found && (table= tables_it++))
  848. {
  849. switch (state)
  850. {
  851. case TMP_TABLE_IN_USE: found= table->query_id > 0; break;
  852. case TMP_TABLE_NOT_IN_USE: found= table->query_id == 0; break;
  853. case TMP_TABLE_ANY: found= true; break;
  854. }
  855. }
  856. if (table && unlikely(table->needs_reopen()))
  857. {
  858. share->all_tmp_tables.remove(table);
  859. free_temporary_table(table);
  860. it.rewind();
  861. continue;
  862. }
  863. result= table;
  864. break;
  865. }
  866. }
  867. if (locked)
  868. {
  869. DBUG_ASSERT(m_tmp_tables_locked);
  870. unlock_temporary_tables();
  871. }
  872. DBUG_RETURN(result);
  873. }
  874. /**
  875. Open a table from the specified TABLE_SHARE with the given alias.
  876. @param share [IN] Table share
  877. @param alias [IN] Table alias
  878. @return Success A pointer to table object
  879. Failure NULL
  880. */
  881. TABLE *THD::open_temporary_table(TMP_TABLE_SHARE *share,
  882. const char *alias_arg)
  883. {
  884. TABLE *table;
  885. LEX_CSTRING alias= {alias_arg, strlen(alias_arg) };
  886. DBUG_ENTER("THD::open_temporary_table");
  887. if (!(table= (TABLE *) my_malloc(key_memory_TABLE, sizeof(TABLE),
  888. MYF(MY_WME))))
  889. {
  890. DBUG_RETURN(NULL); /* Out of memory */
  891. }
  892. if (open_table_from_share(this, share, &alias,
  893. (uint) HA_OPEN_KEYFILE,
  894. EXTRA_RECORD,
  895. (ha_open_options |
  896. (open_options & HA_OPEN_FOR_CREATE)),
  897. table, false))
  898. {
  899. my_free(table);
  900. DBUG_RETURN(NULL);
  901. }
  902. table->reginfo.lock_type= TL_WRITE; /* Simulate locked */
  903. table->grant.privilege= TMP_TABLE_ACLS;
  904. table->query_id= query_id;
  905. share->tmp_table= (table->file->has_transaction_manager() ?
  906. TRANSACTIONAL_TMP_TABLE : NON_TRANSACTIONAL_TMP_TABLE);
  907. share->not_usable_by_query_cache= 1;
  908. /* Add table to the head of table list. */
  909. share->all_tmp_tables.push_front(table);
  910. /* Increment Slave_open_temp_table_definitions status variable count. */
  911. if (rgi_slave)
  912. slave_open_temp_tables++;
  913. DBUG_PRINT("tmptable", ("Opened table: '%s'.'%s table: %p",
  914. table->s->db.str,
  915. table->s->table_name.str, table));
  916. DBUG_RETURN(table);
  917. }
  918. /**
  919. Find a reusable table in the open table list using the specified TABLE_LIST.
  920. @param tl [IN] Table list
  921. @param out_table [OUT] Pointer to the requested TABLE object
  922. @return Success false
  923. Failure true
  924. */
  925. bool THD::find_and_use_tmp_table(const TABLE_LIST *tl, TABLE **out_table)
  926. {
  927. DBUG_ENTER("THD::find_and_use_tmp_table");
  928. char key[MAX_DBKEY_LENGTH];
  929. uint key_length;
  930. bool result;
  931. key_length= create_tmp_table_def_key(key, tl->get_db_name(),
  932. tl->get_table_name());
  933. result= use_temporary_table(find_temporary_table(key, key_length,
  934. TMP_TABLE_NOT_IN_USE),
  935. out_table);
  936. DBUG_RETURN(result);
  937. }
  938. /**
  939. Mark table as in-use.
  940. @param table [IN] Table to be marked in-use
  941. @param out_table [OUT] Pointer to the specified table
  942. @return false Success
  943. true Error
  944. */
  945. bool THD::use_temporary_table(TABLE *table, TABLE **out_table)
  946. {
  947. DBUG_ENTER("THD::use_temporary_table");
  948. *out_table= table;
  949. /* The following can happen if find_temporary_table() returns NULL */
  950. if (!table)
  951. DBUG_RETURN(false);
  952. /*
  953. Temporary tables are not safe for parallel replication. They were
  954. designed to be visible to one thread only, so have no table locking.
  955. Thus there is no protection against two conflicting transactions
  956. committing in parallel and things like that.
  957. So for now, anything that uses temporary tables will be serialised
  958. with anything before it, when using parallel replication.
  959. TODO: We might be able to introduce a reference count or something
  960. on temp tables, and have slave worker threads wait for it to reach
  961. zero before being allowed to use the temp table. Might not be worth
  962. it though, as statement-based replication using temporary tables is
  963. in any case rather fragile.
  964. */
  965. if (rgi_slave &&
  966. rgi_slave->is_parallel_exec &&
  967. wait_for_prior_commit())
  968. DBUG_RETURN(true);
  969. /*
  970. We need to set the THD as it may be different in case of
  971. parallel replication
  972. */
  973. table->in_use= this;
  974. DBUG_RETURN(false);
  975. }
  976. /**
  977. Close a temporary table.
  978. @param table [IN] Table handle
  979. @return void
  980. */
  981. void THD::close_temporary_table(TABLE *table)
  982. {
  983. DBUG_ENTER("THD::close_temporary_table");
  984. DBUG_PRINT("tmptable", ("closing table: '%s'.'%s'%p alias: '%s'",
  985. table->s->db.str, table->s->table_name.str,
  986. table, table->alias.c_ptr()));
  987. closefrm(table);
  988. my_free(table);
  989. if (rgi_slave)
  990. {
  991. /* Natural invariant of temporary_tables */
  992. DBUG_ASSERT(slave_open_temp_tables || !temporary_tables);
  993. /* Decrement Slave_open_temp_table_definitions status variable count. */
  994. slave_open_temp_tables--;
  995. }
  996. DBUG_VOID_RETURN;
  997. }
  998. /**
  999. Write query log events with "DROP TEMPORARY TABLES .." for each pseudo
  1000. thread to the binary log.
  1001. @return false Success
  1002. true Error
  1003. */
  1004. bool THD::log_events_and_free_tmp_shares()
  1005. {
  1006. DBUG_ENTER("THD::log_events_and_free_tmp_shares");
  1007. DBUG_ASSERT(!rgi_slave);
  1008. TMP_TABLE_SHARE *share;
  1009. TMP_TABLE_SHARE *sorted;
  1010. TMP_TABLE_SHARE *prev_sorted;
  1011. // Assume thd->variables.option_bits has OPTION_QUOTE_SHOW_CREATE.
  1012. bool was_quote_show= true;
  1013. bool error= false;
  1014. bool found_user_tables= false;
  1015. // Better add "IF EXISTS" in case a RESET MASTER has been done.
  1016. const char stub[]= "DROP /*!40005 TEMPORARY */ TABLE IF EXISTS ";
  1017. char buf[FN_REFLEN];
  1018. String s_query(buf, sizeof(buf), system_charset_info);
  1019. s_query.copy(stub, sizeof(stub) - 1, system_charset_info);
  1020. /*
  1021. Insertion sort of temporary tables by pseudo_thread_id to build ordered
  1022. list of sublists of equal pseudo_thread_id.
  1023. */
  1024. All_tmp_tables_list::Iterator it_sorted(*temporary_tables);
  1025. All_tmp_tables_list::Iterator it_unsorted(*temporary_tables);
  1026. uint sorted_count= 0;
  1027. while((share= it_unsorted++))
  1028. {
  1029. if (IS_USER_TABLE(share))
  1030. {
  1031. prev_sorted= NULL;
  1032. if (!found_user_tables) found_user_tables= true;
  1033. for (uint i= 0; i < sorted_count; i ++)
  1034. {
  1035. sorted= it_sorted ++;
  1036. if (!IS_USER_TABLE(sorted) ||
  1037. (tmpkeyval(sorted) > tmpkeyval(share)))
  1038. {
  1039. /*
  1040. Insert this share before the current element in
  1041. the sorted part of the list.
  1042. */
  1043. temporary_tables->remove(share);
  1044. if (prev_sorted)
  1045. {
  1046. temporary_tables->insert_after(prev_sorted, share);
  1047. }
  1048. else
  1049. {
  1050. temporary_tables->push_front(share);
  1051. }
  1052. break;
  1053. }
  1054. prev_sorted= sorted;
  1055. }
  1056. it_sorted.rewind();
  1057. }
  1058. sorted_count ++;
  1059. }
  1060. /*
  1061. We always quote db & table names.
  1062. */
  1063. if (found_user_tables &&
  1064. !(was_quote_show= MY_TEST(variables.option_bits &
  1065. OPTION_QUOTE_SHOW_CREATE)))
  1066. {
  1067. variables.option_bits |= OPTION_QUOTE_SHOW_CREATE;
  1068. }
  1069. /*
  1070. Scan sorted temporary tables to generate sequence of DROP.
  1071. */
  1072. share= temporary_tables->pop_front();
  1073. while (share)
  1074. {
  1075. if (IS_USER_TABLE(share))
  1076. {
  1077. bool save_thread_specific_used= thread_specific_used;
  1078. my_thread_id save_pseudo_thread_id= variables.pseudo_thread_id;
  1079. char db_buf[FN_REFLEN];
  1080. String db(db_buf, sizeof(db_buf), system_charset_info);
  1081. bool at_least_one_create_logged;
  1082. /*
  1083. Set pseudo_thread_id to be that of the processed table.
  1084. */
  1085. variables.pseudo_thread_id= tmpkeyval(share);
  1086. db.copy(share->db.str, share->db.length, system_charset_info);
  1087. /*
  1088. Reset s_query() if changed by previous loop.
  1089. */
  1090. s_query.length(sizeof(stub) - 1);
  1091. /*
  1092. Loop forward through all tables that belong to a common database
  1093. within the sublist of common pseudo_thread_id to create single
  1094. DROP query.
  1095. */
  1096. for (at_least_one_create_logged= false;
  1097. share && IS_USER_TABLE(share) &&
  1098. tmpkeyval(share) == variables.pseudo_thread_id &&
  1099. share->db.length == db.length() &&
  1100. memcmp(share->db.str, db.ptr(), db.length()) == 0;
  1101. /* Get the next TABLE_SHARE in the list. */
  1102. share= temporary_tables->pop_front())
  1103. {
  1104. if (share->table_creation_was_logged)
  1105. {
  1106. at_least_one_create_logged= true;
  1107. /*
  1108. We are going to add ` around the table names and possible more
  1109. due to special characters.
  1110. */
  1111. append_identifier(this, &s_query, &share->table_name);
  1112. s_query.append(',');
  1113. }
  1114. rm_temporary_table(share->db_type(), share->path.str);
  1115. free_table_share(share);
  1116. my_free(share);
  1117. }
  1118. if (at_least_one_create_logged)
  1119. {
  1120. clear_error();
  1121. CHARSET_INFO *cs_save= variables.character_set_client;
  1122. variables.character_set_client= system_charset_info;
  1123. thread_specific_used= true;
  1124. Query_log_event qinfo(this, s_query.ptr(),
  1125. s_query.length() - 1 /* to remove trailing ',' */,
  1126. false, true, false, 0);
  1127. qinfo.db= db.ptr();
  1128. qinfo.db_len= db.length();
  1129. variables.character_set_client= cs_save;
  1130. get_stmt_da()->set_overwrite_status(true);
  1131. transaction->stmt.mark_dropped_temp_table();
  1132. bool error2= mysql_bin_log.write(&qinfo);
  1133. if (unlikely(error|= error2))
  1134. {
  1135. /*
  1136. If we're here following THD::cleanup, thence the connection
  1137. has been closed already. So lets print a message to the
  1138. error log instead of pushing yet another error into the
  1139. stmt_da.
  1140. Also, we keep the error flag so that we propagate the error
  1141. up in the stack. This way, if we're the SQL thread we notice
  1142. that THD::close_tables failed. (Actually, the SQL
  1143. thread only calls THD::close_tables while applying
  1144. old Start_log_event_v3 events.)
  1145. */
  1146. sql_print_error("Failed to write the DROP statement for "
  1147. "temporary tables to binary log");
  1148. }
  1149. get_stmt_da()->set_overwrite_status(false);
  1150. }
  1151. variables.pseudo_thread_id= save_pseudo_thread_id;
  1152. thread_specific_used= save_thread_specific_used;
  1153. }
  1154. else
  1155. {
  1156. free_tmp_table_share(share, true);
  1157. /* Get the next TABLE_SHARE in the list. */
  1158. share= temporary_tables->pop_front();
  1159. }
  1160. }
  1161. if (!was_quote_show)
  1162. {
  1163. /*
  1164. Restore option.
  1165. */
  1166. variables.option_bits&= ~OPTION_QUOTE_SHOW_CREATE;
  1167. }
  1168. DBUG_RETURN(error);
  1169. }
  1170. /**
  1171. Delete the files and free the specified table share.
  1172. @param share [IN] TABLE_SHARE to free
  1173. @param delete_table [IN] Whether to delete the table files?
  1174. @return void
  1175. */
  1176. void THD::free_tmp_table_share(TMP_TABLE_SHARE *share, bool delete_table)
  1177. {
  1178. DBUG_ENTER("THD::free_tmp_table_share");
  1179. if (delete_table)
  1180. {
  1181. rm_temporary_table(share->db_type(), share->path.str);
  1182. }
  1183. free_table_share(share);
  1184. my_free(share);
  1185. DBUG_VOID_RETURN;
  1186. }
  1187. /**
  1188. Free the specified table object.
  1189. @param table [IN] Table object to free.
  1190. @return void
  1191. */
  1192. void THD::free_temporary_table(TABLE *table)
  1193. {
  1194. DBUG_ENTER("THD::free_temporary_table");
  1195. /*
  1196. If LOCK TABLES list is not empty and contains this table, unlock the table
  1197. and remove the table from this list.
  1198. */
  1199. mysql_lock_remove(this, lock, table);
  1200. close_temporary_table(table);
  1201. DBUG_VOID_RETURN;
  1202. }
  1203. /**
  1204. On replication slave, acquire the Relay_log_info's data_lock and use slave
  1205. temporary tables.
  1206. @return true Lock acquired
  1207. false Lock wasn't acquired
  1208. */
  1209. bool THD::lock_temporary_tables()
  1210. {
  1211. DBUG_ENTER("THD::lock_temporary_tables");
  1212. /* Do not proceed if a lock has already been taken. */
  1213. if (m_tmp_tables_locked)
  1214. {
  1215. DBUG_RETURN(false);
  1216. }
  1217. #ifdef HAVE_REPLICATION
  1218. if (rgi_slave)
  1219. {
  1220. mysql_mutex_lock(&rgi_slave->rli->data_lock);
  1221. temporary_tables= rgi_slave->rli->save_temporary_tables;
  1222. m_tmp_tables_locked= true;
  1223. }
  1224. #endif
  1225. DBUG_RETURN(m_tmp_tables_locked);
  1226. }
  1227. /**
  1228. On replication slave, release the Relay_log_info::data_lock previously
  1229. acquired to use slave temporary tables.
  1230. @return void
  1231. */
  1232. void THD::unlock_temporary_tables()
  1233. {
  1234. DBUG_ENTER("THD::unlock_temporary_tables");
  1235. if (!m_tmp_tables_locked)
  1236. {
  1237. DBUG_VOID_RETURN;
  1238. }
  1239. #ifdef HAVE_REPLICATION
  1240. if (rgi_slave)
  1241. {
  1242. rgi_slave->rli->save_temporary_tables= temporary_tables;
  1243. temporary_tables= NULL; /* Safety */
  1244. mysql_mutex_unlock(&rgi_slave->rli->data_lock);
  1245. m_tmp_tables_locked= false;
  1246. }
  1247. #endif
  1248. DBUG_VOID_RETURN;
  1249. }
  1250. /**
  1251. Close unused TABLE instances for given temporary table.
  1252. @param tl [IN] TABLE_LIST
  1253. Initial use case was TRUNCATE, which expects only one instance (which is used
  1254. by TRUNCATE itself) to be open. Most probably some ALTER TABLE variants and
  1255. REPAIR may have similar expectations.
  1256. */
  1257. void THD::close_unused_temporary_table_instances(const TABLE_LIST *tl)
  1258. {
  1259. TMP_TABLE_SHARE *share= find_tmp_table_share(tl);
  1260. if (share)
  1261. {
  1262. All_share_tables_list::Iterator tables_it(share->all_tmp_tables);
  1263. while (TABLE *table= tables_it++)
  1264. {
  1265. if (table->query_id == 0)
  1266. {
  1267. /* Note: removing current list element doesn't invalidate iterator. */
  1268. share->all_tmp_tables.remove(table);
  1269. free_temporary_table(table);
  1270. }
  1271. }
  1272. }
  1273. }