Commit 3fa0dd23 authored by unknown's avatar unknown
Browse files

A fix and a test case for Bug#14210 "Simple query with > operator on

large table gives server crash": make sure that when a MyISAM temporary
table is created for a cursor, it's created in its memory root,
not the memory root of the current query.


mysql-test/r/sp.result:
  Test results fixed: a test case for Bug#14210
mysql-test/t/sp.test:
  A test case for Bug#14210 "Simple query with > operator on large table 
  gives server crash"
sql/handler.cc:
  - rewrite get_new_handler to accept a memory root and use it for
sql/handler.h:
  - get_new_handler declaration changed
sql/opt_range.cc:
  - get_new_handler declaration changed
sql/sql_base.cc:
  - get_new_handler declaration changed
sql/sql_select.cc:
  - the actual fix for Bug#14210. In create_myisam_from_heap we should
  create the new table handler in TABLE::mem_root, not in THD::mem_root:
  the latter is freed shortly after cursor is open.
  - adjust create_tmp_table to explicitly supply &table->mem_root
  to get_new_handler when creating a handler for a new temporary table
sql/sql_table.cc:
  - get_new_handler declaration changed
sql/table.cc:
  - get_new_handler declaration changed
sql/unireg.cc:
  - get_new_handler declaration changed
tests/mysql_client_test.c:
  A test case for Bug#14210 "Simple query with > operator on large table
   gives server crash": a C API test case is worth adding because of different
  memory allocation/freeing patterns in handling of C API and SP cursors
parent e2220f47
Loading
Loading
Loading
Loading
+42 −0
Original line number Diff line number Diff line
@@ -3575,4 +3575,46 @@ DROP VIEW bug13095_v1
DROP PROCEDURE IF EXISTS bug13095;
DROP VIEW IF EXISTS bug13095_v1;
DROP TABLE IF EXISTS bug13095_t1;
drop procedure if exists bug14210|
set @@session.max_heap_table_size=16384|
select @@session.max_heap_table_size|
@@session.max_heap_table_size
16384
create table t3 (a char(255)) engine=InnoDB|
create procedure bug14210_fill_table()
begin
declare table_size, max_table_size int default 0;
select @@session.max_heap_table_size into max_table_size;
delete from t3;
insert into t3 (a) values (repeat('a', 255));
repeat
insert into t3 select a from t3;
select count(*)*255 from t3 into table_size;
until table_size > max_table_size*2 end repeat;
end|
call bug14210_fill_table()|
drop procedure bug14210_fill_table|
create table t4 like t3|
create procedure bug14210()
begin
declare a char(255);
declare done int default 0;
declare c cursor for select * from t3;
declare continue handler for sqlstate '02000' set done = 1;
open c;
repeat
fetch c into a;
if not done then
insert into t4 values (upper(a));
end if;
until done end repeat;
close c;
end|
call bug14210()|
select count(*) from t4|
count(*)
256
drop table t3, t4|
drop procedure bug14210|
set @@session.max_heap_table_size=default|
drop table t1,t2;
+52 −0
Original line number Diff line number Diff line
@@ -4488,6 +4488,58 @@ DROP TABLE IF EXISTS bug13095_t1;

delimiter |;

#
# BUG#14210: "Simple query with > operator on large table gives server
# crash"
# Check that cursors work in case when HEAP tables are converted to
# MyISAM
#
--disable_warnings
drop procedure if exists bug14210|
--enable_warnings
set @@session.max_heap_table_size=16384|
select @@session.max_heap_table_size|
# To trigger the memory corruption the original table must be InnoDB.
# No harm if it's not, so don't warn if the suite is run with --skip-innodb
--disable_warnings
create table t3 (a char(255)) engine=InnoDB|
--enable_warnings
create procedure bug14210_fill_table()
begin
  declare table_size, max_table_size int default 0;
  select @@session.max_heap_table_size into max_table_size;
  delete from t3;
  insert into t3 (a) values (repeat('a', 255));
  repeat
    insert into t3 select a from t3;
    select count(*)*255 from t3 into table_size;
  until table_size > max_table_size*2 end repeat;
end|
call bug14210_fill_table()|
drop procedure bug14210_fill_table|
create table t4 like t3|

create procedure bug14210()
begin
  declare a char(255);
  declare done int default 0;
  declare c cursor for select * from t3;
  declare continue handler for sqlstate '02000' set done = 1;
  open c;
  repeat
    fetch c into a;
    if not done then
       insert into t4 values (upper(a));
    end if;
  until done end repeat;
  close c;
end|
call bug14210()|
select count(*) from t4|

drop table t3, t4|
drop procedure bug14210|
set @@session.max_heap_table_size=default|

#
# BUG#NNNN: New bug synopsis
+19 −17
Original line number Diff line number Diff line
@@ -293,61 +293,61 @@ enum db_type ha_checktype(THD *thd, enum db_type database_type,
} /* ha_checktype */


