Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions mysql-test/main/error_simulation.result
Original file line number Diff line number Diff line change
Expand Up @@ -126,3 +126,26 @@ Got one of the listed errors
DROP FUNCTION f1;
SET debug_dbug= @saved_dbug;
# End of 10.2 tests
#
# Conversion of an internal temporary table to the on-disk engine when
# the scan of the in-memory table cannot be started
#
CREATE TABLE t1 (v VARCHAR(1024));
INSERT INTO t1 SELECT CONCAT('v', LPAD(seq, 6, '0')) FROM seq_1_to_100;
SET @save_tmp_table_size= @@tmp_table_size;
SET @save_max_heap_table_size= @@max_heap_table_size;
SET SESSION tmp_table_size= 262144;
SET SESSION max_heap_table_size= 262144;
SET SESSION debug_dbug='+d,heap_conversion_rnd_init_error';
SELECT COUNT(*) FROM t1 a JOIN (SELECT DISTINCT v FROM t1) d ON a.v = d.v;
ERROR HY000: Table definition has changed, please retry transaction
SET debug_dbug= @saved_dbug;
#The on-disk table created for the failed conversion is gone.
#Without the injected failure the query is answered as usual.
SELECT COUNT(*) FROM t1 a JOIN (SELECT DISTINCT v FROM t1) d ON a.v = d.v;
COUNT(*)
100
SET SESSION tmp_table_size= @save_tmp_table_size;
SET SESSION max_heap_table_size= @save_max_heap_table_size;
DROP TABLE t1;
# End of 13.1 tests
35 changes: 35 additions & 0 deletions mysql-test/main/error_simulation.test
Original file line number Diff line number Diff line change
Expand Up @@ -157,3 +157,38 @@ DROP FUNCTION f1;
SET debug_dbug= @saved_dbug;

--echo # End of 10.2 tests

--echo #
--echo # Conversion of an internal temporary table to the on-disk engine when
--echo # the scan of the in-memory table cannot be started
--echo #

CREATE TABLE t1 (v VARCHAR(1024));
INSERT INTO t1 SELECT CONCAT('v', LPAD(seq, 6, '0')) FROM seq_1_to_100;

SET @save_tmp_table_size= @@tmp_table_size;
SET @save_max_heap_table_size= @@max_heap_table_size;

# Small enough that the temporary table of the query below does not fit in
# memory and is converted to the on-disk engine.
SET SESSION tmp_table_size= 262144;
SET SESSION max_heap_table_size= 262144;

--let $tmpdir= `SELECT @@tmpdir`

SET SESSION debug_dbug='+d,heap_conversion_rnd_init_error';
--error ER_TABLE_DEF_CHANGED
SELECT COUNT(*) FROM t1 a JOIN (SELECT DISTINCT v FROM t1) d ON a.v = d.v;
SET debug_dbug= @saved_dbug;

--echo #The on-disk table created for the failed conversion is gone.
--list_files $tmpdir #sql-temptable*

--echo #Without the injected failure the query is answered as usual.
SELECT COUNT(*) FROM t1 a JOIN (SELECT DISTINCT v FROM t1) d ON a.v = d.v;

SET SESSION tmp_table_size= @save_tmp_table_size;
SET SESSION max_heap_table_size= @save_max_heap_table_size;
DROP TABLE t1;

