Commit 39fda600 authored by unknown's avatar unknown
Browse files

Fix for bug #10055 "Using stored function with information_schema causes empty

result set".

To enable full access to contents of I_S tables from stored functions
or statements that use them, we manipulate with thread's open tables
state and ensure that we won't cause deadlock when we open tables by
ignoring flushes and name-locks.
Building of contents of I_S.TABLES no longer requires locking of tables
since we use use handler::info() method with HA_STATUS_AUTO flag instead
of handler::update_auto_increment() for obtaining information about
auto-increment values. But this also means that handlers have to implement
support for HA_STATUS_AUTO flag (particularly InnoDB needs it).


mysql-test/r/alter_table.result:
  Updated test results. This change was caused by the fact that now when
  we build contents of I_S tables (and thus output of SHOW INDEX) we
  don't use instances of tables which may be already opened and locked
  by thread (we always use new instance).
mysql-test/r/information_schema.result:
  Added test which checks how information about current auto-increment value for
  table is reported in INFORMATION_SCHEMA.TABLES view.
mysql-test/r/sp.result:
  Added test for bug #10055 "Using stored function with information_schema causes
  empty result set".
mysql-test/t/information_schema.test:
  Added test which checks how information about current auto-increment value for
  table is reported in INFORMATION_SCHEMA.TABLES view.
mysql-test/t/sp.test:
  Added test for bug #10055 "Using stored function with information_schema causes
  empty result set".
sql/mysql_priv.h:
  close_thread_tables():
    Get rid of 'stopper' argument which is no longer used. Now when we need
    to open and then close some table without touching tables which are already
    opened we use THD::reset_n/restore_backup_open_tables_state() methods.
  open_tables()/open_normal_and_derived_tables():
    Added 'flags' argument to be able open tables even if some has done
    a flush or hold namelock on them.
sql/sp.cc:
  close_proc_table/open_proc_table_for_read/db_find_routine():
    Replaced push_open_tables_state/pop_open_tables_state() methods which
    were saving/restoring current open tables state in/from THD::open_state_list
    with reset_n_backup_open_tables_state/restore_backup_open_tables_state()
    methods which assume that backup storage for this state is allocated on
    stack (or elsewhere) by their caller.
  open_proc_table_for_read():
    Since now we can have several open tables states stacked up we can't rely
    rely on checking whether we have some tables open in previous state.
    Instead we always assume that some tables are open and we need to ignore
    flush while locking mysql.proc. We don't really need 
    MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK in this case since we open mysql.proc table
    only for reading.
sql/sp.h:
  Added declarations of open_proc_table_for_read()/close_proc_table() to be
  able to use them in sql_show.cc.
sql/sql_base.cc:
  close_thread_tables():
    Get rid of 'stopper' argument which is no longer used. Now when we need
    to open and then close some table without touching tables which are already
    opened we use THD::reset_n/restore_backup_open_tables_state() methods.
  open_tables()/open_normal_and_derived_tables():
    Added 'flags' argument to be able open tables even if some has done
    a flush or hold namelock on them.
sql/sql_class.cc:
  Open_tables_state, THD:
    Replaced push_open_tables_state/pop_open_tables_state() methods which
    were saving/restoring current open tables state in/from THD::open_state_list
    with reset_n_backup_open_tables_state/restore_backup_open_tables_state()
    methods which assume that backup storage for this state is allocated on
    stack (or elsewhere) by their caller.
sql/sql_class.h:
  Open_tables_state, THD:
    Replaced push_open_tables_state/pop_open_tables_state() methods which
    were saving/restoring current open tables state in/from THD::open_state_list
    with reset_n_backup_open_tables_state/restore_backup_open_tables_state()
    methods which assume that backup storage for this state is allocated on
    stack (or elsewhere) by their caller.
sql/sql_handler.cc:
  open_tables()/open_normal_and_derived_tables():
    Added 'flags' argument to be able open tables even if some has done
    a flush or hold namelock on them.
sql/sql_prepare.cc:
  open_tables()/open_normal_and_derived_tables():
    Added 'flags' argument to be able open tables even if some has done
    a flush or hold namelock on them.