handler *get_new_handler(TABLE *table, enum db_type db_type)
handler *get_new_handler(TABLE *table, MEM_ROOT *alloc, enum db_type db_type)
{
  switch (db_type) {
#ifndef NO_HASH
  case DB_TYPE_HASH:
    return new ha_hash(table);
    return new (alloc) ha_hash(table);
#endif
  case DB_TYPE_MRG_ISAM:
    return new ha_myisammrg(table);
    return new (alloc) ha_myisammrg(table);
#ifdef HAVE_BERKELEY_DB
  case DB_TYPE_BERKELEY_DB:
    return new ha_berkeley(table);
    return new (alloc) ha_berkeley(table);
#endif
#ifdef HAVE_INNOBASE_DB
  case DB_TYPE_INNODB:
    return new ha_innobase(table);
    return new (alloc) ha_innobase(table);
#endif
#ifdef HAVE_EXAMPLE_DB
  case DB_TYPE_EXAMPLE_DB:
    return new ha_example(table);
    return new (alloc) ha_example(table);
#endif
#ifdef HAVE_ARCHIVE_DB
  case DB_TYPE_ARCHIVE_DB:
    return new ha_archive(table);
    return new (alloc) ha_archive(table);
#endif
#ifdef HAVE_BLACKHOLE_DB
  case DB_TYPE_BLACKHOLE_DB:
    return new ha_blackhole(table);
    return new (alloc) ha_blackhole(table);
#endif
#ifdef HAVE_FEDERATED_DB
  case DB_TYPE_FEDERATED_DB:
    return new ha_federated(table);
    return new (alloc) ha_federated(table);
#endif
#ifdef HAVE_CSV_DB
  case DB_TYPE_CSV_DB:
    return new ha_tina(table);
    return new (alloc) ha_tina(table);
#endif
#ifdef HAVE_NDBCLUSTER_DB
  case DB_TYPE_NDBCLUSTER:
    return new ha_ndbcluster(table);
    return new (alloc) ha_ndbcluster(table);
#endif
  case DB_TYPE_HEAP:
    return new ha_heap(table);
    return new (alloc) ha_heap(table);
  default:					// should never happen
  {
    enum db_type def=(enum db_type) current_thd->variables.table_type;
    /* Try first with 'default table type' */
    if (db_type != def)
      return get_new_handler(table, def);
      return get_new_handler(table, alloc, def);
  }
  /* Fall back to MyISAM */
  case DB_TYPE_MYISAM:
    return new ha_myisam(table);
    return new (alloc) ha_myisam(table);
  case DB_TYPE_MRG_MYISAM:
    return new ha_myisammrg(table);
    return new (alloc) ha_myisammrg(table);
  }
}

@@ -1300,7 +1300,7 @@ int ha_delete_table(THD *thd, enum db_type table_type, const char *path,

  /* DB_TYPE_UNKNOWN is used in ALTER TABLE when renaming only .frm files */
  if (table_type == DB_TYPE_UNKNOWN ||
      ! (file=get_new_handler(&dummy_table, table_type)))
      ! (file=get_new_handler(&dummy_table, thd->mem_root, table_type)))
    DBUG_RETURN(ENOENT);

  if (lower_case_table_names == 2 && !(file->table_flags() & HA_FILE_BASED))
@@ -2469,6 +2469,7 @@ int handler::index_read_idx(byte * buf, uint index, const byte * key,

TYPELIB *ha_known_exts(void)
{
  MEM_ROOT *mem_root= current_thd->mem_root;
  if (!known_extensions.type_names || mysys_usage_id != known_extensions_id)
  {
    handlerton **types;
@@ -2483,7 +2484,8 @@ TYPELIB *ha_known_exts(void)
    {
      if ((*types)->state == SHOW_OPTION_YES)
      {
	handler *file= get_new_handler(0,(enum db_type) (*types)->db_type);
	handler *file= get_new_handler(0, mem_root,
                                       (enum db_type) (*types)->db_type);
	for (ext= file->bas_ext(); *ext; ext++)
	{
	  while ((old_ext= it++))
+1 −1
Original line number Diff line number Diff line
@@ -874,7 +874,7 @@ extern ulong total_ha, total_ha_2pc;
/* lookups */
enum db_type ha_resolve_by_name(const char *name, uint namelen);
const char *ha_get_storage_engine(enum db_type db_type);
handler *get_new_handler(TABLE *table, enum db_type db_type);
handler *get_new_handler(TABLE *table, MEM_ROOT *alloc, enum db_type db_type);
enum db_type ha_checktype(THD *thd, enum db_type database_type,
                          bool no_substitute, bool report_error);
bool ha_check_storage_engine_flag(enum db_type db_type, uint32 flag);
+1 −1
Original line number Diff line number Diff line
@@ -931,7 +931,7 @@ int QUICK_RANGE_SELECT::init_ror_merged_scan(bool reuse_handler)
  }

  THD *thd= current_thd;
  if (!(file= get_new_handler(head, head->s->db_type)))
  if (!(file= get_new_handler(head, thd->mem_root, head->s->db_type)))
    goto failure;
  DBUG_PRINT("info", ("Allocated new handler %p", file));
  if (file->ha_open(head->s->path, head->db_stat, HA_OPEN_IGNORE_IF_LOCKED))
Loading