--echo # End of 13.1 tests
55 changes: 55 additions & 0 deletions mysql-test/main/tmp_table_convert_while_read.result
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
CREATE TABLE t1 (v VARCHAR(1024));
INSERT INTO t1 SELECT CONCAT('v', LPAD(seq, 6, '0')) FROM seq_1_to_100;
CREATE TABLE t2 (a INT);
INSERT INTO t2 VALUES (1),(2);
SET @save_tmp_table_size= @@tmp_table_size;
SET @save_max_heap_table_size= @@max_heap_table_size;
SET SESSION tmp_table_size= 262144;
SET SESSION max_heap_table_size= 262144;
# Derived table with DISTINCT
FLUSH STATUS;
SELECT COUNT(*) FROM t1 a JOIN (SELECT DISTINCT v FROM t1) d ON a.v = d.v;
COUNT(*)
100
SHOW STATUS LIKE 'Created_tmp_disk_tables';
Variable_name Value
Created_tmp_disk_tables 2
# Derived table with GROUP BY
FLUSH STATUS;
SELECT COUNT(*) FROM t1 a JOIN (SELECT v FROM t1 GROUP BY v) d ON a.v = d.v;
COUNT(*)
100
SHOW STATUS LIKE 'Created_tmp_disk_tables';
Variable_name Value
Created_tmp_disk_tables 2
SET SESSION optimizer_switch='derived_merge=off';
# Derived table that is not merged into the outer query
FLUSH STATUS;
SELECT COUNT(*) FROM t2, (SELECT v FROM t1) AS sq;
COUNT(*)
200
SHOW STATUS LIKE 'Created_tmp_disk_tables';
Variable_name Value
Created_tmp_disk_tables 1
# Derived table filled by a UNION
FLUSH STATUS;
SELECT COUNT(*) FROM t2, (SELECT v FROM t1 UNION SELECT v FROM t1) AS sq;
COUNT(*)
200
SHOW STATUS LIKE 'Created_tmp_disk_tables';
Variable_name Value
Created_tmp_disk_tables 2
SET SESSION optimizer_switch=DEFAULT;
# View materialized into a temporary table
CREATE ALGORITHM=TEMPTABLE VIEW v1 AS SELECT * FROM t1;
FLUSH STATUS;
SELECT COUNT(*) FROM v1, t2 WHERE a = 1;
COUNT(*)
100
SHOW STATUS LIKE 'Created_tmp_disk_tables';
Variable_name Value
Created_tmp_disk_tables 1
DROP VIEW v1;
SET SESSION tmp_table_size= @save_tmp_table_size;
SET SESSION max_heap_table_size= @save_max_heap_table_size;
DROP TABLE t1, t2;
65 changes: 65 additions & 0 deletions mysql-test/main/tmp_table_convert_while_read.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#
# An internal temporary table can be converted from the in-memory engine to
# the on-disk engine while a reader of that same table is already in progress.
# The reader keeps state on the handler of the table, so the conversion, which
# replaces that handler, has to carry the state over to the new one.
#
--source include/have_sequence.inc

CREATE TABLE t1 (v VARCHAR(1024));
INSERT INTO t1 SELECT CONCAT('v', LPAD(seq, 6, '0')) FROM seq_1_to_100;

CREATE TABLE t2 (a INT);
INSERT INTO t2 VALUES (1),(2);

SET @save_tmp_table_size= @@tmp_table_size;
SET @save_max_heap_table_size= @@max_heap_table_size;

# Small enough that the temporary tables below do not fit in memory. Set
# explicitly so that the test does not depend on the server defaults.
SET SESSION tmp_table_size= 262144;
SET SESSION max_heap_table_size= 262144;

# Created_tmp_disk_tables is checked after every query so that a future change
# of the sizes above cannot silently leave these queries without a conversion.
--disable_ps2_protocol
--disable_cursor_protocol

--echo # Derived table with DISTINCT
FLUSH STATUS;
SELECT COUNT(*) FROM t1 a JOIN (SELECT DISTINCT v FROM t1) d ON a.v = d.v;
SHOW STATUS LIKE 'Created_tmp_disk_tables';

--echo # Derived table with GROUP BY
FLUSH STATUS;
SELECT COUNT(*) FROM t1 a JOIN (SELECT v FROM t1 GROUP BY v) d ON a.v = d.v;
SHOW STATUS LIKE 'Created_tmp_disk_tables';

SET SESSION optimizer_switch='derived_merge=off';

--echo # Derived table that is not merged into the outer query
FLUSH STATUS;
SELECT COUNT(*) FROM t2, (SELECT v FROM t1) AS sq;
SHOW STATUS LIKE 'Created_tmp_disk_tables';

--echo # Derived table filled by a UNION
FLUSH STATUS;
SELECT COUNT(*) FROM t2, (SELECT v FROM t1 UNION SELECT v FROM t1) AS sq;
SHOW STATUS LIKE 'Created_tmp_disk_tables';