sql/sql_show.cc:
  get_all_tables():
    Now we use THD::reset_n_/restore_backup_open_tables_state() for 
    saving/restoring open tables state instead of working with it directly
    (This also allows us to have proper content of I_S system tables in
    statements with stored functions and in stored functions). We also
    ignore possible flushes when opening tables (we may create deadlock
    otherwise). Also we do all needed manipulations with LEX in this function
    and not in get_schema_tables_result() now.
  get_schema_tables_record():
    Let us use handler::info() method with HA_STATUS_AUTO flag for obtaining
    information about table's auto-increment value. This allows to avoid locking
    of tables which is needed when we use handler::update_auto_increment() method.
  fill_schema_proc():
    Now we use open_proc_table_for_read/close_proc_table() for access to
    mysql.proc table (so we won't cause deadlock if we already have some
    tables open and locked, this also allows us to have proper content in
    ROUTINES system table in statements using stored functions/in stored
    functions).
  get_schema_tables_result():
    Moved all manipulations with Open_tables_state and LEX needed for
    safe opening of tables to ST_SCHEMA_TABLE::fill_table functions
    (i.e. get_all_tables() and fill_schema_proc()).
sql/sql_update.cc:
  open_tables()/open_normal_and_derived_tables():
    Added 'flags' argument to be able open tables even if some has done
    a flush or hold namelock on them.
parent 20d8170a
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -314,7 +314,7 @@ INSERT INTO t1 VALUES ('localhost','root'),('localhost',''),('games','monty');
SHOW INDEX FROM t1;
Table	Non_unique	Key_name	Seq_in_index	Column_name	Collation	Cardinality	Sub_part	Packed	Null	Index_type	Comment
t1	0	PRIMARY	1	Host	A	NULL	NULL	NULL		BTREE	
t1	0	PRIMARY	2	User	A	3	NULL	NULL		BTREE	
t1	0	PRIMARY	2	User	A	0	NULL	NULL		BTREE	
ALTER TABLE t1 ENABLE KEYS;
UNLOCK TABLES;
CHECK TABLES t1;
@@ -338,7 +338,7 @@ INSERT INTO t1 VALUES ('localhost','root'),('localhost','');
SHOW INDEX FROM t1;
Table	Non_unique	Key_name	Seq_in_index	Column_name	Collation	Cardinality	Sub_part	Packed	Null	Index_type	Comment
t1	0	PRIMARY	1	Host	A	NULL	NULL	NULL		BTREE	
t1	0	PRIMARY	2	User	A	2	NULL	NULL		BTREE	
t1	0	PRIMARY	2	User	A	0	NULL	NULL		BTREE	
t1	1	Host	1	Host	A	NULL	NULL	NULL		BTREE	disabled
ALTER TABLE t1 ENABLE KEYS;
SHOW INDEX FROM t1;
+10 −2
Original line number Diff line number Diff line
DROP TABLE IF EXISTS t0,t1,t2;
DROP TABLE IF EXISTS t0,t1,t2,t3,t5;
show variables where variable_name like "skip_show_database";
Variable_name	Value
skip_show_database	OFF
@@ -30,6 +30,8 @@ create table mysqltest.t1(a int, b VARCHAR(30), KEY string_data (b));
create table test.t2(a int);
create table t3(a int, KEY a_data (a));
create table mysqltest.t4(a int);
create table t5 (id int auto_increment primary key);
insert into t5 values (10);
create view v1 (c) as select table_name from information_schema.TABLES;
select * from v1;
c
@@ -69,6 +71,7 @@ t1
t4
t2
t3
t5
v1
select c,table_name from v1 
inner join information_schema.TABLES v2 on (v1.c=v2.table_name)
@@ -87,6 +90,7 @@ t1 t1
t4	t4
t2	t2
t3	t3
t5	t5
select c,table_name from v1 
left join information_schema.TABLES v2 on (v1.c=v2.table_name)
where v1.c like "t%";
@@ -104,6 +108,7 @@ t1 t1
t4	t4
t2	t2
t3	t3
t5	t5
select c, v2.table_name from v1
right join information_schema.TABLES v2 on (v1.c=v2.table_name)
where v1.c like "t%";
@@ -121,6 +126,7 @@ t1 t1
t4	t4
t2	t2
t3	t3
t5	t5
select table_name from information_schema.TABLES
where table_schema = "mysqltest" and table_name like "t%";
table_name
@@ -136,10 +142,12 @@ show tables like 't%';
Tables_in_test (t%)
t2
t3
t5
show table status;
Name	Engine	Version	Row_format	Rows	Avg_row_length	Data_length	Max_data_length	Index_length	Data_free	Auto_increment	Create_time	Update_time	Check_time	Collation	Checksum	Create_options	Comment
t2	MyISAM	10	Fixed	0	0	0	#	1024	0	NULL	#	#	NULL	latin1_swedish_ci	NULL		
t3	MyISAM	10	Fixed	0	0	0	#	1024	0	NULL	#	#	NULL	latin1_swedish_ci	NULL		
t5	MyISAM	10	Fixed	1	7	7	#	2048	0	11	#	#	NULL	latin1_swedish_ci	NULL		
v1	NULL	NULL	NULL	NULL	NULL	NULL	#	NULL	NULL	NULL	#	#	NULL	NULL	NULL	NULL	view
show full columns from t3 like "a%";
Field	Type	Collation	Null	Key	Default	Extra	Privileges	Comment
@@ -173,7 +181,7 @@ where table_schema = 'mysqltest' and table_name = 'v1';
table_name	column_name	privileges
v1	c	select
drop view v1, mysqltest.v1;
drop tables mysqltest.t4, mysqltest.t1, t2, t3;
drop tables mysqltest.t4, mysqltest.t1, t2, t3, t5;
drop database mysqltest;
select * from information_schema.CHARACTER_SETS
where CHARACTER_SET_NAME like 'latin1%';
+9 −0
Original line number Diff line number Diff line
@@ -3062,4 +3062,13 @@ l
drop procedure bug6063|
drop procedure bug7088_1|
drop procedure bug7088_2|
drop function if exists bug10055|
create function bug10055(v char(255)) returns char(255) return lower(v)|
select t.column_name, bug10055(t.column_name)
from information_schema.columns as t
where t.table_schema = 'test' and t.table_name = 't1'|
column_name	bug10055(t.column_name)
id	id
data	data
drop function bug10055|
drop table t1,t2;
+4 −2
Original line number Diff line number Diff line
@@ -5,7 +5,7 @@
# show databases