SET SESSION optimizer_switch=DEFAULT;

--echo # View materialized into a temporary table
CREATE ALGORITHM=TEMPTABLE VIEW v1 AS SELECT * FROM t1;
FLUSH STATUS;
SELECT COUNT(*) FROM v1, t2 WHERE a = 1;
SHOW STATUS LIKE 'Created_tmp_disk_tables';
DROP VIEW v1;

--enable_cursor_protocol
--enable_ps2_protocol

SET SESSION tmp_table_size= @save_tmp_table_size;
SET SESSION max_heap_table_size= @save_max_heap_table_size;

DROP TABLE t1, t2;
3 changes: 3 additions & 0 deletions sql/handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -3621,6 +3621,9 @@ class handler :public Sql_alloc
void start_psi_batch_mode();
/** End a batch started with @c start_psi_batch_mode. */
void end_psi_batch_mode();
/** Check if a batch started with @c start_psi_batch_mode is in progress. */
bool is_in_psi_batch_mode() const
{ return m_psi_batch_mode != PSI_BATCH_MODE_NONE; }

/* If we have row logging enabled for this table */
bool row_logging, row_logging_init;
Expand Down
21 changes: 20 additions & 1 deletion sql/sql_select.cc
Original file line number Diff line number Diff line change
Expand Up @@ -23829,6 +23829,7 @@ create_internal_tmp_table_from_heap(THD *thd, TABLE *table,
TABLE_SHARE share;
const char *save_proc_info;
int write_err= 0;
bool psi_batch_mode= false;
String tmp_alias;
DBUG_ENTER("create_internal_tmp_table_from_heap");
if (is_duplicate)
Expand Down Expand Up @@ -23874,8 +23875,13 @@ create_internal_tmp_table_from_heap(THD *thd, TABLE *table,
if (table->file->indexes_are_disabled())
new_table.file->ha_disable_indexes(key_map(0), false);
table->file->ha_index_or_rnd_end();
DBUG_EXECUTE_IF("heap_conversion_rnd_init_error",
{
table->file->print_error(HA_ERR_TABLE_DEF_CHANGED, MYF(0));
goto err_drop;
});
if (table->file->ha_rnd_init_with_error(1))
DBUG_RETURN(1);
goto err_drop;
if (new_table.no_rows)
new_table.file->extra(HA_EXTRA_NO_ROWS);
else
Expand Down Expand Up @@ -23919,6 +23925,16 @@ create_internal_tmp_table_from_heap(THD *thd, TABLE *table,

/* remove heap table and change to use myisam table */
(void) table->file->ha_rnd_end();
/*
A reader of this table may have put its handler into PFS batch mode, see
JOIN_TAB::pfs_batch_update(). The reader ends the batch on the handler
that table->file points to at that time, which is the new handler, so the
batch has to be moved over to it. Ending it here without starting it again
would leave that call without a matching start_psi_batch_mode().
*/
psi_batch_mode= table->file->is_in_psi_batch_mode();
if (psi_batch_mode)
table->file->end_psi_batch_mode();
(void) table->file->ha_close(); // This deletes the table !
delete table->file;
table->file=0;
Expand All @@ -23939,6 +23955,8 @@ create_internal_tmp_table_from_heap(THD *thd, TABLE *table,

table->file->change_table_ptr(table, table->s);
table->use_all_columns();
if (psi_batch_mode)
table->file->start_psi_batch_mode();
if (save_proc_info)
thd_proc_info(thd, (!strcmp(save_proc_info,"Copying to tmp table") ?
"Copying to tmp table on disk" : save_proc_info));
Expand All @@ -23949,6 +23967,7 @@ create_internal_tmp_table_from_heap(THD *thd, TABLE *table,
table->file->print_error(write_err, MYF(0));
err_killed:
(void) table->file->ha_rnd_end();
err_drop:
(void) new_table.file->drop_table(new_table.s->path.str);
err2:
delete new_table.file;
Expand Down
Loading