--disable_warnings
DROP TABLE IF EXISTS t0,t1,t2;
DROP TABLE IF EXISTS t0,t1,t2,t3,t5;
--enable_warnings


@@ -30,6 +30,8 @@ create table mysqltest.t1(a int, b VARCHAR(30), KEY string_data (b));
create table test.t2(a int);
create table t3(a int, KEY a_data (a));
create table mysqltest.t4(a int);
create table t5 (id int auto_increment primary key);
insert into t5 values (10);
create view v1 (c) as select table_name from information_schema.TABLES;
select * from v1;

@@ -76,7 +78,7 @@ where table_schema = 'mysqltest' and table_name = 'v1';
connection default;

drop view v1, mysqltest.v1;
drop tables mysqltest.t4, mysqltest.t1, t2, t3;
drop tables mysqltest.t4, mysqltest.t1, t2, t3, t5;
drop database mysqltest;

# Test for information_schema.CHARACTER_SETS &
+15 −0
Original line number Diff line number Diff line
@@ -3833,6 +3833,21 @@ drop procedure bug7088_1|
drop procedure bug7088_2|


#
# Bug#10055 "Using stored function with information_schema causes empty
#            result set"
#
--disable_warnings
drop function if exists bug10055|
--enable_warnings
create function bug10055(v char(255)) returns char(255) return lower(v)|
# This select should not crash server and should return all fields in t1
select t.column_name, bug10055(t.column_name)
from information_schema.columns as t
where t.table_schema = 'test' and t.table_name = 't1'|
drop function bug10055|


#
# BUG#NNNN: New bug synopsis
#
Loading